Fix more merge conflicts
This commit is contained in:
commit
158b085f06
135 changed files with 2042 additions and 2702 deletions
2
cargo
2
cargo
|
|
@ -1 +1 @@
|
|||
Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28
|
||||
Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
# `as_unsafe_cell`
|
||||
|
||||
The tracking issue for this feature is: [#27708]
|
||||
|
||||
[#27708]: https://github.com/rust-lang/rust/issues/27708
|
||||
|
||||
------------------------
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# `binary_heap_extras`
|
||||
|
||||
The tracking issue for this feature is: [#28147]
|
||||
|
||||
[#28147]: https://github.com/rust-lang/rust/issues/28147
|
||||
|
||||
------------------------
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# `borrow_state`
|
||||
|
||||
The tracking issue for this feature is: [#27733]
|
||||
|
||||
[#27733]: https://github.com/rust-lang/rust/issues/27733
|
||||
|
||||
------------------------
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# `enumset`
|
||||
|
||||
The tracking issue for this feature is: [#37966]
|
||||
|
||||
[#37966]: https://github.com/rust-lang/rust/issues/37966
|
||||
|
||||
------------------------
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# `float_extras`
|
||||
|
||||
The tracking issue for this feature is: [#27752]
|
||||
|
||||
[#27752]: https://github.com/rust-lang/rust/issues/27752
|
||||
|
||||
------------------------
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# `is_unique`
|
||||
|
||||
The tracking issue for this feature is: [#28356]
|
||||
|
||||
[#28356]: https://github.com/rust-lang/rust/issues/28356
|
||||
|
||||
------------------------
|
||||
|
|
@ -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
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
# `rc_would_unwrap`
|
||||
|
||||
The tracking issue for this feature is: [#28356]
|
||||
|
||||
[#28356]: https://github.com/rust-lang/rust/issues/28356
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# `zero_one`
|
||||
|
||||
The tracking issue for this feature is: [#27739]
|
||||
|
||||
[#27739]: https://github.com/rust-lang/rust/issues/27739
|
||||
|
||||
------------------------
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(binary_heap_extras)]
|
||||
#![feature(binary_heap_peek_mut_pop)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(inclusive_range_syntax)]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
212
src/librustc/traits/trans/mod.rs
Normal file
212
src/librustc/traits/trans/mod.rs
Normal 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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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)) => {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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(..) |
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 { .. } |
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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() }
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
42
src/librustc_trans/symbol_cache.rs
Normal file
42
src/librustc_trans/symbol_cache.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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))));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 => {}
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue