Fix more merge conflicts

This commit is contained in:
Matthew 2017-04-24 10:20:05 +01:00
commit 158b085f06
135 changed files with 2042 additions and 2702 deletions

2
cargo

@ -1 +1 @@
Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28
Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755

View file

@ -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<lt_param_defs> ] simple_path
bound-list := bound | bound '+' bound-list '+' ?
ty_bound := ty_bound_noparen | (ty_bound_noparen)
ty_bound_noparen := [?] [ for<lt_param_defs> ] simple_path
```
### Self types

View file

@ -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)

View file

@ -1,7 +0,0 @@
# `as_unsafe_cell`
The tracking issue for this feature is: [#27708]
[#27708]: https://github.com/rust-lang/rust/issues/27708
------------------------

View file

@ -1,7 +0,0 @@
# `binary_heap_extras`
The tracking issue for this feature is: [#28147]
[#28147]: https://github.com/rust-lang/rust/issues/28147
------------------------

View file

@ -1,7 +0,0 @@
# `borrow_state`
The tracking issue for this feature is: [#27733]
[#27733]: https://github.com/rust-lang/rust/issues/27733
------------------------

View file

@ -1,7 +0,0 @@
# `enumset`
The tracking issue for this feature is: [#37966]
[#37966]: https://github.com/rust-lang/rust/issues/37966
------------------------

View file

@ -1,7 +0,0 @@
# `float_extras`
The tracking issue for this feature is: [#27752]
[#27752]: https://github.com/rust-lang/rust/issues/27752
------------------------

View file

@ -1,7 +0,0 @@
# `is_unique`
The tracking issue for this feature is: [#28356]
[#28356]: https://github.com/rust-lang/rust/issues/28356
------------------------

View file

@ -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

View file

@ -1,5 +0,0 @@
# `rc_would_unwrap`
The tracking issue for this feature is: [#28356]
[#28356]: https://github.com/rust-lang/rust/issues/28356

View file

@ -1,7 +0,0 @@
# `zero_one`
The tracking issue for this feature is: [#27739]
[#27739]: https://github.com/rust-lang/rust/issues/27739
------------------------

View file

@ -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<T: ?Sized>(ptr: *mut T) {
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
let size = size_of_val(&*ptr);
let align = min_align_of_val(&*ptr);
// We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.

View file

@ -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)]

View file

@ -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<T: ?Sized> {
@ -248,7 +248,6 @@ struct RcBox<T: ?Sized> {
value: T,
}
/// A single-threaded reference-counting pointer.
///
/// See the [module-level documentation](./index.html) for more details.
@ -341,19 +340,6 @@ impl<T> Rc<T> {
}
}
/// 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<str> {
}
}
impl<T> 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::<RcBox<[T; 1]>>(), 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<T: ?Sized> Rc<T> {
/// Creates a new [`Weak`][weak] pointer to this value.
///
@ -501,11 +519,7 @@ impl<T: ?Sized> Rc<T> {
///
/// [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
}

View file

@ -555,82 +555,6 @@ impl<T: Ord> BinaryHeap<T> {
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<T> {
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

View file

@ -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

View file

@ -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

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! 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<E> {
// We must maintain the invariant that no bits are set
// for which no variant exists
bits: usize,
marker: marker::PhantomData<E>,
}
impl<E> Copy for EnumSet<E> {}
impl<E> Clone for EnumSet<E> {
fn clone(&self) -> EnumSet<E> {
*self
}
}
impl<E: CLike + fmt::Debug> fmt::Debug for EnumSet<E> {
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: CLike>(e: &E) -> usize {
use core::mem;
let value = e.to_usize();
let bits = mem::size_of::<usize>() * 8;
assert!(value < bits,
"EnumSet only supports up to {} variants.",
bits - 1);
1 << value
}
impl<E: CLike> EnumSet<E> {
/// Returns an empty `EnumSet`.
pub fn new() -> EnumSet<E> {
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<E>) -> bool {
(self.bits & other.bits) == 0
}
/// Returns `true` if a given `EnumSet` is included in this `EnumSet`.
pub fn is_superset(&self, other: &EnumSet<E>) -> 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<E>) -> bool {
other.is_superset(self)
}
/// Returns the union of both `EnumSets`.
pub fn union(&self, e: EnumSet<E>) -> EnumSet<E> {
EnumSet {
bits: self.bits | e.bits,
marker: marker::PhantomData,
}
}
/// Returns the intersection of both `EnumSets`.
pub fn intersection(&self, e: EnumSet<E>) -> EnumSet<E> {
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<E> {
Iter::new(self.bits)
}
}
impl<E: CLike> Sub for EnumSet<E> {
type Output = EnumSet<E>;
fn sub(self, e: EnumSet<E>) -> EnumSet<E> {
EnumSet {
bits: self.bits & !e.bits,
marker: marker::PhantomData,
}
}
}
impl<E: CLike> BitOr for EnumSet<E> {
type Output = EnumSet<E>;
fn bitor(self, e: EnumSet<E>) -> EnumSet<E> {
EnumSet {
bits: self.bits | e.bits,
marker: marker::PhantomData,
}
}
}
impl<E: CLike> BitAnd for EnumSet<E> {
type Output = EnumSet<E>;
fn bitand(self, e: EnumSet<E>) -> EnumSet<E> {
EnumSet {
bits: self.bits & e.bits,
marker: marker::PhantomData,
}
}
}
impl<E: CLike> BitXor for EnumSet<E> {
type Output = EnumSet<E>;
fn bitxor(self, e: EnumSet<E>) -> EnumSet<E> {
EnumSet {
bits: self.bits ^ e.bits,
marker: marker::PhantomData,
}
}
}
/// An iterator over an `EnumSet`
pub struct Iter<E> {
index: usize,
bits: usize,
marker: marker::PhantomData<E>,
}
impl<E: fmt::Debug> fmt::Debug for Iter<E> {
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<E> Clone for Iter<E> {
fn clone(&self) -> Iter<E> {
Iter {
index: self.index,
bits: self.bits,
marker: marker::PhantomData,
}
}
}
impl<E: CLike> Iter<E> {
fn new(bits: usize) -> Iter<E> {
Iter {
index: 0,
bits: bits,
marker: marker::PhantomData,
}
}
}
impl<E: CLike> Iterator for Iter<E> {
type Item = E;
fn next(&mut self) -> Option<E> {
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<usize>) {
let exact = self.bits.count_ones() as usize;
(exact, Some(exact))
}
}
#[unstable(feature = "fused", issue = "35602")]
impl<E: CLike> FusedIterator for Iter<E> {}
impl<E: CLike> FromIterator<E> for EnumSet<E> {
fn from_iter<I: IntoIterator<Item = E>>(iter: I) -> EnumSet<E> {
let mut ret = EnumSet::new();
ret.extend(iter);
ret
}
}
impl<'a, E> IntoIterator for &'a EnumSet<E>
where E: CLike
{
type Item = E;
type IntoIter = Iter<E>;
fn into_iter(self) -> Iter<E> {
self.iter()
}
}
impl<E: CLike> Extend<E> for EnumSet<E> {
fn extend<I: IntoIterator<Item = E>>(&mut self, iter: I) {
for element in iter {
self.insert(element);
}
}
}
impl<'a, E: 'a + CLike + Copy> Extend<&'a E> for EnumSet<E> {
fn extend<I: IntoIterator<Item = &'a E>>(&mut self, iter: I) {
self.extend(iter.into_iter().cloned());
}
}

View file

@ -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;

View file

@ -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

View file

@ -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<i32>) {
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];

View file

@ -10,7 +10,6 @@
#![deny(warnings)]
#![feature(binary_heap_extras)]
#![feature(binary_heap_peek_mut_pop)]
#![feature(box_syntax)]
#![feature(inclusive_range_syntax)]

View file

@ -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

View file

@ -310,26 +310,6 @@ impl<T> Cell<T> {
}
}
/// 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<T> {
&self.value
}
/// Returns a raw pointer to the underlying data in this cell.
///
/// # Examples
@ -480,20 +460,6 @@ pub struct RefCell<T: ?Sized> {
value: UnsafeCell<T>,
}
/// An enumeration of values returned from the `state` method on a `RefCell<T>`.
#[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<T> RefCell<T> {
}
impl<T: ?Sized> RefCell<T> {
/// 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<T: ?Sized> RefCell<T> {
}
}
/// 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<T> {
&self.value
}
/// Returns a raw pointer to the underlying data in this cell.
///
/// # Examples

View file

@ -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<Output=Self> + Rem<Output=Self> +
trait Int: PartialEq + PartialOrd + Div<Output=Self> + Rem<Output=Self> +
Sub<Output=Self> + 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<Output=Self> + Rem<Output=Self> +
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 }

View file

@ -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)
}

View file

@ -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]

View file

@ -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]

View file

@ -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<T: DecodableFloat>(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<T: DecodableFloat>(v: T) -> (/*negative?*/ bool, FullDecoded) {
exp: exp, inclusive: even })
}
FpCategory::Normal => {
let minnorm = <T as DecodableFloat>::min_pos_norm_value().integer_decode2();
let minnorm = <T as DecodableFloat>::min_pos_norm_value().integer_decode();
if mant == minnorm.0 {
// neighbors: (maxmant, exp - 1) -- (minnormmant, exp) -- (minnormmant + 1, exp)
// where maxmant = minnormmant * 2 - 1

View file

@ -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")]

View file

@ -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));
}

View file

@ -88,15 +88,17 @@ pub enum DepNode<D: Clone + Debug> {
// 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<D: Clone + Debug> DepNode<D> {
TransCrateItem,
AssociatedItems,
ItemSignature,
IsForeignItem,
AssociatedItemDefIds,
InherentImpls,
TypeckTables,
@ -221,16 +224,18 @@ impl<D: Clone + Debug> DepNode<D> {
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),

View file

@ -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

View file

@ -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);
}
}
}
}

View file

@ -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
}
}
}

View file

@ -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<VarValue<'tcx>> {
(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.
}
}

View file

@ -38,12 +38,13 @@ pub enum ConstVal<'tcx> {
Str(InternedString),
ByteStr(Rc<Vec<u8>>),
Bool(bool),
Char(char),
Variant(DefId),
Function(DefId, &'tcx Substs<'tcx>),
Struct(BTreeMap<ast::Name, ConstVal<'tcx>>),
Tuple(Vec<ConstVal<'tcx>>),
Array(Vec<ConstVal<'tcx>>),
Repeat(Box<ConstVal<'tcx>>, 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);

View file

@ -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<DefId>>;
fn item_generics_cloned(&self, def: DefId) -> ty::Generics;
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]>;
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>;
// trait info
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;
// impl info
fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity;
fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
// 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<hir::BodyId, hir::Body>;
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<ast::Attribute> { bug!("item_attrs") }
fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]> { bug!("item_attrs") }
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name> { bug!("fn_arg_names") }
// trait info
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId> { vec![] }
// impl info
fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") }
fn impl_parent(&self, def: DefId) -> Option<DefId> { 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<hir::BodyId, hir::Body> {
bug!("item_body_nested_bodies")

View file

@ -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.

View file

@ -223,9 +223,10 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
pub fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
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)
}
}
}

View file

@ -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)
};

View file

@ -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<NodeSet> {
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<NodeSet> {
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) {

View file

@ -1307,10 +1307,11 @@ fn fmt_const_val<W: Write>(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),
}
}

View file

@ -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);

View file

@ -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;

View file

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

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// 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<T>(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<T:TypeFoldable<'gcx>>(&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<DepTrackingMap<TraitSelectionCache<'tcx>>>,
project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
}
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<DefId> {
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<DefId> {
// 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 `<Foo as SomeTrait>::T` and `<Bar as
// SomeTrait>::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<DefId> =
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 }
}
}

View file

@ -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<traits::SpecializesCache>,
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> {

View file

@ -410,7 +410,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> 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)
}))
}

View file

@ -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())
}

View file

@ -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<TyLayout<'gcx>, 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<C: LayoutTyper<'tcx>>(&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)))
}
}

View file

@ -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<ty::Destructor>,
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<ty::TraitRef<'tcx>>,
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<AccessLevels>,
pub reachable_set: reachability_dep_node(CrateNum) -> NodeSet,
pub reachable_set: reachability_dep_node(CrateNum) -> Rc<NodeSet>,
pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>
pub mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>
}
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
@ -465,10 +496,14 @@ fn reachability_dep_node(_: CrateNum) -> DepNode<DefId> {
DepNode::Reachability
}
fn mir_shim(instance: ty::InstanceDef) -> DepNode<DefId> {
fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode<DefId> {
instance.dep_node()
}
fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode<DefId> {
DepNode::TypeckBodiesKrate
}
fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode<DefId> {
DepNode::ConstEval(def_id)
}

View file

@ -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<AccessLevels>,
pub reachable: NodeSet,
pub reachable: Rc<NodeSet>,
pub name: String,
pub glob_map: Option<hir::GlobMap>,
}
@ -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<Item=ConstInt> + '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::<Vec<_>>());
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::<Result<DtorckConstraint, ErrorReported>>()
.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<Rc<Vec<DefId>>>,
}
/// 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<ty::subst::Kind<'tcx>>,
/// Types that could not be resolved: projections and params.
pub dtorck_types: Vec<Ty<'tcx>>,
}
impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx>
{
fn from_iter<I: IntoIterator<Item=DtorckConstraint<'tcx>>>(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());
}
}

View file

@ -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))
}
}

View file

@ -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<ty::subst::Kind<'tcx>>
{
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<T:Clone>`).
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>(X, Y, Z);
//
// and the impl is
//
// impl<#[may_dangle] P0, P1, P2> Drop for S<P1, P2, P0>
//
// We want to return the parameters (X, Y). For that, we match
// up the item-substs <X, Y, Z> with the substs on the impl ADT,
// <P1, P2, P0>, 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<ty::DtorckConstraint<'tcx>, 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)
})

View file

@ -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)) => {

View file

@ -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)
}

View file

@ -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));

View file

@ -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<F>(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);

View file

@ -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)
}

View file

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

View file

@ -72,6 +72,7 @@ pub struct CrateMetadata {
pub cnum_map: RefCell<CrateNumMap>,
pub cnum: CrateNum,
pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
pub attribute_cache: RefCell<[Vec<Option<Rc<[ast::Attribute]>>>; 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;
}

View file

@ -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<ast::Attribute>
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<DefId> {
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<hir::BodyId, hir::Body> {

View file

@ -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<ast::Attribute> {
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<ast::Name> {

View file

@ -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()
});

View file

@ -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")

View file

@ -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))

View file

@ -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(..) |

View file

@ -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());

View file

@ -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 {

View file

@ -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 {

View file

@ -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))
}

View file

@ -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<DefId>,
@ -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::<u64>::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<InternedString>,
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<PI: Iterator<Item=InternedString>>(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 <len, name> 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()
}

View file

@ -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<TransItem<'tcx>>,
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<ModuleTranslation> = 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<SymbolMap<'tcx>>)>)
args: AssertDepGraphSafe<CodegenUnit<'tcx>>)
-> (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<CodegenUnit<'tcx>>, SymbolMap<'tcx>) {
-> (FxHashSet<TransItem<'tcx>>,
Vec<CodegenUnit<'tcx>>,
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<TransItem<'tcx>> = 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)
}

View file

@ -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())
{

View file

@ -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 { .. } |

View file

@ -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)
}

View file

@ -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

View file

@ -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<FxHashSet<TransItem<'tcx>>>,
trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
}
/// 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<usize>,
symbol_map: Rc<SymbolMap<'tcx>>,
/// A counter that is used for generating local symbol names
local_gen_sym_counter: Cell<usize>,
}
// 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<DefId> {
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<DefId> {
// 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 `<Foo as SomeTrait>::T` and `<Bar as
// SomeTrait>::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<DefId> =
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<DepTrackingMap<TraitSelectionCache<'tcx>>> {
&self.trait_cache
}
pub fn project_cache(&self) -> &RefCell<DepTrackingMap<ProjectionCache<'tcx>>> {
&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<FxHashSet<TransItem<'tcx>>> {
&self.translation_items
}
}
impl<'tcx> LocalCrateContext<'tcx> {
pub fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
codegen_unit: CodegenUnit<'tcx>,
symbol_map: Rc<SymbolMap<'tcx>>)
-> 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<FxHashSet<TransItem<'tcx>>> {
&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) {

View file

@ -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;

View file

@ -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<T>(&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<Const<'tcx>, 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 {

View file

@ -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<T>(&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) {

View file

@ -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() }
);

View file

@ -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<T:TypeFoldable<'gcx>>(&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)
})
}
}
}

View file

@ -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<Item=&'b CodegenUnit<'tcx>>,
@ -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("<no hash>");
debug!(" - {} [{:?}] [{}]",
trans_item.to_string(scx.tcx()),
trans_item.to_string(tcx),
linkage,
symbol_hash);
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::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<FxHashMap<TransItem<'tcx>, 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()
}
}

View file

@ -34,8 +34,9 @@ impl<'tcx> SymbolMap<'tcx> {
where I: Iterator<Item=TransItem<'tcx>>
{
// 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()))
}
}
}

View file

@ -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);

View file

@ -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)
}
}

View file

@ -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

View file

@ -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))
}
}

View file

@ -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<Ty<'tcx>>,
/// 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<T> -> Unique<T> -> PhantomData<T> -> 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::<String>(),
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::<String>(),
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<T> Drop for Vec<T> { ... }
// ```
//
// 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::<String>(),
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<T> - 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<X>` is defined via `impl<Y> Drop for Foo<Y>`,
// and never by (for example) `impl<Z> Drop for Foo<Vec<Z>>`.
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(())
}

View file

@ -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(

View file

@ -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))));

View file

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

View file

@ -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 => {}
_ => {

View file

@ -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
}
}
}

View file

@ -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)
}
}

View file

@ -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

Some files were not shown because too many files have changed in this diff Show more