Merge branch 'master' into issue_57128_improve_miri_error_reporting_in_check_in_alloc
This commit is contained in:
commit
3449fa90f8
76 changed files with 1098 additions and 723 deletions
|
|
@ -54,6 +54,7 @@ name = "arena"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_data_structures 0.0.0",
|
||||
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1520,7 +1521,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "minifier"
|
||||
version = "0.0.28"
|
||||
version = "0.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -3039,7 +3040,7 @@ dependencies = [
|
|||
name = "rustdoc"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"minifier 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"minifier 0.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -4149,7 +4150,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16"
|
||||
"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
|
||||
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
||||
"checksum minifier 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "3a2898502751dcc9d66b6fff57f3cf63cc91605e83e1a33515396f5027f8e4ca"
|
||||
"checksum minifier 0.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4950cb2617b1933e2da0446e864dfe0d6a22c22ff72297996c46e6a63b210b"
|
||||
"checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649"
|
||||
"checksum miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c"
|
||||
"checksum miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28edaef377517fd9fe3e085c37d892ce7acd1fbeab9239c5a36eec352d8a8b7e"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 344c4e437ba4cfa5c14db643ec4d6b68dcd164c5
|
||||
Subproject commit 464cb5b166378dff64619081dd4c42533a1eb989
|
||||
|
|
@ -11,3 +11,4 @@ crate-type = ["dylib"]
|
|||
|
||||
[dependencies]
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@
|
|||
|
||||
extern crate alloc;
|
||||
|
||||
use rustc_data_structures::cold_path;
|
||||
use rustc_data_structures::sync::MTLock;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cmp;
|
||||
|
|
@ -55,6 +57,8 @@ pub struct TypedArena<T> {
|
|||
struct TypedArenaChunk<T> {
|
||||
/// The raw storage for the arena chunk.
|
||||
storage: RawVec<T>,
|
||||
/// The number of valid entries in the chunk.
|
||||
entries: usize,
|
||||
}
|
||||
|
||||
impl<T> TypedArenaChunk<T> {
|
||||
|
|
@ -62,6 +66,7 @@ impl<T> TypedArenaChunk<T> {
|
|||
unsafe fn new(capacity: usize) -> TypedArenaChunk<T> {
|
||||
TypedArenaChunk {
|
||||
storage: RawVec::with_capacity(capacity),
|
||||
entries: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -149,6 +154,34 @@ impl<T> TypedArena<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn can_allocate(&self, len: usize) -> bool {
|
||||
let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize;
|
||||
let at_least_bytes = len.checked_mul(mem::size_of::<T>()).unwrap();
|
||||
available_capacity_bytes >= at_least_bytes
|
||||
}
|
||||
|
||||
/// Ensures there's enough space in the current chunk to fit `len` objects.
|
||||
#[inline]
|
||||
fn ensure_capacity(&self, len: usize) {
|
||||
if !self.can_allocate(len) {
|
||||
self.grow(len);
|
||||
debug_assert!(self.can_allocate(len));
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn alloc_raw_slice(&self, len: usize) -> *mut T {
|
||||
assert!(mem::size_of::<T>() != 0);
|
||||
assert!(len != 0);
|
||||
|
||||
self.ensure_capacity(len);
|
||||
|
||||
let start_ptr = self.ptr.get();
|
||||
self.ptr.set(start_ptr.add(len));
|
||||
start_ptr
|
||||
}
|
||||
|
||||
/// Allocates a slice of objects that are copied into the `TypedArena`, returning a mutable
|
||||
/// reference to it. Will panic if passed a zero-sized types.
|
||||
///
|
||||
|
|
@ -161,21 +194,64 @@ impl<T> TypedArena<T> {
|
|||
where
|
||||
T: Copy,
|
||||
{
|
||||
assert!(mem::size_of::<T>() != 0);
|
||||
assert!(slice.len() != 0);
|
||||
|
||||
let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize;
|
||||
let at_least_bytes = slice.len() * mem::size_of::<T>();
|
||||
if available_capacity_bytes < at_least_bytes {
|
||||
self.grow(slice.len());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let start_ptr = self.ptr.get();
|
||||
let arena_slice = slice::from_raw_parts_mut(start_ptr, slice.len());
|
||||
self.ptr.set(start_ptr.add(arena_slice.len()));
|
||||
arena_slice.copy_from_slice(slice);
|
||||
arena_slice
|
||||
let len = slice.len();
|
||||
let start_ptr = self.alloc_raw_slice(len);
|
||||
slice.as_ptr().copy_to_nonoverlapping(start_ptr, len);
|
||||
slice::from_raw_parts_mut(start_ptr, len)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
|
||||
assert!(mem::size_of::<T>() != 0);
|
||||
let mut iter = iter.into_iter();
|
||||
let size_hint = iter.size_hint();
|
||||
|
||||
match size_hint {
|
||||
(min, Some(max)) if min == max => {
|
||||
// We know the exact number of elements the iterator will produce here
|
||||
let len = min;
|
||||
|
||||
if len == 0 {
|
||||
return &mut [];
|
||||
}
|
||||
|
||||
self.ensure_capacity(len);
|
||||
|
||||
let slice = self.ptr.get();
|
||||
|
||||
unsafe {
|
||||
let mut ptr = self.ptr.get();
|
||||
for _ in 0..len {
|
||||
// Write into uninitialized memory.
|
||||
ptr::write(ptr, iter.next().unwrap());
|
||||
// Advance the pointer.
|
||||
ptr = ptr.offset(1);
|
||||
// Update the pointer per iteration so if `iter.next()` panics
|
||||
// we destroy the correct amount
|
||||
self.ptr.set(ptr);
|
||||
}
|
||||
slice::from_raw_parts_mut(slice, len)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
cold_path(move || -> &mut [T] {
|
||||
let mut vec: SmallVec<[_; 8]> = iter.collect();
|
||||
if vec.is_empty() {
|
||||
return &mut [];
|
||||
}
|
||||
// Move the content to the arena by copying it and then forgetting
|
||||
// the content of the SmallVec
|
||||
unsafe {
|
||||
let len = vec.len();
|
||||
let start_ptr = self.alloc_raw_slice(len);
|
||||
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
|
||||
vec.set_len(0);
|
||||
slice::from_raw_parts_mut(start_ptr, len)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -189,6 +265,7 @@ impl<T> TypedArena<T> {
|
|||
if let Some(last_chunk) = chunks.last_mut() {
|
||||
let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize;
|
||||
let currently_used_cap = used_bytes / mem::size_of::<T>();
|
||||
last_chunk.entries = currently_used_cap;
|
||||
if last_chunk.storage.reserve_in_place(currently_used_cap, n) {
|
||||
self.end.set(last_chunk.end());
|
||||
return;
|
||||
|
|
@ -222,8 +299,7 @@ impl<T> TypedArena<T> {
|
|||
let len = chunks_borrow.len();
|
||||
// If `T` is ZST, code below has no effect.
|
||||
for mut chunk in chunks_borrow.drain(..len-1) {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
chunk.destroy(chunk.entries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -265,8 +341,7 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena<T> {
|
|||
self.clear_last_chunk(&mut last_chunk);
|
||||
// The last chunk will be dropped. Destroy all other chunks.
|
||||
for chunk in chunks_borrow.iter_mut() {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
chunk.destroy(chunk.entries);
|
||||
}
|
||||
}
|
||||
// RawVec handles deallocation of `last_chunk` and `self.chunks`.
|
||||
|
|
@ -410,6 +485,54 @@ impl DroplessArena {
|
|||
arena_slice
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
|
||||
let mut iter = iter.into_iter();
|
||||
assert!(mem::size_of::<T>() != 0);
|
||||
assert!(!mem::needs_drop::<T>());
|
||||
|
||||
let size_hint = iter.size_hint();
|
||||
|
||||
match size_hint {
|
||||
(min, Some(max)) if min == max => {
|
||||
// We know the exact number of elements the iterator will produce here
|
||||
let len = min;
|
||||
|
||||
if len == 0 {
|
||||
return &mut []
|
||||
}
|
||||
let size = len.checked_mul(mem::size_of::<T>()).unwrap();
|
||||
let mem = self.alloc_raw(size, mem::align_of::<T>()) as *mut _ as *mut T;
|
||||
unsafe {
|
||||
for i in 0..len {
|
||||
ptr::write(mem.offset(i as isize), iter.next().unwrap())
|
||||
}
|
||||
slice::from_raw_parts_mut(mem, len)
|
||||
}
|
||||
}
|
||||
(_, _) => {
|
||||
cold_path(move || -> &mut [T] {
|
||||
let mut vec: SmallVec<[_; 8]> = iter.collect();
|
||||
if vec.is_empty() {
|
||||
return &mut [];
|
||||
}
|
||||
// Move the content to the arena by copying it and then forgetting
|
||||
// the content of the SmallVec
|
||||
unsafe {
|
||||
let len = vec.len();
|
||||
let start_ptr = self.alloc_raw(
|
||||
len * mem::size_of::<T>(),
|
||||
mem::align_of::<T>()
|
||||
) as *mut _ as *mut T;
|
||||
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
|
||||
vec.set_len(0);
|
||||
slice::from_raw_parts_mut(start_ptr, len)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
|
|||
|
|
@ -334,3 +334,13 @@ fn bench_filter_chain_ref_count(b: &mut Bencher) {
|
|||
(0i64..1000000).chain(0..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count()
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_partial_cmp(b: &mut Bencher) {
|
||||
b.iter(|| (0..100000).map(black_box).partial_cmp((0..100000).map(black_box)))
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_lt(b: &mut Bencher) {
|
||||
b.iter(|| (0..100000).map(black_box).lt((0..100000).map(black_box)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,11 +68,9 @@ macro_rules! step_impl_unsigned {
|
|||
issue = "42168")]
|
||||
impl Step for $t {
|
||||
#[inline]
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn steps_between(start: &$t, end: &$t) -> Option<usize> {
|
||||
if *start < *end {
|
||||
// Note: We assume $t <= usize here
|
||||
Some((*end - *start) as usize)
|
||||
usize::try_from(*end - *start).ok()
|
||||
} else {
|
||||
Some(0)
|
||||
}
|
||||
|
|
@ -98,13 +96,11 @@ macro_rules! step_impl_signed {
|
|||
issue = "42168")]
|
||||
impl Step for $t {
|
||||
#[inline]
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn steps_between(start: &$t, end: &$t) -> Option<usize> {
|
||||
if *start < *end {
|
||||
// Note: We assume $t <= isize here
|
||||
// Use .wrapping_sub and cast to usize to compute the
|
||||
// difference that may not fit inside the range of isize.
|
||||
Some((*end as isize).wrapping_sub(*start as isize) as usize)
|
||||
// Use .wrapping_sub and cast to unsigned to compute the
|
||||
// difference that may not fit inside the range of $t.
|
||||
usize::try_from(end.wrapping_sub(*start) as $unsigned).ok()
|
||||
} else {
|
||||
Some(0)
|
||||
}
|
||||
|
|
@ -134,46 +130,9 @@ macro_rules! step_impl_signed {
|
|||
)*)
|
||||
}
|
||||
|
||||
macro_rules! step_impl_no_between {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable(feature = "step_trait",
|
||||
reason = "likely to be replaced by finer-grained traits",
|
||||
issue = "42168")]
|
||||
impl Step for $t {
|
||||
#[inline]
|
||||
fn steps_between(_start: &Self, _end: &Self) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_usize(&self, n: usize) -> Option<Self> {
|
||||
self.checked_add(n as $t)
|
||||
}
|
||||
|
||||
step_identical_methods!();
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
step_impl_unsigned!(usize u8 u16);
|
||||
#[cfg(not(target_pointer_width = "16"))]
|
||||
step_impl_unsigned!(u32);
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
step_impl_no_between!(u32);
|
||||
step_impl_unsigned!(usize u8 u16 u32 u64 u128);
|
||||
step_impl_signed!([isize: usize] [i8: u8] [i16: u16]);
|
||||
#[cfg(not(target_pointer_width = "16"))]
|
||||
step_impl_signed!([i32: u32]);
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
step_impl_no_between!(i32);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
step_impl_unsigned!(u64);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
step_impl_signed!([i64: u64]);
|
||||
// If the target pointer width is not 64-bits, we
|
||||
// assume here that it is less than 64-bits.
|
||||
#[cfg(not(target_pointer_width = "64"))]
|
||||
step_impl_no_between!(u64 i64);
|
||||
step_impl_no_between!(u128 i128);
|
||||
step_impl_signed!([i32: u32] [i64: u64] [i128: u128]);
|
||||
|
||||
macro_rules! range_exact_iter_impl {
|
||||
($($t:ty)*) => ($(
|
||||
|
|
@ -229,7 +188,7 @@ impl<A: Step> Iterator for ops::Range<A> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
match Step::steps_between(&self.start, &self.end) {
|
||||
Some(hint) => (hint, Some(hint)),
|
||||
None => (0, None)
|
||||
None => (usize::MAX, None)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -273,8 +232,8 @@ range_incl_exact_iter_impl!(u8 u16 i8 i16);
|
|||
//
|
||||
// They need to guarantee that .size_hint() is either exact, or that
|
||||
// the upper bound is None when it does not fit the type limits.
|
||||
range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
|
||||
range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
|
||||
range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128);
|
||||
range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128);
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Step> DoubleEndedIterator for ops::Range<A> {
|
||||
|
|
@ -350,7 +309,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
|||
|
||||
match Step::steps_between(&self.start, &self.end) {
|
||||
Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
|
||||
None => (0, None),
|
||||
None => (usize::MAX, None),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2435,145 +2435,61 @@ pub trait Iterator {
|
|||
/// Determines if the elements of this `Iterator` are unequal to those of
|
||||
/// another.
|
||||
#[stable(feature = "iter_order", since = "1.5.0")]
|
||||
fn ne<I>(mut self, other: I) -> bool where
|
||||
fn ne<I>(self, other: I) -> bool where
|
||||
I: IntoIterator,
|
||||
Self::Item: PartialEq<I::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
let mut other = other.into_iter();
|
||||
|
||||
loop {
|
||||
let x = match self.next() {
|
||||
None => return other.next().is_some(),
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
let y = match other.next() {
|
||||
None => return true,
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
if x != y { return true }
|
||||
}
|
||||
!self.eq(other)
|
||||
}
|
||||
|
||||
/// Determines if the elements of this `Iterator` are lexicographically
|
||||
/// less than those of another.
|
||||
#[stable(feature = "iter_order", since = "1.5.0")]
|
||||
fn lt<I>(mut self, other: I) -> bool where
|
||||
fn lt<I>(self, other: I) -> bool where
|
||||
I: IntoIterator,
|
||||
Self::Item: PartialOrd<I::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
let mut other = other.into_iter();
|
||||
|
||||
loop {
|
||||
let x = match self.next() {
|
||||
None => return other.next().is_some(),
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
let y = match other.next() {
|
||||
None => return false,
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
match x.partial_cmp(&y) {
|
||||
Some(Ordering::Less) => return true,
|
||||
Some(Ordering::Equal) => (),
|
||||
Some(Ordering::Greater) => return false,
|
||||
None => return false,
|
||||
}
|
||||
}
|
||||
self.partial_cmp(other) == Some(Ordering::Less)
|
||||
}
|
||||
|
||||
/// Determines if the elements of this `Iterator` are lexicographically
|
||||
/// less or equal to those of another.
|
||||
#[stable(feature = "iter_order", since = "1.5.0")]
|
||||
fn le<I>(mut self, other: I) -> bool where
|
||||
fn le<I>(self, other: I) -> bool where
|
||||
I: IntoIterator,
|
||||
Self::Item: PartialOrd<I::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
let mut other = other.into_iter();
|
||||
|
||||
loop {
|
||||
let x = match self.next() {
|
||||
None => { other.next(); return true; },
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
let y = match other.next() {
|
||||
None => return false,
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
match x.partial_cmp(&y) {
|
||||
Some(Ordering::Less) => return true,
|
||||
Some(Ordering::Equal) => (),
|
||||
Some(Ordering::Greater) => return false,
|
||||
None => return false,
|
||||
}
|
||||
match self.partial_cmp(other) {
|
||||
Some(Ordering::Less) | Some(Ordering::Equal) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines if the elements of this `Iterator` are lexicographically
|
||||
/// greater than those of another.
|
||||
#[stable(feature = "iter_order", since = "1.5.0")]
|
||||
fn gt<I>(mut self, other: I) -> bool where
|
||||
fn gt<I>(self, other: I) -> bool where
|
||||
I: IntoIterator,
|
||||
Self::Item: PartialOrd<I::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
let mut other = other.into_iter();
|
||||
|
||||
loop {
|
||||
let x = match self.next() {
|
||||
None => { other.next(); return false; },
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
let y = match other.next() {
|
||||
None => return true,
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
match x.partial_cmp(&y) {
|
||||
Some(Ordering::Less) => return false,
|
||||
Some(Ordering::Equal) => (),
|
||||
Some(Ordering::Greater) => return true,
|
||||
None => return false,
|
||||
}
|
||||
}
|
||||
self.partial_cmp(other) == Some(Ordering::Greater)
|
||||
}
|
||||
|
||||
/// Determines if the elements of this `Iterator` are lexicographically
|
||||
/// greater than or equal to those of another.
|
||||
#[stable(feature = "iter_order", since = "1.5.0")]
|
||||
fn ge<I>(mut self, other: I) -> bool where
|
||||
fn ge<I>(self, other: I) -> bool where
|
||||
I: IntoIterator,
|
||||
Self::Item: PartialOrd<I::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
let mut other = other.into_iter();
|
||||
|
||||
loop {
|
||||
let x = match self.next() {
|
||||
None => return other.next().is_none(),
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
let y = match other.next() {
|
||||
None => return true,
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
match x.partial_cmp(&y) {
|
||||
Some(Ordering::Less) => return false,
|
||||
Some(Ordering::Equal) => (),
|
||||
Some(Ordering::Greater) => return true,
|
||||
None => return false,
|
||||
}
|
||||
match self.partial_cmp(other) {
|
||||
Some(Ordering::Greater) | Some(Ordering::Equal) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2561,7 +2561,6 @@ pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_hash)]
|
||||
/// use std::collections::hash_map::DefaultHasher;
|
||||
/// use std::hash::{Hash, Hasher};
|
||||
/// use std::ptr;
|
||||
|
|
@ -2579,7 +2578,7 @@ pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
|
|||
///
|
||||
/// assert_eq!(actual, expected);
|
||||
/// ```
|
||||
#[unstable(feature = "ptr_hash", reason = "newly added", issue = "56286")]
|
||||
#[stable(feature = "ptr_hash", since = "1.35.0")]
|
||||
pub fn hash<T: ?Sized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
|
||||
use hash::Hash;
|
||||
hashee.hash(into);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use core::cell::Cell;
|
||||
use core::convert::TryFrom;
|
||||
use core::iter::*;
|
||||
use core::{i8, i16, isize};
|
||||
use core::usize;
|
||||
|
|
@ -1800,6 +1801,66 @@ fn test_range_inclusive_folds() {
|
|||
assert!(it.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_size_hint() {
|
||||
use core::usize::MAX as UMAX;
|
||||
assert_eq!((0..0usize).size_hint(), (0, Some(0)));
|
||||
assert_eq!((0..100usize).size_hint(), (100, Some(100)));
|
||||
assert_eq!((0..UMAX).size_hint(), (UMAX, Some(UMAX)));
|
||||
|
||||
let umax = u128::try_from(UMAX).unwrap();
|
||||
assert_eq!((0..0u128).size_hint(), (0, Some(0)));
|
||||
assert_eq!((0..100u128).size_hint(), (100, Some(100)));
|
||||
assert_eq!((0..umax).size_hint(), (UMAX, Some(UMAX)));
|
||||
assert_eq!((0..umax + 1).size_hint(), (UMAX, None));
|
||||
|
||||
use core::isize::{MAX as IMAX, MIN as IMIN};
|
||||
assert_eq!((0..0isize).size_hint(), (0, Some(0)));
|
||||
assert_eq!((-100..100isize).size_hint(), (200, Some(200)));
|
||||
assert_eq!((IMIN..IMAX).size_hint(), (UMAX, Some(UMAX)));
|
||||
|
||||
let imin = i128::try_from(IMIN).unwrap();
|
||||
let imax = i128::try_from(IMAX).unwrap();
|
||||
assert_eq!((0..0i128).size_hint(), (0, Some(0)));
|
||||
assert_eq!((-100..100i128).size_hint(), (200, Some(200)));
|
||||
assert_eq!((imin..imax).size_hint(), (UMAX, Some(UMAX)));
|
||||
assert_eq!((imin..imax + 1).size_hint(), (UMAX, None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_inclusive_size_hint() {
|
||||
use core::usize::MAX as UMAX;
|
||||
assert_eq!((1..=0usize).size_hint(), (0, Some(0)));
|
||||
assert_eq!((0..=0usize).size_hint(), (1, Some(1)));
|
||||
assert_eq!((0..=100usize).size_hint(), (101, Some(101)));
|
||||
assert_eq!((0..=UMAX - 1).size_hint(), (UMAX, Some(UMAX)));
|
||||
assert_eq!((0..=UMAX).size_hint(), (UMAX, None));
|
||||
|
||||
let umax = u128::try_from(UMAX).unwrap();
|
||||
assert_eq!((1..=0u128).size_hint(), (0, Some(0)));
|
||||
assert_eq!((0..=0u128).size_hint(), (1, Some(1)));
|
||||
assert_eq!((0..=100u128).size_hint(), (101, Some(101)));
|
||||
assert_eq!((0..=umax - 1).size_hint(), (UMAX, Some(UMAX)));
|
||||
assert_eq!((0..=umax).size_hint(), (UMAX, None));
|
||||
assert_eq!((0..=umax + 1).size_hint(), (UMAX, None));
|
||||
|
||||
use core::isize::{MAX as IMAX, MIN as IMIN};
|
||||
assert_eq!((0..=-1isize).size_hint(), (0, Some(0)));
|
||||
assert_eq!((0..=0isize).size_hint(), (1, Some(1)));
|
||||
assert_eq!((-100..=100isize).size_hint(), (201, Some(201)));
|
||||
assert_eq!((IMIN..=IMAX - 1).size_hint(), (UMAX, Some(UMAX)));
|
||||
assert_eq!((IMIN..=IMAX).size_hint(), (UMAX, None));
|
||||
|
||||
let imin = i128::try_from(IMIN).unwrap();
|
||||
let imax = i128::try_from(IMAX).unwrap();
|
||||
assert_eq!((0..=-1i128).size_hint(), (0, Some(0)));
|
||||
assert_eq!((0..=0i128).size_hint(), (1, Some(1)));
|
||||
assert_eq!((-100..=100i128).size_hint(), (201, Some(201)));
|
||||
assert_eq!((imin..=imax - 1).size_hint(), (UMAX, Some(UMAX)));
|
||||
assert_eq!((imin..=imax).size_hint(), (UMAX, None));
|
||||
assert_eq!((imin..=imax + 1).size_hint(), (UMAX, None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_repeat() {
|
||||
let mut it = repeat(42);
|
||||
|
|
|
|||
|
|
@ -490,7 +490,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
|
|||
visitor.visit_ty(ty);
|
||||
visitor.visit_generics(generics)
|
||||
}
|
||||
ItemKind::Existential(ExistTy { ref generics, ref bounds, impl_trait_fn: _ }) => {
|
||||
ItemKind::Existential(ExistTy {
|
||||
ref generics,
|
||||
ref bounds,
|
||||
..
|
||||
}) => {
|
||||
visitor.visit_id(item.hir_id);
|
||||
walk_generics(visitor, generics);
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ use syntax::symbol::{keywords, Symbol};
|
|||
use syntax::tokenstream::{TokenStream, TokenTree};
|
||||
use syntax::parse::token::Token;
|
||||
use syntax::visit::{self, Visitor};
|
||||
use syntax_pos::{Span, MultiSpan};
|
||||
use syntax_pos::Span;
|
||||
|
||||
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
|
||||
|
||||
|
|
@ -318,6 +318,49 @@ enum AnonymousLifetimeMode {
|
|||
|
||||
/// Pass responsibility to `resolve_lifetime` code for all cases.
|
||||
PassThrough,
|
||||
|
||||
/// Used in the return types of `async fn` where there exists
|
||||
/// exactly one argument-position elided lifetime.
|
||||
///
|
||||
/// In `async fn`, we lower the arguments types using the `CreateParameter`
|
||||
/// mode, meaning that non-`dyn` elided lifetimes are assigned a fresh name.
|
||||
/// If any corresponding elided lifetimes appear in the output, we need to
|
||||
/// replace them with references to the fresh name assigned to the corresponding
|
||||
/// elided lifetime in the arguments.
|
||||
///
|
||||
/// For **Modern cases**, replace the anonymous parameter with a
|
||||
/// reference to a specific freshly-named lifetime that was
|
||||
/// introduced in argument
|
||||
///
|
||||
/// For **Dyn Bound** cases, pass responsibility to
|
||||
/// `resole_lifetime` code.
|
||||
Replace(LtReplacement),
|
||||
}
|
||||
|
||||
/// The type of elided lifetime replacement to perform on `async fn` return types.
|
||||
#[derive(Copy, Clone)]
|
||||
enum LtReplacement {
|
||||
/// Fresh name introduced by the single non-dyn elided lifetime
|
||||
/// in the arguments of the async fn.
|
||||
Some(ParamName),
|
||||
|
||||
/// There is no single non-dyn elided lifetime because no lifetimes
|
||||
/// appeared in the arguments.
|
||||
NoLifetimes,
|
||||
|
||||
/// There is no single non-dyn elided lifetime because multiple
|
||||
/// lifetimes appeared in the arguments.
|
||||
MultipleLifetimes,
|
||||
}
|
||||
|
||||
/// Calculates the `LtReplacement` to use for elided lifetimes in the return
|
||||
/// type based on the fresh elided lifetimes introduced in argument position.
|
||||
fn get_elided_lt_replacement(arg_position_lifetimes: &[(Span, ParamName)]) -> LtReplacement {
|
||||
match arg_position_lifetimes {
|
||||
[] => LtReplacement::NoLifetimes,
|
||||
[(_span, param)] => LtReplacement::Some(*param),
|
||||
_ => LtReplacement::MultipleLifetimes,
|
||||
}
|
||||
}
|
||||
|
||||
struct ImplTraitTypeIdVisitor<'a> { ids: &'a mut SmallVec<[NodeId; 1]> }
|
||||
|
|
@ -778,53 +821,63 @@ impl<'a> LoweringContext<'a> {
|
|||
|
||||
let params = lifetimes_to_define
|
||||
.into_iter()
|
||||
.map(|(span, hir_name)| {
|
||||
let LoweredNodeId { node_id, hir_id } = self.next_id();
|
||||
|
||||
// Get the name we'll use to make the def-path. Note
|
||||
// that collisions are ok here and this shouldn't
|
||||
// really show up for end-user.
|
||||
let (str_name, kind) = match hir_name {
|
||||
ParamName::Plain(ident) => (
|
||||
ident.as_interned_str(),
|
||||
hir::LifetimeParamKind::InBand,
|
||||
),
|
||||
ParamName::Fresh(_) => (
|
||||
keywords::UnderscoreLifetime.name().as_interned_str(),
|
||||
hir::LifetimeParamKind::Elided,
|
||||
),
|
||||
ParamName::Error => (
|
||||
keywords::UnderscoreLifetime.name().as_interned_str(),
|
||||
hir::LifetimeParamKind::Error,
|
||||
),
|
||||
};
|
||||
|
||||
// Add a definition for the in-band lifetime def.
|
||||
self.resolver.definitions().create_def_with_parent(
|
||||
parent_id.index,
|
||||
node_id,
|
||||
DefPathData::LifetimeParam(str_name),
|
||||
DefIndexAddressSpace::High,
|
||||
Mark::root(),
|
||||
span,
|
||||
);
|
||||
|
||||
hir::GenericParam {
|
||||
hir_id,
|
||||
name: hir_name,
|
||||
attrs: hir_vec![],
|
||||
bounds: hir_vec![],
|
||||
span,
|
||||
pure_wrt_drop: false,
|
||||
kind: hir::GenericParamKind::Lifetime { kind }
|
||||
}
|
||||
})
|
||||
.map(|(span, hir_name)| self.lifetime_to_generic_param(
|
||||
span, hir_name, parent_id.index,
|
||||
))
|
||||
.chain(in_band_ty_params.into_iter())
|
||||
.collect();
|
||||
|
||||
(params, res)
|
||||
}
|
||||
|
||||
/// Converts a lifetime into a new generic parameter.
|
||||
fn lifetime_to_generic_param(
|
||||
&mut self,
|
||||
span: Span,
|
||||
hir_name: ParamName,
|
||||
parent_index: DefIndex,
|
||||
) -> hir::GenericParam {
|
||||
let LoweredNodeId { node_id, hir_id } = self.next_id();
|
||||
|
||||
// Get the name we'll use to make the def-path. Note
|
||||
// that collisions are ok here and this shouldn't
|
||||
// really show up for end-user.
|
||||
let (str_name, kind) = match hir_name {
|
||||
ParamName::Plain(ident) => (
|
||||
ident.as_interned_str(),
|
||||
hir::LifetimeParamKind::InBand,
|
||||
),
|
||||
ParamName::Fresh(_) => (
|
||||
keywords::UnderscoreLifetime.name().as_interned_str(),
|
||||
hir::LifetimeParamKind::Elided,
|
||||
),
|
||||
ParamName::Error => (
|
||||
keywords::UnderscoreLifetime.name().as_interned_str(),
|
||||
hir::LifetimeParamKind::Error,
|
||||
),
|
||||
};
|
||||
|
||||
// Add a definition for the in-band lifetime def.
|
||||
self.resolver.definitions().create_def_with_parent(
|
||||
parent_index,
|
||||
node_id,
|
||||
DefPathData::LifetimeParam(str_name),
|
||||
DefIndexAddressSpace::High,
|
||||
Mark::root(),
|
||||
span,
|
||||
);
|
||||
|
||||
hir::GenericParam {
|
||||
hir_id,
|
||||
name: hir_name,
|
||||
attrs: hir_vec![],
|
||||
bounds: hir_vec![],
|
||||
span,
|
||||
pure_wrt_drop: false,
|
||||
kind: hir::GenericParamKind::Lifetime { kind }
|
||||
}
|
||||
}
|
||||
|
||||
/// When there is a reference to some lifetime `'a`, and in-band
|
||||
/// lifetimes are enabled, then we want to push that lifetime into
|
||||
/// the vector of names to define later. In that case, it will get
|
||||
|
|
@ -928,6 +981,13 @@ impl<'a> LoweringContext<'a> {
|
|||
|this| {
|
||||
this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| {
|
||||
let mut params = Vec::new();
|
||||
// Note: it is necessary to lower generics *before* calling `f`.
|
||||
// When lowering `async fn`, there's a final step when lowering
|
||||
// the return type that assumes that all in-scope lifetimes have
|
||||
// already been added to either `in_scope_lifetimes` or
|
||||
// `lifetimes_to_define`. If we swapped the order of these two,
|
||||
// in-band-lifetimes introduced by generics or where-clauses
|
||||
// wouldn't have been added yet.
|
||||
let generics = this.lower_generics(
|
||||
generics,
|
||||
ImplTraitContext::Universal(&mut params),
|
||||
|
|
@ -1426,42 +1486,62 @@ impl<'a> LoweringContext<'a> {
|
|||
|
||||
self.with_hir_id_owner(exist_ty_node_id, |lctx| {
|
||||
let LoweredNodeId { node_id: _, hir_id } = lctx.next_id();
|
||||
let exist_ty_item_kind = hir::ItemKind::Existential(hir::ExistTy {
|
||||
let exist_ty_item = hir::ExistTy {
|
||||
generics: hir::Generics {
|
||||
params: lifetime_defs,
|
||||
where_clause: hir::WhereClause {
|
||||
hir_id,
|
||||
predicates: Vec::new().into(),
|
||||
predicates: hir_vec![],
|
||||
},
|
||||
span,
|
||||
},
|
||||
bounds: hir_bounds,
|
||||
impl_trait_fn: fn_def_id,
|
||||
});
|
||||
let exist_ty_id = lctx.lower_node_id(exist_ty_node_id);
|
||||
// Generate an `existential type Foo: Trait;` declaration.
|
||||
trace!("creating existential type with id {:#?}", exist_ty_id);
|
||||
|
||||
trace!("exist ty def index: {:#?}", exist_ty_def_index);
|
||||
let exist_ty_item = hir::Item {
|
||||
hir_id: exist_ty_id.hir_id,
|
||||
ident: keywords::Invalid.ident(),
|
||||
attrs: Default::default(),
|
||||
node: exist_ty_item_kind,
|
||||
vis: respan(span.shrink_to_lo(), hir::VisibilityKind::Inherited),
|
||||
span: exist_ty_span,
|
||||
origin: hir::ExistTyOrigin::ReturnImplTrait,
|
||||
};
|
||||
|
||||
// Insert the item into the global list. This usually happens
|
||||
// automatically for all AST items. But this existential type item
|
||||
// does not actually exist in the AST.
|
||||
lctx.insert_item(exist_ty_item);
|
||||
trace!("exist ty from impl trait def index: {:#?}", exist_ty_def_index);
|
||||
let exist_ty_id = lctx.generate_existential_type(
|
||||
exist_ty_node_id,
|
||||
exist_ty_item,
|
||||
span,
|
||||
exist_ty_span,
|
||||
);
|
||||
|
||||
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
|
||||
hir::TyKind::Def(hir::ItemId { id: exist_ty_id.hir_id }, lifetimes)
|
||||
})
|
||||
}
|
||||
|
||||
/// Registers a new existential type with the proper NodeIds and
|
||||
/// returns the lowered node ID for the existential type.
|
||||
fn generate_existential_type(
|
||||
&mut self,
|
||||
exist_ty_node_id: NodeId,
|
||||
exist_ty_item: hir::ExistTy,
|
||||
span: Span,
|
||||
exist_ty_span: Span,
|
||||
) -> LoweredNodeId {
|
||||
let exist_ty_item_kind = hir::ItemKind::Existential(exist_ty_item);
|
||||
let exist_ty_id = self.lower_node_id(exist_ty_node_id);
|
||||
// Generate an `existential type Foo: Trait;` declaration.
|
||||
trace!("registering existential type with id {:#?}", exist_ty_id);
|
||||
let exist_ty_item = hir::Item {
|
||||
hir_id: exist_ty_id.hir_id,
|
||||
ident: keywords::Invalid.ident(),
|
||||
attrs: Default::default(),
|
||||
node: exist_ty_item_kind,
|
||||
vis: respan(span.shrink_to_lo(), hir::VisibilityKind::Inherited),
|
||||
span: exist_ty_span,
|
||||
};
|
||||
|
||||
// Insert the item into the global item list. This usually happens
|
||||
// automatically for all AST items. But this existential type item
|
||||
// does not actually exist in the AST.
|
||||
self.insert_item(exist_ty_item);
|
||||
exist_ty_id
|
||||
}
|
||||
|
||||
fn lifetimes_from_impl_trait_bounds(
|
||||
&mut self,
|
||||
exist_ty_id: NodeId,
|
||||
|
|
@ -1569,9 +1649,6 @@ impl<'a> LoweringContext<'a> {
|
|||
name,
|
||||
}));
|
||||
|
||||
// We need to manually create the ids here, because the
|
||||
// definitions will go into the explicit `existential type`
|
||||
// declaration and thus need to have their owner set to that item
|
||||
let def_node_id = self.context.sess.next_node_id();
|
||||
let LoweredNodeId { node_id: _, hir_id } =
|
||||
self.context.lower_node_id_with_owner(def_node_id, self.exist_ty_id);
|
||||
|
|
@ -2108,23 +2185,42 @@ impl<'a> LoweringContext<'a> {
|
|||
impl_trait_return_allow: bool,
|
||||
make_ret_async: Option<NodeId>,
|
||||
) -> P<hir::FnDecl> {
|
||||
let inputs = decl.inputs
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
if let Some((_, ref mut ibty)) = in_band_ty_params {
|
||||
self.lower_ty_direct(&arg.ty, ImplTraitContext::Universal(ibty))
|
||||
} else {
|
||||
self.lower_ty_direct(&arg.ty, ImplTraitContext::disallowed())
|
||||
}
|
||||
})
|
||||
.collect::<HirVec<_>>();
|
||||
let lt_mode = if make_ret_async.is_some() {
|
||||
// In `async fn`, argument-position elided lifetimes
|
||||
// must be transformed into fresh generic parameters so that
|
||||
// they can be applied to the existential return type.
|
||||
AnonymousLifetimeMode::CreateParameter
|
||||
} else {
|
||||
self.anonymous_lifetime_mode
|
||||
};
|
||||
|
||||
// Remember how many lifetimes were already around so that we can
|
||||
// only look at the lifetime parameters introduced by the arguments.
|
||||
let lifetime_count_before_args = self.lifetimes_to_define.len();
|
||||
let inputs = self.with_anonymous_lifetime_mode(lt_mode, |this| {
|
||||
decl.inputs
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
if let Some((_, ibty)) = &mut in_band_ty_params {
|
||||
this.lower_ty_direct(&arg.ty, ImplTraitContext::Universal(ibty))
|
||||
} else {
|
||||
this.lower_ty_direct(&arg.ty, ImplTraitContext::disallowed())
|
||||
}
|
||||
})
|
||||
.collect::<HirVec<_>>()
|
||||
});
|
||||
|
||||
let output = if let Some(ret_id) = make_ret_async {
|
||||
// Calculate the `LtReplacement` to use for any return-position elided
|
||||
// lifetimes based on the elided lifetime parameters introduced in the args.
|
||||
let lt_replacement = get_elided_lt_replacement(
|
||||
&self.lifetimes_to_define[lifetime_count_before_args..]
|
||||
);
|
||||
self.lower_async_fn_ret_ty(
|
||||
&inputs,
|
||||
&decl.output,
|
||||
in_band_ty_params.expect("make_ret_async but no fn_def_id").0,
|
||||
ret_id,
|
||||
lt_replacement,
|
||||
)
|
||||
} else {
|
||||
match decl.output {
|
||||
|
|
@ -2173,233 +2269,171 @@ impl<'a> LoweringContext<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
// Transform `-> T` into `-> impl Future<Output = T>` for `async fn`
|
||||
// Transform `-> T` for `async fn` into -> ExistTy { .. }
|
||||
// combined with the following definition of `ExistTy`:
|
||||
//
|
||||
// existential type ExistTy<generics_from_parent_fn>: Future<Output = T>;
|
||||
//
|
||||
// fn_span: the span of the async function declaration. Used for error reporting.
|
||||
// inputs: lowered types of arguments to the function. Used to collect lifetimes.
|
||||
// output: unlowered output type (`T` in `-> T`)
|
||||
// fn_def_id: DefId of the parent function. Used to create child impl trait definition.
|
||||
// exist_ty_node_id: NodeId of the existential type that should be created.
|
||||
// elided_lt_replacement: replacement for elided lifetimes in the return type
|
||||
fn lower_async_fn_ret_ty(
|
||||
&mut self,
|
||||
inputs: &[hir::Ty],
|
||||
output: &FunctionRetTy,
|
||||
fn_def_id: DefId,
|
||||
return_impl_trait_id: NodeId,
|
||||
exist_ty_node_id: NodeId,
|
||||
elided_lt_replacement: LtReplacement,
|
||||
) -> hir::FunctionRetTy {
|
||||
// Get lifetimes used in the input arguments to the function. Our output type must also
|
||||
// have the same lifetime.
|
||||
// FIXME(cramertj): multiple different lifetimes are not allowed because
|
||||
// `impl Trait + 'a + 'b` doesn't allow for capture `'a` and `'b` where neither is a subset
|
||||
// of the other. We really want some new lifetime that is a subset of all input lifetimes,
|
||||
// but that doesn't exist at the moment.
|
||||
let span = output.span();
|
||||
|
||||
struct AsyncFnLifetimeCollector<'r, 'a: 'r> {
|
||||
context: &'r mut LoweringContext<'a>,
|
||||
// Lifetimes bound by HRTB.
|
||||
currently_bound_lifetimes: Vec<hir::LifetimeName>,
|
||||
// Whether to count elided lifetimes.
|
||||
// Disabled inside of `Fn` or `fn` syntax.
|
||||
collect_elided_lifetimes: bool,
|
||||
// The lifetime found.
|
||||
// Multiple different or elided lifetimes cannot appear in async fn for now.
|
||||
output_lifetime: Option<(hir::LifetimeName, Span)>,
|
||||
}
|
||||
let exist_ty_span = self.mark_span_with_reason(
|
||||
CompilerDesugaringKind::Async,
|
||||
span,
|
||||
None,
|
||||
);
|
||||
|
||||
impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for AsyncFnLifetimeCollector<'r, 'a> {
|
||||
fn nested_visit_map<'this>(
|
||||
&'this mut self,
|
||||
) -> hir::intravisit::NestedVisitorMap<'this, 'v> {
|
||||
hir::intravisit::NestedVisitorMap::None
|
||||
}
|
||||
let exist_ty_def_index = self
|
||||
.resolver
|
||||
.definitions()
|
||||
.opt_def_index(exist_ty_node_id)
|
||||
.unwrap();
|
||||
|
||||
fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs) {
|
||||
// Don't collect elided lifetimes used inside of `Fn()` syntax.
|
||||
if parameters.parenthesized {
|
||||
let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
|
||||
self.collect_elided_lifetimes = false;
|
||||
hir::intravisit::walk_generic_args(self, span, parameters);
|
||||
self.collect_elided_lifetimes = old_collect_elided_lifetimes;
|
||||
} else {
|
||||
hir::intravisit::walk_generic_args(self, span, parameters);
|
||||
}
|
||||
}
|
||||
self.allocate_hir_id_counter(exist_ty_node_id);
|
||||
|
||||
fn visit_ty(&mut self, t: &'v hir::Ty) {
|
||||
// Don't collect elided lifetimes used inside of `fn()` syntax.
|
||||
if let &hir::TyKind::BareFn(_) = &t.node {
|
||||
let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
|
||||
self.collect_elided_lifetimes = false;
|
||||
|
||||
// Record the "stack height" of `for<'a>` lifetime bindings
|
||||
// to be able to later fully undo their introduction.
|
||||
let old_len = self.currently_bound_lifetimes.len();
|
||||
hir::intravisit::walk_ty(self, t);
|
||||
self.currently_bound_lifetimes.truncate(old_len);
|
||||
|
||||
self.collect_elided_lifetimes = old_collect_elided_lifetimes;
|
||||
} else {
|
||||
hir::intravisit::walk_ty(self, t);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_poly_trait_ref(
|
||||
&mut self,
|
||||
trait_ref: &'v hir::PolyTraitRef,
|
||||
modifier: hir::TraitBoundModifier,
|
||||
) {
|
||||
// Record the "stack height" of `for<'a>` lifetime bindings
|
||||
// to be able to later fully undo their introduction.
|
||||
let old_len = self.currently_bound_lifetimes.len();
|
||||
hir::intravisit::walk_poly_trait_ref(self, trait_ref, modifier);
|
||||
self.currently_bound_lifetimes.truncate(old_len);
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, param: &'v hir::GenericParam) {
|
||||
// Record the introduction of 'a in `for<'a> ...`
|
||||
if let hir::GenericParamKind::Lifetime { .. } = param.kind {
|
||||
// Introduce lifetimes one at a time so that we can handle
|
||||
// cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`
|
||||
let lt_name = hir::LifetimeName::Param(param.name);
|
||||
self.currently_bound_lifetimes.push(lt_name);
|
||||
}
|
||||
|
||||
hir::intravisit::walk_generic_param(self, param);
|
||||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
|
||||
let name = match lifetime.name {
|
||||
hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
|
||||
if self.collect_elided_lifetimes {
|
||||
// Use `'_` for both implicit and underscore lifetimes in
|
||||
// `abstract type Foo<'_>: SomeTrait<'_>;`
|
||||
hir::LifetimeName::Underscore
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
hir::LifetimeName::Param(_) => lifetime.name,
|
||||
hir::LifetimeName::Error | hir::LifetimeName::Static => return,
|
||||
};
|
||||
|
||||
if !self.currently_bound_lifetimes.contains(&name) {
|
||||
if let Some((current_lt_name, current_lt_span)) = self.output_lifetime {
|
||||
// We don't currently have a reliable way to desugar `async fn` with
|
||||
// multiple potentially unrelated input lifetimes into
|
||||
// `-> impl Trait + 'lt`, so we report an error in this case.
|
||||
if current_lt_name != name {
|
||||
struct_span_err!(
|
||||
self.context.sess,
|
||||
MultiSpan::from_spans(vec![current_lt_span, lifetime.span]),
|
||||
E0709,
|
||||
"multiple different lifetimes used in arguments of `async fn`",
|
||||
)
|
||||
.span_label(current_lt_span, "first lifetime here")
|
||||
.span_label(lifetime.span, "different lifetime here")
|
||||
.help("`async fn` can only accept borrowed values \
|
||||
with identical lifetimes")
|
||||
.emit()
|
||||
} else if current_lt_name.is_elided() && name.is_elided() {
|
||||
struct_span_err!(
|
||||
self.context.sess,
|
||||
MultiSpan::from_spans(vec![current_lt_span, lifetime.span]),
|
||||
E0707,
|
||||
"multiple elided lifetimes used in arguments of `async fn`",
|
||||
)
|
||||
.span_label(current_lt_span, "first lifetime here")
|
||||
.span_label(lifetime.span, "different lifetime here")
|
||||
.help("consider giving these arguments named lifetimes")
|
||||
.emit()
|
||||
}
|
||||
} else {
|
||||
self.output_lifetime = Some((name, lifetime.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let bound_lifetime = {
|
||||
let mut lifetime_collector = AsyncFnLifetimeCollector {
|
||||
context: self,
|
||||
currently_bound_lifetimes: Vec::new(),
|
||||
collect_elided_lifetimes: true,
|
||||
output_lifetime: None,
|
||||
};
|
||||
|
||||
for arg in inputs {
|
||||
hir::intravisit::walk_ty(&mut lifetime_collector, arg);
|
||||
}
|
||||
lifetime_collector.output_lifetime
|
||||
};
|
||||
|
||||
let span = match output {
|
||||
FunctionRetTy::Ty(ty) => ty.span,
|
||||
FunctionRetTy::Default(span) => *span,
|
||||
};
|
||||
|
||||
let impl_trait_ty = self.lower_existential_impl_trait(
|
||||
span, Some(fn_def_id), return_impl_trait_id, |this| {
|
||||
let output_ty = match output {
|
||||
FunctionRetTy::Ty(ty) => {
|
||||
this.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id)))
|
||||
}
|
||||
FunctionRetTy::Default(span) => {
|
||||
let LoweredNodeId { node_id: _, hir_id } = this.next_id();
|
||||
P(hir::Ty {
|
||||
hir_id,
|
||||
node: hir::TyKind::Tup(hir_vec![]),
|
||||
span: *span,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// "<Output = T>"
|
||||
let LoweredNodeId { node_id: _, hir_id } = this.next_id();
|
||||
let future_params = P(hir::GenericArgs {
|
||||
args: hir_vec![],
|
||||
bindings: hir_vec![hir::TypeBinding {
|
||||
ident: Ident::from_str(FN_OUTPUT_NAME),
|
||||
ty: output_ty,
|
||||
hir_id,
|
||||
let (exist_ty_node_id, lifetime_params) = self.with_hir_id_owner(exist_ty_node_id, |this| {
|
||||
let future_bound = this.with_anonymous_lifetime_mode(
|
||||
AnonymousLifetimeMode::Replace(elided_lt_replacement),
|
||||
|this| this.lower_async_fn_output_type_to_future_bound(
|
||||
output,
|
||||
fn_def_id,
|
||||
span,
|
||||
}],
|
||||
parenthesized: false,
|
||||
});
|
||||
),
|
||||
);
|
||||
|
||||
let future_path =
|
||||
this.std_path(span, &["future", "Future"], Some(future_params), false);
|
||||
// Calculate all the lifetimes that should be captured
|
||||
// by the existential type. This should include all in-scope
|
||||
// lifetime parameters, including those defined in-band.
|
||||
//
|
||||
// Note: this must be done after lowering the output type,
|
||||
// as the output type may introduce new in-band lifetimes.
|
||||
let lifetime_params: Vec<(Span, ParamName)> =
|
||||
this.in_scope_lifetimes
|
||||
.iter().cloned()
|
||||
.map(|ident| (ident.span, ParamName::Plain(ident)))
|
||||
.chain(this.lifetimes_to_define.iter().cloned())
|
||||
.collect();
|
||||
|
||||
let generic_params =
|
||||
lifetime_params
|
||||
.iter().cloned()
|
||||
.map(|(span, hir_name)| {
|
||||
this.lifetime_to_generic_param(span, hir_name, exist_ty_def_index)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let LoweredNodeId { node_id: _, hir_id } = this.next_id();
|
||||
let mut bounds = vec![
|
||||
hir::GenericBound::Trait(
|
||||
hir::PolyTraitRef {
|
||||
trait_ref: hir::TraitRef {
|
||||
path: future_path,
|
||||
hir_ref_id: hir_id,
|
||||
},
|
||||
bound_generic_params: hir_vec![],
|
||||
span,
|
||||
let exist_ty_item = hir::ExistTy {
|
||||
generics: hir::Generics {
|
||||
params: generic_params,
|
||||
where_clause: hir::WhereClause {
|
||||
hir_id,
|
||||
predicates: hir_vec![],
|
||||
},
|
||||
hir::TraitBoundModifier::None
|
||||
),
|
||||
];
|
||||
span,
|
||||
},
|
||||
bounds: hir_vec![future_bound],
|
||||
impl_trait_fn: Some(fn_def_id),
|
||||
origin: hir::ExistTyOrigin::AsyncFn,
|
||||
};
|
||||
|
||||
if let Some((name, span)) = bound_lifetime {
|
||||
let LoweredNodeId { node_id: _, hir_id } = this.next_id();
|
||||
bounds.push(hir::GenericBound::Outlives(
|
||||
hir::Lifetime { hir_id, name, span }));
|
||||
}
|
||||
trace!("exist ty from async fn def index: {:#?}", exist_ty_def_index);
|
||||
let exist_ty_id = this.generate_existential_type(
|
||||
exist_ty_node_id,
|
||||
exist_ty_item,
|
||||
span,
|
||||
exist_ty_span,
|
||||
);
|
||||
|
||||
hir::HirVec::from(bounds)
|
||||
(exist_ty_id.node_id, lifetime_params)
|
||||
});
|
||||
|
||||
let generic_args =
|
||||
lifetime_params
|
||||
.iter().cloned()
|
||||
.map(|(span, hir_name)| {
|
||||
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
|
||||
GenericArg::Lifetime(hir::Lifetime {
|
||||
hir_id,
|
||||
span,
|
||||
name: hir::LifetimeName::Param(hir_name),
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
let exist_ty_hir_id = self.lower_node_id(exist_ty_node_id).hir_id;
|
||||
let exist_ty_ref = hir::TyKind::Def(hir::ItemId { id: exist_ty_hir_id }, generic_args);
|
||||
|
||||
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
|
||||
let impl_trait_ty = P(hir::Ty {
|
||||
node: impl_trait_ty,
|
||||
hir::FunctionRetTy::Return(P(hir::Ty {
|
||||
node: exist_ty_ref,
|
||||
span,
|
||||
hir_id,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Turns `-> T` into `Future<Output = T>`
|
||||
fn lower_async_fn_output_type_to_future_bound(
|
||||
&mut self,
|
||||
output: &FunctionRetTy,
|
||||
fn_def_id: DefId,
|
||||
span: Span,
|
||||
) -> hir::GenericBound {
|
||||
// Compute the `T` in `Future<Output = T>` from the return type.
|
||||
let output_ty = match output {
|
||||
FunctionRetTy::Ty(ty) => {
|
||||
self.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id)))
|
||||
}
|
||||
FunctionRetTy::Default(ret_ty_span) => {
|
||||
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
|
||||
P(hir::Ty {
|
||||
hir_id,
|
||||
node: hir::TyKind::Tup(hir_vec![]),
|
||||
span: *ret_ty_span,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// "<Output = T>"
|
||||
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
|
||||
let future_params = P(hir::GenericArgs {
|
||||
args: hir_vec![],
|
||||
bindings: hir_vec![hir::TypeBinding {
|
||||
ident: Ident::from_str(FN_OUTPUT_NAME),
|
||||
ty: output_ty,
|
||||
hir_id,
|
||||
span,
|
||||
}],
|
||||
parenthesized: false,
|
||||
});
|
||||
|
||||
hir::FunctionRetTy::Return(impl_trait_ty)
|
||||
// ::std::future::Future<future_params>
|
||||
let future_path =
|
||||
self.std_path(span, &["future", "Future"], Some(future_params), false);
|
||||
|
||||
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
|
||||
hir::GenericBound::Trait(
|
||||
hir::PolyTraitRef {
|
||||
trait_ref: hir::TraitRef {
|
||||
path: future_path,
|
||||
hir_ref_id: hir_id,
|
||||
},
|
||||
bound_generic_params: hir_vec![],
|
||||
span,
|
||||
},
|
||||
hir::TraitBoundModifier::None,
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_param_bound(
|
||||
|
|
@ -2437,6 +2471,11 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
|
||||
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span),
|
||||
|
||||
AnonymousLifetimeMode::Replace(replacement) => {
|
||||
let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(l.id);
|
||||
self.replace_elided_lifetime(hir_id, span, replacement)
|
||||
}
|
||||
},
|
||||
ident => {
|
||||
self.maybe_collect_in_band_lifetime(ident);
|
||||
|
|
@ -2461,6 +2500,39 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Replace a return-position elided lifetime with the elided lifetime
|
||||
/// from the arguments.
|
||||
fn replace_elided_lifetime(
|
||||
&mut self,
|
||||
hir_id: hir::HirId,
|
||||
span: Span,
|
||||
replacement: LtReplacement,
|
||||
) -> hir::Lifetime {
|
||||
let multiple_or_none = match replacement {
|
||||
LtReplacement::Some(name) => {
|
||||
return hir::Lifetime {
|
||||
hir_id,
|
||||
span,
|
||||
name: hir::LifetimeName::Param(name),
|
||||
};
|
||||
}
|
||||
LtReplacement::MultipleLifetimes => "multiple",
|
||||
LtReplacement::NoLifetimes => "none",
|
||||
};
|
||||
|
||||
let mut err = crate::middle::resolve_lifetime::report_missing_lifetime_specifiers(
|
||||
self.sess,
|
||||
span,
|
||||
1,
|
||||
);
|
||||
err.note(&format!(
|
||||
"return-position elided lifetimes require exactly one \
|
||||
input-position elided lifetime, found {}.", multiple_or_none));
|
||||
err.emit();
|
||||
|
||||
hir::Lifetime { hir_id, span, name: hir::LifetimeName::Error }
|
||||
}
|
||||
|
||||
fn lower_generic_params(
|
||||
&mut self,
|
||||
params: &[GenericParam],
|
||||
|
|
@ -2941,6 +3013,7 @@ impl<'a> LoweringContext<'a> {
|
|||
generics: self.lower_generics(generics, ImplTraitContext::disallowed()),
|
||||
bounds: self.lower_param_bounds(b, ImplTraitContext::disallowed()),
|
||||
impl_trait_fn: None,
|
||||
origin: hir::ExistTyOrigin::ExistentialType,
|
||||
}),
|
||||
ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
|
||||
hir::EnumDef {
|
||||
|
|
@ -5083,7 +5156,8 @@ impl<'a> LoweringContext<'a> {
|
|||
/// with no explicit lifetime.
|
||||
fn elided_ref_lifetime(&mut self, span: Span) -> hir::Lifetime {
|
||||
match self.anonymous_lifetime_mode {
|
||||
// Intercept when we are in an impl header and introduce an in-band lifetime.
|
||||
// Intercept when we are in an impl header or async fn and introduce an in-band
|
||||
// lifetime.
|
||||
// Hence `impl Foo for &u32` becomes `impl<'f> Foo for &'f u32` for some fresh
|
||||
// `'f`.
|
||||
AnonymousLifetimeMode::CreateParameter => {
|
||||
|
|
@ -5099,6 +5173,10 @@ impl<'a> LoweringContext<'a> {
|
|||
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
|
||||
|
||||
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
|
||||
|
||||
AnonymousLifetimeMode::Replace(replacement) => {
|
||||
self.new_replacement_lifetime(replacement, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5133,6 +5211,12 @@ impl<'a> LoweringContext<'a> {
|
|||
/// sorts of cases are deprecated. This may therefore report a warning or an
|
||||
/// error, depending on the mode.
|
||||
fn elided_path_lifetimes(&mut self, span: Span, count: usize) -> P<[hir::Lifetime]> {
|
||||
(0..count)
|
||||
.map(|_| self.elided_path_lifetime(span))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
|
||||
match self.anonymous_lifetime_mode {
|
||||
// N.B., We intentionally ignore the create-parameter mode here
|
||||
// and instead "pass through" to resolve-lifetimes, which will then
|
||||
|
|
@ -5140,21 +5224,16 @@ impl<'a> LoweringContext<'a> {
|
|||
// impl elision for deprecated forms like
|
||||
//
|
||||
// impl Foo for std::cell::Ref<u32> // note lack of '_
|
||||
AnonymousLifetimeMode::CreateParameter => {}
|
||||
AnonymousLifetimeMode::CreateParameter |
|
||||
// This is the normal case.
|
||||
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
|
||||
|
||||
AnonymousLifetimeMode::ReportError => {
|
||||
return (0..count)
|
||||
.map(|_| self.new_error_lifetime(None, span))
|
||||
.collect();
|
||||
AnonymousLifetimeMode::Replace(replacement) => {
|
||||
self.new_replacement_lifetime(replacement, span)
|
||||
}
|
||||
|
||||
// This is the normal case.
|
||||
AnonymousLifetimeMode::PassThrough => {}
|
||||
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
|
||||
}
|
||||
|
||||
(0..count)
|
||||
.map(|_| self.new_implicit_lifetime(span))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Invoked to create the lifetime argument(s) for an elided trait object
|
||||
|
|
@ -5184,11 +5263,25 @@ impl<'a> LoweringContext<'a> {
|
|||
|
||||
// This is the normal case.
|
||||
AnonymousLifetimeMode::PassThrough => {}
|
||||
|
||||
// We don't need to do any replacement here as this lifetime
|
||||
// doesn't refer to an elided lifetime elsewhere in the function
|
||||
// signature.
|
||||
AnonymousLifetimeMode::Replace(_) => {}
|
||||
}
|
||||
|
||||
self.new_implicit_lifetime(span)
|
||||
}
|
||||
|
||||
fn new_replacement_lifetime(
|
||||
&mut self,
|
||||
replacement: LtReplacement,
|
||||
span: Span,
|
||||
) -> hir::Lifetime {
|
||||
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
|
||||
self.replace_elided_lifetime(hir_id, span, replacement)
|
||||
}
|
||||
|
||||
fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
|
||||
let LoweredNodeId { node_id: _, hir_id } = self.next_id();
|
||||
|
||||
|
|
|
|||
|
|
@ -1799,6 +1799,18 @@ pub struct ExistTy {
|
|||
pub generics: Generics,
|
||||
pub bounds: GenericBounds,
|
||||
pub impl_trait_fn: Option<DefId>,
|
||||
pub origin: ExistTyOrigin,
|
||||
}
|
||||
|
||||
/// Where the existential type came from
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub enum ExistTyOrigin {
|
||||
/// `existential type Foo: Trait;`
|
||||
ExistentialType,
|
||||
/// `-> impl Trait`
|
||||
ReturnImplTrait,
|
||||
/// `async fn`
|
||||
AsyncFn,
|
||||
}
|
||||
|
||||
/// The various kinds of types recognized by the compiler.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//! Error Reporting for Anonymous Region Lifetime Errors
|
||||
//! where one region is named and the other is anonymous.
|
||||
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use crate::hir::{FunctionRetTy, TyKind};
|
||||
use crate::ty;
|
||||
use errors::{Applicability, DiagnosticBuilder};
|
||||
|
||||
|
|
@ -11,9 +12,10 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
|
|||
let (span, sub, sup) = self.get_regions();
|
||||
|
||||
debug!(
|
||||
"try_report_named_anon_conflict(sub={:?}, sup={:?})",
|
||||
"try_report_named_anon_conflict(sub={:?}, sup={:?}, error={:?})",
|
||||
sub,
|
||||
sup
|
||||
sup,
|
||||
self.error,
|
||||
);
|
||||
|
||||
// Determine whether the sub and sup consist of one named region ('a)
|
||||
|
|
@ -84,6 +86,13 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
|
|||
{
|
||||
return None;
|
||||
}
|
||||
if let FunctionRetTy::Return(ty) = &fndecl.output {
|
||||
if let (TyKind::Def(_, _), ty::ReStatic) = (&ty.node, sub) {
|
||||
// This is an impl Trait return that evaluates de need of 'static.
|
||||
// We handle this case better in `static_impl_trait`.
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (error_var, span_label_var) = if let Some(simple_ident) = arg.pat.simple_ident() {
|
||||
|
|
@ -103,13 +112,13 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
|
|||
error_var
|
||||
);
|
||||
|
||||
diag.span_label(span, format!("lifetime `{}` required", named));
|
||||
diag.span_suggestion(
|
||||
new_ty_span,
|
||||
&format!("add explicit lifetime `{}` to {}", named, span_label_var),
|
||||
new_ty.to_string(),
|
||||
Applicability::Unspecified,
|
||||
)
|
||||
.span_label(span, format!("lifetime `{}` required", named));
|
||||
new_ty_span,
|
||||
&format!("add explicit lifetime `{}` to {}", named, span_label_var),
|
||||
new_ty.to_string(),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
|
||||
Some(diag)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,9 @@ pub struct OpaqueTypeDecl<'tcx> {
|
|||
/// the fn body). (Ultimately, writeback is responsible for this
|
||||
/// check.)
|
||||
pub has_required_region_bounds: bool,
|
||||
|
||||
/// The origin of the existential type
|
||||
pub origin: hir::ExistTyOrigin,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
|
|
@ -326,14 +329,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
// There are two regions (`lr` and
|
||||
// `subst_arg`) which are not relatable. We can't
|
||||
// find a best choice.
|
||||
self.tcx
|
||||
let context_name = match opaque_defn.origin {
|
||||
hir::ExistTyOrigin::ExistentialType => "existential type",
|
||||
hir::ExistTyOrigin::ReturnImplTrait => "impl Trait",
|
||||
hir::ExistTyOrigin::AsyncFn => "async fn",
|
||||
};
|
||||
let msg = format!("ambiguous lifetime bound in `{}`", context_name);
|
||||
let mut err = self.tcx
|
||||
.sess
|
||||
.struct_span_err(span, "ambiguous lifetime bound in `impl Trait`")
|
||||
.span_label(
|
||||
span,
|
||||
format!("neither `{}` nor `{}` outlives the other", lr, subst_arg),
|
||||
)
|
||||
.emit();
|
||||
.struct_span_err(span, &msg);
|
||||
|
||||
let lr_name = lr.to_string();
|
||||
let subst_arg_name = subst_arg.to_string();
|
||||
let label_owned;
|
||||
let label = match (&*lr_name, &*subst_arg_name) {
|
||||
("'_", "'_") => "the elided lifetimes here do not outlive one another",
|
||||
_ => {
|
||||
label_owned = format!(
|
||||
"neither `{}` nor `{}` outlives the other",
|
||||
lr_name,
|
||||
subst_arg_name,
|
||||
);
|
||||
&label_owned
|
||||
}
|
||||
};
|
||||
err.span_label(span, label);
|
||||
|
||||
if let hir::ExistTyOrigin::AsyncFn = opaque_defn.origin {
|
||||
err.note("multiple unrelated lifetimes are not allowed in \
|
||||
`async fn`.");
|
||||
err.note("if you're using argument-position elided lifetimes, consider \
|
||||
switching to a single named lifetime.");
|
||||
}
|
||||
err.emit();
|
||||
|
||||
least_region = Some(self.tcx.mk_region(ty::ReEmpty));
|
||||
break;
|
||||
|
|
@ -692,31 +720,41 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
|||
parent_def_id == tcx.hir()
|
||||
.local_def_id_from_hir_id(opaque_parent_hir_id)
|
||||
};
|
||||
let in_definition_scope = match tcx.hir().find_by_hir_id(opaque_hir_id) {
|
||||
let (in_definition_scope, origin) =
|
||||
match tcx.hir().find_by_hir_id(opaque_hir_id)
|
||||
{
|
||||
Some(Node::Item(item)) => match item.node {
|
||||
// impl trait
|
||||
hir::ItemKind::Existential(hir::ExistTy {
|
||||
impl_trait_fn: Some(parent),
|
||||
origin,
|
||||
..
|
||||
}) => parent == self.parent_def_id,
|
||||
}) => (parent == self.parent_def_id, origin),
|
||||
// named existential types
|
||||
hir::ItemKind::Existential(hir::ExistTy {
|
||||
impl_trait_fn: None,
|
||||
origin,
|
||||
..
|
||||
}) => may_define_existential_type(
|
||||
tcx,
|
||||
self.parent_def_id,
|
||||
opaque_hir_id,
|
||||
}) => (
|
||||
may_define_existential_type(
|
||||
tcx,
|
||||
self.parent_def_id,
|
||||
opaque_hir_id,
|
||||
),
|
||||
origin,
|
||||
),
|
||||
_ => def_scope_default(),
|
||||
_ => (def_scope_default(), hir::ExistTyOrigin::ExistentialType),
|
||||
},
|
||||
Some(Node::ImplItem(item)) => match item.node {
|
||||
hir::ImplItemKind::Existential(_) => may_define_existential_type(
|
||||
tcx,
|
||||
self.parent_def_id,
|
||||
opaque_hir_id,
|
||||
hir::ImplItemKind::Existential(_) => (
|
||||
may_define_existential_type(
|
||||
tcx,
|
||||
self.parent_def_id,
|
||||
opaque_hir_id,
|
||||
),
|
||||
hir::ExistTyOrigin::ExistentialType,
|
||||
),
|
||||
_ => def_scope_default(),
|
||||
_ => (def_scope_default(), hir::ExistTyOrigin::ExistentialType),
|
||||
},
|
||||
_ => bug!(
|
||||
"expected (impl) item, found {}",
|
||||
|
|
@ -724,7 +762,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
|||
),
|
||||
};
|
||||
if in_definition_scope {
|
||||
return self.fold_opaque_ty(ty, def_id, substs);
|
||||
return self.fold_opaque_ty(ty, def_id, substs, origin);
|
||||
}
|
||||
|
||||
debug!(
|
||||
|
|
@ -746,6 +784,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
|||
ty: Ty<'tcx>,
|
||||
def_id: DefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
origin: hir::ExistTyOrigin,
|
||||
) -> Ty<'tcx> {
|
||||
let infcx = self.infcx;
|
||||
let tcx = infcx.tcx;
|
||||
|
|
@ -795,6 +834,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
|||
substs,
|
||||
concrete_ty: ty_var,
|
||||
has_required_region_bounds: !required_region_bounds.is_empty(),
|
||||
origin,
|
||||
},
|
||||
);
|
||||
debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
|
||||
|
|
|
|||
|
|
@ -2891,7 +2891,7 @@ fn insert_late_bound_lifetimes(
|
|||
}
|
||||
}
|
||||
|
||||
fn report_missing_lifetime_specifiers(
|
||||
pub fn report_missing_lifetime_specifiers(
|
||||
sess: &Session,
|
||||
span: Span,
|
||||
count: usize,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ pub type ConstEvalResult<'tcx> = Result<ty::Const<'tcx>, ErrorHandled>;
|
|||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct ConstEvalErr<'tcx> {
|
||||
pub span: Span,
|
||||
pub error: crate::mir::interpret::EvalErrorKind<'tcx, u64>,
|
||||
pub error: crate::mir::interpret::InterpError<'tcx, u64>,
|
||||
pub stacktrace: Vec<FrameInfo<'tcx>>,
|
||||
}
|
||||
|
||||
|
|
@ -135,10 +135,10 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
|
|||
lint_root: Option<hir::HirId>,
|
||||
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
|
||||
match self.error {
|
||||
EvalErrorKind::Layout(LayoutError::Unknown(_)) |
|
||||
EvalErrorKind::TooGeneric => return Err(ErrorHandled::TooGeneric),
|
||||
EvalErrorKind::Layout(LayoutError::SizeOverflow(_)) |
|
||||
EvalErrorKind::TypeckError => return Err(ErrorHandled::Reported),
|
||||
InterpError::Layout(LayoutError::Unknown(_)) |
|
||||
InterpError::TooGeneric => return Err(ErrorHandled::TooGeneric),
|
||||
InterpError::Layout(LayoutError::SizeOverflow(_)) |
|
||||
InterpError::TypeckError => return Err(ErrorHandled::Reported),
|
||||
_ => {},
|
||||
}
|
||||
trace!("reporting const eval failure at {:?}", self.span);
|
||||
|
|
@ -180,7 +180,7 @@ pub fn struct_error<'a, 'gcx, 'tcx>(
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EvalError<'tcx> {
|
||||
pub kind: EvalErrorKind<'tcx, u64>,
|
||||
pub kind: InterpError<'tcx, u64>,
|
||||
pub backtrace: Option<Box<Backtrace>>,
|
||||
}
|
||||
|
||||
|
|
@ -197,8 +197,8 @@ fn print_backtrace(backtrace: &mut Backtrace) {
|
|||
eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
|
||||
}
|
||||
|
||||
impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
|
||||
fn from(kind: EvalErrorKind<'tcx, u64>) -> Self {
|
||||
impl<'tcx> From<InterpError<'tcx, u64>> for EvalError<'tcx> {
|
||||
fn from(kind: InterpError<'tcx, u64>) -> Self {
|
||||
let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
|
||||
// matching RUST_BACKTRACE, we treat "0" the same as "not present".
|
||||
Ok(ref val) if val != "0" => {
|
||||
|
|
@ -221,10 +221,10 @@ impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub type AssertMessage<'tcx> = EvalErrorKind<'tcx, mir::Operand<'tcx>>;
|
||||
pub type AssertMessage<'tcx> = InterpError<'tcx, mir::Operand<'tcx>>;
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub enum EvalErrorKind<'tcx, O> {
|
||||
pub enum InterpError<'tcx, O> {
|
||||
/// This variant is used by machines to signal their own errors that do not
|
||||
/// match an existing variant.
|
||||
MachineError(String),
|
||||
|
|
@ -312,9 +312,9 @@ pub enum EvalErrorKind<'tcx, O> {
|
|||
|
||||
pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;
|
||||
|
||||
impl<'tcx, O> EvalErrorKind<'tcx, O> {
|
||||
impl<'tcx, O> InterpError<'tcx, O> {
|
||||
pub fn description(&self) -> &str {
|
||||
use self::EvalErrorKind::*;
|
||||
use self::InterpError::*;
|
||||
match *self {
|
||||
MachineError(ref inner) => inner,
|
||||
FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..)
|
||||
|
|
@ -450,15 +450,15 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for EvalErrorKind<'tcx, u64> {
|
||||
impl<'tcx> fmt::Display for InterpError<'tcx, u64> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
|
||||
impl<'tcx, O: fmt::Debug> fmt::Debug for InterpError<'tcx, O> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use self::EvalErrorKind::*;
|
||||
use self::InterpError::*;
|
||||
match *self {
|
||||
PointerOutOfBounds { ptr, msg, allocation_size } => {
|
||||
write!(f, "Pointer must be in-bounds{} at offset {}, but is outside bounds of \
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! err {
|
||||
($($tt:tt)*) => { Err($crate::mir::interpret::EvalErrorKind::$($tt)*.into()) };
|
||||
($($tt:tt)*) => { Err($crate::mir::interpret::InterpError::$($tt)*.into()) };
|
||||
}
|
||||
|
||||
mod error;
|
||||
|
|
@ -11,7 +11,7 @@ mod allocation;
|
|||
mod pointer;
|
||||
|
||||
pub use self::error::{
|
||||
EvalError, EvalResult, EvalErrorKind, AssertMessage, ConstEvalErr, struct_error,
|
||||
EvalError, EvalResult, InterpError, AssertMessage, ConstEvalErr, struct_error,
|
||||
FrameInfo, ConstEvalRawResult, ConstEvalResult, ErrorHandled,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
use crate::hir::def::{CtorKind, Namespace};
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::hir::{self, HirId, InlineAsm};
|
||||
use crate::mir::interpret::{ConstValue, EvalErrorKind, Scalar};
|
||||
use crate::mir::interpret::{ConstValue, InterpError, Scalar};
|
||||
use crate::mir::visit::MirVisitable;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
use rustc_apfloat::Float;
|
||||
|
|
@ -3226,8 +3226,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
|
|||
target,
|
||||
cleanup,
|
||||
} => {
|
||||
let msg = if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg {
|
||||
EvalErrorKind::BoundsCheck {
|
||||
let msg = if let InterpError::BoundsCheck { ref len, ref index } = *msg {
|
||||
InterpError::BoundsCheck {
|
||||
len: len.fold_with(folder),
|
||||
index: index.fold_with(folder),
|
||||
}
|
||||
|
|
@ -3301,7 +3301,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
|
|||
ref cond, ref msg, ..
|
||||
} => {
|
||||
if cond.visit_with(visitor) {
|
||||
if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg {
|
||||
if let InterpError::BoundsCheck { ref len, ref index } = *msg {
|
||||
len.visit_with(visitor) || index.visit_with(visitor)
|
||||
} else {
|
||||
false
|
||||
|
|
|
|||
|
|
@ -560,7 +560,7 @@ macro_rules! make_mir_visitor {
|
|||
fn super_assert_message(&mut self,
|
||||
msg: & $($mutability)? AssertMessage<'tcx>,
|
||||
location: Location) {
|
||||
use crate::mir::interpret::EvalErrorKind::*;
|
||||
use crate::mir::interpret::InterpError::*;
|
||||
if let BoundsCheck { len, index } = msg {
|
||||
self.visit_operand(len, location);
|
||||
self.visit_operand(index, location);
|
||||
|
|
|
|||
|
|
@ -1200,6 +1200,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
"when using two-phase-borrows, allow two phases even for non-autoref `&mut` borrows"),
|
||||
time_passes: bool = (false, parse_bool, [UNTRACKED],
|
||||
"measure time of each rustc pass"),
|
||||
time: bool = (false, parse_bool, [UNTRACKED],
|
||||
"measure time of rustc processes"),
|
||||
count_llvm_insns: bool = (false, parse_bool,
|
||||
[UNTRACKED_WITH_WARNING(true,
|
||||
"The output generated by `-Z count_llvm_insns` might not be reliable \
|
||||
|
|
|
|||
|
|
@ -504,6 +504,9 @@ impl Session {
|
|||
self.opts.debugging_opts.verbose
|
||||
}
|
||||
pub fn time_passes(&self) -> bool {
|
||||
self.opts.debugging_opts.time_passes || self.opts.debugging_opts.time
|
||||
}
|
||||
pub fn time_extended(&self) -> bool {
|
||||
self.opts.debugging_opts.time_passes
|
||||
}
|
||||
pub fn profile_queries(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use crate::session::{CrateDisambiguator, Session};
|
|||
use crate::ty;
|
||||
use crate::ty::codec::{self as ty_codec, TyDecoder, TyEncoder};
|
||||
use crate::ty::context::TyCtxt;
|
||||
use crate::util::common::time;
|
||||
use crate::util::common::{time, time_ext};
|
||||
|
||||
use errors::Diagnostic;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
|
@ -1080,23 +1080,22 @@ fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
let desc = &format!("encode_query_results for {}",
|
||||
unsafe { ::std::intrinsics::type_name::<Q>() });
|
||||
|
||||
time(tcx.sess, desc, || {
|
||||
time_ext(tcx.sess.time_extended(), Some(tcx.sess), desc, || {
|
||||
let map = Q::query_cache(tcx).borrow();
|
||||
assert!(map.active.is_empty());
|
||||
for (key, entry) in map.results.iter() {
|
||||
if Q::cache_on_disk(tcx, key.clone()) {
|
||||
let dep_node = SerializedDepNodeIndex::new(entry.index.index());
|
||||
|
||||
let map = Q::query_cache(tcx).borrow();
|
||||
assert!(map.active.is_empty());
|
||||
for (key, entry) in map.results.iter() {
|
||||
if Q::cache_on_disk(tcx, key.clone()) {
|
||||
let dep_node = SerializedDepNodeIndex::new(entry.index.index());
|
||||
// Record position of the cache entry
|
||||
query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position())));
|
||||
|
||||
// Record position of the cache entry
|
||||
query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position())));
|
||||
|
||||
// Encode the type check tables with the SerializedDepNodeIndex
|
||||
// as tag.
|
||||
encoder.encode_tagged(dep_node, &entry.value)?;
|
||||
// Encode the type check tables with the SerializedDepNodeIndex
|
||||
// as tag.
|
||||
encoder.encode_tagged(dep_node, &entry.value)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use rustc::session::Session;
|
|||
use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind};
|
||||
use rustc::middle::dependency_format::Linkage;
|
||||
use rustc_codegen_ssa::CodegenResults;
|
||||
use rustc::util::common::time;
|
||||
use rustc::util::common::{time, time_ext};
|
||||
use rustc_fs_util::fix_windows_verbatim_for_gcc;
|
||||
use rustc::hir::def_id::CrateNum;
|
||||
use tempfile::{Builder as TempFileBuilder, TempDir};
|
||||
|
|
@ -1319,7 +1319,7 @@ fn add_upstream_rust_crates(cmd: &mut dyn Linker,
|
|||
let name = cratepath.file_name().unwrap().to_str().unwrap();
|
||||
let name = &name[3..name.len() - 5]; // chop off lib/.rlib
|
||||
|
||||
time(sess, &format!("altering {}.rlib", name), || {
|
||||
time_ext(sess.time_extended(), Some(sess), &format!("altering {}.rlib", name), || {
|
||||
let cfg = archive_config(sess, &dst, Some(cratepath));
|
||||
let mut archive = ArchiveBuilder::new(cfg);
|
||||
archive.update_symbols();
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ impl ModuleConfig {
|
|||
self.verify_llvm_ir = sess.verify_llvm_ir();
|
||||
self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes;
|
||||
self.no_builtins = no_builtins || sess.target.target.options.no_builtins;
|
||||
self.time_passes = sess.time_passes();
|
||||
self.time_passes = sess.time_extended();
|
||||
self.inline_threshold = sess.opts.cg.inline_threshold;
|
||||
self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode ||
|
||||
sess.opts.cg.linker_plugin_lto.enabled();
|
||||
|
|
@ -1091,7 +1091,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
fewer_names: sess.fewer_names(),
|
||||
save_temps: sess.opts.cg.save_temps,
|
||||
opts: Arc::new(sess.opts.clone()),
|
||||
time_passes: sess.time_passes(),
|
||||
time_passes: sess.time_extended(),
|
||||
profiler: sess.self_profiling.clone(),
|
||||
exported_symbols,
|
||||
plugin_passes: sess.plugin_llvm_passes.borrow().clone(),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use rustc::middle::lang_items;
|
|||
use rustc::ty::{self, Ty, TypeFoldable};
|
||||
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
|
||||
use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
|
||||
use rustc::mir::interpret::EvalErrorKind;
|
||||
use rustc::mir::interpret::InterpError;
|
||||
use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_mir::monomorphize;
|
||||
|
|
@ -365,7 +365,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// checked operation, just a comparison with the minimum
|
||||
// value, so we have to check for the assert message.
|
||||
if !bx.check_overflow() {
|
||||
if let mir::interpret::EvalErrorKind::OverflowNeg = *msg {
|
||||
if let mir::interpret::InterpError::OverflowNeg = *msg {
|
||||
const_cond = Some(expected);
|
||||
}
|
||||
}
|
||||
|
|
@ -400,7 +400,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
|
||||
// Put together the arguments to the panic entry point.
|
||||
let (lang_item, args) = match *msg {
|
||||
EvalErrorKind::BoundsCheck { ref len, ref index } => {
|
||||
InterpError::BoundsCheck { ref len, ref index } => {
|
||||
let len = self.codegen_operand(&mut bx, len).immediate();
|
||||
let index = self.codegen_operand(&mut bx, index).immediate();
|
||||
|
||||
|
|
|
|||
|
|
@ -511,14 +511,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
)
|
||||
}
|
||||
|
||||
(BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
|
||||
| (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) => {
|
||||
// Shallow borrows are uses from the user's point of view.
|
||||
self.report_use_while_mutably_borrowed(context, (place, span), issued_borrow);
|
||||
return;
|
||||
}
|
||||
(BorrowKind::Shared, _, _, BorrowKind::Shared, _, _)
|
||||
| (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _)
|
||||
| (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _)
|
||||
| (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
|
||||
| (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _)
|
||||
| (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -688,7 +688,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||
cleanup: _,
|
||||
} => {
|
||||
self.consume_operand(ContextKind::Assert.new(loc), (cond, span), flow_state);
|
||||
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
|
||||
use rustc::mir::interpret::InterpError::BoundsCheck;
|
||||
if let BoundsCheck { ref len, ref index } = *msg {
|
||||
self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state);
|
||||
self.consume_operand(ContextKind::Assert.new(loc), (index, span), flow_state);
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||
cleanup: _,
|
||||
} => {
|
||||
self.consume_operand(ContextKind::Assert.new(location), cond);
|
||||
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
|
||||
use rustc::mir::interpret::InterpError::BoundsCheck;
|
||||
if let BoundsCheck { ref len, ref index } = *msg {
|
||||
self.consume_operand(ContextKind::Assert.new(location), len);
|
||||
self.consume_operand(ContextKind::Assert.new(location), index);
|
||||
|
|
|
|||
|
|
@ -132,6 +132,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
});
|
||||
if let Some(i) = best_choice {
|
||||
if let Some(next) = categorized_path.get(i + 1) {
|
||||
if categorized_path[i].0 == ConstraintCategory::Return
|
||||
&& next.0 == ConstraintCategory::OpaqueType
|
||||
{
|
||||
// The return expression is being influenced by the return type being
|
||||
// impl Trait, point at the return type and not the return expr.
|
||||
return *next;
|
||||
}
|
||||
}
|
||||
return categorized_path[i];
|
||||
}
|
||||
|
||||
|
|
@ -240,6 +249,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
self.provides_universal_region(r, fr, outlived_fr)
|
||||
});
|
||||
|
||||
debug!("report_error: category={:?} {:?}", category, span);
|
||||
// Check if we can use one of the "nice region errors".
|
||||
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
|
||||
let tables = infcx.tcx.typeck_tables_of(mir_def_id);
|
||||
|
|
|
|||
|
|
@ -403,8 +403,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
mir_def_id: DefId,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) -> Option<ClosureRegionRequirements<'gcx>> {
|
||||
common::time(
|
||||
infcx.tcx.sess,
|
||||
common::time_ext(
|
||||
infcx.tcx.sess.time_extended(),
|
||||
Some(infcx.tcx.sess),
|
||||
&format!("solve_nll_region_constraints({:?})", mir_def_id),
|
||||
|| self.solve_inner(infcx, mir, mir_def_id, errors_buffer),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use rustc::infer::canonical::QueryRegionConstraint;
|
|||
use rustc::infer::outlives::env::RegionBoundPairs;
|
||||
use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin};
|
||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use rustc::mir::interpret::{EvalErrorKind::BoundsCheck, ConstValue};
|
||||
use rustc::mir::interpret::{InterpError::BoundsCheck, ConstValue};
|
||||
use rustc::mir::tcx::PlaceTy;
|
||||
use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
|
||||
use rustc::mir::*;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::build::expr::category::Category;
|
|||
use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
|
||||
use crate::build::{BlockAnd, BlockAndExtension, Builder};
|
||||
use crate::hair::*;
|
||||
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
|
||||
use rustc::mir::interpret::InterpError::BoundsCheck;
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{CanonicalUserTypeAnnotation, Variance};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::build::expr::category::{Category, RvalueFunc};
|
|||
use crate::build::{BlockAnd, BlockAndExtension, Builder};
|
||||
use crate::hair::*;
|
||||
use rustc::middle::region;
|
||||
use rustc::mir::interpret::EvalErrorKind;
|
||||
use rustc::mir::interpret::InterpError;
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, UpvarSubsts};
|
||||
use syntax_pos::Span;
|
||||
|
|
@ -101,7 +101,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
block,
|
||||
Operand::Move(is_min),
|
||||
false,
|
||||
EvalErrorKind::OverflowNeg,
|
||||
InterpError::OverflowNeg,
|
||||
expr_span,
|
||||
);
|
||||
}
|
||||
|
|
@ -433,7 +433,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let val = result_value.clone().field(val_fld, ty);
|
||||
let of = result_value.field(of_fld, bool_ty);
|
||||
|
||||
let err = EvalErrorKind::Overflow(op);
|
||||
let err = InterpError::Overflow(op);
|
||||
|
||||
block = self.assert(block, Operand::Move(of), false, err, span);
|
||||
|
||||
|
|
@ -444,9 +444,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
// and 2. there are two possible failure cases, divide-by-zero and overflow.
|
||||
|
||||
let (zero_err, overflow_err) = if op == BinOp::Div {
|
||||
(EvalErrorKind::DivisionByZero, EvalErrorKind::Overflow(op))
|
||||
(InterpError::DivisionByZero, InterpError::Overflow(op))
|
||||
} else {
|
||||
(EvalErrorKind::RemainderByZero, EvalErrorKind::Overflow(op))
|
||||
(InterpError::RemainderByZero, InterpError::Overflow(op))
|
||||
};
|
||||
|
||||
// Check for / 0
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use syntax::source_map::{Span, DUMMY_SP};
|
|||
use crate::interpret::{self,
|
||||
PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Immediate, Scalar, Pointer,
|
||||
RawConst, ConstValue,
|
||||
EvalResult, EvalError, EvalErrorKind, GlobalId, InterpretCx, StackPopCleanup,
|
||||
EvalResult, EvalError, InterpError, GlobalId, InterpretCx, StackPopCleanup,
|
||||
Allocation, AllocId, MemoryKind,
|
||||
snapshot, RefTracking,
|
||||
};
|
||||
|
|
@ -173,7 +173,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
|
|||
|
||||
impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
|
||||
fn into(self) -> EvalError<'tcx> {
|
||||
EvalErrorKind::MachineError(self.to_string()).into()
|
||||
InterpError::MachineError(self.to_string()).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -351,7 +351,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
|
|||
Ok(Some(match ecx.load_mir(instance.def) {
|
||||
Ok(mir) => mir,
|
||||
Err(err) => {
|
||||
if let EvalErrorKind::NoMirFor(ref path) = err.kind {
|
||||
if let InterpError::NoMirFor(ref path) = err.kind {
|
||||
return Err(
|
||||
ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
|
||||
.into(),
|
||||
|
|
@ -679,7 +679,7 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
|
|||
// any other kind of error will be reported to the user as a deny-by-default lint
|
||||
_ => if let Some(p) = cid.promoted {
|
||||
let span = tcx.optimized_mir(def_id).promoted[p].span;
|
||||
if let EvalErrorKind::ReferencedConstant = err.error {
|
||||
if let InterpError::ReferencedConstant = err.error {
|
||||
err.report_as_error(
|
||||
tcx.at(span),
|
||||
"evaluation of constant expression failed",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use syntax::ast::{FloatTy, IntTy, UintTy};
|
|||
|
||||
use rustc_apfloat::ieee::{Single, Double};
|
||||
use rustc::mir::interpret::{
|
||||
Scalar, EvalResult, Pointer, PointerArithmetic, EvalErrorKind, truncate
|
||||
Scalar, EvalResult, Pointer, PointerArithmetic, InterpError, truncate
|
||||
};
|
||||
use rustc::mir::CastKind;
|
||||
use rustc_apfloat::Float;
|
||||
|
|
@ -85,7 +85,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
|||
self.param_env,
|
||||
def_id,
|
||||
substs,
|
||||
).ok_or_else(|| EvalErrorKind::TooGeneric.into());
|
||||
).ok_or_else(|| InterpError::TooGeneric.into());
|
||||
let fn_ptr = self.memory.create_fn_alloc(instance?).with_default_tag();
|
||||
self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use rustc_data_structures::indexed_vec::IndexVec;
|
|||
use rustc::mir::interpret::{
|
||||
ErrorHandled,
|
||||
GlobalId, Scalar, FrameInfo, AllocId,
|
||||
EvalResult, EvalErrorKind,
|
||||
EvalResult, InterpError,
|
||||
truncate, sign_extend,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
|
@ -167,7 +167,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> LayoutOf
|
|||
#[inline]
|
||||
fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
|
||||
self.tcx.layout_of(self.param_env.and(ty))
|
||||
.map_err(|layout| EvalErrorKind::Layout(layout).into())
|
||||
.map_err(|layout| InterpError::Layout(layout).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
|
|||
self.param_env,
|
||||
def_id,
|
||||
substs,
|
||||
).ok_or_else(|| EvalErrorKind::TooGeneric.into())
|
||||
).ok_or_else(|| InterpError::TooGeneric.into())
|
||||
}
|
||||
|
||||
pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
|
||||
|
|
@ -647,8 +647,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
|
|||
// `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
|
||||
let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| {
|
||||
match err {
|
||||
ErrorHandled::Reported => EvalErrorKind::ReferencedConstant,
|
||||
ErrorHandled::TooGeneric => EvalErrorKind::TooGeneric,
|
||||
ErrorHandled::Reported => InterpError::ReferencedConstant,
|
||||
ErrorHandled::TooGeneric => InterpError::TooGeneric,
|
||||
}
|
||||
})?;
|
||||
self.raw_const_to_mplace(val)
|
||||
|
|
@ -670,7 +670,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
|
|||
|
||||
match self.stack[frame].locals[local].access() {
|
||||
Err(err) => {
|
||||
if let EvalErrorKind::DeadLocal = err.kind {
|
||||
if let InterpError::DeadLocal = err.kind {
|
||||
write!(msg, " is dead").unwrap();
|
||||
} else {
|
||||
panic!("Failed to access local: {:?}", err);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc::ty;
|
|||
use rustc::ty::layout::{LayoutOf, Primitive, Size};
|
||||
use rustc::mir::BinOp;
|
||||
use rustc::mir::interpret::{
|
||||
EvalResult, EvalErrorKind, Scalar,
|
||||
EvalResult, InterpError, Scalar,
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
|
@ -87,7 +87,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
|||
let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?;
|
||||
let kind = match layout_of.abi {
|
||||
ty::layout::Abi::Scalar(ref scalar) => scalar.value,
|
||||
_ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?,
|
||||
_ => Err(::rustc::mir::interpret::InterpError::TypeNotPrimitive(ty))?,
|
||||
};
|
||||
let out_val = if intrinsic_name.ends_with("_nonzero") {
|
||||
if bits == 0 {
|
||||
|
|
@ -248,7 +248,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
|||
let file = Symbol::intern(self.read_str(file_place)?);
|
||||
let line = self.read_scalar(line.into())?.to_u32()?;
|
||||
let col = self.read_scalar(col.into())?.to_u32()?;
|
||||
return Err(EvalErrorKind::Panic { msg, file, line, col }.into());
|
||||
return Err(InterpError::Panic { msg, file, line, col }.into());
|
||||
} else if Some(def_id) == self.tcx.lang_items().begin_panic_fn() {
|
||||
assert!(args.len() == 2);
|
||||
// &'static str, &(&'static str, u32, u32)
|
||||
|
|
@ -266,7 +266,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
|||
let file = Symbol::intern(self.read_str(file_place)?);
|
||||
let line = self.read_scalar(line.into())?.to_u32()?;
|
||||
let col = self.read_scalar(col.into())?.to_u32()?;
|
||||
return Err(EvalErrorKind::Panic { msg, file, line, col }.into());
|
||||
return Err(InterpError::Panic { msg, file, line, col }.into());
|
||||
} else {
|
||||
return Ok(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use syntax::ast::Mutability;
|
|||
|
||||
use super::{
|
||||
Pointer, AllocId, Allocation, GlobalId, AllocationExtra,
|
||||
EvalResult, Scalar, EvalErrorKind, AllocKind, PointerArithmetic,
|
||||
EvalResult, Scalar, InterpError, AllocKind, PointerArithmetic,
|
||||
Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg,
|
||||
};
|
||||
|
||||
|
|
@ -344,8 +344,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
// no need to report anything, the const_eval call takes care of that for statics
|
||||
assert!(tcx.is_static(def_id).is_some());
|
||||
match err {
|
||||
ErrorHandled::Reported => EvalErrorKind::ReferencedConstant.into(),
|
||||
ErrorHandled::TooGeneric => EvalErrorKind::TooGeneric.into(),
|
||||
ErrorHandled::Reported => InterpError::ReferencedConstant.into(),
|
||||
ErrorHandled::TooGeneric => InterpError::TooGeneric.into(),
|
||||
}
|
||||
}).map(|raw_const| {
|
||||
let allocation = tcx.alloc_map.lock().unwrap_memory(raw_const.alloc_id);
|
||||
|
|
@ -458,7 +458,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
trace!("reading fn ptr: {}", ptr.alloc_id);
|
||||
match self.tcx.alloc_map.lock().get(ptr.alloc_id) {
|
||||
Some(AllocKind::Function(instance)) => Ok(instance),
|
||||
_ => Err(EvalErrorKind::ExecuteMemory.into()),
|
||||
_ => Err(InterpError::ExecuteMemory.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerEx
|
|||
use rustc::mir::interpret::{
|
||||
GlobalId, AllocId, CheckInAllocMsg,
|
||||
ConstValue, Pointer, Scalar,
|
||||
EvalResult, EvalErrorKind,
|
||||
EvalResult, InterpError,
|
||||
sign_extend, truncate,
|
||||
};
|
||||
use super::{
|
||||
|
|
@ -369,7 +369,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
|||
let len = mplace.len(self)?;
|
||||
let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len as u64))?;
|
||||
let str = ::std::str::from_utf8(bytes)
|
||||
.map_err(|err| EvalErrorKind::ValidationFailure(err.to_string()))?;
|
||||
.map_err(|err| InterpError::ValidationFailure(err.to_string()))?;
|
||||
Ok(str)
|
||||
}
|
||||
|
||||
|
|
@ -653,7 +653,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
|||
.expect("tagged layout for non adt")
|
||||
.discriminants(self.tcx.tcx)
|
||||
.find(|(_, var)| var.val == real_discr)
|
||||
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant(raw_discr.erase_tag()))?;
|
||||
.ok_or_else(|| InterpError::InvalidDiscriminant(raw_discr.erase_tag()))?;
|
||||
(real_discr, index.0)
|
||||
},
|
||||
layout::DiscriminantKind::Niche {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc::mir;
|
|||
use rustc::mir::interpret::{
|
||||
AllocId, Pointer, Scalar,
|
||||
Relocations, Allocation, UndefMask,
|
||||
EvalResult, EvalErrorKind,
|
||||
EvalResult, InterpError,
|
||||
};
|
||||
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
|
|
@ -78,7 +78,7 @@ impl<'a, 'mir, 'tcx> InfiniteLoopDetector<'a, 'mir, 'tcx>
|
|||
}
|
||||
|
||||
// Second cycle
|
||||
Err(EvalErrorKind::InfiniteLoop.into())
|
||||
Err(InterpError::InfiniteLoop.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -431,7 +431,7 @@ impl<'a, 'mir, 'tcx> Eq for EvalSnapshot<'a, 'mir, 'tcx>
|
|||
impl<'a, 'mir, 'tcx> PartialEq for EvalSnapshot<'a, 'mir, 'tcx>
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
// FIXME: This looks to be a *ridicolously expensive* comparison operation.
|
||||
// FIXME: This looks to be a *ridiculously expensive* comparison operation.
|
||||
// Doesn't this make tons of copies? Either `snapshot` is very badly named,
|
||||
// or it does!
|
||||
self.snapshot() == other.snapshot()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc::ty::layout::{self, TyLayout, LayoutOf};
|
|||
use syntax::source_map::Span;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar};
|
||||
use rustc::mir::interpret::{EvalResult, PointerArithmetic, InterpError, Scalar};
|
||||
use super::{
|
||||
InterpretCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup
|
||||
};
|
||||
|
|
@ -134,7 +134,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
|||
self.goto_block(Some(target))?;
|
||||
} else {
|
||||
// Compute error message
|
||||
use rustc::mir::interpret::EvalErrorKind::*;
|
||||
use rustc::mir::interpret::InterpError::*;
|
||||
return match *msg {
|
||||
BoundsCheck { ref len, ref index } => {
|
||||
let len = self.read_immediate(self.eval_operand(len, None)?)
|
||||
|
|
@ -212,7 +212,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
|||
return Ok(());
|
||||
}
|
||||
let caller_arg = caller_arg.next()
|
||||
.ok_or_else(|| EvalErrorKind::FunctionArgCountMismatch)?;
|
||||
.ok_or_else(|| InterpError::FunctionArgCountMismatch)?;
|
||||
if rust_abi {
|
||||
debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf, VariantIdx};
|
|||
use rustc::ty;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc::mir::interpret::{
|
||||
Scalar, AllocKind, EvalResult, EvalErrorKind, CheckInAllocMsg,
|
||||
Scalar, AllocKind, EvalResult, InterpError, CheckInAllocMsg,
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
|
@ -258,11 +258,11 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
|
|||
match self.walk_value(op) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(err) => match err.kind {
|
||||
EvalErrorKind::InvalidDiscriminant(val) =>
|
||||
InterpError::InvalidDiscriminant(val) =>
|
||||
validation_failure!(
|
||||
val, self.path, "a valid enum discriminant"
|
||||
),
|
||||
EvalErrorKind::ReadPointerAsBytes =>
|
||||
InterpError::ReadPointerAsBytes =>
|
||||
validation_failure!(
|
||||
"a pointer", self.path, "plain (non-pointer) bytes"
|
||||
),
|
||||
|
|
@ -355,9 +355,9 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
|
|||
Err(err) => {
|
||||
error!("{:?} is not aligned to {:?}", ptr, align);
|
||||
match err.kind {
|
||||
EvalErrorKind::InvalidNullPointerUsage =>
|
||||
InterpError::InvalidNullPointerUsage =>
|
||||
return validation_failure!("NULL reference", self.path),
|
||||
EvalErrorKind::AlignmentCheckFailed { required, has } =>
|
||||
InterpError::AlignmentCheckFailed { required, has } =>
|
||||
return validation_failure!(format!("unaligned reference \
|
||||
(required {} byte alignment but found {})",
|
||||
required.bytes(), has.bytes()), self.path),
|
||||
|
|
@ -562,7 +562,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
|
|||
Err(err) => {
|
||||
// For some errors we might be able to provide extra information
|
||||
match err.kind {
|
||||
EvalErrorKind::ReadUndefBytes(offset) => {
|
||||
InterpError::ReadUndefBytes(offset) => {
|
||||
// Some byte was undefined, determine which
|
||||
// element that byte belongs to so we can
|
||||
// provide an index.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc::mir::{Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Loc
|
|||
use rustc::mir::{NullOp, UnOp, StatementKind, Statement, BasicBlock, LocalKind, Static, StaticKind};
|
||||
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
|
||||
use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
|
||||
use rustc::mir::interpret::{EvalErrorKind, Scalar, GlobalId, EvalResult};
|
||||
use rustc::mir::interpret::{InterpError, Scalar, GlobalId, EvalResult};
|
||||
use rustc::ty::{TyCtxt, self, Instance};
|
||||
use syntax::source_map::{Span, DUMMY_SP};
|
||||
use rustc::ty::subst::InternalSubsts;
|
||||
|
|
@ -144,7 +144,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
|
|||
Ok(val) => Some(val),
|
||||
Err(error) => {
|
||||
let diagnostic = error_to_const_error(&self.ecx, error);
|
||||
use rustc::mir::interpret::EvalErrorKind::*;
|
||||
use rustc::mir::interpret::InterpError::*;
|
||||
match diagnostic.error {
|
||||
// don't report these, they make no sense in a const prop context
|
||||
| MachineError(_)
|
||||
|
|
@ -457,7 +457,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
|
|||
)
|
||||
} else {
|
||||
if overflow {
|
||||
let err = EvalErrorKind::Overflow(op).into();
|
||||
let err = InterpError::Overflow(op).into();
|
||||
let _: Option<()> = self.use_ecx(source_info, |_| Err(err));
|
||||
return None;
|
||||
}
|
||||
|
|
@ -611,7 +611,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
|
|||
.hir()
|
||||
.as_local_hir_id(self.source.def_id())
|
||||
.expect("some part of a failing const eval must be local");
|
||||
use rustc::mir::interpret::EvalErrorKind::*;
|
||||
use rustc::mir::interpret::InterpError::*;
|
||||
let msg = match msg {
|
||||
Overflow(_) |
|
||||
OverflowNeg |
|
||||
|
|
|
|||
|
|
@ -773,7 +773,7 @@ fn create_generator_resume_function<'a, 'tcx>(
|
|||
|
||||
let mut cases = create_cases(mir, &transform, |point| Some(point.resume));
|
||||
|
||||
use rustc::mir::interpret::EvalErrorKind::{
|
||||
use rustc::mir::interpret::InterpError::{
|
||||
GeneratorResumedAfterPanic,
|
||||
GeneratorResumedAfterReturn,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -728,7 +728,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
|||
interior mutability, create a static instead");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if let BorrowKind::Mut { .. } | BorrowKind::Shared = kind {
|
||||
// Don't promote BorrowKind::Shallow borrows, as they don't
|
||||
// reach codegen.
|
||||
|
||||
// We might have a candidate for promotion.
|
||||
let candidate = Candidate::Ref(location);
|
||||
// We can only promote interior borrows of promotable temps.
|
||||
|
|
|
|||
|
|
@ -1979,6 +1979,7 @@ fn explicit_predicates_of<'a, 'tcx>(
|
|||
ref bounds,
|
||||
impl_trait_fn,
|
||||
ref generics,
|
||||
origin: _,
|
||||
}) => {
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
let opaque_ty = tcx.mk_opaque(def_id, substs);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@ path = "lib.rs"
|
|||
|
||||
[dependencies]
|
||||
pulldown-cmark = { version = "0.1.2", default-features = false }
|
||||
minifier = "0.0.28"
|
||||
minifier = "0.0.29"
|
||||
tempfile = "3"
|
||||
parking_lot = "0.7"
|
||||
|
|
|
|||
|
|
@ -965,7 +965,11 @@ themePicker.onblur = handleThemeButtonsBlur;
|
|||
if for_search_index && line.starts_with("var R") {
|
||||
variables.push(line.clone());
|
||||
// We need to check if the crate name has been put into a variable as well.
|
||||
let tokens = js::simple_minify(&line).apply(js::clean_tokens);
|
||||
let tokens: js::Tokens<'_> = js::simple_minify(&line)
|
||||
.into_iter()
|
||||
.filter(js::clean_token)
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
let mut pos = 0;
|
||||
while pos < tokens.len() {
|
||||
if let Some((var_pos, Some(value_pos))) =
|
||||
|
|
@ -1288,46 +1292,51 @@ fn write_minify_replacer<W: Write>(
|
|||
contents: &str,
|
||||
enable_minification: bool,
|
||||
) -> io::Result<()> {
|
||||
use minifier::js::{Keyword, ReservedChar, Token};
|
||||
use minifier::js::{simple_minify, Keyword, ReservedChar, Token, Tokens};
|
||||
|
||||
if enable_minification {
|
||||
writeln!(dst, "{}",
|
||||
minifier::js::simple_minify(contents)
|
||||
.apply(|f| {
|
||||
// We keep backlines.
|
||||
minifier::js::clean_tokens_except(f, |c| {
|
||||
c.get_char() != Some(ReservedChar::Backline)
|
||||
})
|
||||
})
|
||||
.apply(|f| {
|
||||
minifier::js::replace_token_with(f, |t| {
|
||||
match *t {
|
||||
Token::Keyword(Keyword::Null) => Some(Token::Other("N")),
|
||||
Token::String(s) => {
|
||||
let s = &s[1..s.len() -1]; // The quotes are included
|
||||
if s.is_empty() {
|
||||
Some(Token::Other("E"))
|
||||
} else if s == "t" {
|
||||
Some(Token::Other("T"))
|
||||
} else if s == "u" {
|
||||
Some(Token::Other("U"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
})
|
||||
.apply(|f| {
|
||||
// We add a backline after the newly created variables.
|
||||
minifier::js::aggregate_strings_into_array_with_separation(
|
||||
f,
|
||||
"R",
|
||||
Token::Char(ReservedChar::Backline),
|
||||
)
|
||||
})
|
||||
.to_string())
|
||||
{
|
||||
let tokens: Tokens<'_> = simple_minify(contents)
|
||||
.into_iter()
|
||||
.filter(|f| {
|
||||
// We keep backlines.
|
||||
minifier::js::clean_token_except(f, &|c: &Token<'_>| {
|
||||
c.get_char() != Some(ReservedChar::Backline)
|
||||
})
|
||||
})
|
||||
.map(|f| {
|
||||
minifier::js::replace_token_with(f, &|t: &Token<'_>| {
|
||||
match *t {
|
||||
Token::Keyword(Keyword::Null) => Some(Token::Other("N")),
|
||||
Token::String(s) => {
|
||||
let s = &s[1..s.len() -1]; // The quotes are included
|
||||
if s.is_empty() {
|
||||
Some(Token::Other("E"))
|
||||
} else if s == "t" {
|
||||
Some(Token::Other("T"))
|
||||
} else if s == "u" {
|
||||
Some(Token::Other("U"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
tokens.apply(|f| {
|
||||
// We add a backline after the newly created variables.
|
||||
minifier::js::aggregate_strings_into_array_with_separation(
|
||||
f,
|
||||
"R",
|
||||
Token::Char(ReservedChar::Backline),
|
||||
)
|
||||
})
|
||||
.to_string()
|
||||
})
|
||||
} else {
|
||||
writeln!(dst, "{}", contents)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,9 +69,9 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64
|
|||
}
|
||||
|
||||
// check entry is being called according to ABI
|
||||
assert_eq!(p3, 0);
|
||||
assert_eq!(p4, 0);
|
||||
assert_eq!(p5, 0);
|
||||
rtassert!(p3 == 0);
|
||||
rtassert!(p4 == 0);
|
||||
rtassert!(p5 == 0);
|
||||
|
||||
unsafe {
|
||||
// The actual types of these arguments are `p1: *const Arg, p2:
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ pub fn relocate_elf_rela() {
|
|||
};
|
||||
for rela in relas {
|
||||
if rela.info != (/*0 << 32 |*/ R_X86_64_RELATIVE as u64) {
|
||||
panic!("Invalid relocation");
|
||||
rtabort!("Invalid relocation");
|
||||
}
|
||||
unsafe { *mem::rel_ptr_mut::<*const ()>(rela.offset) = mem::rel_ptr(rela.addend) };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,20 +100,24 @@ impl Tls {
|
|||
}
|
||||
|
||||
pub fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
|
||||
let index = TLS_KEY_IN_USE.set().expect("TLS limit exceeded");
|
||||
let index = if let Some(index) = TLS_KEY_IN_USE.set() {
|
||||
index
|
||||
} else {
|
||||
rtabort!("TLS limit exceeded")
|
||||
};
|
||||
TLS_DESTRUCTOR[index].store(dtor.map_or(0, |f| f as usize), Ordering::Relaxed);
|
||||
Key::from_index(index)
|
||||
}
|
||||
|
||||
pub fn set(key: Key, value: *mut u8) {
|
||||
let index = key.to_index();
|
||||
assert!(TLS_KEY_IN_USE.get(index));
|
||||
rtassert!(TLS_KEY_IN_USE.get(index));
|
||||
unsafe { Self::current() }.data[index].set(value);
|
||||
}
|
||||
|
||||
pub fn get(key: Key) -> *mut u8 {
|
||||
let index = key.to_index();
|
||||
assert!(TLS_KEY_IN_USE.get(index));
|
||||
rtassert!(TLS_KEY_IN_USE.get(index));
|
||||
unsafe { Self::current() }.data[index].get()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -190,11 +190,15 @@ impl<T: ?Sized> User<T> where T: UserSafe {
|
|||
unsafe {
|
||||
// Mustn't call alloc with size 0.
|
||||
let ptr = if size > 0 {
|
||||
super::alloc(size, T::align_of()).expect("User memory allocation failed") as _
|
||||
rtunwrap!(Ok, super::alloc(size, T::align_of())) as _
|
||||
} else {
|
||||
T::align_of() as _ // dangling pointer ok for size 0
|
||||
};
|
||||
User(NonNull::new_userref(T::from_raw_sized(ptr, size)))
|
||||
if let Ok(v) = crate::panic::catch_unwind(|| T::from_raw_sized(ptr, size)) {
|
||||
User(NonNull::new_userref(v))
|
||||
} else {
|
||||
rtabort!("Got invalid pointer from alloc() usercall")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ pub fn close(fd: Fd) {
|
|||
|
||||
fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
|
||||
String::from_utf8(buf.copy_user_buffer())
|
||||
.unwrap_or_else(|_| panic!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
|
||||
.unwrap_or_else(|_| rtabort!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
|
||||
}
|
||||
|
||||
/// Usercall `bind_stream`. See the ABI documentation for more information.
|
||||
|
|
@ -176,7 +176,7 @@ fn check_os_error(err: Result) -> i32 {
|
|||
{
|
||||
err
|
||||
} else {
|
||||
panic!("Usercall: returned invalid error value {}", err)
|
||||
rtabort!("Usercall: returned invalid error value {}", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -131,22 +131,22 @@ impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> {
|
|||
|
||||
impl ReturnValue for ! {
|
||||
fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self {
|
||||
panic!("Usercall {}: did not expect to be re-entered", call);
|
||||
rtabort!("Usercall {}: did not expect to be re-entered", call);
|
||||
}
|
||||
}
|
||||
|
||||
impl ReturnValue for () {
|
||||
fn from_registers(call: &'static str, regs: (Register, Register)) -> Self {
|
||||
assert_eq!(regs.0, 0, "Usercall {}: expected {} return value to be 0", call, "1st");
|
||||
assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd");
|
||||
fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
|
||||
rtassert!(usercall_retval.0 == 0);
|
||||
rtassert!(usercall_retval.1 == 0);
|
||||
()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RegisterArgument> ReturnValue for T {
|
||||
fn from_registers(call: &'static str, regs: (Register, Register)) -> Self {
|
||||
assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd");
|
||||
T::from_register(regs.0)
|
||||
fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
|
||||
rtassert!(usercall_retval.1 == 0);
|
||||
T::from_register(usercall_retval.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -174,8 +174,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
|
|||
#[inline(always)]
|
||||
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
|
||||
ReturnValue::from_registers(stringify!($f), do_usercall(
|
||||
NonZeroU64::new(Usercalls::$f as Register)
|
||||
.expect("Usercall number must be non-zero"),
|
||||
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
|
||||
RegisterArgument::into_register($n1),
|
||||
RegisterArgument::into_register($n2),
|
||||
RegisterArgument::into_register($n3),
|
||||
|
|
@ -191,8 +190,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
|
|||
#[inline(always)]
|
||||
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
|
||||
ReturnValue::from_registers(stringify!($f), do_usercall(
|
||||
NonZeroU64::new(Usercalls::$f as Register)
|
||||
.expect("Usercall number must be non-zero"),
|
||||
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
|
||||
RegisterArgument::into_register($n1),
|
||||
RegisterArgument::into_register($n2),
|
||||
RegisterArgument::into_register($n3),
|
||||
|
|
@ -208,8 +206,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
|
|||
#[inline(always)]
|
||||
pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
|
||||
ReturnValue::from_registers(stringify!($f), do_usercall(
|
||||
NonZeroU64::new(Usercalls::$f as Register)
|
||||
.expect("Usercall number must be non-zero"),
|
||||
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
|
||||
RegisterArgument::into_register($n1),
|
||||
RegisterArgument::into_register($n2),
|
||||
0,0,
|
||||
|
|
@ -224,8 +221,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
|
|||
#[inline(always)]
|
||||
pub unsafe fn $f($n1: $t1) -> $r {
|
||||
ReturnValue::from_registers(stringify!($f), do_usercall(
|
||||
NonZeroU64::new(Usercalls::$f as Register)
|
||||
.expect("Usercall number must be non-zero"),
|
||||
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
|
||||
RegisterArgument::into_register($n1),
|
||||
0,0,0,
|
||||
return_type_is_abort!($r)
|
||||
|
|
@ -239,8 +235,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
|
|||
#[inline(always)]
|
||||
pub unsafe fn $f() -> $r {
|
||||
ReturnValue::from_registers(stringify!($f), do_usercall(
|
||||
NonZeroU64::new(Usercalls::$f as Register)
|
||||
.expect("Usercall number must be non-zero"),
|
||||
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
|
||||
0,0,0,0,
|
||||
return_type_is_abort!($r)
|
||||
))
|
||||
|
|
|
|||
|
|
@ -32,9 +32,8 @@ impl Condvar {
|
|||
mutex.lock()
|
||||
}
|
||||
|
||||
pub unsafe fn wait_timeout(&self, mutex: &Mutex, _dur: Duration) -> bool {
|
||||
mutex.unlock(); // don't hold the lock while panicking
|
||||
panic!("timeout not supported in SGX");
|
||||
pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
|
||||
rtabort!("timeout not supported in SGX");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
|
|||
return ret;
|
||||
}
|
||||
}
|
||||
panic!("Failed to obtain random data");
|
||||
rtabort!("Failed to obtain random data");
|
||||
}
|
||||
}
|
||||
(rdrand64(), rdrand64())
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ impl RWLock {
|
|||
*wguard.lock_var_mut() = true;
|
||||
} else {
|
||||
// No writers were waiting, the lock is released
|
||||
assert!(rguard.queue_empty());
|
||||
rtassert!(rguard.queue_empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,17 +62,15 @@ impl Thread {
|
|||
}
|
||||
|
||||
pub(super) fn entry() {
|
||||
let mut guard = task_queue::lock();
|
||||
let task = guard.pop().expect("Thread started but no tasks pending");
|
||||
drop(guard); // make sure to not hold the task queue lock longer than necessary
|
||||
let mut pending_tasks = task_queue::lock();
|
||||
let task = rtunwrap!(Some, pending_tasks.pop());
|
||||
drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary
|
||||
task.run()
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
assert_eq!(
|
||||
usercalls::wait(0, usercalls::raw::WAIT_NO).unwrap_err().kind(),
|
||||
io::ErrorKind::WouldBlock
|
||||
);
|
||||
let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO));
|
||||
rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock);
|
||||
}
|
||||
|
||||
pub fn set_name(_name: &CStr) {
|
||||
|
|
@ -80,7 +78,7 @@ impl Thread {
|
|||
}
|
||||
|
||||
pub fn sleep(_dur: Duration) {
|
||||
panic!("can't sleep"); // FIXME
|
||||
rtabort!("can't sleep"); // FIXME
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ impl<'a, T> Drop for WaitGuard<'a, T> {
|
|||
NotifiedTcs::Single(tcs) => Some(tcs),
|
||||
NotifiedTcs::All { .. } => None
|
||||
};
|
||||
usercalls::send(EV_UNPARK, target_tcs).unwrap();
|
||||
rtunwrap!(Ok, usercalls::send(EV_UNPARK, target_tcs));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -141,6 +141,7 @@ impl WaitQueue {
|
|||
///
|
||||
/// This function does not return until this thread has been awoken.
|
||||
pub fn wait<T>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>) {
|
||||
// very unsafe: check requirements of UnsafeList::push
|
||||
unsafe {
|
||||
let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry {
|
||||
tcs: thread::current(),
|
||||
|
|
@ -149,10 +150,9 @@ impl WaitQueue {
|
|||
let entry = guard.queue.inner.push(&mut entry);
|
||||
drop(guard);
|
||||
while !entry.lock().wake {
|
||||
assert_eq!(
|
||||
usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap() & EV_UNPARK,
|
||||
EV_UNPARK
|
||||
);
|
||||
// don't panic, this would invalidate `entry` during unwinding
|
||||
let eventset = rtunwrap!(Ok, usercalls::wait(EV_UNPARK, WAIT_INDEFINITE));
|
||||
rtassert!(eventset & EV_UNPARK == EV_UNPARK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -269,7 +269,7 @@ mod unsafe_list {
|
|||
// ,-------> /---------\ next ---,
|
||||
// | |head_tail| |
|
||||
// `--- prev \---------/ <-------`
|
||||
assert_eq!(self.head_tail.as_ref().prev, first);
|
||||
rtassert!(self.head_tail.as_ref().prev == first);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
|
@ -285,7 +285,9 @@ mod unsafe_list {
|
|||
/// # Safety
|
||||
///
|
||||
/// The entry must remain allocated until the entry is removed from the
|
||||
/// list AND the caller who popped is done using the entry.
|
||||
/// list AND the caller who popped is done using the entry. Special
|
||||
/// care must be taken in the caller of `push` to ensure unwinding does
|
||||
/// not destroy the stack frame containing the entry.
|
||||
pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T {
|
||||
self.init();
|
||||
|
||||
|
|
@ -303,6 +305,7 @@ mod unsafe_list {
|
|||
entry.as_mut().prev = prev_tail;
|
||||
entry.as_mut().next = self.head_tail;
|
||||
prev_tail.as_mut().next = entry;
|
||||
// unwrap ok: always `Some` on non-dummy entries
|
||||
(*entry.as_ptr()).value.as_ref().unwrap()
|
||||
}
|
||||
|
||||
|
|
@ -333,6 +336,7 @@ mod unsafe_list {
|
|||
second.as_mut().prev = self.head_tail;
|
||||
first.as_mut().next = NonNull::dangling();
|
||||
first.as_mut().prev = NonNull::dangling();
|
||||
// unwrap ok: always `Some` on non-dummy entries
|
||||
Some((*first.as_ptr()).value.as_ref().unwrap())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,15 @@ macro_rules! rtassert {
|
|||
})
|
||||
}
|
||||
|
||||
#[allow(unused_macros)] // not used on all platforms
|
||||
macro_rules! rtunwrap {
|
||||
($ok:ident, $e:expr) => (if let $ok(v) = $e {
|
||||
v
|
||||
} else {
|
||||
rtabort!(concat!("unwrap failed: ", stringify!($e)));
|
||||
})
|
||||
}
|
||||
|
||||
pub mod alloc;
|
||||
pub mod at_exit_imp;
|
||||
#[cfg(feature = "backtrace")]
|
||||
|
|
|
|||
|
|
@ -6722,6 +6722,22 @@ impl<'a> Parser<'a> {
|
|||
self.expect(&token::OpenDelim(token::Brace))?;
|
||||
let mut trait_items = vec![];
|
||||
while !self.eat(&token::CloseDelim(token::Brace)) {
|
||||
if let token::DocComment(_) = self.token {
|
||||
if self.look_ahead(1,
|
||||
|tok| tok == &token::Token::CloseDelim(token::Brace)) {
|
||||
let mut err = self.diagnostic().struct_span_err_with_code(
|
||||
self.span,
|
||||
"found a documentation comment that doesn't document anything",
|
||||
DiagnosticId::Error("E0584".into()),
|
||||
);
|
||||
err.help("doc comments must come before what they document, maybe a \
|
||||
comment was intended with `//`?",
|
||||
);
|
||||
err.emit();
|
||||
self.bump();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let mut at_end = false;
|
||||
match self.parse_trait_item(&mut at_end) {
|
||||
Ok(item) => trait_items.push(item),
|
||||
|
|
|
|||
|
|
@ -70,8 +70,8 @@ fn main() {
|
|||
// }
|
||||
// bb8: { // binding1 and guard
|
||||
// StorageLive(_6);
|
||||
// _6 = &(((promoted[1]: std::option::Option<i32>) as Some).0: i32);
|
||||
// _4 = &shallow (promoted[0]: std::option::Option<i32>);
|
||||
// _6 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
|
||||
// _4 = &shallow _2;
|
||||
// StorageLive(_7);
|
||||
// _7 = const guard() -> [return: bb9, unwind: bb1];
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -79,6 +79,11 @@ async fn async_fn(x: u8) -> u8 {
|
|||
x
|
||||
}
|
||||
|
||||
async fn generic_async_fn<T>(x: T) -> T {
|
||||
await!(wake_and_yield_once());
|
||||
x
|
||||
}
|
||||
|
||||
async fn async_fn_with_borrow(x: &u8) -> u8 {
|
||||
await!(wake_and_yield_once());
|
||||
*x
|
||||
|
|
@ -96,14 +101,21 @@ fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output
|
|||
}
|
||||
}
|
||||
|
||||
async fn async_fn_with_named_lifetime_multiple_args<'a>(x: &'a u8, _y: &'a u8) -> u8 {
|
||||
/* FIXME(cramertj) support when `existential type T<'a, 'b>:;` works
|
||||
async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 {
|
||||
await!(wake_and_yield_once());
|
||||
*x
|
||||
}
|
||||
*/
|
||||
|
||||
async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 {
|
||||
await!(wake_and_yield_once());
|
||||
*x
|
||||
}
|
||||
|
||||
fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
|
||||
async move {
|
||||
await!(async_fn_with_borrow(&y))
|
||||
await!(async_fn_with_borrow_named_lifetime(&y))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,6 +174,7 @@ fn main() {
|
|||
async_nonmove_block,
|
||||
async_closure,
|
||||
async_fn,
|
||||
generic_async_fn,
|
||||
async_fn_with_internal_borrow,
|
||||
Foo::async_method,
|
||||
|x| {
|
||||
|
|
@ -170,7 +183,6 @@ fn main() {
|
|||
}
|
||||
},
|
||||
}
|
||||
|
||||
test_with_borrow! {
|
||||
async_block_with_borrow_named_lifetime,
|
||||
async_fn_with_borrow,
|
||||
|
|
@ -178,7 +190,7 @@ fn main() {
|
|||
async_fn_with_impl_future_named_lifetime,
|
||||
|x| {
|
||||
async move {
|
||||
await!(async_fn_with_named_lifetime_multiple_args(x, x))
|
||||
await!(async_fn_multiple_args_named_lifetime(x, x))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
use std::ops::Add;
|
||||
|
||||
async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
|
||||
//~^ ERROR multiple different lifetimes used in arguments of `async fn`
|
||||
//~^ ERROR ambiguous lifetime bound in `async fn`
|
||||
|
||||
async fn multiple_hrtb_and_single_named_lifetime_ok<'c>(
|
||||
_: impl for<'a> Add<&'a u8>,
|
||||
|
|
@ -14,7 +14,6 @@ async fn multiple_hrtb_and_single_named_lifetime_ok<'c>(
|
|||
) {}
|
||||
|
||||
async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
|
||||
//~^ ERROR multiple elided lifetimes used
|
||||
//~^^ ERROR missing lifetime specifier
|
||||
//~^ ambiguous lifetime bound in `async fn`
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,20 @@
|
|||
error[E0709]: multiple different lifetimes used in arguments of `async fn`
|
||||
--> $DIR/async-fn-multiple-lifetimes.rs:7:47
|
||||
error: ambiguous lifetime bound in `async fn`
|
||||
--> $DIR/async-fn-multiple-lifetimes.rs:7:65
|
||||
|
|
||||
LL | async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
|
||||
| ^^ ^^ different lifetime here
|
||||
| |
|
||||
| first lifetime here
|
||||
| ^ neither `'a` nor `'b` outlives the other
|
||||
|
|
||||
= help: `async fn` can only accept borrowed values with identical lifetimes
|
||||
= note: multiple unrelated lifetimes are not allowed in `async fn`.
|
||||
= note: if you're using argument-position elided lifetimes, consider switching to a single named lifetime.
|
||||
|
||||
error[E0707]: multiple elided lifetimes used in arguments of `async fn`
|
||||
--> $DIR/async-fn-multiple-lifetimes.rs:16:39
|
||||
error: ambiguous lifetime bound in `async fn`
|
||||
--> $DIR/async-fn-multiple-lifetimes.rs:16:52
|
||||
|
|
||||
LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
|
||||
| ^ ^ different lifetime here
|
||||
| |
|
||||
| first lifetime here
|
||||
| ^ the elided lifetimes here do not outlive one another
|
||||
|
|
||||
= help: consider giving these arguments named lifetimes
|
||||
= note: multiple unrelated lifetimes are not allowed in `async fn`.
|
||||
= note: if you're using argument-position elided lifetimes, consider switching to a single named lifetime.
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/async-fn-multiple-lifetimes.rs:16:39
|
||||
|
|
||||
LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
|
||||
| ^ expected lifetime parameter
|
||||
|
|
||||
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_` or `_`
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors occurred: E0106, E0707, E0709.
|
||||
For more information about an error, try `rustc --explain E0106`.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
fn elided(x: &i32) -> impl Copy { x }
|
||||
//~^ ERROR explicit lifetime required in the type of `x` [E0621]
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
|
||||
fn explicit<'a>(x: &'a i32) -> impl Copy { x }
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
|
|
|
|||
|
|
@ -1,10 +1,20 @@
|
|||
error[E0621]: explicit lifetime required in the type of `x`
|
||||
--> $DIR/must_outlive_least_region_or_bound.rs:3:23
|
||||
error: cannot infer an appropriate lifetime
|
||||
--> $DIR/must_outlive_least_region_or_bound.rs:3:35
|
||||
|
|
||||
LL | fn elided(x: &i32) -> impl Copy { x }
|
||||
| ---- ^^^^^^^^^ lifetime `'static` required
|
||||
| |
|
||||
| help: add explicit lifetime `'static` to the type of `x`: `&'static i32`
|
||||
| --------- ^ ...but this borrow...
|
||||
| |
|
||||
| this return type evaluates to the `'static` lifetime...
|
||||
|
|
||||
note: ...can't outlive the anonymous lifetime #1 defined on the function body at 3:1
|
||||
--> $DIR/must_outlive_least_region_or_bound.rs:3:1
|
||||
|
|
||||
LL | fn elided(x: &i32) -> impl Copy { x }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 3:1
|
||||
|
|
||||
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: cannot infer an appropriate lifetime
|
||||
--> $DIR/must_outlive_least_region_or_bound.rs:6:44
|
||||
|
|
@ -67,5 +77,5 @@ LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
|
|||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors occurred: E0310, E0621, E0623.
|
||||
Some errors occurred: E0310, E0623.
|
||||
For more information about an error, try `rustc --explain E0310`.
|
||||
|
|
|
|||
16
src/test/ui/issues/issue-54974.rs
Normal file
16
src/test/ui/issues/issue-54974.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// compile-pass
|
||||
// edition:2018
|
||||
|
||||
#![feature(async_await, await_macro, futures_api)]
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
trait SomeTrait: Send + Sync + 'static {
|
||||
fn do_something(&self);
|
||||
}
|
||||
|
||||
async fn my_task(obj: Arc<SomeTrait>) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
14
src/test/ui/issues/issue-55324.rs
Normal file
14
src/test/ui/issues/issue-55324.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// compile-pass
|
||||
// edition:2018
|
||||
|
||||
#![feature(async_await, await_macro, futures_api)]
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
#[allow(unused)]
|
||||
async fn foo<F: Future<Output = i32>>(x: &i32, future: F) -> i32 {
|
||||
let y = await!(future);
|
||||
*x + y
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
21
src/test/ui/issues/issue-58885.rs
Normal file
21
src/test/ui/issues/issue-58885.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// compile-pass
|
||||
// edition:2018
|
||||
|
||||
#![feature(async_await, await_macro, futures_api)]
|
||||
|
||||
struct Xyz {
|
||||
a: u64,
|
||||
}
|
||||
|
||||
trait Foo {}
|
||||
|
||||
impl Xyz {
|
||||
async fn do_sth<'a>(
|
||||
&'a self, foo: &'a dyn Foo
|
||||
) -> bool
|
||||
{
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
17
src/test/ui/issues/issue-59001.rs
Normal file
17
src/test/ui/issues/issue-59001.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// compile-pass
|
||||
// edition:2018
|
||||
|
||||
#![feature(async_await, await_macro, futures_api)]
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
#[allow(unused)]
|
||||
async fn enter<'a, F, R>(mut callback: F)
|
||||
where
|
||||
F: FnMut(&'a mut i32) -> R,
|
||||
R: Future<Output = ()> + 'a,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -8,8 +8,8 @@ trait Foo<'a> {
|
|||
impl<'a, T> Foo<'a> for T { }
|
||||
|
||||
fn foo<'a, T>(x: &T) -> impl Foo<'a> {
|
||||
//~^ ERROR explicit lifetime required in the type of `x` [E0621]
|
||||
x
|
||||
//~^ ERROR explicit lifetime required in the type of `x` [E0621]
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error[E0621]: explicit lifetime required in the type of `x`
|
||||
--> $DIR/impl-trait-captures.rs:11:5
|
||||
--> $DIR/impl-trait-captures.rs:10:25
|
||||
|
|
||||
LL | x
|
||||
| ^ lifetime `ReEarlyBound(0, 'a)` required
|
||||
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
|
||||
| ^^^^^^^^^^^^ lifetime `ReEarlyBound(0, 'a)` required
|
||||
help: add explicit lifetime `ReEarlyBound(0, 'a)` to the type of `x`
|
||||
|
|
||||
LL | fn foo<'a, T>(x: &ReEarlyBound(0, 'a) T) -> impl Foo<'a> {
|
||||
|
|
|
|||
6
src/test/ui/parser/doc-inside-trait-item.rs
Normal file
6
src/test/ui/parser/doc-inside-trait-item.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
trait User{
|
||||
fn test();
|
||||
/// empty doc
|
||||
//~^ ERROR found a documentation comment that doesn't document anything
|
||||
}
|
||||
fn main() {}
|
||||
11
src/test/ui/parser/doc-inside-trait-item.stderr
Normal file
11
src/test/ui/parser/doc-inside-trait-item.stderr
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
error[E0584]: found a documentation comment that doesn't document anything
|
||||
--> $DIR/doc-inside-trait-item.rs:3:5
|
||||
|
|
||||
LL | /// empty doc
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0584`.
|
||||
|
|
@ -30,7 +30,7 @@ const TEST_REPOS: &'static [Test] = &[
|
|||
},
|
||||
Test {
|
||||
name: "tokei",
|
||||
repo: "https://github.com/Aaronepower/tokei",
|
||||
repo: "https://github.com/XAMPPRocky/tokei",
|
||||
sha: "5e11c4852fe4aa086b0e4fe5885822fbe57ba928",
|
||||
lock: None,
|
||||
packages: &[],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue