mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Auto merge of #62192 - Centril:rollup-kssnlta, r=Centril
Rollup of 16 pull requests Successful merges: - #61878 (improve pinning projection docs) - #62043 (Remove `FnBox`) - #62067 (Add suggestion for missing `.await` keyword) - #62076 (Updated RELEASES.md for 1.36.0) - #62102 (call out explicitly that general read needs to be called with an initialized buffer) - #62106 (Add more tests for async/await) - #62124 (refactor lexer to use idiomatic borrowing) - #62131 (libsyntax: Fix some Clippy warnings) - #62152 (Don't ICE on item in `.await` expression) - #62154 (Remove old fixme) - #62155 (Add regression test for MIR drop generation in async loops) - #62156 (Update books) - #62160 (Remove outdated question_mark_macro_sep lint) - #62164 (save-analysis: use buffered writes) - #62171 (rustc: Retry SIGILL linker invocations) - #62176 (Update RLS) Failed merges: r? @ghost
This commit is contained in:
commit
433a467815
101
RELEASES.md
101
RELEASES.md
@ -1,3 +1,104 @@
|
||||
Version 1.36.0 (2019-07-04)
|
||||
==========================
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Non-Lexical Lifetimes are now enabled on the 2015 edition.][59114]
|
||||
- [The order of traits in trait objects no longer affects the semantics of that
|
||||
object.][59445] e.g. `dyn Send + fmt::Debug` is now equivalent to
|
||||
`dyn fmt::Debug + Send`, where this was previously not the case.
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [`HashMap`'s implementation has been replaced with `hashbrown::HashMap` implementation.][58623]
|
||||
- [`TryFromSliceError` now implements `From<Infallible>`.][60318]
|
||||
- [`mem::needs_drop` is now available as a const fn.][60364]
|
||||
- [`alloc::Layout::from_size_align_unchecked` is now available as a const fn.][60370]
|
||||
- [`String` now implements `BorrowMut<str>`.][60404]
|
||||
- [`io::Cursor` now implements `Default`.][60234]
|
||||
- [Both `NonNull::{dangling, cast}` are now const fns.][60244]
|
||||
- [The `alloc` crate is now stable.][59675] `alloc` allows you to use a subset
|
||||
of `std` (e.g. `Vec`, `Box`, `Arc`) in `#![no_std]` environments if the
|
||||
environment has access to heap memory allocation.
|
||||
- [`String` now implements `From<&String>`.][59825]
|
||||
- [You can now pass multiple arguments to the `dbg!` macro.][59826] `dbg!` will
|
||||
return a tuple of each argument when there is multiple arguments.
|
||||
- [`Result::{is_err, is_ok}` are now `#[must_use]` and will produce a warning if
|
||||
not used.][59648]
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
- [`VecDeque::rotate_left`]
|
||||
- [`VecDeque::rotate_right`]
|
||||
- [`Iterator::copied`]
|
||||
- [`io::IoSlice`]
|
||||
- [`io::IoSliceMut`]
|
||||
- [`Read::read_vectored`]
|
||||
- [`Write::write_vectored`]
|
||||
- [`str::as_mut_ptr`]
|
||||
- [`mem::MaybeUninit`]
|
||||
- [`pointer::align_offset`]
|
||||
- [`future::Future`]
|
||||
- [`task::Context`]
|
||||
- [`task::RawWaker`]
|
||||
- [`task::RawWakerVTable`]
|
||||
- [`task::Waker`]
|
||||
- [`task::Poll`]
|
||||
|
||||
Cargo
|
||||
-----
|
||||
- [Cargo will now produce an error if you attempt to use the name of a required dependency as a feature.][cargo/6860]
|
||||
- [You can now pass the `--offline` flag to run cargo without accessing the network.][cargo/6934]
|
||||
|
||||
You can find further change's in [Cargo's 1.36.0 release notes][cargo-1-36-0].
|
||||
|
||||
Clippy
|
||||
------
|
||||
There have been numerous additions and fixes to clippy, see [Clippy's 1.36.0 release notes][clippy-1-36-0] for more details.
|
||||
|
||||
Misc
|
||||
----
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- With the stabilisation of `mem::MaybeUninit`, `mem::uninitialized` use is no
|
||||
longer recommended, and will be deprecated in 1.38.0.
|
||||
|
||||
[60318]: https://github.com/rust-lang/rust/pull/60318/
|
||||
[60364]: https://github.com/rust-lang/rust/pull/60364/
|
||||
[60370]: https://github.com/rust-lang/rust/pull/60370/
|
||||
[60404]: https://github.com/rust-lang/rust/pull/60404/
|
||||
[60234]: https://github.com/rust-lang/rust/pull/60234/
|
||||
[60244]: https://github.com/rust-lang/rust/pull/60244/
|
||||
[58623]: https://github.com/rust-lang/rust/pull/58623/
|
||||
[59648]: https://github.com/rust-lang/rust/pull/59648/
|
||||
[59675]: https://github.com/rust-lang/rust/pull/59675/
|
||||
[59825]: https://github.com/rust-lang/rust/pull/59825/
|
||||
[59826]: https://github.com/rust-lang/rust/pull/59826/
|
||||
[59445]: https://github.com/rust-lang/rust/pull/59445/
|
||||
[59114]: https://github.com/rust-lang/rust/pull/59114/
|
||||
[cargo/6860]: https://github.com/rust-lang/cargo/pull/6860/
|
||||
[cargo/6934]: https://github.com/rust-lang/cargo/pull/6934/
|
||||
[`VecDeque::rotate_left`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.rotate_left
|
||||
[`VecDeque::rotate_right`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.rotate_right
|
||||
[`Iterator::copied`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.copied
|
||||
[`io::IoSlice`]: https://doc.rust-lang.org/std/io/struct.IoSlice.html
|
||||
[`io::IoSliceMut`]: https://doc.rust-lang.org/std/io/struct.IoSliceMut.html
|
||||
[`Read::read_vectored`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_vectored
|
||||
[`Write::write_vectored`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_vectored
|
||||
[`str::as_mut_ptr`]: https://doc.rust-lang.org/std/primitive.str.html#method.as_mut_ptr
|
||||
[`mem::MaybeUninit`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html
|
||||
[`pointer::align_offset`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.align_offset
|
||||
[`future::Future`]: https://doc.rust-lang.org/std/future/trait.Future.html
|
||||
[`task::Context`]: https://doc.rust-lang.org/beta/std/task/struct.Context.html
|
||||
[`task::RawWaker`]: https://doc.rust-lang.org/beta/std/task/struct.RawWaker.html
|
||||
[`task::RawWakerVTable`]: https://doc.rust-lang.org/beta/std/task/struct.RawWakerVTable.html
|
||||
[`task::Waker`]: https://doc.rust-lang.org/beta/std/task/struct.Waker.html
|
||||
[`task::Poll`]: https://doc.rust-lang.org/beta/std/task/enum.Poll.html
|
||||
[clippy-1-36-0]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md#rust-136
|
||||
[cargo-1-36-0]: https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-136-2019-07-04
|
||||
|
||||
|
||||
Version 1.35.0 (2019-05-23)
|
||||
==========================
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 9aacfcc4c5b102c8cda195932addefd32fe955d2
|
||||
Subproject commit 6c0d83499c8e77e06a71d28c5e1adccec278d4f3
|
@ -1 +1 @@
|
||||
Subproject commit c656171b749b7307f21371dd0d3278efee5573b8
|
||||
Subproject commit 341c221116a8b9f1010cf1eece952b80c5ec7f54
|
@ -1 +1 @@
|
||||
Subproject commit 08ae27a4921ca53967656a7391c82f6c0ddd1ccc
|
||||
Subproject commit 7a5aab5fd50d6290679beb4cf42fa5f46ed22aec
|
@ -1 +1 @@
|
||||
Subproject commit b27472962986e85c94f4183b1a6d2207660d3ed6
|
||||
Subproject commit 62b3ff2cb44dd8b648c3ef2a9347c3706d148014
|
@ -1 +1 @@
|
||||
Subproject commit f55e97c145cf37fd664db2e0e2f2d05df328bf4f
|
||||
Subproject commit abf512fc9cc969dcbea69aa15b44586bbeb13c2d
|
@ -117,9 +117,7 @@ fn main () {
|
||||
}
|
||||
```
|
||||
|
||||
One of the objectives of this feature is to allow `Box<dyn FnOnce>`, instead of `Box<dyn FnBox>` in the future. See [#28796] for details.
|
||||
|
||||
[#28796]: https://github.com/rust-lang/rust/issues/28796
|
||||
One of the objectives of this feature is to allow `Box<dyn FnOnce>`.
|
||||
|
||||
## Variable length arrays
|
||||
|
||||
|
@ -1,32 +0,0 @@
|
||||
# `fnbox`
|
||||
|
||||
The tracking issue for this feature is [#28796]
|
||||
|
||||
[#28796]: https://github.com/rust-lang/rust/issues/28796
|
||||
|
||||
------------------------
|
||||
|
||||
This had been a temporary alternative to the following impls:
|
||||
|
||||
```rust,ignore
|
||||
impl<A, F> FnOnce for Box<F> where F: FnOnce<A> + ?Sized {}
|
||||
impl<A, F> FnMut for Box<F> where F: FnMut<A> + ?Sized {}
|
||||
impl<A, F> Fn for Box<F> where F: Fn<A> + ?Sized {}
|
||||
```
|
||||
|
||||
The impls are parallel to these (relatively old) impls:
|
||||
|
||||
```rust,ignore
|
||||
impl<A, F> FnOnce for &mut F where F: FnMut<A> + ?Sized {}
|
||||
impl<A, F> FnMut for &mut F where F: FnMut<A> + ?Sized {}
|
||||
impl<A, F> Fn for &mut F where F: Fn<A> + ?Sized {}
|
||||
impl<A, F> FnOnce for &F where F: Fn<A> + ?Sized {}
|
||||
impl<A, F> FnMut for &F where F: Fn<A> + ?Sized {}
|
||||
impl<A, F> Fn for &F where F: Fn<A> + ?Sized {}
|
||||
```
|
||||
|
||||
Before the introduction of [`unsized_locals`][unsized_locals], we had been unable to provide the former impls. That means, unlike `&dyn Fn()` or `&mut dyn FnMut()` we could not use `Box<dyn FnOnce()>` at that time.
|
||||
|
||||
[unsized_locals]: ../language-features/unsized-locals.md
|
||||
|
||||
`FnBox()` is an alternative approach to `Box<dyn FnBox()>` is delegated to `FnBox::call_box` which doesn't need unsized locals. As we now have `Box<dyn FnOnce()>` working, the `fnbox` feature is going to be removed.
|
@ -761,85 +761,6 @@ impl<A, F: Fn<A> + ?Sized> Fn<A> for Box<F> {
|
||||
}
|
||||
}
|
||||
|
||||
/// `FnBox` is deprecated and will be removed.
|
||||
/// `Box<dyn FnOnce()>` can be called directly, since Rust 1.35.0.
|
||||
///
|
||||
/// `FnBox` is a version of the `FnOnce` intended for use with boxed
|
||||
/// closure objects. The idea was that where one would normally store a
|
||||
/// `Box<dyn FnOnce()>` in a data structure, you whould use
|
||||
/// `Box<dyn FnBox()>`. The two traits behave essentially the same, except
|
||||
/// that a `FnBox` closure can only be called if it is boxed.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Here is a snippet of code which creates a hashmap full of boxed
|
||||
/// once closures and then removes them one by one, calling each
|
||||
/// closure as it is removed. Note that the type of the closures
|
||||
/// stored in the map is `Box<dyn FnBox() -> i32>` and not `Box<dyn FnOnce()
|
||||
/// -> i32>`.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(fnbox)]
|
||||
/// #![allow(deprecated)]
|
||||
///
|
||||
/// use std::boxed::FnBox;
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// fn make_map() -> HashMap<i32, Box<dyn FnBox() -> i32>> {
|
||||
/// let mut map: HashMap<i32, Box<dyn FnBox() -> i32>> = HashMap::new();
|
||||
/// map.insert(1, Box::new(|| 22));
|
||||
/// map.insert(2, Box::new(|| 44));
|
||||
/// map
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut map = make_map();
|
||||
/// for i in &[1, 2] {
|
||||
/// let f = map.remove(&i).unwrap();
|
||||
/// assert_eq!(f(), i * 22);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// In Rust 1.35.0 or later, use `FnOnce`, `FnMut`, or `Fn` instead:
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// fn make_map() -> HashMap<i32, Box<dyn FnOnce() -> i32>> {
|
||||
/// let mut map: HashMap<i32, Box<dyn FnOnce() -> i32>> = HashMap::new();
|
||||
/// map.insert(1, Box::new(|| 22));
|
||||
/// map.insert(2, Box::new(|| 44));
|
||||
/// map
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut map = make_map();
|
||||
/// for i in &[1, 2] {
|
||||
/// let f = map.remove(&i).unwrap();
|
||||
/// assert_eq!(f(), i * 22);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[rustc_paren_sugar]
|
||||
#[unstable(feature = "fnbox", issue = "28796")]
|
||||
#[rustc_deprecated(reason = "use `FnOnce`, `FnMut`, or `Fn` instead", since = "1.37.0")]
|
||||
pub trait FnBox<A>: FnOnce<A> {
|
||||
/// Performs the call operation.
|
||||
fn call_box(self: Box<Self>, args: A) -> Self::Output;
|
||||
}
|
||||
|
||||
#[unstable(feature = "fnbox", issue = "28796")]
|
||||
#[rustc_deprecated(reason = "use `FnOnce`, `FnMut`, or `Fn` instead", since = "1.37.0")]
|
||||
#[allow(deprecated, deprecated_in_future)]
|
||||
impl<A, F> FnBox<A> for F
|
||||
where F: FnOnce<A>
|
||||
{
|
||||
fn call_box(self: Box<F>, args: A) -> F::Output {
|
||||
self.call_once(args)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "coerce_unsized", issue = "27732")]
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
|
||||
|
||||
|
@ -25,6 +25,7 @@ use crate::task::{Context, Poll};
|
||||
#[doc(spotlight)]
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||
#[cfg_attr(not(bootstrap), lang = "future_trait")]
|
||||
pub trait Future {
|
||||
/// The type of value produced on completion.
|
||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||
|
@ -138,10 +138,11 @@
|
||||
//! To make this work, not just moving the data is restricted; deallocating, repurposing, or
|
||||
//! otherwise invalidating the memory used to store the data is restricted, too.
|
||||
//! Concretely, for pinned data you have to maintain the invariant
|
||||
//! that *its memory will not get invalidated from the moment it gets pinned until
|
||||
//! that *its memory will not get invalidated or repurposed from the moment it gets pinned until
|
||||
//! when `drop` is called*. Memory can be invalidated by deallocation, but also by
|
||||
//! replacing a [`Some(v)`] by [`None`], or calling [`Vec::set_len`] to "kill" some elements
|
||||
//! off of a vector.
|
||||
//! off of a vector. It can be repurposed by using [`ptr::write`] to overwrite it without
|
||||
//! calling the destructor first.
|
||||
//!
|
||||
//! This is exactly the kind of guarantee that the intrusive linked list from the previous
|
||||
//! section needs to function correctly.
|
||||
@ -166,57 +167,130 @@
|
||||
//! implementation as well: if an element of your type could have been pinned,
|
||||
//! you must treat Drop as implicitly taking `Pin<&mut Self>`.
|
||||
//!
|
||||
//! In particular, if your type is `#[repr(packed)]`, the compiler will automatically
|
||||
//! For example, you could implement `Drop` as follows:
|
||||
//! ```rust,no_run
|
||||
//! # use std::pin::Pin;
|
||||
//! # struct Type { }
|
||||
//! impl Drop for Type {
|
||||
//! fn drop(&mut self) {
|
||||
//! // `new_unchecked` is okay because we know this value is never used
|
||||
//! // again after being dropped.
|
||||
//! inner_drop(unsafe { Pin::new_unchecked(self)});
|
||||
//! fn inner_drop(this: Pin<&mut Type>) {
|
||||
//! // Actual drop code goes here.
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//! The function `inner_drop` has the type that `drop` *should* have, so this makes sure that
|
||||
//! you do not accidentally use `self`/`this` in a way that is in conflict with pinning.
|
||||
//!
|
||||
//! Moreover, if your type is `#[repr(packed)]`, the compiler will automatically
|
||||
//! move fields around to be able to drop them. As a consequence, you cannot use
|
||||
//! pinning with a `#[repr(packed)]` type.
|
||||
//!
|
||||
//! # Projections and Structural Pinning
|
||||
//!
|
||||
//! One interesting question arises when considering the interaction of pinning
|
||||
//! and the fields of a struct. When can a struct have a "pinning projection",
|
||||
//! i.e., an operation with type `fn(Pin<&Struct>) -> Pin<&Field>`? In a
|
||||
//! similar vein, when can a generic wrapper type (such as `Vec<T>`, `Box<T>`,
|
||||
//! or `RefCell<T>`) have an operation with type `fn(Pin<&Wrapper<T>>) ->
|
||||
//! Pin<&T>`?
|
||||
//! When working with pinned structs, the question arises how one can access the
|
||||
//! fields of that struct in a method that takes just `Pin<&mut Struct>`.
|
||||
//! The usual approach is to write helper methods (so called *projections*)
|
||||
//! that turn `Pin<&mut Struct>` into a reference to the field, but what
|
||||
//! type should that reference have? Is it `Pin<&mut Field>` or `&mut Field`?
|
||||
//! The same question arises with the fields of an `enum`, and also when considering
|
||||
//! container/wrapper types such as [`Vec<T>`], [`Box<T>`], or [`RefCell<T>`].
|
||||
//! (This question applies to both mutable and shared references, we just
|
||||
//! use the more common case of mutable references here for illustration.)
|
||||
//!
|
||||
//! Note: For the entirety of this discussion, the same applies for mutable references as it
|
||||
//! does for shared references.
|
||||
//! It turns out that it is actually up to the author of the data structure
|
||||
//! to decide whether the pinned projection for a particular field turns
|
||||
//! `Pin<&mut Struct>` into `Pin<&mut Field>` or `&mut Field`. There are some
|
||||
//! constraints though, and the most important constraint is *consistency*:
|
||||
//! every field can be *either* projected to a pinned reference, *or* have
|
||||
//! pinning removed as part of the projection. If both are done for the same field,
|
||||
//! that will likely be unsound!
|
||||
//!
|
||||
//! Having a pinning projection for some field means that pinning is "structural":
|
||||
//! when the wrapper is pinned, the field must be considered pinned, too.
|
||||
//! After all, the pinning projection lets us get a `Pin<&Field>`.
|
||||
//! As the author of a data structure you get to decide for each field whether pinning
|
||||
//! "propagates" to this field or not. Pinning that propagates is also called "structural",
|
||||
//! because it follows the structure of the type.
|
||||
//! In the following subsections, we describe the considerations that have to be made
|
||||
//! for either choice.
|
||||
//!
|
||||
//! However, structural pinning comes with a few extra requirements, so not all
|
||||
//! wrappers can be structural and hence not all wrappers can offer pinning projections:
|
||||
//! ## Pinning *is not* structural for `field`
|
||||
//!
|
||||
//! 1. The wrapper must only be [`Unpin`] if all the structural fields are
|
||||
//! It may seem counter-intuitive that the field of a pinned struct might not be pinned,
|
||||
//! but that is actually the easiest choice: if a `Pin<&mut Field>` is never created,
|
||||
//! nothing can go wrong! So, if you decide that some field does not have structural pinning,
|
||||
//! all you have to ensure is that you never create a pinned reference to that field.
|
||||
//!
|
||||
//! Fields without structural pinning may have a projection method that turns
|
||||
//! `Pin<&mut Struct>` into `&mut Field`:
|
||||
//! ```rust,no_run
|
||||
//! # use std::pin::Pin;
|
||||
//! # type Field = i32;
|
||||
//! # struct Struct { field: Field }
|
||||
//! impl Struct {
|
||||
//! fn pin_get_field<'a>(self: Pin<&'a mut Self>) -> &'a mut Field {
|
||||
//! // This is okay because `field` is never considered pinned.
|
||||
//! unsafe { &mut self.get_unchecked_mut().field }
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! You may also `impl Unpin for Struct` *even if* the type of `field`
|
||||
//! is not `Unpin`. What that type thinks about pinning is not relevant
|
||||
//! when no `Pin<&mut Field>` is ever created.
|
||||
//!
|
||||
//! ## Pinning *is* structural for `field`
|
||||
//!
|
||||
//! The other option is to decide that pinning is "structural" for `field`,
|
||||
//! meaning that if the struct is pinned then so is the field.
|
||||
//!
|
||||
//! This allows writing a projection that creates a `Pin<&mut Field>`, thus
|
||||
//! witnessing that the field is pinned:
|
||||
//! ```rust,no_run
|
||||
//! # use std::pin::Pin;
|
||||
//! # type Field = i32;
|
||||
//! # struct Struct { field: Field }
|
||||
//! impl Struct {
|
||||
//! fn pin_get_field<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut Field> {
|
||||
//! // This is okay because `field` is pinned when `self` is.
|
||||
//! unsafe { self.map_unchecked_mut(|s| &mut s.field) }
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! However, structural pinning comes with a few extra requirements:
|
||||
//!
|
||||
//! 1. The struct must only be [`Unpin`] if all the structural fields are
|
||||
//! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of
|
||||
//! the wrapper it is your responsibility *not* to add something like
|
||||
//! `impl<T> Unpin for Wrapper<T>`. (Notice that adding a projection operation
|
||||
//! the struct it is your responsibility *not* to add something like
|
||||
//! `impl<T> Unpin for Struct<T>`. (Notice that adding a projection operation
|
||||
//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break
|
||||
//! the principle that you only have to worry about any of this if you use `unsafe`.)
|
||||
//! 2. The destructor of the wrapper must not move structural fields out of its argument. This
|
||||
//! 2. The destructor of the struct must not move structural fields out of its argument. This
|
||||
//! is the exact point that was raised in the [previous section][drop-impl]: `drop` takes
|
||||
//! `&mut self`, but the wrapper (and hence its fields) might have been pinned before.
|
||||
//! `&mut self`, but the struct (and hence its fields) might have been pinned before.
|
||||
//! You have to guarantee that you do not move a field inside your `Drop` implementation.
|
||||
//! In particular, as explained previously, this means that your wrapper type must *not*
|
||||
//! In particular, as explained previously, this means that your struct must *not*
|
||||
//! be `#[repr(packed)]`.
|
||||
//! See that section for how to write `drop` in a way that the compiler can help you
|
||||
//! not accidentally break pinning.
|
||||
//! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]:
|
||||
//! once your wrapper is pinned, the memory that contains the
|
||||
//! once your struct is pinned, the memory that contains the
|
||||
//! content is not overwritten or deallocated without calling the content's destructors.
|
||||
//! This can be tricky, as witnessed by `VecDeque<T>`: the destructor of `VecDeque<T>` can fail
|
||||
//! to call `drop` on all elements if one of the destructors panics. This violates the
|
||||
//! This can be tricky, as witnessed by [`VecDeque<T>`]: the destructor of `VecDeque<T>`
|
||||
//! can fail to call `drop` on all elements if one of the destructors panics. This violates the
|
||||
//! `Drop` guarantee, because it can lead to elements being deallocated without
|
||||
//! their destructor being called. (`VecDeque` has no pinning projections, so this
|
||||
//! does not cause unsoundness.)
|
||||
//! 4. You must not offer any other operations that could lead to data being moved out of
|
||||
//! the fields when your type is pinned. For example, if the wrapper contains an
|
||||
//! the structural fields when your type is pinned. For example, if the struct contains an
|
||||
//! `Option<T>` and there is a `take`-like operation with type
|
||||
//! `fn(Pin<&mut Wrapper<T>>) -> Option<T>`,
|
||||
//! that operation can be used to move a `T` out of a pinned `Wrapper<T>` -- which means
|
||||
//! pinning cannot be structural.
|
||||
//! `fn(Pin<&mut Struct<T>>) -> Option<T>`,
|
||||
//! that operation can be used to move a `T` out of a pinned `Struct<T>` -- which means
|
||||
//! pinning cannot be structural for the field holding this data.
|
||||
//!
|
||||
//! For a more complex example of moving data out of a pinned type, imagine if `RefCell<T>`
|
||||
//! For a more complex example of moving data out of a pinned type, imagine if [`RefCell<T>`]
|
||||
//! had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`.
|
||||
//! Then we could do the following:
|
||||
//! ```compile_fail
|
||||
@ -231,13 +305,16 @@
|
||||
//! (using `RefCell::get_pin_mut`) and then move that content using the mutable
|
||||
//! reference we got later.
|
||||
//!
|
||||
//! For a type like `Vec<T>`, both possibilites (structural pinning or not) make sense,
|
||||
//! and the choice is up to the author. A `Vec<T>` with structural pinning could
|
||||
//! have `get_pin`/`get_pin_mut` projections. However, it could *not* allow calling
|
||||
//! ## Examples
|
||||
//!
|
||||
//! For a type like [`Vec<T>`], both possibilites (structural pinning or not) make sense.
|
||||
//! A `Vec<T>` with structural pinning could have `get_pin`/`get_pin_mut` methods to get
|
||||
//! pinned references to elements. However, it could *not* allow calling
|
||||
//! `pop` on a pinned `Vec<T>` because that would move the (structurally pinned) contents!
|
||||
//! Nor could it allow `push`, which might reallocate and thus also move the contents.
|
||||
//! A `Vec<T>` without structural pinning could `impl<T> Unpin for Vec<T>`, because the contents
|
||||
//! are never pinned and the `Vec<T>` itself is fine with being moved as well.
|
||||
//! At that point pinning just has no effect on the vector at all.
|
||||
//!
|
||||
//! In the standard library, pointer types generally do not have structural pinning,
|
||||
//! and thus they do not offer pinning projections. This is why `Box<T>: Unpin` holds for all `T`.
|
||||
@ -249,16 +326,28 @@
|
||||
//! whether the content is pinned is entirely independent of whether the pointer is
|
||||
//! pinned, meaning pinning is *not* structural.
|
||||
//!
|
||||
//! When implementing a [`Future`] combinator, you will usually need structural pinning
|
||||
//! for the nested futures, as you need to get pinned references to them to call `poll`.
|
||||
//! But if your combinator contains any other data that does not need to be pinned,
|
||||
//! you can make those fields not structural and hence freely access them with a
|
||||
//! mutable reference even when you just have `Pin<&mut Self>` (such as in your own
|
||||
//! `poll` implementation).
|
||||
//!
|
||||
//! [`Pin<P>`]: struct.Pin.html
|
||||
//! [`Unpin`]: ../../std/marker/trait.Unpin.html
|
||||
//! [`Deref`]: ../../std/ops/trait.Deref.html
|
||||
//! [`DerefMut`]: ../../std/ops/trait.DerefMut.html
|
||||
//! [`mem::swap`]: ../../std/mem/fn.swap.html
|
||||
//! [`mem::forget`]: ../../std/mem/fn.forget.html
|
||||
//! [`Unpin`]: ../marker/trait.Unpin.html
|
||||
//! [`Deref`]: ../ops/trait.Deref.html
|
||||
//! [`DerefMut`]: ../ops/trait.DerefMut.html
|
||||
//! [`mem::swap`]: ../mem/fn.swap.html
|
||||
//! [`mem::forget`]: ../mem/fn.forget.html
|
||||
//! [`Box<T>`]: ../../std/boxed/struct.Box.html
|
||||
//! [`Vec<T>`]: ../../std/vec/struct.Vec.html
|
||||
//! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len
|
||||
//! [`None`]: ../../std/option/enum.Option.html#variant.None
|
||||
//! [`Some(v)`]: ../../std/option/enum.Option.html#variant.Some
|
||||
//! [`VecDeque<T>`]: ../../std/collections/struct.VecDeque.html
|
||||
//! [`RefCell<T>`]: ../cell/struct.RefCell.html
|
||||
//! [`None`]: ../option/enum.Option.html#variant.None
|
||||
//! [`Some(v)`]: ../option/enum.Option.html#variant.Some
|
||||
//! [`ptr::write`]: ../ptr/fn.write.html
|
||||
//! [`Future`]: ../future/trait.Future.html
|
||||
//! [drop-impl]: #drop-implementation
|
||||
//! [drop-guarantee]: #drop-guarantee
|
||||
|
||||
|
@ -5795,7 +5795,6 @@ impl<'a> LoweringContext<'a> {
|
||||
err.span_label(item_sp, "this is not `async`");
|
||||
}
|
||||
err.emit();
|
||||
return hir::ExprKind::Err;
|
||||
}
|
||||
}
|
||||
let span = self.mark_span_with_reason(
|
||||
|
@ -1713,7 +1713,7 @@ pub enum GeneratorMovability {
|
||||
}
|
||||
|
||||
/// The yield kind that caused an `ExprKind::Yield`.
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub enum YieldSource {
|
||||
/// An `<expr>.await`.
|
||||
Await,
|
||||
|
@ -348,12 +348,6 @@ declare_lint! {
|
||||
|
||||
/// Some lints that are buffered from `libsyntax`. See `syntax::early_buffered_lints`.
|
||||
pub mod parser {
|
||||
declare_lint! {
|
||||
pub QUESTION_MARK_MACRO_SEP,
|
||||
Allow,
|
||||
"detects the use of `?` as a macro separator"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub ILL_FORMED_ATTRIBUTE_INPUT,
|
||||
Warn,
|
||||
@ -444,7 +438,6 @@ declare_lint_pass! {
|
||||
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
|
||||
MACRO_USE_EXTERN_CRATE,
|
||||
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
|
||||
parser::QUESTION_MARK_MACRO_SEP,
|
||||
parser::ILL_FORMED_ATTRIBUTE_INPUT,
|
||||
DEPRECATED_IN_FUTURE,
|
||||
AMBIGUOUS_ASSOCIATED_ITEMS,
|
||||
|
@ -27,7 +27,7 @@ use crate::hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use crate::hir::intravisit;
|
||||
use crate::hir;
|
||||
use crate::lint::builtin::BuiltinLintDiagnostics;
|
||||
use crate::lint::builtin::parser::{QUESTION_MARK_MACRO_SEP, ILL_FORMED_ATTRIBUTE_INPUT};
|
||||
use crate::lint::builtin::parser::ILL_FORMED_ATTRIBUTE_INPUT;
|
||||
use crate::session::{Session, DiagnosticMessageId};
|
||||
use crate::ty::TyCtxt;
|
||||
use crate::ty::query::Providers;
|
||||
@ -80,7 +80,6 @@ impl Lint {
|
||||
/// Returns the `rust::lint::Lint` for a `syntax::early_buffered_lints::BufferedEarlyLintId`.
|
||||
pub fn from_parser_lint_id(lint_id: BufferedEarlyLintId) -> &'static Self {
|
||||
match lint_id {
|
||||
BufferedEarlyLintId::QuestionMarkMacroSep => QUESTION_MARK_MACRO_SEP,
|
||||
BufferedEarlyLintId::IllFormedAttributeInput => ILL_FORMED_ATTRIBUTE_INPUT,
|
||||
}
|
||||
}
|
||||
|
@ -320,6 +320,7 @@ language_item_table! {
|
||||
FnMutTraitLangItem, "fn_mut", fn_mut_trait, Target::Trait;
|
||||
FnOnceTraitLangItem, "fn_once", fn_once_trait, Target::Trait;
|
||||
|
||||
FutureTraitLangItem, "future_trait", future_trait, Target::Trait;
|
||||
GeneratorStateLangItem, "generator_state", gen_state, Target::Enum;
|
||||
GeneratorTraitLangItem, "generator", gen_trait, Target::Trait;
|
||||
UnpinTraitLangItem, "unpin", unpin_trait, Target::Trait;
|
||||
|
@ -29,7 +29,7 @@ use std::fmt;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Output, Stdio};
|
||||
use std::process::{Output, Stdio, ExitStatus};
|
||||
use std::str;
|
||||
use std::env;
|
||||
|
||||
@ -510,21 +510,6 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
|
||||
sess.abort_if_errors();
|
||||
|
||||
// Invoke the system linker
|
||||
//
|
||||
// Note that there's a terribly awful hack that really shouldn't be present
|
||||
// in any compiler. Here an environment variable is supported to
|
||||
// automatically retry the linker invocation if the linker looks like it
|
||||
// segfaulted.
|
||||
//
|
||||
// Gee that seems odd, normally segfaults are things we want to know about!
|
||||
// Unfortunately though in rust-lang/rust#38878 we're experiencing the
|
||||
// linker segfaulting on Travis quite a bit which is causing quite a bit of
|
||||
// pain to land PRs when they spuriously fail due to a segfault.
|
||||
//
|
||||
// The issue #38878 has some more debugging information on it as well, but
|
||||
// this unfortunately looks like it's just a race condition in macOS's linker
|
||||
// with some thread pool working in the background. It seems that no one
|
||||
// currently knows a fix for this so in the meantime we're left with this...
|
||||
info!("{:?}", &cmd);
|
||||
let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok();
|
||||
let mut prog;
|
||||
@ -567,21 +552,59 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
|
||||
info!("{:?}", &cmd);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Here's a terribly awful hack that really shouldn't be present in any
|
||||
// compiler. Here an environment variable is supported to automatically
|
||||
// retry the linker invocation if the linker looks like it segfaulted.
|
||||
//
|
||||
// Gee that seems odd, normally segfaults are things we want to know
|
||||
// about! Unfortunately though in rust-lang/rust#38878 we're
|
||||
// experiencing the linker segfaulting on Travis quite a bit which is
|
||||
// causing quite a bit of pain to land PRs when they spuriously fail
|
||||
// due to a segfault.
|
||||
//
|
||||
// The issue #38878 has some more debugging information on it as well,
|
||||
// but this unfortunately looks like it's just a race condition in
|
||||
// macOS's linker with some thread pool working in the background. It
|
||||
// seems that no one currently knows a fix for this so in the meantime
|
||||
// we're left with this...
|
||||
if !retry_on_segfault || i > 3 {
|
||||
break
|
||||
}
|
||||
let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11";
|
||||
let msg_bus = "clang: error: unable to execute command: Bus error: 10";
|
||||
if !(out.contains(msg_segv) || out.contains(msg_bus)) {
|
||||
break
|
||||
if out.contains(msg_segv) || out.contains(msg_bus) {
|
||||
warn!(
|
||||
"looks like the linker segfaulted when we tried to call it, \
|
||||
automatically retrying again. cmd = {:?}, out = {}.",
|
||||
cmd,
|
||||
out,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
warn!(
|
||||
"looks like the linker segfaulted when we tried to call it, \
|
||||
automatically retrying again. cmd = {:?}, out = {}.",
|
||||
cmd,
|
||||
out,
|
||||
);
|
||||
if is_illegal_instruction(&output.status) {
|
||||
warn!(
|
||||
"looks like the linker hit an illegal instruction when we \
|
||||
tried to call it, automatically retrying again. cmd = {:?}, ]\
|
||||
out = {}, status = {}.",
|
||||
cmd,
|
||||
out,
|
||||
output.status,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn is_illegal_instruction(status: &ExitStatus) -> bool {
|
||||
use std::os::unix::prelude::*;
|
||||
status.signal() == Some(libc::SIGILL)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn is_illegal_instruction(_status: &ExitStatus) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
match prog {
|
||||
|
@ -39,8 +39,8 @@ impl Fingerprint {
|
||||
// you want.
|
||||
#[inline]
|
||||
pub fn combine_commutative(self, other: Fingerprint) -> Fingerprint {
|
||||
let a = (self.1 as u128) << 64 | self.0 as u128;
|
||||
let b = (other.1 as u128) << 64 | other.0 as u128;
|
||||
let a = u128::from(self.1) << 64 | u128::from(self.0);
|
||||
let b = u128::from(other.1) << 64 | u128::from(other.0);
|
||||
|
||||
let c = a.wrapping_add(b);
|
||||
|
||||
|
@ -263,7 +263,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
done_cache: Default::default(),
|
||||
waiting_cache: Default::default(),
|
||||
scratch: Some(vec![]),
|
||||
obligation_tree_id_generator: (0..).map(|i| ObligationTreeId(i)),
|
||||
obligation_tree_id_generator: (0..).map(ObligationTreeId),
|
||||
error_cache: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -70,15 +70,15 @@ unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
|
||||
let mut i = 0; // current byte index (from LSB) in the output u64
|
||||
let mut out = 0;
|
||||
if i + 3 < len {
|
||||
out = load_int_le!(buf, start + i, u32) as u64;
|
||||
out = u64::from(load_int_le!(buf, start + i, u32));
|
||||
i += 4;
|
||||
}
|
||||
if i + 1 < len {
|
||||
out |= (load_int_le!(buf, start + i, u16) as u64) << (i * 8);
|
||||
out |= u64::from(load_int_le!(buf, start + i, u16)) << (i * 8);
|
||||
i += 2
|
||||
}
|
||||
if i < len {
|
||||
out |= (*buf.get_unchecked(start + i) as u64) << (i * 8);
|
||||
out |= u64::from(*buf.get_unchecked(start + i)) << (i * 8);
|
||||
i += 1;
|
||||
}
|
||||
debug_assert_eq!(i, len);
|
||||
@ -237,7 +237,7 @@ impl Hasher for SipHasher128 {
|
||||
|
||||
if self.ntail != 0 {
|
||||
needed = 8 - self.ntail;
|
||||
self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << 8 * self.ntail;
|
||||
self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail);
|
||||
if length < needed {
|
||||
self.ntail += length;
|
||||
return
|
||||
|
@ -44,7 +44,7 @@ impl<W: StableHasherResult> StableHasher<W> {
|
||||
impl StableHasherResult for u128 {
|
||||
fn finish(hasher: StableHasher<Self>) -> Self {
|
||||
let (_0, _1) = hasher.finalize();
|
||||
(_0 as u128) | ((_1 as u128) << 64)
|
||||
u128::from(_0) | (u128::from(_1) << 64)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ where
|
||||
Ls: Links,
|
||||
{
|
||||
VecLinkedListIterator {
|
||||
links: links,
|
||||
links,
|
||||
current: first,
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ impl<'a> DiagnosticConverter<'a> {
|
||||
annotation_type: Self::annotation_type_for_level(self.level),
|
||||
}),
|
||||
footer: vec![],
|
||||
slices: slices,
|
||||
slices,
|
||||
})
|
||||
} else {
|
||||
// FIXME(#59346): Is it ok to return None if there's no source_map?
|
||||
|
@ -388,7 +388,7 @@ impl Diagnostic {
|
||||
}],
|
||||
msg: msg.to_owned(),
|
||||
style: SuggestionStyle::CompletelyHidden,
|
||||
applicability: applicability,
|
||||
applicability,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
@ -1339,7 +1339,7 @@ impl EmitterWriter {
|
||||
}
|
||||
|
||||
let mut dst = self.dst.writable();
|
||||
match write!(dst, "\n") {
|
||||
match writeln!(dst) {
|
||||
Err(e) => panic!("failed to emit error: {}", e),
|
||||
_ => {
|
||||
match dst.flush() {
|
||||
@ -1598,7 +1598,7 @@ fn emit_to_destination(rendered_buffer: &[Vec<StyledString>],
|
||||
dst.reset()?;
|
||||
}
|
||||
if !short_message && (!lvl.is_failure_note() || pos != rendered_buffer.len() - 1) {
|
||||
write!(dst, "\n")?;
|
||||
writeln!(dst)?;
|
||||
}
|
||||
}
|
||||
dst.flush()?;
|
||||
|
@ -42,7 +42,6 @@ use rustc::lint::builtin::{
|
||||
INTRA_DOC_LINK_RESOLUTION_FAILURE,
|
||||
MISSING_DOC_CODE_EXAMPLES,
|
||||
PRIVATE_DOC_TESTS,
|
||||
parser::QUESTION_MARK_MACRO_SEP,
|
||||
parser::ILL_FORMED_ATTRIBUTE_INPUT,
|
||||
};
|
||||
use rustc::session;
|
||||
@ -404,11 +403,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
||||
reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>",
|
||||
edition: None,
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(QUESTION_MARK_MACRO_SEP),
|
||||
reference: "issue #48075 <https://github.com/rust-lang/rust/issues/48075>",
|
||||
edition: Some(Edition::Edition2018),
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS),
|
||||
reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>",
|
||||
|
@ -29,6 +29,7 @@ use std::cell::Cell;
|
||||
use std::default::Default;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::BufWriter;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use syntax::ast::{self, Attribute, DUMMY_NODE_ID, NodeId, PatKind};
|
||||
@ -1025,7 +1026,7 @@ impl<'a> DumpHandler<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn output_file(&self, ctx: &SaveContext<'_, '_>) -> (File, PathBuf) {
|
||||
fn output_file(&self, ctx: &SaveContext<'_, '_>) -> (BufWriter<File>, PathBuf) {
|
||||
let sess = &ctx.tcx.sess;
|
||||
let file_name = match ctx.config.output_file {
|
||||
Some(ref s) => PathBuf::from(s),
|
||||
@ -1059,9 +1060,9 @@ impl<'a> DumpHandler<'a> {
|
||||
|
||||
info!("Writing output to {}", file_name.display());
|
||||
|
||||
let output_file = File::create(&file_name).unwrap_or_else(
|
||||
let output_file = BufWriter::new(File::create(&file_name).unwrap_or_else(
|
||||
|e| sess.fatal(&format!("Could not open {}: {}", file_name.display(), e)),
|
||||
);
|
||||
));
|
||||
|
||||
(output_file, file_name)
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ pub fn opts() -> TargetOptions {
|
||||
is_like_fuchsia: true,
|
||||
linker_is_gnu: true,
|
||||
has_rpath: false,
|
||||
pre_link_args: pre_link_args,
|
||||
pre_link_args,
|
||||
pre_link_objects_exe: vec![
|
||||
"Scrt1.o".to_string()
|
||||
],
|
||||
|
@ -127,6 +127,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
self.suggest_compatible_variants(&mut err, expr, expected, expr_ty);
|
||||
self.suggest_ref_or_into(&mut err, expr, expected, expr_ty);
|
||||
self.suggest_missing_await(&mut err, expr, expected, expr_ty);
|
||||
|
||||
(expected, Some(err))
|
||||
}
|
||||
|
@ -295,8 +295,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ExprKind::Index(ref base, ref idx) => {
|
||||
self.check_expr_index(base, idx, needs, expr)
|
||||
}
|
||||
ExprKind::Yield(ref value, _) => {
|
||||
self.check_expr_yield(value, expr)
|
||||
ExprKind::Yield(ref value, ref src) => {
|
||||
self.check_expr_yield(value, expr, src)
|
||||
}
|
||||
hir::ExprKind::Err => {
|
||||
tcx.types.err
|
||||
@ -1541,12 +1541,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr_yield(&self, value: &'tcx hir::Expr, expr: &'tcx hir::Expr) -> Ty<'tcx> {
|
||||
fn check_expr_yield(
|
||||
&self,
|
||||
value: &'tcx hir::Expr,
|
||||
expr: &'tcx hir::Expr,
|
||||
src: &'tcx hir::YieldSource
|
||||
) -> Ty<'tcx> {
|
||||
match self.yield_ty {
|
||||
Some(ty) => {
|
||||
self.check_expr_coercable_to_type(&value, ty);
|
||||
}
|
||||
None => {
|
||||
// Given that this `yield` expression was generated as a result of lowering a `.await`,
|
||||
// we know that the yield type must be `()`; however, the context won't contain this
|
||||
// information. Hence, we check the source of the yield expression here and check its
|
||||
// value's type against `()` (this check should always hold).
|
||||
None if src == &hir::YieldSource::Await => {
|
||||
self.check_expr_coercable_to_type(&value, self.tcx.mk_unit());
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(self.tcx.sess, expr.span, E0627,
|
||||
"yield statement outside of generator literal").emit();
|
||||
}
|
||||
|
@ -3932,6 +3932,72 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A possible error is to forget to add `.await` when using futures:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(async_await)]
|
||||
///
|
||||
/// async fn make_u32() -> u32 {
|
||||
/// 22
|
||||
/// }
|
||||
///
|
||||
/// fn take_u32(x: u32) {}
|
||||
///
|
||||
/// async fn foo() {
|
||||
/// let x = make_u32();
|
||||
/// take_u32(x);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
|
||||
/// expected type. If this is the case, and we are inside of an async body, it suggests adding
|
||||
/// `.await` to the tail of the expression.
|
||||
fn suggest_missing_await(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
expr: &hir::Expr,
|
||||
expected: Ty<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
) {
|
||||
// `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the
|
||||
// body isn't `async`.
|
||||
let item_id = self.tcx().hir().get_parent_node(self.body_id);
|
||||
if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) {
|
||||
let body = self.tcx().hir().body(body_id);
|
||||
if let Some(hir::GeneratorKind::Async) = body.generator_kind {
|
||||
let sp = expr.span;
|
||||
// Check for `Future` implementations by constructing a predicate to
|
||||
// prove: `<T as Future>::Output == U`
|
||||
let future_trait = self.tcx.lang_items().future_trait().unwrap();
|
||||
let item_def_id = self.tcx.associated_items(future_trait).next().unwrap().def_id;
|
||||
let predicate = ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate {
|
||||
// `<T as Future>::Output`
|
||||
projection_ty: ty::ProjectionTy {
|
||||
// `T`
|
||||
substs: self.tcx.mk_substs_trait(
|
||||
found,
|
||||
self.fresh_substs_for_item(sp, item_def_id)
|
||||
),
|
||||
// `Future::Output`
|
||||
item_def_id,
|
||||
},
|
||||
ty: expected,
|
||||
}));
|
||||
let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
|
||||
if self.infcx.predicate_may_hold(&obligation) {
|
||||
if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
|
||||
err.span_suggestion(
|
||||
sp,
|
||||
"consider using `.await` here",
|
||||
format!("{}.await", code),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A common error is to add an extra semicolon:
|
||||
///
|
||||
/// ```
|
||||
|
@ -461,7 +461,7 @@ impl<'a> Encoder<'a> {
|
||||
/// Creates a new JSON encoder whose output will be written to the writer
|
||||
/// specified.
|
||||
pub fn new(writer: &'a mut dyn fmt::Write) -> Encoder<'a> {
|
||||
Encoder { writer: writer, is_emitting_map_key: false, }
|
||||
Encoder { writer, is_emitting_map_key: false, }
|
||||
}
|
||||
}
|
||||
|
||||
@ -513,7 +513,7 @@ impl<'a> crate::Encoder for Encoder<'a> {
|
||||
emit_enquoted_if_mapkey!(self, fmt_number_or_null(v))
|
||||
}
|
||||
fn emit_f32(&mut self, v: f32) -> EncodeResult {
|
||||
self.emit_f64(v as f64)
|
||||
self.emit_f64(f64::from(v))
|
||||
}
|
||||
|
||||
fn emit_char(&mut self, v: char) -> EncodeResult {
|
||||
@ -763,7 +763,7 @@ impl<'a> crate::Encoder for PrettyEncoder<'a> {
|
||||
emit_enquoted_if_mapkey!(self, fmt_number_or_null(v))
|
||||
}
|
||||
fn emit_f32(&mut self, v: f32) -> EncodeResult {
|
||||
self.emit_f64(v as f64)
|
||||
self.emit_f64(f64::from(v))
|
||||
}
|
||||
|
||||
fn emit_char(&mut self, v: char) -> EncodeResult {
|
||||
@ -1698,12 +1698,12 @@ impl<T: Iterator<Item=char>> Parser<T> {
|
||||
if n2 < 0xDC00 || n2 > 0xDFFF {
|
||||
return self.error(LoneLeadingSurrogateInHexEscape)
|
||||
}
|
||||
let c = (((n1 - 0xD800) as u32) << 10 |
|
||||
(n2 - 0xDC00) as u32) + 0x1_0000;
|
||||
let c = (u32::from(n1 - 0xD800) << 10 |
|
||||
u32::from(n2 - 0xDC00)) + 0x1_0000;
|
||||
res.push(char::from_u32(c).unwrap());
|
||||
}
|
||||
|
||||
n => match char::from_u32(n as u32) {
|
||||
n => match char::from_u32(u32::from(n)) {
|
||||
Some(c) => res.push(c),
|
||||
None => return self.error(InvalidUnicodeCodePoint),
|
||||
},
|
||||
@ -2405,7 +2405,7 @@ impl ToJson for Json {
|
||||
}
|
||||
|
||||
impl ToJson for f32 {
|
||||
fn to_json(&self) -> Json { (*self as f64).to_json() }
|
||||
fn to_json(&self) -> Json { f64::from(*self).to_json() }
|
||||
}
|
||||
|
||||
impl ToJson for f64 {
|
||||
|
@ -123,7 +123,7 @@ pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i128, usize) {
|
||||
loop {
|
||||
byte = data[position];
|
||||
position += 1;
|
||||
result |= ((byte & 0x7F) as i128) << shift;
|
||||
result |= i128::from(byte & 0x7F) << shift;
|
||||
shift += 7;
|
||||
|
||||
if (byte & 0x80) == 0 {
|
||||
|
@ -296,13 +296,13 @@ impl<'a> serialize::Decoder for Decoder<'a> {
|
||||
#[inline]
|
||||
fn read_f64(&mut self) -> Result<f64, Self::Error> {
|
||||
let bits = self.read_u64()?;
|
||||
Ok(unsafe { ::std::mem::transmute(bits) })
|
||||
Ok(f64::from_bits(bits))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_f32(&mut self) -> Result<f32, Self::Error> {
|
||||
let bits = self.read_u32()?;
|
||||
Ok(unsafe { ::std::mem::transmute(bits) })
|
||||
Ok(f32::from_bits(bits))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -506,9 +506,18 @@ pub trait Read {
|
||||
///
|
||||
/// No guarantees are provided about the contents of `buf` when this
|
||||
/// function is called, implementations cannot rely on any property of the
|
||||
/// contents of `buf` being true. It is recommended that implementations
|
||||
/// contents of `buf` being true. It is recommended that *implementations*
|
||||
/// only write data to `buf` instead of reading its contents.
|
||||
///
|
||||
/// Correspondingly, however, *callers* of this method may not assume any guarantees
|
||||
/// about how the implementation uses `buf`. The trait is safe to implement,
|
||||
// so it is possible that the code that's supposed to write to the buffer might also read
|
||||
// from it. It is your responsibility to make sure that `buf` is initialized
|
||||
/// before calling `read`. Calling `read` with an uninitialized `buf` (of the kind one
|
||||
/// obtains via [`MaybeUninit<T>`]) is not safe, and can lead to undefined behavior.
|
||||
///
|
||||
/// [`MaybeUninit<T>`]: ../mem/union.MaybeUninit.html
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If this function encounters any form of I/O or other error, an error
|
||||
|
@ -262,7 +262,6 @@
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(external_doc)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(fnbox)]
|
||||
#![feature(generator_trait)]
|
||||
#![feature(hash_raw_entry)]
|
||||
#![feature(hashmap_internals)]
|
||||
|
@ -1832,7 +1832,7 @@ impl Arg {
|
||||
lt,
|
||||
MutTy {
|
||||
ty: infer_ty,
|
||||
mutbl: mutbl,
|
||||
mutbl,
|
||||
},
|
||||
),
|
||||
span,
|
||||
@ -2120,7 +2120,7 @@ impl PolyTraitRef {
|
||||
PolyTraitRef {
|
||||
bound_generic_params: generic_params,
|
||||
trait_ref: TraitRef {
|
||||
path: path,
|
||||
path,
|
||||
ref_id: DUMMY_NODE_ID,
|
||||
},
|
||||
span,
|
||||
|
@ -9,8 +9,6 @@ use syntax_pos::MultiSpan;
|
||||
/// Since we cannot import `LintId`s from `rustc::lint`, we define some Ids here which can later be
|
||||
/// passed to `rustc::lint::Lint::from_parser_lint_id` to get a `rustc::lint::Lint`.
|
||||
pub enum BufferedEarlyLintId {
|
||||
/// Usage of `?` as a macro separator is deprecated.
|
||||
QuestionMarkMacroSep,
|
||||
IllFormedAttributeInput,
|
||||
}
|
||||
|
||||
|
@ -815,7 +815,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||
|
||||
|
||||
fn pat(&self, span: Span, pat: PatKind) -> P<ast::Pat> {
|
||||
P(ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span: span })
|
||||
P(ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span })
|
||||
}
|
||||
fn pat_wild(&self, span: Span) -> P<ast::Pat> {
|
||||
self.pat(span, PatKind::Wild)
|
||||
|
@ -231,7 +231,7 @@ pub struct MacroExpander<'a, 'b> {
|
||||
|
||||
impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
|
||||
MacroExpander { cx: cx, monotonic: monotonic }
|
||||
MacroExpander { cx, monotonic }
|
||||
}
|
||||
|
||||
pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
|
||||
@ -377,7 +377,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
_ => item.clone(),
|
||||
};
|
||||
invocations.push(Invocation {
|
||||
kind: InvocationKind::Derive { path: path.clone(), item: item },
|
||||
kind: InvocationKind::Derive { path: path.clone(), item },
|
||||
fragment_kind: invoc.fragment_kind,
|
||||
expansion_data: ExpansionData {
|
||||
mark,
|
||||
@ -944,7 +944,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
||||
}
|
||||
|
||||
fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment {
|
||||
self.collect(kind, InvocationKind::Bang { mac: mac, ident: None, span: span })
|
||||
self.collect(kind, InvocationKind::Bang { mac, ident: None, span })
|
||||
}
|
||||
|
||||
fn collect_attr(&mut self,
|
||||
|
@ -319,7 +319,7 @@ fn parse_tree(
|
||||
tokenstream::TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited(
|
||||
span,
|
||||
Lrc::new(Delimited {
|
||||
delim: delim,
|
||||
delim,
|
||||
tts: parse(
|
||||
tts.into(),
|
||||
expect_matchers,
|
||||
|
@ -23,8 +23,8 @@ enum Frame {
|
||||
impl Frame {
|
||||
/// Construct a new frame around the delimited set of tokens.
|
||||
fn new(tts: Vec<quoted::TokenTree>) -> Frame {
|
||||
let forest = Lrc::new(quoted::Delimited { delim: token::NoDelim, tts: tts });
|
||||
Frame::Delimited { forest: forest, idx: 0, span: DelimSpan::dummy() }
|
||||
let forest = Lrc::new(quoted::Delimited { delim: token::NoDelim, tts });
|
||||
Frame::Delimited { forest, idx: 0, span: DelimSpan::dummy() }
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,7 +248,7 @@ pub fn transcribe(
|
||||
// the previous results (from outside the Delimited).
|
||||
quoted::TokenTree::Delimited(mut span, delimited) => {
|
||||
span = span.apply_mark(cx.current_expansion.mark);
|
||||
stack.push(Frame::Delimited { forest: delimited, idx: 0, span: span });
|
||||
stack.push(Frame::Delimited { forest: delimited, idx: 0, span });
|
||||
result_stack.push(mem::replace(&mut result, Vec::new()));
|
||||
}
|
||||
|
||||
|
@ -1665,7 +1665,7 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
|
||||
pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
|
||||
let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] };
|
||||
let cx = Context { features, parse_sess, plugin_attributes: &[] };
|
||||
cx.check_attribute(
|
||||
attr,
|
||||
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name).map(|a| *a)),
|
||||
|
@ -942,7 +942,7 @@ impl<'a> Parser<'a> {
|
||||
// {foo(bar {}}
|
||||
// - ^
|
||||
// | |
|
||||
// | help: `)` may belong here (FIXME: #58270)
|
||||
// | help: `)` may belong here
|
||||
// |
|
||||
// unclosed delimiter
|
||||
if let Some(sp) = unmatched.unclosed_span {
|
||||
|
@ -1,4 +1,3 @@
|
||||
use crate::ast;
|
||||
use crate::parse::ParseSess;
|
||||
use crate::parse::token::{self, Token, TokenKind};
|
||||
use crate::symbol::{sym, Symbol};
|
||||
@ -321,33 +320,29 @@ impl<'a> StringReader<'a> {
|
||||
(pos - self.source_file.start_pos).to_usize()
|
||||
}
|
||||
|
||||
/// Calls `f` with a string slice of the source text spanning from `start`
|
||||
/// up to but excluding `self.pos`, meaning the slice does not include
|
||||
/// the character `self.ch`.
|
||||
fn with_str_from<T, F>(&self, start: BytePos, f: F) -> T
|
||||
where F: FnOnce(&str) -> T
|
||||
/// Slice of the source text from `start` up to but excluding `self.pos`,
|
||||
/// meaning the slice does not include the character `self.ch`.
|
||||
fn str_from(&self, start: BytePos) -> &str
|
||||
{
|
||||
self.with_str_from_to(start, self.pos, f)
|
||||
self.str_from_to(start, self.pos)
|
||||
}
|
||||
|
||||
/// Creates a Name from a given offset to the current offset.
|
||||
fn name_from(&self, start: BytePos) -> ast::Name {
|
||||
/// Creates a Symbol from a given offset to the current offset.
|
||||
fn symbol_from(&self, start: BytePos) -> Symbol {
|
||||
debug!("taking an ident from {:?} to {:?}", start, self.pos);
|
||||
self.with_str_from(start, Symbol::intern)
|
||||
Symbol::intern(self.str_from(start))
|
||||
}
|
||||
|
||||
/// As name_from, with an explicit endpoint.
|
||||
fn name_from_to(&self, start: BytePos, end: BytePos) -> ast::Name {
|
||||
/// As symbol_from, with an explicit endpoint.
|
||||
fn symbol_from_to(&self, start: BytePos, end: BytePos) -> Symbol {
|
||||
debug!("taking an ident from {:?} to {:?}", start, end);
|
||||
self.with_str_from_to(start, end, Symbol::intern)
|
||||
Symbol::intern(self.str_from_to(start, end))
|
||||
}
|
||||
|
||||
/// Calls `f` with a string slice of the source text spanning from `start`
|
||||
/// up to but excluding `end`.
|
||||
fn with_str_from_to<T, F>(&self, start: BytePos, end: BytePos, f: F) -> T
|
||||
where F: FnOnce(&str) -> T
|
||||
/// Slice of the source text spanning from `start` up to but excluding `end`.
|
||||
fn str_from_to(&self, start: BytePos, end: BytePos) -> &str
|
||||
{
|
||||
f(&self.src[self.src_index(start)..self.src_index(end)])
|
||||
&self.src[self.src_index(start)..self.src_index(end)]
|
||||
}
|
||||
|
||||
/// Converts CRLF to LF in the given string, raising an error on bare CR.
|
||||
@ -444,7 +439,7 @@ impl<'a> StringReader<'a> {
|
||||
}
|
||||
|
||||
/// Eats <XID_start><XID_continue>*, if possible.
|
||||
fn scan_optional_raw_name(&mut self) -> Option<ast::Name> {
|
||||
fn scan_optional_raw_name(&mut self) -> Option<Symbol> {
|
||||
if !ident_start(self.ch) {
|
||||
return None;
|
||||
}
|
||||
@ -456,8 +451,8 @@ impl<'a> StringReader<'a> {
|
||||
self.bump();
|
||||
}
|
||||
|
||||
self.with_str_from(start, |string| {
|
||||
if string == "_" {
|
||||
match self.str_from(start) {
|
||||
"_" => {
|
||||
self.sess.span_diagnostic
|
||||
.struct_span_warn(self.mk_sp(start, self.pos),
|
||||
"underscore literal suffix is not allowed")
|
||||
@ -468,10 +463,9 @@ impl<'a> StringReader<'a> {
|
||||
<https://github.com/rust-lang/rust/issues/42326>")
|
||||
.emit();
|
||||
None
|
||||
} else {
|
||||
Some(Symbol::intern(string))
|
||||
}
|
||||
})
|
||||
name => Some(Symbol::intern(name))
|
||||
}
|
||||
}
|
||||
|
||||
/// PRECONDITION: self.ch is not whitespace
|
||||
@ -513,9 +507,7 @@ impl<'a> StringReader<'a> {
|
||||
}
|
||||
|
||||
let kind = if doc_comment {
|
||||
self.with_str_from(start_bpos, |string| {
|
||||
token::DocComment(Symbol::intern(string))
|
||||
})
|
||||
token::DocComment(self.symbol_from(start_bpos))
|
||||
} else {
|
||||
token::Comment
|
||||
};
|
||||
@ -544,7 +536,7 @@ impl<'a> StringReader<'a> {
|
||||
self.bump();
|
||||
}
|
||||
return Some(Token::new(
|
||||
token::Shebang(self.name_from(start)),
|
||||
token::Shebang(self.symbol_from(start)),
|
||||
self.mk_sp(start, self.pos),
|
||||
));
|
||||
}
|
||||
@ -615,23 +607,22 @@ impl<'a> StringReader<'a> {
|
||||
self.bump();
|
||||
}
|
||||
|
||||
self.with_str_from(start_bpos, |string| {
|
||||
// but comments with only "*"s between two "/"s are not
|
||||
let kind = if is_block_doc_comment(string) {
|
||||
let string = if has_cr {
|
||||
self.translate_crlf(start_bpos,
|
||||
string,
|
||||
"bare CR not allowed in block doc-comment")
|
||||
} else {
|
||||
string.into()
|
||||
};
|
||||
token::DocComment(Symbol::intern(&string[..]))
|
||||
let string = self.str_from(start_bpos);
|
||||
// but comments with only "*"s between two "/"s are not
|
||||
let kind = if is_block_doc_comment(string) {
|
||||
let string = if has_cr {
|
||||
self.translate_crlf(start_bpos,
|
||||
string,
|
||||
"bare CR not allowed in block doc-comment")
|
||||
} else {
|
||||
token::Comment
|
||||
string.into()
|
||||
};
|
||||
token::DocComment(Symbol::intern(&string[..]))
|
||||
} else {
|
||||
token::Comment
|
||||
};
|
||||
|
||||
Some(Token::new(kind, self.mk_sp(start_bpos, self.pos)))
|
||||
})
|
||||
Some(Token::new(kind, self.mk_sp(start_bpos, self.pos)))
|
||||
}
|
||||
|
||||
/// Scan through any digits (base `scan_radix`) or underscores,
|
||||
@ -727,17 +718,17 @@ impl<'a> StringReader<'a> {
|
||||
let pos = self.pos;
|
||||
self.check_float_base(start_bpos, pos, base);
|
||||
|
||||
(token::Float, self.name_from(start_bpos))
|
||||
(token::Float, self.symbol_from(start_bpos))
|
||||
} else {
|
||||
// it might be a float if it has an exponent
|
||||
if self.ch_is('e') || self.ch_is('E') {
|
||||
self.scan_float_exponent();
|
||||
let pos = self.pos;
|
||||
self.check_float_base(start_bpos, pos, base);
|
||||
return (token::Float, self.name_from(start_bpos));
|
||||
return (token::Float, self.symbol_from(start_bpos));
|
||||
}
|
||||
// but we certainly have an integer!
|
||||
(token::Integer, self.name_from(start_bpos))
|
||||
(token::Integer, self.symbol_from(start_bpos))
|
||||
}
|
||||
}
|
||||
|
||||
@ -838,20 +829,17 @@ impl<'a> StringReader<'a> {
|
||||
self.bump();
|
||||
}
|
||||
|
||||
return Ok(self.with_str_from(start, |string| {
|
||||
// FIXME: perform NFKC normalization here. (Issue #2253)
|
||||
let name = ast::Name::intern(string);
|
||||
|
||||
if is_raw_ident {
|
||||
let span = self.mk_sp(raw_start, self.pos);
|
||||
if !name.can_be_raw() {
|
||||
self.err_span(span, &format!("`{}` cannot be a raw identifier", name));
|
||||
}
|
||||
self.sess.raw_identifier_spans.borrow_mut().push(span);
|
||||
// FIXME: perform NFKC normalization here. (Issue #2253)
|
||||
let name = self.symbol_from(start);
|
||||
if is_raw_ident {
|
||||
let span = self.mk_sp(raw_start, self.pos);
|
||||
if !name.can_be_raw() {
|
||||
self.err_span(span, &format!("`{}` cannot be a raw identifier", name));
|
||||
}
|
||||
self.sess.raw_identifier_spans.borrow_mut().push(span);
|
||||
}
|
||||
|
||||
token::Ident(name, is_raw_ident)
|
||||
}));
|
||||
return Ok(token::Ident(name, is_raw_ident));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1017,7 +1005,7 @@ impl<'a> StringReader<'a> {
|
||||
// lifetimes shouldn't end with a single quote
|
||||
// if we find one, then this is an invalid character literal
|
||||
if self.ch_is('\'') {
|
||||
let symbol = self.name_from(start);
|
||||
let symbol = self.symbol_from(start);
|
||||
self.bump();
|
||||
self.validate_char_escape(start_with_quote);
|
||||
return Ok(TokenKind::lit(token::Char, symbol, None));
|
||||
@ -1035,7 +1023,7 @@ impl<'a> StringReader<'a> {
|
||||
// Include the leading `'` in the real identifier, for macro
|
||||
// expansion purposes. See #12512 for the gory details of why
|
||||
// this is necessary.
|
||||
return Ok(token::Lifetime(self.name_from(start_with_quote)));
|
||||
return Ok(token::Lifetime(self.symbol_from(start_with_quote)));
|
||||
}
|
||||
let msg = "unterminated character literal";
|
||||
let symbol = self.scan_single_quoted_string(start_with_quote, msg);
|
||||
@ -1063,7 +1051,7 @@ impl<'a> StringReader<'a> {
|
||||
},
|
||||
Some('r') => {
|
||||
let (start, end, hash_count) = self.scan_raw_string();
|
||||
let symbol = self.name_from_to(start, end);
|
||||
let symbol = self.symbol_from_to(start, end);
|
||||
self.validate_raw_byte_str_escape(start, end);
|
||||
|
||||
(token::ByteStrRaw(hash_count), symbol)
|
||||
@ -1084,7 +1072,7 @@ impl<'a> StringReader<'a> {
|
||||
}
|
||||
'r' => {
|
||||
let (start, end, hash_count) = self.scan_raw_string();
|
||||
let symbol = self.name_from_to(start, end);
|
||||
let symbol = self.symbol_from_to(start, end);
|
||||
self.validate_raw_str_escape(start, end);
|
||||
let suffix = self.scan_optional_raw_name();
|
||||
|
||||
@ -1185,7 +1173,7 @@ impl<'a> StringReader<'a> {
|
||||
|
||||
fn scan_single_quoted_string(&mut self,
|
||||
start_with_quote: BytePos,
|
||||
unterminated_msg: &str) -> ast::Name {
|
||||
unterminated_msg: &str) -> Symbol {
|
||||
// assumes that first `'` is consumed
|
||||
let start = self.pos;
|
||||
// lex `'''` as a single char, for recovery
|
||||
@ -1217,12 +1205,12 @@ impl<'a> StringReader<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
let id = self.name_from(start);
|
||||
let id = self.symbol_from(start);
|
||||
self.bump();
|
||||
id
|
||||
}
|
||||
|
||||
fn scan_double_quoted_string(&mut self, unterminated_msg: &str) -> ast::Name {
|
||||
fn scan_double_quoted_string(&mut self, unterminated_msg: &str) -> Symbol {
|
||||
debug_assert!(self.ch_is('\"'));
|
||||
let start_with_quote = self.pos;
|
||||
self.bump();
|
||||
@ -1237,7 +1225,7 @@ impl<'a> StringReader<'a> {
|
||||
}
|
||||
self.bump();
|
||||
}
|
||||
let id = self.name_from(start);
|
||||
let id = self.symbol_from(start);
|
||||
self.bump();
|
||||
id
|
||||
}
|
||||
@ -1300,101 +1288,95 @@ impl<'a> StringReader<'a> {
|
||||
}
|
||||
|
||||
fn validate_char_escape(&self, start_with_quote: BytePos) {
|
||||
self.with_str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1), |lit| {
|
||||
if let Err((off, err)) = unescape::unescape_char(lit) {
|
||||
emit_unescape_error(
|
||||
&self.sess.span_diagnostic,
|
||||
lit,
|
||||
self.mk_sp(start_with_quote, self.pos),
|
||||
unescape::Mode::Char,
|
||||
0..off,
|
||||
err,
|
||||
)
|
||||
}
|
||||
});
|
||||
let lit = self.str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1));
|
||||
if let Err((off, err)) = unescape::unescape_char(lit) {
|
||||
emit_unescape_error(
|
||||
&self.sess.span_diagnostic,
|
||||
lit,
|
||||
self.mk_sp(start_with_quote, self.pos),
|
||||
unescape::Mode::Char,
|
||||
0..off,
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_byte_escape(&self, start_with_quote: BytePos) {
|
||||
self.with_str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1), |lit| {
|
||||
if let Err((off, err)) = unescape::unescape_byte(lit) {
|
||||
let lit = self.str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1));
|
||||
if let Err((off, err)) = unescape::unescape_byte(lit) {
|
||||
emit_unescape_error(
|
||||
&self.sess.span_diagnostic,
|
||||
lit,
|
||||
self.mk_sp(start_with_quote, self.pos),
|
||||
unescape::Mode::Byte,
|
||||
0..off,
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_str_escape(&self, start_with_quote: BytePos) {
|
||||
let lit = self.str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1));
|
||||
unescape::unescape_str(lit, &mut |range, c| {
|
||||
if let Err(err) = c {
|
||||
emit_unescape_error(
|
||||
&self.sess.span_diagnostic,
|
||||
lit,
|
||||
self.mk_sp(start_with_quote, self.pos),
|
||||
unescape::Mode::Byte,
|
||||
0..off,
|
||||
unescape::Mode::Str,
|
||||
range,
|
||||
err,
|
||||
)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn validate_str_escape(&self, start_with_quote: BytePos) {
|
||||
self.with_str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1), |lit| {
|
||||
unescape::unescape_str(lit, &mut |range, c| {
|
||||
if let Err(err) = c {
|
||||
emit_unescape_error(
|
||||
&self.sess.span_diagnostic,
|
||||
lit,
|
||||
self.mk_sp(start_with_quote, self.pos),
|
||||
unescape::Mode::Str,
|
||||
range,
|
||||
err,
|
||||
)
|
||||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
fn validate_raw_str_escape(&self, content_start: BytePos, content_end: BytePos) {
|
||||
self.with_str_from_to(content_start, content_end, |lit: &str| {
|
||||
unescape::unescape_raw_str(lit, &mut |range, c| {
|
||||
if let Err(err) = c {
|
||||
emit_unescape_error(
|
||||
&self.sess.span_diagnostic,
|
||||
lit,
|
||||
self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)),
|
||||
unescape::Mode::Str,
|
||||
range,
|
||||
err,
|
||||
)
|
||||
}
|
||||
})
|
||||
});
|
||||
let lit = self.str_from_to(content_start, content_end);
|
||||
unescape::unescape_raw_str(lit, &mut |range, c| {
|
||||
if let Err(err) = c {
|
||||
emit_unescape_error(
|
||||
&self.sess.span_diagnostic,
|
||||
lit,
|
||||
self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)),
|
||||
unescape::Mode::Str,
|
||||
range,
|
||||
err,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn validate_raw_byte_str_escape(&self, content_start: BytePos, content_end: BytePos) {
|
||||
self.with_str_from_to(content_start, content_end, |lit: &str| {
|
||||
unescape::unescape_raw_byte_str(lit, &mut |range, c| {
|
||||
if let Err(err) = c {
|
||||
emit_unescape_error(
|
||||
&self.sess.span_diagnostic,
|
||||
lit,
|
||||
self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)),
|
||||
unescape::Mode::ByteStr,
|
||||
range,
|
||||
err,
|
||||
)
|
||||
}
|
||||
})
|
||||
});
|
||||
let lit = self.str_from_to(content_start, content_end);
|
||||
unescape::unescape_raw_byte_str(lit, &mut |range, c| {
|
||||
if let Err(err) = c {
|
||||
emit_unescape_error(
|
||||
&self.sess.span_diagnostic,
|
||||
lit,
|
||||
self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)),
|
||||
unescape::Mode::ByteStr,
|
||||
range,
|
||||
err,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn validate_byte_str_escape(&self, start_with_quote: BytePos) {
|
||||
self.with_str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1), |lit| {
|
||||
unescape::unescape_byte_str(lit, &mut |range, c| {
|
||||
if let Err(err) = c {
|
||||
emit_unescape_error(
|
||||
&self.sess.span_diagnostic,
|
||||
lit,
|
||||
self.mk_sp(start_with_quote, self.pos),
|
||||
unescape::Mode::ByteStr,
|
||||
range,
|
||||
err,
|
||||
)
|
||||
}
|
||||
})
|
||||
});
|
||||
let lit = self.str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1));
|
||||
unescape::unescape_byte_str(lit, &mut |range, c| {
|
||||
if let Err(err) = c {
|
||||
emit_unescape_error(
|
||||
&self.sess.span_diagnostic,
|
||||
lit,
|
||||
self.mk_sp(start_with_quote, self.pos),
|
||||
unescape::Mode::ByteStr,
|
||||
range,
|
||||
err,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,10 +290,10 @@ crate enum LastToken {
|
||||
}
|
||||
|
||||
impl TokenCursorFrame {
|
||||
fn new(sp: DelimSpan, delim: DelimToken, tts: &TokenStream) -> Self {
|
||||
fn new(span: DelimSpan, delim: DelimToken, tts: &TokenStream) -> Self {
|
||||
TokenCursorFrame {
|
||||
delim: delim,
|
||||
span: sp,
|
||||
delim,
|
||||
span,
|
||||
open_delim: delim == token::NoDelim,
|
||||
tree_cursor: tts.clone().into_trees(),
|
||||
close_delim: delim == token::NoDelim,
|
||||
@ -1449,7 +1449,7 @@ impl<'a> Parser<'a> {
|
||||
let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
|
||||
let mutbl = self.parse_mutability();
|
||||
let ty = self.parse_ty_no_plus()?;
|
||||
return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty: ty, mutbl: mutbl }));
|
||||
return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl }));
|
||||
}
|
||||
|
||||
fn parse_ptr(&mut self) -> PResult<'a, MutTy> {
|
||||
@ -1467,7 +1467,7 @@ impl<'a> Parser<'a> {
|
||||
Mutability::Immutable
|
||||
};
|
||||
let t = self.parse_ty_no_plus()?;
|
||||
Ok(MutTy { ty: t, mutbl: mutbl })
|
||||
Ok(MutTy { ty: t, mutbl })
|
||||
}
|
||||
|
||||
fn is_named_argument(&self) -> bool {
|
||||
@ -4366,7 +4366,7 @@ impl<'a> Parser<'a> {
|
||||
self.report_invalid_macro_expansion_item();
|
||||
}
|
||||
|
||||
(ident, ast::MacroDef { tokens: tokens, legacy: true })
|
||||
(ident, ast::MacroDef { tokens, legacy: true })
|
||||
}
|
||||
_ => return Ok(None),
|
||||
};
|
||||
@ -6789,12 +6789,12 @@ impl<'a> Parser<'a> {
|
||||
let hi = self.token.span;
|
||||
self.expect(&token::Semi)?;
|
||||
Ok(ast::ForeignItem {
|
||||
ident: ident,
|
||||
attrs: attrs,
|
||||
ident,
|
||||
attrs,
|
||||
node: ForeignItemKind::Ty,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: lo.to(hi),
|
||||
vis: vis
|
||||
vis
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -497,7 +497,7 @@ impl<'a> Printer<'a> {
|
||||
|
||||
pub fn print_newline(&mut self, amount: isize) -> io::Result<()> {
|
||||
debug!("NEWLINE {}", amount);
|
||||
let ret = write!(self.out, "\n");
|
||||
let ret = writeln!(self.out);
|
||||
self.pending_indentation = 0;
|
||||
self.indent(amount);
|
||||
ret
|
||||
|
@ -150,7 +150,7 @@ impl SourceMap {
|
||||
-> SourceMap {
|
||||
SourceMap {
|
||||
files: Default::default(),
|
||||
file_loader: file_loader,
|
||||
file_loader,
|
||||
path_mapping,
|
||||
}
|
||||
}
|
||||
@ -396,7 +396,7 @@ impl SourceMap {
|
||||
let f = (*self.files.borrow().source_files)[idx].clone();
|
||||
|
||||
match f.lookup_line(pos) {
|
||||
Some(line) => Ok(SourceFileAndLine { sf: f, line: line }),
|
||||
Some(line) => Ok(SourceFileAndLine { sf: f, line }),
|
||||
None => Err(f)
|
||||
}
|
||||
}
|
||||
@ -511,7 +511,7 @@ impl SourceMap {
|
||||
start_col,
|
||||
end_col: hi.col });
|
||||
|
||||
Ok(FileLines {file: lo.file, lines: lines})
|
||||
Ok(FileLines {file: lo.file, lines})
|
||||
}
|
||||
|
||||
/// Extracts the source surrounding the given `Span` using the `extract_source` function. The
|
||||
@ -820,7 +820,7 @@ impl SourceMap {
|
||||
let idx = self.lookup_source_file_idx(bpos);
|
||||
let sf = (*self.files.borrow().source_files)[idx].clone();
|
||||
let offset = bpos - sf.start_pos;
|
||||
SourceFileAndBytePos {sf: sf, pos: offset}
|
||||
SourceFileAndBytePos {sf, pos: offset}
|
||||
}
|
||||
|
||||
/// Converts an absolute BytePos to a CharPos relative to the source_file.
|
||||
|
@ -1,13 +0,0 @@
|
||||
#![feature(fnbox)]
|
||||
#![allow(deprecated, deprecated_in_future)]
|
||||
|
||||
use std::boxed::FnBox;
|
||||
|
||||
fn call_it<T>(f: Box<dyn FnBox() -> T>) -> T {
|
||||
f()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = "hello".to_owned();
|
||||
assert_eq!(&call_it(Box::new(|| s)) as &str, "hello");
|
||||
}
|
59
src/test/ui/async-await/async-fn-nonsend.rs
Normal file
59
src/test/ui/async-await/async-fn-nonsend.rs
Normal file
@ -0,0 +1,59 @@
|
||||
// compile-fail
|
||||
// edition:2018
|
||||
// compile-flags: --crate-type lib
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
fmt::Debug,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
fn non_sync() -> impl Debug { RefCell::new(()) }
|
||||
|
||||
fn non_send() -> impl Debug { Rc::new(()) }
|
||||
|
||||
fn take_ref<T>(_: &T) {}
|
||||
|
||||
async fn fut() {}
|
||||
|
||||
async fn fut_arg<T>(_: T) {}
|
||||
|
||||
async fn local_dropped_before_await() {
|
||||
// FIXME: it'd be nice for this to be allowed in a `Send` `async fn`
|
||||
let x = non_send();
|
||||
drop(x);
|
||||
fut().await;
|
||||
}
|
||||
|
||||
async fn non_send_temporary_in_match() {
|
||||
// We could theoretically make this work as well (produce a `Send` future)
|
||||
// for scrutinees / temporaries that can or will
|
||||
// be dropped prior to the match body
|
||||
// (e.g. `Copy` types).
|
||||
match Some(non_send()) {
|
||||
Some(_) => fut().await,
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
async fn non_sync_with_method_call() {
|
||||
// FIXME: it'd be nice for this to work.
|
||||
let f: &mut std::fmt::Formatter = panic!();
|
||||
if non_sync().fmt(f).unwrap() == () {
|
||||
fut().await;
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_send(_: impl Send) {}
|
||||
|
||||
pub fn pass_assert() {
|
||||
assert_send(local_dropped_before_await());
|
||||
//~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
assert_send(non_send_temporary_in_match());
|
||||
//~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
assert_send(non_sync_with_method_call());
|
||||
//~^ ERROR `dyn std::fmt::Write` cannot be sent between threads safely
|
||||
//~^^ ERROR `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
|
||||
}
|
87
src/test/ui/async-await/async-fn-nonsend.stderr
Normal file
87
src/test/ui/async-await/async-fn-nonsend.stderr
Normal file
@ -0,0 +1,87 @@
|
||||
error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
--> $DIR/async-fn-nonsend.rs:52:5
|
||||
|
|
||||
LL | assert_send(local_dropped_before_await());
|
||||
| ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
|
|
||||
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
|
||||
= note: required because it appears within the type `impl std::fmt::Debug`
|
||||
= note: required because it appears within the type `{impl std::fmt::Debug, impl std::future::Future, ()}`
|
||||
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:23:39: 28:2 {impl std::fmt::Debug, impl std::future::Future, ()}]`
|
||||
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:23:39: 28:2 {impl std::fmt::Debug, impl std::future::Future, ()}]>`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
note: required by `assert_send`
|
||||
--> $DIR/async-fn-nonsend.rs:49:1
|
||||
|
|
||||
LL | fn assert_send(_: impl Send) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
--> $DIR/async-fn-nonsend.rs:54:5
|
||||
|
|
||||
LL | assert_send(non_send_temporary_in_match());
|
||||
| ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
|
|
||||
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
|
||||
= note: required because it appears within the type `impl std::fmt::Debug`
|
||||
= note: required because it appears within the type `{fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, ()}`
|
||||
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:30:40: 39:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, ()}]`
|
||||
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:30:40: 39:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, ()}]>`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
note: required by `assert_send`
|
||||
--> $DIR/async-fn-nonsend.rs:49:1
|
||||
|
|
||||
LL | fn assert_send(_: impl Send) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: `dyn std::fmt::Write` cannot be sent between threads safely
|
||||
--> $DIR/async-fn-nonsend.rs:56:5
|
||||
|
|
||||
LL | assert_send(non_sync_with_method_call());
|
||||
| ^^^^^^^^^^^ `dyn std::fmt::Write` cannot be sent between threads safely
|
||||
|
|
||||
= help: the trait `std::marker::Send` is not implemented for `dyn std::fmt::Write`
|
||||
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut dyn std::fmt::Write`
|
||||
= note: required because it appears within the type `std::fmt::Formatter<'_>`
|
||||
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
|
||||
= note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}`
|
||||
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]`
|
||||
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
note: required by `assert_send`
|
||||
--> $DIR/async-fn-nonsend.rs:49:1
|
||||
|
|
||||
LL | fn assert_send(_: impl Send) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
|
||||
--> $DIR/async-fn-nonsend.rs:56:5
|
||||
|
|
||||
LL | assert_send(non_sync_with_method_call());
|
||||
| ^^^^^^^^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
|
||||
|
|
||||
= help: within `std::fmt::ArgumentV1<'_>`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)`
|
||||
= note: required because it appears within the type `std::marker::PhantomData<*mut (dyn std::ops::Fn() + 'static)>`
|
||||
= note: required because it appears within the type `core::fmt::Void`
|
||||
= note: required because it appears within the type `&core::fmt::Void`
|
||||
= note: required because it appears within the type `std::fmt::ArgumentV1<'_>`
|
||||
= note: required because of the requirements on the impl of `std::marker::Send` for `std::slice::Iter<'_, std::fmt::ArgumentV1<'_>>`
|
||||
= note: required because it appears within the type `std::fmt::Formatter<'_>`
|
||||
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
|
||||
= note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}`
|
||||
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]`
|
||||
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
note: required by `assert_send`
|
||||
--> $DIR/async-fn-nonsend.rs:49:1
|
||||
|
|
||||
LL | fn assert_send(_: impl Send) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
59
src/test/ui/async-await/async-fn-send-uses-nonsend.rs
Normal file
59
src/test/ui/async-await/async-fn-send-uses-nonsend.rs
Normal file
@ -0,0 +1,59 @@
|
||||
// compile-pass
|
||||
// edition:2018
|
||||
// compile-flags: --crate-type lib
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
fmt::Debug,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
fn non_sync() -> impl Debug { RefCell::new(()) }
|
||||
|
||||
fn non_send() -> impl Debug { Rc::new(()) }
|
||||
|
||||
fn take_ref<T>(_: &T) {}
|
||||
|
||||
async fn fut() {}
|
||||
|
||||
async fn fut_arg<T>(_: T) {}
|
||||
|
||||
async fn still_send() {
|
||||
fut().await;
|
||||
println!("{:?} {:?}", non_send(), non_sync());
|
||||
fut().await;
|
||||
drop(non_send());
|
||||
drop(non_sync());
|
||||
fut().await;
|
||||
fut_arg(non_sync()).await;
|
||||
|
||||
// Note: all temporaries in `if let` and `match` scrutinee
|
||||
// are dropped at the *end* of the blocks, so using `non_send()`
|
||||
// in either of those positions with an await in the middle will
|
||||
// cause a `!Send` future. It might be nice in the future to allow
|
||||
// this for `Copy` types, since they can be "dropped" early without
|
||||
// affecting the end user.
|
||||
if let Some(_) = Some(non_sync()) {
|
||||
fut().await;
|
||||
}
|
||||
match Some(non_sync()) {
|
||||
Some(_) => fut().await,
|
||||
None => fut().await,
|
||||
}
|
||||
|
||||
let _ = non_send();
|
||||
fut().await;
|
||||
|
||||
{
|
||||
let _x = non_send();
|
||||
}
|
||||
fut().await;
|
||||
}
|
||||
|
||||
fn assert_send(_: impl Send) {}
|
||||
|
||||
pub fn pass_assert() {
|
||||
assert_send(still_send());
|
||||
}
|
21
src/test/ui/async-await/dont-suggest-missing-await.rs
Normal file
21
src/test/ui/async-await/dont-suggest-missing-await.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// edition:2018
|
||||
|
||||
// This test ensures we don't make the suggestion in bodies that aren't `async`.
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
fn take_u32(x: u32) {}
|
||||
|
||||
async fn make_u32() -> u32 {
|
||||
22
|
||||
}
|
||||
|
||||
async fn dont_suggest_await_in_closure() {
|
||||
|| {
|
||||
let x = make_u32();
|
||||
take_u32(x)
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
12
src/test/ui/async-await/dont-suggest-missing-await.stderr
Normal file
12
src/test/ui/async-await/dont-suggest-missing-await.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/dont-suggest-missing-await.rs:16:18
|
||||
|
|
||||
LL | take_u32(x)
|
||||
| ^ expected u32, found opaque type
|
||||
|
|
||||
= note: expected type `u32`
|
||||
found type `impl std::future::Future`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
90
src/test/ui/async-await/generics-and-bounds.rs
Normal file
90
src/test/ui/async-await/generics-and-bounds.rs
Normal file
@ -0,0 +1,90 @@
|
||||
// compile-pass
|
||||
// edition:2018
|
||||
// compile-flags: --crate-type lib
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
pub async fn simple_generic<T>() {}
|
||||
|
||||
pub trait Foo {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
struct FooType;
|
||||
impl Foo for FooType {}
|
||||
|
||||
pub async fn call_generic_bound<F: Foo>(f: F) {
|
||||
f.foo()
|
||||
}
|
||||
|
||||
pub async fn call_where_clause<F>(f: F)
|
||||
where
|
||||
F: Foo,
|
||||
{
|
||||
f.foo()
|
||||
}
|
||||
|
||||
pub async fn call_impl_trait(f: impl Foo) {
|
||||
f.foo()
|
||||
}
|
||||
|
||||
pub async fn call_with_ref(f: &impl Foo) {
|
||||
f.foo()
|
||||
}
|
||||
|
||||
pub fn async_fn_with_same_generic_params_unifies() {
|
||||
let mut a = call_generic_bound(FooType);
|
||||
a = call_generic_bound(FooType);
|
||||
|
||||
let mut b = call_where_clause(FooType);
|
||||
b = call_where_clause(FooType);
|
||||
|
||||
let mut c = call_impl_trait(FooType);
|
||||
c = call_impl_trait(FooType);
|
||||
|
||||
let f_one = FooType;
|
||||
let f_two = FooType;
|
||||
let mut d = call_with_ref(&f_one);
|
||||
d = call_with_ref(&f_two);
|
||||
}
|
||||
|
||||
pub fn simple_generic_block<T>() -> impl Future<Output = ()> {
|
||||
async move {}
|
||||
}
|
||||
|
||||
pub fn call_generic_bound_block<F: Foo>(f: F) -> impl Future<Output = ()> {
|
||||
async move { f.foo() }
|
||||
}
|
||||
|
||||
pub fn call_where_clause_block<F>(f: F) -> impl Future<Output = ()>
|
||||
where
|
||||
F: Foo,
|
||||
{
|
||||
async move { f.foo() }
|
||||
}
|
||||
|
||||
pub fn call_impl_trait_block(f: impl Foo) -> impl Future<Output = ()> {
|
||||
async move { f.foo() }
|
||||
}
|
||||
|
||||
pub fn call_with_ref_block<'a>(f: &'a (impl Foo + 'a)) -> impl Future<Output = ()> + 'a {
|
||||
async move { f.foo() }
|
||||
}
|
||||
|
||||
pub fn async_block_with_same_generic_params_unifies() {
|
||||
let mut a = call_generic_bound_block(FooType);
|
||||
a = call_generic_bound_block(FooType);
|
||||
|
||||
let mut b = call_where_clause_block(FooType);
|
||||
b = call_where_clause_block(FooType);
|
||||
|
||||
let mut c = call_impl_trait_block(FooType);
|
||||
c = call_impl_trait_block(FooType);
|
||||
|
||||
let f_one = FooType;
|
||||
let f_two = FooType;
|
||||
let mut d = call_with_ref_block(&f_one);
|
||||
d = call_with_ref_block(&f_two);
|
||||
}
|
@ -7,7 +7,8 @@
|
||||
async fn foo() {}
|
||||
|
||||
fn make_generator() {
|
||||
let _gen = || foo.await; //~ ERROR `await` is only allowed inside `async` functions and blocks
|
||||
let _gen = || foo().await;
|
||||
//~^ ERROR `await` is only allowed inside `async` functions and blocks
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,8 +1,8 @@
|
||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||
--> $DIR/issue-51719.rs:10:19
|
||||
|
|
||||
LL | let _gen = || foo.await;
|
||||
| -- ^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||
LL | let _gen = || foo().await;
|
||||
| -- ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||
| |
|
||||
| this is not `async`
|
||||
|
||||
|
21
src/test/ui/async-await/issues/issue-61986.rs
Normal file
21
src/test/ui/async-await/issues/issue-61986.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// compile-pass
|
||||
// edition:2018
|
||||
//
|
||||
// Tests that we properly handle StorageDead/StorageLives for temporaries
|
||||
// created in async loop bodies.
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
async fn bar() -> Option<()> {
|
||||
Some(())
|
||||
}
|
||||
|
||||
async fn listen() {
|
||||
while let Some(_) = bar().await {
|
||||
String::new();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
listen();
|
||||
}
|
19
src/test/ui/async-await/issues/issue-62009.rs
Normal file
19
src/test/ui/async-await/issues/issue-62009.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// edition:2018
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
async fn print_dur() {}
|
||||
|
||||
fn main() {
|
||||
async { let (); }.await;
|
||||
//~^ ERROR `await` is only allowed inside `async` functions and blocks
|
||||
async {
|
||||
//~^ ERROR `await` is only allowed inside `async` functions and blocks
|
||||
let task1 = print_dur().await;
|
||||
}.await;
|
||||
(async || 2333)().await;
|
||||
//~^ ERROR `await` is only allowed inside `async` functions and blocks
|
||||
(|_| 2333).await;
|
||||
//~^ ERROR `await` is only allowed inside `async` functions and blocks
|
||||
//~^^ ERROR
|
||||
}
|
49
src/test/ui/async-await/issues/issue-62009.stderr
Normal file
49
src/test/ui/async-await/issues/issue-62009.stderr
Normal file
@ -0,0 +1,49 @@
|
||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||
--> $DIR/issue-62009.rs:8:5
|
||||
|
|
||||
LL | fn main() {
|
||||
| ---- this is not `async`
|
||||
LL | async { let (); }.await;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||
|
||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||
--> $DIR/issue-62009.rs:10:5
|
||||
|
|
||||
LL | fn main() {
|
||||
| ---- this is not `async`
|
||||
...
|
||||
LL | / async {
|
||||
LL | |
|
||||
LL | | let task1 = print_dur().await;
|
||||
LL | | }.await;
|
||||
| |___________^ only allowed inside `async` functions and blocks
|
||||
|
||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||
--> $DIR/issue-62009.rs:14:5
|
||||
|
|
||||
LL | fn main() {
|
||||
| ---- this is not `async`
|
||||
...
|
||||
LL | (async || 2333)().await;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||
|
||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||
--> $DIR/issue-62009.rs:16:5
|
||||
|
|
||||
LL | fn main() {
|
||||
| ---- this is not `async`
|
||||
...
|
||||
LL | (|_| 2333).await;
|
||||
| ^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||
|
||||
error[E0277]: the trait bound `[closure@$DIR/issue-62009.rs:16:5: 16:15]: std::future::Future` is not satisfied
|
||||
--> $DIR/issue-62009.rs:16:5
|
||||
|
|
||||
LL | (|_| 2333).await;
|
||||
| ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009.rs:16:5: 16:15]`
|
||||
|
|
||||
= note: required by `std::future::poll_with_tls_context`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
8
src/test/ui/async-await/no-async-const.rs
Normal file
8
src/test/ui/async-await/no-async-const.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// compile-fail
|
||||
// edition:2018
|
||||
// compile-flags: --crate-type lib
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
pub async const fn x() {}
|
||||
//~^ ERROR expected one of `fn` or `unsafe`, found `const`
|
8
src/test/ui/async-await/no-async-const.stderr
Normal file
8
src/test/ui/async-await/no-async-const.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: expected one of `fn` or `unsafe`, found `const`
|
||||
--> $DIR/no-async-const.rs:7:11
|
||||
|
|
||||
LL | pub async const fn x() {}
|
||||
| ^^^^^ expected one of `fn` or `unsafe` here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
9
src/test/ui/async-await/no-const-async.rs
Normal file
9
src/test/ui/async-await/no-const-async.rs
Normal file
@ -0,0 +1,9 @@
|
||||
// compile-fail
|
||||
// edition:2018
|
||||
// compile-flags: --crate-type lib
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
pub const async fn x() {}
|
||||
//~^ ERROR expected identifier, found reserved keyword `async`
|
||||
//~^^ expected `:`, found keyword `fn`
|
18
src/test/ui/async-await/no-const-async.stderr
Normal file
18
src/test/ui/async-await/no-const-async.stderr
Normal file
@ -0,0 +1,18 @@
|
||||
error: expected identifier, found reserved keyword `async`
|
||||
--> $DIR/no-const-async.rs:7:11
|
||||
|
|
||||
LL | pub const async fn x() {}
|
||||
| ^^^^^ expected identifier, found reserved keyword
|
||||
help: you can escape reserved keywords to use them as identifiers
|
||||
|
|
||||
LL | pub const r#async fn x() {}
|
||||
| ^^^^^^^
|
||||
|
||||
error: expected `:`, found keyword `fn`
|
||||
--> $DIR/no-const-async.rs:7:17
|
||||
|
|
||||
LL | pub const async fn x() {}
|
||||
| ^^ expected `:`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
32
src/test/ui/async-await/suggest-missing-await.fixed
Normal file
32
src/test/ui/async-await/suggest-missing-await.fixed
Normal file
@ -0,0 +1,32 @@
|
||||
// edition:2018
|
||||
// run-rustfix
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
fn take_u32(_x: u32) {}
|
||||
|
||||
async fn make_u32() -> u32 {
|
||||
22
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
async fn suggest_await_in_async_fn() {
|
||||
let x = make_u32();
|
||||
take_u32(x.await)
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
//~| HELP consider using `.await` here
|
||||
//~| SUGGESTION x.await
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
async fn suggest_await_in_async_closure() {
|
||||
async || {
|
||||
let x = make_u32();
|
||||
take_u32(x.await)
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
//~| HELP consider using `.await` here
|
||||
//~| SUGGESTION x.await
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
32
src/test/ui/async-await/suggest-missing-await.rs
Normal file
32
src/test/ui/async-await/suggest-missing-await.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// edition:2018
|
||||
// run-rustfix
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
fn take_u32(_x: u32) {}
|
||||
|
||||
async fn make_u32() -> u32 {
|
||||
22
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
async fn suggest_await_in_async_fn() {
|
||||
let x = make_u32();
|
||||
take_u32(x)
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
//~| HELP consider using `.await` here
|
||||
//~| SUGGESTION x.await
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
async fn suggest_await_in_async_closure() {
|
||||
async || {
|
||||
let x = make_u32();
|
||||
take_u32(x)
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
//~| HELP consider using `.await` here
|
||||
//~| SUGGESTION x.await
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
27
src/test/ui/async-await/suggest-missing-await.stderr
Normal file
27
src/test/ui/async-await/suggest-missing-await.stderr
Normal file
@ -0,0 +1,27 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-missing-await.rs:15:14
|
||||
|
|
||||
LL | take_u32(x)
|
||||
| ^
|
||||
| |
|
||||
| expected u32, found opaque type
|
||||
| help: consider using `.await` here: `x.await`
|
||||
|
|
||||
= note: expected type `u32`
|
||||
found type `impl std::future::Future`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-missing-await.rs:25:18
|
||||
|
|
||||
LL | take_u32(x)
|
||||
| ^
|
||||
| |
|
||||
| expected u32, found opaque type
|
||||
| help: consider using `.await` here: `x.await`
|
||||
|
|
||||
= note: expected type `u32`
|
||||
found type `impl std::future::Future`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -1 +1 @@
|
||||
Subproject commit 3e519650cea91a4b785cd773a3e5965553f74249
|
||||
Subproject commit 597c9be8c75be3e664f189c4325c96cf9b464dc3
|
Loading…
Reference in New Issue
Block a user