Auto merge of #48608 - kennytm:rollup, r=kennytm

Rollup of 15 pull requests

- Successful merges: #48266, #48321, #48365, #48381, #48450, #48473, #48479, #48484, #48488, #48497, #48541, #48548, #48558, #48560, #48565
- Failed merges:
This commit is contained in:
bors 2018-02-28 11:24:23 +00:00
commit 0ff9872b22
55 changed files with 698 additions and 1394 deletions

View file

@ -623,6 +623,7 @@ For people new to Rust, and just starting to contribute, or even for
more seasoned developers, some useful places to look for information
are:
* The [rustc guide] contains information about how various parts of the compiler work
* [Rust Forge][rustforge] contains additional documentation, including write-ups of how to achieve common tasks
* The [Rust Internals forum][rif], a place to ask questions and
discuss Rust's internals
@ -635,6 +636,7 @@ are:
* **Google!** ([search only in Rust Documentation][gsearchdocs] to find types, traits, etc. quickly)
* Don't be afraid to ask! The Rust community is friendly and helpful.
[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/about-this-guide.html
[gdfrustc]: http://manishearth.github.io/rust-internals-docs/rustc/
[gsearchdocs]: https://www.google.com/search?q=site:doc.rust-lang.org+your+query+here
[rif]: http://internals.rust-lang.org

View file

@ -227,9 +227,13 @@ variety of channels on Mozilla's IRC network, irc.mozilla.org. The
most popular channel is [#rust], a venue for general discussion about
Rust. And a good place to ask for help would be [#rust-beginners].
Also, the [rustc guide] might be a good place to start if you want to
find out how various parts of the compiler work.
[IRC]: https://en.wikipedia.org/wiki/Internet_Relay_Chat
[#rust]: irc://irc.mozilla.org/rust
[#rust-beginners]: irc://irc.mozilla.org/rust-beginners
[rustc-guide]: https://rust-lang-nursery.github.io/rustc-guide/about-this-guide.html
## License
[license]: #license

15
src/README.md Normal file
View file

@ -0,0 +1,15 @@
This directory contains the source code of the rust project, including:
- `rustc` and its tests
- `libstd`
- Various submodules for tools, like rustdoc, rls, etc.
For more information on how various parts of the compiler work, see the [rustc guide].
Their is also useful content in the following READMEs, which are gradually being moved over to the guide:
- https://github.com/rust-lang/rust/tree/master/src/librustc/ty/maps
- https://github.com/rust-lang/rust/tree/master/src/librustc/dep_graph
- https://github.com/rust-lang/rust/blob/master/src/librustc/infer/region_constraints
- https://github.com/rust-lang/rust/tree/master/src/librustc/infer/higher_ranked
- https://github.com/rust-lang/rust/tree/master/src/librustc/infer/lexical_region_resolve
[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/about-this-guide.html

View file

@ -1007,6 +1007,10 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo
continue
};
if json["reason"].as_str() != Some("compiler-artifact") {
if build.config.rustc_error_format.as_ref().map_or(false, |e| e == "json") {
// most likely not a cargo message, so let's send it out as well
println!("{}", line);
}
continue
}
for filename in json["filenames"].as_array().unwrap() {

View file

@ -119,7 +119,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
opts.optflag("h", "help", "print this help message");
opts.optflag("", "error-format", "rustc error format");
opts.optopt("", "error-format", "rustc error format", "FORMAT");
// fn usage()
let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! {

View file

@ -480,6 +480,7 @@ impl Step for Openssl {
"mips64el-unknown-linux-gnuabi64" => "linux64-mips64",
"mipsel-unknown-linux-gnu" => "linux-mips32",
"powerpc-unknown-linux-gnu" => "linux-ppc",
"powerpc-unknown-linux-gnuspe" => "linux-ppc",
"powerpc-unknown-netbsd" => "BSD-generic32",
"powerpc64-unknown-linux-gnu" => "linux-ppc64",
"powerpc64le-unknown-linux-gnu" => "linux-ppc64le",

View file

@ -13,7 +13,6 @@
#![feature(i128_type)]
#![feature(rand)]
#![feature(repr_simd)]
#![feature(slice_rotate)]
#![feature(test)]
extern crate rand;

View file

@ -79,7 +79,6 @@
#![cfg_attr(test, feature(placement_in))]
#![cfg_attr(not(test), feature(core_float))]
#![cfg_attr(not(test), feature(exact_size_is_empty))]
#![cfg_attr(not(test), feature(slice_rotate))]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(rand, test))]
#![feature(allow_internal_unstable)]

View file

@ -1460,8 +1460,6 @@ impl<T> [T] {
/// # Examples
///
/// ```
/// #![feature(slice_rotate)]
///
/// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
/// a.rotate_left(2);
/// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']);
@ -1470,23 +1468,15 @@ impl<T> [T] {
/// Rotating a subslice:
///
/// ```
/// #![feature(slice_rotate)]
///
/// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
/// a[1..5].rotate_left(1);
/// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']);
/// ```
#[unstable(feature = "slice_rotate", issue = "41891")]
/// ```
#[stable(feature = "slice_rotate", since = "1.26.0")]
pub fn rotate_left(&mut self, mid: usize) {
core_slice::SliceExt::rotate_left(self, mid);
}
#[unstable(feature = "slice_rotate", issue = "41891")]
#[rustc_deprecated(since = "", reason = "renamed to `rotate_left`")]
pub fn rotate(&mut self, mid: usize) {
core_slice::SliceExt::rotate_left(self, mid);
}
/// Rotates the slice in-place such that the first `self.len() - k`
/// elements of the slice move to the end while the last `k` elements move
/// to the front. After calling `rotate_right`, the element previously at
@ -1505,8 +1495,6 @@ impl<T> [T] {
/// # Examples
///
/// ```
/// #![feature(slice_rotate)]
///
/// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
/// a.rotate_right(2);
/// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']);
@ -1515,13 +1503,11 @@ impl<T> [T] {
/// Rotate a subslice:
///
/// ```
/// #![feature(slice_rotate)]
///
/// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
/// a[1..5].rotate_right(1);
/// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']);
/// ```
#[unstable(feature = "slice_rotate", issue = "41891")]
#[stable(feature = "slice_rotate", since = "1.26.0")]
pub fn rotate_right(&mut self, k: usize) {
core_slice::SliceExt::rotate_right(self, k);
}

View file

@ -23,7 +23,6 @@
#![feature(pattern)]
#![feature(placement_in_syntax)]
#![feature(rand)]
#![feature(slice_rotate)]
#![feature(splice)]
#![feature(str_escape)]
#![feature(string_retain)]

View file

@ -863,6 +863,9 @@ impl<T: ?Sized> !Sync for RefCell<T> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Clone> Clone for RefCell<T> {
/// # Panics
///
/// Panics if the value is currently mutably borrowed.
#[inline]
fn clone(&self) -> RefCell<T> {
RefCell::new(self.borrow().clone())
@ -880,6 +883,9 @@ impl<T:Default> Default for RefCell<T> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + PartialEq> PartialEq for RefCell<T> {
/// # Panics
///
/// Panics if the value in either `RefCell` is currently borrowed.
#[inline]
fn eq(&self, other: &RefCell<T>) -> bool {
*self.borrow() == *other.borrow()
@ -891,26 +897,41 @@ impl<T: ?Sized + Eq> Eq for RefCell<T> {}
#[stable(feature = "cell_ord", since = "1.10.0")]
impl<T: ?Sized + PartialOrd> PartialOrd for RefCell<T> {
/// # Panics
///
/// Panics if the value in either `RefCell` is currently borrowed.
#[inline]
fn partial_cmp(&self, other: &RefCell<T>) -> Option<Ordering> {
self.borrow().partial_cmp(&*other.borrow())
}
/// # Panics
///
/// Panics if the value in either `RefCell` is currently borrowed.
#[inline]
fn lt(&self, other: &RefCell<T>) -> bool {
*self.borrow() < *other.borrow()
}
/// # Panics
///
/// Panics if the value in either `RefCell` is currently borrowed.
#[inline]
fn le(&self, other: &RefCell<T>) -> bool {
*self.borrow() <= *other.borrow()
}
/// # Panics
///
/// Panics if the value in either `RefCell` is currently borrowed.
#[inline]
fn gt(&self, other: &RefCell<T>) -> bool {
*self.borrow() > *other.borrow()
}
/// # Panics
///
/// Panics if the value in either `RefCell` is currently borrowed.
#[inline]
fn ge(&self, other: &RefCell<T>) -> bool {
*self.borrow() >= *other.borrow()
@ -919,6 +940,9 @@ impl<T: ?Sized + PartialOrd> PartialOrd for RefCell<T> {
#[stable(feature = "cell_ord", since = "1.10.0")]
impl<T: ?Sized + Ord> Ord for RefCell<T> {
/// # Panics
///
/// Panics if the value in either `RefCell` is currently borrowed.
#[inline]
fn cmp(&self, other: &RefCell<T>) -> Ordering {
self.borrow().cmp(&*other.borrow())

View file

@ -634,6 +634,46 @@ $EndFeature, "
}
}
doc_comment! {
concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
overflow occurred.
# Examples
Basic usage:
```
#![feature(no_panic_pow)]
", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64));
assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);",
$EndFeature, "
```"),
#[unstable(feature = "no_panic_pow", issue = "48320")]
#[inline]
pub fn checked_pow(self, mut exp: u32) -> Option<Self> {
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = acc.checked_mul(base)?;
}
exp /= 2;
base = base.checked_mul(base)?;
}
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
acc = acc.checked_mul(base)?;
}
Some(acc)
}
}
doc_comment! {
concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric
bounds instead of overflowing.
@ -713,6 +753,34 @@ $EndFeature, "
}
}
doc_comment! {
concat!("Saturating integer exponentiation. Computes `self.pow(exp)`,
saturating at the numeric bounds instead of overflowing.
# Examples
Basic usage:
```
#![feature(no_panic_pow)]
", $Feature, "use std::", stringify!($SelfT), ";
assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64);
assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX);
assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);",
$EndFeature, "
```"),
#[unstable(feature = "no_panic_pow", issue = "48320")]
#[inline]
pub fn saturating_pow(self, exp: u32) -> Self {
match self.checked_pow(exp) {
Some(x) => x,
None if self < 0 && exp % 2 == 1 => Self::min_value(),
None => Self::max_value(),
}
}
}
doc_comment! {
concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the
boundary of the type.
@ -947,6 +1015,46 @@ $EndFeature, "
}
}
doc_comment! {
concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
wrapping around at the boundary of the type.
# Examples
Basic usage:
```
#![feature(no_panic_pow)]
", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81);
assert_eq!(3i8.wrapping_pow(5), -13);
assert_eq!(3i8.wrapping_pow(6), -39);",
$EndFeature, "
```"),
#[unstable(feature = "no_panic_pow", issue = "48320")]
#[inline]
pub fn wrapping_pow(self, mut exp: u32) -> Self {
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = acc.wrapping_mul(base);
}
exp /= 2;
base = base.wrapping_mul(base);
}
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
acc = acc.wrapping_mul(base);
}
acc
}
}
doc_comment! {
concat!("Calculates `self` + `rhs`
@ -1202,6 +1310,56 @@ $EndFeature, "
doc_comment! {
concat!("Raises self to the power of `exp`, using exponentiation by squaring.
Returns a tuple of the exponentiation along with a bool indicating
whether an overflow happened.
# Examples
Basic usage:
```
#![feature(no_panic_pow)]
", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false));
assert_eq!(3i8.overflowing_pow(5), (-13, true));",
$EndFeature, "
```"),
#[unstable(feature = "no_panic_pow", issue = "48320")]
#[inline]
pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
let mut base = self;
let mut acc: Self = 1;
let mut overflown = false;
// Scratch space for storing results of overflowing_mul.
let mut r;
while exp > 1 {
if (exp & 1) == 1 {
r = acc.overflowing_mul(base);
acc = r.0;
overflown |= r.1;
}
exp /= 2;
r = base.overflowing_mul(base);
base = r.0;
overflown |= r.1;
}
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
r = acc.overflowing_mul(base);
acc = r.0;
overflown |= r.1;
}
(acc, overflown)
}
}
doc_comment! {
concat!("Raises self to the power of `exp`, using exponentiation by squaring.
# Examples
Basic usage:
@ -1887,6 +2045,44 @@ assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature,
}
}
doc_comment! {
concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
overflow occurred.
# Examples
Basic usage:
```
#![feature(no_panic_pow)]
", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32));
assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);", $EndFeature, "
```"),
#[unstable(feature = "no_panic_pow", issue = "48320")]
#[inline]
pub fn checked_pow(self, mut exp: u32) -> Option<Self> {
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = acc.checked_mul(base)?;
}
exp /= 2;
base = base.checked_mul(base)?;
}
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
acc = acc.checked_mul(base)?;
}
Some(acc)
}
}
doc_comment! {
concat!("Saturating integer addition. Computes `self + rhs`, saturating at
the numeric bounds instead of overflowing.
@ -1953,6 +2149,32 @@ assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($Se
}
}
doc_comment! {
concat!("Saturating integer exponentiation. Computes `self.pow(exp)`,
saturating at the numeric bounds instead of overflowing.
# Examples
Basic usage:
```
#![feature(no_panic_pow)]
", $Feature, "use std::", stringify!($SelfT), ";
assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64);
assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);",
$EndFeature, "
```"),
#[unstable(feature = "no_panic_pow", issue = "48320")]
#[inline]
pub fn saturating_pow(self, exp: u32) -> Self {
match self.checked_pow(exp) {
Some(x) => x,
None => Self::max_value(),
}
}
}
doc_comment! {
concat!("Wrapping (modular) addition. Computes `self + rhs`,
wrapping around at the boundary of the type.
@ -2147,6 +2369,44 @@ assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, "
}
}
doc_comment! {
concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
wrapping around at the boundary of the type.
# Examples
Basic usage:
```
#![feature(no_panic_pow)]
", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243);
assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
```"),
#[unstable(feature = "no_panic_pow", issue = "48320")]
#[inline]
pub fn wrapping_pow(self, mut exp: u32) -> Self {
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = acc.wrapping_mul(base);
}
exp /= 2;
base = base.wrapping_mul(base);
}
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
acc = acc.wrapping_mul(base);
}
acc
}
}
doc_comment! {
concat!("Calculates `self` + `rhs`
@ -2353,7 +2613,55 @@ assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $E
pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
(self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
}
}
doc_comment! {
concat!("Raises self to the power of `exp`, using exponentiation by squaring.
Returns a tuple of the exponentiation along with a bool indicating
whether an overflow happened.
# Examples
Basic usage:
```
#![feature(no_panic_pow)]
", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false));
assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
```"),
#[unstable(feature = "no_panic_pow", issue = "48320")]
#[inline]
pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
let mut base = self;
let mut acc: Self = 1;
let mut overflown = false;
// Scratch space for storing results of overflowing_mul.
let mut r;
while exp > 1 {
if (exp & 1) == 1 {
r = acc.overflowing_mul(base);
acc = r.0;
overflown |= r.1;
}
exp /= 2;
r = base.overflowing_mul(base);
base = r.0;
overflown |= r.1;
}
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
r = acc.overflowing_mul(base);
acc = r.0;
overflown |= r.1;
}
(acc, overflown)
}
}
doc_comment! {

View file

@ -211,10 +211,10 @@ pub trait SliceExt {
#[stable(feature = "core", since = "1.6.0")]
fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq;
#[unstable(feature = "slice_rotate", issue = "41891")]
#[stable(feature = "slice_rotate", since = "1.26.0")]
fn rotate_left(&mut self, mid: usize);
#[unstable(feature = "slice_rotate", issue = "41891")]
#[stable(feature = "slice_rotate", since = "1.26.0")]
fn rotate_right(&mut self, k: usize);
#[stable(feature = "clone_from_slice", since = "1.7.0")]

View file

@ -37,7 +37,6 @@
#![feature(refcell_replace_swap)]
#![feature(sip_hash_13)]
#![feature(slice_patterns)]
#![feature(slice_rotate)]
#![feature(sort_internals)]
#![feature(specialization)]
#![feature(step_trait)]

View file

@ -1,204 +1,3 @@
An informal guide to reading and working on the rustc compiler.
==================================================================
For more information about how rustc works, see the [rustc guide].
If you wish to expand on this document, or have a more experienced
Rust contributor add anything else to it, please get in touch:
* https://internals.rust-lang.org/
* https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
or file a bug:
https://github.com/rust-lang/rust/issues
Your concerns are probably the same as someone else's.
You may also be interested in the
[Rust Forge](https://forge.rust-lang.org/), which includes a number of
interesting bits of information.
Finally, at the end of this file is a GLOSSARY defining a number of
common (and not necessarily obvious!) names that are used in the Rust
compiler code. If you see some funky name and you'd like to know what
it stands for, check there!
The crates of rustc
===================
Rustc consists of a number of crates, including `syntax`,
`rustc`, `rustc_back`, `rustc_trans`, `rustc_driver`, and
many more. The source for each crate can be found in a directory
like `src/libXXX`, where `XXX` is the crate name.
(NB. The names and divisions of these crates are not set in
stone and may change over time -- for the time being, we tend towards
a finer-grained division to help with compilation time, though as
incremental improves that may change.)
The dependency structure of these crates is roughly a diamond:
```
rustc_driver
/ | \
/ | \
/ | \
/ v \
rustc_trans rustc_borrowck ... rustc_metadata
\ | /
\ | /
\ | /
\ v /
rustc
|
v
syntax
/ \
/ \
syntax_pos syntax_ext
```
The `rustc_driver` crate, at the top of this lattice, is effectively
the "main" function for the rust compiler. It doesn't have much "real
code", but instead ties together all of the code defined in the other
crates and defines the overall flow of execution. (As we transition
more and more to the [query model](ty/maps/README.md), however, the
"flow" of compilation is becoming less centrally defined.)
At the other extreme, the `rustc` crate defines the common and
pervasive data structures that all the rest of the compiler uses
(e.g., how to represent types, traits, and the program itself). It
also contains some amount of the compiler itself, although that is
relatively limited.
Finally, all the crates in the bulge in the middle define the bulk of
the compiler -- they all depend on `rustc`, so that they can make use
of the various types defined there, and they export public routines
that `rustc_driver` will invoke as needed (more and more, what these
crates export are "query definitions", but those are covered later
on).
Below `rustc` lie various crates that make up the parser and error
reporting mechanism. For historical reasons, these crates do not have
the `rustc_` prefix, but they are really just as much an internal part
of the compiler and not intended to be stable (though they do wind up
getting used by some crates in the wild; a practice we hope to
gradually phase out).
Each crate has a `README.md` file that describes, at a high-level,
what it contains, and tries to give some kind of explanation (some
better than others).
The compiler process
====================
The Rust compiler is in a bit of transition right now. It used to be a
purely "pass-based" compiler, where we ran a number of passes over the
entire program, and each did a particular check of transformation.
We are gradually replacing this pass-based code with an alternative
setup based on on-demand **queries**. In the query-model, we work
backwards, executing a *query* that expresses our ultimate goal (e.g.,
"compile this crate"). This query in turn may make other queries
(e.g., "get me a list of all modules in the crate"). Those queries
make other queries that ultimately bottom out in the base operations,
like parsing the input, running the type-checker, and so forth. This
on-demand model permits us to do exciting things like only do the
minimal amount of work needed to type-check a single function. It also
helps with incremental compilation. (For details on defining queries,
check out `src/librustc/ty/maps/README.md`.)
Regardless of the general setup, the basic operations that the
compiler must perform are the same. The only thing that changes is
whether these operations are invoked front-to-back, or on demand. In
order to compile a Rust crate, these are the general steps that we
take:
1. **Parsing input**
- this processes the `.rs` files and produces the AST ("abstract syntax tree")
- the AST is defined in `syntax/ast.rs`. It is intended to match the lexical
syntax of the Rust language quite closely.
2. **Name resolution, macro expansion, and configuration**
- once parsing is complete, we process the AST recursively, resolving paths
and expanding macros. This same process also processes `#[cfg]` nodes, and hence
may strip things out of the AST as well.
3. **Lowering to HIR**
- Once name resolution completes, we convert the AST into the HIR,
or "high-level IR". The HIR is defined in `src/librustc/hir/`; that module also includes
the lowering code.
- The HIR is a lightly desugared variant of the AST. It is more processed than the
AST and more suitable for the analyses that follow. It is **not** required to match
the syntax of the Rust language.
- As a simple example, in the **AST**, we preserve the parentheses
that the user wrote, so `((1 + 2) + 3)` and `1 + 2 + 3` parse
into distinct trees, even though they are equivalent. In the
HIR, however, parentheses nodes are removed, and those two
expressions are represented in the same way.
3. **Type-checking and subsequent analyses**
- An important step in processing the HIR is to perform type
checking. This process assigns types to every HIR expression,
for example, and also is responsible for resolving some
"type-dependent" paths, such as field accesses (`x.f` -- we
can't know what field `f` is being accessed until we know the
type of `x`) and associated type references (`T::Item` -- we
can't know what type `Item` is until we know what `T` is).
- Type checking creates "side-tables" (`TypeckTables`) that include
the types of expressions, the way to resolve methods, and so forth.
- After type-checking, we can do other analyses, such as privacy checking.
4. **Lowering to MIR and post-processing**
- Once type-checking is done, we can lower the HIR into MIR ("middle IR"), which
is a **very** desugared version of Rust, well suited to the borrowck but also
certain high-level optimizations.
5. **Translation to LLVM and LLVM optimizations**
- From MIR, we can produce LLVM IR.
- LLVM then runs its various optimizations, which produces a number of `.o` files
(one for each "codegen unit").
6. **Linking**
- Finally, those `.o` files are linked together.
Glossary
========
The compiler uses a number of...idiosyncratic abbreviations and
things. This glossary attempts to list them and give you a few
pointers for understanding them better.
- AST -- the **abstract syntax tree** produced by the `syntax` crate; reflects user syntax
very closely.
- codegen unit -- when we produce LLVM IR, we group the Rust code into a number of codegen
units. Each of these units is processed by LLVM independently from one another,
enabling parallelism. They are also the unit of incremental re-use.
- cx -- we tend to use "cx" as an abbrevation for context. See also tcx, infcx, etc.
- `DefId` -- an index identifying a **definition** (see `librustc/hir/def_id.rs`). Uniquely
identifies a `DefPath`.
- HIR -- the **High-level IR**, created by lowering and desugaring the AST. See `librustc/hir`.
- `HirId` -- identifies a particular node in the HIR by combining a
def-id with an "intra-definition offset".
- `'gcx` -- the lifetime of the global arena (see `librustc/ty`).
- generics -- the set of generic type parameters defined on a type or item
- ICE -- internal compiler error. When the compiler crashes.
- ICH -- incremental compilation hash.
- infcx -- the inference context (see `librustc/infer`)
- MIR -- the **Mid-level IR** that is created after type-checking for use by borrowck and trans.
Defined in the `src/librustc/mir/` module, but much of the code that manipulates it is
found in `src/librustc_mir`.
- obligation -- something that must be proven by the trait system; see `librustc/traits`.
- local crate -- the crate currently being compiled.
- node-id or `NodeId` -- an index identifying a particular node in the
AST or HIR; gradually being phased out and replaced with `HirId`.
- query -- perhaps some sub-computation during compilation; see `librustc/maps`.
- provider -- the function that executes a query; see `librustc/maps`.
- sess -- the **compiler session**, which stores global data used throughout compilation
- side tables -- because the AST and HIR are immutable once created, we often carry extra
information about them in the form of hashtables, indexed by the id of a particular node.
- span -- a location in the user's source code, used for error
reporting primarily. These are like a file-name/line-number/column
tuple on steroids: they carry a start/end point, and also track
macro expansions and compiler desugaring. All while being packed
into a few bytes (really, it's an index into a table). See the
`Span` datatype for more.
- substs -- the **substitutions** for a given generic type or item
(e.g., the `i32, u32` in `HashMap<i32, u32>`)
- tcx -- the "typing context", main data structure of the compiler (see `librustc/ty`).
- trans -- the code to **translate** MIR into LLVM IR.
- trait reference -- a trait and values for its type parameters (see `librustc/ty`).
- ty -- the internal representation of a **type** (see `librustc/ty`).
[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/

View file

@ -168,7 +168,7 @@ impl DepGraph {
/// what state they have access to. In particular, we want to
/// prevent implicit 'leaks' of tracked state into the task (which
/// could then be read without generating correct edges in the
/// dep-graph -- see the module-level [README] for more details on
/// dep-graph -- see the [rustc guide] for more details on
/// the dep-graph). To this end, the task function gets exactly two
/// pieces of state: the context `cx` and an argument `arg`. Both
/// of these bits of state must be of some type that implements
@ -188,7 +188,7 @@ impl DepGraph {
/// - If you need 3+ arguments, use a tuple for the
/// `arg` parameter.
///
/// [README]: https://github.com/rust-lang/rust/blob/master/src/librustc/dep_graph/README.md
/// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/incremental-compilation.html
pub fn with_task<C, A, R, HCX>(&self,
key: DepNode,
cx: C,

View file

@ -1,119 +0,0 @@
# Introduction to the HIR
The HIR -- "High-level IR" -- is the primary IR used in most of
rustc. It is a desugared version of the "abstract syntax tree" (AST)
that is generated after parsing, macro expansion, and name resolution
have completed. Many parts of HIR resemble Rust surface syntax quite
closely, with the exception that some of Rust's expression forms have
been desugared away (as an example, `for` loops are converted into a
`loop` and do not appear in the HIR).
This README covers the main concepts of the HIR.
### Out-of-band storage and the `Crate` type
The top-level data-structure in the HIR is the `Crate`, which stores
the contents of the crate currently being compiled (we only ever
construct HIR for the current crate). Whereas in the AST the crate
data structure basically just contains the root module, the HIR
`Crate` structure contains a number of maps and other things that
serve to organize the content of the crate for easier access.
For example, the contents of individual items (e.g., modules,
functions, traits, impls, etc) in the HIR are not immediately
accessible in the parents. So, for example, if had a module item `foo`
containing a function `bar()`:
```
mod foo {
fn bar() { }
}
```
Then in the HIR the representation of module `foo` (the `Mod`
stuct) would have only the **`ItemId`** `I` of `bar()`. To get the
details of the function `bar()`, we would lookup `I` in the
`items` map.
One nice result from this representation is that one can iterate
over all items in the crate by iterating over the key-value pairs
in these maps (without the need to trawl through the IR in total).
There are similar maps for things like trait items and impl items,
as well as "bodies" (explained below).
The other reason to setup the representation this way is for better
integration with incremental compilation. This way, if you gain access
to a `&hir::Item` (e.g. for the mod `foo`), you do not immediately
gain access to the contents of the function `bar()`. Instead, you only
gain access to the **id** for `bar()`, and you must invoke some
function to lookup the contents of `bar()` given its id; this gives us
a chance to observe that you accessed the data for `bar()` and record
the dependency.
### Identifiers in the HIR
Most of the code that has to deal with things in HIR tends not to
carry around references into the HIR, but rather to carry around
*identifier numbers* (or just "ids"). Right now, you will find four
sorts of identifiers in active use:
- `DefId`, which primarily names "definitions" or top-level items.
- You can think of a `DefId` as being shorthand for a very explicit
and complete path, like `std::collections::HashMap`. However,
these paths are able to name things that are not nameable in
normal Rust (e.g., impls), and they also include extra information
about the crate (such as its version number, as two versions of
the same crate can co-exist).
- A `DefId` really consists of two parts, a `CrateNum` (which
identifies the crate) and a `DefIndex` (which indixes into a list
of items that is maintained per crate).
- `HirId`, which combines the index of a particular item with an
offset within that item.
- the key point of a `HirId` is that it is *relative* to some item (which is named
via a `DefId`).
- `BodyId`, this is an absolute identifier that refers to a specific
body (definition of a function or constant) in the crate. It is currently
effectively a "newtype'd" `NodeId`.
- `NodeId`, which is an absolute id that identifies a single node in the HIR tree.
- While these are still in common use, **they are being slowly phased out**.
- Since they are absolute within the crate, adding a new node
anywhere in the tree causes the node-ids of all subsequent code in
the crate to change. This is terrible for incremental compilation,
as you can perhaps imagine.
### HIR Map
Most of the time when you are working with the HIR, you will do so via
the **HIR Map**, accessible in the tcx via `tcx.hir` (and defined in
the `hir::map` module). The HIR map contains a number of methods to
convert between ids of various kinds and to lookup data associated
with a HIR node.
For example, if you have a `DefId`, and you would like to convert it
to a `NodeId`, you can use `tcx.hir.as_local_node_id(def_id)`. This
returns an `Option<NodeId>` -- this will be `None` if the def-id
refers to something outside of the current crate (since then it has no
HIR node), but otherwise returns `Some(n)` where `n` is the node-id of
the definition.
Similarly, you can use `tcx.hir.find(n)` to lookup the node for a
`NodeId`. This returns a `Option<Node<'tcx>>`, where `Node` is an enum
defined in the map; by matching on this you can find out what sort of
node the node-id referred to and also get a pointer to the data
itself. Often, you know what sort of node `n` is -- e.g., if you know
that `n` must be some HIR expression, you can do
`tcx.hir.expect_expr(n)`, which will extract and return the
`&hir::Expr`, panicking if `n` is not in fact an expression.
Finally, you can use the HIR map to find the parents of nodes, via
calls like `tcx.hir.get_parent_node(n)`.
### HIR Bodies
A **body** represents some kind of executable code, such as the body
of a function/closure or the definition of a constant. Bodies are
associated with an **owner**, which is typically some kind of item
(e.g., a `fn()` or `const`), but could also be a closure expression
(e.g., `|x, y| x + y`). You can use the HIR map to find the body
associated with a given def-id (`maybe_body_owned_by()`) or to find
the owner of a body (`body_owner_def_id()`).

View file

@ -1,4 +0,0 @@
The HIR map, accessible via `tcx.hir`, allows you to quickly navigate the
HIR and convert between various forms of identifiers. See [the HIR README] for more information.
[the HIR README]: ../README.md

View file

@ -602,9 +602,9 @@ pub type CrateConfig = HirVec<P<MetaItem>>;
/// The top-level data structure that stores the entire contents of
/// the crate currently being compiled.
///
/// For more details, see the module-level [README].
/// For more details, see the [rustc guide].
///
/// [README]: https://github.com/rust-lang/rust/blob/master/src/librustc/hir/README.md.
/// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/hir.html
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
pub struct Crate {
pub module: Mod,

View file

@ -1,227 +0,0 @@
# Type inference engine
The type inference is based on standard HM-type inference, but
extended in various way to accommodate subtyping, region inference,
and higher-ranked types.
## A note on terminology
We use the notation `?T` to refer to inference variables, also called
existential variables.
We use the term "region" and "lifetime" interchangeably. Both refer to
the `'a` in `&'a T`.
The term "bound region" refers to regions bound in a function
signature, such as the `'a` in `for<'a> fn(&'a u32)`. A region is
"free" if it is not bound.
## Creating an inference context
You create and "enter" an inference context by doing something like
the following:
```rust
tcx.infer_ctxt().enter(|infcx| {
// use the inference context `infcx` in here
})
```
Each inference context creates a short-lived type arena to store the
fresh types and things that it will create, as described in
[the README in the ty module][ty-readme]. This arena is created by the `enter`
function and disposed after it returns.
[ty-readme]: src/librustc/ty/README.md
Within the closure, the infcx will have the type `InferCtxt<'cx, 'gcx,
'tcx>` for some fresh `'cx` and `'tcx` -- the latter corresponds to
the lifetime of this temporary arena, and the `'cx` is the lifetime of
the `InferCtxt` itself. (Again, see [that ty README][ty-readme] for
more details on this setup.)
The `tcx.infer_ctxt` method actually returns a build, which means
there are some kinds of configuration you can do before the `infcx` is
created. See `InferCtxtBuilder` for more information.
## Inference variables
The main purpose of the inference context is to house a bunch of
**inference variables** -- these represent types or regions whose precise
value is not yet known, but will be uncovered as we perform type-checking.
If you're familiar with the basic ideas of unification from H-M type
systems, or logic languages like Prolog, this is the same concept. If
you're not, you might want to read a tutorial on how H-M type
inference works, or perhaps this blog post on
[unification in the Chalk project].
[Unification in the Chalk project]: http://smallcultfollowing.com/babysteps/blog/2017/03/25/unification-in-chalk-part-1/
All told, the inference context stores four kinds of inference variables as of this
writing:
- Type variables, which come in three varieties:
- General type variables (the most common). These can be unified with any type.
- Integral type variables, which can only be unified with an integral type, and
arise from an integer literal expression like `22`.
- Float type variables, which can only be unified with a float type, and
arise from a float literal expression like `22.0`.
- Region variables, which represent lifetimes, and arise all over the dang place.
All the type variables work in much the same way: you can create a new
type variable, and what you get is `Ty<'tcx>` representing an
unresolved type `?T`. Then later you can apply the various operations
that the inferencer supports, such as equality or subtyping, and it
will possibly **instantiate** (or **bind**) that `?T` to a specific
value as a result.
The region variables work somewhat differently, and are described
below in a separate section.
## Enforcing equality / subtyping
The most basic operations you can perform in the type inferencer is
**equality**, which forces two types `T` and `U` to be the same. The
recommended way to add an equality constraint is using the `at`
method, roughly like so:
```
infcx.at(...).eq(t, u);
```
The first `at()` call provides a bit of context, i.e., why you are
doing this unification, and in what environment, and the `eq` method
performs the actual equality constraint.
When you equate things, you force them to be precisely equal. Equating
returns a `InferResult` -- if it returns `Err(err)`, then equating
failed, and the enclosing `TypeError` will tell you what went wrong.
The success case is perhaps more interesting. The "primary" return
type of `eq` is `()` -- that is, when it succeeds, it doesn't return a
value of any particular interest. Rather, it is executed for its
side-effects of constraining type variables and so forth. However, the
actual return type is not `()`, but rather `InferOk<()>`. The
`InferOk` type is used to carry extra trait obligations -- your job is
to ensure that these are fulfilled (typically by enrolling them in a
fulfillment context). See the [trait README] for more background here.
[trait README]: ../traits/README.md
You can also enforce subtyping through `infcx.at(..).sub(..)`. The same
basic concepts apply as above.
## "Trying" equality
Sometimes you would like to know if it is *possible* to equate two
types without error. You can test that with `infcx.can_eq` (or
`infcx.can_sub` for subtyping). If this returns `Ok`, then equality
is possible -- but in all cases, any side-effects are reversed.
Be aware though that the success or failure of these methods is always
**modulo regions**. That is, two types `&'a u32` and `&'b u32` will
return `Ok` for `can_eq`, even if `'a != 'b`. This falls out from the
"two-phase" nature of how we solve region constraints.
## Snapshots
As described in the previous section on `can_eq`, often it is useful
to be able to do a series of operations and then roll back their
side-effects. This is done for various reasons: one of them is to be
able to backtrack, trying out multiple possibilities before settling
on which path to take. Another is in order to ensure that a series of
smaller changes take place atomically or not at all.
To allow for this, the inference context supports a `snapshot` method.
When you call it, it will start recording changes that occur from the
operations you perform. When you are done, you can either invoke
`rollback_to`, which will undo those changes, or else `confirm`, which
will make the permanent. Snapshots can be nested as long as you follow
a stack-like discipline.
Rather than use snapshots directly, it is often helpful to use the
methods like `commit_if_ok` or `probe` that encapsulate higher-level
patterns.
## Subtyping obligations
One thing worth discussing are subtyping obligations. When you force
two types to be a subtype, like `?T <: i32`, we can often convert those
into equality constraints. This follows from Rust's rather limited notion
of subtyping: so, in the above case, `?T <: i32` is equivalent to `?T = i32`.
However, in some cases we have to be more careful. For example, when
regions are involved. So if you have `?T <: &'a i32`, what we would do
is to first "generalize" `&'a i32` into a type with a region variable:
`&'?b i32`, and then unify `?T` with that (`?T = &'?b i32`). We then
relate this new variable with the original bound:
&'?b i32 <: &'a i32
This will result in a region constraint (see below) of `'?b: 'a`.
One final interesting case is relating two unbound type variables,
like `?T <: ?U`. In that case, we can't make progress, so we enqueue
an obligation `Subtype(?T, ?U)` and return it via the `InferOk`
mechanism. You'll have to try again when more details about `?T` or
`?U` are known.
## Region constraints
Regions are inferred somewhat differently from types. Rather than
eagerly unifying things, we simply collect constraints as we go, but
make (almost) no attempt to solve regions. These constraints have the
form of an outlives constraint:
'a: 'b
Actually the code tends to view them as a subregion relation, but it's the same
idea:
'b <= 'a
(There are various other kinds of constriants, such as "verifys"; see
the `region_constraints` module for details.)
There is one case where we do some amount of eager unification. If you have an equality constraint
between two regions
'a = 'b
we will record that fact in a unification table. You can then use
`opportunistic_resolve_var` to convert `'b` to `'a` (or vice
versa). This is sometimes needed to ensure termination of fixed-point
algorithms.
## Extracting region constraints
Ultimately, region constraints are only solved at the very end of
type-checking, once all other constraints are known. There are two
ways to solve region constraints right now: lexical and
non-lexical. Eventually there will only be one.
To solve **lexical** region constraints, you invoke
`resolve_regions_and_report_errors`. This will "close" the region
constraint process and invoke the `lexical_region_resolve` code. Once
this is done, any further attempt to equate or create a subtyping
relationship will yield an ICE.
Non-lexical region constraints are not handled within the inference
context. Instead, the NLL solver (actually, the MIR type-checker)
invokes `take_and_reset_region_constraints` periodically. This
extracts all of the outlives constraints from the region solver, but
leaves the set of variables intact. This is used to get *just* the
region constraints that resulted from some particular point in the
program, since the NLL solver needs to know not just *what* regions
were subregions but *where*. Finally, the NLL solver invokes
`take_region_var_origins`, which "closes" the region constraint
process in the same way as normal solving.
## Lexical region resolution
Lexical region resolution is done by initially assigning each region
variable to an empty value. We then process each outlives constraint
repeatedly, growing region variables until a fixed-point is reached.
Region variables can be grown using a least-upper-bound relation on
the region lattice in a fairly straight-forward fashion.

View file

@ -28,8 +28,9 @@
//! this code handles low-level equality and subtyping operations. The
//! type check pass in the compiler is found in the `librustc_typeck` crate.
//!
//! For a deeper explanation of how the compiler works and is
//! organized, see the README.md file in this directory.
//! For more information about how rustc works, see the [rustc guide].
//!
//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/
//!
//! # Note
//!

View file

@ -1,90 +0,0 @@
# MIR definition and pass system
This file contains the definition of the MIR datatypes along with the
various types for the "MIR Pass" system, which lets you easily
register and define new MIR transformations and analyses.
Most of the code that operates on MIR can be found in the
`librustc_mir` crate or other crates. The code found here in
`librustc` is just the datatype definitions, along with the functions
which operate on MIR to be placed everywhere else.
## MIR Data Types and visitor
The main MIR data type is `rustc::mir::Mir`, defined in `mod.rs`.
There is also the MIR visitor (in `visit.rs`) which allows you to walk
the MIR and override what actions will be taken at various points (you
can visit in either shared or mutable mode; the latter allows changing
the MIR in place). Finally `traverse.rs` contains various traversal
routines for visiting the MIR CFG in [different standard orders][traversal]
(e.g. pre-order, reverse post-order, and so forth).
[traversal]: https://en.wikipedia.org/wiki/Tree_traversal
## MIR pass suites and their integration into the query system
As a MIR *consumer*, you are expected to use one of the queries that
returns a "final MIR". As of the time of this writing, there is only
one: `optimized_mir(def_id)`, but more are expected to come in the
future. For foreign def-ids, we simply read the MIR from the other
crate's metadata. But for local def-ids, the query will construct the
MIR and then iteratively optimize it by putting it through various
pipeline stages. This section describes those pipeline stages and how
you can extend them.
To produce the `optimized_mir(D)` for a given def-id `D`, the MIR
passes through several suites of optimizations, each represented by a
query. Each suite consists of multiple optimizations and
transformations. These suites represent useful intermediate points
where we want to access the MIR for type checking or other purposes:
- `mir_build(D)` -- not a query, but this constructs the initial MIR
- `mir_const(D)` -- applies some simple transformations to make MIR ready for constant evaluation;
- `mir_validated(D)` -- applies some more transformations, making MIR ready for borrow checking;
- `optimized_mir(D)` -- the final state, after all optimizations have been performed.
### Stealing
The intermediate queries `mir_const()` and `mir_validated()` yield up
a `&'tcx Steal<Mir<'tcx>>`, allocated using
`tcx.alloc_steal_mir()`. This indicates that the result may be
**stolen** by the next suite of optimizations -- this is an
optimization to avoid cloning the MIR. Attempting to use a stolen
result will cause a panic in the compiler. Therefore, it is important
that you do not read directly from these intermediate queries except as
part of the MIR processing pipeline.
Because of this stealing mechanism, some care must also be taken to
ensure that, before the MIR at a particular phase in the processing
pipeline is stolen, anyone who may want to read from it has already
done so. Concretely, this means that if you have some query `foo(D)`
that wants to access the result of `mir_const(D)` or
`mir_validated(D)`, you need to have the successor pass "force"
`foo(D)` using `ty::queries::foo::force(...)`. This will force a query
to execute even though you don't directly require its result.
As an example, consider MIR const qualification. It wants to read the
result produced by the `mir_const()` suite. However, that result will
be **stolen** by the `mir_validated()` suite. If nothing was done,
then `mir_const_qualif(D)` would succeed if it came before
`mir_validated(D)`, but fail otherwise. Therefore, `mir_validated(D)`
will **force** `mir_const_qualif` before it actually steals, thus
ensuring that the reads have already happened:
```
mir_const(D) --read-by--> mir_const_qualif(D)
| ^
stolen-by |
| (forces)
v |
mir_validated(D) ------------+
```
### Implementing and registering a pass
To create a new MIR pass, you simply implement the `MirPass` trait for
some fresh singleton type `Foo`. Once you have implemented a trait for
your type `Foo`, you then have to insert `Foo` into one of the suites;
this is done in `librustc_driver/driver.rs` by invoking `push_pass(S,
Foo)` with the appropriate suite substituted for `S`.

View file

@ -1,482 +0,0 @@
# TRAIT RESOLUTION
This document describes the general process and points out some non-obvious
things.
## Major concepts
Trait resolution is the process of pairing up an impl with each
reference to a trait. So, for example, if there is a generic function like:
```rust
fn clone_slice<T:Clone>(x: &[T]) -> Vec<T> { /*...*/ }
```
and then a call to that function:
```rust
let v: Vec<isize> = clone_slice(&[1, 2, 3])
```
it is the job of trait resolution to figure out (in which case)
whether there exists an impl of `isize : Clone`
Note that in some cases, like generic functions, we may not be able to
find a specific impl, but we can figure out that the caller must
provide an impl. To see what I mean, consider the body of `clone_slice`:
```rust
fn clone_slice<T:Clone>(x: &[T]) -> Vec<T> {
let mut v = Vec::new();
for e in &x {
v.push((*e).clone()); // (*)
}
}
```
The line marked `(*)` is only legal if `T` (the type of `*e`)
implements the `Clone` trait. Naturally, since we don't know what `T`
is, we can't find the specific impl; but based on the bound `T:Clone`,
we can say that there exists an impl which the caller must provide.
We use the term *obligation* to refer to a trait reference in need of
an impl.
## Overview
Trait resolution consists of three major parts:
- SELECTION: Deciding how to resolve a specific obligation. For
example, selection might decide that a specific obligation can be
resolved by employing an impl which matches the self type, or by
using a parameter bound. In the case of an impl, Selecting one
obligation can create *nested obligations* because of where clauses
on the impl itself. It may also require evaluating those nested
obligations to resolve ambiguities.
- FULFILLMENT: The fulfillment code is what tracks that obligations
are completely fulfilled. Basically it is a worklist of obligations
to be selected: once selection is successful, the obligation is
removed from the worklist and any nested obligations are enqueued.
- COHERENCE: The coherence checks are intended to ensure that there
are never overlapping impls, where two impls could be used with
equal precedence.
## Selection
Selection is the process of deciding whether an obligation can be
resolved and, if so, how it is to be resolved (via impl, where clause, etc).
The main interface is the `select()` function, which takes an obligation
and returns a `SelectionResult`. There are three possible outcomes:
- `Ok(Some(selection))` -- yes, the obligation can be resolved, and
`selection` indicates how. If the impl was resolved via an impl,
then `selection` may also indicate nested obligations that are required
by the impl.
- `Ok(None)` -- we are not yet sure whether the obligation can be
resolved or not. This happens most commonly when the obligation
contains unbound type variables.
- `Err(err)` -- the obligation definitely cannot be resolved due to a
type error, or because there are no impls that could possibly apply,
etc.
The basic algorithm for selection is broken into two big phases:
candidate assembly and confirmation.
### Candidate assembly
Searches for impls/where-clauses/etc that might
possibly be used to satisfy the obligation. Each of those is called
a candidate. To avoid ambiguity, we want to find exactly one
candidate that is definitively applicable. In some cases, we may not
know whether an impl/where-clause applies or not -- this occurs when
the obligation contains unbound inference variables.
The basic idea for candidate assembly is to do a first pass in which
we identify all possible candidates. During this pass, all that we do
is try and unify the type parameters. (In particular, we ignore any
nested where clauses.) Presuming that this unification succeeds, the
impl is added as a candidate.
Once this first pass is done, we can examine the set of candidates. If
it is a singleton set, then we are done: this is the only impl in
scope that could possibly apply. Otherwise, we can winnow down the set
of candidates by using where clauses and other conditions. If this
reduced set yields a single, unambiguous entry, we're good to go,
otherwise the result is considered ambiguous.
#### The basic process: Inferring based on the impls we see
This process is easier if we work through some examples. Consider
the following trait:
```rust
trait Convert<Target> {
fn convert(&self) -> Target;
}
```
This trait just has one method. It's about as simple as it gets. It
converts from the (implicit) `Self` type to the `Target` type. If we
wanted to permit conversion between `isize` and `usize`, we might
implement `Convert` like so:
```rust
impl Convert<usize> for isize { /*...*/ } // isize -> usize
impl Convert<isize> for usize { /*...*/ } // usize -> isize
```
Now imagine there is some code like the following:
```rust
let x: isize = ...;
let y = x.convert();
```
The call to convert will generate a trait reference `Convert<$Y> for
isize`, where `$Y` is the type variable representing the type of
`y`. When we match this against the two impls we can see, we will find
that only one remains: `Convert<usize> for isize`. Therefore, we can
select this impl, which will cause the type of `$Y` to be unified to
`usize`. (Note that while assembling candidates, we do the initial
unifications in a transaction, so that they don't affect one another.)
There are tests to this effect in src/test/run-pass:
traits-multidispatch-infer-convert-source-and-target.rs
traits-multidispatch-infer-convert-target.rs
#### Winnowing: Resolving ambiguities
But what happens if there are multiple impls where all the types
unify? Consider this example:
```rust
trait Get {
fn get(&self) -> Self;
}
impl<T:Copy> Get for T {
fn get(&self) -> T { *self }
}
impl<T:Get> Get for Box<T> {
fn get(&self) -> Box<T> { box get_it(&**self) }
}
```
What happens when we invoke `get_it(&box 1_u16)`, for example? In this
case, the `Self` type is `Box<u16>` -- that unifies with both impls,
because the first applies to all types, and the second to all
boxes. In the olden days we'd have called this ambiguous. But what we
do now is do a second *winnowing* pass that considers where clauses
and attempts to remove candidates -- in this case, the first impl only
applies if `Box<u16> : Copy`, which doesn't hold. After winnowing,
then, we are left with just one candidate, so we can proceed. There is
a test of this in `src/test/run-pass/traits-conditional-dispatch.rs`.
#### Matching
The subroutines that decide whether a particular impl/where-clause/etc
applies to a particular obligation. At the moment, this amounts to
unifying the self types, but in the future we may also recursively
consider some of the nested obligations, in the case of an impl.
#### Lifetimes and selection
Because of how that lifetime inference works, it is not possible to
give back immediate feedback as to whether a unification or subtype
relationship between lifetimes holds or not. Therefore, lifetime
matching is *not* considered during selection. This is reflected in
the fact that subregion assignment is infallible. This may yield
lifetime constraints that will later be found to be in error (in
contrast, the non-lifetime-constraints have already been checked
during selection and can never cause an error, though naturally they
may lead to other errors downstream).
#### Where clauses
Besides an impl, the other major way to resolve an obligation is via a
where clause. The selection process is always given a *parameter
environment* which contains a list of where clauses, which are
basically obligations that can assume are satisfiable. We will iterate
over that list and check whether our current obligation can be found
in that list, and if so it is considered satisfied. More precisely, we
want to check whether there is a where-clause obligation that is for
the same trait (or some subtrait) and for which the self types match,
using the definition of *matching* given above.
Consider this simple example:
```rust
trait A1 { /*...*/ }
trait A2 : A1 { /*...*/ }
trait B { /*...*/ }
fn foo<X:A2+B> { /*...*/ }
```
Clearly we can use methods offered by `A1`, `A2`, or `B` within the
body of `foo`. In each case, that will incur an obligation like `X :
A1` or `X : A2`. The parameter environment will contain two
where-clauses, `X : A2` and `X : B`. For each obligation, then, we
search this list of where-clauses. To resolve an obligation `X:A1`,
we would note that `X:A2` implies that `X:A1`.
### Confirmation
Confirmation unifies the output type parameters of the trait with the
values found in the obligation, possibly yielding a type error. If we
return to our example of the `Convert` trait from the previous
section, confirmation is where an error would be reported, because the
impl specified that `T` would be `usize`, but the obligation reported
`char`. Hence the result of selection would be an error.
### Selection during translation
During type checking, we do not store the results of trait selection.
We simply wish to verify that trait selection will succeed. Then
later, at trans time, when we have all concrete types available, we
can repeat the trait selection. In this case, we do not consider any
where-clauses to be in scope. We know that therefore each resolution
will resolve to a particular impl.
One interesting twist has to do with nested obligations. In general, in trans,
we only need to do a "shallow" selection for an obligation. That is, we wish to
identify which impl applies, but we do not (yet) need to decide how to select
any nested obligations. Nonetheless, we *do* currently do a complete resolution,
and that is because it can sometimes inform the results of type inference. That is,
we do not have the full substitutions in terms of the type variables of the impl available
to us, so we must run trait selection to figure everything out.
Here is an example:
```rust
trait Foo { /*...*/ }
impl<U,T:Bar<U>> Foo for Vec<T> { /*...*/ }
impl Bar<usize> for isize { /*...*/ }
```
After one shallow round of selection for an obligation like `Vec<isize>
: Foo`, we would know which impl we want, and we would know that
`T=isize`, but we do not know the type of `U`. We must select the
nested obligation `isize : Bar<U>` to find out that `U=usize`.
It would be good to only do *just as much* nested resolution as
necessary. Currently, though, we just do a full resolution.
# Higher-ranked trait bounds
One of the more subtle concepts at work are *higher-ranked trait
bounds*. An example of such a bound is `for<'a> MyTrait<&'a isize>`.
Let's walk through how selection on higher-ranked trait references
works.
## Basic matching and skolemization leaks
Let's walk through the test `compile-fail/hrtb-just-for-static.rs` to see
how it works. The test starts with the trait `Foo`:
```rust
trait Foo<X> {
fn foo(&self, x: X) { }
}
```
Let's say we have a function `want_hrtb` that wants a type which
implements `Foo<&'a isize>` for any `'a`:
```rust
fn want_hrtb<T>() where T : for<'a> Foo<&'a isize> { ... }
```
Now we have a struct `AnyInt` that implements `Foo<&'a isize>` for any
`'a`:
```rust
struct AnyInt;
impl<'a> Foo<&'a isize> for AnyInt { }
```
And the question is, does `AnyInt : for<'a> Foo<&'a isize>`? We want the
answer to be yes. The algorithm for figuring it out is closely related
to the subtyping for higher-ranked types (which is described in
`middle::infer::higher_ranked::doc`, but also in a [paper by SPJ] that
I recommend you read).
1. Skolemize the obligation.
2. Match the impl against the skolemized obligation.
3. Check for skolemization leaks.
[paper by SPJ]: http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/
So let's work through our example. The first thing we would do is to
skolemize the obligation, yielding `AnyInt : Foo<&'0 isize>` (here `'0`
represents skolemized region #0). Note that now have no quantifiers;
in terms of the compiler type, this changes from a `ty::PolyTraitRef`
to a `TraitRef`. We would then create the `TraitRef` from the impl,
using fresh variables for it's bound regions (and thus getting
`Foo<&'$a isize>`, where `'$a` is the inference variable for `'a`). Next
we relate the two trait refs, yielding a graph with the constraint
that `'0 == '$a`. Finally, we check for skolemization "leaks" -- a
leak is basically any attempt to relate a skolemized region to another
skolemized region, or to any region that pre-existed the impl match.
The leak check is done by searching from the skolemized region to find
the set of regions that it is related to in any way. This is called
the "taint" set. To pass the check, that set must consist *solely* of
itself and region variables from the impl. If the taint set includes
any other region, then the match is a failure. In this case, the taint
set for `'0` is `{'0, '$a}`, and hence the check will succeed.
Let's consider a failure case. Imagine we also have a struct
```rust
struct StaticInt;
impl Foo<&'static isize> for StaticInt;
```
We want the obligation `StaticInt : for<'a> Foo<&'a isize>` to be
considered unsatisfied. The check begins just as before. `'a` is
skolemized to `'0` and the impl trait reference is instantiated to
`Foo<&'static isize>`. When we relate those two, we get a constraint
like `'static == '0`. This means that the taint set for `'0` is `{'0,
'static}`, which fails the leak check.
## Higher-ranked trait obligations
Once the basic matching is done, we get to another interesting topic:
how to deal with impl obligations. I'll work through a simple example
here. Imagine we have the traits `Foo` and `Bar` and an associated impl:
```rust
trait Foo<X> {
fn foo(&self, x: X) { }
}
trait Bar<X> {
fn bar(&self, x: X) { }
}
impl<X,F> Foo<X> for F
where F : Bar<X>
{
}
```
Now let's say we have a obligation `for<'a> Foo<&'a isize>` and we match
this impl. What obligation is generated as a result? We want to get
`for<'a> Bar<&'a isize>`, but how does that happen?
After the matching, we are in a position where we have a skolemized
substitution like `X => &'0 isize`. If we apply this substitution to the
impl obligations, we get `F : Bar<&'0 isize>`. Obviously this is not
directly usable because the skolemized region `'0` cannot leak out of
our computation.
What we do is to create an inverse mapping from the taint set of `'0`
back to the original bound region (`'a`, here) that `'0` resulted
from. (This is done in `higher_ranked::plug_leaks`). We know that the
leak check passed, so this taint set consists solely of the skolemized
region itself plus various intermediate region variables. We then walk
the trait-reference and convert every region in that taint set back to
a late-bound region, so in this case we'd wind up with `for<'a> F :
Bar<&'a isize>`.
# Caching and subtle considerations therewith
In general we attempt to cache the results of trait selection. This
is a somewhat complex process. Part of the reason for this is that we
want to be able to cache results even when all the types in the trait
reference are not fully known. In that case, it may happen that the
trait selection process is also influencing type variables, so we have
to be able to not only cache the *result* of the selection process,
but *replay* its effects on the type variables.
## An example
The high-level idea of how the cache works is that we first replace
all unbound inference variables with skolemized versions. Therefore,
if we had a trait reference `usize : Foo<$1>`, where `$n` is an unbound
inference variable, we might replace it with `usize : Foo<%0>`, where
`%n` is a skolemized type. We would then look this up in the cache.
If we found a hit, the hit would tell us the immediate next step to
take in the selection process: i.e., apply impl #22, or apply where
clause `X : Foo<Y>`. Let's say in this case there is no hit.
Therefore, we search through impls and where clauses and so forth, and
we come to the conclusion that the only possible impl is this one,
with def-id 22:
```rust
impl Foo<isize> for usize { ... } // Impl #22
```
We would then record in the cache `usize : Foo<%0> ==>
ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which
would (as a side-effect) unify `$1` with `isize`.
Now, at some later time, we might come along and see a `usize :
Foo<$3>`. When skolemized, this would yield `usize : Foo<%0>`, just as
before, and hence the cache lookup would succeed, yielding
`ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would
(as a side-effect) unify `$3` with `isize`.
## Where clauses and the local vs global cache
One subtle interaction is that the results of trait lookup will vary
depending on what where clauses are in scope. Therefore, we actually
have *two* caches, a local and a global cache. The local cache is
attached to the `ParamEnv` and the global cache attached to the
`tcx`. We use the local cache whenever the result might depend on the
where clauses that are in scope. The determination of which cache to
use is done by the method `pick_candidate_cache` in `select.rs`. At
the moment, we use a very simple, conservative rule: if there are any
where-clauses in scope, then we use the local cache. We used to try
and draw finer-grained distinctions, but that led to a serious of
annoying and weird bugs like #22019 and #18290. This simple rule seems
to be pretty clearly safe and also still retains a very high hit rate
(~95% when compiling rustc).
# Specialization
Defined in the `specialize` module.
The basic strategy is to build up a *specialization graph* during
coherence checking. Insertion into the graph locates the right place
to put an impl in the specialization hierarchy; if there is no right
place (due to partial overlap but no containment), you get an overlap
error. Specialization is consulted when selecting an impl (of course),
and the graph is consulted when propagating defaults down the
specialization hierarchy.
You might expect that the specialization graph would be used during
selection -- i.e., when actually performing specialization. This is
not done for two reasons:
- It's merely an optimization: given a set of candidates that apply,
we can determine the most specialized one by comparing them directly
for specialization, rather than consulting the graph. Given that we
also cache the results of selection, the benefit of this
optimization is questionable.
- To build the specialization graph in the first place, we need to use
selection (because we need to determine whether one impl specializes
another). Dealing with this reentrancy would require some additional
mode switch for selection. Given that there seems to be no strong
reason to use the graph anyway, we stick with a simpler approach in
selection, and use the graph only for propagating default
implementations.
Trait impl selection can succeed even when multiple impls can apply,
as long as they are part of the same specialization family. In that
case, it returns a *single* impl on success -- this is the most
specialized impl *known* to apply. However, if there are any inference
variables in play, the returned impl may not be the actual impl we
will use at trans time. Thus, we take special care to avoid projecting
associated types unless either (1) the associated type does not use
`default` and thus cannot be overridden or (2) all input types are
known concretely.

View file

@ -8,7 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! See `README.md` for high-level documentation
//! See rustc guide chapters on [trait-resolution] and [trait-specialization] for more info on how
//! this works.
//!
//! [trait-resolution]: https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html
//! [trait-specialization]: https://rust-lang-nursery.github.io/rustc-guide/trait-specialization.html
use hir::def_id::{DefId, LOCAL_CRATE};
use syntax_pos::DUMMY_SP;

View file

@ -8,7 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Trait Resolution. See README.md for an overview of how this works.
//! Trait Resolution. See [rustc guide] for more info on how this works.
//!
//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html
pub use self::SelectionError::*;
pub use self::FulfillmentErrorCode::*;

View file

@ -8,7 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! See `README.md` for high-level documentation
//! See [rustc guide] for more info on how this works.
//!
//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html#selection
use self::SelectionCandidate::*;
use self::EvaluationResult::*;
@ -1045,8 +1047,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
//
// The selection process begins by examining all in-scope impls,
// caller obligations, and so forth and assembling a list of
// candidates. See `README.md` and the `Candidate` type for more
// details.
// candidates. See [rustc guide] for more details.
//
// [rustc guide]:
// https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html#candidate-assembly
fn candidate_from_obligation<'o>(&mut self,
stack: &TraitObligationStack<'o, 'tcx>)
@ -2333,7 +2337,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
//
// Confirmation unifies the output type parameters of the trait
// with the values found in the obligation, possibly yielding a
// type error. See `README.md` for more details.
// type error. See [rustc guide] for more details.
//
// [rustc guide]:
// https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html#confirmation
fn confirm_candidate(&mut self,
obligation: &TraitObligation<'tcx>,

View file

@ -8,14 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Logic and data structures related to impl specialization, explained in
// greater detail below.
//
// At the moment, this implementation support only the simple "chain" rule:
// If any two impls overlap, one must be a strict subset of the other.
//
// See traits/README.md for a bit more detail on how specialization
// fits together with the rest of the trait machinery.
//! Logic and data structures related to impl specialization, explained in
//! greater detail below.
//!
//! At the moment, this implementation support only the simple "chain" rule:
//! If any two impls overlap, one must be a strict subset of the other.
//!
//! See the [rustc guide] for a bit more detail on how specialization
//! fits together with the rest of the trait machinery.
//!
//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trait-specialization.html
use super::{SelectionContext, FulfillmentContext};
use super::util::impl_trait_ref_and_oblig;

View file

@ -1,165 +0,0 @@
# Types and the Type Context
The `ty` module defines how the Rust compiler represents types
internally. It also defines the *typing context* (`tcx` or `TyCtxt`),
which is the central data structure in the compiler.
## The tcx and how it uses lifetimes
The `tcx` ("typing context") is the central data structure in the
compiler. It is the context that you use to perform all manner of
queries. The struct `TyCtxt` defines a reference to this shared context:
```rust
tcx: TyCtxt<'a, 'gcx, 'tcx>
// -- ---- ----
// | | |
// | | innermost arena lifetime (if any)
// | "global arena" lifetime
// lifetime of this reference
```
As you can see, the `TyCtxt` type takes three lifetime parameters.
These lifetimes are perhaps the most complex thing to understand about
the tcx. During Rust compilation, we allocate most of our memory in
**arenas**, which are basically pools of memory that get freed all at
once. When you see a reference with a lifetime like `'tcx` or `'gcx`,
you know that it refers to arena-allocated data (or data that lives as
long as the arenas, anyhow).
We use two distinct levels of arenas. The outer level is the "global
arena". This arena lasts for the entire compilation: so anything you
allocate in there is only freed once compilation is basically over
(actually, when we shift to executing LLVM).
To reduce peak memory usage, when we do type inference, we also use an
inner level of arena. These arenas get thrown away once type inference
is over. This is done because type inference generates a lot of
"throw-away" types that are not particularly interesting after type
inference completes, so keeping around those allocations would be
wasteful.
Often, we wish to write code that explicitly asserts that it is not
taking place during inference. In that case, there is no "local"
arena, and all the types that you can access are allocated in the
global arena. To express this, the idea is to use the same lifetime
for the `'gcx` and `'tcx` parameters of `TyCtxt`. Just to be a touch
confusing, we tend to use the name `'tcx` in such contexts. Here is an
example:
```rust
fn not_in_inference<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
// ---- ----
// Using the same lifetime here asserts
// that the innermost arena accessible through
// this reference *is* the global arena.
}
```
In contrast, if we want to code that can be usable during type inference, then you
need to declare a distinct `'gcx` and `'tcx` lifetime parameter:
```rust
fn maybe_in_inference<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId) {
// ---- ----
// Using different lifetimes here means that
// the innermost arena *may* be distinct
// from the global arena (but doesn't have to be).
}
```
### Allocating and working with types
Rust types are represented using the `Ty<'tcx>` defined in the `ty`
module (not to be confused with the `Ty` struct from [the HIR]). This
is in fact a simple type alias for a reference with `'tcx` lifetime:
```rust
pub type Ty<'tcx> = &'tcx TyS<'tcx>;
```
[the HIR]: ../hir/README.md
You can basically ignore the `TyS` struct -- you will basically never
access it explicitly. We always pass it by reference using the
`Ty<'tcx>` alias -- the only exception I think is to define inherent
methods on types. Instances of `TyS` are only ever allocated in one of
the rustc arenas (never e.g. on the stack).
One common operation on types is to **match** and see what kinds of
types they are. This is done by doing `match ty.sty`, sort of like this:
```rust
fn test_type<'tcx>(ty: Ty<'tcx>) {
match ty.sty {
ty::TyArray(elem_ty, len) => { ... }
...
}
}
```
The `sty` field (the origin of this name is unclear to me; perhaps
structural type?) is of type `TypeVariants<'tcx>`, which is an enum
defining all of the different kinds of types in the compiler.
> NB: inspecting the `sty` field on types during type inference can be
> risky, as there may be inference variables and other things to
> consider, or sometimes types are not yet known that will become
> known later.).
To allocate a new type, you can use the various `mk_` methods defined
on the `tcx`. These have names that correpond mostly to the various kinds
of type variants. For example:
```rust
let array_ty = tcx.mk_array(elem_ty, len * 2);
```
These methods all return a `Ty<'tcx>` -- note that the lifetime you
get back is the lifetime of the innermost arena that this `tcx` has
access to. In fact, types are always canonicalized and interned (so we
never allocate exactly the same type twice) and are always allocated
in the outermost arena where they can be (so, if they do not contain
any inference variables or other "temporary" types, they will be
allocated in the global arena). However, the lifetime `'tcx` is always
a safe approximation, so that is what you get back.
> NB. Because types are interned, it is possible to compare them for
> equality efficiently using `==` -- however, this is almost never what
> you want to do unless you happen to be hashing and looking for
> duplicates. This is because often in Rust there are multiple ways to
> represent the same type, particularly once inference is involved. If
> you are going to be testing for type equality, you probably need to
> start looking into the inference code to do it right.
You can also find various common types in the `tcx` itself by accessing
`tcx.types.bool`, `tcx.types.char`, etc (see `CommonTypes` for more).
### Beyond types: Other kinds of arena-allocated data structures
In addition to types, there are a number of other arena-allocated data
structures that you can allocate, and which are found in this
module. Here are a few examples:
- `Substs`, allocated with `mk_substs` -- this will intern a slice of types, often used to
specify the values to be substituted for generics (e.g., `HashMap<i32, u32>`
would be represented as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`).
- `TraitRef`, typically passed by value -- a **trait reference**
consists of a reference to a trait along with its various type
parameters (including `Self`), like `i32: Display` (here, the def-id
would reference the `Display` trait, and the substs would contain
`i32`).
- `Predicate` defines something the trait system has to prove (see `traits` module).
### Import conventions
Although there is no hard and fast rule, the `ty` module tends to be used like so:
```rust
use ty::{self, Ty, TyCtxt};
```
In particular, since they are so common, the `Ty` and `TyCtxt` types
are imported directly. Other types are often referenced with an
explicit `ty::` prefix (e.g., `ty::TraitRef<'tcx>`). But some modules
choose to import a larger or smaller set of names explicitly.

View file

@ -779,9 +779,9 @@ impl<'tcx> CommonTypes<'tcx> {
/// The central data structure of the compiler. It stores references
/// to the various **arenas** and also houses the results of the
/// various **compiler queries** that have been performed. See the
/// module-level [README] for more details.
/// [rustc guide] for more details.
///
/// [README]: https://github.com/rust-lang/rust/blob/master/src/librustc/ty/README.md
/// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/ty.html
#[derive(Copy, Clone)]
pub struct TyCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
gcx: &'a GlobalCtxt<'gcx>,

View file

@ -46,6 +46,7 @@ pub fn opts() -> TargetOptions {
pre_link_args: LinkArgs::new(),
exe_allocation_crate: super::maybe_jemalloc(),
has_elf_tls: version >= (10, 7),
abi_return_struct_as_int: true,
.. Default::default()
}
}

View file

@ -36,6 +36,7 @@ pub fn opts() -> TargetOptions {
eliminate_frame_pointer: false, // FIXME 43575
relro_level: RelroLevel::Full,
exe_allocation_crate: super::maybe_jemalloc(),
abi_return_struct_as_int: true,
.. Default::default()
}
}

View file

@ -143,6 +143,7 @@ supported_targets! {
("mips64el-unknown-linux-gnuabi64", mips64el_unknown_linux_gnuabi64),
("mipsel-unknown-linux-gnu", mipsel_unknown_linux_gnu),
("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu),
("powerpc-unknown-linux-gnuspe", powerpc_unknown_linux_gnuspe),
("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu),
("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu),
@ -345,9 +346,8 @@ pub struct TargetOptions {
pub staticlib_suffix: String,
/// OS family to use for conditional compilation. Valid options: "unix", "windows".
pub target_family: Option<String>,
/// Whether the target toolchain is like OpenBSD's.
/// Only useful for compiling against OpenBSD, for configuring abi when returning a struct.
pub is_like_openbsd: bool,
/// Whether the target toolchain's ABI supports returning small structs as an integer.
pub abi_return_struct_as_int: bool,
/// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS,
/// in particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false.
pub is_like_osx: bool,
@ -503,7 +503,7 @@ impl Default for TargetOptions {
staticlib_prefix: "lib".to_string(),
staticlib_suffix: ".a".to_string(),
target_family: None,
is_like_openbsd: false,
abi_return_struct_as_int: false,
is_like_osx: false,
is_like_solaris: false,
is_like_windows: false,
@ -758,7 +758,7 @@ impl Target {
key!(staticlib_prefix);
key!(staticlib_suffix);
key!(target_family, optional);
key!(is_like_openbsd, bool);
key!(abi_return_struct_as_int, bool);
key!(is_like_osx, bool);
key!(is_like_solaris, bool);
key!(is_like_windows, bool);
@ -956,7 +956,7 @@ impl ToJson for Target {
target_option_val!(staticlib_prefix);
target_option_val!(staticlib_suffix);
target_option_val!(target_family);
target_option_val!(is_like_openbsd);
target_option_val!(abi_return_struct_as_int);
target_option_val!(is_like_osx);
target_option_val!(is_like_solaris);
target_option_val!(is_like_windows);

View file

@ -31,7 +31,7 @@ pub fn opts() -> TargetOptions {
target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
is_like_openbsd: true,
abi_return_struct_as_int: true,
pre_link_args: args,
position_independent_executables: true,
eliminate_frame_pointer: false, // FIXME 43575

View file

@ -0,0 +1,35 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mspe".to_string());
base.max_atomic_width = Some(32);
// see #36994
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "powerpc-unknown-linux-gnuspe".to_string(),
target_endian: "big".to_string(),
target_pointer_width: "32".to_string(),
target_c_int_width: "32".to_string(),
data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
arch: "powerpc".to_string(),
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}

View file

@ -101,6 +101,7 @@ pub fn opts() -> TargetOptions {
"rsend.o".to_string()
],
custom_unwind_resume: true,
abi_return_struct_as_int: true,
.. Default::default()
}

View file

@ -34,6 +34,7 @@ pub fn opts() -> TargetOptions {
pre_link_args: args,
crt_static_allows_dylibs: true,
crt_static_respected: true,
abi_return_struct_as_int: true,
.. Default::default()
}

View file

@ -139,6 +139,19 @@ pub mod target_features {
const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
md#bug-reports";
const ICE_REPORT_COMPILER_FLAGS: &'static [&'static str] = &[
"Z",
"C",
"crate-type",
];
const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &'static [&'static str] = &[
"metadata",
"extra-filename",
];
const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &'static [&'static str] = &[
"incremental",
];
pub fn abort_on_err<T>(result: Result<T, CompileIncomplete>, sess: &Session) -> T {
match result {
Err(CompileIncomplete::Errored(ErrorReported)) => {
@ -1431,6 +1444,57 @@ pub fn in_rustc_thread<F, R>(f: F) -> Result<R, Box<Any + Send>>
thread.unwrap().join()
}
/// Get a list of extra command-line flags provided by the user, as strings.
///
/// This function is used during ICEs to show more information useful for
/// debugging, since some ICEs only happens with non-default compiler flags
/// (and the users don't always report them).
fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
let mut args = Vec::new();
for arg in env::args_os() {
args.push(arg.to_string_lossy().to_string());
}
let matches = if let Some(matches) = handle_options(&args) {
matches
} else {
return None;
};
let mut result = Vec::new();
let mut excluded_cargo_defaults = false;
for flag in ICE_REPORT_COMPILER_FLAGS {
let prefix = if flag.len() == 1 { "-" } else { "--" };
for content in &matches.opt_strs(flag) {
// Split always returns the first element
let name = if let Some(first) = content.split('=').next() {
first
} else {
&content
};
let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
name
} else {
content
};
if !ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&name) {
result.push(format!("{}{} {}", prefix, flag, content));
} else {
excluded_cargo_defaults = true;
}
}
}
if result.len() > 0 {
Some((result, excluded_cargo_defaults))
} else {
None
}
}
/// Run a procedure which will detect panics in the compiler and print nicer
/// error messages rather than just failing the test.
///
@ -1462,11 +1526,22 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
errors::Level::Bug);
}
let xs = ["the compiler unexpectedly panicked. this is a bug.".to_string(),
format!("we would appreciate a bug report: {}", BUG_REPORT_URL),
format!("rustc {} running on {}",
option_env!("CFG_VERSION").unwrap_or("unknown_version"),
config::host_triple())];
let mut xs = vec![
"the compiler unexpectedly panicked. this is a bug.".to_string(),
format!("we would appreciate a bug report: {}", BUG_REPORT_URL),
format!("rustc {} running on {}",
option_env!("CFG_VERSION").unwrap_or("unknown_version"),
config::host_triple()),
];
if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
xs.push(format!("compiler flags: {}", flags.join(" ")));
if excluded_cargo_defaults {
xs.push("some of the compiler flags provided by cargo are hidden".to_string());
}
}
for note in &xs {
handler.emit(&MultiSpan::new(),
&note,

View file

@ -118,10 +118,13 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
match *self.as_mono_item() {
MonoItem::Fn(ref instance) => {
let entry_def_id =
tcx.sess.entry_fn.borrow().map(|(id, _)| tcx.hir.local_def_id(id));
// If this function isn't inlined or otherwise has explicit
// linkage, then we'll be creating a globally shared version.
if self.explicit_linkage(tcx).is_some() ||
!instance.def.requires_local(tcx)
!instance.def.requires_local(tcx) ||
Some(instance.def_id()) == entry_def_id
{
return InstantiationMode::GloballyShared { may_conflict: false }
}

View file

@ -849,7 +849,19 @@ fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path)
args.push_str("\n");
}
let file = tmpdir.join("linker-arguments");
fs::write(&file, args.as_bytes())?;
let bytes = if sess.target.target.options.is_like_msvc {
let mut out = vec![];
// start the stream with a UTF-16 BOM
for c in vec![0xFEFF].into_iter().chain(args.encode_utf16()) {
// encode in little endian
out.push(c as u8);
out.push((c >> 8) as u8);
}
out
} else {
args.into_bytes()
};
fs::write(&file, &bytes)?;
cmd2.arg(format!("@{}", file.display()));
return cmd2.output();

View file

@ -52,8 +52,7 @@ pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
// http://www.angelcode.com/dev/callconv/callconv.html
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
let t = &cx.sess().target.target;
if t.options.is_like_osx || t.options.is_like_windows
|| t.options.is_like_openbsd {
if t.options.abi_return_struct_as_int {
// According to Clang, everyone but MSVC returns single-element
// float aggregates directly in a floating-point register.
if !t.options.is_like_msvc && is_single_fp_element(cx, fty.ret.layout) {

View file

@ -87,7 +87,7 @@ const X86_WHITELIST: &'static [&'static str] = &["aes", "avx", "avx2", "avx512bw
"avx512cd", "avx512dq", "avx512er",
"avx512f", "avx512ifma", "avx512pf",
"avx512vbmi", "avx512vl", "avx512vpopcntdq",
"bmi", "bmi2", "fma", "fxsr",
"bmi1", "bmi2", "fma", "fxsr",
"lzcnt", "mmx", "pclmulqdq",
"popcnt", "rdrand", "rdseed",
"sse", "sse2", "sse3", "sse4.1",
@ -108,6 +108,7 @@ pub fn to_llvm_feature(s: &str) -> &str {
match s {
"pclmulqdq" => "pclmul",
"rdrand" => "rdrnd",
"bmi1" => "bmi",
s => s,
}
}

View file

@ -25,7 +25,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
AdtKind::Struct => Def::Struct,
AdtKind::Enum => Def::Enum,
AdtKind::Union => Def::Union,
},
}
_ => panic!("Unexpected type {:?}", def_id),
};

View file

@ -3428,7 +3428,11 @@ fn build_deref_target_impls(cx: &DocContext,
let primitive = match *target {
ResolvedPath { did, .. } if did.is_local() => continue,
ResolvedPath { did, .. } => {
ret.extend(inline::build_impls(cx, did, true));
// We set the last parameter to false to avoid looking for auto-impls for traits
// and therefore avoid an ICE.
// The reason behind this is that auto-traits don't propagate through Deref so
// we're not supposed to synthesise impls for them.
ret.extend(inline::build_impls(cx, did, false));
continue
}
_ => match target.primitive_type() {

View file

@ -96,14 +96,6 @@
}
}
function onEach(arr, func) {
if (arr && arr.length > 0 && func) {
for (var i = 0; i < arr.length; i++) {
func(arr[i]);
}
}
}
function isHidden(elem) {
return (elem.offsetParent === null)
}

View file

@ -1202,6 +1202,10 @@ kbd {
top: 19px;
}
.theme-picker button {
outline: none;
}
#theme-picker {
padding: 4px;
width: 27px;

View file

@ -13,6 +13,18 @@
var currentTheme = document.getElementById("themeStyle");
var mainTheme = document.getElementById("mainThemeStyle");
var savedHref = [];
function onEach(arr, func) {
if (arr && arr.length > 0 && func) {
for (var i = 0; i < arr.length; i++) {
if (func(arr[i]) === true) {
break;
}
}
}
}
function updateLocalStorage(name, value) {
if (typeof(Storage) !== "undefined") {
localStorage[name] = value;
@ -29,8 +41,24 @@ function getCurrentValue(name) {
}
function switchTheme(styleElem, mainStyleElem, newTheme) {
styleElem.href = mainStyleElem.href.replace("rustdoc.css", newTheme + ".css");
updateLocalStorage('theme', newTheme);
var newHref = mainStyleElem.href.replace("rustdoc.css", newTheme + ".css");
var found = false;
if (savedHref.length === 0) {
onEach(document.getElementsByTagName("link"), function(el) {
savedHref.push(el.href);
});
}
onEach(savedHref, function(el) {
if (el === newHref) {
found = true;
return true;
}
});
if (found === true) {
styleElem.href = newHref;
updateLocalStorage('rustdoc-theme', newTheme);
}
}
switchTheme(currentTheme, mainTheme, getCurrentValue('theme') || 'main');
switchTheme(currentTheme, mainTheme, getCurrentValue('rustdoc-theme') || 'main');

View file

@ -1080,6 +1080,15 @@ impl fmt::Display for ExitStatus {
}
}
/// This is ridiculously unstable, as it's a completely-punted-upon part
/// of the `?`-in-`main` RFC. It's here only to allow experimenting with
/// returning a code directly from main. It will definitely change
/// drastically before being stabilized, if it doesn't just get deleted.
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
#[unstable(feature = "process_exitcode_placeholder", issue = "43301")]
pub struct ExitCode(pub i32);
impl Child {
/// Forces the child to exit. This is equivalent to sending a
/// SIGKILL on unix platforms.
@ -1428,7 +1437,7 @@ impl Termination for () {
}
#[unstable(feature = "termination_trait_lib", issue = "43301")]
impl<T: Termination, E: fmt::Debug> Termination for Result<T, E> {
impl<E: fmt::Debug> Termination for Result<(), E> {
fn report(self) -> i32 {
match self {
Ok(val) => val.report(),
@ -1442,20 +1451,23 @@ impl<T: Termination, E: fmt::Debug> Termination for Result<T, E> {
#[unstable(feature = "termination_trait_lib", issue = "43301")]
impl Termination for ! {
fn report(self) -> i32 { unreachable!(); }
fn report(self) -> i32 { self }
}
#[unstable(feature = "termination_trait_lib", issue = "43301")]
impl Termination for bool {
impl<E: fmt::Debug> Termination for Result<!, E> {
fn report(self) -> i32 {
if self { exit::SUCCESS } else { exit::FAILURE }
let Err(err) = self;
eprintln!("Error: {:?}", err);
exit::FAILURE
}
}
#[unstable(feature = "termination_trait_lib", issue = "43301")]
impl Termination for i32 {
impl Termination for ExitCode {
fn report(self) -> i32 {
self
let ExitCode(code) = self;
code
}
}

View file

@ -32,6 +32,8 @@ endif
ifeq ($(filter powerpc,$(LLVM_COMPONENTS)),powerpc)
$(RUSTC) --target=powerpc-unknown-linux-gnu atomic_lock_free.rs
nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add
$(RUSTC) --target=powerpc-unknown-linux-gnuspe atomic_lock_free.rs
nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add
$(RUSTC) --target=powerpc64-unknown-linux-gnu atomic_lock_free.rs
nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add
$(RUSTC) --target=powerpc64le-unknown-linux-gnu atomic_lock_free.rs

View file

@ -36,8 +36,11 @@ fn main() {
let ok = tmpdir.join("ok");
let not_ok = tmpdir.join("not_ok");
if env::var("YOU_ARE_A_LINKER").is_ok() {
match env::args().find(|a| a.contains("@")) {
Some(file) => { fs::copy(&file[1..], &ok).unwrap(); }
match env::args_os().find(|a| a.to_string_lossy().contains("@")) {
Some(file) => {
let file = file.to_str().unwrap();
fs::copy(&file[1..], &ok).unwrap();
}
None => { File::create(&not_ok).unwrap(); }
}
return
@ -84,11 +87,23 @@ fn main() {
continue
}
let mut contents = String::new();
File::open(&ok).unwrap().read_to_string(&mut contents).unwrap();
let mut contents = Vec::new();
File::open(&ok).unwrap().read_to_end(&mut contents).unwrap();
for j in 0..i {
assert!(contents.contains(&format!("{}{}", lib_name, j)));
let exp = format!("{}{}", lib_name, j);
let exp = if cfg!(target_env = "msvc") {
let mut out = Vec::with_capacity(exp.len() * 2);
for c in exp.encode_utf16() {
// encode in little endian
out.push(c as u8);
out.push((c >> 8) as u8);
}
out
} else {
exp.into_bytes()
};
assert!(contents.windows(exp.len()).any(|w| w == &exp[..]));
}
break

View file

@ -27,7 +27,8 @@ fn main() {
let tmpdir = PathBuf::from(env::var_os("TMPDIR").unwrap());
let ok = tmpdir.join("ok");
if env::var("YOU_ARE_A_LINKER").is_ok() {
if let Some(file) = env::args().find(|a| a.contains("@")) {
if let Some(file) = env::args_os().find(|a| a.to_string_lossy().contains("@")) {
let file = file.to_str().expect("non-utf8 file argument");
fs::copy(&file[1..], &ok).unwrap();
}
return
@ -76,11 +77,23 @@ fn main() {
continue
}
let mut contents = String::new();
File::open(&ok).unwrap().read_to_string(&mut contents).unwrap();
let mut contents = Vec::new();
File::open(&ok).unwrap().read_to_end(&mut contents).unwrap();
for j in 0..i {
assert!(contents.contains(&format!("{}{}", lib_name, j)));
let exp = format!("{}{}", lib_name, j);
let exp = if cfg!(target_env = "msvc") {
let mut out = Vec::with_capacity(exp.len() * 2);
for c in exp.encode_utf16() {
// encode in little endian
out.push(c as u8);
out.push((c >> 8) as u8);
}
out
} else {
exp.into_bytes()
};
assert!(contents.windows(exp.len()).any(|w| w == &exp[..]));
}
break

View file

@ -0,0 +1,12 @@
// Copyright 2018 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.
#[inline(always)]
fn main() {}

View file

@ -9,7 +9,10 @@
// except according to those terms.
#![feature(termination_trait)]
#![feature(process_exitcode_placeholder)]
fn main() -> i32 {
0
use std::process::ExitCode;
fn main() -> ExitCode {
ExitCode(0)
}

View file

@ -0,0 +1,26 @@
// Copyright 2018 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.
// Test for https://github.com/rust-lang/rust/issues/48463 issue.
use std::any::Any;
use std::ops::Deref;
pub struct AnyValue {
val: Box<Any>,
}
impl Deref for AnyValue {
type Target = Any;
fn deref(&self) -> &Any {
&*self.val
}
}

View file

@ -83,6 +83,7 @@ static TARGETS: &'static [&'static str] = &[
"mipsel-unknown-linux-gnu",
"mipsel-unknown-linux-musl",
"powerpc-unknown-linux-gnu",
"powerpc-unknown-linux-gnuspe",
"powerpc64-unknown-linux-gnu",
"powerpc64le-unknown-linux-gnu",
"s390x-unknown-linux-gnu",

View file

@ -736,17 +736,12 @@ fn analyze_gdb(gdb: Option<String>) -> (Option<String>, Option<u32>, bool) {
Some(ref s) => s,
};
let version_line = Command::new(gdb)
.arg("--version")
.output()
.map(|output| {
String::from_utf8_lossy(&output.stdout)
.lines()
.next()
.unwrap()
.to_string()
})
.ok();
let mut version_line = None;
if let Ok(output) = Command::new(gdb).arg("--version").output() {
if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() {
version_line = Some(first_line.to_string());
}
}
let version = match version_line {
Some(line) => extract_gdb_version(&line),