diff --git a/cargo b/cargo index c416fb60b11e..8326a3683a90 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 +Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755 diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 3fbf9f06d99f..12daa24e857f 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -781,10 +781,11 @@ never_type : "!" ; ### Type parameter bounds ```antlr +bound-list := bound | bound '+' bound-list '+' ? bound := ty_bound | lt_bound lt_bound := lifetime -ty_bound := [?] [ for ] simple_path -bound-list := bound | bound '+' bound-list '+' ? +ty_bound := ty_bound_noparen | (ty_bound_noparen) +ty_bound_noparen := [?] [ for ] simple_path ``` ### Self types diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 1cfb46530237..ef67941975bf 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -101,11 +101,8 @@ - [alloc_system](library-features/alloc-system.md) - [alloc](library-features/alloc.md) - [as_c_str](library-features/as-c-str.md) - - [as_unsafe_cell](library-features/as-unsafe-cell.md) - [ascii_ctype](library-features/ascii-ctype.md) - - [binary_heap_extras](library-features/binary-heap-extras.md) - [binary_heap_peek_mut_pop](library-features/binary-heap-peek-mut-pop.md) - - [borrow_state](library-features/borrow-state.md) - [box_heap](library-features/box-heap.md) - [c_void_variant](library-features/c-void-variant.md) - [char_escape_debug](library-features/char-escape-debug.md) @@ -130,14 +127,12 @@ - [derive_clone_copy](library-features/derive-clone-copy.md) - [derive_eq](library-features/derive-eq.md) - [discriminant_value](library-features/discriminant-value.md) - - [enumset](library-features/enumset.md) - [error_type_id](library-features/error-type-id.md) - [exact_size_is_empty](library-features/exact-size-is-empty.md) - [fd](library-features/fd.md) - [fd_read](library-features/fd-read.md) - [fixed_size_array](library-features/fixed-size-array.md) - [float_bits_conv](library-features/float-bits-conv.md) - - [float_extras](library-features/float-extras.md) - [flt2dec](library-features/flt2dec.md) - [fmt_flags_align](library-features/fmt-flags-align.md) - [fmt_internals](library-features/fmt-internals.md) @@ -157,7 +152,6 @@ - [io_error_internals](library-features/io-error-internals.md) - [io](library-features/io.md) - [ip](library-features/ip.md) - - [is_unique](library-features/is-unique.md) - [iter_rfind](library-features/iter-rfind.md) - [libstd_io_internals](library-features/libstd-io-internals.md) - [libstd_sys_internals](library-features/libstd-sys-internals.md) @@ -165,7 +159,6 @@ - [linked_list_extras](library-features/linked-list-extras.md) - [lookup_host](library-features/lookup-host.md) - [manually_drop](library-features/manually-drop.md) - - [map_entry_recover_keys](library-features/map-entry-recover-keys.md) - [mpsc_select](library-features/mpsc-select.md) - [n16](library-features/n16.md) - [never_type_impls](library-features/never-type-impls.md) @@ -188,7 +181,6 @@ - [rand](library-features/rand.md) - [range_contains](library-features/range-contains.md) - [raw](library-features/raw.md) - - [rc_would_unwrap](library-features/rc-would-unwrap.md) - [retain_hash_collection](library-features/retain-hash-collection.md) - [reverse_cmp_key](library-features/reverse-cmp-key.md) - [rt](library-features/rt.md) @@ -224,4 +216,3 @@ - [windows_handle](library-features/windows-handle.md) - [windows_net](library-features/windows-net.md) - [windows_stdio](library-features/windows-stdio.md) - - [zero_one](library-features/zero-one.md) diff --git a/src/doc/unstable-book/src/library-features/as-unsafe-cell.md b/src/doc/unstable-book/src/library-features/as-unsafe-cell.md deleted file mode 100644 index 79d7a7cad0b6..000000000000 --- a/src/doc/unstable-book/src/library-features/as-unsafe-cell.md +++ /dev/null @@ -1,7 +0,0 @@ -# `as_unsafe_cell` - -The tracking issue for this feature is: [#27708] - -[#27708]: https://github.com/rust-lang/rust/issues/27708 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/binary-heap-extras.md b/src/doc/unstable-book/src/library-features/binary-heap-extras.md deleted file mode 100644 index aa535f3b6784..000000000000 --- a/src/doc/unstable-book/src/library-features/binary-heap-extras.md +++ /dev/null @@ -1,7 +0,0 @@ -# `binary_heap_extras` - -The tracking issue for this feature is: [#28147] - -[#28147]: https://github.com/rust-lang/rust/issues/28147 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/borrow-state.md b/src/doc/unstable-book/src/library-features/borrow-state.md deleted file mode 100644 index 304b8dffe986..000000000000 --- a/src/doc/unstable-book/src/library-features/borrow-state.md +++ /dev/null @@ -1,7 +0,0 @@ -# `borrow_state` - -The tracking issue for this feature is: [#27733] - -[#27733]: https://github.com/rust-lang/rust/issues/27733 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/enumset.md b/src/doc/unstable-book/src/library-features/enumset.md deleted file mode 100644 index 24c8d8fa7dbb..000000000000 --- a/src/doc/unstable-book/src/library-features/enumset.md +++ /dev/null @@ -1,7 +0,0 @@ -# `enumset` - -The tracking issue for this feature is: [#37966] - -[#37966]: https://github.com/rust-lang/rust/issues/37966 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/float-extras.md b/src/doc/unstable-book/src/library-features/float-extras.md deleted file mode 100644 index ff2d20a545fe..000000000000 --- a/src/doc/unstable-book/src/library-features/float-extras.md +++ /dev/null @@ -1,7 +0,0 @@ -# `float_extras` - -The tracking issue for this feature is: [#27752] - -[#27752]: https://github.com/rust-lang/rust/issues/27752 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/is-unique.md b/src/doc/unstable-book/src/library-features/is-unique.md deleted file mode 100644 index 6070006758b7..000000000000 --- a/src/doc/unstable-book/src/library-features/is-unique.md +++ /dev/null @@ -1,7 +0,0 @@ -# `is_unique` - -The tracking issue for this feature is: [#28356] - -[#28356]: https://github.com/rust-lang/rust/issues/28356 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md b/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md deleted file mode 100644 index 2d15aa0e90de..000000000000 --- a/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md +++ /dev/null @@ -1,5 +0,0 @@ -# `map_entry_recover_keys` - -The tracking issue for this feature is: [#34285] - -[#34285]: https://github.com/rust-lang/rust/issues/34285 diff --git a/src/doc/unstable-book/src/library-features/rc-would-unwrap.md b/src/doc/unstable-book/src/library-features/rc-would-unwrap.md deleted file mode 100644 index 462387dfdcc4..000000000000 --- a/src/doc/unstable-book/src/library-features/rc-would-unwrap.md +++ /dev/null @@ -1,5 +0,0 @@ -# `rc_would_unwrap` - -The tracking issue for this feature is: [#28356] - -[#28356]: https://github.com/rust-lang/rust/issues/28356 diff --git a/src/doc/unstable-book/src/library-features/zero-one.md b/src/doc/unstable-book/src/library-features/zero-one.md deleted file mode 100644 index 4d1cf38c3c2e..000000000000 --- a/src/doc/unstable-book/src/library-features/zero-one.md +++ /dev/null @@ -1,7 +0,0 @@ -# `zero_one` - -The tracking issue for this feature is: [#27739] - -[#27739]: https://github.com/rust-lang/rust/issues/27739 - ------------------------- diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 08a0b2a6d008..056af13016cf 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -16,7 +16,6 @@ issue = "27700")] use core::{isize, usize}; -#[cfg(not(test))] use core::intrinsics::{min_align_of_val, size_of_val}; #[allow(improper_ctypes)] @@ -158,10 +157,9 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { } } -#[cfg(not(test))] -#[lang = "box_free"] +#[cfg_attr(not(test), lang = "box_free")] #[inline] -unsafe fn box_free(ptr: *mut T) { +pub(crate) unsafe fn box_free(ptr: *mut T) { let size = size_of_val(&*ptr); let align = min_align_of_val(&*ptr); // We do not allocate for Box when T is ZST, so deallocation is also not necessary. diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 0c01eabd593f..c70d82392f91 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -87,6 +87,7 @@ #![feature(needs_allocator)] #![feature(optin_builtin_traits)] #![feature(placement_in_syntax)] +#![cfg_attr(stage0, feature(pub_restricted))] #![feature(shared)] #![feature(staged_api)] #![feature(unboxed_closures)] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index fed718e9be4c..38dc91458351 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -239,7 +239,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, Shared}; use core::convert::From; -use heap::deallocate; +use heap::{allocate, deallocate, box_free}; use raw_vec::RawVec; struct RcBox { @@ -248,7 +248,6 @@ struct RcBox { value: T, } - /// A single-threaded reference-counting pointer. /// /// See the [module-level documentation](./index.html) for more details. @@ -341,19 +340,6 @@ impl Rc { } } - /// Checks whether [`Rc::try_unwrap`][try_unwrap] would return - /// [`Ok`]. - /// - /// [try_unwrap]: struct.Rc.html#method.try_unwrap - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - #[unstable(feature = "rc_would_unwrap", - reason = "just added for niche usecase", - issue = "28356")] - #[rustc_deprecated(since = "1.15.0", reason = "too niche; use `strong_count` instead")] - pub fn would_unwrap(this: &Self) -> bool { - Rc::strong_count(&this) == 1 - } - /// Consumes the `Rc`, returning the wrapped pointer. /// /// To avoid a memory leak the pointer must be converted back to an `Rc` using @@ -438,6 +424,38 @@ impl Rc { } } +impl Rc<[T]> { + /// Constructs a new `Rc<[T]>` from a `Box<[T]>`. + #[doc(hidden)] + #[unstable(feature = "rustc_private", + reason = "for internal use in rustc", + issue = "0")] + pub fn __from_array(value: Box<[T]>) -> Rc<[T]> { + unsafe { + let ptr: *mut RcBox<[T]> = + mem::transmute([mem::align_of::>(), value.len()]); + // FIXME(custom-DST): creating this invalid &[T] is dubiously defined, + // we should have a better way of getting the size/align + // of a DST from its unsized part. + let ptr = allocate(size_of_val(&*ptr), align_of_val(&*ptr)); + let ptr: *mut RcBox<[T]> = mem::transmute([ptr as usize, value.len()]); + + // Initialize the new RcBox. + ptr::write(&mut (*ptr).strong, Cell::new(1)); + ptr::write(&mut (*ptr).weak, Cell::new(1)); + ptr::copy_nonoverlapping( + value.as_ptr(), + &mut (*ptr).value as *mut [T] as *mut T, + value.len()); + + // Free the original allocation without freeing its (moved) contents. + box_free(Box::into_raw(value)); + + Rc { ptr: Shared::new(ptr as *const _) } + } + } +} + impl Rc { /// Creates a new [`Weak`][weak] pointer to this value. /// @@ -501,11 +519,7 @@ impl Rc { /// /// [weak]: struct.Weak.html #[inline] - #[unstable(feature = "is_unique", reason = "uniqueness has unclear meaning", - issue = "28356")] - #[rustc_deprecated(since = "1.15.0", - reason = "too niche; use `strong_count` and `weak_count` instead")] - pub fn is_unique(this: &Self) -> bool { + fn is_unique(this: &Self) -> bool { Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 } diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 149c285a72a9..7d972403f65d 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -555,82 +555,6 @@ impl BinaryHeap { self.sift_up(0, old_len); } - /// Pushes an item onto the binary heap, then pops the greatest item off the queue in - /// an optimized fashion. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(binary_heap_extras)] - /// #![allow(deprecated)] - /// - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// heap.push(1); - /// heap.push(5); - /// - /// assert_eq!(heap.push_pop(3), 5); - /// assert_eq!(heap.push_pop(9), 9); - /// assert_eq!(heap.len(), 2); - /// assert_eq!(heap.peek(), Some(&3)); - /// ``` - #[unstable(feature = "binary_heap_extras", - reason = "needs to be audited", - issue = "28147")] - #[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")] - pub fn push_pop(&mut self, mut item: T) -> T { - match self.data.get_mut(0) { - None => return item, - Some(top) => { - if *top > item { - swap(&mut item, top); - } else { - return item; - } - } - } - - self.sift_down(0); - item - } - - /// Pops the greatest item off the binary heap, then pushes an item onto the queue in - /// an optimized fashion. The push is done regardless of whether the binary heap - /// was empty. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(binary_heap_extras)] - /// #![allow(deprecated)] - /// - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// - /// assert_eq!(heap.replace(1), None); - /// assert_eq!(heap.replace(3), Some(1)); - /// assert_eq!(heap.len(), 1); - /// assert_eq!(heap.peek(), Some(&3)); - /// ``` - #[unstable(feature = "binary_heap_extras", - reason = "needs to be audited", - issue = "28147")] - #[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")] - pub fn replace(&mut self, mut item: T) -> Option { - if !self.is_empty() { - swap(&mut item, &mut self.data[0]); - self.sift_down(0); - Some(item) - } else { - self.push(item); - None - } - } - /// Consumes the `BinaryHeap` and returns the underlying vector /// in arbitrary order. /// @@ -1042,7 +966,7 @@ impl<'a, T> FusedIterator for Iter<'a, T> {} /// An owning iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`] +/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`][`BinaryHeap`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.BinaryHeap.html#method.into_iter diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index fb0b852d1027..d73c0254a745 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -298,7 +298,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> { /// An owning iterator over the entries of a `BTreeMap`. /// -/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`] +/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`][`BTreeMap`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.BTreeMap.html#method.into_iter @@ -2217,13 +2217,6 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { self.handle.reborrow().into_kv().0 } - /// Deprecated, renamed to `remove_entry` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")] - pub fn remove_pair(self) -> (K, V) { - self.remove_entry() - } - /// Take ownership of the key and value from the map. /// /// # Examples diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index e05533aa50e3..d32460da9392 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -97,7 +97,7 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { /// An owning iterator over the items of a `BTreeSet`. /// -/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`] +/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`][`BTreeSet`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs deleted file mode 100644 index aaee567bf1db..000000000000 --- a/src/libcollections/enum_set.rs +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A structure for holding a set of enum variants. -//! -//! This module defines a container which uses an efficient bit mask -//! representation to hold C-like enum variants. - -#![unstable(feature = "enumset", - reason = "matches collection reform specification, \ - waiting for dust to settle", - issue = "37966")] -#![rustc_deprecated(since = "1.16.0", reason = "long since replaced")] -#![allow(deprecated)] - -use core::marker; -use core::fmt; -use core::iter::{FromIterator, FusedIterator}; -use core::ops::{Sub, BitOr, BitAnd, BitXor}; - -// FIXME(contentions): implement union family of methods? (general design may be -// wrong here) - -/// A specialized set implementation to use enum types. -/// -/// It is a logic error for an item to be modified in such a way that the -/// transformation of the item to or from a `usize`, as determined by the -/// `CLike` trait, changes while the item is in the set. This is normally only -/// possible through `Cell`, `RefCell`, global state, I/O, or unsafe code. -#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct EnumSet { - // We must maintain the invariant that no bits are set - // for which no variant exists - bits: usize, - marker: marker::PhantomData, -} - -impl Copy for EnumSet {} - -impl Clone for EnumSet { - fn clone(&self) -> EnumSet { - *self - } -} - -impl fmt::Debug for EnumSet { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_set().entries(self).finish() - } -} - -/// An interface for casting C-like enum to usize and back. -/// A typically implementation is as below. -/// -/// ```{rust,ignore} -/// #[repr(usize)] -/// enum Foo { -/// A, B, C -/// } -/// -/// impl CLike for Foo { -/// fn to_usize(&self) -> usize { -/// *self as usize -/// } -/// -/// fn from_usize(v: usize) -> Foo { -/// unsafe { mem::transmute(v) } -/// } -/// } -/// ``` -pub trait CLike { - /// Converts a C-like enum to a `usize`. - fn to_usize(&self) -> usize; - /// Converts a `usize` to a C-like enum. - fn from_usize(usize) -> Self; -} - -fn bit(e: &E) -> usize { - use core::mem; - let value = e.to_usize(); - let bits = mem::size_of::() * 8; - assert!(value < bits, - "EnumSet only supports up to {} variants.", - bits - 1); - 1 << value -} - -impl EnumSet { - /// Returns an empty `EnumSet`. - pub fn new() -> EnumSet { - EnumSet { - bits: 0, - marker: marker::PhantomData, - } - } - - /// Returns the number of elements in the given `EnumSet`. - pub fn len(&self) -> usize { - self.bits.count_ones() as usize - } - - /// Returns `true` if the `EnumSet` is empty. - pub fn is_empty(&self) -> bool { - self.bits == 0 - } - - pub fn clear(&mut self) { - self.bits = 0; - } - - /// Returns `false` if the `EnumSet` contains any enum of the given `EnumSet`. - pub fn is_disjoint(&self, other: &EnumSet) -> bool { - (self.bits & other.bits) == 0 - } - - /// Returns `true` if a given `EnumSet` is included in this `EnumSet`. - pub fn is_superset(&self, other: &EnumSet) -> bool { - (self.bits & other.bits) == other.bits - } - - /// Returns `true` if this `EnumSet` is included in the given `EnumSet`. - pub fn is_subset(&self, other: &EnumSet) -> bool { - other.is_superset(self) - } - - /// Returns the union of both `EnumSets`. - pub fn union(&self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits | e.bits, - marker: marker::PhantomData, - } - } - - /// Returns the intersection of both `EnumSets`. - pub fn intersection(&self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits & e.bits, - marker: marker::PhantomData, - } - } - - /// Adds an enum to the `EnumSet`, and returns `true` if it wasn't there before - pub fn insert(&mut self, e: E) -> bool { - let result = !self.contains(&e); - self.bits |= bit(&e); - result - } - - /// Removes an enum from the EnumSet - pub fn remove(&mut self, e: &E) -> bool { - let result = self.contains(e); - self.bits &= !bit(e); - result - } - - /// Returns `true` if an `EnumSet` contains a given enum. - pub fn contains(&self, e: &E) -> bool { - (self.bits & bit(e)) != 0 - } - - /// Returns an iterator over an `EnumSet`. - pub fn iter(&self) -> Iter { - Iter::new(self.bits) - } -} - -impl Sub for EnumSet { - type Output = EnumSet; - - fn sub(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits & !e.bits, - marker: marker::PhantomData, - } - } -} - -impl BitOr for EnumSet { - type Output = EnumSet; - - fn bitor(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits | e.bits, - marker: marker::PhantomData, - } - } -} - -impl BitAnd for EnumSet { - type Output = EnumSet; - - fn bitand(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits & e.bits, - marker: marker::PhantomData, - } - } -} - -impl BitXor for EnumSet { - type Output = EnumSet; - - fn bitxor(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits ^ e.bits, - marker: marker::PhantomData, - } - } -} - -/// An iterator over an `EnumSet` -pub struct Iter { - index: usize, - bits: usize, - marker: marker::PhantomData, -} - -impl fmt::Debug for Iter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Iter") - .field(&self.index) - .field(&self.bits) - .finish() - } -} - -// FIXME(#19839) Remove in favor of `#[derive(Clone)]` -impl Clone for Iter { - fn clone(&self) -> Iter { - Iter { - index: self.index, - bits: self.bits, - marker: marker::PhantomData, - } - } -} - -impl Iter { - fn new(bits: usize) -> Iter { - Iter { - index: 0, - bits: bits, - marker: marker::PhantomData, - } - } -} - -impl Iterator for Iter { - type Item = E; - - fn next(&mut self) -> Option { - if self.bits == 0 { - return None; - } - - while (self.bits & 1) == 0 { - self.index += 1; - self.bits >>= 1; - } - let elem = CLike::from_usize(self.index); - self.index += 1; - self.bits >>= 1; - Some(elem) - } - - fn size_hint(&self) -> (usize, Option) { - let exact = self.bits.count_ones() as usize; - (exact, Some(exact)) - } -} - -#[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for Iter {} - -impl FromIterator for EnumSet { - fn from_iter>(iter: I) -> EnumSet { - let mut ret = EnumSet::new(); - ret.extend(iter); - ret - } -} - -impl<'a, E> IntoIterator for &'a EnumSet - where E: CLike -{ - type Item = E; - type IntoIter = Iter; - - fn into_iter(self) -> Iter { - self.iter() - } -} - -impl Extend for EnumSet { - fn extend>(&mut self, iter: I) { - for element in iter { - self.insert(element); - } - } -} - -impl<'a, E: 'a + CLike + Copy> Extend<&'a E> for EnumSet { - fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().cloned()); - } -} diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 3bea61f6220b..8d056afdb571 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -89,9 +89,6 @@ pub use btree_set::BTreeSet; #[doc(no_inline)] pub use linked_list::LinkedList; #[doc(no_inline)] -#[allow(deprecated)] -pub use enum_set::EnumSet; -#[doc(no_inline)] pub use vec_deque::VecDeque; #[doc(no_inline)] pub use string::String; @@ -107,7 +104,6 @@ mod macros; pub mod binary_heap; mod btree; pub mod borrow; -pub mod enum_set; pub mod fmt; pub mod linked_list; pub mod range; diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 1cc5e10418f2..adfd91bec489 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -115,7 +115,7 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { /// An owning iterator over the elements of a `LinkedList`. /// -/// This `struct` is created by the [`into_iter`] method on [`LinkedList`] +/// This `struct` is created by the [`into_iter`] method on [`LinkedList`][`LinkedList`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.LinkedList.html#method.into_iter diff --git a/src/libcollections/tests/binary_heap.rs b/src/libcollections/tests/binary_heap.rs index d284937a9e67..af18cddaddb0 100644 --- a/src/libcollections/tests/binary_heap.rs +++ b/src/libcollections/tests/binary_heap.rs @@ -152,36 +152,6 @@ fn test_push_unique() { assert!(*heap.peek().unwrap() == box 103); } -#[test] -#[allow(deprecated)] -fn test_push_pop() { - let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(6), 6); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(0), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(4), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(1), 4); - assert_eq!(heap.len(), 5); -} - -#[test] -#[allow(deprecated)] -fn test_replace() { - let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(6).unwrap(), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(0).unwrap(), 6); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(4).unwrap(), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(1).unwrap(), 4); - assert_eq!(heap.len(), 5); -} - fn check_to_vec(mut data: Vec) { let heap = BinaryHeap::from(data.clone()); let mut v = heap.clone().into_vec(); @@ -227,13 +197,6 @@ fn test_empty_peek_mut() { assert!(empty.peek_mut().is_none()); } -#[test] -#[allow(deprecated)] -fn test_empty_replace() { - let mut heap = BinaryHeap::new(); - assert!(heap.replace(5).is_none()); -} - #[test] fn test_from_iter() { let xs = vec![9, 8, 7, 6, 5, 4, 3, 2, 1]; diff --git a/src/libcollections/tests/lib.rs b/src/libcollections/tests/lib.rs index 618eb386c0f4..9c6e31d70a54 100644 --- a/src/libcollections/tests/lib.rs +++ b/src/libcollections/tests/lib.rs @@ -10,7 +10,6 @@ #![deny(warnings)] -#![feature(binary_heap_extras)] #![feature(binary_heap_peek_mut_pop)] #![feature(box_syntax)] #![feature(inclusive_range_syntax)] diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index a9e795f9378a..079d3acf3764 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -2070,7 +2070,7 @@ impl<'a, T> FusedIterator for IterMut<'a, T> {} /// An owning iterator over the elements of a `VecDeque`. /// -/// This `struct` is created by the [`into_iter`] method on [`VecDeque`] +/// This `struct` is created by the [`into_iter`] method on [`VecDeque`][`VecDeque`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.VecDeque.html#method.into_iter diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 0186d9727828..ba04cbb0543c 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -310,26 +310,6 @@ impl Cell { } } - /// Returns a reference to the underlying `UnsafeCell`. - /// - /// # Examples - /// - /// ``` - /// #![feature(as_unsafe_cell)] - /// - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// - /// let uc = c.as_unsafe_cell(); - /// ``` - #[inline] - #[unstable(feature = "as_unsafe_cell", issue = "27708")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] - pub fn as_unsafe_cell(&self) -> &UnsafeCell { - &self.value - } - /// Returns a raw pointer to the underlying data in this cell. /// /// # Examples @@ -480,20 +460,6 @@ pub struct RefCell { value: UnsafeCell, } -/// An enumeration of values returned from the `state` method on a `RefCell`. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "borrow_state", issue = "27733")] -#[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")] -#[allow(deprecated)] -pub enum BorrowState { - /// The cell is currently being read, there is at least one active `borrow`. - Reading, - /// The cell is currently being written to, there is an active `borrow_mut`. - Writing, - /// There are no outstanding borrows on this cell. - Unused, -} - /// An error returned by [`RefCell::try_borrow`](struct.RefCell.html#method.try_borrow). #[stable(feature = "try_borrow", since = "1.13.0")] pub struct BorrowError { @@ -582,38 +548,6 @@ impl RefCell { } impl RefCell { - /// Query the current state of this `RefCell` - /// - /// The returned value can be dispatched on to determine if a call to - /// `borrow` or `borrow_mut` would succeed. - /// - /// # Examples - /// - /// ``` - /// #![feature(borrow_state)] - /// - /// use std::cell::{BorrowState, RefCell}; - /// - /// let c = RefCell::new(5); - /// - /// match c.borrow_state() { - /// BorrowState::Writing => println!("Cannot be borrowed"), - /// BorrowState::Reading => println!("Cannot be borrowed mutably"), - /// BorrowState::Unused => println!("Can be borrowed (mutably as well)"), - /// } - /// ``` - #[unstable(feature = "borrow_state", issue = "27733")] - #[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")] - #[allow(deprecated)] - #[inline] - pub fn borrow_state(&self) -> BorrowState { - match self.borrow.get() { - WRITING => BorrowState::Writing, - UNUSED => BorrowState::Unused, - _ => BorrowState::Reading, - } - } - /// Immutably borrows the wrapped value. /// /// The borrow lasts until the returned `Ref` exits scope. Multiple @@ -769,29 +703,6 @@ impl RefCell { } } - /// Returns a reference to the underlying `UnsafeCell`. - /// - /// This can be used to circumvent `RefCell`'s safety checks. - /// - /// This function is `unsafe` because `UnsafeCell`'s field is public. - /// - /// # Examples - /// - /// ``` - /// #![feature(as_unsafe_cell)] - /// - /// use std::cell::RefCell; - /// - /// let c = RefCell::new(5); - /// let c = unsafe { c.as_unsafe_cell() }; - /// ``` - #[inline] - #[unstable(feature = "as_unsafe_cell", issue = "27708")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] - pub unsafe fn as_unsafe_cell(&self) -> &UnsafeCell { - &self.value - } - /// Returns a raw pointer to the underlying data in this cell. /// /// # Examples diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index a324a4aed257..4ca303dee43f 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -15,7 +15,6 @@ // FIXME: #6220 Implement floating point formatting use fmt; -use num::Zero; use ops::{Div, Rem, Sub}; use str; use slice; @@ -23,8 +22,9 @@ use ptr; use mem; #[doc(hidden)] -trait Int: Zero + PartialEq + PartialOrd + Div + Rem + +trait Int: PartialEq + PartialOrd + Div + Rem + Sub + Copy { + fn zero() -> Self; fn from_u8(u: u8) -> Self; fn to_u8(&self) -> u8; fn to_u16(&self) -> u16; @@ -35,6 +35,7 @@ trait Int: Zero + PartialEq + PartialOrd + Div + Rem + macro_rules! doit { ($($t:ident)*) => ($(impl Int for $t { + fn zero() -> $t { 0 } fn from_u8(u: u8) -> $t { u as $t } fn to_u8(&self) -> u8 { *self as u8 } fn to_u16(&self) -> u16 { *self as u16 } diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index 1485c79ead25..2a60292d0232 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -63,11 +63,8 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp const NAN: Self; const ZERO: Self; - // suffix of "2" because Float::integer_decode is deprecated - #[allow(deprecated)] - fn integer_decode2(self) -> (u64, i16, i8) { - Float::integer_decode(self) - } + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8); /// Get the raw binary representation of the float. fn transmute(self) -> u64; @@ -160,6 +157,21 @@ impl RawFloat for f32 { const ZERO_CUTOFF: i64 = -48; other_constants!(f32); + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8) { + let bits: u32 = unsafe { transmute(self) }; + let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; + let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; + let mantissa = if exponent == 0 { + (bits & 0x7fffff) << 1 + } else { + (bits & 0x7fffff) | 0x800000 + }; + // Exponent bias + mantissa shift + exponent -= 127 + 23; + (mantissa as u64, exponent, sign) + } + fn transmute(self) -> u64 { let bits: u32 = unsafe { transmute(self) }; bits as u64 @@ -171,7 +183,7 @@ impl RawFloat for f32 { } fn unpack(self) -> Unpacked { - let (sig, exp, _sig) = self.integer_decode2(); + let (sig, exp, _sig) = self.integer_decode(); Unpacked::new(sig, exp) } @@ -196,6 +208,21 @@ impl RawFloat for f64 { const ZERO_CUTOFF: i64 = -326; other_constants!(f64); + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8) { + let bits: u64 = unsafe { transmute(self) }; + let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; + let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; + let mantissa = if exponent == 0 { + (bits & 0xfffffffffffff) << 1 + } else { + (bits & 0xfffffffffffff) | 0x10000000000000 + }; + // Exponent bias + mantissa shift + exponent -= 1023 + 52; + (mantissa, exponent, sign) + } + fn transmute(self) -> u64 { let bits: u64 = unsafe { transmute(self) }; bits @@ -206,7 +233,7 @@ impl RawFloat for f64 { } fn unpack(self) -> Unpacked { - let (sig, exp, _sig) = self.integer_decode2(); + let (sig, exp, _sig) = self.integer_decode(); Unpacked::new(sig, exp) } diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 4527d46a27d8..91ca213e96e0 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -143,36 +143,6 @@ pub mod consts { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] impl Float for f32 { - #[inline] - fn nan() -> f32 { - NAN - } - - #[inline] - fn infinity() -> f32 { - INFINITY - } - - #[inline] - fn neg_infinity() -> f32 { - NEG_INFINITY - } - - #[inline] - fn zero() -> f32 { - 0.0 - } - - #[inline] - fn neg_zero() -> f32 { - -0.0 - } - - #[inline] - fn one() -> f32 { - 1.0 - } - /// Returns `true` if the number is NaN. #[inline] fn is_nan(self) -> bool { @@ -214,21 +184,6 @@ impl Float for f32 { } } - /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8) { - let bits: u32 = unsafe { mem::transmute(self) }; - let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; - let mantissa = if exponent == 0 { - (bits & 0x7fffff) << 1 - } else { - (bits & 0x7fffff) | 0x800000 - }; - // Exponent bias + mantissa shift - exponent -= 127 + 23; - (mantissa as u64, exponent, sign) - } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[inline] diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 991a85683494..7d6d6cef0497 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -143,36 +143,6 @@ pub mod consts { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] impl Float for f64 { - #[inline] - fn nan() -> f64 { - NAN - } - - #[inline] - fn infinity() -> f64 { - INFINITY - } - - #[inline] - fn neg_infinity() -> f64 { - NEG_INFINITY - } - - #[inline] - fn zero() -> f64 { - 0.0 - } - - #[inline] - fn neg_zero() -> f64 { - -0.0 - } - - #[inline] - fn one() -> f64 { - 1.0 - } - /// Returns `true` if the number is NaN. #[inline] fn is_nan(self) -> bool { @@ -214,21 +184,6 @@ impl Float for f64 { } } - /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8) { - let bits: u64 = unsafe { mem::transmute(self) }; - let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; - let mantissa = if exponent == 0 { - (bits & 0xfffffffffffff) << 1 - } else { - (bits & 0xfffffffffffff) | 0x10000000000000 - }; - // Exponent bias + mantissa shift - exponent -= 1023 + 52; - (mantissa, exponent, sign) - } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[inline] diff --git a/src/libcore/num/flt2dec/decoder.rs b/src/libcore/num/flt2dec/decoder.rs index 72529d3da01d..b779eefce575 100644 --- a/src/libcore/num/flt2dec/decoder.rs +++ b/src/libcore/num/flt2dec/decoder.rs @@ -67,7 +67,7 @@ impl DecodableFloat for f64 { /// Returns a sign (true when negative) and `FullDecoded` value /// from given floating point number. pub fn decode(v: T) -> (/*negative?*/ bool, FullDecoded) { - let (mant, exp, sign) = v.integer_decode2(); + let (mant, exp, sign) = v.integer_decode(); let even = (mant & 1) == 0; let decoded = match v.classify() { FpCategory::Nan => FullDecoded::Nan, @@ -81,7 +81,7 @@ pub fn decode(v: T) -> (/*negative?*/ bool, FullDecoded) { exp: exp, inclusive: even }) } FpCategory::Normal => { - let minnorm = ::min_pos_norm_value().integer_decode2(); + let minnorm = ::min_pos_norm_value().integer_decode(); if mant == minnorm.0 { // neighbors: (maxmant, exp - 1) -- (minnormmant, exp) -- (minnormmant + 1, exp) // where maxmant = minnormmant * 2 - 1 diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index f665cfdee77a..5c4a43fbd110 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -96,78 +96,6 @@ pub mod dec2flt; pub mod bignum; pub mod diy_float; -/// Types that have a "zero" value. -/// -/// This trait is intended for use in conjunction with `Add`, as an identity: -/// `x + T::zero() == x`. -#[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] -#[rustc_deprecated(since = "1.11.0", reason = "no longer used for \ - Iterator::sum")] -pub trait Zero: Sized { - /// The "zero" (usually, additive identity) for this type. - fn zero() -> Self; -} - -/// Types that have a "one" value. -/// -/// This trait is intended for use in conjunction with `Mul`, as an identity: -/// `x * T::one() == x`. -#[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] -#[rustc_deprecated(since = "1.11.0", reason = "no longer used for \ - Iterator::product")] -pub trait One: Sized { - /// The "one" (usually, multiplicative identity) for this type. - fn one() -> Self; -} - -macro_rules! zero_one_impl { - ($($t:ty)*) => ($( - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl Zero for $t { - #[inline] - fn zero() -> Self { 0 } - } - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl One for $t { - #[inline] - fn one() -> Self { 1 } - } - )*) -} -zero_one_impl! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } - -macro_rules! zero_one_impl_float { - ($($t:ty)*) => ($( - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl Zero for $t { - #[inline] - fn zero() -> Self { 0.0 } - } - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl One for $t { - #[inline] - fn one() -> Self { 1.0 } - } - )*) -} -zero_one_impl_float! { f32 f64 } - macro_rules! checked_op { ($U:ty, $op:path, $x:expr, $y:expr) => {{ let (result, overflowed) = unsafe { $op($x as $U, $y as $U) }; @@ -2525,49 +2453,6 @@ pub enum FpCategory { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] pub trait Float: Sized { - /// Returns the NaN value. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn nan() -> Self; - /// Returns the infinite value. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn infinity() -> Self; - /// Returns the negative infinite value. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn neg_infinity() -> Self; - /// Returns -0.0. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn neg_zero() -> Self; - /// Returns 0.0. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn zero() -> Self; - /// Returns 1.0. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn one() -> Self; - /// Returns `true` if this value is NaN and false otherwise. #[stable(feature = "core", since = "1.6.0")] fn is_nan(self) -> bool; @@ -2585,14 +2470,6 @@ pub trait Float: Sized { #[stable(feature = "core", since = "1.6.0")] fn classify(self) -> FpCategory; - /// Returns the mantissa, exponent and sign as integers, respectively. - #[unstable(feature = "float_extras", reason = "signature is undecided", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn integer_decode(self) -> (u64, i16, i8); - /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[stable(feature = "core", since = "1.6.0")] diff --git a/src/libcore/tests/num/dec2flt/rawfp.rs b/src/libcore/tests/num/dec2flt/rawfp.rs index 1a3533317dae..2b0afc402027 100644 --- a/src/libcore/tests/num/dec2flt/rawfp.rs +++ b/src/libcore/tests/num/dec2flt/rawfp.rs @@ -8,23 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::f32; use std::f64; -use std::mem; use core::num::diy_float::Fp; use core::num::dec2flt::rawfp::{fp_to_float, prev_float, next_float, round_normal}; +use core::num::dec2flt::rawfp::RawFloat; fn integer_decode(f: f64) -> (u64, i16, i8) { - let bits: u64 = unsafe { mem::transmute(f) }; - let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; - let mantissa = if exponent == 0 { - (bits & 0xfffffffffffff) << 1 - } else { - (bits & 0xfffffffffffff) | 0x10000000000000 - }; - // Exponent bias + mantissa shift - exponent -= 1023 + 52; - (mantissa, exponent, sign) + RawFloat::integer_decode(f) } #[test] @@ -152,3 +143,35 @@ fn next_float_monotonic() { } assert!(x > 0.5); } + +#[test] +fn test_f32_integer_decode() { + assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); + assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); + assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); + assert_eq!(0f32.integer_decode(), (0, -150, 1)); + assert_eq!((-0f32).integer_decode(), (0, -150, -1)); + assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1)); + assert_eq!(f32::NEG_INFINITY.integer_decode(), (8388608, 105, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = f32::NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (12582912, 105)); +} + +#[test] +fn test_f64_integer_decode() { + assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); + assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); + assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); + assert_eq!(0f64.integer_decode(), (0, -1075, 1)); + assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); + assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1)); + assert_eq!(f64::NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = f64::NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (6755399441055744, 972)); +} diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index fd9750dbfe3f..33133f6834b9 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -88,15 +88,17 @@ pub enum DepNode { // predicates for an item wind up in `ItemSignature`). AssociatedItems(D), ItemSignature(D), + IsForeignItem(D), TypeParamPredicates((D, D)), SizedConstraint(D), + DtorckConstraint(D), AdtDestructor(D), AssociatedItemDefIds(D), InherentImpls(D), TypeckBodiesKrate, TypeckTables(D), UsedTraitImports(D), - MonomorphicConstEval(D), + ConstEval(D), // The set of impls for a given trait. Ultimately, it would be // nice to get more fine-grained here (e.g., to include a @@ -171,6 +173,7 @@ impl DepNode { TransCrateItem, AssociatedItems, ItemSignature, + IsForeignItem, AssociatedItemDefIds, InherentImpls, TypeckTables, @@ -221,16 +224,18 @@ impl DepNode { TransInlinedItem(ref d) => op(d).map(TransInlinedItem), AssociatedItems(ref d) => op(d).map(AssociatedItems), ItemSignature(ref d) => op(d).map(ItemSignature), + IsForeignItem(ref d) => op(d).map(IsForeignItem), TypeParamPredicates((ref item, ref param)) => { Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param))))) } SizedConstraint(ref d) => op(d).map(SizedConstraint), + DtorckConstraint(ref d) => op(d).map(DtorckConstraint), AdtDestructor(ref d) => op(d).map(AdtDestructor), AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds), InherentImpls(ref d) => op(d).map(InherentImpls), TypeckTables(ref d) => op(d).map(TypeckTables), UsedTraitImports(ref d) => op(d).map(UsedTraitImports), - MonomorphicConstEval(ref d) => op(d).map(MonomorphicConstEval), + ConstEval(ref d) => op(d).map(ConstEval), TraitImpls(ref d) => op(d).map(TraitImpls), TraitItems(ref d) => op(d).map(TraitItems), ReprHints(ref d) => op(d).map(ReprHints), diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 2851191dc141..30e9f502abc8 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1829,6 +1829,7 @@ register_diagnostics! { E0314, // closure outlives stack frame E0315, // cannot invoke closure outside of its lifetime E0316, // nested quantification of lifetimes + E0320, // recursive overflow during dropck E0473, // dereference of reference outside its lifetime E0474, // captured variable `..` does not outlive the enclosing closure E0475, // index of slice outside its lifetime diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f55462fb5deb..16af98c20354 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -273,6 +273,12 @@ for ::middle::const_val::ConstVal<'tcx> { ConstVal::Bool(value) => { value.hash_stable(hcx, hasher); } + ConstVal::Char(value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Variant(def_id) => { + def_id.hash_stable(hcx, hasher); + } ConstVal::Function(def_id, substs) => { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); @@ -296,9 +302,6 @@ for ::middle::const_val::ConstVal<'tcx> { value.hash_stable(hcx, hasher); times.hash_stable(hcx, hasher); } - ConstVal::Char(value) => { - value.hash_stable(hcx, hasher); - } } } } diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 697a1ecadc45..922842136dc9 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::ReEmpty | ty::ReErased => { // replace all free regions with 'erased - self.tcx().mk_region(ty::ReErased) + self.tcx().types.re_erased } } } diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index 0bb9e2c7fa15..fa6775737b57 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -948,7 +948,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } else { // otherwise, we don't know what the free region is, // so we must conservatively say the LUB is static: - self.tcx.mk_region(ReStatic) + self.tcx.types.re_static } } @@ -971,7 +971,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { if a == b { a } else { - self.tcx.mk_region(ReStatic) + self.tcx.types.re_static } } } @@ -1018,7 +1018,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { fn construct_var_data(&self) -> Vec> { (0..self.num_vars() as usize) - .map(|_| Value(self.tcx.mk_region(ty::ReEmpty))) + .map(|_| Value(self.tcx.types.re_empty)) .collect() } @@ -1493,7 +1493,7 @@ fn lookup<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, -> &'tcx ty::Region { match values[rid.index as usize] { Value(r) => r, - ErrorValue => tcx.mk_region(ReStatic), // Previously reported error. + ErrorValue => tcx.types.re_static, // Previously reported error. } } diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index b4c5af940194..ec7b3c4dd8df 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -38,12 +38,13 @@ pub enum ConstVal<'tcx> { Str(InternedString), ByteStr(Rc>), Bool(bool), + Char(char), + Variant(DefId), Function(DefId, &'tcx Substs<'tcx>), Struct(BTreeMap>), Tuple(Vec>), Array(Vec>), Repeat(Box>, u64), - Char(char), } impl<'tcx> ConstVal<'tcx> { @@ -54,12 +55,13 @@ impl<'tcx> ConstVal<'tcx> { Str(_) => "string literal", ByteStr(_) => "byte string literal", Bool(_) => "boolean", + Char(..) => "char", + Variant(_) => "enum variant", Struct(_) => "struct", Tuple(_) => "tuple", Function(..) => "function definition", Array(..) => "array", Repeat(..) => "repeat", - Char(..) => "char", } } @@ -85,7 +87,6 @@ pub enum ErrKind<'tcx> { MissingStructField, NegateOn(ConstVal<'tcx>), NotOn(ConstVal<'tcx>), - CallOn(ConstVal<'tcx>), NonConstPath, UnimplementedConstVal(&'static str), @@ -145,7 +146,6 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { CannotCast => simple!("can't cast this type"), NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), NotOn(ref const_val) => simple!("not on {}", const_val.description()), - CallOn(ref const_val) => simple!("call on {}", const_val.description()), MissingStructField => simple!("nonexistent struct field"), NonConstPath => simple!("non-constant path in constant expression"), @@ -227,7 +227,8 @@ pub fn eval_length(tcx: TyCtxt, { let count_expr = &tcx.hir.body(count).value; let count_def_id = tcx.hir.body_owner_def_id(count); - match ty::queries::monomorphic_const_eval::get(tcx, count_expr.span, count_def_id) { + let substs = Substs::empty(); + match ty::queries::const_eval::get(tcx, count_expr.span, (count_def_id, substs)) { Ok(Integral(Usize(count))) => { let val = count.as_u64(tcx.sess.target.uint_type); assert_eq!(val as usize as u64, val); diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index cbbfeacadb40..3251addcb328 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -188,14 +188,13 @@ pub trait CrateStore { fn visibility(&self, def: DefId) -> ty::Visibility; fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap>; fn item_generics_cloned(&self, def: DefId) -> ty::Generics; - fn item_attrs(&self, def_id: DefId) -> Vec; + fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]>; fn fn_arg_names(&self, did: DefId) -> Vec; // trait info fn implementations_of_trait(&self, filter: Option) -> Vec; // impl info - fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity; fn impl_parent(&self, impl_def_id: DefId) -> Option; // trait/impl-item info @@ -250,8 +249,8 @@ pub trait CrateStore { fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro; // misc. metadata - fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option<&'tcx hir::Body>; + fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> &'tcx hir::Body; fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap; fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool; @@ -323,14 +322,13 @@ impl CrateStore for DummyCrateStore { } fn item_generics_cloned(&self, def: DefId) -> ty::Generics { bug!("item_generics_cloned") } - fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } + fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]> { bug!("item_attrs") } fn fn_arg_names(&self, did: DefId) -> Vec { bug!("fn_arg_names") } // trait info fn implementations_of_trait(&self, filter: Option) -> Vec { vec![] } // impl info - fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") } fn impl_parent(&self, def: DefId) -> Option { bug!("impl_parent") } // trait/impl-item info @@ -401,9 +399,9 @@ impl CrateStore for DummyCrateStore { fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") } // misc. metadata - fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option<&'tcx hir::Body> { - bug!("maybe_get_item_body") + fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> &'tcx hir::Body { + bug!("item_body") } fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap { bug!("item_body_nested_bodies") diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a10f52e2d4cc..8b2631591582 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -426,7 +426,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { hir::ExprMatch(ref discr, ref arms, _) => { let discr_cmt = return_if_err!(self.mc.cat_expr(&discr)); - let r = self.tcx().mk_region(ty::ReEmpty); + let r = self.tcx().types.re_empty; self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant); // treatment of the discriminant is handled while walking the arms. diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 32dfb63d6150..3b506d748ef7 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -223,9 +223,10 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { pub fn extract(attrs: &[ast::Attribute]) -> Option { for attribute in attrs { - match attribute.value_str() { - Some(value) if attribute.check_name("lang") => return Some(value), - _ => {} + if attribute.check_name("lang") { + if let Some(value) = attribute.value_str() { + return Some(value) + } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 7d3c17a04891..188fcc914149 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -871,8 +871,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // we can promote to a constant, otherwise equal to enclosing temp // lifetime. let (re, old_re) = if promotable { - (self.tcx().mk_region(ty::ReStatic), - self.tcx().mk_region(ty::ReStatic)) + (self.tcx().types.re_static, + self.tcx().types.re_static) } else { self.temporary_scope(id) }; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 63455f94cedf..be4ec16cd63a 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -18,6 +18,7 @@ use hir::map as hir_map; use hir::def::Def; use hir::def_id::{DefId, CrateNum}; +use std::rc::Rc; use ty::{self, TyCtxt}; use ty::maps::Providers; use middle::privacy; @@ -362,11 +363,11 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, } } -pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { +pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc { ty::queries::reachable_set::get(tcx, DUMMY_SP, LOCAL_CRATE) } -fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> NodeSet { +fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> Rc { debug_assert!(crate_num == LOCAL_CRATE); let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); @@ -411,7 +412,7 @@ fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> reachable_context.propagate(); // Return the set of reachable symbols. - reachable_context.reachable_symbols + Rc::new(reachable_context.reachable_symbols) } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9ff64b295b76..bfb72b5df7b2 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1307,10 +1307,11 @@ fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { write!(fmt, "b\"{}\"", escaped) } Bool(b) => write!(fmt, "{:?}", b), + Char(c) => write!(fmt, "{:?}", c), + Variant(def_id) | Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), Struct(_) | Tuple(_) | Array(_) | Repeat(..) => bug!("ConstVal `{:?}` should not be in MIR", const_val), - Char(c) => write!(fmt, "{:?}", c), } } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index d49affa3e872..908bb337fa18 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -443,7 +443,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( // Otherwise, we have something of the form // `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`. Some(t_a) => { - let r_static = selcx.tcx().mk_region(ty::ReStatic); + let r_static = selcx.tcx().types.re_static; register_region_obligation(t_a, r_static, obligation.cause.clone(), region_obligations); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 0ff379b30ffd..281c1e253798 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -55,6 +55,7 @@ mod object_safety; mod select; mod specialize; mod structural_impls; +pub mod trans; mod util; /// An `Obligation` represents some trait reference (e.g. `int:Eq`) for @@ -628,7 +629,7 @@ pub fn get_vtable_methods<'a, 'tcx>( // the method may have some early-bound lifetimes, add // regions for those let substs = Substs::for_item(tcx, def_id, - |_, _| tcx.mk_region(ty::ReErased), + |_, _| tcx.types.re_erased, |def, _| trait_ref.substs().type_for_def(def)); // the trait type may have higher-ranked lifetimes in it; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 70ddcff5181b..207016170faa 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -943,17 +943,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); i += 1; + + // If there are *STILL* multiple candidates, give up + // and report ambiguity. + if i > 1 { + debug!("multiple matches, ambig"); + return Ok(None); + } } } } - // If there are *STILL* multiple candidates, give up and - // report ambiguity. - if candidates.len() > 1 { - debug!("multiple matches, ambig"); - return Ok(None); - } - // If there are *NO* candidates, then there are no impls -- // that we know of, anyway. Note that in the case where there // are unbound type variables within the obligation, it might @@ -1300,8 +1300,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .iter() .filter_map(|o| o.to_opt_poly_trait_ref()); + // micro-optimization: filter out predicates relating to different + // traits. let matching_bounds = - all_bounds.filter( + all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); + + let matching_bounds = + matching_bounds.filter( |bound| self.evaluate_where_clause(stack, bound.clone()).may_apply()); let param_candidates = @@ -1790,11 +1795,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyAdt(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here - Where(ty::Binder(match sized_crit.sty { - ty::TyTuple(tys, _) => tys.to_vec().subst(self.tcx(), substs), - ty::TyBool => vec![], - _ => vec![sized_crit.subst(self.tcx(), substs)] - })) + Where(ty::Binder( + sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect() + )) } ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None, diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs new file mode 100644 index 000000000000..e38306aed2a9 --- /dev/null +++ b/src/librustc/traits/trans/mod.rs @@ -0,0 +1,212 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This file contains various trait resolution methods used by trans. +// They all assume regions can be erased and monomorphic types. It +// seems likely that they should eventually be merged into more +// general routines. + +use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; +use hir::def_id::DefId; +use infer::TransNormalize; +use std::cell::RefCell; +use std::marker::PhantomData; +use syntax::ast; +use syntax_pos::Span; +use traits::{FulfillmentContext, Obligation, ObligationCause, Reveal, SelectionContext, Vtable}; +use ty::{self, Ty, TyCtxt}; +use ty::subst::{Subst, Substs}; +use ty::fold::{TypeFoldable, TypeFolder}; +use util::common::MemoizationMap; + +impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { + /// Attempts to resolve an obligation to a vtable.. The result is + /// a shallow vtable resolution -- meaning that we do not + /// (necessarily) resolve all nested obligations on the impl. Note + /// that type check should guarantee to us that all nested + /// obligations *could be* resolved if we wanted to. + pub fn trans_fulfill_obligation(self, + span: Span, + trait_ref: ty::PolyTraitRef<'tcx>) + -> Vtable<'tcx, ()> + { + // Remove any references to regions; this helps improve caching. + let trait_ref = self.erase_regions(&trait_ref); + + self.trans_trait_caches.trait_cache.memoize(trait_ref, || { + debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", + trait_ref, trait_ref.def_id()); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + self.infer_ctxt((), Reveal::All).enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = ObligationCause::misc(span, + ast::DUMMY_NODE_ID); + let obligation = Obligation::new(obligation_cause, + trait_ref.to_poly_trait_predicate()); + + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => { + // Ambiguity can happen when monomorphizing during trans + // expands to some humongo type that never occurred + // statically -- this humongo type can then overflow, + // leading to an ambiguous result. So report this as an + // overflow bug, since I believe this is the only case + // where ambiguity can result. + debug!("Encountered ambiguity selecting `{:?}` during trans, \ + presuming due to overflow", + trait_ref); + self.sess.span_fatal(span, + "reached the recursion limit during monomorphization \ + (selection ambiguity)"); + } + Err(e) => { + span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans", + e, trait_ref) + } + }; + + debug!("fulfill_obligation: selection={:?}", selection); + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut fulfill_cx = FulfillmentContext::new(); + let vtable = selection.map(|predicate| { + debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable); + + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); + vtable + }) + }) + } + + /// Monomorphizes a type from the AST by first applying the in-scope + /// substitutions and then normalizing any associated types. + pub fn trans_apply_param_substs(self, + param_substs: &Substs<'tcx>, + value: &T) + -> T + where T: TransNormalize<'tcx> + { + debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); + let substituted = value.subst(self, param_substs); + let substituted = self.erase_regions(&substituted); + AssociatedTypeNormalizer::new(self).fold(&substituted) + } +} + +struct AssociatedTypeNormalizer<'a, 'gcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'gcx>, +} + +impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> { + fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> Self { + AssociatedTypeNormalizer { tcx } + } + + fn fold>(&mut self, value: &T) -> T { + if !value.has_projection_types() { + value.clone() + } else { + value.fold_with(self) + } + } +} + +impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> { + fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { + if !ty.has_projection_types() { + ty + } else { + self.tcx.trans_trait_caches.project_cache.memoize(ty, || { + debug!("AssociatedTypeNormalizer: ty={:?}", ty); + self.tcx.normalize_associated_type(&ty) + }) + } + } +} + +/// Specializes caches used in trans -- in particular, they assume all +/// types are fully monomorphized and that free regions can be erased. +pub struct TransTraitCaches<'tcx> { + trait_cache: RefCell>>, + project_cache: RefCell>>, +} + +impl<'tcx> TransTraitCaches<'tcx> { + pub fn new(graph: DepGraph) -> Self { + TransTraitCaches { + trait_cache: RefCell::new(DepTrackingMap::new(graph.clone())), + project_cache: RefCell::new(DepTrackingMap::new(graph)), + } + } +} + +// Implement DepTrackingMapConfig for `trait_cache` +pub struct TraitSelectionCache<'tcx> { + data: PhantomData<&'tcx ()> +} + +impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { + type Key = ty::PolyTraitRef<'tcx>; + type Value = Vtable<'tcx, ()>; + fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode { + key.to_poly_trait_predicate().dep_node() + } +} + +// # Global Cache + +pub struct ProjectionCache<'gcx> { + data: PhantomData<&'gcx ()> +} + +impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { + type Key = Ty<'gcx>; + type Value = Ty<'gcx>; + fn to_dep_node(key: &Self::Key) -> DepNode { + // Ideally, we'd just put `key` into the dep-node, but we + // can't put full types in there. So just collect up all the + // def-ids of structs/enums as well as any traits that we + // project out of. It doesn't matter so much what we do here, + // except that if we are too coarse, we'll create overly + // coarse edges between impls and the trans. For example, if + // we just used the def-id of things we are projecting out of, + // then the key for `::T` and `::T` would both share a dep-node + // (`TraitSelect(SomeTrait)`), and hence the impls for both + // `Foo` and `Bar` would be considered inputs. So a change to + // `Bar` would affect things that just normalized `Foo`. + // Anyway, this heuristic is not ideal, but better than + // nothing. + let def_ids: Vec = + key.walk() + .filter_map(|t| match t.sty { + ty::TyAdt(adt_def, _) => Some(adt_def.did), + ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), + _ => None, + }) + .collect(); + + DepNode::ProjectionCache { def_ids: def_ids } + } +} + diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a41629258716..b20ac8ddbfc8 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -190,6 +190,10 @@ pub struct CommonTypes<'tcx> { pub f64: Ty<'tcx>, pub never: Ty<'tcx>, pub err: Ty<'tcx>, + + pub re_empty: &'tcx Region, + pub re_static: &'tcx Region, + pub re_erased: &'tcx Region, } #[derive(RustcEncodable, RustcDecodable)] @@ -360,6 +364,14 @@ impl<'tcx> TypeckTables<'tcx> { impl<'tcx> CommonTypes<'tcx> { fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { let mk = |sty| interners.intern_ty(sty, None); + let mk_region = |r| { + if let Some(r) = interners.region.borrow().get(&r) { + return r.0; + } + let r = interners.arena.alloc(r); + interners.region.borrow_mut().insert(Interned(r)); + &*r + }; CommonTypes { bool: mk(TyBool), char: mk(TyChar), @@ -379,6 +391,10 @@ impl<'tcx> CommonTypes<'tcx> { u128: mk(TyUint(ast::UintTy::U128)), f32: mk(TyFloat(ast::FloatTy::F32)), f64: mk(TyFloat(ast::FloatTy::F64)), + + re_empty: mk_region(Region::ReEmpty), + re_static: mk_region(Region::ReStatic), + re_erased: mk_region(Region::ReErased), } } } @@ -407,6 +423,8 @@ pub struct GlobalCtxt<'tcx> { pub specializes_cache: RefCell, + pub trans_trait_caches: traits::trans::TransTraitCaches<'tcx>, + pub dep_graph: DepGraph, /// Common types, pre-interned for your convenience. @@ -689,6 +707,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { providers[LOCAL_CRATE] = local_providers; tls::enter_global(GlobalCtxt { sess: s, + trans_trait_caches: traits::trans::TransTraitCaches::new(dep_graph.clone()), specializes_cache: RefCell::new(traits::SpecializesCache::new()), global_arenas: arenas, global_interners: interners, @@ -1229,7 +1248,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_static_str(self) -> Ty<'tcx> { - self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str()) + self.mk_imm_ref(self.types.re_static, self.mk_str()) } pub fn mk_adt(self, def: &'tcx AdtDef, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index e29653c9e88a..969d040e7a6e 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -410,7 +410,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn erase_late_bound_regions(self, value: &Binder) -> T where T : TypeFoldable<'tcx> { - self.replace_late_bound_regions(value, |_| self.mk_region(ty::ReErased)).0 + self.replace_late_bound_regions(value, |_| self.types.re_erased).0 } /// Rewrite any late-bound regions so that they are anonymous. Region numbers are @@ -538,7 +538,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // whenever a substitution occurs. match *r { ty::ReLateBound(..) => r, - _ => self.tcx().mk_region(ty::ReErased) + _ => self.tcx().types.re_erased } } } @@ -565,6 +565,22 @@ pub fn shift_region(region: ty::Region, amount: u32) -> ty::Region { } } +pub fn shift_region_ref<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + region: &'tcx ty::Region, + amount: u32) + -> &'tcx ty::Region +{ + match region { + &ty::ReLateBound(debruijn, br) if amount > 0 => { + tcx.mk_region(ty::ReLateBound(debruijn.shifted(amount), br)) + } + _ => { + region + } + } +} + pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>, amount: u32, value: &T) -> T where T: TypeFoldable<'tcx> @@ -573,7 +589,7 @@ pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>, value, amount); value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| { - tcx.mk_region(shift_region(*region, amount)) + shift_region_ref(tcx, region, amount) })) } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 67287f1b4ff7..cfff3d0e5736 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -13,10 +13,7 @@ use hir::def_id::DefId; use ty::{self, Ty, TypeFoldable, Substs}; use util::ppaux; -use std::borrow::Cow; use std::fmt; -use syntax::ast; - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Instance<'tcx> { @@ -59,7 +56,7 @@ impl<'tcx> InstanceDef<'tcx> { } #[inline] - pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Cow<'tcx, [ast::Attribute]> { + pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> { tcx.get_attrs(self.def_id()) } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 6a206640b3ba..49cc4e7c993a 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -822,7 +822,7 @@ impl<'a, 'gcx, 'tcx> Struct { } (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => { - let normalized = normalize_associated_type(infcx, ty); + let normalized = infcx.normalize_projections(ty); if ty == normalized { return Ok(None); } @@ -1067,28 +1067,6 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { } } -/// Helper function for normalizing associated types in an inference context. -fn normalize_associated_type<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - ty: Ty<'gcx>) - -> Ty<'gcx> { - if !ty.has_projection_types() { - return ty; - } - - let mut selcx = traits::SelectionContext::new(infcx); - let cause = traits::ObligationCause::dummy(); - let traits::Normalized { value: result, obligations } = - traits::normalize(&mut selcx, cause, &ty); - - let mut fulfill_cx = traits::FulfillmentContext::new(); - - for obligation in obligations { - fulfill_cx.register_predicate_obligation(infcx, obligation); - } - - infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) -} - impl<'a, 'gcx, 'tcx> Layout { pub fn compute_uncached(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>) @@ -1100,7 +1078,7 @@ impl<'a, 'gcx, 'tcx> Layout { let ptr_layout = |pointee: Ty<'gcx>| { let non_zero = !ty.is_unsafe_ptr(); - let pointee = normalize_associated_type(infcx, pointee); + let pointee = infcx.normalize_projections(pointee); if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) { Ok(Scalar { value: Pointer, non_zero: non_zero }) } else { @@ -1494,7 +1472,7 @@ impl<'a, 'gcx, 'tcx> Layout { // Types with no meaningful known layout. ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = normalize_associated_type(infcx, ty); + let normalized = infcx.normalize_projections(ty); if ty == normalized { return Err(LayoutError::Unknown(ty)); } @@ -1812,7 +1790,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { } ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = normalize_associated_type(infcx, ty); + let normalized = infcx.normalize_projections(ty); if ty == normalized { Err(err) } else { @@ -1882,13 +1860,14 @@ pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> { type TyLayout; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout; + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>; } impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { type TyLayout = Result, LayoutError<'gcx>>; fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout { - let ty = normalize_associated_type(self, ty); + let ty = self.normalize_projections(ty); Ok(TyLayout { ty: ty, @@ -1896,6 +1875,25 @@ impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { variant_index: None }) } + + fn normalize_projections(self, ty: Ty<'gcx>) -> Ty<'gcx> { + if !ty.has_projection_types() { + return ty; + } + + let mut selcx = traits::SelectionContext::new(self); + let cause = traits::ObligationCause::dummy(); + let traits::Normalized { value: result, obligations } = + traits::normalize(&mut selcx, cause, &ty); + + let mut fulfill_cx = traits::FulfillmentContext::new(); + + for obligation in obligations { + fulfill_cx.register_predicate_obligation(self, obligation); + } + + self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) + } } impl<'a, 'tcx> TyLayout<'tcx> { @@ -2019,6 +2017,6 @@ impl<'a, 'tcx> TyLayout<'tcx> { } pub fn field>(&self, cx: C, i: usize) -> C::TyLayout { - cx.layout_of(self.field_type(cx, i)) + cx.layout_of(cx.normalize_projections(self.field_type(cx, i))) } } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index e9eb5e97582b..4595a8c4f778 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -10,11 +10,13 @@ use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use hir; use middle::const_val; use middle::privacy::AccessLevels; use mir; use session::CompileResult; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; +use ty::subst::Substs; use util::nodemap::NodeSet; use rustc_data_structures::indexed_vec::IndexVec; @@ -73,6 +75,15 @@ impl Key for (CrateNum, DefId) { } } +impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) { + fn map_crate(&self) -> CrateNum { + self.0.krate + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.0.default_span(tcx) + } +} + trait Value<'tcx>: Sized { fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; } @@ -96,6 +107,13 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> { } } + +impl<'tcx> Value<'tcx> for ty::DtorckConstraint<'tcx> { + fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self { + Self::empty() + } +} + pub struct CycleError<'a, 'tcx: 'a> { span: Span, cycle: RefMut<'a, [(Span, Query<'tcx>)]>, @@ -216,6 +234,13 @@ impl<'tcx> QueryDescription for queries::reachable_set<'tcx> { } } +impl<'tcx> QueryDescription for queries::const_eval<'tcx> { + fn describe(tcx: TyCtxt, (def_id, _): (DefId, &'tcx Substs<'tcx>)) -> String { + format!("const-evaluating `{}`", + tcx.item_path_str(def_id)) + } +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* @@ -378,7 +403,11 @@ define_maps! { <'tcx> pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef, pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef, pub adt_destructor: AdtDestructor(DefId) -> Option, - pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>, + pub adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], + pub adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>, + + /// True if this is a foreign item (i.e., linked via `extern { ... }`). + pub is_foreign_item: IsForeignItem(DefId) -> bool, /// Maps from def-id of a type or region parameter to its /// (inferred) variance. @@ -391,6 +420,7 @@ define_maps! { <'tcx> pub associated_item: AssociatedItems(DefId) -> ty::AssociatedItem, pub impl_trait_ref: ItemSignature(DefId) -> Option>, + pub impl_polarity: ItemSignature(DefId) -> hir::ImplPolarity, /// Maps a DefId of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. @@ -441,16 +471,17 @@ define_maps! { <'tcx> /// (Defined only for LOCAL_CRATE) pub crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (), - /// Results of evaluating monomorphic constants embedded in - /// other items, such as enum variant explicit discriminants. - pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> const_val::EvalResult<'tcx>, + /// Results of evaluating const items or constants embedded in + /// other items (such as enum variant explicit discriminants). + pub const_eval: const_eval_dep_node((DefId, &'tcx Substs<'tcx>)) + -> const_val::EvalResult<'tcx>, /// Performs the privacy check and computes "access levels". pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc, - pub reachable_set: reachability_dep_node(CrateNum) -> NodeSet, + pub reachable_set: reachability_dep_node(CrateNum) -> Rc, - pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell> + pub mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell> } fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode { @@ -465,10 +496,14 @@ fn reachability_dep_node(_: CrateNum) -> DepNode { DepNode::Reachability } -fn mir_shim(instance: ty::InstanceDef) -> DepNode { +fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode { instance.dep_node() } fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode { DepNode::TypeckBodiesKrate } + +fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode { + DepNode::ConstEval(def_id) +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5be73542b931..352b6ab1d356 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -31,14 +31,15 @@ use ty; use ty::subst::{Subst, Substs}; use ty::util::IntTypeExt; use ty::walk::TypeWalker; -use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; +use util::common::ErrorReported; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; use serialize::{self, Encodable, Encoder}; -use std::borrow::Cow; use std::cell::{Cell, RefCell, Ref}; use std::collections::BTreeMap; use std::cmp; use std::hash::{Hash, Hasher}; +use std::iter::FromIterator; use std::ops::Deref; use std::rc::Rc; use std::slice; @@ -115,7 +116,7 @@ mod sty; #[derive(Clone)] pub struct CrateAnalysis { pub access_levels: Rc, - pub reachable: NodeSet, + pub reachable: Rc, pub name: String, pub glob_map: Option, } @@ -1333,17 +1334,6 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { pub struct Destructor { /// The def-id of the destructor method pub did: DefId, - /// Invoking the destructor of a dtorck type during usual cleanup - /// (e.g. the glue emitted for stack unwinding) requires all - /// lifetimes in the type-structure of `adt` to strictly outlive - /// the adt value itself. - /// - /// If `adt` is not dtorck, then the adt's destructor can be - /// invoked even when there are lifetimes in the type-structure of - /// `adt` that do not strictly outlive the adt value itself. - /// (This allows programs to make cyclic structures without - /// resorting to unsafe means; see RFCs 769 and 1238). - pub is_dtorck: bool, } bitflags! { @@ -1610,14 +1600,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } - /// Returns whether this is a dtorck type. If this returns - /// true, this type being safe for destruction requires it to be - /// alive; Otherwise, only the contents are required to be. - #[inline] - pub fn is_dtorck(&'gcx self, tcx: TyCtxt) -> bool { - self.destructor(tcx).map_or(false, |d| d.is_dtorck) - } - /// Returns whether this type is #[fundamental] for the purposes /// of coherence checking. #[inline] @@ -1694,6 +1676,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } + #[inline] pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> impl Iterator + 'a { let repr_type = self.repr.discr_type(); @@ -1702,11 +1685,18 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.variants.iter().map(move |v| { let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr()); if let VariantDiscr::Explicit(expr_did) = v.discr { - match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) { + let substs = Substs::empty(); + match queries::const_eval::get(tcx, DUMMY_SP, (expr_did, substs)) { Ok(ConstVal::Integral(v)) => { discr = v; } - _ => {} + err => { + if !expr_did.is_local() { + span_bug!(tcx.def_span(expr_did), + "variant discriminant evaluation succeeded \ + in its crate but failed locally: {:?}", err); + } + } } } prev_discr = Some(discr); @@ -1734,12 +1724,21 @@ impl<'a, 'gcx, 'tcx> AdtDef { explicit_index -= distance; } ty::VariantDiscr::Explicit(expr_did) => { - match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) { + let substs = Substs::empty(); + match queries::const_eval::get(tcx, DUMMY_SP, (expr_did, substs)) { Ok(ConstVal::Integral(v)) => { explicit_value = v; break; } - _ => { + err => { + if !expr_did.is_local() { + span_bug!(tcx.def_span(expr_did), + "variant discriminant evaluation succeeded \ + in its crate but failed locally: {:?}", err); + } + if explicit_index == 0 { + break; + } explicit_index -= 1; } } @@ -1764,16 +1763,9 @@ impl<'a, 'gcx, 'tcx> AdtDef { queries::adt_destructor::get(tcx, DUMMY_SP, self.did) } - /// Returns a simpler type such that `Self: Sized` if and only + /// Returns a list of types such that `Self: Sized` if and only /// if that type is Sized, or `TyErr` if this type is recursive. /// - /// HACK: instead of returning a list of types, this function can - /// return a tuple. In that case, the result is Sized only if - /// all elements of the tuple are Sized. - /// - /// This is generally the `struct_tail` if this is a struct, or a - /// tuple of them if this is an enum. - /// /// Oddly enough, checking that the sized-constraint is Sized is /// actually more expressive than checking all members: /// the Sized trait is inductive, so an associated type that references @@ -1781,16 +1773,16 @@ impl<'a, 'gcx, 'tcx> AdtDef { /// /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer, e.g. issue #31299. - pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { + pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] { match queries::adt_sized_constraint::try_get(tcx, DUMMY_SP, self.did) { - Ok(ty) => ty, + Ok(tys) => tys, Err(_) => { debug!("adt_sized_constraint: {:?} is recursive", self); // This should be reported as an error by `check_representable`. // // Consider the type as Sized in the meanwhile to avoid // further errors. - tcx.types.err + tcx.intern_type_list(&[tcx.types.err]) } } } @@ -1820,18 +1812,13 @@ impl<'a, 'gcx, 'tcx> AdtDef { TyAdt(adt, substs) => { // recursive case - let adt_ty = - adt.sized_constraint(tcx) - .subst(tcx, substs); + let adt_tys = adt.sized_constraint(tcx); debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", - ty, adt_ty); - if let ty::TyTuple(ref tys, _) = adt_ty.sty { - tys.iter().flat_map(|ty| { - self.sized_constraint_for_ty(tcx, ty) - }).collect() - } else { - self.sized_constraint_for_ty(tcx, adt_ty) - } + ty, adt_tys); + adt_tys.iter() + .map(|ty| ty.subst(tcx, substs)) + .flat_map(|ty| self.sized_constraint_for_ty(tcx, ty)) + .collect() } TyProjection(..) | TyAnon(..) => { @@ -2036,6 +2023,23 @@ impl BorrowKind { } } +#[derive(Debug, Clone)] +pub enum Attributes<'gcx> { + Owned(Rc<[ast::Attribute]>), + Borrowed(&'gcx [ast::Attribute]) +} + +impl<'gcx> ::std::ops::Deref for Attributes<'gcx> { + type Target = [ast::Attribute]; + + fn deref(&self) -> &[ast::Attribute] { + match self { + &Attributes::Owned(ref data) => &data, + &Attributes::Borrowed(data) => data + } + } +} + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn body_tables(self, body: hir::BodyId) -> &'gcx TypeckTables<'gcx> { self.item_tables(self.hir.body_owner_def_id(body)) @@ -2133,14 +2137,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn trait_impl_polarity(self, id: DefId) -> hir::ImplPolarity { - if let Some(id) = self.hir.as_local_node_id(id) { - match self.hir.expect_item(id).node { - hir::ItemImpl(_, polarity, ..) => polarity, - ref item => bug!("trait_impl_polarity: {:?} not an impl", item) - } - } else { - self.sess.cstore.impl_polarity(id) - } + queries::impl_polarity::get(self, DUMMY_SP, id) } pub fn trait_relevant_for_never(self, did: DefId) -> bool { @@ -2389,11 +2386,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } /// Get the attributes of a definition. - pub fn get_attrs(self, did: DefId) -> Cow<'gcx, [ast::Attribute]> { + pub fn get_attrs(self, did: DefId) -> Attributes<'gcx> { if let Some(id) = self.hir.as_local_node_id(did) { - Cow::Borrowed(self.hir.attrs(id)) + Attributes::Borrowed(self.hir.attrs(id)) } else { - Cow::Owned(self.sess.cstore.item_attrs(did)) + Attributes::Owned(self.sess.cstore.item_attrs(did)) } } @@ -2499,15 +2496,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Construct a parameter environment suitable for static contexts or other contexts where there /// are no free type/lifetime parameters in scope. pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> { - - // for an empty parameter environment, there ARE no free - // regions, so it shouldn't matter what we use for the free id - let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID); ty::ParameterEnvironment { free_substs: self.intern_substs(&[]), caller_bounds: Vec::new(), - implicit_region_bound: self.mk_region(ty::ReEmpty), - free_id_outlive: free_id_outlive, + implicit_region_bound: self.types.re_empty, + // for an empty parameter environment, there ARE no free + // regions, so it shouldn't matter what we use for the free id + free_id_outlive: ROOT_CODE_EXTENT, is_copy_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()), is_freeze_cache: RefCell::new(FxHashMap()), @@ -2673,13 +2668,7 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) /// Calculates the Sized-constraint. /// -/// As the Sized-constraint of enums can be a *set* of types, -/// the Sized-constraint may need to be a set also. Because introducing -/// a new type of IVar is currently a complex affair, the Sized-constraint -/// may be a tuple. -/// -/// In fact, there are only a few options for the constraint: -/// - `bool`, if the type is always Sized +/// In fact, there are only a few options for the types in the constraint: /// - an obviously-unsized type /// - a type parameter or projection whose Sizedness can't be known /// - a tuple of type parameters or projections, if there are multiple @@ -2688,26 +2677,50 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) /// check should catch this case. fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Ty<'tcx> { + -> &'tcx [Ty<'tcx>] { let def = tcx.lookup_adt_def(def_id); - let tys: Vec<_> = def.variants.iter().flat_map(|v| { + let result = tcx.intern_type_list(&def.variants.iter().flat_map(|v| { v.fields.last() }).flat_map(|f| { - let ty = tcx.item_type(f.did); - def.sized_constraint_for_ty(tcx, ty) - }).collect(); + def.sized_constraint_for_ty(tcx, tcx.item_type(f.did)) + }).collect::>()); - let ty = match tys.len() { - _ if tys.references_error() => tcx.types.err, - 0 => tcx.types.bool, - 1 => tys[0], - _ => tcx.intern_tup(&tys[..], false) - }; + debug!("adt_sized_constraint: {:?} => {:?}", def, result); - debug!("adt_sized_constraint: {:?} => {:?}", def, ty); + result +} - ty +/// Calculates the dtorck constraint for a type. +fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> DtorckConstraint<'tcx> { + let def = tcx.lookup_adt_def(def_id); + let span = tcx.def_span(def_id); + debug!("dtorck_constraint: {:?}", def); + + if def.is_phantom_data() { + let result = DtorckConstraint { + outlives: vec![], + dtorck_types: vec![ + tcx.mk_param_from_def(&tcx.item_generics(def_id).types[0]) + ] + }; + debug!("dtorck_constraint: {:?} => {:?}", def, result); + return result; + } + + let mut result = def.all_fields() + .map(|field| tcx.item_type(field.did)) + .map(|fty| tcx.dtorck_constraint_for_ty(span, fty, 0, fty)) + .collect::>() + .unwrap_or(DtorckConstraint::empty()); + result.outlives.extend(tcx.destructor_constraints(def)); + result.dedup(); + + debug!("dtorck_constraint: {:?} => {:?}", def, result); + + result } fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -2738,6 +2751,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { associated_item, associated_item_def_ids, adt_sized_constraint, + adt_dtorck_constraint, ..*providers }; } @@ -2745,6 +2759,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { pub fn provide_extern(providers: &mut ty::maps::Providers) { *providers = ty::maps::Providers { adt_sized_constraint, + adt_dtorck_constraint, ..*providers }; } @@ -2761,3 +2776,45 @@ pub struct CrateInherentImpls { pub inherent_impls: DefIdMap>>, } +/// A set of constraints that need to be satisfied in order for +/// a type to be valid for destruction. +#[derive(Clone, Debug)] +pub struct DtorckConstraint<'tcx> { + /// Types that are required to be alive in order for this + /// type to be valid for destruction. + pub outlives: Vec>, + /// Types that could not be resolved: projections and params. + pub dtorck_types: Vec>, +} + +impl<'tcx> FromIterator> for DtorckConstraint<'tcx> +{ + fn from_iter>>(iter: I) -> Self { + let mut result = Self::empty(); + + for constraint in iter { + result.outlives.extend(constraint.outlives); + result.dtorck_types.extend(constraint.dtorck_types); + } + + result + } +} + + +impl<'tcx> DtorckConstraint<'tcx> { + fn empty() -> DtorckConstraint<'tcx> { + DtorckConstraint { + outlives: vec![], + dtorck_types: vec![] + } + } + + fn dedup<'a>(&mut self) { + let mut outlives = FxHashSet(); + let mut dtorck_types = FxHashSet(); + + self.outlives.retain(|&val| outlives.replace(val).is_none()); + self.dtorck_types.retain(|&val| dtorck_types.replace(val).is_none()); + } +} diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 0a2cc1c30f40..14aebdf8418f 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -539,6 +539,9 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { } fn shift_region_through_binders(&self, region: &'tcx ty::Region) -> &'tcx ty::Region { + if self.region_binders_passed == 0 || !region.has_escaping_regions() { + return region; + } self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed)) } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 49d79f6545e2..f68cf6f97f85 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -19,6 +19,7 @@ use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; use ty::ParameterEnvironment; use ty::fold::TypeVisitor; use ty::layout::{Layout, LayoutError}; +use ty::subst::{Subst, Kind}; use ty::TypeVariants::*; use util::common::ErrorReported; use util::nodemap::{FxHashMap, FxHashSet}; @@ -385,6 +386,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { None => return None, }; + Some(ty::Destructor { did: dtor_did }) + } + + /// Return the set of types that are required to be alive in + /// order to run the destructor of `def` (see RFCs 769 and + /// 1238). + /// + /// Note that this returns only the constraints for the + /// destructor of `def` itself. For the destructors of the + /// contents, you need `adt_dtorck_constraint`. + pub fn destructor_constraints(self, def: &'tcx ty::AdtDef) + -> Vec> + { + let dtor = match def.destructor(self) { + None => { + debug!("destructor_constraints({:?}) - no dtor", def.did); + return vec![] + } + Some(dtor) => dtor.did + }; + // RFC 1238: if the destructor method is tagged with the // attribute `unsafe_destructor_blind_to_params`, then the // compiler is being instructed to *assume* that the @@ -394,11 +416,147 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Such access can be in plain sight (e.g. dereferencing // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden // (e.g. calling `foo.0.clone()` of `Foo`). - let is_dtorck = !self.has_attr(dtor_did, "unsafe_destructor_blind_to_params"); - Some(ty::Destructor { did: dtor_did, is_dtorck: is_dtorck }) + if self.has_attr(dtor, "unsafe_destructor_blind_to_params") { + debug!("destructor_constraint({:?}) - blind", def.did); + return vec![]; + } + + let impl_def_id = self.associated_item(dtor).container.id(); + let impl_generics = self.item_generics(impl_def_id); + + // We have a destructor - all the parameters that are not + // pure_wrt_drop (i.e, don't have a #[may_dangle] attribute) + // must be live. + + // We need to return the list of parameters from the ADTs + // generics/substs that correspond to impure parameters on the + // impl's generics. This is a bit ugly, but conceptually simple: + // + // Suppose our ADT looks like the following + // + // struct S(X, Y, Z); + // + // and the impl is + // + // impl<#[may_dangle] P0, P1, P2> Drop for S + // + // We want to return the parameters (X, Y). For that, we match + // up the item-substs with the substs on the impl ADT, + // , and then look up which of the impl substs refer to + // parameters marked as pure. + + let impl_substs = match self.item_type(impl_def_id).sty { + ty::TyAdt(def_, substs) if def_ == def => substs, + _ => bug!() + }; + + let item_substs = match self.item_type(def.did).sty { + ty::TyAdt(def_, substs) if def_ == def => substs, + _ => bug!() + }; + + let result = item_substs.iter().zip(impl_substs.iter()) + .filter(|&(_, &k)| { + if let Some(&ty::Region::ReEarlyBound(ref ebr)) = k.as_region() { + !impl_generics.region_param(ebr).pure_wrt_drop + } else if let Some(&ty::TyS { + sty: ty::TypeVariants::TyParam(ref pt), .. + }) = k.as_type() { + !impl_generics.type_param(pt).pure_wrt_drop + } else { + // not a type or region param - this should be reported + // as an error. + false + } + }).map(|(&item_param, _)| item_param).collect(); + debug!("destructor_constraint({:?}) = {:?}", def.did, result); + result } - pub fn closure_base_def_id(&self, def_id: DefId) -> DefId { + /// Return a set of constraints that needs to be satisfied in + /// order for `ty` to be valid for destruction. + pub fn dtorck_constraint_for_ty(self, + span: Span, + for_ty: Ty<'tcx>, + depth: usize, + ty: Ty<'tcx>) + -> Result, ErrorReported> + { + debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", + span, for_ty, depth, ty); + + if depth >= self.sess.recursion_limit.get() { + let mut err = struct_span_err!( + self.sess, span, E0320, + "overflow while adding drop-check rules for {}", for_ty); + err.note(&format!("overflowed on {}", ty)); + err.emit(); + return Err(ErrorReported); + } + + let result = match ty.sty { + ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | + ty::TyFloat(_) | ty::TyStr | ty::TyNever | + ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => { + // these types never have a destructor + Ok(ty::DtorckConstraint::empty()) + } + + ty::TyArray(ety, _) | ty::TySlice(ety) => { + // single-element containers, behave like their element + self.dtorck_constraint_for_ty(span, for_ty, depth+1, ety) + } + + ty::TyTuple(tys, _) => { + tys.iter().map(|ty| { + self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) + }).collect() + } + + ty::TyClosure(def_id, substs) => { + substs.upvar_tys(def_id, self).map(|ty| { + self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) + }).collect() + } + + ty::TyAdt(def, substs) => { + let ty::DtorckConstraint { + dtorck_types, outlives + } = ty::queries::adt_dtorck_constraint::get(self, span, def.did); + Ok(ty::DtorckConstraint { + // FIXME: we can try to recursively `dtorck_constraint_on_ty` + // there, but that needs some way to handle cycles. + dtorck_types: dtorck_types.subst(self, substs), + outlives: outlives.subst(self, substs) + }) + } + + // Objects must be alive in order for their destructor + // to be called. + ty::TyDynamic(..) => Ok(ty::DtorckConstraint { + outlives: vec![Kind::from(ty)], + dtorck_types: vec![], + }), + + // Types that can't be resolved. Pass them forward. + ty::TyProjection(..) | ty::TyAnon(..) | ty::TyParam(..) => { + Ok(ty::DtorckConstraint { + outlives: vec![], + dtorck_types: vec![ty], + }) + } + + ty::TyInfer(..) | ty::TyError => { + self.sess.delay_span_bug(span, "unresolved type in dtorck"); + Err(ErrorReported) + } + }; + + debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result); + result + } + + pub fn closure_base_def_id(self, def_id: DefId) -> DefId { let mut def_id = def_id; while self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr { def_id = self.parent_def_id(def_id).unwrap_or_else(|| { @@ -412,7 +570,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// a suitable "empty substs" for it. pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx ty::Substs<'tcx> { ty::Substs::for_item(self, item_def_id, - |_, _| self.mk_region(ty::ReErased), + |_, _| self.types.re_erased, |_, _| { bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) }) diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index bbfb7e5874ea..b921678b495c 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -120,7 +120,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } Categorization::StaticItem | Categorization::Deref(.., mc::UnsafePtr(..)) => { - self.bccx.tcx.mk_region(ty::ReStatic) + self.bccx.tcx.types.re_static } Categorization::Deref(.., mc::BorrowedPtr(_, r)) | Categorization::Deref(.., mc::Implicit(_, r)) => { diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 9c5a669bef0d..e9352f53c92d 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -15,7 +15,7 @@ use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind}; use rustc::hir::map as hir_map; use rustc::hir::map::blocks::FnLikeNode; use rustc::traits; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; @@ -48,110 +48,39 @@ macro_rules! math { } } -fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - variant_def: DefId) - -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> { - if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) { - let enum_node_id = tcx.hir.get_parent(variant_node_id); - if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) { - if let hir::ItemEnum(ref edef, _) = it.node { - for variant in &edef.variants { - if variant.node.data.id() == variant_node_id { - return variant.node.disr_expr.map(|e| { - let def_id = tcx.hir.body_owner_def_id(e); - (&tcx.hir.body(e).value, - tcx.item_tables(def_id)) - }); - } - } - } - } - } - None -} - /// * `def_id` is the id of the constant. /// * `substs` is the monomorphized substitutions for the expression. /// /// `substs` is optional and is used for associated constants. /// This generally happens in late/trans const evaluation. -pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>) - -> Option<(&'tcx Expr, - &'a ty::TypeckTables<'tcx>)> { +pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>) + -> Option<(DefId, &'tcx Substs<'tcx>)> { if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { match tcx.hir.find(node_id) { - None => None, - Some(hir_map::NodeItem(&hir::Item { - node: hir::ItemConst(_, body), .. - })) | - Some(hir_map::NodeImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Const(_, body), .. - })) => { - Some((&tcx.hir.body(body).value, - tcx.item_tables(def_id))) + Some(hir_map::NodeTraitItem(_)) => { + // If we have a trait item and the substitutions for it, + // `resolve_trait_associated_const` will select an impl + // or the default. + resolve_trait_associated_const(tcx, def_id, substs) } - Some(hir_map::NodeTraitItem(ti)) => match ti.node { - hir::TraitItemKind::Const(_, default) => { - // If we have a trait item and the substitutions for it, - // `resolve_trait_associated_const` will select an impl - // or the default. - let trait_id = tcx.hir.get_parent(node_id); - let trait_id = tcx.hir.local_def_id(trait_id); - let default_value = default.map(|body| { - (&tcx.hir.body(body).value, - tcx.item_tables(def_id)) - }); - resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs) - } - _ => None - }, - Some(_) => None + _ => Some((def_id, substs)) } } else { - let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| { - (&body.value, tcx.item_tables(def_id)) - }); match tcx.sess.cstore.describe_def(def_id) { Some(Def::AssociatedConst(_)) => { - let trait_id = tcx.sess.cstore.trait_of_item(def_id); // As mentioned in the comments above for in-crate // constants, we only try to find the expression for a // trait-associated const if the caller gives us the // substitutions for the reference to it. - if let Some(trait_id) = trait_id { - resolve_trait_associated_const(tcx, def_id, expr_and_tables, - trait_id, substs) + if tcx.sess.cstore.trait_of_item(def_id).is_some() { + resolve_trait_associated_const(tcx, def_id, substs) } else { - expr_and_tables + Some((def_id, substs)) } - }, - Some(Def::Const(..)) => expr_and_tables, - _ => None - } - } -} - -fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)> -{ - if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { - FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| { - if fn_like.constness() == hir::Constness::Const { - Some((tcx.hir.body(fn_like.body()), - tcx.item_tables(def_id))) - } else { - None } - }) - } else { - if tcx.sess.cstore.is_const_fn(def_id) { - tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| { - (body, tcx.item_tables(def_id)) - }) - } else { - None + _ => Some((def_id, substs)) } } } @@ -338,9 +267,22 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } } hir::ExprCast(ref base, _) => { - match cast_const(tcx, cx.eval(base)?, ety) { - Ok(val) => val, - Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }), + let base_val = cx.eval(base)?; + let base_ty = cx.tables.expr_ty(base); + + // Avoid applying substitutions if they're empty, that'd ICE. + let base_ty = if cx.substs.is_empty() { + base_ty + } else { + base_ty.subst(tcx, cx.substs) + }; + if ety == base_ty { + base_val + } else { + match cast_const(tcx, base_val, ety) { + Ok(val) => val, + Err(kind) => signal!(e, kind), + } } } hir::ExprPath(ref qpath) => { @@ -357,42 +299,29 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, match cx.tables.qpath_def(qpath, e.id) { Def::Const(def_id) | Def::AssociatedConst(def_id) => { - if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) { - let cx = ConstContext::with_tables(tcx, tables); - match cx.eval(expr) { - Ok(val) => val, - Err(ConstEvalErr { kind: TypeckError, .. }) => { - signal!(e, TypeckError); - } - Err(err) => { - debug!("bad reference: {:?}, {:?}", err.description(), err.span); - signal!(e, ErroneousReferencedConstant(box err)) - }, - } - } else { - signal!(e, TypeckError); - } + match ty::queries::const_eval::get(tcx, e.span, (def_id, substs)) { + Ok(val) => val, + Err(ConstEvalErr { kind: TypeckError, .. }) => { + signal!(e, TypeckError); + } + Err(err) => { + debug!("bad reference: {:?}, {:?}", err.description(), err.span); + signal!(e, ErroneousReferencedConstant(box err)) + }, + } }, - Def::VariantCtor(variant_def, ..) => { - if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) { - let cx = ConstContext::with_tables(tcx, tables); - match cx.eval(expr) { - Ok(val) => val, - Err(ConstEvalErr { kind: TypeckError, .. }) => { - signal!(e, TypeckError); - } - Err(err) => { - debug!("bad reference: {:?}, {:?}", err.description(), err.span); - signal!(e, ErroneousReferencedConstant(box err)) - }, - } - } else { - signal!(e, UnimplementedConstVal("enum variants")); - } + Def::VariantCtor(variant_def, CtorKind::Const) => { + Variant(variant_def) } - Def::StructCtor(..) => { + Def::VariantCtor(_, CtorKind::Fn) => { + signal!(e, UnimplementedConstVal("enum variants")); + } + Def::StructCtor(_, CtorKind::Const) => { ConstVal::Struct(Default::default()) } + Def::StructCtor(_, CtorKind::Fn) => { + signal!(e, UnimplementedConstVal("tuple struct constructors")) + } Def::Local(def_id) => { debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args); if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) { @@ -407,14 +336,27 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } } hir::ExprCall(ref callee, ref args) => { - let (did, substs) = match cx.eval(callee)? { - Function(did, substs) => (did, substs), - Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")), - callee => signal!(e, CallOn(callee)), + let (def_id, substs) = match cx.eval(callee)? { + Function(def_id, substs) => (def_id, substs), + _ => signal!(e, TypeckError), }; - let (body, tables) = match lookup_const_fn_by_id(tcx, did) { - Some(x) => x, - None => signal!(e, NonConstPath), + + let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) { + if fn_like.constness() == hir::Constness::Const { + tcx.hir.body(fn_like.body()) + } else { + signal!(e, TypeckError) + } + } else { + signal!(e, TypeckError) + } + } else { + if tcx.sess.cstore.is_const_fn(def_id) { + tcx.sess.cstore.item_body(tcx, def_id) + } else { + signal!(e, TypeckError) + } }; let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node { @@ -434,7 +376,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, debug!("const call({:?})", call_args); let callee_cx = ConstContext { tcx: tcx, - tables: tables, + tables: tcx.item_tables(def_id), substs: substs, fn_args: Some(call_args) }; @@ -532,19 +474,16 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, Ok(result) } -fn resolve_trait_associated_const<'a, 'tcx: 'a>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_item_id: DefId, - default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>, - trait_id: DefId, - rcvr_substs: &'tcx Substs<'tcx> -) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> -{ - let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs)); +fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>) + -> Option<(DefId, &'tcx Substs<'tcx>)> { + let trait_item = tcx.associated_item(def_id); + let trait_id = trait_item.container.id(); + let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs)); debug!("resolve_trait_associated_const: trait_ref={:?}", trait_ref); - tcx.populate_implementations_for_trait_if_necessary(trait_id); tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { let mut selcx = traits::SelectionContext::new(&infcx); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), @@ -569,12 +508,20 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>( // when constructing the inference context above. match selection { traits::VtableImpl(ref impl_data) => { - let name = tcx.associated_item(trait_item_id).name; + let name = trait_item.name; let ac = tcx.associated_items(impl_data.impl_def_id) .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name); match ac { - Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()), - None => default_value, + // FIXME(eddyb) Use proper Instance resolution to + // get the correct Substs returned from here. + Some(ic) => Some((ic.def_id, Substs::empty())), + None => { + if trait_item.defaultness.has_value() { + Some((def_id, substs)) + } else { + None + } + } } } _ => { @@ -615,7 +562,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, U8(u) => Ok(Char(u as char)), _ => bug!(), }, - _ => bug!(), + _ => Err(CannotCast), } } @@ -659,6 +606,11 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Bool(b) => cast_const_int(tcx, U8(b as u8), ty), Float(f) => cast_const_float(tcx, f, ty), Char(c) => cast_const_int(tcx, U32(c as u32), ty), + Variant(v) => { + let adt = tcx.lookup_adt_def(tcx.parent_def_id(v).unwrap()); + let idx = adt.variant_index_with_id(v); + cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty) + } Function(..) => Err(UnimplementedConstVal("casting fn pointers")), ByteStr(b) => match ty.sty { ty::TyRawPtr(_) => { @@ -796,21 +748,35 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { pub fn provide(providers: &mut Providers) { *providers = Providers { - monomorphic_const_eval, + const_eval, ..*providers }; } -fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> EvalResult<'tcx> { - let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id)); +fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + (def_id, substs): (DefId, &'tcx Substs<'tcx>)) + -> EvalResult<'tcx> { + let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, def_id, substs) { + resolved + } else { + return Err(ConstEvalErr { + span: tcx.def_span(def_id), + kind: TypeckError + }); + }; + + let cx = ConstContext { + tcx, + tables: tcx.item_tables(def_id), + substs: substs, + fn_args: None + }; let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); tcx.hir.body(tcx.hir.body_owned_by(id)) } else { - tcx.sess.cstore.maybe_get_item_body(tcx, def_id).unwrap() + tcx.sess.cstore.item_body(tcx, def_id) }; cx.eval(&body.value) } diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index f20fa27dc225..0dfafeb6fb83 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -116,6 +116,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]), ConstVal::Bool(b) => write!(f, "{:?}", b), ConstVal::Char(c) => write!(f, "{:?}", c), + ConstVal::Variant(_) | ConstVal::Struct(_) | ConstVal::Tuple(_) | ConstVal::Function(..) | @@ -587,11 +588,16 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { let substs = self.tables.node_id_item_substs(id) .unwrap_or_else(|| tcx.intern_substs(&[])); match eval::lookup_const_by_id(tcx, def_id, substs) { - Some((const_expr, const_tables)) => { + Some((def_id, _substs)) => { // Enter the inlined constant's tables temporarily. let old_tables = self.tables; - self.tables = const_tables; - let pat = self.lower_const_expr(const_expr, pat_id, span); + self.tables = tcx.item_tables(def_id); + let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { + tcx.hir.body(tcx.hir.body_owned_by(id)) + } else { + tcx.sess.cstore.item_body(tcx, def_id) + }; + let pat = self.lower_const_expr(&body.value, pat_id, span); self.tables = old_tables; return pat; } @@ -615,7 +621,12 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables); match const_cx.eval(expr) { Ok(value) => { - PatternKind::Constant { value: value } + if let ConstVal::Variant(def_id) = value { + let ty = self.tables.expr_ty(expr); + self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![]) + } else { + PatternKind::Constant { value: value } + } } Err(e) => { self.errors.push(PatternError::ConstEval(e)); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 7632b40ab4f9..438f482fa55c 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -225,6 +225,8 @@ pub fn compile_input(sess: &Session, sess.code_stats.borrow().print_type_sizes(); } + if ::std::env::var("SKIP_LLVM").is_ok() { ::std::process::exit(0); } + let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs); controller_entry_point!(after_llvm, @@ -810,7 +812,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, defs: resolver.definitions, analysis: ty::CrateAnalysis { access_levels: Rc::new(AccessLevels::default()), - reachable: NodeSet(), + reachable: Rc::new(NodeSet()), name: crate_name.to_string(), glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None }, }, @@ -889,9 +891,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let index = stability::Index::new(&hir_map); let mut local_providers = ty::maps::Providers::default(); - mir::provide(&mut local_providers); - rustc_privacy::provide(&mut local_providers); borrowck::provide(&mut local_providers); + mir::provide(&mut local_providers); + reachable::provide(&mut local_providers); + rustc_privacy::provide(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); reachable::provide(&mut local_providers); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 7447fba3038e..147d6558e19c 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -343,12 +343,12 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } pub fn t_rptr_static(&self) -> Ty<'tcx> { - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReStatic), + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_static, self.tcx().types.isize) } pub fn t_rptr_empty(&self) -> Ty<'tcx> { - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReEmpty), + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_empty, self.tcx().types.isize) } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index a8ee999505e2..7bc0e8a512be 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -326,6 +326,7 @@ impl<'a> CrateLoader<'a> { cnum_map: RefCell::new(cnum_map), cnum: cnum, codemap_import_info: RefCell::new(vec![]), + attribute_cache: RefCell::new([Vec::new(), Vec::new()]), dep_kind: Cell::new(dep_kind), source: cstore::CrateSource { dylib: dylib, diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 17a6a706e0aa..72ad1d75a561 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -72,6 +72,7 @@ pub struct CrateMetadata { pub cnum_map: RefCell, pub cnum: CrateNum, pub codemap_import_info: RefCell>, + pub attribute_cache: RefCell<[Vec>>; 2]>, pub root: schema::CrateRoot, @@ -269,7 +270,7 @@ impl CrateMetadata { } pub fn is_staged_api(&self) -> bool { - for attr in self.get_item_attrs(CRATE_DEF_INDEX) { + for attr in self.get_item_attrs(CRATE_DEF_INDEX).iter() { if attr.path == "stable" || attr.path == "unstable" { return true; } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 3239dfb937b5..9e6a45e7f8b7 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -89,6 +89,7 @@ provide! { <'tcx> tcx, def_id, cdata } associated_item => { cdata.get_associated_item(def_id.index) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } + impl_polarity => { cdata.get_impl_polarity(def_id.index) } coerce_unsized_info => { cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| { bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); @@ -111,6 +112,7 @@ provide! { <'tcx> tcx, def_id, cdata closure_kind => { cdata.closure_kind(def_id.index) } closure_type => { cdata.closure_ty(def_id.index, tcx) } inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } + is_foreign_item => { cdata.is_foreign_item(def_id.index) } } impl CrateStore for cstore::CStore { @@ -148,7 +150,7 @@ impl CrateStore for cstore::CStore { self.get_crate_data(def.krate).get_generics(def.index) } - fn item_attrs(&self, def_id: DefId) -> Vec + fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]> { self.dep_graph.read(DepNode::MetaData(def_id)); self.get_crate_data(def_id.krate).get_item_attrs(def_id.index) @@ -176,12 +178,6 @@ impl CrateStore for cstore::CStore { result } - fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity - { - self.dep_graph.read(DepNode::MetaData(def)); - self.get_crate_data(def.krate).get_impl_polarity(def.index) - } - fn impl_parent(&self, impl_def: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(impl_def)); self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index) @@ -405,7 +401,7 @@ impl CrateStore for cstore::CStore { // Mark the attrs as used let attrs = data.get_item_attrs(id.index); - for attr in &attrs { + for attr in attrs.iter() { attr::mark_used(attr); } @@ -418,25 +414,24 @@ impl CrateStore for cstore::CStore { ident: ast::Ident::with_empty_ctxt(name), id: ast::DUMMY_NODE_ID, span: local_span, - attrs: attrs, + attrs: attrs.iter().cloned().collect(), node: ast::ItemKind::MacroDef(body.into()), vis: ast::Visibility::Inherited, }) } - fn maybe_get_item_body<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> Option<&'tcx hir::Body> - { + fn item_body<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> &'tcx hir::Body { if let Some(cached) = tcx.hir.get_inlined_body(def_id) { - return Some(cached); + return cached; } self.dep_graph.read(DepNode::MetaData(def_id)); - debug!("maybe_get_item_body({}): inlining item", tcx.item_path_str(def_id)); + debug!("item_body({}): inlining item", tcx.item_path_str(def_id)); - self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index) + self.get_crate_data(def_id.krate).item_body(tcx, def_id.index) } fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index fac6079529e3..a9eae5281b24 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -31,6 +31,7 @@ use std::cell::Ref; use std::collections::BTreeMap; use std::io; use std::mem; +use std::rc::Rc; use std::str; use std::u32; @@ -749,16 +750,15 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn maybe_get_item_body(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: DefIndex) - -> Option<&'tcx hir::Body> { - if self.is_proc_macro(id) { return None; } - self.entry(id).ast.map(|ast| { - let def_id = self.local_def_id(id); - let body = ast.decode(self).body.decode(self); - tcx.hir.intern_inlined_body(def_id, body) - }) + pub fn item_body(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: DefIndex) + -> &'tcx hir::Body { + assert!(!self.is_proc_macro(id)); + let ast = self.entry(id).ast.unwrap(); + let def_id = self.local_def_id(id); + let body = ast.decode(self).body.decode(self); + tcx.hir.intern_inlined_body(def_id, body) } pub fn item_body_tables(&self, @@ -859,10 +859,18 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec { + pub fn get_item_attrs(&self, node_id: DefIndex) -> Rc<[ast::Attribute]> { + let (node_as, node_index) = + (node_id.address_space().index(), node_id.as_array_index()); if self.is_proc_macro(node_id) { - return Vec::new(); + return Rc::new([]); } + + if let Some(&Some(ref val)) = + self.attribute_cache.borrow()[node_as].get(node_index) { + return val.clone(); + } + // The attributes for a tuple struct are attached to the definition, not the ctor; // we assume that someone passing in a tuple struct ctor is actually wanting to // look at the definition @@ -871,7 +879,13 @@ impl<'a, 'tcx> CrateMetadata { if def_key.disambiguated_data.data == DefPathData::StructCtor { item = self.entry(def_key.parent.unwrap()); } - self.get_attributes(&item) + let result = Rc::__from_array(self.get_attributes(&item).into_boxed_slice()); + let vec_ = &mut self.attribute_cache.borrow_mut()[node_as]; + if vec_.len() < node_index + 1 { + vec_.resize(node_index + 1, None); + } + vec_[node_index] = Some(result.clone()); + result } pub fn get_struct_field_names(&self, id: DefIndex) -> Vec { diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 5fece4d6a5d2..0833342927fe 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { assert!(ty.is_slice()); let array_ty = tcx.mk_array(tcx.types.u8, bytes.len()); - let array_ref = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), array_ty); + let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty); let array = self.literal_operand(test.span, array_ref, Literal::Value { value: value.clone() }); diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index b7de50efe344..736c076ea154 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -593,7 +593,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprRepeat(ref v, count) => { let c = &cx.tcx.hir.body(count).value; let def_id = cx.tcx.hir.body_owner_def_id(count); - let count = match ty::queries::monomorphic_const_eval::get(cx.tcx, c.span, def_id) { + let substs = Substs::empty(); + let count = match ty::queries::const_eval::get(cx.tcx, c.span, (def_id, substs)) { Ok(ConstVal::Integral(ConstInt::Usize(u))) => u, Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 4d70540a7c68..7f7377e5ffe3 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -308,10 +308,9 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, Adjustment::Deref => Operand::Consume(rcvr_l.deref()), Adjustment::RefMut => { // let rcvr = &mut rcvr; - let re_erased = tcx.mk_region(ty::ReErased); let ref_rcvr = local_decls.push(temp_decl( Mutability::Not, - tcx.mk_ref(re_erased, ty::TypeAndMut { + tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::MutMutable }), @@ -321,7 +320,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, source_info: source_info, kind: StatementKind::Assign( Lvalue::Local(ref_rcvr), - Rvalue::Ref(re_erased, BorrowKind::Mut, rcvr_l) + Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, rcvr_l) ) }); Operand::Consume(Lvalue::Local(ref_rcvr)) diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 0f869e7ed02f..5cc5cf297936 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -13,7 +13,7 @@ //! care erasing regions all over the place. use rustc::ty::subst::Substs; -use rustc::ty::{Ty, TyCtxt, ReErased, ClosureSubsts}; +use rustc::ty::{Ty, TyCtxt, ClosureSubsts}; use rustc::mir::*; use rustc::mir::visit::MutVisitor; use rustc::mir::transform::{MirPass, MirSource, Pass}; @@ -43,7 +43,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { match *rvalue { Rvalue::Ref(ref mut r, _, _) => { - *r = self.tcx.mk_region(ReErased); + *r = self.tcx.types.re_erased; } Rvalue::Use(..) | Rvalue::Repeat(..) | diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 892d67ac2372..45bdff9195c4 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let dest = if dest_needs_borrow(&destination.0) { debug!("Creating temp for return destination"); let dest = Rvalue::Ref( - self.tcx.mk_region(ty::ReErased), + self.tcx.types.re_erased, BorrowKind::Mut, destination.0); @@ -582,7 +582,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { fn cast_box_free_arg(&self, arg: Lvalue<'tcx>, ptr_ty: Ty<'tcx>, callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Operand<'tcx> { let arg = Rvalue::Ref( - self.tcx.mk_region(ty::ReErased), + self.tcx.types.re_erased, BorrowKind::Mut, arg.deref()); diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 0a8f147b2141..ef7990653ba9 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -124,6 +124,8 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { self.collapse_goto_chain(successor, &mut changed); } + changed |= self.simplify_unwind(&mut terminator); + let mut new_stmts = vec![]; let mut inner_changed = true; while inner_changed { @@ -238,6 +240,38 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { true } + // turn an unwind branch to a resume block into a None + fn simplify_unwind(&mut self, terminator: &mut Terminator<'tcx>) -> bool { + let unwind = match terminator.kind { + TerminatorKind::Drop { ref mut unwind, .. } | + TerminatorKind::DropAndReplace { ref mut unwind, .. } | + TerminatorKind::Call { cleanup: ref mut unwind, .. } | + TerminatorKind::Assert { cleanup: ref mut unwind, .. } => + unwind, + _ => return false + }; + + if let &mut Some(unwind_block) = unwind { + let is_resume_block = match self.basic_blocks[unwind_block] { + BasicBlockData { + ref statements, + terminator: Some(Terminator { + kind: TerminatorKind::Resume, .. + }), .. + } if statements.is_empty() => true, + _ => false + }; + if is_resume_block { + debug!("simplifying unwind to {:?} from {:?}", + unwind_block, terminator.source_info); + *unwind = None; + } + return is_resume_block; + } + + false + } + fn strip_nops(&mut self) { for blk in self.basic_blocks.iter_mut() { blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind { diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 07025fcfdb94..9d7c7ec63cfc 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -506,8 +506,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let ty = self.lvalue_ty(self.lvalue); let substs = tcx.mk_substs(iter::once(Kind::from(ty))); - let re_erased = tcx.mk_region(ty::ReErased); - let ref_ty = tcx.mk_ref(re_erased, ty::TypeAndMut { + let ref_ty = tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut { ty: ty, mutbl: hir::Mutability::MutMutable }); @@ -519,7 +518,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> source_info: self.source_info, kind: StatementKind::Assign( Lvalue::Local(ref_lvalue), - Rvalue::Ref(re_erased, BorrowKind::Mut, self.lvalue.clone()) + Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, self.lvalue.clone()) ) }], terminator: Some(Terminator { diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 5d6717272fdf..221c52141a83 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -53,7 +53,7 @@ impl ExportedSymbols { scx.tcx().hir.local_def_id(node_id) }) .map(|def_id| { - let name = symbol_for_def_id(scx, def_id, symbol_map); + let name = symbol_for_def_id(scx.tcx(), def_id, symbol_map); let export_level = export_level(scx, def_id); debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level); (name, export_level) @@ -108,7 +108,7 @@ impl ExportedSymbols { .exported_symbols(cnum) .iter() .map(|&def_id| { - let name = symbol_name(Instance::mono(scx.tcx(), def_id), scx); + let name = symbol_name(Instance::mono(scx.tcx(), def_id), scx.tcx()); let export_level = if special_runtime_crate { // We can probably do better here by just ensuring that // it has hidden visibility rather than public @@ -214,21 +214,21 @@ pub fn is_below_threshold(level: SymbolExportLevel, } } -fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn symbol_for_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, symbol_map: &SymbolMap<'tcx>) -> String { // Just try to look things up in the symbol map. If nothing's there, we // recompute. - if let Some(node_id) = scx.tcx().hir.as_local_node_id(def_id) { + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) { return sym.to_owned(); } } - let instance = Instance::mono(scx.tcx(), def_id); + let instance = Instance::mono(tcx, def_id); symbol_map.get(TransItem::Fn(instance)) .map(str::to_owned) - .unwrap_or_else(|| symbol_name(instance, scx)) + .unwrap_or_else(|| symbol_name(instance, tcx)) } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 8facbd6cc278..f21864764ddf 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -97,13 +97,12 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. -use common::SharedCrateContext; use monomorphize::Instance; use rustc::middle::weak_lang_items; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; -use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::fold::TypeVisitor; use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; use rustc::ty::subst::Substs; @@ -111,9 +110,10 @@ use rustc::hir::map::definitions::DefPathData; use rustc::util::common::record_time; use syntax::attr; -use syntax::symbol::{Symbol, InternedString}; -fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +use std::fmt::Write; + +fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // the DefId of the item this name is for def_id: Option, @@ -130,8 +130,6 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, -> String { debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs); - let tcx = scx.tcx(); - let mut hasher = ty::util::TypeIdHasher::::new(tcx); record_time(&tcx.sess.perf_stats.symbol_hash_time, || { @@ -157,8 +155,8 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // in case the same instances is emitted in two crates of the same // project. if substs.types().next().is_some() { - hasher.hash(scx.tcx().crate_name.as_str()); - hasher.hash(scx.sess().local_crate_disambiguator().as_str()); + hasher.hash(tcx.crate_name.as_str()); + hasher.hash(tcx.sess.local_crate_disambiguator().as_str()); } } }); @@ -168,37 +166,37 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, - scx: &SharedCrateContext<'a, 'tcx>) -> String { + tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { let def_id = instance.def_id(); let substs = instance.substs; debug!("symbol_name(def_id={:?}, substs={:?})", def_id, substs); - let node_id = scx.tcx().hir.as_local_node_id(def_id); + let node_id = tcx.hir.as_local_node_id(def_id); if let Some(id) = node_id { - if scx.sess().plugin_registrar_fn.get() == Some(id) { + if tcx.sess.plugin_registrar_fn.get() == Some(id) { let idx = def_id.index; - let disambiguator = scx.sess().local_crate_disambiguator(); - return scx.sess().generate_plugin_registrar_symbol(disambiguator, idx); + let disambiguator = tcx.sess.local_crate_disambiguator(); + return tcx.sess.generate_plugin_registrar_symbol(disambiguator, idx); } - if scx.sess().derive_registrar_fn.get() == Some(id) { + if tcx.sess.derive_registrar_fn.get() == Some(id) { let idx = def_id.index; - let disambiguator = scx.sess().local_crate_disambiguator(); - return scx.sess().generate_derive_registrar_symbol(disambiguator, idx); + let disambiguator = tcx.sess.local_crate_disambiguator(); + return tcx.sess.generate_derive_registrar_symbol(disambiguator, idx); } } // FIXME(eddyb) Precompute a custom symbol name based on attributes. - let attrs = scx.tcx().get_attrs(def_id); + let attrs = tcx.get_attrs(def_id); let is_foreign = if let Some(id) = node_id { - match scx.tcx().hir.get(id) { + match tcx.hir.get(id) { hir_map::NodeForeignItem(_) => true, _ => false } } else { - scx.sess().cstore.is_foreign_item(def_id) + tcx.sess.cstore.is_foreign_item(def_id) }; if let Some(name) = weak_lang_items::link_name(&attrs) { @@ -210,17 +208,17 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, return name.to_string(); } // Don't mangle foreign items. - return scx.tcx().item_name(def_id).as_str().to_string(); + return tcx.item_name(def_id).as_str().to_string(); } - if let Some(name) = attr::find_export_name_attr(scx.sess().diagnostic(), &attrs) { + if let Some(name) = attr::find_export_name_attr(tcx.sess.diagnostic(), &attrs) { // Use provided name return name.to_string(); } if attr::contains_name(&attrs, "no_mangle") { // Don't mangle - return scx.tcx().item_name(def_id).as_str().to_string(); + return tcx.item_name(def_id).as_str().to_string(); } // We want to compute the "type" of this item. Unfortunately, some @@ -230,11 +228,11 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, let mut ty_def_id = def_id; let instance_ty; loop { - let key = scx.tcx().def_key(ty_def_id); + let key = tcx.def_key(ty_def_id); match key.disambiguated_data.data { DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { - instance_ty = scx.tcx().item_type(ty_def_id); + instance_ty = tcx.item_type(ty_def_id); break; } _ => { @@ -251,23 +249,51 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, // Erase regions because they may not be deterministic when hashed // and should not matter anyhow. - let instance_ty = scx.tcx().erase_regions(&instance_ty); + let instance_ty = tcx.erase_regions(&instance_ty); - let hash = get_symbol_hash(scx, Some(def_id), instance_ty, Some(substs)); - - let mut buffer = SymbolPathBuffer { - names: Vec::new() - }; + let hash = get_symbol_hash(tcx, Some(def_id), instance_ty, Some(substs)); + let mut buffer = SymbolPathBuffer::new(); item_path::with_forced_absolute_paths(|| { - scx.tcx().push_item_path(&mut buffer, def_id); + tcx.push_item_path(&mut buffer, def_id); }); - - mangle(buffer.names.into_iter(), &hash) + buffer.finish(&hash) } +// Follow C++ namespace-mangling style, see +// http://en.wikipedia.org/wiki/Name_mangling for more info. +// +// It turns out that on macOS you can actually have arbitrary symbols in +// function names (at least when given to LLVM), but this is not possible +// when using unix's linker. Perhaps one day when we just use a linker from LLVM +// we won't need to do this name mangling. The problem with name mangling is +// that it seriously limits the available characters. For example we can't +// have things like &T in symbol names when one would theoretically +// want them for things like impls of traits on that type. +// +// To be able to work on all platforms and get *some* reasonable output, we +// use C++ name-mangling. struct SymbolPathBuffer { - names: Vec, + result: String, + temp_buf: String +} + +impl SymbolPathBuffer { + fn new() -> Self { + let mut result = SymbolPathBuffer { + result: String::with_capacity(64), + temp_buf: String::with_capacity(16) + }; + result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested + result + } + + fn finish(mut self, hash: &str) -> String { + // end name-sequence + self.push(hash); + self.result.push('E'); + self.result + } } impl ItemPathBuffer for SymbolPathBuffer { @@ -277,24 +303,32 @@ impl ItemPathBuffer for SymbolPathBuffer { } fn push(&mut self, text: &str) { - self.names.push(Symbol::intern(text).as_str()); + self.temp_buf.clear(); + let need_underscore = sanitize(&mut self.temp_buf, text); + let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize)); + if need_underscore { + self.result.push('_'); + } + self.result.push_str(&self.temp_buf); } } -pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +pub fn exported_name_from_type_and_prefix<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, t: Ty<'tcx>, prefix: &str) -> String { - let hash = get_symbol_hash(scx, None, t, None); - let path = [Symbol::intern(prefix).as_str()]; - mangle(path.iter().cloned(), &hash) + let hash = get_symbol_hash(tcx, None, t, None); + let mut buffer = SymbolPathBuffer::new(); + buffer.push(prefix); + buffer.finish(&hash) } // Name sanitation. LLVM will happily accept identifiers with weird names, but // gas doesn't! // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $ -pub fn sanitize(s: &str) -> String { - let mut result = String::new(); +// +// returns true if an underscore must be added at the start +pub fn sanitize(result: &mut String, s: &str) -> bool { for c in s.chars() { match c { // Escape these with $ sequences @@ -331,44 +365,7 @@ pub fn sanitize(s: &str) -> String { } // Underscore-qualify anything that didn't start as an ident. - if !result.is_empty() && + !result.is_empty() && result.as_bytes()[0] != '_' as u8 && - ! (result.as_bytes()[0] as char).is_xid_start() { - return format!("_{}", result); - } - - return result; -} - -fn mangle>(path: PI, hash: &str) -> String { - // Follow C++ namespace-mangling style, see - // http://en.wikipedia.org/wiki/Name_mangling for more info. - // - // It turns out that on macOS you can actually have arbitrary symbols in - // function names (at least when given to LLVM), but this is not possible - // when using unix's linker. Perhaps one day when we just use a linker from LLVM - // we won't need to do this name mangling. The problem with name mangling is - // that it seriously limits the available characters. For example we can't - // have things like &T in symbol names when one would theoretically - // want them for things like impls of traits on that type. - // - // To be able to work on all platforms and get *some* reasonable output, we - // use C++ name-mangling. - - let mut n = String::from("_ZN"); // _Z == Begin name-sequence, N == nested - - fn push(n: &mut String, s: &str) { - let sani = sanitize(s); - n.push_str(&format!("{}{}", sani.len(), sani)); - } - - // First, connect each component with pairs. - for data in path { - push(&mut n, &data); - } - - push(&mut n, hash); - - n.push('E'); // End name-sequence. - n + ! (result.as_bytes()[0] as char).is_xid_start() } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index cb8022efedb8..ba119bd9ef06 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -65,6 +65,7 @@ use meth; use mir; use monomorphize::{self, Instance}; use partitioning::{self, PartitioningStrategy, CodegenUnit}; +use symbol_cache::SymbolCache; use symbol_map::SymbolMap; use symbol_names_test; use trans_item::{TransItem, DefPathBasedNames}; @@ -75,7 +76,6 @@ use util::nodemap::{NodeSet, FxHashMap, FxHashSet}; use libc::c_uint; use std::ffi::{CStr, CString}; -use std::rc::Rc; use std::str; use std::i32; use syntax_pos::Span; @@ -802,6 +802,7 @@ fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, /// in any other compilation unit. Give these symbols internal linkage. fn internalize_symbols<'a, 'tcx>(sess: &Session, scx: &SharedCrateContext<'a, 'tcx>, + translation_items: &FxHashSet>, llvm_modules: &[ModuleLlvm], symbol_map: &SymbolMap<'tcx>, exported_symbols: &ExportedSymbols) { @@ -854,7 +855,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, let mut locally_defined_symbols = FxHashSet(); let mut linkage_fixed_explicitly = FxHashSet(); - for trans_item in scx.translation_items().borrow().iter() { + for trans_item in translation_items { let symbol_name = symbol_map.get_or_compute(scx, *trans_item); if trans_item.explicit_linkage(tcx).is_some() { linkage_fixed_explicitly.insert(symbol_name.clone()); @@ -1011,8 +1012,8 @@ fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter { /// /// This list is later used by linkers to determine the set of symbols needed to /// be exposed from a dynamic library and it's also encoded into the metadata. -pub fn find_exported_symbols(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { - reachable.into_iter().filter(|&id| { +pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet { + reachable.iter().cloned().filter(|&id| { // Next, we want to ignore some FFI functions that are not exposed from // this crate. Reachable FFI functions can be lumped into two // categories: @@ -1064,7 +1065,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let krate = tcx.hir.krate(); let ty::CrateAnalysis { reachable, .. } = analysis; - let exported_symbols = find_exported_symbols(tcx, reachable); + let exported_symbols = find_exported_symbols(tcx, &reachable); let check_overflow = tcx.sess.overflow_checks(); @@ -1109,9 +1110,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Run the translation item collector and partition the collected items into // codegen units. - let (codegen_units, symbol_map) = collect_and_partition_translation_items(&shared_ccx); - - let symbol_map = Rc::new(symbol_map); + let (translation_items, codegen_units, symbol_map) = + collect_and_partition_translation_items(&shared_ccx); let mut all_stats = Stats::default(); let modules: Vec = codegen_units @@ -1121,7 +1121,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (stats, module) = tcx.dep_graph.with_task(dep_node, AssertDepGraphSafe(&shared_ccx), - AssertDepGraphSafe((cgu, symbol_map.clone())), + AssertDepGraphSafe(cgu), module_translation); all_stats.extend(stats); module @@ -1130,16 +1130,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn module_translation<'a, 'tcx>( scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>, - args: AssertDepGraphSafe<(CodegenUnit<'tcx>, Rc>)>) + args: AssertDepGraphSafe>) -> (Stats, ModuleTranslation) { // FIXME(#40304): We ought to be using the id as a key and some queries, I think. let AssertDepGraphSafe(scx) = scx; - let AssertDepGraphSafe((cgu, symbol_map)) = args; + let AssertDepGraphSafe(cgu) = args; let cgu_name = String::from(cgu.name()); let cgu_id = cgu.work_product_id(); - let symbol_name_hash = cgu.compute_symbol_name_hash(scx, &symbol_map); + let symbol_cache = SymbolCache::new(scx.tcx()); + let symbol_name_hash = cgu.compute_symbol_name_hash(scx, &symbol_cache); // Check whether there is a previous work-product we can // re-use. Not only must the file exist, and the inputs not @@ -1174,11 +1175,11 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // Instantiate translation items without filling out definitions yet... - let lcx = LocalCrateContext::new(scx, cgu, symbol_map.clone()); + let lcx = LocalCrateContext::new(scx, cgu, &symbol_cache); let module = { let ccx = CrateContext::new(scx, &lcx); let trans_items = ccx.codegen_unit() - .items_in_deterministic_order(ccx.tcx(), &symbol_map); + .items_in_deterministic_order(ccx.tcx(), &symbol_cache); for &(trans_item, linkage) in &trans_items { trans_item.predefine(&ccx, linkage); } @@ -1238,7 +1239,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert_module_sources::assert_module_sources(tcx, &modules); - symbol_names_test::report_symbol_names(&shared_ccx); + symbol_names_test::report_symbol_names(tcx); if shared_ccx.sess().trans_stats() { println!("--- trans stats ---"); @@ -1289,6 +1290,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, time(shared_ccx.sess().time_passes(), "internalize symbols", || { internalize_symbols(sess, &shared_ccx, + &translation_items, &llvm_modules, &symbol_map, &exported_symbols); @@ -1517,7 +1519,9 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { } fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) - -> (Vec>, SymbolMap<'tcx>) { + -> (FxHashSet>, + Vec>, + SymbolMap<'tcx>) { let time_passes = scx.sess().time_passes(); let collection_mode = match scx.sess().opts.debugging_opts.print_trans_items { @@ -1563,13 +1567,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a assert!(scx.tcx().sess.opts.cg.codegen_units == codegen_units.len() || scx.tcx().sess.opts.debugging_opts.incremental.is_some()); - { - let mut ccx_map = scx.translation_items().borrow_mut(); - - for trans_item in items.iter().cloned() { - ccx_map.insert(trans_item); - } - } + let translation_items: FxHashSet> = items.iter().cloned().collect(); if scx.sess().opts.debugging_opts.print_trans_items.is_some() { let mut item_to_cgus = FxHashMap(); @@ -1624,5 +1622,5 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a } } - (codegen_units, symbol_map) + (translation_items, codegen_units, symbol_map) } diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index aefee51191ac..264e26e4594c 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -14,18 +14,18 @@ //! and methods are represented as just a fn ptr and not a full //! closure. -use llvm::{self, ValueRef}; -use rustc::hir::def_id::DefId; -use rustc::ty::subst::Substs; use attributes; use common::{self, CrateContext}; -use monomorphize; use consts; use declare; -use monomorphize::Instance; +use llvm::{self, ValueRef}; +use monomorphize::{self, Instance}; +use rustc::hir::def_id::DefId; +use rustc::ty::{self, TypeFoldable}; +use rustc::ty::subst::Substs; +use syntax_pos::DUMMY_SP; use trans_item::TransItem; use type_of; -use rustc::ty::TypeFoldable; /// Translates a reference to a fn/method item, monomorphizing and /// inlining as it goes. @@ -51,8 +51,7 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return llfn; } - let sym = ccx.symbol_map().get_or_compute(ccx.shared(), - TransItem::Fn(instance)); + let sym = ccx.symbol_cache().get(TransItem::Fn(instance)); debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym); // This is subtle and surprising, but sometimes we have to bitcast @@ -102,15 +101,17 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let attrs = instance.def.attrs(ccx.tcx()); attributes::from_fn_attrs(ccx, &attrs, llfn); - let is_local_def = ccx.shared().translation_items().borrow() - .contains(&TransItem::Fn(instance)); - if is_local_def { - // FIXME(eddyb) Doubt all extern fn should allow unwinding. + // Perhaps questionable, but we assume that anything defined + // *in Rust code* may unwind. Foreign items like `extern "C" { + // fn foo(); }` are assumed not to unwind **unless** they have + // a `#[unwind]` attribute. + if !ty::queries::is_foreign_item::get(tcx, DUMMY_SP, instance.def_id()) { attributes::unwind(llfn, true); unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); } } + if ccx.use_dll_storage_attrs() && ccx.sess().cstore.is_dllimport_foreign_item(instance.def_id()) { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index ba2b807d5a01..13bb0d371250 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -467,13 +467,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => { - let target_ty = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &target_ty); + let target_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, + &target_ty); let source_ty = operand.ty(self.mir, self.scx.tcx()); - let source_ty = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &source_ty); + let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, + &source_ty); let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx, source_ty, target_ty); @@ -489,10 +487,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => { let fn_ty = operand.ty(self.mir, self.scx.tcx()); - let fn_ty = monomorphize::apply_param_substs( - self.scx, - self.param_substs, - &fn_ty); + let fn_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, + &fn_ty); visit_fn_use(self.scx, fn_ty, false, &mut self.output); } mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => { @@ -534,9 +530,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } if let mir::Literal::Item { def_id, substs } = constant.literal { - let substs = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &substs); + let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs, + &substs); let instance = monomorphize::resolve(self.scx, def_id, substs); collect_neighbours(self.scx, instance, self.output); } @@ -552,17 +547,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { match *kind { mir::TerminatorKind::Call { ref func, .. } => { let callee_ty = func.ty(self.mir, tcx); - let callee_ty = monomorphize::apply_param_substs( - self.scx, self.param_substs, &callee_ty); + let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty); visit_fn_use(self.scx, callee_ty, true, &mut self.output); } mir::TerminatorKind::Drop { ref location, .. } | mir::TerminatorKind::DropAndReplace { ref location, .. } => { let ty = location.ty(self.mir, self.scx.tcx()) .to_ty(self.scx.tcx()); - let ty = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &ty); + let ty = tcx.trans_apply_param_substs(self.param_substs, &ty); visit_drop_use(self.scx, ty, true, self.output); } mir::TerminatorKind::Goto { .. } | diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 5d58c9353892..648ea92c8437 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -564,7 +564,7 @@ pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, -> Ty<'tcx> { let ty = shared.tcx().item_type(def_id); - monomorphize::apply_param_substs(shared, substs, &ty) + shared.tcx().trans_apply_param_substs(substs, &ty) } /// Return the substituted type of an instance. @@ -573,5 +573,5 @@ pub fn instance_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, -> Ty<'tcx> { let ty = instance.def.def_ty(shared.tcx()); - monomorphize::apply_param_substs(shared, instance.substs, &ty) + shared.tcx().trans_apply_param_substs(instance.substs, &ty) } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index eb3ac309be16..3d614cfbcbf3 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -93,20 +93,19 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { hir_map::NodeItem(&hir::Item { ref attrs, span, node: hir::ItemStatic(..), .. }) => { - let sym = ccx.symbol_map() - .get(TransItem::Static(id)) - .expect("Local statics should always be in the SymbolMap"); + let sym = ccx.symbol_cache() + .get(TransItem::Static(id)); let defined_in_current_codegen_unit = ccx.codegen_unit() .items() .contains_key(&TransItem::Static(id)); assert!(!defined_in_current_codegen_unit); - if declare::get_declared_value(ccx, sym).is_some() { + if declare::get_declared_value(ccx, &sym[..]).is_some() { span_bug!(span, "trans: Conflicting symbol names for static?"); } - let g = declare::define_global(ccx, sym, llty).unwrap(); + let g = declare::define_global(ccx, &sym[..], llty).unwrap(); (g, attrs) } @@ -114,7 +113,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { hir_map::NodeForeignItem(&hir::ForeignItem { ref attrs, span, node: hir::ForeignItemStatic(..), .. }) => { - let sym = symbol_names::symbol_name(instance, ccx.shared()); + let sym = symbol_names::symbol_name(instance, ccx.tcx()); let g = if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "linkage") { // If this is a static with a linkage specified, then we need to handle @@ -174,7 +173,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { g } else { - let sym = symbol_names::symbol_name(instance, ccx.shared()); + let sym = symbol_names::symbol_name(instance, ccx.tcx()); // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? // FIXME(nagisa): investigate whether it can be changed into define_global diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 1d1921bf7b96..bef22cf304dc 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -10,7 +10,7 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef}; -use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, DepTrackingMapConfig}; +use rustc::dep_graph::{DepGraph, DepGraphSafe}; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::traits; @@ -21,7 +21,6 @@ use declare; use monomorphize::Instance; use partitioning::CodegenUnit; -use trans_item::TransItem; use type_::Type; use rustc_data_structures::base_n; use rustc::ty::subst::Substs; @@ -30,15 +29,13 @@ use rustc::ty::layout::{LayoutTyper, TyLayout}; use session::config::NoDebugInfo; use session::Session; use session::config; -use symbol_map::SymbolMap; -use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; +use symbol_cache::SymbolCache; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; -use std::marker::PhantomData; use std::ptr; use std::iter; -use std::rc::Rc; use std::str; use syntax::ast; use syntax::symbol::InternedString; @@ -86,17 +83,13 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { check_overflow: bool, use_dll_storage_attrs: bool, - - translation_items: RefCell>>, - trait_cache: RefCell>>, - project_cache: RefCell>>, } /// The local portion of a `CrateContext`. There is one `LocalCrateContext` /// per compilation unit. Each one has its own LLVM `ContextRef` so that /// several compilation units may be optimized in parallel. All other LLVM /// data structures in the `LocalCrateContext` are tied to that `ContextRef`. -pub struct LocalCrateContext<'tcx> { +pub struct LocalCrateContext<'a, 'tcx: 'a> { llmod: ModuleRef, llcx: ContextRef, stats: Stats, @@ -168,60 +161,10 @@ pub struct LocalCrateContext<'tcx> { /// Depth of the current type-of computation - used to bail out type_of_depth: Cell, - symbol_map: Rc>, - /// A counter that is used for generating local symbol names local_gen_sym_counter: Cell, -} -// Implement DepTrackingMapConfig for `trait_cache` -pub struct TraitSelectionCache<'tcx> { - data: PhantomData<&'tcx ()> -} - -impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { - type Key = ty::PolyTraitRef<'tcx>; - type Value = traits::Vtable<'tcx, ()>; - fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode { - key.to_poly_trait_predicate().dep_node() - } -} - -// # Global Cache - -pub struct ProjectionCache<'gcx> { - data: PhantomData<&'gcx ()> -} - -impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { - type Key = Ty<'gcx>; - type Value = Ty<'gcx>; - fn to_dep_node(key: &Self::Key) -> DepNode { - // Ideally, we'd just put `key` into the dep-node, but we - // can't put full types in there. So just collect up all the - // def-ids of structs/enums as well as any traits that we - // project out of. It doesn't matter so much what we do here, - // except that if we are too coarse, we'll create overly - // coarse edges between impls and the trans. For example, if - // we just used the def-id of things we are projecting out of, - // then the key for `::T` and `::T` would both share a dep-node - // (`TraitSelect(SomeTrait)`), and hence the impls for both - // `Foo` and `Bar` would be considered inputs. So a change to - // `Bar` would affect things that just normalized `Foo`. - // Anyway, this heuristic is not ideal, but better than - // nothing. - let def_ids: Vec = - key.walk() - .filter_map(|t| match t.sty { - ty::TyAdt(adt_def, _) => Some(adt_def.did), - ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), - _ => None, - }) - .collect(); - - DepNode::ProjectionCache { def_ids: def_ids } - } + symbol_cache: &'a SymbolCache<'a, 'tcx>, } /// A CrateContext value binds together one LocalCrateContext with the @@ -229,12 +172,12 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { /// pass around (SharedCrateContext, LocalCrateContext) tuples all over trans. pub struct CrateContext<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, - local_ccx: &'a LocalCrateContext<'tcx>, + local_ccx: &'a LocalCrateContext<'a, 'tcx>, } impl<'a, 'tcx> CrateContext<'a, 'tcx> { pub fn new(shared: &'a SharedCrateContext<'a, 'tcx>, - local_ccx: &'a LocalCrateContext<'tcx>) + local_ccx: &'a LocalCrateContext<'a, 'tcx>) -> Self { CrateContext { shared, local_ccx } } @@ -385,9 +328,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { tcx: tcx, check_overflow: check_overflow, use_dll_storage_attrs: use_dll_storage_attrs, - translation_items: RefCell::new(FxHashSet()), - trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), - project_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), } } @@ -407,14 +347,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.exported_symbols } - pub fn trait_cache(&self) -> &RefCell>> { - &self.trait_cache - } - - pub fn project_cache(&self) -> &RefCell>> { - &self.project_cache - } - pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx } @@ -430,17 +362,13 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn use_dll_storage_attrs(&self) -> bool { self.use_dll_storage_attrs } - - pub fn translation_items(&self) -> &RefCell>> { - &self.translation_items - } } -impl<'tcx> LocalCrateContext<'tcx> { - pub fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, - codegen_unit: CodegenUnit<'tcx>, - symbol_map: Rc>) - -> LocalCrateContext<'tcx> { +impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { + pub fn new(shared: &SharedCrateContext<'a, 'tcx>, + codegen_unit: CodegenUnit<'tcx>, + symbol_cache: &'a SymbolCache<'a, 'tcx>) + -> LocalCrateContext<'a, 'tcx> { unsafe { // Append ".rs" to LLVM module identifier. // @@ -494,8 +422,8 @@ impl<'tcx> LocalCrateContext<'tcx> { rust_try_fn: Cell::new(None), intrinsics: RefCell::new(FxHashMap()), type_of_depth: Cell::new(0), - symbol_map: symbol_map, local_gen_sym_counter: Cell::new(0), + symbol_cache: symbol_cache, }; let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = { @@ -529,9 +457,9 @@ impl<'tcx> LocalCrateContext<'tcx> { /// This is used in the `LocalCrateContext` constructor to allow calling /// functions that expect a complete `CrateContext`, even before the local /// portion is fully initialized and attached to the `SharedCrateContext`. - fn dummy_ccx<'a>(shared: &'a SharedCrateContext<'a, 'tcx>, - local_ccxs: &'a [LocalCrateContext<'tcx>]) - -> CrateContext<'a, 'tcx> { + fn dummy_ccx(shared: &'a SharedCrateContext<'a, 'tcx>, + local_ccxs: &'a [LocalCrateContext<'a, 'tcx>]) + -> CrateContext<'a, 'tcx> { assert!(local_ccxs.len() == 1); CrateContext { shared: shared, @@ -549,7 +477,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.shared } - fn local(&self) -> &'b LocalCrateContext<'tcx> { + fn local(&self) -> &'b LocalCrateContext<'b, 'tcx> { self.local_ccx } @@ -716,12 +644,8 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.shared.use_dll_storage_attrs() } - pub fn symbol_map(&self) -> &SymbolMap<'tcx> { - &*self.local().symbol_map - } - - pub fn translation_items(&self) -> &RefCell>> { - &self.shared.translation_items + pub fn symbol_cache(&self) -> &'b SymbolCache<'b, 'tcx> { + self.local().symbol_cache } /// Given the def-id of some item that has no type parameters, make @@ -847,6 +771,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> { type TyLayout = TyLayout<'tcx>; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { + if let Some(&layout) = self.tcx().layout_cache.borrow().get(&ty) { + return TyLayout { ty: ty, layout: layout, variant_index: None }; + } + self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { infcx.layout_of(ty).unwrap_or_else(|e| { match e { @@ -857,6 +785,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> { }) }) } + + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.tcx().normalize_associated_type(&ty) + } } impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> { @@ -865,9 +797,13 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> { fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { self.shared.layout_of(ty) } + + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.shared.normalize_projections(ty) + } } -pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>); +pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'a, 'tcx>); impl<'a, 'tcx> Drop for TypeOfDepthLock<'a, 'tcx> { fn drop(&mut self) { diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index be214a0f6143..117d8568500b 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -124,6 +124,7 @@ mod meth; mod mir; mod monomorphize; mod partitioning; +mod symbol_cache; mod symbol_map; mod symbol_names_test; mod trans_item; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 8bce0cf85c08..040194e63d07 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -100,15 +100,13 @@ impl<'tcx> Const<'tcx> { ConstVal::Integral(ref i) => return Const::from_constint(ccx, i), ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()), ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"), + ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false), + ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)), + ConstVal::Variant(_) | ConstVal::Struct(_) | ConstVal::Tuple(_) | ConstVal::Array(..) | ConstVal::Repeat(..) => { bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv) } - ConstVal::Function(..) => { - let llty = type_of::type_of(ccx, ty); - return Const::new(C_null(llty), ty); - } - ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false), }; assert!(!ty.has_erasable_regions()); @@ -260,9 +258,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn monomorphize(&self, value: &T) -> T where T: TransNormalize<'tcx> { - monomorphize::apply_param_substs(self.ccx.shared(), - self.substs, - value) + self.ccx.tcx().trans_apply_param_substs(self.substs, value) } fn trans(&mut self) -> Result, ConstEvalErr<'tcx>> { @@ -710,7 +706,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let tr_lvalue = self.const_lvalue(lvalue, span)?; let ty = tr_lvalue.ty; - let ref_ty = tcx.mk_ref(tcx.mk_region(ty::ReErased), + let ref_ty = tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() }); let base = match tr_lvalue.base { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index d39a91405c18..af0e27c8ca39 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -22,7 +22,7 @@ use base; use builder::Builder; use common::{self, CrateContext, Funclet}; use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; -use monomorphize::{self, Instance}; +use monomorphize::Instance; use abi::FnType; use type_of; @@ -102,8 +102,9 @@ pub struct MirContext<'a, 'tcx:'a> { impl<'a, 'tcx> MirContext<'a, 'tcx> { pub fn monomorphize(&self, value: &T) -> T - where T: TransNormalize<'tcx> { - monomorphize::apply_param_substs(self.ccx.shared(), self.param_substs, value) + where T: TransNormalize<'tcx> + { + self.ccx.tcx().trans_apply_param_substs(self.param_substs, value) } pub fn set_debug_loc(&mut self, bcx: &Builder, source_info: mir::SourceInfo) { diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index de1c1e492f39..b8e9a490b0e7 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -329,7 +329,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let ty = tr_lvalue.ty.to_ty(bcx.tcx()); let ref_ty = bcx.tcx().mk_ref( - bcx.tcx().mk_region(ty::ReErased), + bcx.tcx().types.re_erased, ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() } ); diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 382ca8ef0100..d27eeb2b6466 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -13,17 +13,13 @@ use common::*; use glue; use rustc::hir::def_id::DefId; -use rustc::infer::TransNormalize; use rustc::middle::lang_items::DropInPlaceFnLangItem; -use rustc::traits::{self, SelectionContext, Reveal}; +use rustc::traits; use rustc::ty::adjustment::CustomCoerceUnsized; -use rustc::ty::fold::{TypeFolder, TypeFoldable}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::util::common::MemoizationMap; -use syntax::ast; -use syntax::codemap::{Span, DUMMY_SP}; +use syntax::codemap::DUMMY_SP; pub use rustc::ty::Instance; @@ -104,73 +100,6 @@ pub fn resolve_closure<'a, 'tcx> ( } } -/// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we -/// do not (necessarily) resolve all nested obligations on the impl. Note that type check should -/// guarantee to us that all nested obligations *could be* resolved if we wanted to. -fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - span: Span, - trait_ref: ty::PolyTraitRef<'tcx>) - -> traits::Vtable<'tcx, ()> -{ - let tcx = scx.tcx(); - - // Remove any references to regions; this helps improve caching. - let trait_ref = tcx.erase_regions(&trait_ref); - - scx.trait_cache().memoize(trait_ref, || { - debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", - trait_ref, trait_ref.def_id()); - - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - tcx.infer_ctxt((), Reveal::All).enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = traits::ObligationCause::misc(span, - ast::DUMMY_NODE_ID); - let obligation = traits::Obligation::new(obligation_cause, - trait_ref.to_poly_trait_predicate()); - - let selection = match selcx.select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => { - // Ambiguity can happen when monomorphizing during trans - // expands to some humongo type that never occurred - // statically -- this humongo type can then overflow, - // leading to an ambiguous result. So report this as an - // overflow bug, since I believe this is the only case - // where ambiguity can result. - debug!("Encountered ambiguity selecting `{:?}` during trans, \ - presuming due to overflow", - trait_ref); - tcx.sess.span_fatal(span, - "reached the recursion limit during monomorphization \ - (selection ambiguity)"); - } - Err(e) => { - span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans", - e, trait_ref) - } - }; - - debug!("fulfill_obligation: selection={:?}", selection); - - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = traits::FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable); - - info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - vtable - }) - }) -} - fn resolve_associated_item<'a, 'tcx>( scx: &SharedCrateContext<'a, 'tcx>, trait_item: &ty::AssociatedItem, @@ -185,7 +114,7 @@ fn resolve_associated_item<'a, 'tcx>( def_id, trait_id, rcvr_substs); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = fulfill_obligation(scx, DUMMY_SP, ty::Binder(trait_ref)); + let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::Binder(trait_ref)); // Now that we know which impl is being used, we can dispatch to // the actual function: @@ -285,7 +214,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty]) }); - match fulfill_obligation(scx, DUMMY_SP, trait_ref) { + match scx.tcx().trans_fulfill_obligation(DUMMY_SP, trait_ref) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { scx.tcx().coerce_unsized_info(impl_def_id).custom_kind.unwrap() } @@ -295,21 +224,6 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx } } -/// Monomorphizes a type from the AST by first applying the in-scope -/// substitutions and then normalizing any associated types. -pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>, - param_substs: &Substs<'tcx>, - value: &T) - -> T - where T: TransNormalize<'tcx> -{ - let tcx = scx.tcx(); - debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); - let substituted = value.subst(tcx, param_substs); - let substituted = scx.tcx().erase_regions(&substituted); - AssociatedTypeNormalizer::new(scx).fold(&substituted) -} - /// Returns the normalized type of a struct field pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_substs: &Substs<'tcx>, @@ -319,39 +233,3 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.normalize_associated_type(&f.ty(tcx, param_substs)) } -struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b> { - shared: &'a SharedCrateContext<'b, 'gcx>, -} - -impl<'a, 'b, 'gcx> AssociatedTypeNormalizer<'a, 'b, 'gcx> { - fn new(shared: &'a SharedCrateContext<'b, 'gcx>) -> Self { - AssociatedTypeNormalizer { - shared: shared, - } - } - - fn fold>(&mut self, value: &T) -> T { - if !value.has_projection_types() { - value.clone() - } else { - value.fold_with(self) - } - } -} - -impl<'a, 'b, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'b, 'gcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { - self.shared.tcx() - } - - fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { - if !ty.has_projection_types() { - ty - } else { - self.shared.project_cache().memoize(ty, || { - debug!("AssociatedTypeNormalizer: ty={:?}", ty); - self.shared.tcx().normalize_associated_type(&ty) - }) - } - } -} diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 4973181202ee..6b89d11cfb68 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -116,7 +116,7 @@ use rustc_incremental::IchHasher; use std::cmp::Ordering; use std::hash::Hash; use std::sync::Arc; -use symbol_map::SymbolMap; +use symbol_cache::SymbolCache; use syntax::ast::NodeId; use syntax::symbol::{Symbol, InternedString}; use trans_item::{TransItem, InstantiationMode}; @@ -174,14 +174,15 @@ impl<'tcx> CodegenUnit<'tcx> { DepNode::WorkProduct(self.work_product_id()) } - pub fn compute_symbol_name_hash(&self, - scx: &SharedCrateContext, - symbol_map: &SymbolMap) -> u64 { + pub fn compute_symbol_name_hash<'a>(&self, + scx: &SharedCrateContext<'a, 'tcx>, + symbol_cache: &SymbolCache<'a, 'tcx>) + -> u64 { let mut state = IchHasher::new(); let exported_symbols = scx.exported_symbols(); - let all_items = self.items_in_deterministic_order(scx.tcx(), symbol_map); + let all_items = self.items_in_deterministic_order(scx.tcx(), symbol_cache); for (item, _) in all_items { - let symbol_name = symbol_map.get(item).unwrap(); + let symbol_name = symbol_cache.get(item); symbol_name.len().hash(&mut state); symbol_name.hash(&mut state); let exported = match item { @@ -201,10 +202,10 @@ impl<'tcx> CodegenUnit<'tcx> { state.finish().to_smaller_hash() } - pub fn items_in_deterministic_order(&self, - tcx: TyCtxt, - symbol_map: &SymbolMap) - -> Vec<(TransItem<'tcx>, llvm::Linkage)> { + pub fn items_in_deterministic_order<'a>(&self, + tcx: TyCtxt, + symbol_cache: &SymbolCache<'a, 'tcx>) + -> Vec<(TransItem<'tcx>, llvm::Linkage)> { let mut items: Vec<(TransItem<'tcx>, llvm::Linkage)> = self.items.iter().map(|(item, linkage)| (*item, *linkage)).collect(); @@ -216,9 +217,9 @@ impl<'tcx> CodegenUnit<'tcx> { match (node_id1, node_id2) { (None, None) => { - let symbol_name1 = symbol_map.get(trans_item1).unwrap(); - let symbol_name2 = symbol_map.get(trans_item2).unwrap(); - symbol_name1.cmp(symbol_name2) + let symbol_name1 = symbol_cache.get(trans_item1); + let symbol_name2 = symbol_cache.get(trans_item2); + symbol_name1.cmp(&symbol_name2) } // In the following two cases we can avoid looking up the symbol (None, Some(_)) => Ordering::Less, @@ -230,9 +231,9 @@ impl<'tcx> CodegenUnit<'tcx> { return ordering; } - let symbol_name1 = symbol_map.get(trans_item1).unwrap(); - let symbol_name2 = symbol_map.get(trans_item2).unwrap(); - symbol_name1.cmp(symbol_name2) + let symbol_name1 = symbol_cache.get(trans_item1); + let symbol_name2 = symbol_cache.get(trans_item2); + symbol_name1.cmp(&symbol_name2) } } }); @@ -271,14 +272,14 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, let mut initial_partitioning = place_root_translation_items(scx, trans_items); - debug_dump(scx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter()); + debug_dump(tcx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter()); // If the partitioning should produce a fixed count of codegen units, merge // until that count is reached. if let PartitioningStrategy::FixedUnitCount(count) = strategy { merge_codegen_units(&mut initial_partitioning, count, &tcx.crate_name.as_str()); - debug_dump(scx, "POST MERGING:", initial_partitioning.codegen_units.iter()); + debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); } // In the next step, we use the inlining map to determine which addtional @@ -288,7 +289,7 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, let post_inlining = place_inlined_translation_items(initial_partitioning, inlining_map); - debug_dump(scx, "POST INLINING:", post_inlining.0.iter()); + debug_dump(tcx, "POST INLINING:", post_inlining.0.iter()); // Finally, sort by codegen unit name, so that we get deterministic results let mut result = post_inlining.0; @@ -528,7 +529,7 @@ fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString Symbol::intern(&format!("{}{}{}", crate_name, NUMBERED_CODEGEN_UNIT_MARKER, index)).as_str() } -fn debug_dump<'a, 'b, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, +fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, label: &str, cgus: I) where I: Iterator>, @@ -536,20 +537,18 @@ fn debug_dump<'a, 'b, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, { if cfg!(debug_assertions) { debug!("{}", label); + let symbol_cache = SymbolCache::new(tcx); for cgu in cgus { - let symbol_map = SymbolMap::build(scx, cgu.items - .iter() - .map(|(&trans_item, _)| trans_item)); debug!("CodegenUnit {}:", cgu.name); for (trans_item, linkage) in &cgu.items { - let symbol_name = symbol_map.get_or_compute(scx, *trans_item); + let symbol_name = symbol_cache.get(*trans_item); let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..]) .unwrap_or(""); debug!(" - {} [{:?}] [{}]", - trans_item.to_string(scx.tcx()), + trans_item.to_string(tcx), linkage, symbol_hash); } diff --git a/src/librustc_trans/symbol_cache.rs b/src/librustc_trans/symbol_cache.rs new file mode 100644 index 000000000000..ddc1ef537a55 --- /dev/null +++ b/src/librustc_trans/symbol_cache.rs @@ -0,0 +1,42 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::ty::TyCtxt; +use std::cell::RefCell; +use syntax_pos::symbol::{InternedString, Symbol}; +use trans_item::TransItem; +use util::nodemap::FxHashMap; + +// In the SymbolCache we collect the symbol names of translation items +// and cache them for later reference. This is just a performance +// optimization and the cache is populated lazilly; symbol names of +// translation items are deterministic and fully defined by the item. +// Thus they can always be recomputed if needed. + +pub struct SymbolCache<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + index: RefCell, Symbol>>, +} + +impl<'a, 'tcx> SymbolCache<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { + SymbolCache { + tcx: tcx, + index: RefCell::new(FxHashMap()) + } + } + + pub fn get(&self, trans_item: TransItem<'tcx>) -> InternedString { + let mut index = self.index.borrow_mut(); + index.entry(trans_item) + .or_insert_with(|| Symbol::intern(&trans_item.compute_symbol_name(self.tcx))) + .as_str() + } +} diff --git a/src/librustc_trans/symbol_map.rs b/src/librustc_trans/symbol_map.rs index 36c3981e3a6f..9d3e62888a2d 100644 --- a/src/librustc_trans/symbol_map.rs +++ b/src/librustc_trans/symbol_map.rs @@ -34,8 +34,9 @@ impl<'tcx> SymbolMap<'tcx> { where I: Iterator> { // Check for duplicate symbol names + let tcx = scx.tcx(); let mut symbols: Vec<_> = trans_items.map(|trans_item| { - (trans_item, trans_item.compute_symbol_name(scx)) + (trans_item, trans_item.compute_symbol_name(tcx)) }).collect(); (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{ @@ -124,7 +125,7 @@ impl<'tcx> SymbolMap<'tcx> { if let Some(sym) = self.get(trans_item) { Cow::from(sym) } else { - Cow::from(trans_item.compute_symbol_name(scx)) + Cow::from(trans_item.compute_symbol_name(scx.tcx())) } } } diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index fe551b06b3d9..fd817cb94c1c 100644 --- a/src/librustc_trans/symbol_names_test.rs +++ b/src/librustc_trans/symbol_names_test.rs @@ -17,43 +17,42 @@ use back::symbol_names; use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use rustc::ty::TyCtxt; use syntax::ast; -use common::SharedCrateContext; use monomorphize::Instance; const SYMBOL_NAME: &'static str = "rustc_symbol_name"; const ITEM_PATH: &'static str = "rustc_item_path"; -pub fn report_symbol_names(scx: &SharedCrateContext) { +pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - let tcx = scx.tcx(); if !tcx.sess.features.borrow().rustc_attrs { return; } let _ignore = tcx.dep_graph.in_ignore(); - let mut visitor = SymbolNamesTest { scx: scx }; + let mut visitor = SymbolNamesTest { tcx: tcx }; // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); } struct SymbolNamesTest<'a, 'tcx:'a> { - scx: &'a SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, } impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { fn process_attrs(&mut self, node_id: ast::NodeId) { - let tcx = self.scx.tcx(); + let tcx = self.tcx; let def_id = tcx.hir.local_def_id(node_id); for attr in tcx.get_attrs(def_id).iter() { if attr.check_name(SYMBOL_NAME) { // for now, can only use on monomorphic names let instance = Instance::mono(tcx, def_id); - let name = symbol_names::symbol_name(instance, self.scx); + let name = symbol_names::symbol_name(instance, self.tcx); tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); } else if attr.check_name(ITEM_PATH) { let path = tcx.item_path_str(def_id); diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 4d908f3c94fa..de35d1b7dd4c 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -18,7 +18,7 @@ use asm; use attributes; use base; use consts; -use context::{CrateContext, SharedCrateContext}; +use context::CrateContext; use common; use declare; use llvm; @@ -118,8 +118,7 @@ impl<'a, 'tcx> TransItem<'tcx> { self.to_raw_string(), ccx.codegen_unit().name()); - let symbol_name = ccx.symbol_map() - .get_or_compute(ccx.shared(), *self); + let symbol_name = ccx.symbol_cache().get(*self); debug!("symbol {}", &symbol_name); @@ -185,16 +184,15 @@ impl<'a, 'tcx> TransItem<'tcx> { ccx.instances().borrow_mut().insert(instance, lldecl); } - pub fn compute_symbol_name(&self, - scx: &SharedCrateContext<'a, 'tcx>) -> String { + pub fn compute_symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { match *self { - TransItem::Fn(instance) => symbol_names::symbol_name(instance, scx), + TransItem::Fn(instance) => symbol_names::symbol_name(instance, tcx), TransItem::Static(node_id) => { - let def_id = scx.tcx().hir.local_def_id(node_id); - symbol_names::symbol_name(Instance::mono(scx.tcx(), def_id), scx) + let def_id = tcx.hir.local_def_id(node_id); + symbol_names::symbol_name(Instance::mono(tcx, def_id), tcx) } TransItem::GlobalAsm(node_id) => { - let def_id = scx.tcx().hir.local_def_id(node_id); + let def_id = tcx.hir.local_def_id(node_id); format!("global_asm_{:?}", def_id) } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9426d601dfcc..5137ae6ff422 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -109,7 +109,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let tcx = self.tcx(); let r = match tcx.named_region_map.defs.get(&lifetime.id) { Some(&rl::Region::Static) => { - tcx.mk_region(ty::ReStatic) + tcx.types.re_static } Some(&rl::Region::LateBound(debruijn, id)) => { @@ -171,7 +171,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .emit(); return Substs::for_item(tcx, def_id, |_, _| { - tcx.mk_region(ty::ReStatic) + tcx.types.re_static }, |_, _| { tcx.types.err }); @@ -254,7 +254,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { if let Some(lifetime) = lifetimes.get(i) { self.ast_region_to_region(lifetime, Some(def)) } else { - tcx.mk_region(ty::ReStatic) + tcx.types.re_static } }, |def, substs| { let i = def.index as usize; @@ -715,7 +715,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span_err!(tcx.sess, span, E0228, "the lifetime bound for this object type cannot be deduced \ from context; please supply an explicit bound"); - tcx.mk_region(ty::ReStatic) + tcx.types.re_static }) } }) @@ -1357,7 +1357,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // If any of the derived region bounds are 'static, that is always // the best choice. if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) { - return Some(tcx.mk_region(ty::ReStatic)); + return Some(tcx.types.re_static); } // Determine whether there is exactly one unique region in the set diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 4a0446424444..1086773041c9 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_ty = self.structurally_resolved_type(pat.span, expected); if let ty::TyRef(_, mt) = expected_ty.sty { if let ty::TySlice(_) = mt.ty.sty { - pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), + pat_ty = tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_slice(tcx.types.u8)) } } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index b71ff58ccec3..c125d7c02556 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -15,12 +15,11 @@ use middle::free_region::FreeRegionMap; use rustc::infer::{self, InferOk}; use middle::region; use rustc::ty::subst::{Subst, Substs}; -use rustc::ty::{self, AdtKind, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::traits::{self, ObligationCause, Reveal}; use util::common::ErrorReported; use util::nodemap::FxHashSet; -use syntax::ast; use syntax_pos::Span; /// check_drop_impl confirms that the Drop implementation identfied by @@ -270,389 +269,64 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( /// pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>, - typ: ty::Ty<'tcx>, + ty: ty::Ty<'tcx>, span: Span, scope: region::CodeExtent) + -> Result<(), ErrorReported> { debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}", - typ, scope); + ty, scope); let parent_scope = match rcx.tcx.region_maps.opt_encl_scope(scope) { - Some(parent_scope) => parent_scope, - // If no enclosing scope, then it must be the root scope which cannot be outlived. - None => return + Some(parent_scope) => parent_scope, + // If no enclosing scope, then it must be the root scope + // which cannot be outlived. + None => return Ok(()) }; + let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope)); + let origin = || infer::SubregionOrigin::SafeDestructor(span); - let result = iterate_over_potentially_unsafe_regions_in_type( - &mut DropckContext { - rcx: rcx, - span: span, - parent_scope: parent_scope, - breadcrumbs: FxHashSet() - }, - TypeContext::Root, - typ, - 0); - match result { - Ok(()) => {} - Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => { - let tcx = rcx.tcx; - let mut err = struct_span_err!(tcx.sess, span, E0320, - "overflow while adding drop-check rules for {}", typ); - match *ctxt { - TypeContext::Root => { - // no need for an additional note if the overflow - // was somehow on the root. + let ty = rcx.fcx.resolve_type_vars_if_possible(&ty); + let for_ty = ty; + let mut types = vec![(ty, 0)]; + let mut known = FxHashSet(); + while let Some((ty, depth)) = types.pop() { + let ty::DtorckConstraint { + dtorck_types, outlives + } = rcx.tcx.dtorck_constraint_for_ty(span, for_ty, depth, ty)?; + + for ty in dtorck_types { + let ty = rcx.fcx.normalize_associated_types_in(span, &ty); + let ty = rcx.fcx.resolve_type_vars_with_obligations(ty); + let ty = rcx.fcx.resolve_type_and_region_vars_if_possible(&ty); + match ty.sty { + // All parameters live for the duration of the + // function. + ty::TyParam(..) => {} + + // A projection that we couldn't resolve - it + // might have a destructor. + ty::TyProjection(..) | ty::TyAnon(..) => { + rcx.type_must_outlive(origin(), ty, parent_scope); } - TypeContext::ADT { def_id, variant, field } => { - let adt = tcx.lookup_adt_def(def_id); - let variant_name = match adt.adt_kind() { - AdtKind::Enum => format!("enum {} variant {}", - tcx.item_path_str(def_id), - variant), - AdtKind::Struct => format!("struct {}", - tcx.item_path_str(def_id)), - AdtKind::Union => format!("union {}", - tcx.item_path_str(def_id)), - }; - span_note!( - &mut err, - span, - "overflowed on {} field {} type: {}", - variant_name, - field, - detected_on_typ); + + _ => { + if let None = known.replace(ty) { + types.push((ty, depth+1)); + } } } - err.emit(); - } - } -} - -enum Error<'tcx> { - Overflow(TypeContext, ty::Ty<'tcx>), -} - -#[derive(Copy, Clone)] -enum TypeContext { - Root, - ADT { - def_id: DefId, - variant: ast::Name, - field: ast::Name, - } -} - -struct DropckContext<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> { - rcx: &'a mut RegionCtxt<'b, 'gcx, 'tcx>, - /// types that have already been traversed - breadcrumbs: FxHashSet>, - /// span for error reporting - span: Span, - /// the scope reachable dtorck types must outlive - parent_scope: region::CodeExtent -} - -// `context` is used for reporting overflow errors -fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( - cx: &mut DropckContext<'a, 'b, 'gcx, 'tcx>, - context: TypeContext, - ty: Ty<'tcx>, - depth: usize) - -> Result<(), Error<'tcx>> -{ - let tcx = cx.rcx.tcx; - // Issue #22443: Watch out for overflow. While we are careful to - // handle regular types properly, non-regular ones cause problems. - let recursion_limit = tcx.sess.recursion_limit.get(); - if depth / 4 >= recursion_limit { - // This can get into rather deep recursion, especially in the - // presence of things like Vec -> Unique -> PhantomData -> T. - // use a higher recursion limit to avoid errors. - return Err(Error::Overflow(context, ty)) - } - - // canoncialize the regions in `ty` before inserting - infinitely many - // region variables can refer to the same region. - let ty = cx.rcx.resolve_type_and_region_vars_if_possible(&ty); - - if !cx.breadcrumbs.insert(ty) { - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}ty: {} scope: {:?} - cached", - (0..depth).map(|_| ' ').collect::(), - ty, cx.parent_scope); - return Ok(()); // we already visited this type - } - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}ty: {} scope: {:?}", - (0..depth).map(|_| ' ').collect::(), - ty, cx.parent_scope); - - // If `typ` has a destructor, then we must ensure that all - // borrowed data reachable via `typ` must outlive the parent - // of `scope`. This is handled below. - // - // However, there is an important special case: for any Drop - // impl that is tagged as "blind" to their parameters, - // we assume that data borrowed via such type parameters - // remains unreachable via that Drop impl. - // - // For example, consider: - // - // ```rust - // #[unsafe_destructor_blind_to_params] - // impl Drop for Vec { ... } - // ``` - // - // which does have to be able to drop instances of `T`, but - // otherwise cannot read data from `T`. - // - // Of course, for the type expression passed in for any such - // unbounded type parameter `T`, we must resume the recursive - // analysis on `T` (since it would be ignored by - // type_must_outlive). - let dropck_kind = has_dtor_of_interest(tcx, ty); - debug!("iterate_over_potentially_unsafe_regions_in_type \ - ty: {:?} dropck_kind: {:?}", ty, dropck_kind); - match dropck_kind { - DropckKind::NoBorrowedDataAccessedInMyDtor => { - // The maximally blind attribute. - } - DropckKind::BorrowedDataMustStrictlyOutliveSelf => { - cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), - ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); - return Ok(()); - } - DropckKind::RevisedSelf(revised_ty) => { - cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), - revised_ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); - // Do not return early from this case; we want - // to recursively process the internal structure of Self - // (because even though the Drop for Self has been asserted - // safe, the types instantiated for the generics of Self - // may themselves carry dropck constraints.) - } - } - - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}ty: {} scope: {:?} - checking interior", - (0..depth).map(|_| ' ').collect::(), - ty, cx.parent_scope); - - // We still need to ensure all referenced data is safe. - match ty.sty { - ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | - ty::TyFloat(_) | ty::TyStr | ty::TyNever => { - // primitive - definitely safe - Ok(()) } - ty::TyArray(ity, _) | ty::TySlice(ity) => { - // single-element containers, behave like their element - iterate_over_potentially_unsafe_regions_in_type( - cx, context, ity, depth+1) - } - - ty::TyAdt(def, substs) if def.is_phantom_data() => { - // PhantomData - behaves identically to T - let ity = substs.type_at(0); - iterate_over_potentially_unsafe_regions_in_type( - cx, context, ity, depth+1) - } - - ty::TyAdt(def, substs) => { - let did = def.did; - for variant in &def.variants { - for field in variant.fields.iter() { - let fty = field.ty(tcx, substs); - let fty = cx.rcx.fcx.resolve_type_vars_with_obligations( - cx.rcx.fcx.normalize_associated_types_in(cx.span, &fty)); - iterate_over_potentially_unsafe_regions_in_type( - cx, - TypeContext::ADT { - def_id: did, - field: field.name, - variant: variant.name, - }, - fty, - depth+1)? - } + for outlive in outlives { + if let Some(r) = outlive.as_region() { + rcx.sub_regions(origin(), parent_scope, r); + } else if let Some(ty) = outlive.as_type() { + rcx.type_must_outlive(origin(), ty, parent_scope); } - Ok(()) - } - - ty::TyClosure(def_id, substs) => { - for ty in substs.upvar_tys(def_id, tcx) { - iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)? - } - Ok(()) - } - - ty::TyTuple(tys, _) => { - for ty in tys { - iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)? - } - Ok(()) - } - - ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyParam(..) => { - // these always come with a witness of liveness (references - // explicitly, pointers implicitly, parameters by the - // caller). - Ok(()) - } - - ty::TyFnDef(..) | ty::TyFnPtr(_) => { - // FIXME(#26656): this type is always destruction-safe, but - // it implicitly witnesses Self: Fn, which can be false. - Ok(()) - } - - ty::TyInfer(..) | ty::TyError => { - tcx.sess.delay_span_bug(cx.span, "unresolved type in regionck"); - Ok(()) - } - - // these are always dtorck - ty::TyDynamic(..) | ty::TyProjection(_) | ty::TyAnon(..) => bug!(), - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum DropckKind<'tcx> { - /// The "safe" kind; i.e. conservatively assume any borrow - /// accessed by dtor, and therefore such data must strictly - /// outlive self. - /// - /// Equivalent to RevisedTy with no change to the self type. - BorrowedDataMustStrictlyOutliveSelf, - - /// The nearly completely-unsafe kind. - /// - /// Equivalent to RevisedSelf with *all* parameters remapped to () - /// (maybe...?) - NoBorrowedDataAccessedInMyDtor, - - /// Assume all borrowed data access by dtor occurs as if Self has the - /// type carried by this variant. In practice this means that some - /// of the type parameters are remapped to `()` (and some lifetime - /// parameters remapped to `'static`), because the developer has asserted - /// that the destructor will not access their contents. - RevisedSelf(Ty<'tcx>), -} - -/// Returns the classification of what kind of check should be applied -/// to `ty`, which may include a revised type where some of the type -/// parameters are re-mapped to `()` to reflect the destructor's -/// "purity" with respect to their actual contents. -fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - ty: Ty<'tcx>) - -> DropckKind<'tcx> { - match ty.sty { - ty::TyAdt(adt_def, substs) => { - if !adt_def.is_dtorck(tcx) { - return DropckKind::NoBorrowedDataAccessedInMyDtor; - } - - // Find the `impl<..> Drop for _` to inspect any - // attributes attached to the impl's generics. - let dtor_method = adt_def.destructor(tcx) - .expect("dtorck type without destructor impossible"); - let method = tcx.associated_item(dtor_method.did); - let impl_def_id = method.container.id(); - let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs); - return DropckKind::RevisedSelf(revised_ty); - } - ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyAnon(..) => { - debug!("ty: {:?} isn't known, and therefore is a dropck type", ty); - return DropckKind::BorrowedDataMustStrictlyOutliveSelf; - }, - _ => { - return DropckKind::NoBorrowedDataAccessedInMyDtor; } } -} - -// Constructs new Ty just like the type defined by `adt_def` coupled -// with `substs`, except each type and lifetime parameter marked as -// `#[may_dangle]` in the Drop impl (identified by `impl_def_id`) is -// respectively mapped to `()` or `'static`. -// -// For example: If the `adt_def` maps to: -// -// enum Foo<'a, X, Y> { ... } -// -// and the `impl_def_id` maps to: -// -// impl<#[may_dangle] 'a, X, #[may_dangle] Y> Drop for Foo<'a, X, Y> { ... } -// -// then revises input: `Foo<'r,i64,&'r i64>` to: `Foo<'static,i64,()>` -fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - adt_def: &'tcx ty::AdtDef, - impl_def_id: DefId, - substs: &Substs<'tcx>) - -> Ty<'tcx> { - // Get generics for `impl Drop` to query for `#[may_dangle]` attr. - let impl_bindings = tcx.item_generics(impl_def_id); - - // Get Substs attached to Self on `impl Drop`; process in parallel - // with `substs`, replacing dangling entries as appropriate. - let self_substs = { - let impl_self_ty: Ty<'tcx> = tcx.item_type(impl_def_id); - if let ty::TyAdt(self_adt_def, self_substs) = impl_self_ty.sty { - assert_eq!(adt_def, self_adt_def); - self_substs - } else { - bug!("Self in `impl Drop for _` must be an Adt."); - } - }; - - // Walk `substs` + `self_substs`, build new substs appropriate for - // `adt_def`; each non-dangling param reuses entry from `substs`. - // - // Note: The manner we map from a right-hand side (i.e. Region or - // Ty) for a given `def` to generic parameter associated with that - // right-hand side is tightly coupled to `Drop` impl constraints. - // - // E.g. we know such a Ty must be `TyParam`, because a destructor - // for `struct Foo` is defined via `impl Drop for Foo`, - // and never by (for example) `impl Drop for Foo>`. - let substs = Substs::for_item( - tcx, - adt_def.did, - |def, _| { - let r_orig = substs.region_for_def(def); - let impl_self_orig = self_substs.region_for_def(def); - let r = if let ty::Region::ReEarlyBound(ref ebr) = *impl_self_orig { - if impl_bindings.region_param(ebr).pure_wrt_drop { - tcx.mk_region(ty::ReStatic) - } else { - r_orig - } - } else { - bug!("substs for an impl must map regions to ReEarlyBound"); - }; - debug!("has_dtor_of_interest mapping def {:?} orig {:?} to {:?}", - def, r_orig, r); - r - }, - |def, _| { - let t_orig = substs.type_for_def(def); - let impl_self_orig = self_substs.type_for_def(def); - let t = if let ty::TypeVariants::TyParam(ref pt) = impl_self_orig.sty { - if impl_bindings.type_param(pt).pure_wrt_drop { - tcx.mk_nil() - } else { - t_orig - } - } else { - bug!("substs for an impl must map types to TyParam"); - }; - debug!("has_dtor_of_interest mapping def {:?} orig {:?} {:?} to {:?} {:?}", - def, t_orig, t_orig.sty, t, t.sty); - t - }); - - tcx.mk_adt(adt_def, &substs) + + Ok(()) } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index cd58fcd4806d..bf7649242fa7 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -36,7 +36,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let def_id = tcx.hir.local_def_id(it.id); let substs = Substs::for_item(tcx, def_id, - |_, _| tcx.mk_region(ty::ReErased), + |_, _| tcx.types.re_erased, |def, _| tcx.mk_param_from_def(def)); let fty = tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig( diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 59dbbfe49f0a..80f9372eb54c 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1063,7 +1063,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // In general, during probing we erase regions. See // `impl_self_ty()` for an explanation. - let region = tcx.mk_region(ty::ReErased); + let region = tcx.types.re_erased; // Search through mutabilities in order to find one where pick works: [hir::MutImmutable, hir::MutMutable] @@ -1325,7 +1325,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } else { // In general, during probe we erase regions. See // `impl_self_ty()` for an explanation. - self.tcx.mk_region(ty::ReErased) + self.tcx.types.re_erased } }, |def, cur_substs| { let i = def.index as usize; @@ -1345,7 +1345,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let substs = Substs::for_item(self.tcx, impl_def_id, - |_, _| self.tcx.mk_region(ty::ReErased), + |_, _| self.tcx.types.re_erased, |_, _| self.next_ty_var( TypeVariableOrigin::SubstitutionPlaceholder( self.tcx.def_span(impl_def_id)))); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 839af0fa6706..098e8c53a52c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1954,7 +1954,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // FIXME(#27579) all uses of this should be migrated to register_wf_obligation eventually let cause = traits::ObligationCause::new(span, self.body_id, code); - self.register_region_obligation(ty, self.tcx.mk_region(ty::ReEmpty), cause); + self.register_region_obligation(ty, self.tcx.types.re_empty, cause); } /// Registers obligations that all types appearing in `substs` are well-formed. @@ -2513,7 +2513,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match lit.node { ast::LitKind::Str(..) => tcx.mk_static_str(), ast::LitKind::ByteStr(ref v) => { - tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), + tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_array(tcx.types.u8, v.len())) } ast::LitKind::Byte(_) => tcx.types.u8, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 8bfb390bd2a5..dcef22da8796 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -457,7 +457,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.type_of_node_must_outlive(origin, id, var_region); let typ = self.resolve_node_type(id); - dropck::check_safety_of_destructor_if_necessary(self, typ, span, var_scope); + let _ = dropck::check_safety_of_destructor_if_necessary( + self, typ, span, var_scope); }) } } @@ -995,10 +996,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { match *region { ty::ReScope(rvalue_scope) => { let typ = self.resolve_type(cmt.ty); - dropck::check_safety_of_destructor_if_necessary(self, - typ, - span, - rvalue_scope); + let _ = dropck::check_safety_of_destructor_if_necessary( + self, typ, span, rvalue_scope); } ty::ReStatic => {} _ => { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index f196aa82b1ef..35b2e8f8afcb 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -288,8 +288,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| { match *r { // 'static is valid everywhere. - ty::ReStatic | - ty::ReEmpty => gcx.mk_region(*r), + ty::ReStatic => gcx.types.re_static, + ty::ReEmpty => gcx.types.re_empty, // Free regions that come from early-bound regions are valid. ty::ReFree(ty::FreeRegion { @@ -307,7 +307,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { span_err!(self.tcx().sess, span, E0564, "only named lifetimes are allowed in `impl Trait`, \ but `{}` was found in the type `{}`", r, inside_ty); - gcx.mk_region(ty::ReStatic) + gcx.types.re_static } ty::ReVar(_) | @@ -526,7 +526,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> { match self.infcx.fully_resolve(&r) { Ok(r) => r, Err(_) => { - self.tcx.mk_region(ty::ReStatic) + self.tcx.types.re_static } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index af0ef279e4f0..660ce837043c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -99,6 +99,8 @@ pub fn provide(providers: &mut Providers) { trait_def, adt_def, impl_trait_ref, + impl_polarity, + is_foreign_item, ..*providers }; } @@ -553,7 +555,8 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr()); prev_discr = Some(if let Some(e) = variant.node.disr_expr { let expr_did = tcx.hir.local_def_id(e.node_id); - let result = ty::queries::monomorphic_const_eval::get(tcx, variant.span, expr_did); + let substs = Substs::empty(); + let result = ty::queries::const_eval::get(tcx, variant.span, (expr_did, substs)); // enum variant evaluation happens before the global constant check // so we need to report the real error @@ -1132,6 +1135,16 @@ fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> hir::ImplPolarity { + let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); + match tcx.hir.expect_item(node_id).node { + hir::ItemImpl(_, polarity, ..) => polarity, + ref item => bug!("trait_impl_polarity: {:?} not an impl", item) + } +} + // Is it marked with ?Sized fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, ast_bounds: &[hir::TyParamBound], @@ -1530,3 +1543,13 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( let substs = Substs::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id, substs, fty) } + +fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> bool { + match tcx.hir.get_if_local(def_id) { + Some(hir_map::NodeForeignItem(..)) => true, + Some(_) => false, + _ => bug!("is_foreign_item applied to non-local def-id {:?}", def_id) + } +} diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index c50156fa5f27..2bae6a0d9e11 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4154,7 +4154,6 @@ register_diagnostics! { // E0248, // value used as a type, now reported earlier during resolution as E0412 // E0249, // E0319, // trait impls for defaulted traits allowed just for structs/enums - E0320, // recursive overflow during dropck // E0372, // coherence not object safe E0377, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures with the same definition diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cc30fdf56fc3..6016fd488f56 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -487,7 +487,7 @@ impl hir::print::PpAnn for InlinedConst { } fn print_inlined_const(cx: &DocContext, did: DefId) -> String { - let body = cx.tcx.sess.cstore.maybe_get_item_body(cx.tcx, did).unwrap(); + let body = cx.tcx.sess.cstore.item_body(cx.tcx, did); let inlined = InlinedConst { nested_bodies: cx.tcx.sess.cstore.item_body_nested_bodies(did) }; diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 4bf856240f66..85a28bbfbc6d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -32,6 +32,7 @@ use std::ascii::AsciiExt; use std::cell::RefCell; use std::collections::{HashMap, VecDeque}; use std::default::Default; +use std::ffi::CString; use std::fmt::{self, Write}; use std::str; use syntax::feature_gate::UnstableFeatures; @@ -40,21 +41,28 @@ use syntax::codemap::Span; use html::render::derive_id; use html::toc::TocBuilder; use html::highlight; +use html::escape::Escape; use test; use pulldown_cmark::{html, Event, Tag, Parser}; use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES}; +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum RenderType { + Hoedown, + Pulldown, +} + /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. // The second parameter is whether we need a shorter version or not. -pub struct Markdown<'a>(pub &'a str); +pub struct Markdown<'a>(pub &'a str, pub RenderType); /// A unit struct like `Markdown`, that renders the markdown with a /// table of contents. -pub struct MarkdownWithToc<'a>(pub &'a str); +pub struct MarkdownWithToc<'a>(pub &'a str, pub RenderType); /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags. -pub struct MarkdownHtml<'a>(pub &'a str); +pub struct MarkdownHtml<'a>(pub &'a str, pub RenderType); /// A unit struct like `Markdown`, that renders only the first paragraph. pub struct MarkdownSummaryLine<'a>(pub &'a str); @@ -73,6 +81,14 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { } } +/// Returns a new string with all consecutive whitespace collapsed into +/// single spaces. +/// +/// Any leading or trailing whitespace will be trimmed. +fn collapse_whitespace(s: &str) -> String { + s.split_whitespace().collect::>().join(" ") +} + /// Convert chars from a title for an id. /// /// "Hello, world!" -> "hello-world" @@ -368,6 +384,7 @@ const HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3; const HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4; const HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8; const HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2; +const HOEDOWN_HTML_ESCAPE: libc::c_uint = 1 << 1; const HOEDOWN_EXTENSIONS: libc::c_uint = HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES | @@ -462,6 +479,13 @@ struct hoedown_buffer { unit: libc::size_t, } +struct MyOpaque { + dfltblk: extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, + *const hoedown_buffer, *const hoedown_renderer_data, + libc::size_t), + toc_builder: Option, +} + extern { fn hoedown_html_renderer_new(render_flags: libc::c_uint, nesting_level: libc::c_int) @@ -478,6 +502,7 @@ extern { fn hoedown_document_free(md: *mut hoedown_document); fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer; + fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *const libc::c_char); fn hoedown_buffer_free(b: *mut hoedown_buffer); } @@ -487,12 +512,214 @@ impl hoedown_buffer { } } +pub fn render(w: &mut fmt::Formatter, + s: &str, + print_toc: bool, + html_flags: libc::c_uint) -> fmt::Result { + extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer, + lang: *const hoedown_buffer, data: *const hoedown_renderer_data, + line: libc::size_t) { + unsafe { + if orig_text.is_null() { return } + + let opaque = (*data).opaque as *mut hoedown_html_renderer_state; + let my_opaque: &MyOpaque = &*((*opaque).opaque as *const MyOpaque); + let text = (*orig_text).as_bytes(); + let origtext = str::from_utf8(text).unwrap(); + let origtext = origtext.trim_left(); + debug!("docblock: ==============\n{:?}\n=======", text); + let rendered = if lang.is_null() || origtext.is_empty() { + false + } else { + let rlang = (*lang).as_bytes(); + let rlang = str::from_utf8(rlang).unwrap(); + if !LangString::parse(rlang).rust { + (my_opaque.dfltblk)(ob, orig_text, lang, + opaque as *const hoedown_renderer_data, + line); + true + } else { + false + } + }; + + let lines = origtext.lines().filter(|l| { + stripped_filtered_line(*l).is_none() + }); + let text = lines.collect::>().join("\n"); + if rendered { return } + PLAYGROUND.with(|play| { + // insert newline to clearly separate it from the + // previous block so we can shorten the html output + let mut s = String::from("\n"); + let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| { + if url.is_empty() { + return None; + } + let test = origtext.lines().map(|l| { + stripped_filtered_line(l).unwrap_or(l) + }).collect::>().join("\n"); + let krate = krate.as_ref().map(|s| &**s); + let test = test::maketest(&test, krate, false, + &Default::default()); + let channel = if test.contains("#![feature(") { + "&version=nightly" + } else { + "" + }; + // These characters don't need to be escaped in a URI. + // FIXME: use a library function for percent encoding. + fn dont_escape(c: u8) -> bool { + (b'a' <= c && c <= b'z') || + (b'A' <= c && c <= b'Z') || + (b'0' <= c && c <= b'9') || + c == b'-' || c == b'_' || c == b'.' || + c == b'~' || c == b'!' || c == b'\'' || + c == b'(' || c == b')' || c == b'*' + } + let mut test_escaped = String::new(); + for b in test.bytes() { + if dont_escape(b) { + test_escaped.push(char::from(b)); + } else { + write!(test_escaped, "%{:02X}", b).unwrap(); + } + } + Some(format!( + r#"Run"#, + url, test_escaped, channel + )) + }); + s.push_str(&highlight::render_with_highlighting( + &text, + Some("rust-example-rendered"), + None, + playground_button.as_ref().map(String::as_str))); + let output = CString::new(s).unwrap(); + hoedown_buffer_puts(ob, output.as_ptr()); + }) + } + } + + extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer, + level: libc::c_int, data: *const hoedown_renderer_data, + _: libc::size_t) { + // hoedown does this, we may as well too + unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); } + + // Extract the text provided + let s = if text.is_null() { + "".to_owned() + } else { + let s = unsafe { (*text).as_bytes() }; + str::from_utf8(&s).unwrap().to_owned() + }; + + // Discard '', '' tags and some escaped characters, + // transform the contents of the header into a hyphenated string + // without non-alphanumeric characters other than '-' and '_'. + // + // This is a terrible hack working around how hoedown gives us rendered + // html for text rather than the raw text. + let mut id = s.clone(); + let repl_sub = vec!["", "", "", "", + "", "", + "<", ">", "&", "'", """]; + for sub in repl_sub { + id = id.replace(sub, ""); + } + let id = id.chars().filter_map(|c| { + if c.is_alphanumeric() || c == '-' || c == '_' { + if c.is_ascii() { + Some(c.to_ascii_lowercase()) + } else { + Some(c) + } + } else if c.is_whitespace() && c.is_ascii() { + Some('-') + } else { + None + } + }).collect::(); + + let opaque = unsafe { (*data).opaque as *mut hoedown_html_renderer_state }; + let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) }; + + let id = derive_id(id); + + let sec = opaque.toc_builder.as_mut().map_or("".to_owned(), |builder| { + format!("{} ", builder.push(level as u32, s.clone(), id.clone())) + }); + + // Render the HTML + let text = format!("\ + {sec}{}", + s, lvl = level, id = id, sec = sec); + + let text = CString::new(text).unwrap(); + unsafe { hoedown_buffer_puts(ob, text.as_ptr()) } + } + + extern fn codespan( + ob: *mut hoedown_buffer, + text: *const hoedown_buffer, + _: *const hoedown_renderer_data, + _: libc::size_t + ) -> libc::c_int { + let content = if text.is_null() { + "".to_owned() + } else { + let bytes = unsafe { (*text).as_bytes() }; + let s = str::from_utf8(bytes).unwrap(); + collapse_whitespace(s) + }; + + let content = format!("{}", Escape(&content)); + let element = CString::new(content).unwrap(); + unsafe { hoedown_buffer_puts(ob, element.as_ptr()); } + // Return anything except 0, which would mean "also print the code span verbatim". + 1 + } + + unsafe { + let ob = hoedown_buffer_new(DEF_OUNIT); + let renderer = hoedown_html_renderer_new(html_flags, 0); + let mut opaque = MyOpaque { + dfltblk: (*renderer).blockcode.unwrap(), + toc_builder: if print_toc {Some(TocBuilder::new())} else {None} + }; + (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque + = &mut opaque as *mut _ as *mut libc::c_void; + (*renderer).blockcode = Some(block); + (*renderer).header = Some(header); + (*renderer).codespan = Some(codespan); + + let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); + hoedown_document_render(document, ob, s.as_ptr(), + s.len() as libc::size_t); + hoedown_document_free(document); + + hoedown_html_renderer_free(renderer); + + let mut ret = opaque.toc_builder.map_or(Ok(()), |builder| { + write!(w, "", builder.into_toc()) + }); + + if ret.is_ok() { + let buf = (*ob).as_bytes(); + ret = w.write_str(str::from_utf8(buf).unwrap()); + } + hoedown_buffer_free(ob); + ret + } +} + pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { extern fn block(_ob: *mut hoedown_buffer, text: *const hoedown_buffer, lang: *const hoedown_buffer, data: *const hoedown_renderer_data, - _line: libc::size_t) { + line: libc::size_t) { unsafe { if text.is_null() { return } let block_info = if lang.is_null() { @@ -510,8 +737,19 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position let lines = text.lines().map(|l| { stripped_filtered_line(l).unwrap_or(l) }); + let text = lines.collect::>().join("\n"); let filename = tests.get_filename(); - tests.add_old_test(lines.collect::>().join("\n"), filename); + + if tests.render_type == RenderType::Hoedown { + let line = tests.get_line() + line; + tests.add_test(text.to_owned(), + block_info.should_panic, block_info.no_run, + block_info.ignore, block_info.test_harness, + block_info.compile_fail, block_info.error_codes, + line, filename); + } else { + tests.add_old_test(text, filename); + } } } @@ -533,7 +771,6 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position } tests.set_position(position); - unsafe { let ob = hoedown_buffer_new(DEF_OUNIT); let renderer = hoedown_html_renderer_new(0, 0); @@ -702,72 +939,84 @@ impl LangString { impl<'a> fmt::Display for Markdown<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let Markdown(md) = *self; + let Markdown(md, render_type) = *self; + // This is actually common enough to special-case if md.is_empty() { return Ok(()) } + if render_type == RenderType::Hoedown { + render(fmt, md, false, 0) + } else { + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); + let p = Parser::new_ext(md, opts); - let p = Parser::new_ext(md, opts); + let mut s = String::with_capacity(md.len() * 3 / 2); - let mut s = String::with_capacity(md.len() * 3 / 2); + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); - html::push_html(&mut s, - Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); - - fmt.write_str(&s) + fmt.write_str(&s) + } } } impl<'a> fmt::Display for MarkdownWithToc<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let MarkdownWithToc(md) = *self; + let MarkdownWithToc(md, render_type) = *self; - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); + if render_type == RenderType::Hoedown { + render(fmt, md, true, 0) + } else { + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); - let p = Parser::new_ext(md, opts); + let p = Parser::new_ext(md, opts); - let mut s = String::with_capacity(md.len() * 3 / 2); + let mut s = String::with_capacity(md.len() * 3 / 2); - let mut toc = TocBuilder::new(); + let mut toc = TocBuilder::new(); - html::push_html(&mut s, - Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc))))); + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc))))); - write!(fmt, "", toc.into_toc())?; + write!(fmt, "", toc.into_toc())?; - fmt.write_str(&s) + fmt.write_str(&s) + } } } impl<'a> fmt::Display for MarkdownHtml<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let MarkdownHtml(md) = *self; + let MarkdownHtml(md, render_type) = *self; + // This is actually common enough to special-case if md.is_empty() { return Ok(()) } + if render_type == RenderType::Hoedown { + render(fmt, md, false, HOEDOWN_HTML_ESCAPE) + } else { + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); + let p = Parser::new_ext(md, opts); - let p = Parser::new_ext(md, opts); + // Treat inline HTML as plain text. + let p = p.map(|event| match event { + Event::Html(text) | Event::InlineHtml(text) => Event::Text(text), + _ => event + }); - // Treat inline HTML as plain text. - let p = p.map(|event| match event { - Event::Html(text) | Event::InlineHtml(text) => Event::Text(text), - _ => event - }); + let mut s = String::with_capacity(md.len() * 3 / 2); - let mut s = String::with_capacity(md.len() * 3 / 2); + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); - html::push_html(&mut s, - Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); - - fmt.write_str(&s) + fmt.write_str(&s) + } } } @@ -841,6 +1090,7 @@ pub fn plain_summary_line(md: &str) -> String { mod tests { use super::{LangString, Markdown, MarkdownHtml}; use super::plain_summary_line; + use super::RenderType; use html::render::reset_ids; #[test] @@ -881,14 +1131,14 @@ mod tests { #[test] fn issue_17736() { let markdown = "# title"; - format!("{}", Markdown(markdown)); + format!("{}", Markdown(markdown, RenderType::Pulldown)); reset_ids(true); } #[test] fn test_header() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input)); + let output = format!("{}", Markdown(input, RenderType::Pulldown)); assert_eq!(output, expect, "original: {}", input); reset_ids(true); } @@ -910,7 +1160,7 @@ mod tests { #[test] fn test_header_ids_multiple_blocks() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input)); + let output = format!("{}", Markdown(input, RenderType::Pulldown)); assert_eq!(output, expect, "original: {}", input); } @@ -951,7 +1201,7 @@ mod tests { #[test] fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { - let output = format!("{}", MarkdownHtml(input)); + let output = format!("{}", MarkdownHtml(input, RenderType::Pulldown)); assert_eq!(output, expect, "original: {}", input); } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d55a0640562a..57d71e6c4e00 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -72,7 +72,7 @@ use html::format::{TyParamBounds, WhereClause, href, AbiSpace}; use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace}; use html::format::fmt_impl_for_trait_page; use html::item_type::ItemType; -use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine}; +use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, RenderType}; use html::{highlight, layout}; /// A pair of name and its optional document. @@ -98,6 +98,7 @@ pub struct Context { /// publicly reused items to redirect to the right location. pub render_redirect_pages: bool, pub shared: Arc, + pub render_type: RenderType, } pub struct SharedContext { @@ -433,7 +434,8 @@ pub fn run(mut krate: clean::Crate, dst: PathBuf, passes: FxHashSet, css_file_extension: Option, - renderinfo: RenderInfo) -> Result<(), Error> { + renderinfo: RenderInfo, + render_type: RenderType) -> Result<(), Error> { let src_root = match krate.src.parent() { Some(p) => p.to_path_buf(), None => PathBuf::new(), @@ -495,6 +497,7 @@ pub fn run(mut krate: clean::Crate, dst: dst, render_redirect_pages: false, shared: Arc::new(scx), + render_type: render_type, }; // Crawl the crate to build various caches used for the output @@ -1638,11 +1641,12 @@ fn plain_summary_line(s: Option<&str>) -> String { fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result { document_stability(w, cx, item)?; - document_full(w, item)?; + document_full(w, item, cx.render_type)?; Ok(()) } -fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink) -> fmt::Result { +fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink, + render_type: RenderType) -> fmt::Result { if let Some(s) = item.doc_value() { let markdown = if s.contains('\n') { format!("{} [Read more]({})", @@ -1651,7 +1655,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin format!("{}", &plain_summary_line(Some(s))) }; write!(w, "
{}
", - Markdown(&markdown))?; + Markdown(&markdown, render_type))?; } Ok(()) } @@ -1681,10 +1685,11 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> { } } -fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { +fn document_full(w: &mut fmt::Formatter, item: &clean::Item, + render_type: RenderType) -> fmt::Result { if let Some(s) = get_doc_value(item) { write!(w, "
{}
", - Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?; + Markdown(&format!("{}{}", md_render_assoc_item(item), s), render_type))?; } Ok(()) } @@ -1872,7 +1877,13 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ", name = *myitem.name.as_ref().unwrap(), stab_docs = stab_docs, - docs = MarkdownSummaryLine(doc_value), + docs = if cx.render_type == RenderType::Hoedown { + format!("{}", + shorter(Some(&Markdown(doc_value, + RenderType::Hoedown).to_string()))) + } else { + format!("{}", MarkdownSummaryLine(doc_value)) + }, class = myitem.type_(), stab = myitem.stability_class().unwrap_or("".to_string()), unsafety_flag = unsafety_flag, @@ -1915,7 +1926,9 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec{}", text)) }; @@ -1944,7 +1957,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec🔬 \ This is a nightly-only experimental API. {}\ {}", - unstable_extra, MarkdownHtml(&stab.unstable_reason)); + unstable_extra, + MarkdownHtml(&stab.unstable_reason, cx.render_type)); stability.push(format!("
{}
", text)); } @@ -1964,7 +1978,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec{}", text)) } @@ -2900,7 +2914,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "")?; write!(w, "\n")?; if let Some(ref dox) = i.impl_item.doc_value() { - write!(w, "
{}
", Markdown(dox))?; + write!(w, "
{}
", Markdown(dox, cx.render_type))?; } } @@ -2999,11 +3013,11 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi // because impls can't have a stability. document_stability(w, cx, it)?; if get_doc_value(item).is_some() { - document_full(w, item)?; + document_full(w, item, cx.render_type)?; } else { // In case the item isn't documented, // provide short documentation from the trait. - document_short(w, it, link)?; + document_short(w, it, link, cx.render_type)?; } } } else { @@ -3011,7 +3025,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi } } else { document_stability(w, cx, item)?; - document_short(w, item, link)?; + document_short(w, item, link, cx.render_type)?; } } Ok(()) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 0ca267bb82d2..2a6134fde5c3 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -93,6 +93,8 @@ pub mod test; use clean::AttributesExt; +use html::markdown::RenderType; + struct Output { krate: clean::Crate, renderinfo: html::render::RenderInfo, @@ -169,6 +171,7 @@ pub fn opts() -> Vec { "URL to send code snippets to, may be reset by --markdown-playground-url \ or `#![doc(html_playground_url=...)]`", "URL")), + unstable(optflag("", "enable-commonmark", "to enable commonmark doc rendering/testing")), ] } @@ -250,6 +253,12 @@ pub fn main_args(args: &[String]) -> isize { let css_file_extension = matches.opt_str("e").map(|s| PathBuf::from(&s)); let cfgs = matches.opt_strs("cfg"); + let render_type = if matches.opt_present("enable-commonmark") { + RenderType::Pulldown + } else { + RenderType::Hoedown + }; + if let Some(ref p) = css_file_extension { if !p.is_file() { writeln!( @@ -273,15 +282,17 @@ pub fn main_args(args: &[String]) -> isize { match (should_test, markdown_input) { (true, true) => { - return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot) + return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, render_type) } (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) } (false, true) => return markdown::render(input, output.unwrap_or(PathBuf::from("doc")), &matches, &external_html, - !matches.opt_present("markdown-no-toc")), + !matches.opt_present("markdown-no-toc"), + render_type), (false, false) => {} } @@ -295,7 +306,8 @@ pub fn main_args(args: &[String]) -> isize { output.unwrap_or(PathBuf::from("doc")), passes.into_iter().collect(), css_file_extension, - renderinfo) + renderinfo, + render_type) .expect("failed to generate documentation"); 0 } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index f75144c23aca..b9ed0eeaef73 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -26,6 +26,7 @@ use html::render::reset_ids; use html::escape::Escape; use html::markdown; use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, old_find_testable_code}; +use html::markdown::RenderType; use test::{TestOptions, Collector}; /// Separate any lines at the start of the file that begin with `# ` or `%`. @@ -50,7 +51,8 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) { /// Render `input` (e.g. "foo.md") into an HTML file in `output` /// (e.g. output = "bar" => "bar/foo.html"). pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, - external_html: &ExternalHtml, include_toc: bool) -> isize { + external_html: &ExternalHtml, include_toc: bool, + render_type: RenderType) -> isize { let input_p = Path::new(input); output.push(input_p.file_stem().unwrap()); output.set_extension("html"); @@ -94,9 +96,9 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, reset_ids(false); let rendered = if include_toc { - format!("{}", MarkdownWithToc(text)) + format!("{}", MarkdownWithToc(text, render_type)) } else { - format!("{}", Markdown(text)) + format!("{}", Markdown(text, render_type)) }; let err = write!( @@ -147,7 +149,8 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, /// Run any tests/code examples in the markdown file `input`. pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, - mut test_args: Vec, maybe_sysroot: Option) -> isize { + mut test_args: Vec, maybe_sysroot: Option, + render_type: RenderType) -> isize { let input_str = match load_string(input) { Ok(s) => s, Err(LoadStringError::ReadFail) => return 1, @@ -158,7 +161,8 @@ pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, opts.no_crate_inject = true; let mut collector = Collector::new(input.to_string(), cfgs, libs, externs, true, opts, maybe_sysroot, None, - Some(input.to_owned())); + Some(input.to_owned()), + render_type); old_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()); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 3206b5021075..5b9ab304db0a 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -43,7 +43,7 @@ use errors; use errors::emitter::ColorConfig; use clean::Attributes; -use html::markdown; +use html::markdown::{self, RenderType}; #[derive(Clone, Default)] pub struct TestOptions { @@ -57,7 +57,8 @@ pub fn run(input: &str, externs: Externs, mut test_args: Vec, crate_name: Option, - maybe_sysroot: Option) + maybe_sysroot: Option, + render_type: RenderType) -> isize { let input_path = PathBuf::from(input); let input = config::Input::File(input_path.clone()); @@ -106,7 +107,8 @@ pub fn run(input: &str, opts, maybe_sysroot, Some(codemap), - None); + None, + render_type); { let dep_graph = DepGraph::new(false); @@ -396,12 +398,15 @@ pub struct Collector { position: Span, codemap: Option>, filename: Option, + // to be removed when hoedown will be removed as well + pub render_type: RenderType, } impl Collector { pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: Externs, use_headers: bool, opts: TestOptions, maybe_sysroot: Option, - codemap: Option>, filename: Option) -> Collector { + codemap: Option>, filename: Option, + render_type: RenderType) -> Collector { Collector { tests: Vec::new(), old_tests: HashMap::new(), @@ -418,6 +423,7 @@ impl Collector { position: DUMMY_SP, codemap: codemap, filename: filename, + render_type: render_type, } } @@ -458,20 +464,22 @@ impl Collector { as_test_harness: bool, compile_fail: bool, error_codes: Vec, line: usize, filename: String) { let name = self.generate_name(line, &filename); - let name_beg = self.generate_name_beginning(&filename); - let mut found = false; // to be removed when hoedown is removed - let test = test.trim().to_owned(); - if let Some(entry) = self.old_tests.get_mut(&name_beg) { - found = entry.remove_item(&test).is_some(); - } - if !found { - let _ = writeln!(&mut io::stderr(), - "WARNING: {} Code block is not currently run as a test, but will in \ - future versions of rustdoc. Please ensure this code block is a \ - runnable test, or use the `ignore` directive.", - name); - return + if self.render_type == RenderType::Pulldown { + let name_beg = self.generate_name_beginning(&filename); + let mut found = false; + let test = test.trim().to_owned(); + if let Some(entry) = self.old_tests.get_mut(&name_beg) { + found = entry.remove_item(&test).is_some(); + } + if !found { + let _ = writeln!(&mut io::stderr(), + "WARNING: {} Code block is not currently run as a test, but will \ + in future versions of rustdoc. Please ensure this code block is \ + a runnable test, or use the `ignore` directive.", + name); + return + } } let cfgs = self.cfgs.clone(); let libs = self.libs.clone(); @@ -587,10 +595,15 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { attrs.unindent_doc_comments(); if let Some(doc) = attrs.doc_value() { self.collector.cnt = 0; - markdown::old_find_testable_code(doc, self.collector, + if self.collector.render_type == RenderType::Pulldown { + markdown::old_find_testable_code(doc, self.collector, + attrs.span.unwrap_or(DUMMY_SP)); + markdown::find_testable_code(doc, self.collector, attrs.span.unwrap_or(DUMMY_SP)); - markdown::find_testable_code(doc, self.collector, - attrs.span.unwrap_or(DUMMY_SP)); + } else { + markdown::old_find_testable_code(doc, self.collector, + attrs.span.unwrap_or(DUMMY_SP)); + } } nested(self); diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index eacb59d375a5..51d127f8ba79 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1377,7 +1377,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> { /// An owning iterator over the entries of a `HashMap`. /// -/// This `struct` is created by the [`into_iter`] method on [`HashMap`] +/// This `struct` is created by the [`into_iter`] method on [`HashMap`][`HashMap`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.HashMap.html#method.into_iter @@ -2017,13 +2017,6 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { self.elem.read().0 } - /// Deprecated, renamed to `remove_entry` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")] - pub fn remove_pair(self) -> (K, V) { - self.remove_entry() - } - /// Take the ownership of the key and value from the map. /// /// # Examples diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index e3fad2850257..7215e1bde850 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -890,7 +890,7 @@ pub struct Iter<'a, K: 'a> { /// An owning iterator over the items of a `HashSet`. /// -/// This `struct` is created by the [`into_iter`] method on [`HashSet`] +/// This `struct` is created by the [`into_iter`] method on [`HashSet`][`HashSet`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`HashSet`]: struct.HashSet.html diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 316e6841c4fe..4abad7e24f81 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -22,8 +22,6 @@ use core::num; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] -use libc::c_int; -#[cfg(not(test))] use num::FpCategory; @@ -73,8 +71,6 @@ mod cmath { pub fn atan2f(a: c_float, b: c_float) -> c_float; pub fn atanf(n: c_float) -> c_float; pub fn coshf(n: c_float) -> c_float; - pub fn frexpf(n: c_float, value: &mut c_int) -> c_float; - pub fn ldexpf(x: c_float, n: c_int) -> c_float; pub fn sinhf(n: c_float) -> c_float; pub fn tanf(n: c_float) -> c_float; pub fn tanhf(n: c_float) -> c_float; @@ -84,7 +80,7 @@ mod cmath { pub use self::shims::*; #[cfg(target_env = "msvc")] mod shims { - use libc::{c_float, c_int}; + use libc::c_float; #[inline] pub unsafe fn acosf(n: c_float) -> c_float { @@ -111,20 +107,6 @@ mod cmath { f64::cosh(n as f64) as c_float } - #[inline] - #[allow(deprecated)] - pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float { - let (a, b) = f64::frexp(x as f64); - *value = b as c_int; - a as c_float - } - - #[inline] - #[allow(deprecated)] - pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float { - f64::ldexp(x as f64, n as isize) as c_float - } - #[inline] pub unsafe fn sinhf(n: c_float) -> c_float { f64::sinh(n as f64) as c_float @@ -244,40 +226,6 @@ impl f32 { #[inline] pub fn classify(self) -> FpCategory { num::Float::classify(self) } - /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. - /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. - /// The floating point encoding is documented in the [Reference][floating-point]. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// - /// let num = 2.0f32; - /// - /// // (8388608, -22, 1) - /// let (mantissa, exponent, sign) = num.integer_decode(); - /// let sign_f = sign as f32; - /// let mantissa_f = mantissa as f32; - /// let exponent_f = num.powf(exponent as f32); - /// - /// // 1 * 8388608 * 2^(-22) == 2 - /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - /// [floating-point]: ../reference/types.html#machine-types - #[unstable(feature = "float_extras", reason = "signature is undecided", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - #[allow(deprecated)] - pub fn integer_decode(self) -> (u64, i16, i8) { - num::Float::integer_decode(self) - } - /// Returns the largest integer less than or equal to a number. /// /// ``` @@ -712,89 +660,6 @@ impl f32 { #[inline] pub fn to_radians(self) -> f32 { num::Float::to_radians(self) } - /// Constructs a floating point number of `x*2^exp`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// // 3*2^2 - 12 == 0 - /// let abs_difference = (f32::ldexp(3.0, 2) - 12.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn ldexp(x: f32, exp: isize) -> f32 { - unsafe { cmath::ldexpf(x, exp as c_int) } - } - - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// * `self = x * 2^exp` - /// * `0.5 <= abs(x) < 1.0` - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// - /// let x = 4.0f32; - /// - /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0 - /// let f = x.frexp(); - /// let abs_difference_0 = (f.0 - 0.5).abs(); - /// let abs_difference_1 = (f.1 as f32 - 3.0).abs(); - /// - /// assert!(abs_difference_0 <= f32::EPSILON); - /// assert!(abs_difference_1 <= f32::EPSILON); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn frexp(self) -> (f32, isize) { - unsafe { - let mut exp = 0; - let x = cmath::frexpf(self, &mut exp); - (x, exp as isize) - } - } - - /// Returns the next representable floating-point value in the direction of - /// `other`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// - /// let x = 1.0f32; - /// - /// let abs_diff = (x.next_after(2.0) - 1.00000011920928955078125_f32).abs(); - /// - /// assert!(abs_diff <= f32::EPSILON); - /// ``` - #[unstable(feature = "float_extras", - reason = "unsure about its place in the world", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn next_after(self, other: f32) -> f32 { - unsafe { cmath::nextafterf(self, other) } - } - /// Returns the maximum of the two numbers. /// /// ``` @@ -1462,23 +1327,6 @@ mod tests { assert_eq!(1e-38f32.classify(), Fp::Subnormal); } - #[test] - #[allow(deprecated)] - fn test_integer_decode() { - assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); - assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); - assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); - assert_eq!(0f32.integer_decode(), (0, -150, 1)); - assert_eq!((-0f32).integer_decode(), (0, -150, -1)); - assert_eq!(INFINITY.integer_decode(), (8388608, 105, 1)); - assert_eq!(NEG_INFINITY.integer_decode(), (8388608, 105, -1)); - - // Ignore the "sign" (quiet / signalling flag) of NAN. - // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (12582912, 105)); - } - #[test] fn test_floor() { assert_approx_eq!(1.0f32.floor(), 1.0f32); @@ -1790,58 +1638,6 @@ mod tests { assert_eq!(neg_inf.to_radians(), neg_inf); } - #[test] - #[allow(deprecated)] - fn test_ldexp() { - let f1 = 2.0f32.powi(-123); - let f2 = 2.0f32.powi(-111); - let f3 = 1.75 * 2.0f32.powi(-12); - assert_eq!(f32::ldexp(1f32, -123), f1); - assert_eq!(f32::ldexp(1f32, -111), f2); - assert_eq!(f32::ldexp(1.75f32, -12), f3); - - assert_eq!(f32::ldexp(0f32, -123), 0f32); - assert_eq!(f32::ldexp(-0f32, -123), -0f32); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(f32::ldexp(inf, -123), inf); - assert_eq!(f32::ldexp(neg_inf, -123), neg_inf); - assert!(f32::ldexp(nan, -123).is_nan()); - } - - #[test] - #[allow(deprecated)] - fn test_frexp() { - let f1 = 2.0f32.powi(-123); - let f2 = 2.0f32.powi(-111); - let f3 = 1.75 * 2.0f32.powi(-123); - let (x1, exp1) = f1.frexp(); - let (x2, exp2) = f2.frexp(); - let (x3, exp3) = f3.frexp(); - assert_eq!((x1, exp1), (0.5f32, -122)); - assert_eq!((x2, exp2), (0.5f32, -110)); - assert_eq!((x3, exp3), (0.875f32, -122)); - assert_eq!(f32::ldexp(x1, exp1), f1); - assert_eq!(f32::ldexp(x2, exp2), f2); - assert_eq!(f32::ldexp(x3, exp3), f3); - - assert_eq!(0f32.frexp(), (0f32, 0)); - assert_eq!((-0f32).frexp(), (-0f32, 0)); - } - - #[test] #[cfg_attr(windows, ignore)] // FIXME #8755 - #[allow(deprecated)] - fn test_frexp_nowin() { - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(match inf.frexp() { (x, _) => x }, inf); - assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf); - assert!(match nan.frexp() { (x, _) => x.is_nan() }) - } - #[test] fn test_asinh() { assert_eq!(0.0f32.asinh(), 0.0f32); diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index be55cb80c92f..82e3903eec7b 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -22,8 +22,6 @@ use core::num; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] -use libc::c_int; -#[cfg(not(test))] use num::FpCategory; #[stable(feature = "rust1", since = "1.0.0")] @@ -188,36 +186,6 @@ impl f64 { #[inline] pub fn classify(self) -> FpCategory { num::Float::classify(self) } - /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. - /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. - /// The floating point encoding is documented in the [Reference][floating-point]. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// let num = 2.0f64; - /// - /// // (8388608, -22, 1) - /// let (mantissa, exponent, sign) = num.integer_decode(); - /// let sign_f = sign as f64; - /// let mantissa_f = mantissa as f64; - /// let exponent_f = num.powf(exponent as f64); - /// - /// // 1 * 8388608 * 2^(-22) == 2 - /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - /// [floating-point]: ../reference/types.html#machine-types - #[unstable(feature = "float_extras", reason = "signature is undecided", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - #[allow(deprecated)] - pub fn integer_decode(self) -> (u64, i16, i8) { num::Float::integer_decode(self) } - /// Returns the largest integer less than or equal to a number. /// /// ``` @@ -606,84 +574,6 @@ impl f64 { #[inline] pub fn to_radians(self) -> f64 { num::Float::to_radians(self) } - /// Constructs a floating point number of `x*2^exp`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// // 3*2^2 - 12 == 0 - /// let abs_difference = (f64::ldexp(3.0, 2) - 12.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn ldexp(x: f64, exp: isize) -> f64 { - unsafe { cmath::ldexp(x, exp as c_int) } - } - - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// * `self = x * 2^exp` - /// * `0.5 <= abs(x) < 1.0` - /// - /// ``` - /// #![feature(float_extras)] - /// - /// let x = 4.0_f64; - /// - /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0 - /// let f = x.frexp(); - /// let abs_difference_0 = (f.0 - 0.5).abs(); - /// let abs_difference_1 = (f.1 as f64 - 3.0).abs(); - /// - /// assert!(abs_difference_0 < 1e-10); - /// assert!(abs_difference_1 < 1e-10); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn frexp(self) -> (f64, isize) { - unsafe { - let mut exp = 0; - let x = cmath::frexp(self, &mut exp); - (x, exp as isize) - } - } - - /// Returns the next representable floating-point value in the direction of - /// `other`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// let x = 1.0f64; - /// - /// let abs_diff = (x.next_after(2.0) - 1.0000000000000002220446049250313_f64).abs(); - /// - /// assert!(abs_diff < 1e-10); - /// ``` - #[unstable(feature = "float_extras", - reason = "unsure about its place in the world", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn next_after(self, other: f64) -> f64 { - unsafe { cmath::nextafter(self, other) } - } - /// Returns the maximum of the two numbers. /// /// ``` @@ -1353,23 +1243,6 @@ mod tests { assert_eq!(1e-308f64.classify(), Fp::Subnormal); } - #[test] - #[allow(deprecated)] - fn test_integer_decode() { - assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); - assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); - assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); - assert_eq!(0f64.integer_decode(), (0, -1075, 1)); - assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); - assert_eq!(INFINITY.integer_decode(), (4503599627370496, 972, 1)); - assert_eq!(NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1)); - - // Ignore the "sign" (quiet / signalling flag) of NAN. - // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (6755399441055744, 972)); - } - #[test] fn test_floor() { assert_approx_eq!(1.0f64.floor(), 1.0f64); @@ -1681,58 +1554,6 @@ mod tests { assert_eq!(neg_inf.to_radians(), neg_inf); } - #[test] - #[allow(deprecated)] - fn test_ldexp() { - let f1 = 2.0f64.powi(-123); - let f2 = 2.0f64.powi(-111); - let f3 = 1.75 * 2.0f64.powi(-12); - assert_eq!(f64::ldexp(1f64, -123), f1); - assert_eq!(f64::ldexp(1f64, -111), f2); - assert_eq!(f64::ldexp(1.75f64, -12), f3); - - assert_eq!(f64::ldexp(0f64, -123), 0f64); - assert_eq!(f64::ldexp(-0f64, -123), -0f64); - - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; - assert_eq!(f64::ldexp(inf, -123), inf); - assert_eq!(f64::ldexp(neg_inf, -123), neg_inf); - assert!(f64::ldexp(nan, -123).is_nan()); - } - - #[test] - #[allow(deprecated)] - fn test_frexp() { - let f1 = 2.0f64.powi(-123); - let f2 = 2.0f64.powi(-111); - let f3 = 1.75 * 2.0f64.powi(-123); - let (x1, exp1) = f1.frexp(); - let (x2, exp2) = f2.frexp(); - let (x3, exp3) = f3.frexp(); - assert_eq!((x1, exp1), (0.5f64, -122)); - assert_eq!((x2, exp2), (0.5f64, -110)); - assert_eq!((x3, exp3), (0.875f64, -122)); - assert_eq!(f64::ldexp(x1, exp1), f1); - assert_eq!(f64::ldexp(x2, exp2), f2); - assert_eq!(f64::ldexp(x3, exp3), f3); - - assert_eq!(0f64.frexp(), (0f64, 0)); - assert_eq!((-0f64).frexp(), (-0f64, 0)); - } - - #[test] #[cfg_attr(windows, ignore)] // FIXME #8755 - #[allow(deprecated)] - fn test_frexp_nowin() { - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; - assert_eq!(match inf.frexp() { (x, _) => x }, inf); - assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf); - assert!(match nan.frexp() { (x, _) => x.is_nan() }) - } - #[test] fn test_asinh() { assert_eq!(0.0f64.asinh(), 0.0f64); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 367779bb701c..70225da5f335 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -248,7 +248,6 @@ #![feature(allow_internal_unstable)] #![feature(asm)] #![feature(associated_consts)] -#![feature(borrow_state)] #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] @@ -263,7 +262,6 @@ #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] -#![feature(float_extras)] #![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] @@ -319,7 +317,6 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_push_all)] -#![feature(zero_one)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(stage0, feature(pub_restricted))] #![cfg_attr(test, feature(float_bits_conv))] diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 5f83d077a136..ff89887ac92c 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -16,9 +16,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -pub use core::num::{Zero, One}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 15bc74a83401..9d66430bc930 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -10,7 +10,7 @@ //! Cross-platform path manipulation. //! -//! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`] +//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`] //! and [`str`]), for working with paths abstractly. These types are thin wrappers //! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly //! on strings according to the local platform's path syntax. diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 852675edc023..6c8839224f77 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -452,7 +452,7 @@ pub struct SendError(#[stable(feature = "rust1", since = "1.0.0")] pub T); /// An error returned from the [`recv`] function on a [`Receiver`]. /// /// The [`recv`] operation can only fail if the sending half of a -/// [`channel`] (or [`sync_channel`]) is disconnected, implying that no further +/// [`channel`][`channel`] (or [`sync_channel`]) is disconnected, implying that no further /// messages will ever be received. /// /// [`recv`]: struct.Receiver.html#method.recv diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0cdb09a842f4..1baf0d1b54ce 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -152,6 +152,7 @@ fn maybe_append(mut lhs: Vec, rhs: Option>) enum PrevTokenKind { DocComment, Comma, + Plus, Interpolated, Eof, Other, @@ -1061,6 +1062,7 @@ impl<'a> Parser<'a> { self.prev_token_kind = match self.token { token::DocComment(..) => PrevTokenKind::DocComment, token::Comma => PrevTokenKind::Comma, + token::BinOp(token::Plus) => PrevTokenKind::Plus, token::Interpolated(..) => PrevTokenKind::Interpolated, token::Eof => PrevTokenKind::Eof, _ => PrevTokenKind::Other, @@ -1354,20 +1356,26 @@ impl<'a> Parser<'a> { break; } } + let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; self.expect(&token::CloseDelim(token::Paren))?; if ts.len() == 1 && !last_comma { let ty = ts.into_iter().nth(0).unwrap().unwrap(); + let maybe_bounds = allow_plus && self.token == token::BinOp(token::Plus); match ty.node { - // Accept `(Trait1) + Trait2 + 'a` for backward compatibility (#39318). - TyKind::Path(None, ref path) - if allow_plus && self.token == token::BinOp(token::Plus) => { - self.bump(); // `+` - let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span)); - let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)]; - bounds.append(&mut self.parse_ty_param_bounds()?); - TyKind::TraitObject(bounds) + // `(TY_BOUND_NOPAREN) + BOUND + ...`. + TyKind::Path(None, ref path) if maybe_bounds => { + self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)? } + TyKind::TraitObject(ref bounds) + if maybe_bounds && bounds.len() == 1 && !trailing_plus => { + let path = match bounds[0] { + TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(), + _ => self.bug("unexpected lifetime bound"), + }; + self.parse_remaining_bounds(Vec::new(), path, lo, true)? + } + // `(TYPE)` _ => TyKind::Paren(P(ty)) } } else { @@ -1418,11 +1426,8 @@ impl<'a> Parser<'a> { // Just a type path or bound list (trait object type) starting with a trait. // `Type` // `Trait1 + Trait2 + 'a` - if allow_plus && self.eat(&token::BinOp(token::Plus)) { - let poly_trait = PolyTraitRef::new(Vec::new(), path, lo.to(self.prev_span)); - let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; - bounds.append(&mut self.parse_ty_param_bounds()?); - TyKind::TraitObject(bounds) + if allow_plus && self.check(&token::BinOp(token::Plus)) { + self.parse_remaining_bounds(Vec::new(), path, lo, true)? } else { TyKind::Path(None, path) } @@ -1440,12 +1445,8 @@ impl<'a> Parser<'a> { self.parse_ty_bare_fn(lifetime_defs)? } else { let path = self.parse_path(PathStyle::Type)?; - let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); - let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; - if allow_plus && self.eat(&token::BinOp(token::Plus)) { - bounds.append(&mut self.parse_ty_param_bounds()?) - } - TyKind::TraitObject(bounds) + let parse_plus = allow_plus && self.check(&token::BinOp(token::Plus)); + self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? } } else if self.eat_keyword(keywords::Impl) { // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511). @@ -1468,6 +1469,17 @@ impl<'a> Parser<'a> { Ok(P(ty)) } + fn parse_remaining_bounds(&mut self, lifetime_defs: Vec, path: ast::Path, + lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { + let poly_trait_ref = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); + let mut bounds = vec![TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)]; + if parse_plus { + self.bump(); // `+` + bounds.append(&mut self.parse_ty_param_bounds()?); + } + Ok(TyKind::TraitObject(bounds)) + } + fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { // Do not add `+` to expected tokens. if !allow_plus || self.token != token::BinOp(token::Plus) { @@ -4070,28 +4082,43 @@ impl<'a> Parser<'a> { // Parse bounds of a type parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) - // TY_BOUND = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) + // TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) + // TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> { let mut bounds = Vec::new(); loop { - let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; - if self.check_lifetime() { - if let Some(question_span) = question { - self.span_err(question_span, - "`?` may only modify trait bounds, not lifetime bounds"); - } - bounds.push(RegionTyParamBound(self.expect_lifetime())); - } else if self.check_keyword(keywords::For) || self.check_path() { - let lo = self.span; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - let path = self.parse_path(PathStyle::Type)?; - let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); - let modifier = if question.is_some() { - TraitBoundModifier::Maybe + let is_bound_start = self.check_path() || self.check_lifetime() || + self.check(&token::Question) || + self.check_keyword(keywords::For) || + self.check(&token::OpenDelim(token::Paren)); + if is_bound_start { + let has_parens = self.eat(&token::OpenDelim(token::Paren)); + let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; + if self.token.is_lifetime() { + if let Some(question_span) = question { + self.span_err(question_span, + "`?` may only modify trait bounds, not lifetime bounds"); + } + bounds.push(RegionTyParamBound(self.expect_lifetime())); } else { - TraitBoundModifier::None - }; - bounds.push(TraitTyParamBound(poly_trait, modifier)); + let lo = self.span; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); + let modifier = if question.is_some() { + TraitBoundModifier::Maybe + } else { + TraitBoundModifier::None + }; + bounds.push(TraitTyParamBound(poly_trait, modifier)); + } + if has_parens { + self.expect(&token::CloseDelim(token::Paren))?; + if let Some(&RegionTyParamBound(..)) = bounds.last() { + self.span_err(self.prev_span, + "parenthesized lifetime bounds are not supported"); + } + } } else { break } diff --git a/src/test/codegen/drop.rs b/src/test/codegen/drop.rs index a4bd5cf2c158..d7e2cb6d9a50 100644 --- a/src/test/codegen/drop.rs +++ b/src/test/codegen/drop.rs @@ -36,7 +36,7 @@ pub fn droppy() { // CHECK-NOT: call{{.*}}drop{{.*}}SomeUniqueName // CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName // CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName -// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName +// CHECK: call{{.*}}drop{{.*}}SomeUniqueName // CHECK-NOT: {{(call|invoke).*}}drop{{.*}}SomeUniqueName // The next line checks for the } that ends the function definition // CHECK-LABEL: {{^[}]}} diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs index e0de64b26df4..9fd600b32e6c 100644 --- a/src/test/codegen/personality_lifetimes.rs +++ b/src/test/codegen/personality_lifetimes.rs @@ -37,5 +37,6 @@ pub fn test() { // CHECK: bitcast{{.*}}personalityslot // CHECK-NEXT: call void @llvm.lifetime.start might_unwind(); + let _t = S; might_unwind(); } diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs index ff83dd004a25..0745ac02d072 100644 --- a/src/test/compile-fail/const-call.rs +++ b/src/test/compile-fail/const-call.rs @@ -17,6 +17,4 @@ fn f(x: usize) -> usize { fn main() { let _ = [0; f(2)]; //~^ ERROR calls in constants are limited to constant functions - //~| ERROR constant evaluation error [E0080] - //~| non-constant path in constant expression } diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs index b40aa2a8e27d..71cac3edbc18 100644 --- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs +++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs @@ -10,21 +10,22 @@ #![feature(const_fn)] +#[derive(PartialEq, Eq)] enum Cake { BlackForest, Marmor, } use Cake::*; -const BOO: (Cake, Cake) = (Marmor, BlackForest); +struct Pair(A, B); + +const BOO: Pair = Pair(Marmor, BlackForest); //~^ ERROR: constant evaluation error [E0080] -//~| unimplemented constant expression: enum variants +//~| unimplemented constant expression: tuple struct constructors const FOO: Cake = BOO.1; const fn foo() -> Cake { Marmor - //~^ ERROR: constant evaluation error [E0080] - //~| unimplemented constant expression: enum variants } const WORKS: Cake = Marmor; @@ -34,7 +35,7 @@ const GOO: Cake = foo(); fn main() { match BlackForest { FOO => println!("hi"), //~ NOTE: for pattern here - GOO => println!("meh"), //~ NOTE: for pattern here + GOO => println!("meh"), WORKS => println!("möp"), _ => println!("bye"), } diff --git a/src/test/compile-fail/issue-39559.rs b/src/test/compile-fail/issue-39559.rs index 06e8406cbc0b..b7f767f109c0 100644 --- a/src/test/compile-fail/issue-39559.rs +++ b/src/test/compile-fail/issue-39559.rs @@ -28,10 +28,6 @@ pub struct Vector { fn main() { let array: [usize; Dim3::dim()] //~^ ERROR calls in constants are limited to constant functions - //~| ERROR constant evaluation error - //~| non-constant path in constant expression = [0; Dim3::dim()]; //~^ ERROR calls in constants are limited to constant functions - //~| ERROR constant evaluation error - //~| non-constant path in constant expression } diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/compile-fail/issue-41394.rs similarity index 70% rename from src/test/rustdoc/check-hard-break.rs rename to src/test/compile-fail/issue-41394.rs index f048b64d104a..1fb3b7c4ee12 100644 --- a/src/test/rustdoc/check-hard-break.rs +++ b/src/test/compile-fail/issue-41394.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_name = "foo"] +enum Foo { + A = "" + 1 + //~^ ERROR binary operation `+` cannot be applied to type `&'static str` +} -// ignore-tidy-end-whitespace +enum Bar { + A = Foo::A as isize +} -// @has foo/fn.f.html -// @has - '

hard break:
' -// @has - 'after hard break

' -/// hard break: -/// after hard break -pub fn f() {} +fn main() {} diff --git a/src/test/parse-fail/bound-single-question-mark.rs b/src/test/parse-fail/bound-single-question-mark.rs new file mode 100644 index 000000000000..9dde5268c087 --- /dev/null +++ b/src/test/parse-fail/bound-single-question-mark.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn f() {} //~ ERROR expected identifier, found `>` diff --git a/src/test/parse-fail/trait-object-bad-parens.rs b/src/test/parse-fail/trait-object-bad-parens.rs new file mode 100644 index 000000000000..a44c0c3f32fe --- /dev/null +++ b/src/test/parse-fail/trait-object-bad-parens.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only -Z continue-parse-after-error + +fn main() { + let _: Box<((Copy)) + Copy>; + //~^ ERROR expected a path on the left-hand side of `+`, not `((Copy))` + let _: Box<(Copy + Copy) + Copy>; + //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy + Copy)` + let _: Box<(Copy +) + Copy>; + //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy)` +} diff --git a/src/test/parse-fail/trait-object-lifetime-parens.rs b/src/test/parse-fail/trait-object-lifetime-parens.rs new file mode 100644 index 000000000000..6be62d966eb9 --- /dev/null +++ b/src/test/parse-fail/trait-object-lifetime-parens.rs @@ -0,0 +1,18 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only -Z continue-parse-after-error + +fn f() {} //~ ERROR parenthesized lifetime bounds are not supported + +fn main() { + let _: Box; //~ ERROR parenthesized lifetime bounds are not supported + let _: Box<('a) + Copy>; //~ ERROR expected type, found `'a` +} diff --git a/src/test/parse-fail/trait-object-trait-parens.rs b/src/test/parse-fail/trait-object-trait-parens.rs new file mode 100644 index 000000000000..dc44f4f3fb13 --- /dev/null +++ b/src/test/parse-fail/trait-object-trait-parens.rs @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn f Trait<'a>)>() {} + +fn main() { + let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; + let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>; + let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; +} + +FAIL //~ ERROR diff --git a/src/test/run-pass/auxiliary/issue-41394.rs b/src/test/run-pass/auxiliary/issue-41394.rs new file mode 100644 index 000000000000..f06b81279ac4 --- /dev/null +++ b/src/test/run-pass/auxiliary/issue-41394.rs @@ -0,0 +1,26 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] + +#[repr(u32)] +pub enum Foo { + Foo = Private::Variant as u32 +} + +#[repr(u8)] +enum Private { + Variant = 42 +} + +#[inline(always)] +pub fn foo() -> Foo { + Foo::Foo +} diff --git a/src/test/run-pass/const-pattern-variant.rs b/src/test/run-pass/const-pattern-variant.rs new file mode 100644 index 000000000000..104ab6e19db6 --- /dev/null +++ b/src/test/run-pass/const-pattern-variant.rs @@ -0,0 +1,38 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(const_fn)] + +#[derive(PartialEq, Eq)] +enum Cake { + BlackForest, + Marmor, +} +use Cake::*; + +const BOO: (Cake, Cake) = (Marmor, BlackForest); +const FOO: Cake = BOO.1; + +const fn foo() -> Cake { + Marmor +} + +const WORKS: Cake = Marmor; + +const GOO: Cake = foo(); + +fn main() { + match BlackForest { + FOO => println!("hi"), + GOO => println!("meh"), + WORKS => println!("möp"), + _ => println!("bye"), + } +} diff --git a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs b/src/test/run-pass/issue-23898.rs similarity index 73% rename from src/test/compile-fail/non-constant-enum-for-vec-repeat.rs rename to src/test/run-pass/issue-23898.rs index cadfec5a38d3..3f5546ce83dd 100644 --- a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs +++ b/src/test/run-pass/issue-23898.rs @@ -8,13 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Note: This test is checking that we forbid a coding pattern that -// Issue #5873 explicitly wants to allow. +// Note: This test was used to demonstrate #5873 (now #23898). enum State { ST_NULL, ST_WHITESPACE } fn main() { [State::ST_NULL; (State::ST_WHITESPACE as usize)]; - //~^ ERROR constant evaluation error - //~| unimplemented constant expression: enum variants } diff --git a/src/test/run-pass/issue-41394.rs b/src/test/run-pass/issue-41394.rs new file mode 100644 index 000000000000..798905599a85 --- /dev/null +++ b/src/test/run-pass/issue-41394.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue-41394.rs + +extern crate issue_41394 as lib; + +fn main() { + assert_eq!(lib::foo() as u32, 42); +} diff --git a/src/test/run-pass/issue-8460.rs b/src/test/run-pass/issue-8460.rs index 5148be5af830..17ea5b9a7948 100644 --- a/src/test/run-pass/issue-8460.rs +++ b/src/test/run-pass/issue-8460.rs @@ -9,11 +9,22 @@ // except according to those terms. // ignore-emscripten no threads support -#![feature(rustc_attrs, zero_one)] +#![feature(rustc_attrs)] -use std::num::Zero; use std::thread; +trait Int { + fn zero() -> Self; + fn one() -> Self; +} +macro_rules! doit { + ($($t:ident)*) => ($(impl Int for $t { + fn zero() -> $t { 0 } + fn one() -> $t { 1 } + })*) +} +doit! { i8 i16 i32 i64 isize } + macro_rules! check { ($($e:expr),*) => { $(assert!(thread::spawn({ @@ -24,21 +35,21 @@ macro_rules! check { fn main() { check![ - isize::min_value() / -1, - i8::min_value() / -1, - i16::min_value() / -1, - i32::min_value() / -1, - i64::min_value() / -1, + isize::min_value() / -isize::one(), + i8::min_value() / -i8::one(), + i16::min_value() / -i16::one(), + i32::min_value() / -i32::one(), + i64::min_value() / -i64::one(), 1isize / isize::zero(), 1i8 / i8::zero(), 1i16 / i16::zero(), 1i32 / i32::zero(), 1i64 / i64::zero(), - isize::min_value() % -1, - i8::min_value() % -1, - i16::min_value() % -1, - i32::min_value() % -1, - i64::min_value() % -1, + isize::min_value() % -isize::one(), + i8::min_value() % -i8::one(), + i16::min_value() % -i16::one(), + i32::min_value() % -i32::one(), + i64::min_value() % -i64::one(), 1isize % isize::zero(), 1i8 % i8::zero(), 1i16 % i16::zero(), diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs index d046705c94bb..ea154590deef 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -10,13 +10,12 @@ #![allow(warnings)] #![feature(collections)] -#![feature(drain, enumset, collections_bound, btree_range, vecmap)] +#![feature(drain, collections_bound, btree_range, vecmap)] extern crate collections; use collections::BinaryHeap; use collections::{BTreeMap, BTreeSet}; -use collections::EnumSet; use collections::LinkedList; use collections::String; use collections::Vec; @@ -25,7 +24,6 @@ use std::collections::HashMap; use std::collections::HashSet; use collections::Bound::Included; -use collections::enum_set::CLike; use std::mem; fn is_sync(_: T) where T: Sync {} @@ -76,21 +74,6 @@ fn main() { all_sync_send!(LinkedList::::new(), iter, iter_mut, into_iter); - #[derive(Copy, Clone)] - #[repr(usize)] - #[allow(dead_code)] - enum Foo { A, B, C } - impl CLike for Foo { - fn to_usize(&self) -> usize { - *self as usize - } - - fn from_usize(v: usize) -> Foo { - unsafe { mem::transmute(v) } - } - } - all_sync_send!(EnumSet::::new(), iter); - all_sync_send!(VecDeque::::new(), iter, iter_mut, into_iter); is_sync_send!(VecDeque::::new(), drain(..)); diff --git a/src/test/run-pass/union/union-transmute.rs b/src/test/run-pass/union/union-transmute.rs index 4eb66268ab8e..7a0b4c6aaca4 100644 --- a/src/test/run-pass/union/union-transmute.rs +++ b/src/test/run-pass/union/union-transmute.rs @@ -8,12 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(core_float)] -#![feature(float_extras)] #![feature(untagged_unions)] extern crate core; -use core::num::Float; +use core::f32; union U { a: (u8, u8), @@ -33,8 +31,8 @@ fn main() { assert_eq!(u.a, (2, 2)); let mut w = W { a: 0b0_11111111_00000000000000000000000 }; - assert_eq!(w.b, f32::infinity()); - w.b = f32::neg_infinity(); + assert_eq!(w.b, f32::INFINITY); + w.b = f32::NEG_INFINITY; assert_eq!(w.a, 0b1_11111111_00000000000000000000000); } } diff --git a/src/test/run-pass/while-let.rs b/src/test/run-pass/while-let.rs index 9ffba2c7999f..aed6986c5fe5 100644 --- a/src/test/run-pass/while-let.rs +++ b/src/test/run-pass/while-let.rs @@ -9,8 +9,6 @@ // except according to those terms. -#![feature(binary_heap_extras)] - use std::collections::BinaryHeap; fn make_pq() -> BinaryHeap { diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs deleted file mode 100644 index 46542677857f..000000000000 --- a/src/test/rustdoc/check-rule-image-footnote.rs +++ /dev/null @@ -1,44 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_name = "foo"] - -// ignore-tidy-linelength - -// @has foo/fn.f.html -// @has - '

markdown test

' -// @has - '

this is a link.

' -// @has - '
' -// @has - '

a footnote1.

' -// @has - '

another footnote2.

' -// @has - '

Rust

' -// @has - '

  1. ' -// @has - '

    Thing â†©

  2. ' -// @has - '

    Another Thing â†©

' -/// markdown test -/// -/// this is a [link]. -/// -/// [link]: https://example.com "this is a title" -/// -/// ----------- -/// -/// a footnote[^footnote]. -/// -/// another footnote[^footnotebis]. -/// -/// [^footnote]: Thing -/// -/// -/// [^footnotebis]: Another Thing -/// -/// -/// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png) -pub fn f() {} diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index efadde992277..ca383b5add01 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -24,7 +24,7 @@ use std::path::PathBuf; use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; -use rustdoc::html::markdown::{Markdown, PLAYGROUND}; +use rustdoc::html::markdown::{Markdown, PLAYGROUND, RenderType}; use rustc_serialize::json; enum OutputFormat { @@ -100,7 +100,7 @@ impl Formatter for HTMLFormatter { // Description rendered as markdown. match info.description { - Some(ref desc) => write!(output, "{}", Markdown(desc))?, + Some(ref desc) => write!(output, "{}", Markdown(desc, RenderType::Hoedown))?, None => write!(output, "

No description.

\n")?, }