mirror of https://github.com/rust-lang/rust.git
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
|
||||
your system. In most cases, that will just mean using the defaults provided
|
||||
for Rust. Configuring involves invoking the `configure` script in the project
|
||||
root.
|
||||
for Rust.
|
||||
|
||||
```
|
||||
./configure
|
||||
```
|
||||
To change configuration, you must copy the file `src/bootstrap/config.toml.example`
|
||||
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
|
||||
configuration used later in the build process. Some options to note:
|
||||
There are large number of options provided in this config file that will alter the
|
||||
configuration used in the build process. Some options to note:
|
||||
|
||||
- `--enable-debug` - Build a debug version of the compiler (disables optimizations,
|
||||
which speeds up compilation of stage1 rustc)
|
||||
- `--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
|
||||
#### `[llvm]`:
|
||||
- `ccache = true` - Use ccache when building llvm
|
||||
|
||||
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
|
||||
|
||||
Although the `./configure` script will generate a `Makefile`, this is actually
|
||||
just a thin veneer over the actual build system driver, `x.py`. This file, at
|
||||
the root of the repository, is used to build, test, and document various parts
|
||||
of the compiler. You can execute it as:
|
||||
The build system uses the `x.py` script to control the build process. This script
|
||||
is used to build, test, and document various parts of the compiler. You can
|
||||
execute it as:
|
||||
|
||||
```sh
|
||||
python x.py build
|
||||
|
@ -185,6 +190,9 @@ To learn about all possible rules you can execute, run:
|
|||
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
|
||||
|
||||
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.
|
||||
|
||||
Compiling all of `make check` can take a while. When testing your pull request,
|
||||
consider using one of the more specialized `make` targets to cut down on the
|
||||
Compiling all of `./x.py test` can take a while. When testing your pull request,
|
||||
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
|
||||
once before running these will work, but that’s only one full build rather than
|
||||
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
|
||||
|
||||
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
|
||||
reference to `doc/reference.html`. The CSS might be messed up, but you can
|
||||
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:
|
||||
|
||||
```sh
|
||||
$ ./configure
|
||||
$ make && sudo make install
|
||||
$ ./x.py build && sudo ./x.py dist --install
|
||||
```
|
||||
|
||||
> ***Note:*** Install locations can be adjusted by passing a `--prefix`
|
||||
> argument to `configure`. Various other options are also supported – pass
|
||||
> `--help` for more information on them.
|
||||
> ***Note:*** Install locations can be adjusted by copying the config file
|
||||
> from `./src/bootstrap/config.toml.example` to `./config.toml`, and
|
||||
> 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
|
||||
API-documentation tool. This install does not include [Cargo],
|
||||
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
|
||||
build.
|
||||
|
||||
|
||||
#### MinGW
|
||||
|
||||
[MSYS2][msys2] can be used to easily build Rust on Windows:
|
||||
|
@ -94,11 +93,10 @@ build.
|
|||
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
|
||||
$ ./configure
|
||||
$ make && make install
|
||||
$ ./x.py build && ./x.py dist --install
|
||||
```
|
||||
|
||||
#### MSVC
|
||||
|
@ -114,13 +112,6 @@ shell with:
|
|||
> 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
|
||||
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
|
||||
|
@ -131,13 +122,43 @@ CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.
|
|||
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
|
||||
|
||||
If you’d like to build the documentation, it’s almost the same:
|
||||
|
||||
```sh
|
||||
$ ./configure
|
||||
$ make docs
|
||||
$ ./x.py doc
|
||||
```
|
||||
|
||||
The generated documentation will appear in a top-level `doc` directory,
|
||||
|
|
|
@ -349,8 +349,8 @@ to it.
|
|||
|
||||
## Lifetime Elision
|
||||
|
||||
Rust supports powerful local type inference in the bodies of functions but not in their item signatures.
|
||||
It's forbidden to allow reasoning about types based on the item signature alone.
|
||||
Rust supports powerful local type inference in the bodies of functions, but it
|
||||
deliberately does not perform any reasoning about types for item signatures.
|
||||
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 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
|
||||
[`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
|
||||
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.
|
||||
|
||||
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.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// This trait should generally not be implemented by consumers of the standard
|
||||
/// library. The `write!` macro accepts an instance of `io::Write`, and the
|
||||
/// `io::Write` trait is favored over implementing this trait.
|
||||
/// library. The [`write!`] macro accepts an instance of [`io::Write`], and the
|
||||
/// [`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")]
|
||||
pub trait Write {
|
||||
/// Writes a slice of bytes into this writer, returning whether the write
|
||||
|
@ -82,29 +85,79 @@ pub trait Write {
|
|||
///
|
||||
/// # 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")]
|
||||
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
|
||||
/// written, and this method will not return until all data has been
|
||||
/// written or an error occurs.
|
||||
///
|
||||
/// # 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")]
|
||||
fn write_char(&mut self, c: char) -> Result {
|
||||
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
|
||||
/// 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")]
|
||||
fn write_fmt(&mut self, args: Arguments) -> Result {
|
||||
// This Adapter is needed to allow `self` (of type `&mut
|
||||
|
|
|
@ -21,7 +21,6 @@ use super::{
|
|||
SelectionContext,
|
||||
SelectionError,
|
||||
ObjectSafetyViolation,
|
||||
MethodViolationCode,
|
||||
};
|
||||
|
||||
use fmt_macros::{Parser, Piece, Position};
|
||||
|
@ -267,61 +266,63 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
|
||||
let span = obligation.cause.span;
|
||||
let mut report = None;
|
||||
for item in self.tcx.get_attrs(def_id).iter() {
|
||||
if item.check_name("rustc_on_unimplemented") {
|
||||
let err_sp = item.meta().span.substitute_dummy(span);
|
||||
let trait_str = self.tcx.item_path_str(trait_ref.def_id);
|
||||
if let Some(istring) = item.value_str() {
|
||||
let istring = &*istring.as_str();
|
||||
let generics = self.tcx.item_generics(trait_ref.def_id);
|
||||
let generic_map = generics.types.iter().map(|param| {
|
||||
(param.name.as_str().to_string(),
|
||||
trait_ref.substs.type_for_def(param).to_string())
|
||||
}).collect::<FxHashMap<String, String>>();
|
||||
let parser = Parser::new(istring);
|
||||
let mut errored = false;
|
||||
let err: String = parser.filter_map(|p| {
|
||||
match p {
|
||||
Piece::String(s) => Some(s),
|
||||
Piece::NextArgument(a) => match a.position {
|
||||
Position::ArgumentNamed(s) => match generic_map.get(s) {
|
||||
Some(val) => Some(val),
|
||||
None => {
|
||||
span_err!(self.tcx.sess, err_sp, E0272,
|
||||
"the #[rustc_on_unimplemented] \
|
||||
attribute on \
|
||||
trait definition for {} refers to \
|
||||
non-existent type parameter {}",
|
||||
trait_str, s);
|
||||
errored = true;
|
||||
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);
|
||||
if let Some(item) = self.tcx
|
||||
.get_attrs(def_id)
|
||||
.into_iter()
|
||||
.filter(|a| a.check_name("rustc_on_unimplemented"))
|
||||
.next()
|
||||
{
|
||||
let err_sp = item.meta().span.substitute_dummy(span);
|
||||
let trait_str = self.tcx.item_path_str(trait_ref.def_id);
|
||||
if let Some(istring) = item.value_str() {
|
||||
let istring = &*istring.as_str();
|
||||
let generics = self.tcx.item_generics(trait_ref.def_id);
|
||||
let generic_map = generics.types.iter().map(|param| {
|
||||
(param.name.as_str().to_string(),
|
||||
trait_ref.substs.type_for_def(param).to_string())
|
||||
}).collect::<FxHashMap<String, String>>();
|
||||
let parser = Parser::new(istring);
|
||||
let mut errored = false;
|
||||
let err: String = parser.filter_map(|p| {
|
||||
match p {
|
||||
Piece::String(s) => Some(s),
|
||||
Piece::NextArgument(a) => match a.position {
|
||||
Position::ArgumentNamed(s) => match generic_map.get(s) {
|
||||
Some(val) => Some(val),
|
||||
None => {
|
||||
span_err!(self.tcx.sess, err_sp, E0272,
|
||||
"the #[rustc_on_unimplemented] \
|
||||
attribute on \
|
||||
trait definition for {} refers to \
|
||||
non-existent type parameter {}",
|
||||
trait_str, s);
|
||||
errored = true;
|
||||
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 {
|
||||
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);
|
||||
}).collect();
|
||||
// Report only if the format string checks out
|
||||
if !errored {
|
||||
report = Some(err);
|
||||
}
|
||||
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
|
||||
|
@ -359,34 +360,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn report_similar_impl_candidates(&self,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
impl_candidates: Vec<ty::TraitRef<'tcx>>,
|
||||
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() {
|
||||
return;
|
||||
}
|
||||
|
@ -525,127 +501,118 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
lint_id)
|
||||
.emit();
|
||||
return;
|
||||
} else {
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref trait_predicate) => {
|
||||
let trait_predicate =
|
||||
self.resolve_type_vars_if_possible(trait_predicate);
|
||||
}
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref trait_predicate) => {
|
||||
let trait_predicate =
|
||||
self.resolve_type_vars_if_possible(trait_predicate);
|
||||
|
||||
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();
|
||||
if self.tcx.sess.has_errors() && trait_predicate.references_error() {
|
||||
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) => {
|
||||
// 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);
|
||||
// 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);
|
||||
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()) {
|
||||
continue;
|
||||
}
|
||||
let buf;
|
||||
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.note(&violation.error_msg());
|
||||
}
|
||||
err
|
||||
}
|
||||
|
@ -774,46 +710,46 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
let trait_ref = data.to_poly_trait_ref();
|
||||
let self_ty = trait_ref.self_ty();
|
||||
if predicate.references_error() {
|
||||
} else {
|
||||
// Typically, this ambiguity should only happen if
|
||||
// there are unresolved type inference variables
|
||||
// (otherwise it would suggest a coherence
|
||||
// failure). But given #21974 that is not necessarily
|
||||
// the case -- we can have multiple where clauses that
|
||||
// are only distinguished by a region, which results
|
||||
// in an ambiguity even when all types are fully
|
||||
// known, since we don't dispatch based on region
|
||||
// relationships.
|
||||
return;
|
||||
}
|
||||
// Typically, this ambiguity should only happen if
|
||||
// there are unresolved type inference variables
|
||||
// (otherwise it would suggest a coherence
|
||||
// failure). But given #21974 that is not necessarily
|
||||
// the case -- we can have multiple where clauses that
|
||||
// are only distinguished by a region, which results
|
||||
// in an ambiguity even when all types are fully
|
||||
// known, since we don't dispatch based on region
|
||||
// relationships.
|
||||
|
||||
// This is kind of a hack: it frequently happens that some earlier
|
||||
// error prevents types from being fully inferred, and then we get
|
||||
// a bunch of uninteresting errors saying something like "<generic
|
||||
// #0> doesn't implement Sized". It may even be true that we
|
||||
// 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 created, registered as an obligation, and
|
||||
// then never forced by writeback, and hence by skipping here we'd
|
||||
// be ignoring the fact that we don't KNOW the type works
|
||||
// out. Though even that would probably be harmless, given that
|
||||
// we're only talking about builtin traits, which are known to be
|
||||
// inhabited. But in any case I just threw in this check for
|
||||
// has_errors() to be sure that compilation isn't happening
|
||||
// anyway. In that case, why inundate the user.
|
||||
if !self.tcx.sess.has_errors() {
|
||||
if
|
||||
self.tcx.lang_items.sized_trait()
|
||||
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
|
||||
{
|
||||
self.need_type_info(obligation, self_ty);
|
||||
} else {
|
||||
let mut err = struct_span_err!(self.tcx.sess,
|
||||
obligation.cause.span, E0283,
|
||||
"type annotations required: \
|
||||
cannot resolve `{}`",
|
||||
predicate);
|
||||
self.note_obligation_cause(&mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
// This is kind of a hack: it frequently happens that some earlier
|
||||
// error prevents types from being fully inferred, and then we get
|
||||
// a bunch of uninteresting errors saying something like "<generic
|
||||
// #0> doesn't implement Sized". It may even be true that we
|
||||
// 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 created, registered as an obligation, and
|
||||
// then never forced by writeback, and hence by skipping here we'd
|
||||
// be ignoring the fact that we don't KNOW the type works
|
||||
// out. Though even that would probably be harmless, given that
|
||||
// we're only talking about builtin traits, which are known to be
|
||||
// inhabited. But in any case I just threw in this check for
|
||||
// has_errors() to be sure that compilation isn't happening
|
||||
// anyway. In that case, why inundate the user.
|
||||
if !self.tcx.sess.has_errors() {
|
||||
if
|
||||
self.tcx.lang_items.sized_trait()
|
||||
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
|
||||
{
|
||||
self.need_type_info(obligation, self_ty);
|
||||
} else {
|
||||
let mut err = struct_span_err!(self.tcx.sess,
|
||||
obligation.cause.span, E0283,
|
||||
"type annotations required: \
|
||||
cannot resolve `{}`",
|
||||
predicate);
|
||||
self.note_obligation_cause(&mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ use hir::def_id::DefId;
|
|||
use traits;
|
||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use ty::subst::Substs;
|
||||
use std::borrow::Cow;
|
||||
use syntax::ast;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
|
@ -38,6 +39,25 @@ pub enum ObjectSafetyViolation {
|
|||
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.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
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
|
||||
/// details about the type/lifetime parameters that are in scope.
|
||||
/// It primarily stores the bounds information.
|
||||
|
|
|
@ -389,6 +389,24 @@ pub struct TraitRef<'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>>;
|
||||
|
||||
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,
|
||||
stab.issue) {
|
||||
(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),
|
||||
(false, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
|
||||
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() {
|
||||
stability.push(format!("<div class='stab unstable'>\
|
||||
<span class=microscope>🔬</span> \
|
||||
This is a nightly-only experimental API. {}\
|
||||
This is a nightly-only experimental API. {}\
|
||||
</div>",
|
||||
unstable_extra));
|
||||
unstable_extra));
|
||||
} else {
|
||||
let text = format!("<summary><span class=microscope>🔬</span> \
|
||||
This is a nightly-only experimental API. {}\
|
||||
This is a nightly-only experimental API. {}\
|
||||
</summary>{}",
|
||||
unstable_extra, MarkdownHtml(&stab.unstable_reason));
|
||||
stability.push(format!("<div class='stab unstable'><details>{}</details></div>",
|
||||
|
|
|
@ -27,6 +27,31 @@
|
|||
//!
|
||||
//! 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")]
|
||||
|
||||
|
|
|
@ -18,12 +18,57 @@ use time::Duration;
|
|||
|
||||
/// A type indicating whether a timed wait on a condition variable returned
|
||||
/// 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)]
|
||||
#[stable(feature = "wait_timeout", since = "1.5.0")]
|
||||
pub struct WaitTimeoutResult(bool);
|
||||
|
||||
impl WaitTimeoutResult {
|
||||
/// 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")]
|
||||
pub fn timed_out(&self) -> bool {
|
||||
self.0
|
||||
|
@ -55,15 +100,16 @@ impl WaitTimeoutResult {
|
|||
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
|
||||
/// 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|| {
|
||||
/// 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
|
||||
/// // Wait for the thread to start up.
|
||||
/// let &(ref lock, ref cvar) = &*pair;
|
||||
/// let mut started = lock.lock().unwrap();
|
||||
/// while !*started {
|
||||
|
@ -79,6 +125,14 @@ pub struct Condvar {
|
|||
impl Condvar {
|
||||
/// Creates a new condition variable which is ready to be waited on and
|
||||
/// notified.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Condvar;
|
||||
///
|
||||
/// let condvar = Condvar::new();
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn new() -> Condvar {
|
||||
let mut c = Condvar {
|
||||
|
@ -95,10 +149,10 @@ impl Condvar {
|
|||
/// notification.
|
||||
///
|
||||
/// This function will atomically unlock the mutex specified (represented by
|
||||
/// `mutex_guard`) and block the current thread. This means that any calls
|
||||
/// to `notify_*()` which happen logically after the mutex is unlocked are
|
||||
/// candidates to wake this thread up. When this function call returns, the
|
||||
/// lock specified will have been re-acquired.
|
||||
/// `guard`) and block the current thread. This means that any calls
|
||||
/// to [`notify_one()`] or [`notify_all()`] which happen logically after the
|
||||
/// mutex is unlocked are candidates to wake this thread up. When this
|
||||
/// function call returns, the lock specified will have been re-acquired.
|
||||
///
|
||||
/// Note that this function is susceptible to spurious wakeups. Condition
|
||||
/// 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
|
||||
/// 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
|
||||
///
|
||||
/// 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
|
||||
/// mutex to ensure defined behavior across platforms. If this functionality
|
||||
/// 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")]
|
||||
pub fn wait<'a, T>(&self, guard: 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
|
||||
/// 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
|
||||
/// than `ms` milliseconds. This method should not be used for
|
||||
/// 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
|
||||
/// 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.
|
||||
///
|
||||
/// [`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")]
|
||||
#[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)
|
||||
|
@ -165,7 +285,7 @@ impl Condvar {
|
|||
/// Waits on this condition variable for a notification, timing out after a
|
||||
/// 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
|
||||
/// method should not be used for precise timing due to anomalies such as
|
||||
/// 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
|
||||
/// 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.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// [`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")]
|
||||
pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
|
||||
dur: Duration)
|
||||
|
@ -200,10 +356,40 @@ impl Condvar {
|
|||
/// Wakes up one blocked thread on this condvar.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// 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")]
|
||||
pub fn notify_one(&self) {
|
||||
unsafe { self.inner.notify_one() }
|
||||
|
@ -215,7 +401,35 @@ impl Condvar {
|
|||
/// variable are awoken. Calls to `notify_all()` are not buffered in any
|
||||
/// 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")]
|
||||
pub fn notify_all(&self) {
|
||||
unsafe { self.inner.notify_all() }
|
||||
|
|
|
@ -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")]
|
||||
|
||||
// @has issue_27759/unstable/index.html
|
||||
// @has - '<code>test</code>'
|
||||
// @has - '<code>test </code>'
|
||||
// @has - '<a href="http://issue_url/27759">#27759</a>'
|
||||
#[unstable(feature="test", issue="27759")]
|
||||
pub mod unstable {
|
||||
// @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>'
|
||||
#[unstable(feature="test_function", issue="1234567890")]
|
||||
pub fn issue() {}
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
|
||||
// @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \
|
||||
// 'Deprecated since 1.0.0: text'
|
||||
// @has - '<code>test</code>'
|
||||
// @has - '<code>test </code>'
|
||||
// @has - '<a href="http://issue_url/32374">#32374</a>'
|
||||
// @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")]
|
||||
#[unstable(feature = "test", issue = "32374")]
|
||||
pub struct T;
|
||||
|
@ -29,11 +29,11 @@ pub struct T;
|
|||
// @has issue_32374/struct.U.html '//*[@class="stab deprecated"]' \
|
||||
// 'Deprecated since 1.0.0: deprecated'
|
||||
// @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' \
|
||||
// '🔬 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' \
|
||||
// '🔬 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' \
|
||||
// 'unstable'
|
||||
#[rustc_deprecated(since = "1.0.0", reason = "deprecated")]
|
||||
|
|
|
@ -169,8 +169,8 @@ pub fn check(path: &Path, bad: &mut bool) {
|
|||
let whitelist = vec![
|
||||
"abi_ptx", "simd",
|
||||
"cfg_target_has_atomic",
|
||||
"unboxed_closures", "stmt_expr_attributes",
|
||||
"cfg_target_thread_local", "unwind_attributes"
|
||||
"stmt_expr_attributes",
|
||||
"cfg_target_thread_local", "unwind_attributes",
|
||||
];
|
||||
|
||||
// Only check the number of lang features.
|
||||
|
|
Loading…
Reference in New Issue