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:
commit
0ff9872b22
55 changed files with 698 additions and 1394 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
15
src/README.md
Normal 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
|
||||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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| -> ! {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#![feature(i128_type)]
|
||||
#![feature(rand)]
|
||||
#![feature(repr_simd)]
|
||||
#![feature(slice_rotate)]
|
||||
#![feature(test)]
|
||||
|
||||
extern crate rand;
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
#![feature(pattern)]
|
||||
#![feature(placement_in_syntax)]
|
||||
#![feature(rand)]
|
||||
#![feature(slice_rotate)]
|
||||
#![feature(splice)]
|
||||
#![feature(str_escape)]
|
||||
#![feature(string_retain)]
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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! {
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()`).
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
35
src/librustc_back/target/powerpc_unknown_linux_gnuspe.rs
Normal file
35
src/librustc_back/target/powerpc_unknown_linux_gnuspe.rs
Normal 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,
|
||||
})
|
||||
}
|
||||
|
|
@ -101,6 +101,7 @@ pub fn opts() -> TargetOptions {
|
|||
"rsend.o".to_string()
|
||||
],
|
||||
custom_unwind_resume: true,
|
||||
abi_return_struct_as_int: true,
|
||||
|
||||
.. Default::default()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
¬e,
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1202,6 +1202,10 @@ kbd {
|
|||
top: 19px;
|
||||
}
|
||||
|
||||
.theme-picker button {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#theme-picker {
|
||||
padding: 4px;
|
||||
width: 27px;
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(¬_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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
12
src/test/run-pass/inlined-main.rs
Normal file
12
src/test/run-pass/inlined-main.rs
Normal 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() {}
|
||||
|
|
@ -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)
|
||||
}
|
||||
26
src/test/rustdoc/auto-impl-for-trait.rs
Normal file
26
src/test/rustdoc/auto-impl-for-trait.rs
Normal 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue