mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Auto merge of #40148 - frewsxcv:rollup, r=frewsxcv
Rollup of 9 pull requests - Successful merges: #39977, #40033, #40047, #40056, #40057, #40122, #40124, #40126, #40131 - Failed merges: #40101
This commit is contained in:
commit
be760566cf
@ -97,33 +97,38 @@ system internals, try asking in [`#rust-internals`][pound-rust-internals].
|
|||||||
|
|
||||||
Before you can start building the compiler you need to configure the build for
|
Before you can start building the compiler you need to configure the build for
|
||||||
your system. In most cases, that will just mean using the defaults provided
|
your system. In most cases, that will just mean using the defaults provided
|
||||||
for Rust. Configuring involves invoking the `configure` script in the project
|
for Rust.
|
||||||
root.
|
|
||||||
|
|
||||||
```
|
To change configuration, you must copy the file `src/bootstrap/config.toml.example`
|
||||||
./configure
|
to `config.toml` in the directory from which you will be running the build, and
|
||||||
```
|
change the settings provided.
|
||||||
|
|
||||||
There are large number of options accepted by this script to alter the
|
There are large number of options provided in this config file that will alter the
|
||||||
configuration used later in the build process. Some options to note:
|
configuration used in the build process. Some options to note:
|
||||||
|
|
||||||
- `--enable-debug` - Build a debug version of the compiler (disables optimizations,
|
#### `[llvm]`:
|
||||||
which speeds up compilation of stage1 rustc)
|
- `ccache = true` - Use ccache when building llvm
|
||||||
- `--enable-optimize` - Enable optimizations (can be used with `--enable-debug`
|
|
||||||
to make a debug build with optimizations)
|
|
||||||
- `--disable-valgrind-rpass` - Don't run tests with valgrind
|
|
||||||
- `--enable-clang` - Prefer clang to gcc for building dependencies (e.g., LLVM)
|
|
||||||
- `--enable-ccache` - Invoke clang/gcc with ccache to re-use object files between builds
|
|
||||||
- `--enable-compiler-docs` - Build compiler documentation
|
|
||||||
|
|
||||||
To see a full list of options, run `./configure --help`.
|
#### `[build]`:
|
||||||
|
- `compiler-docs = true` - Build compiler documentation
|
||||||
|
|
||||||
|
#### `[rust]`:
|
||||||
|
- `debuginfo = true` - Build a compiler with debuginfo
|
||||||
|
- `optimize = false` - Disable optimizations to speed up compilation of stage1 rust
|
||||||
|
|
||||||
|
For more options, the `config.toml` file contains commented out defaults, with
|
||||||
|
descriptions of what each option will do.
|
||||||
|
|
||||||
|
Note: Previously the `./configure` script was used to configure this
|
||||||
|
project. It can still be used, but it's recommended to use a `config.toml`
|
||||||
|
file. If you still have a `config.mk` file in your directory - from
|
||||||
|
`./configure` - you may need to delete it for `config.toml` to work.
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
Although the `./configure` script will generate a `Makefile`, this is actually
|
The build system uses the `x.py` script to control the build process. This script
|
||||||
just a thin veneer over the actual build system driver, `x.py`. This file, at
|
is used to build, test, and document various parts of the compiler. You can
|
||||||
the root of the repository, is used to build, test, and document various parts
|
execute it as:
|
||||||
of the compiler. You can execute it as:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
python x.py build
|
python x.py build
|
||||||
@ -185,6 +190,9 @@ To learn about all possible rules you can execute, run:
|
|||||||
python x.py build --help --verbose
|
python x.py build --help --verbose
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: Previously `./configure` and `make` were used to build this project.
|
||||||
|
They are still available, but `x.py` is the recommended build system.
|
||||||
|
|
||||||
### Useful commands
|
### Useful commands
|
||||||
|
|
||||||
Some common invocations of `x.py` are:
|
Some common invocations of `x.py` are:
|
||||||
@ -235,8 +243,8 @@ feature. We use the 'fork and pull' model described there.
|
|||||||
|
|
||||||
Please make pull requests against the `master` branch.
|
Please make pull requests against the `master` branch.
|
||||||
|
|
||||||
Compiling all of `make check` can take a while. When testing your pull request,
|
Compiling all of `./x.py test` can take a while. When testing your pull request,
|
||||||
consider using one of the more specialized `make` targets to cut down on the
|
consider using one of the more specialized `./x.py` targets to cut down on the
|
||||||
amount of time you have to wait. You need to have built the compiler at least
|
amount of time you have to wait. You need to have built the compiler at least
|
||||||
once before running these will work, but that’s only one full build rather than
|
once before running these will work, but that’s only one full build rather than
|
||||||
one each time.
|
one each time.
|
||||||
@ -307,7 +315,7 @@ To find documentation-related issues, sort by the [A-docs label][adocs].
|
|||||||
|
|
||||||
[adocs]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AA-docs
|
[adocs]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AA-docs
|
||||||
|
|
||||||
In many cases, you don't need a full `make doc`. You can use `rustdoc` directly
|
In many cases, you don't need a full `./x.py doc`. You can use `rustdoc` directly
|
||||||
to check small fixes. For example, `rustdoc src/doc/reference.md` will render
|
to check small fixes. For example, `rustdoc src/doc/reference.md` will render
|
||||||
reference to `doc/reference.html`. The CSS might be messed up, but you can
|
reference to `doc/reference.html`. The CSS might be messed up, but you can
|
||||||
verify that the HTML is right.
|
verify that the HTML is right.
|
||||||
|
59
README.md
59
README.md
@ -35,15 +35,15 @@ Read ["Installing Rust"] from [The Book].
|
|||||||
3. Build and install:
|
3. Build and install:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ ./configure
|
$ ./x.py build && sudo ./x.py dist --install
|
||||||
$ make && sudo make install
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> ***Note:*** Install locations can be adjusted by passing a `--prefix`
|
> ***Note:*** Install locations can be adjusted by copying the config file
|
||||||
> argument to `configure`. Various other options are also supported – pass
|
> from `./src/bootstrap/config.toml.example` to `./config.toml`, and
|
||||||
> `--help` for more information on them.
|
> adjusting the `prefix` option under `[install]`. Various other options are
|
||||||
|
> also supported, and are documented in the config file.
|
||||||
|
|
||||||
When complete, `sudo make install` will place several programs into
|
When complete, `sudo ./x.py dist --install` will place several programs into
|
||||||
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
|
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
|
||||||
API-documentation tool. This install does not include [Cargo],
|
API-documentation tool. This install does not include [Cargo],
|
||||||
Rust's package manager, which you may also want to build.
|
Rust's package manager, which you may also want to build.
|
||||||
@ -59,7 +59,6 @@ for interop with software produced by Visual Studio use the MSVC build of Rust;
|
|||||||
for interop with GNU software built using the MinGW/MSYS2 toolchain use the GNU
|
for interop with GNU software built using the MinGW/MSYS2 toolchain use the GNU
|
||||||
build.
|
build.
|
||||||
|
|
||||||
|
|
||||||
#### MinGW
|
#### MinGW
|
||||||
|
|
||||||
[MSYS2][msys2] can be used to easily build Rust on Windows:
|
[MSYS2][msys2] can be used to easily build Rust on Windows:
|
||||||
@ -94,11 +93,10 @@ build.
|
|||||||
mingw-w64-x86_64-gcc
|
mingw-w64-x86_64-gcc
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Navigate to Rust's source code (or clone it), then configure and build it:
|
4. Navigate to Rust's source code (or clone it), then build it:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ ./configure
|
$ ./x.py build && ./x.py dist --install
|
||||||
$ make && make install
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### MSVC
|
#### MSVC
|
||||||
@ -114,13 +112,6 @@ shell with:
|
|||||||
> python x.py build
|
> python x.py build
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're running inside of an msys shell, however, you can run:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ ./configure --build=x86_64-pc-windows-msvc
|
|
||||||
$ make && make install
|
|
||||||
```
|
|
||||||
|
|
||||||
Currently building Rust only works with some known versions of Visual Studio. If
|
Currently building Rust only works with some known versions of Visual Studio. If
|
||||||
you have a more recent version installed the build system doesn't understand
|
you have a more recent version installed the build system doesn't understand
|
||||||
then you may need to force rustbuild to use an older version. This can be done
|
then you may need to force rustbuild to use an older version. This can be done
|
||||||
@ -131,13 +122,43 @@ CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.
|
|||||||
python x.py build
|
python x.py build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Specifying an ABI
|
||||||
|
|
||||||
|
Each specific ABI can also be used from either environment (for example, using
|
||||||
|
the GNU ABI in powershell) by using an explicit build triple. The available
|
||||||
|
Windows build triples are:
|
||||||
|
- GNU ABI (using GCC)
|
||||||
|
- `i686-pc-windows-gnu`
|
||||||
|
- `x86_64-pc-windows-gnu`
|
||||||
|
- The MSVC ABI
|
||||||
|
- `i686-pc-windows-msvc`
|
||||||
|
- `x86_64-pc-windows-msvc`
|
||||||
|
|
||||||
|
The build triple can be specified by either specifying `--build=ABI` when
|
||||||
|
invoking `x.py` commands, or by copying the `config.toml` file (as described
|
||||||
|
in Building From Source), and modifying the `build` option under the `[build]`
|
||||||
|
section.
|
||||||
|
|
||||||
|
### Configure and Make
|
||||||
|
|
||||||
|
While it's not the recommended build system, this project also provides a
|
||||||
|
configure script and makefile (the latter of which just invokes `x.py`).
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ ./configure
|
||||||
|
$ make && sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
When using the configure script, the generated config.mk` file may override the
|
||||||
|
`config.toml` file. To go back to the `config.toml` file, delete the generated
|
||||||
|
`config.mk` file.
|
||||||
|
|
||||||
## Building Documentation
|
## Building Documentation
|
||||||
|
|
||||||
If you’d like to build the documentation, it’s almost the same:
|
If you’d like to build the documentation, it’s almost the same:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ ./configure
|
$ ./x.py doc
|
||||||
$ make docs
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The generated documentation will appear in a top-level `doc` directory,
|
The generated documentation will appear in a top-level `doc` directory,
|
||||||
|
@ -349,8 +349,8 @@ to it.
|
|||||||
|
|
||||||
## Lifetime Elision
|
## Lifetime Elision
|
||||||
|
|
||||||
Rust supports powerful local type inference in the bodies of functions but not in their item signatures.
|
Rust supports powerful local type inference in the bodies of functions, but it
|
||||||
It's forbidden to allow reasoning about types based on the item signature alone.
|
deliberately does not perform any reasoning about types for item signatures.
|
||||||
However, for ergonomic reasons, a very restricted secondary inference algorithm called
|
However, for ergonomic reasons, a very restricted secondary inference algorithm called
|
||||||
“lifetime elision” does apply when judging lifetimes. Lifetime elision is concerned solely with inferring
|
“lifetime elision” does apply when judging lifetimes. Lifetime elision is concerned solely with inferring
|
||||||
lifetime parameters using three easily memorizable and unambiguous rules. This means lifetime elision
|
lifetime parameters using three easily memorizable and unambiguous rules. This means lifetime elision
|
||||||
|
@ -128,7 +128,7 @@ pub fn hello_world(input: TokenStream) -> TokenStream {
|
|||||||
So there is a lot going on here. We have introduced two new crates: [`syn`] and
|
So there is a lot going on here. We have introduced two new crates: [`syn`] and
|
||||||
[`quote`]. As you may have noticed, `input: TokenSteam` is immediately converted
|
[`quote`]. As you may have noticed, `input: TokenSteam` is immediately converted
|
||||||
to a `String`. This `String` is a string representation of the Rust code for which
|
to a `String`. This `String` is a string representation of the Rust code for which
|
||||||
we are deriving `HelloWorld` for. At the moment, the only thing you can do with a
|
we are deriving `HelloWorld`. At the moment, the only thing you can do with a
|
||||||
`TokenStream` is convert it to a string. A richer API will exist in the future.
|
`TokenStream` is convert it to a string. A richer API will exist in the future.
|
||||||
|
|
||||||
So what we really need is to be able to _parse_ Rust code into something
|
So what we really need is to be able to _parse_ Rust code into something
|
||||||
|
@ -65,12 +65,15 @@ pub struct Error;
|
|||||||
/// A collection of methods that are required to format a message into a stream.
|
/// A collection of methods that are required to format a message into a stream.
|
||||||
///
|
///
|
||||||
/// This trait is the type which this modules requires when formatting
|
/// This trait is the type which this modules requires when formatting
|
||||||
/// information. This is similar to the standard library's `io::Write` trait,
|
/// information. This is similar to the standard library's [`io::Write`] trait,
|
||||||
/// but it is only intended for use in libcore.
|
/// but it is only intended for use in libcore.
|
||||||
///
|
///
|
||||||
/// This trait should generally not be implemented by consumers of the standard
|
/// This trait should generally not be implemented by consumers of the standard
|
||||||
/// library. The `write!` macro accepts an instance of `io::Write`, and the
|
/// library. The [`write!`] macro accepts an instance of [`io::Write`], and the
|
||||||
/// `io::Write` trait is favored over implementing this trait.
|
/// [`io::Write`] trait is favored over implementing this trait.
|
||||||
|
///
|
||||||
|
/// [`write!`]: ../../std/macro.write.html
|
||||||
|
/// [`io::Write`]: ../../std/io/trait.Write.html
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub trait Write {
|
pub trait Write {
|
||||||
/// Writes a slice of bytes into this writer, returning whether the write
|
/// Writes a slice of bytes into this writer, returning whether the write
|
||||||
@ -82,29 +85,79 @@ pub trait Write {
|
|||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// This function will return an instance of `Error` on error.
|
/// This function will return an instance of [`Error`] on error.
|
||||||
|
///
|
||||||
|
/// [`Error`]: struct.Error.html
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::fmt::{Error, Write};
|
||||||
|
///
|
||||||
|
/// fn writer<W: Write>(f: &mut W, s: &str) -> Result<(), Error> {
|
||||||
|
/// f.write_str(s)
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let mut buf = String::new();
|
||||||
|
/// writer(&mut buf, "hola").unwrap();
|
||||||
|
/// assert_eq!(&buf, "hola");
|
||||||
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
fn write_str(&mut self, s: &str) -> Result;
|
fn write_str(&mut self, s: &str) -> Result;
|
||||||
|
|
||||||
/// Writes a `char` into this writer, returning whether the write succeeded.
|
/// Writes a [`char`] into this writer, returning whether the write succeeded.
|
||||||
///
|
///
|
||||||
/// A single `char` may be encoded as more than one byte.
|
/// A single [`char`] may be encoded as more than one byte.
|
||||||
/// This method can only succeed if the entire byte sequence was successfully
|
/// This method can only succeed if the entire byte sequence was successfully
|
||||||
/// written, and this method will not return until all data has been
|
/// written, and this method will not return until all data has been
|
||||||
/// written or an error occurs.
|
/// written or an error occurs.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// This function will return an instance of `Error` on error.
|
/// This function will return an instance of [`Error`] on error.
|
||||||
|
///
|
||||||
|
/// [`char`]: ../../std/primitive.char.html
|
||||||
|
/// [`Error`]: struct.Error.html
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::fmt::{Error, Write};
|
||||||
|
///
|
||||||
|
/// fn writer<W: Write>(f: &mut W, c: char) -> Result<(), Error> {
|
||||||
|
/// f.write_char(c)
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let mut buf = String::new();
|
||||||
|
/// writer(&mut buf, 'a').unwrap();
|
||||||
|
/// writer(&mut buf, 'b').unwrap();
|
||||||
|
/// assert_eq!(&buf, "ab");
|
||||||
|
/// ```
|
||||||
#[stable(feature = "fmt_write_char", since = "1.1.0")]
|
#[stable(feature = "fmt_write_char", since = "1.1.0")]
|
||||||
fn write_char(&mut self, c: char) -> Result {
|
fn write_char(&mut self, c: char) -> Result {
|
||||||
self.write_str(c.encode_utf8(&mut [0; 4]))
|
self.write_str(c.encode_utf8(&mut [0; 4]))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Glue for usage of the `write!` macro with implementors of this trait.
|
/// Glue for usage of the [`write!`] macro with implementors of this trait.
|
||||||
///
|
///
|
||||||
/// This method should generally not be invoked manually, but rather through
|
/// This method should generally not be invoked manually, but rather through
|
||||||
/// the `write!` macro itself.
|
/// the [`write!`] macro itself.
|
||||||
|
///
|
||||||
|
/// [`write!`]: ../../std/macro.write.html
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::fmt::{Error, Write};
|
||||||
|
///
|
||||||
|
/// fn writer<W: Write>(f: &mut W, s: &str) -> Result<(), Error> {
|
||||||
|
/// f.write_fmt(format_args!("{}", s))
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let mut buf = String::new();
|
||||||
|
/// writer(&mut buf, "world").unwrap();
|
||||||
|
/// assert_eq!(&buf, "world");
|
||||||
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
fn write_fmt(&mut self, args: Arguments) -> Result {
|
fn write_fmt(&mut self, args: Arguments) -> Result {
|
||||||
// This Adapter is needed to allow `self` (of type `&mut
|
// This Adapter is needed to allow `self` (of type `&mut
|
||||||
|
@ -21,7 +21,6 @@ use super::{
|
|||||||
SelectionContext,
|
SelectionContext,
|
||||||
SelectionError,
|
SelectionError,
|
||||||
ObjectSafetyViolation,
|
ObjectSafetyViolation,
|
||||||
MethodViolationCode,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use fmt_macros::{Parser, Piece, Position};
|
use fmt_macros::{Parser, Piece, Position};
|
||||||
@ -267,61 +266,63 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
let span = obligation.cause.span;
|
let span = obligation.cause.span;
|
||||||
let mut report = None;
|
let mut report = None;
|
||||||
for item in self.tcx.get_attrs(def_id).iter() {
|
if let Some(item) = self.tcx
|
||||||
if item.check_name("rustc_on_unimplemented") {
|
.get_attrs(def_id)
|
||||||
let err_sp = item.meta().span.substitute_dummy(span);
|
.into_iter()
|
||||||
let trait_str = self.tcx.item_path_str(trait_ref.def_id);
|
.filter(|a| a.check_name("rustc_on_unimplemented"))
|
||||||
if let Some(istring) = item.value_str() {
|
.next()
|
||||||
let istring = &*istring.as_str();
|
{
|
||||||
let generics = self.tcx.item_generics(trait_ref.def_id);
|
let err_sp = item.meta().span.substitute_dummy(span);
|
||||||
let generic_map = generics.types.iter().map(|param| {
|
let trait_str = self.tcx.item_path_str(trait_ref.def_id);
|
||||||
(param.name.as_str().to_string(),
|
if let Some(istring) = item.value_str() {
|
||||||
trait_ref.substs.type_for_def(param).to_string())
|
let istring = &*istring.as_str();
|
||||||
}).collect::<FxHashMap<String, String>>();
|
let generics = self.tcx.item_generics(trait_ref.def_id);
|
||||||
let parser = Parser::new(istring);
|
let generic_map = generics.types.iter().map(|param| {
|
||||||
let mut errored = false;
|
(param.name.as_str().to_string(),
|
||||||
let err: String = parser.filter_map(|p| {
|
trait_ref.substs.type_for_def(param).to_string())
|
||||||
match p {
|
}).collect::<FxHashMap<String, String>>();
|
||||||
Piece::String(s) => Some(s),
|
let parser = Parser::new(istring);
|
||||||
Piece::NextArgument(a) => match a.position {
|
let mut errored = false;
|
||||||
Position::ArgumentNamed(s) => match generic_map.get(s) {
|
let err: String = parser.filter_map(|p| {
|
||||||
Some(val) => Some(val),
|
match p {
|
||||||
None => {
|
Piece::String(s) => Some(s),
|
||||||
span_err!(self.tcx.sess, err_sp, E0272,
|
Piece::NextArgument(a) => match a.position {
|
||||||
"the #[rustc_on_unimplemented] \
|
Position::ArgumentNamed(s) => match generic_map.get(s) {
|
||||||
attribute on \
|
Some(val) => Some(val),
|
||||||
trait definition for {} refers to \
|
None => {
|
||||||
non-existent type parameter {}",
|
span_err!(self.tcx.sess, err_sp, E0272,
|
||||||
trait_str, s);
|
"the #[rustc_on_unimplemented] \
|
||||||
errored = true;
|
attribute on \
|
||||||
None
|
trait definition for {} refers to \
|
||||||
}
|
non-existent type parameter {}",
|
||||||
},
|
trait_str, s);
|
||||||
_ => {
|
|
||||||
span_err!(self.tcx.sess, err_sp, E0273,
|
|
||||||
"the #[rustc_on_unimplemented] attribute \
|
|
||||||
on trait definition for {} must have \
|
|
||||||
named format arguments, eg \
|
|
||||||
`#[rustc_on_unimplemented = \
|
|
||||||
\"foo {{T}}\"]`", trait_str);
|
|
||||||
errored = true;
|
errored = true;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
span_err!(self.tcx.sess, err_sp, E0273,
|
||||||
|
"the #[rustc_on_unimplemented] attribute \
|
||||||
|
on trait definition for {} must have \
|
||||||
|
named format arguments, eg \
|
||||||
|
`#[rustc_on_unimplemented = \
|
||||||
|
\"foo {{T}}\"]`", trait_str);
|
||||||
|
errored = true;
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).collect();
|
|
||||||
// Report only if the format string checks out
|
|
||||||
if !errored {
|
|
||||||
report = Some(err);
|
|
||||||
}
|
}
|
||||||
} else {
|
}).collect();
|
||||||
span_err!(self.tcx.sess, err_sp, E0274,
|
// Report only if the format string checks out
|
||||||
"the #[rustc_on_unimplemented] attribute on \
|
if !errored {
|
||||||
trait definition for {} must have a value, \
|
report = Some(err);
|
||||||
eg `#[rustc_on_unimplemented = \"foo\"]`",
|
|
||||||
trait_str);
|
|
||||||
}
|
}
|
||||||
break;
|
} else {
|
||||||
|
span_err!(self.tcx.sess, err_sp, E0274,
|
||||||
|
"the #[rustc_on_unimplemented] attribute on \
|
||||||
|
trait definition for {} must have a value, \
|
||||||
|
eg `#[rustc_on_unimplemented = \"foo\"]`",
|
||||||
|
trait_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
report
|
report
|
||||||
@ -359,34 +360,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn report_similar_impl_candidates(&self,
|
fn report_similar_impl_candidates(&self,
|
||||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
impl_candidates: Vec<ty::TraitRef<'tcx>>,
|
||||||
err: &mut DiagnosticBuilder)
|
err: &mut DiagnosticBuilder)
|
||||||
{
|
{
|
||||||
let simp = fast_reject::simplify_type(self.tcx,
|
|
||||||
trait_ref.skip_binder().self_ty(),
|
|
||||||
true);
|
|
||||||
let mut impl_candidates = Vec::new();
|
|
||||||
let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id());
|
|
||||||
|
|
||||||
match simp {
|
|
||||||
Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| {
|
|
||||||
let imp = self.tcx.impl_trait_ref(def_id).unwrap();
|
|
||||||
let imp_simp = fast_reject::simplify_type(self.tcx,
|
|
||||||
imp.self_ty(),
|
|
||||||
true);
|
|
||||||
if let Some(imp_simp) = imp_simp {
|
|
||||||
if simp != imp_simp {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl_candidates.push(imp);
|
|
||||||
}),
|
|
||||||
None => trait_def.for_each_impl(self.tcx, |def_id| {
|
|
||||||
impl_candidates.push(
|
|
||||||
self.tcx.impl_trait_ref(def_id).unwrap());
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
if impl_candidates.is_empty() {
|
if impl_candidates.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -525,127 +501,118 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||||||
lint_id)
|
lint_id)
|
||||||
.emit();
|
.emit();
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
match obligation.predicate {
|
match obligation.predicate {
|
||||||
ty::Predicate::Trait(ref trait_predicate) => {
|
ty::Predicate::Trait(ref trait_predicate) => {
|
||||||
let trait_predicate =
|
let trait_predicate =
|
||||||
self.resolve_type_vars_if_possible(trait_predicate);
|
self.resolve_type_vars_if_possible(trait_predicate);
|
||||||
|
|
||||||
if self.tcx.sess.has_errors() && trait_predicate.references_error() {
|
if self.tcx.sess.has_errors() && trait_predicate.references_error() {
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
let trait_ref = trait_predicate.to_poly_trait_ref();
|
|
||||||
let (post_message, pre_message) = match self.get_parent_trait_ref(
|
|
||||||
&obligation.cause.code)
|
|
||||||
{
|
|
||||||
Some(t) => {
|
|
||||||
(format!(" in `{}`", t), format!("within `{}`, ", t))
|
|
||||||
}
|
|
||||||
None => (String::new(), String::new()),
|
|
||||||
};
|
|
||||||
let mut err = struct_span_err!(
|
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
|
||||||
E0277,
|
|
||||||
"the trait bound `{}` is not satisfied{}",
|
|
||||||
trait_ref.to_predicate(),
|
|
||||||
post_message);
|
|
||||||
err.span_label(span,
|
|
||||||
&format!("{}the trait `{}` is not \
|
|
||||||
implemented for `{}`",
|
|
||||||
pre_message,
|
|
||||||
trait_ref,
|
|
||||||
trait_ref.self_ty()));
|
|
||||||
|
|
||||||
// Try to report a help message
|
|
||||||
|
|
||||||
if !trait_ref.has_infer_types() &&
|
|
||||||
self.predicate_can_apply(trait_ref) {
|
|
||||||
// If a where-clause may be useful, remind the
|
|
||||||
// user that they can add it.
|
|
||||||
//
|
|
||||||
// don't display an on-unimplemented note, as
|
|
||||||
// these notes will often be of the form
|
|
||||||
// "the type `T` can't be frobnicated"
|
|
||||||
// which is somewhat confusing.
|
|
||||||
err.help(&format!("consider adding a `where {}` bound",
|
|
||||||
trait_ref.to_predicate()));
|
|
||||||
} else if let Some(s) = self.on_unimplemented_note(trait_ref,
|
|
||||||
obligation) {
|
|
||||||
// If it has a custom "#[rustc_on_unimplemented]"
|
|
||||||
// error message, let's display it!
|
|
||||||
err.note(&s);
|
|
||||||
} else {
|
|
||||||
// If we can't show anything useful, try to find
|
|
||||||
// similar impls.
|
|
||||||
let impl_candidates =
|
|
||||||
self.find_similar_impl_candidates(trait_ref);
|
|
||||||
if impl_candidates.len() > 0 {
|
|
||||||
self.report_similar_impl_candidates(trait_ref, &mut err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Predicate::Equate(ref predicate) => {
|
|
||||||
let predicate = self.resolve_type_vars_if_possible(predicate);
|
|
||||||
let err = self.equality_predicate(&obligation.cause,
|
|
||||||
&predicate).err().unwrap();
|
|
||||||
struct_span_err!(self.tcx.sess, span, E0278,
|
|
||||||
"the requirement `{}` is not satisfied (`{}`)",
|
|
||||||
predicate, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Predicate::RegionOutlives(ref predicate) => {
|
|
||||||
let predicate = self.resolve_type_vars_if_possible(predicate);
|
|
||||||
let err = self.region_outlives_predicate(&obligation.cause,
|
|
||||||
&predicate).err().unwrap();
|
|
||||||
struct_span_err!(self.tcx.sess, span, E0279,
|
|
||||||
"the requirement `{}` is not satisfied (`{}`)",
|
|
||||||
predicate, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
|
|
||||||
let predicate =
|
|
||||||
self.resolve_type_vars_if_possible(&obligation.predicate);
|
|
||||||
struct_span_err!(self.tcx.sess, span, E0280,
|
|
||||||
"the requirement `{}` is not satisfied",
|
|
||||||
predicate)
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Predicate::ObjectSafe(trait_def_id) => {
|
|
||||||
let violations = self.tcx.object_safety_violations(trait_def_id);
|
|
||||||
self.tcx.report_object_safety_error(span,
|
|
||||||
trait_def_id,
|
|
||||||
violations)
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Predicate::ClosureKind(closure_def_id, kind) => {
|
|
||||||
let found_kind = self.closure_kind(closure_def_id).unwrap();
|
|
||||||
let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
|
|
||||||
let mut err = struct_span_err!(
|
|
||||||
self.tcx.sess, closure_span, E0525,
|
|
||||||
"expected a closure that implements the `{}` trait, \
|
|
||||||
but this closure only implements `{}`",
|
|
||||||
kind,
|
|
||||||
found_kind);
|
|
||||||
err.span_note(
|
|
||||||
obligation.cause.span,
|
|
||||||
&format!("the requirement to implement \
|
|
||||||
`{}` derives from here", kind));
|
|
||||||
err.emit();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let trait_ref = trait_predicate.to_poly_trait_ref();
|
||||||
|
let (post_message, pre_message) =
|
||||||
|
self.get_parent_trait_ref(&obligation.cause.code)
|
||||||
|
.map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
|
||||||
|
.unwrap_or((String::new(), String::new()));
|
||||||
|
let mut err = struct_span_err!(
|
||||||
|
self.tcx.sess,
|
||||||
|
span,
|
||||||
|
E0277,
|
||||||
|
"the trait bound `{}` is not satisfied{}",
|
||||||
|
trait_ref.to_predicate(),
|
||||||
|
post_message);
|
||||||
|
err.span_label(span,
|
||||||
|
&format!("{}the trait `{}` is not \
|
||||||
|
implemented for `{}`",
|
||||||
|
pre_message,
|
||||||
|
trait_ref,
|
||||||
|
trait_ref.self_ty()));
|
||||||
|
|
||||||
ty::Predicate::WellFormed(ty) => {
|
// Try to report a help message
|
||||||
// WF predicates cannot themselves make
|
|
||||||
// errors. They can only block due to
|
if !trait_ref.has_infer_types() &&
|
||||||
// ambiguity; otherwise, they always
|
self.predicate_can_apply(trait_ref) {
|
||||||
// degenerate into other obligations
|
// If a where-clause may be useful, remind the
|
||||||
// (which may fail).
|
// user that they can add it.
|
||||||
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
|
//
|
||||||
|
// don't display an on-unimplemented note, as
|
||||||
|
// these notes will often be of the form
|
||||||
|
// "the type `T` can't be frobnicated"
|
||||||
|
// which is somewhat confusing.
|
||||||
|
err.help(&format!("consider adding a `where {}` bound",
|
||||||
|
trait_ref.to_predicate()));
|
||||||
|
} else if let Some(s) = self.on_unimplemented_note(trait_ref,
|
||||||
|
obligation) {
|
||||||
|
// If it has a custom "#[rustc_on_unimplemented]"
|
||||||
|
// error message, let's display it!
|
||||||
|
err.note(&s);
|
||||||
|
} else {
|
||||||
|
// If we can't show anything useful, try to find
|
||||||
|
// similar impls.
|
||||||
|
let impl_candidates = self.find_similar_impl_candidates(trait_ref);
|
||||||
|
self.report_similar_impl_candidates(impl_candidates, &mut err);
|
||||||
}
|
}
|
||||||
|
err
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Predicate::Equate(ref predicate) => {
|
||||||
|
let predicate = self.resolve_type_vars_if_possible(predicate);
|
||||||
|
let err = self.equality_predicate(&obligation.cause,
|
||||||
|
&predicate).err().unwrap();
|
||||||
|
struct_span_err!(self.tcx.sess, span, E0278,
|
||||||
|
"the requirement `{}` is not satisfied (`{}`)",
|
||||||
|
predicate, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Predicate::RegionOutlives(ref predicate) => {
|
||||||
|
let predicate = self.resolve_type_vars_if_possible(predicate);
|
||||||
|
let err = self.region_outlives_predicate(&obligation.cause,
|
||||||
|
&predicate).err().unwrap();
|
||||||
|
struct_span_err!(self.tcx.sess, span, E0279,
|
||||||
|
"the requirement `{}` is not satisfied (`{}`)",
|
||||||
|
predicate, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
|
||||||
|
let predicate =
|
||||||
|
self.resolve_type_vars_if_possible(&obligation.predicate);
|
||||||
|
struct_span_err!(self.tcx.sess, span, E0280,
|
||||||
|
"the requirement `{}` is not satisfied",
|
||||||
|
predicate)
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Predicate::ObjectSafe(trait_def_id) => {
|
||||||
|
let violations = self.tcx.object_safety_violations(trait_def_id);
|
||||||
|
self.tcx.report_object_safety_error(span,
|
||||||
|
trait_def_id,
|
||||||
|
violations)
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Predicate::ClosureKind(closure_def_id, kind) => {
|
||||||
|
let found_kind = self.closure_kind(closure_def_id).unwrap();
|
||||||
|
let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
|
||||||
|
let mut err = struct_span_err!(
|
||||||
|
self.tcx.sess, closure_span, E0525,
|
||||||
|
"expected a closure that implements the `{}` trait, \
|
||||||
|
but this closure only implements `{}`",
|
||||||
|
kind,
|
||||||
|
found_kind);
|
||||||
|
err.span_note(
|
||||||
|
obligation.cause.span,
|
||||||
|
&format!("the requirement to implement \
|
||||||
|
`{}` derives from here", kind));
|
||||||
|
err.emit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Predicate::WellFormed(ty) => {
|
||||||
|
// WF predicates cannot themselves make
|
||||||
|
// errors. They can only block due to
|
||||||
|
// ambiguity; otherwise, they always
|
||||||
|
// degenerate into other obligations
|
||||||
|
// (which may fail).
|
||||||
|
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -713,38 +680,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||||||
if !reported_violations.insert(violation.clone()) {
|
if !reported_violations.insert(violation.clone()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let buf;
|
err.note(&violation.error_msg());
|
||||||
let note = match violation {
|
|
||||||
ObjectSafetyViolation::SizedSelf => {
|
|
||||||
"the trait cannot require that `Self : Sized`"
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectSafetyViolation::SupertraitSelf => {
|
|
||||||
"the trait cannot use `Self` as a type parameter \
|
|
||||||
in the supertrait listing"
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectSafetyViolation::Method(name,
|
|
||||||
MethodViolationCode::StaticMethod) => {
|
|
||||||
buf = format!("method `{}` has no receiver", name);
|
|
||||||
&buf
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectSafetyViolation::Method(name,
|
|
||||||
MethodViolationCode::ReferencesSelf) => {
|
|
||||||
buf = format!("method `{}` references the `Self` type \
|
|
||||||
in its arguments or return type",
|
|
||||||
name);
|
|
||||||
&buf
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectSafetyViolation::Method(name,
|
|
||||||
MethodViolationCode::Generic) => {
|
|
||||||
buf = format!("method `{}` has generic type parameters", name);
|
|
||||||
&buf
|
|
||||||
}
|
|
||||||
};
|
|
||||||
err.note(note);
|
|
||||||
}
|
}
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
@ -774,46 +710,46 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||||||
let trait_ref = data.to_poly_trait_ref();
|
let trait_ref = data.to_poly_trait_ref();
|
||||||
let self_ty = trait_ref.self_ty();
|
let self_ty = trait_ref.self_ty();
|
||||||
if predicate.references_error() {
|
if predicate.references_error() {
|
||||||
} else {
|
return;
|
||||||
// Typically, this ambiguity should only happen if
|
}
|
||||||
// there are unresolved type inference variables
|
// Typically, this ambiguity should only happen if
|
||||||
// (otherwise it would suggest a coherence
|
// there are unresolved type inference variables
|
||||||
// failure). But given #21974 that is not necessarily
|
// (otherwise it would suggest a coherence
|
||||||
// the case -- we can have multiple where clauses that
|
// failure). But given #21974 that is not necessarily
|
||||||
// are only distinguished by a region, which results
|
// the case -- we can have multiple where clauses that
|
||||||
// in an ambiguity even when all types are fully
|
// are only distinguished by a region, which results
|
||||||
// known, since we don't dispatch based on region
|
// in an ambiguity even when all types are fully
|
||||||
// relationships.
|
// known, since we don't dispatch based on region
|
||||||
|
// relationships.
|
||||||
|
|
||||||
// This is kind of a hack: it frequently happens that some earlier
|
// This is kind of a hack: it frequently happens that some earlier
|
||||||
// error prevents types from being fully inferred, and then we get
|
// error prevents types from being fully inferred, and then we get
|
||||||
// a bunch of uninteresting errors saying something like "<generic
|
// a bunch of uninteresting errors saying something like "<generic
|
||||||
// #0> doesn't implement Sized". It may even be true that we
|
// #0> doesn't implement Sized". It may even be true that we
|
||||||
// could just skip over all checks where the self-ty is an
|
// could just skip over all checks where the self-ty is an
|
||||||
// inference variable, but I was afraid that there might be an
|
// inference variable, but I was afraid that there might be an
|
||||||
// inference variable created, registered as an obligation, and
|
// inference variable created, registered as an obligation, and
|
||||||
// then never forced by writeback, and hence by skipping here we'd
|
// then never forced by writeback, and hence by skipping here we'd
|
||||||
// be ignoring the fact that we don't KNOW the type works
|
// be ignoring the fact that we don't KNOW the type works
|
||||||
// out. Though even that would probably be harmless, given that
|
// out. Though even that would probably be harmless, given that
|
||||||
// we're only talking about builtin traits, which are known to be
|
// we're only talking about builtin traits, which are known to be
|
||||||
// inhabited. But in any case I just threw in this check for
|
// inhabited. But in any case I just threw in this check for
|
||||||
// has_errors() to be sure that compilation isn't happening
|
// has_errors() to be sure that compilation isn't happening
|
||||||
// anyway. In that case, why inundate the user.
|
// anyway. In that case, why inundate the user.
|
||||||
if !self.tcx.sess.has_errors() {
|
if !self.tcx.sess.has_errors() {
|
||||||
if
|
if
|
||||||
self.tcx.lang_items.sized_trait()
|
self.tcx.lang_items.sized_trait()
|
||||||
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
|
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
|
||||||
{
|
{
|
||||||
self.need_type_info(obligation, self_ty);
|
self.need_type_info(obligation, self_ty);
|
||||||
} else {
|
} else {
|
||||||
let mut err = struct_span_err!(self.tcx.sess,
|
let mut err = struct_span_err!(self.tcx.sess,
|
||||||
obligation.cause.span, E0283,
|
obligation.cause.span, E0283,
|
||||||
"type annotations required: \
|
"type annotations required: \
|
||||||
cannot resolve `{}`",
|
cannot resolve `{}`",
|
||||||
predicate);
|
predicate);
|
||||||
self.note_obligation_cause(&mut err, obligation);
|
self.note_obligation_cause(&mut err, obligation);
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ use hir::def_id::DefId;
|
|||||||
use traits;
|
use traits;
|
||||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
use ty::subst::Substs;
|
use ty::subst::Substs;
|
||||||
|
use std::borrow::Cow;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
@ -38,6 +39,25 @@ pub enum ObjectSafetyViolation {
|
|||||||
Method(ast::Name, MethodViolationCode),
|
Method(ast::Name, MethodViolationCode),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ObjectSafetyViolation {
|
||||||
|
pub fn error_msg(&self) -> Cow<'static, str> {
|
||||||
|
match *self {
|
||||||
|
ObjectSafetyViolation::SizedSelf =>
|
||||||
|
"the trait cannot require that `Self : Sized`".into(),
|
||||||
|
ObjectSafetyViolation::SupertraitSelf =>
|
||||||
|
"the trait cannot use `Self` as a type parameter \
|
||||||
|
in the supertrait listing".into(),
|
||||||
|
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod) =>
|
||||||
|
format!("method `{}` has no receiver", name).into(),
|
||||||
|
ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) =>
|
||||||
|
format!("method `{}` references the `Self` type \
|
||||||
|
in its arguments or return type", name).into(),
|
||||||
|
ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
|
||||||
|
format!("method `{}` has generic type parameters", name).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Reasons a method might not be object-safe.
|
/// Reasons a method might not be object-safe.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum MethodViolationCode {
|
pub enum MethodViolationCode {
|
||||||
|
@ -1097,24 +1097,6 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TraitRef<'tcx> {
|
|
||||||
pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> TraitRef<'tcx> {
|
|
||||||
TraitRef { def_id: def_id, substs: substs }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn self_ty(&self) -> Ty<'tcx> {
|
|
||||||
self.substs.type_at(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
|
|
||||||
// Select only the "input types" from a trait-reference. For
|
|
||||||
// now this is all the types that appear in the
|
|
||||||
// trait-reference, but it should eventually exclude
|
|
||||||
// associated types.
|
|
||||||
self.substs.types()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// When type checking, we use the `ParameterEnvironment` to track
|
/// When type checking, we use the `ParameterEnvironment` to track
|
||||||
/// details about the type/lifetime parameters that are in scope.
|
/// details about the type/lifetime parameters that are in scope.
|
||||||
/// It primarily stores the bounds information.
|
/// It primarily stores the bounds information.
|
||||||
|
@ -389,6 +389,24 @@ pub struct TraitRef<'tcx> {
|
|||||||
pub substs: &'tcx Substs<'tcx>,
|
pub substs: &'tcx Substs<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TraitRef<'tcx> {
|
||||||
|
pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> TraitRef<'tcx> {
|
||||||
|
TraitRef { def_id: def_id, substs: substs }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn self_ty(&self) -> Ty<'tcx> {
|
||||||
|
self.substs.type_at(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
|
||||||
|
// Select only the "input types" from a trait-reference. For
|
||||||
|
// now this is all the types that appear in the
|
||||||
|
// trait-reference, but it should eventually exclude
|
||||||
|
// associated types.
|
||||||
|
self.substs.types()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>;
|
pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>;
|
||||||
|
|
||||||
impl<'tcx> PolyTraitRef<'tcx> {
|
impl<'tcx> PolyTraitRef<'tcx> {
|
||||||
|
@ -1878,7 +1878,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
|
|||||||
&cx.shared.issue_tracker_base_url,
|
&cx.shared.issue_tracker_base_url,
|
||||||
stab.issue) {
|
stab.issue) {
|
||||||
(true, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
|
(true, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
|
||||||
format!(" (<code>{}</code> <a href=\"{}{}\">#{}</a>)",
|
format!(" (<code>{} </code><a href=\"{}{}\">#{}</a>)",
|
||||||
Escape(&stab.feature), tracker_url, issue_no, issue_no),
|
Escape(&stab.feature), tracker_url, issue_no, issue_no),
|
||||||
(false, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
|
(false, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
|
||||||
format!(" (<a href=\"{}{}\">#{}</a>)", Escape(&tracker_url), issue_no,
|
format!(" (<a href=\"{}{}\">#{}</a>)", Escape(&tracker_url), issue_no,
|
||||||
@ -1890,12 +1890,12 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
|
|||||||
if stab.unstable_reason.is_empty() {
|
if stab.unstable_reason.is_empty() {
|
||||||
stability.push(format!("<div class='stab unstable'>\
|
stability.push(format!("<div class='stab unstable'>\
|
||||||
<span class=microscope>🔬</span> \
|
<span class=microscope>🔬</span> \
|
||||||
This is a nightly-only experimental API. {}\
|
This is a nightly-only experimental API. {}\
|
||||||
</div>",
|
</div>",
|
||||||
unstable_extra));
|
unstable_extra));
|
||||||
} else {
|
} else {
|
||||||
let text = format!("<summary><span class=microscope>🔬</span> \
|
let text = format!("<summary><span class=microscope>🔬</span> \
|
||||||
This is a nightly-only experimental API. {}\
|
This is a nightly-only experimental API. {}\
|
||||||
</summary>{}",
|
</summary>{}",
|
||||||
unstable_extra, MarkdownHtml(&stab.unstable_reason));
|
unstable_extra, MarkdownHtml(&stab.unstable_reason));
|
||||||
stability.push(format!("<div class='stab unstable'><details>{}</details></div>",
|
stability.push(format!("<div class='stab unstable'><details>{}</details></div>",
|
||||||
|
@ -27,6 +27,31 @@
|
|||||||
//!
|
//!
|
||||||
//! assert!(ecode.success());
|
//! assert!(ecode.success());
|
||||||
//! ```
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Calling a command with input and reading its output:
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! use std::process::{Command, Stdio};
|
||||||
|
//! use std::io::Write;
|
||||||
|
//!
|
||||||
|
//! let mut child = Command::new("/bin/cat")
|
||||||
|
//! .stdin(Stdio::piped())
|
||||||
|
//! .stdout(Stdio::piped())
|
||||||
|
//! .spawn()
|
||||||
|
//! .expect("failed to execute child");
|
||||||
|
//!
|
||||||
|
//! {
|
||||||
|
//! // limited borrow of stdin
|
||||||
|
//! let stdin = child.stdin.as_mut().expect("failed to get stdin");
|
||||||
|
//! stdin.write_all(b"test").expect("failed to write to stdin");
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! let output = child
|
||||||
|
//! .wait_with_output()
|
||||||
|
//! .expect("failed to wait on child");
|
||||||
|
//!
|
||||||
|
//! assert_eq!(b"test", output.stdout.as_slice());
|
||||||
|
//! ```
|
||||||
|
|
||||||
#![stable(feature = "process", since = "1.0.0")]
|
#![stable(feature = "process", since = "1.0.0")]
|
||||||
|
|
||||||
|
@ -18,12 +18,57 @@ use time::Duration;
|
|||||||
|
|
||||||
/// A type indicating whether a timed wait on a condition variable returned
|
/// A type indicating whether a timed wait on a condition variable returned
|
||||||
/// due to a time out or not.
|
/// due to a time out or not.
|
||||||
|
///
|
||||||
|
/// It is returned by the [`wait_timeout`] method.
|
||||||
|
///
|
||||||
|
/// [`wait_timeout`]: struct.Condvar.html#method.wait_timeout
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
#[stable(feature = "wait_timeout", since = "1.5.0")]
|
#[stable(feature = "wait_timeout", since = "1.5.0")]
|
||||||
pub struct WaitTimeoutResult(bool);
|
pub struct WaitTimeoutResult(bool);
|
||||||
|
|
||||||
impl WaitTimeoutResult {
|
impl WaitTimeoutResult {
|
||||||
/// Returns whether the wait was known to have timed out.
|
/// Returns whether the wait was known to have timed out.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// This example spawns a thread which will update the boolean value and
|
||||||
|
/// then wait 100 milliseconds before notifying the condvar.
|
||||||
|
///
|
||||||
|
/// The main thread will wait with a timeout on the condvar and then leave
|
||||||
|
/// once the boolean has been updated and notified.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::sync::{Arc, Mutex, Condvar};
|
||||||
|
/// use std::thread;
|
||||||
|
/// use std::time::Duration;
|
||||||
|
///
|
||||||
|
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
|
/// let pair2 = pair.clone();
|
||||||
|
///
|
||||||
|
/// thread::spawn(move|| {
|
||||||
|
/// let &(ref lock, ref cvar) = &*pair2;
|
||||||
|
/// let mut started = lock.lock().unwrap();
|
||||||
|
/// // We update the boolean value.
|
||||||
|
/// *started = true;
|
||||||
|
/// // Let's wait 20 milliseconds before notifying the condvar.
|
||||||
|
/// thread::sleep(Duration::from_millis(20));
|
||||||
|
/// cvar.notify_one();
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// // Wait for the thread to start up.
|
||||||
|
/// let &(ref lock, ref cvar) = &*pair;
|
||||||
|
/// let mut started = lock.lock().unwrap();
|
||||||
|
/// loop {
|
||||||
|
/// // Let's put a timeout on the condvar's wait.
|
||||||
|
/// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
|
||||||
|
/// // 10 milliseconds have passed, or maybe the value changed!
|
||||||
|
/// started = result.0;
|
||||||
|
/// if *started == true {
|
||||||
|
/// // We received the notification and the value has been updated, we can leave.
|
||||||
|
/// break
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[stable(feature = "wait_timeout", since = "1.5.0")]
|
#[stable(feature = "wait_timeout", since = "1.5.0")]
|
||||||
pub fn timed_out(&self) -> bool {
|
pub fn timed_out(&self) -> bool {
|
||||||
self.0
|
self.0
|
||||||
@ -55,15 +100,16 @@ impl WaitTimeoutResult {
|
|||||||
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
|
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
/// let pair2 = pair.clone();
|
/// let pair2 = pair.clone();
|
||||||
///
|
///
|
||||||
/// // Inside of our lock, spawn a new thread, and then wait for it to start
|
/// // Inside of our lock, spawn a new thread, and then wait for it to start.
|
||||||
/// thread::spawn(move|| {
|
/// thread::spawn(move|| {
|
||||||
/// let &(ref lock, ref cvar) = &*pair2;
|
/// let &(ref lock, ref cvar) = &*pair2;
|
||||||
/// let mut started = lock.lock().unwrap();
|
/// let mut started = lock.lock().unwrap();
|
||||||
/// *started = true;
|
/// *started = true;
|
||||||
|
/// // We notify the condvar that the value has changed.
|
||||||
/// cvar.notify_one();
|
/// cvar.notify_one();
|
||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
/// // wait for the thread to start up
|
/// // Wait for the thread to start up.
|
||||||
/// let &(ref lock, ref cvar) = &*pair;
|
/// let &(ref lock, ref cvar) = &*pair;
|
||||||
/// let mut started = lock.lock().unwrap();
|
/// let mut started = lock.lock().unwrap();
|
||||||
/// while !*started {
|
/// while !*started {
|
||||||
@ -79,6 +125,14 @@ pub struct Condvar {
|
|||||||
impl Condvar {
|
impl Condvar {
|
||||||
/// Creates a new condition variable which is ready to be waited on and
|
/// Creates a new condition variable which is ready to be waited on and
|
||||||
/// notified.
|
/// notified.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::sync::Condvar;
|
||||||
|
///
|
||||||
|
/// let condvar = Condvar::new();
|
||||||
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn new() -> Condvar {
|
pub fn new() -> Condvar {
|
||||||
let mut c = Condvar {
|
let mut c = Condvar {
|
||||||
@ -95,10 +149,10 @@ impl Condvar {
|
|||||||
/// notification.
|
/// notification.
|
||||||
///
|
///
|
||||||
/// This function will atomically unlock the mutex specified (represented by
|
/// This function will atomically unlock the mutex specified (represented by
|
||||||
/// `mutex_guard`) and block the current thread. This means that any calls
|
/// `guard`) and block the current thread. This means that any calls
|
||||||
/// to `notify_*()` which happen logically after the mutex is unlocked are
|
/// to [`notify_one()`] or [`notify_all()`] which happen logically after the
|
||||||
/// candidates to wake this thread up. When this function call returns, the
|
/// mutex is unlocked are candidates to wake this thread up. When this
|
||||||
/// lock specified will have been re-acquired.
|
/// function call returns, the lock specified will have been re-acquired.
|
||||||
///
|
///
|
||||||
/// Note that this function is susceptible to spurious wakeups. Condition
|
/// Note that this function is susceptible to spurious wakeups. Condition
|
||||||
/// variables normally have a boolean predicate associated with them, and
|
/// variables normally have a boolean predicate associated with them, and
|
||||||
@ -109,14 +163,46 @@ impl Condvar {
|
|||||||
///
|
///
|
||||||
/// This function will return an error if the mutex being waited on is
|
/// This function will return an error if the mutex being waited on is
|
||||||
/// poisoned when this thread re-acquires the lock. For more information,
|
/// poisoned when this thread re-acquires the lock. For more information,
|
||||||
/// see information about poisoning on the Mutex type.
|
/// see information about [poisoning] on the [`Mutex`] type.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// This function will `panic!()` if it is used with more than one mutex
|
/// This function will [`panic!()`] if it is used with more than one mutex
|
||||||
/// over time. Each condition variable is dynamically bound to exactly one
|
/// over time. Each condition variable is dynamically bound to exactly one
|
||||||
/// mutex to ensure defined behavior across platforms. If this functionality
|
/// mutex to ensure defined behavior across platforms. If this functionality
|
||||||
/// is not desired, then unsafe primitives in `sys` are provided.
|
/// is not desired, then unsafe primitives in `sys` are provided.
|
||||||
|
///
|
||||||
|
/// [`notify_one()`]: #method.notify_one
|
||||||
|
/// [`notify_all()`]: #method.notify_all
|
||||||
|
/// [poisoning]: ../sync/struct.Mutex.html#poisoning
|
||||||
|
/// [`Mutex`]: ../sync/struct.Mutex.html
|
||||||
|
/// [`panic!()`]: ../../std/macro.panic.html
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::sync::{Arc, Mutex, Condvar};
|
||||||
|
/// use std::thread;
|
||||||
|
///
|
||||||
|
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
|
/// let pair2 = pair.clone();
|
||||||
|
///
|
||||||
|
/// thread::spawn(move|| {
|
||||||
|
/// let &(ref lock, ref cvar) = &*pair2;
|
||||||
|
/// let mut started = lock.lock().unwrap();
|
||||||
|
/// *started = true;
|
||||||
|
/// // We notify the condvar that the value has changed.
|
||||||
|
/// cvar.notify_one();
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// // Wait for the thread to start up.
|
||||||
|
/// let &(ref lock, ref cvar) = &*pair;
|
||||||
|
/// let mut started = lock.lock().unwrap();
|
||||||
|
/// // As long as the value inside the `Mutex` is false, we wait.
|
||||||
|
/// while !*started {
|
||||||
|
/// started = cvar.wait(started).unwrap();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>)
|
pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>)
|
||||||
-> LockResult<MutexGuard<'a, T>> {
|
-> LockResult<MutexGuard<'a, T>> {
|
||||||
@ -136,7 +222,7 @@ impl Condvar {
|
|||||||
/// Waits on this condition variable for a notification, timing out after a
|
/// Waits on this condition variable for a notification, timing out after a
|
||||||
/// specified duration.
|
/// specified duration.
|
||||||
///
|
///
|
||||||
/// The semantics of this function are equivalent to `wait()`
|
/// The semantics of this function are equivalent to [`wait`]
|
||||||
/// except that the thread will be blocked for roughly no longer
|
/// except that the thread will be blocked for roughly no longer
|
||||||
/// than `ms` milliseconds. This method should not be used for
|
/// than `ms` milliseconds. This method should not be used for
|
||||||
/// precise timing due to anomalies such as preemption or platform
|
/// precise timing due to anomalies such as preemption or platform
|
||||||
@ -150,8 +236,42 @@ impl Condvar {
|
|||||||
/// The returned boolean is `false` only if the timeout is known
|
/// The returned boolean is `false` only if the timeout is known
|
||||||
/// to have elapsed.
|
/// to have elapsed.
|
||||||
///
|
///
|
||||||
/// Like `wait`, the lock specified will be re-acquired when this function
|
/// Like [`wait`], the lock specified will be re-acquired when this function
|
||||||
/// returns, regardless of whether the timeout elapsed or not.
|
/// returns, regardless of whether the timeout elapsed or not.
|
||||||
|
///
|
||||||
|
/// [`wait`]: #method.wait
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::sync::{Arc, Mutex, Condvar};
|
||||||
|
/// use std::thread;
|
||||||
|
///
|
||||||
|
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
|
/// let pair2 = pair.clone();
|
||||||
|
///
|
||||||
|
/// thread::spawn(move|| {
|
||||||
|
/// let &(ref lock, ref cvar) = &*pair2;
|
||||||
|
/// let mut started = lock.lock().unwrap();
|
||||||
|
/// *started = true;
|
||||||
|
/// // We notify the condvar that the value has changed.
|
||||||
|
/// cvar.notify_one();
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// // Wait for the thread to start up.
|
||||||
|
/// let &(ref lock, ref cvar) = &*pair;
|
||||||
|
/// let mut started = lock.lock().unwrap();
|
||||||
|
/// // As long as the value inside the `Mutex` is false, we wait.
|
||||||
|
/// loop {
|
||||||
|
/// let result = cvar.wait_timeout_ms(started, 10).unwrap();
|
||||||
|
/// // 10 milliseconds have passed, or maybe the value changed!
|
||||||
|
/// started = result.0;
|
||||||
|
/// if *started == true {
|
||||||
|
/// // We received the notification and the value has been updated, we can leave.
|
||||||
|
/// break
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")]
|
#[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")]
|
||||||
pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
|
pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
|
||||||
@ -165,7 +285,7 @@ impl Condvar {
|
|||||||
/// Waits on this condition variable for a notification, timing out after a
|
/// Waits on this condition variable for a notification, timing out after a
|
||||||
/// specified duration.
|
/// specified duration.
|
||||||
///
|
///
|
||||||
/// The semantics of this function are equivalent to `wait()` except that
|
/// The semantics of this function are equivalent to [`wait`] except that
|
||||||
/// the thread will be blocked for roughly no longer than `dur`. This
|
/// the thread will be blocked for roughly no longer than `dur`. This
|
||||||
/// method should not be used for precise timing due to anomalies such as
|
/// method should not be used for precise timing due to anomalies such as
|
||||||
/// preemption or platform differences that may not cause the maximum
|
/// preemption or platform differences that may not cause the maximum
|
||||||
@ -175,11 +295,47 @@ impl Condvar {
|
|||||||
/// measured with a monotonic clock, and not affected by the changes made to
|
/// measured with a monotonic clock, and not affected by the changes made to
|
||||||
/// the system time.
|
/// the system time.
|
||||||
///
|
///
|
||||||
/// The returned `WaitTimeoutResult` value indicates if the timeout is
|
/// The returned [`WaitTimeoutResult`] value indicates if the timeout is
|
||||||
/// known to have elapsed.
|
/// known to have elapsed.
|
||||||
///
|
///
|
||||||
/// Like `wait`, the lock specified will be re-acquired when this function
|
/// Like [`wait`], the lock specified will be re-acquired when this function
|
||||||
/// returns, regardless of whether the timeout elapsed or not.
|
/// returns, regardless of whether the timeout elapsed or not.
|
||||||
|
///
|
||||||
|
/// [`wait`]: #method.wait
|
||||||
|
/// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::sync::{Arc, Mutex, Condvar};
|
||||||
|
/// use std::thread;
|
||||||
|
/// use std::time::Duration;
|
||||||
|
///
|
||||||
|
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
|
/// let pair2 = pair.clone();
|
||||||
|
///
|
||||||
|
/// thread::spawn(move|| {
|
||||||
|
/// let &(ref lock, ref cvar) = &*pair2;
|
||||||
|
/// let mut started = lock.lock().unwrap();
|
||||||
|
/// *started = true;
|
||||||
|
/// // We notify the condvar that the value has changed.
|
||||||
|
/// cvar.notify_one();
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// // wait for the thread to start up
|
||||||
|
/// let &(ref lock, ref cvar) = &*pair;
|
||||||
|
/// let mut started = lock.lock().unwrap();
|
||||||
|
/// // as long as the value inside the `Mutex` is false, we wait
|
||||||
|
/// loop {
|
||||||
|
/// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
|
||||||
|
/// // 10 milliseconds have passed, or maybe the value changed!
|
||||||
|
/// started = result.0;
|
||||||
|
/// if *started == true {
|
||||||
|
/// // We received the notification and the value has been updated, we can leave.
|
||||||
|
/// break
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[stable(feature = "wait_timeout", since = "1.5.0")]
|
#[stable(feature = "wait_timeout", since = "1.5.0")]
|
||||||
pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
|
pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
|
||||||
dur: Duration)
|
dur: Duration)
|
||||||
@ -200,10 +356,40 @@ impl Condvar {
|
|||||||
/// Wakes up one blocked thread on this condvar.
|
/// Wakes up one blocked thread on this condvar.
|
||||||
///
|
///
|
||||||
/// If there is a blocked thread on this condition variable, then it will
|
/// If there is a blocked thread on this condition variable, then it will
|
||||||
/// be woken up from its call to `wait` or `wait_timeout`. Calls to
|
/// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
|
||||||
/// `notify_one` are not buffered in any way.
|
/// `notify_one` are not buffered in any way.
|
||||||
///
|
///
|
||||||
/// To wake up all threads, see `notify_all()`.
|
/// To wake up all threads, see [`notify_all()`].
|
||||||
|
///
|
||||||
|
/// [`wait`]: #method.wait
|
||||||
|
/// [`wait_timeout`]: #method.wait_timeout
|
||||||
|
/// [`notify_all()`]: #method.notify_all
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::sync::{Arc, Mutex, Condvar};
|
||||||
|
/// use std::thread;
|
||||||
|
///
|
||||||
|
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
|
/// let pair2 = pair.clone();
|
||||||
|
///
|
||||||
|
/// thread::spawn(move|| {
|
||||||
|
/// let &(ref lock, ref cvar) = &*pair2;
|
||||||
|
/// let mut started = lock.lock().unwrap();
|
||||||
|
/// *started = true;
|
||||||
|
/// // We notify the condvar that the value has changed.
|
||||||
|
/// cvar.notify_one();
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// // Wait for the thread to start up.
|
||||||
|
/// let &(ref lock, ref cvar) = &*pair;
|
||||||
|
/// let mut started = lock.lock().unwrap();
|
||||||
|
/// // As long as the value inside the `Mutex` is false, we wait.
|
||||||
|
/// while !*started {
|
||||||
|
/// started = cvar.wait(started).unwrap();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn notify_one(&self) {
|
pub fn notify_one(&self) {
|
||||||
unsafe { self.inner.notify_one() }
|
unsafe { self.inner.notify_one() }
|
||||||
@ -215,7 +401,35 @@ impl Condvar {
|
|||||||
/// variable are awoken. Calls to `notify_all()` are not buffered in any
|
/// variable are awoken. Calls to `notify_all()` are not buffered in any
|
||||||
/// way.
|
/// way.
|
||||||
///
|
///
|
||||||
/// To wake up only one thread, see `notify_one()`.
|
/// To wake up only one thread, see [`notify_one()`].
|
||||||
|
///
|
||||||
|
/// [`notify_one()`]: #method.notify_one
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::sync::{Arc, Mutex, Condvar};
|
||||||
|
/// use std::thread;
|
||||||
|
///
|
||||||
|
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
|
/// let pair2 = pair.clone();
|
||||||
|
///
|
||||||
|
/// thread::spawn(move|| {
|
||||||
|
/// let &(ref lock, ref cvar) = &*pair2;
|
||||||
|
/// let mut started = lock.lock().unwrap();
|
||||||
|
/// *started = true;
|
||||||
|
/// // We notify the condvar that the value has changed.
|
||||||
|
/// cvar.notify_all();
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// // Wait for the thread to start up.
|
||||||
|
/// let &(ref lock, ref cvar) = &*pair;
|
||||||
|
/// let mut started = lock.lock().unwrap();
|
||||||
|
/// // As long as the value inside the `Mutex` is false, we wait.
|
||||||
|
/// while !*started {
|
||||||
|
/// started = cvar.wait(started).unwrap();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn notify_all(&self) {
|
pub fn notify_all(&self) {
|
||||||
unsafe { self.inner.notify_all() }
|
unsafe { self.inner.notify_all() }
|
||||||
|
24
src/test/compile-fail/feature-gate-unboxed-closures.rs
Normal file
24
src/test/compile-fail/feature-gate-unboxed-closures.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
struct Test;
|
||||||
|
|
||||||
|
impl FnOnce<(u32, u32)> for Test {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 {
|
||||||
|
a + b
|
||||||
|
}
|
||||||
|
//~^^^ ERROR rust-call ABI is subject to change (see issue #29625)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(Test(1u32, 2u32), 3u32);
|
||||||
|
}
|
@ -14,12 +14,12 @@
|
|||||||
#![unstable(feature="test", issue="27759")]
|
#![unstable(feature="test", issue="27759")]
|
||||||
|
|
||||||
// @has issue_27759/unstable/index.html
|
// @has issue_27759/unstable/index.html
|
||||||
// @has - '<code>test</code>'
|
// @has - '<code>test </code>'
|
||||||
// @has - '<a href="http://issue_url/27759">#27759</a>'
|
// @has - '<a href="http://issue_url/27759">#27759</a>'
|
||||||
#[unstable(feature="test", issue="27759")]
|
#[unstable(feature="test", issue="27759")]
|
||||||
pub mod unstable {
|
pub mod unstable {
|
||||||
// @has issue_27759/unstable/fn.issue.html
|
// @has issue_27759/unstable/fn.issue.html
|
||||||
// @has - '<code>test_function</code>'
|
// @has - '<code>test_function </code>'
|
||||||
// @has - '<a href="http://issue_url/1234567890">#1234567890</a>'
|
// @has - '<a href="http://issue_url/1234567890">#1234567890</a>'
|
||||||
#[unstable(feature="test_function", issue="1234567890")]
|
#[unstable(feature="test_function", issue="1234567890")]
|
||||||
pub fn issue() {}
|
pub fn issue() {}
|
||||||
|
@ -18,10 +18,10 @@
|
|||||||
|
|
||||||
// @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \
|
// @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \
|
||||||
// 'Deprecated since 1.0.0: text'
|
// 'Deprecated since 1.0.0: text'
|
||||||
// @has - '<code>test</code>'
|
// @has - '<code>test </code>'
|
||||||
// @has - '<a href="http://issue_url/32374">#32374</a>'
|
// @has - '<a href="http://issue_url/32374">#32374</a>'
|
||||||
// @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \
|
// @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \
|
||||||
// '🔬 This is a nightly-only experimental API. \(test #32374\)$'
|
// '🔬 This is a nightly-only experimental API. \(test #32374\)$'
|
||||||
#[rustc_deprecated(since = "1.0.0", reason = "text")]
|
#[rustc_deprecated(since = "1.0.0", reason = "text")]
|
||||||
#[unstable(feature = "test", issue = "32374")]
|
#[unstable(feature = "test", issue = "32374")]
|
||||||
pub struct T;
|
pub struct T;
|
||||||
@ -29,11 +29,11 @@ pub struct T;
|
|||||||
// @has issue_32374/struct.U.html '//*[@class="stab deprecated"]' \
|
// @has issue_32374/struct.U.html '//*[@class="stab deprecated"]' \
|
||||||
// 'Deprecated since 1.0.0: deprecated'
|
// 'Deprecated since 1.0.0: deprecated'
|
||||||
// @has issue_32374/struct.U.html '//*[@class="stab unstable"]' \
|
// @has issue_32374/struct.U.html '//*[@class="stab unstable"]' \
|
||||||
// '🔬 This is a nightly-only experimental API. (test #32374)'
|
// '🔬 This is a nightly-only experimental API. (test #32374)'
|
||||||
// @has issue_32374/struct.U.html '//details' \
|
// @has issue_32374/struct.U.html '//details' \
|
||||||
// '🔬 This is a nightly-only experimental API. (test #32374)'
|
// '🔬 This is a nightly-only experimental API. (test #32374)'
|
||||||
// @has issue_32374/struct.U.html '//summary' \
|
// @has issue_32374/struct.U.html '//summary' \
|
||||||
// '🔬 This is a nightly-only experimental API. (test #32374)'
|
// '🔬 This is a nightly-only experimental API. (test #32374)'
|
||||||
// @has issue_32374/struct.U.html '//details/p' \
|
// @has issue_32374/struct.U.html '//details/p' \
|
||||||
// 'unstable'
|
// 'unstable'
|
||||||
#[rustc_deprecated(since = "1.0.0", reason = "deprecated")]
|
#[rustc_deprecated(since = "1.0.0", reason = "deprecated")]
|
||||||
|
@ -169,8 +169,8 @@ pub fn check(path: &Path, bad: &mut bool) {
|
|||||||
let whitelist = vec![
|
let whitelist = vec![
|
||||||
"abi_ptx", "simd",
|
"abi_ptx", "simd",
|
||||||
"cfg_target_has_atomic",
|
"cfg_target_has_atomic",
|
||||||
"unboxed_closures", "stmt_expr_attributes",
|
"stmt_expr_attributes",
|
||||||
"cfg_target_thread_local", "unwind_attributes"
|
"cfg_target_thread_local", "unwind_attributes",
|
||||||
];
|
];
|
||||||
|
|
||||||
// Only check the number of lang features.
|
// Only check the number of lang features.
|
||||||
|
Loading…
Reference in New Issue
Block a user