diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 70376c120fc0a..552961b9b66c1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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 diff --git a/README.md b/README.md index 589aa1afe35ec..fd35606ec0dbb 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000000000..690ab674c64eb --- /dev/null +++ b/src/README.md @@ -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 diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index c85b04ddc0245..2c9f0ddb6c33d 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -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() { diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 8ca5910a11c0d..af50ad1e96b9f 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -119,7 +119,7 @@ To learn more about a subcommand, run `./x.py -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| -> ! { diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 15dd7fabfa58b..653606e5d24b5 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -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", diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index 174628ccd0788..2de0ffb4b2611 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -13,7 +13,6 @@ #![feature(i128_type)] #![feature(rand)] #![feature(repr_simd)] -#![feature(slice_rotate)] #![feature(test)] extern crate rand; diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 5139e54b5604a..d250cfe1880fc 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -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)] diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 028983de556f2..dc40062ef13df 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -1460,8 +1460,6 @@ impl [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] { /// 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] { /// # 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] { /// 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); } diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 427a7adcbded1..168dbb2ce9b1f 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -23,7 +23,6 @@ #![feature(pattern)] #![feature(placement_in_syntax)] #![feature(rand)] -#![feature(slice_rotate)] #![feature(splice)] #![feature(str_escape)] #![feature(string_retain)] diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index ec0d1b704dceb..419ae96b94bd6 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -863,6 +863,9 @@ impl !Sync for RefCell {} #[stable(feature = "rust1", since = "1.0.0")] impl Clone for RefCell { + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. #[inline] fn clone(&self) -> RefCell { RefCell::new(self.borrow().clone()) @@ -880,6 +883,9 @@ impl Default for RefCell { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for RefCell { + /// # Panics + /// + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn eq(&self, other: &RefCell) -> bool { *self.borrow() == *other.borrow() @@ -891,26 +897,41 @@ impl Eq for RefCell {} #[stable(feature = "cell_ord", since = "1.10.0")] impl PartialOrd for RefCell { + /// # Panics + /// + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn partial_cmp(&self, other: &RefCell) -> Option { self.borrow().partial_cmp(&*other.borrow()) } + /// # Panics + /// + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn lt(&self, other: &RefCell) -> bool { *self.borrow() < *other.borrow() } + /// # Panics + /// + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn le(&self, other: &RefCell) -> bool { *self.borrow() <= *other.borrow() } + /// # Panics + /// + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn gt(&self, other: &RefCell) -> bool { *self.borrow() > *other.borrow() } + /// # Panics + /// + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn ge(&self, other: &RefCell) -> bool { *self.borrow() >= *other.borrow() @@ -919,6 +940,9 @@ impl PartialOrd for RefCell { #[stable(feature = "cell_ord", since = "1.10.0")] impl Ord for RefCell { + /// # Panics + /// + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn cmp(&self, other: &RefCell) -> Ordering { self.borrow().cmp(&*other.borrow()) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 7d5aa25016bdd..59a67fff48cfe 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -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 { + 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 { + 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! { diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index ac390313a6797..a43ed65907f83 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -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")] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 7954d52f6b1e3..0049ed66a102a 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -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)] diff --git a/src/librustc/README.md b/src/librustc/README.md index 722456a76ce59..9909ff91a18aa 100644 --- a/src/librustc/README.md +++ b/src/librustc/README.md @@ -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`) -- 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/ diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index b77431e806a6d..61a8fb09118bf 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -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(&self, key: DepNode, cx: C, diff --git a/src/librustc/hir/README.md b/src/librustc/hir/README.md deleted file mode 100644 index e283fc40c50a3..0000000000000 --- a/src/librustc/hir/README.md +++ /dev/null @@ -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` -- 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>`, 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()`). diff --git a/src/librustc/hir/map/README.md b/src/librustc/hir/map/README.md deleted file mode 100644 index 34ed325705ab9..0000000000000 --- a/src/librustc/hir/map/README.md +++ /dev/null @@ -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 diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 0fa1b95d8e777..c4873cb83076a 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -602,9 +602,9 @@ pub type CrateConfig = HirVec>; /// 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, diff --git a/src/librustc/infer/README.md b/src/librustc/infer/README.md deleted file mode 100644 index 7f58d03906026..0000000000000 --- a/src/librustc/infer/README.md +++ /dev/null @@ -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. diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 2e7bf4d001d26..d08a41010ab16 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -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 //! diff --git a/src/librustc/mir/README.md b/src/librustc/mir/README.md deleted file mode 100644 index cac86be0fcb75..0000000000000 --- a/src/librustc/mir/README.md +++ /dev/null @@ -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>`, 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`. - diff --git a/src/librustc/traits/README.md b/src/librustc/traits/README.md deleted file mode 100644 index fa7f5c08608bb..0000000000000 --- a/src/librustc/traits/README.md +++ /dev/null @@ -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(x: &[T]) -> Vec { /*...*/ } -``` - -and then a call to that function: - -```rust -let v: Vec = 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(x: &[T]) -> Vec { - 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 { - 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 for isize { /*...*/ } // isize -> usize -impl Convert 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 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 Get for T { - fn get(&self) -> T { *self } -} - -impl Get for Box { - fn get(&self) -> Box { box get_it(&**self) } -} -``` - -What happens when we invoke `get_it(&box 1_u16)`, for example? In this -case, the `Self` type is `Box` -- 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 : 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 { /*...*/ } -``` - -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> Foo for Vec { /*...*/ } - -impl Bar for isize { /*...*/ } -``` - -After one shallow round of selection for an obligation like `Vec -: 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` 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 { - 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() 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 { - fn foo(&self, x: X) { } -} - -trait Bar { - fn bar(&self, x: X) { } -} - -impl Foo for F - where F : Bar -{ -} -``` - -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`. 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 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. diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 7311b47974ac5..a9f1c8750f4be 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -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; diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 49f43b18e6198..c1ffc10c3c0f0 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -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::*; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 9a3738c163d38..f21ec295c5f7b 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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>, diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index afe29cc0e7baf..72d9dd9012ca9 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -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; diff --git a/src/librustc/ty/README.md b/src/librustc/ty/README.md deleted file mode 100644 index 3fd956ecfb87d..0000000000000 --- a/src/librustc/ty/README.md +++ /dev/null @@ -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` - 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. diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e4e07454c97ac..3613a34f66af6 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -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>, diff --git a/src/librustc_back/target/apple_base.rs b/src/librustc_back/target/apple_base.rs index 159f93a74c683..72173b62594e9 100644 --- a/src/librustc_back/target/apple_base.rs +++ b/src/librustc_back/target/apple_base.rs @@ -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() } } diff --git a/src/librustc_back/target/freebsd_base.rs b/src/librustc_back/target/freebsd_base.rs index a0f84a6ab0495..291b22768998c 100644 --- a/src/librustc_back/target/freebsd_base.rs +++ b/src/librustc_back/target/freebsd_base.rs @@ -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() } } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index d356105e39314..be69127d8f2ab 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -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, - /// 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); diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_back/target/openbsd_base.rs index ab421dec7807f..311e260ee3f34 100644 --- a/src/librustc_back/target/openbsd_base.rs +++ b/src/librustc_back/target/openbsd_base.rs @@ -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 diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnuspe.rs b/src/librustc_back/target/powerpc_unknown_linux_gnuspe.rs new file mode 100644 index 0000000000000..ffcc321749b5a --- /dev/null +++ b/src/librustc_back/target/powerpc_unknown_linux_gnuspe.rs @@ -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 or the MIT license +// , 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, + }) +} diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs index cc40b8b052983..30038400f6c81 100644 --- a/src/librustc_back/target/windows_base.rs +++ b/src/librustc_back/target/windows_base.rs @@ -101,6 +101,7 @@ pub fn opts() -> TargetOptions { "rsend.o".to_string() ], custom_unwind_resume: true, + abi_return_struct_as_int: true, .. Default::default() } diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs index 64df6624dd1c2..e0bf36ee4077e 100644 --- a/src/librustc_back/target/windows_msvc_base.rs +++ b/src/librustc_back/target/windows_msvc_base.rs @@ -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() } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index f872fd475461e..6af7a23f66d73 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -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(result: Result, sess: &Session) -> T { match result { Err(CompileIncomplete::Errored(ErrorReported)) => { @@ -1431,6 +1444,57 @@ pub fn in_rustc_thread(f: F) -> Result> 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, 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: 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, diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 549919a2c8919..7c86f5a4b1a84 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -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 } } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index d7c75dea8d04e..8f308e726865c 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -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(); diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs index 60347ba0945f9..b14558448067c 100644 --- a/src/librustc_trans/cabi_x86.rs +++ b/src/librustc_trans/cabi_x86.rs @@ -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) { diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 6271dcdfb2433..00ac9d802457c 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -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, } } diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index f1bba0e836189..3654de6fb2ed2 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -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), }; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4543b246b83ad..870b5383852b0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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() { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index aa09e93e61ac1..960f2f198d8b0 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -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) } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index d91e0679ed02d..b70dc37fdd55e 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1202,6 +1202,10 @@ kbd { top: 19px; } +.theme-picker button { + outline: none; +} + #theme-picker { padding: 4px; width: 27px; diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index 0aa1065b3786a..f21dfc8af9298 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -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'); diff --git a/src/libstd/process.rs b/src/libstd/process.rs index e25599b8bd871..e5fc33e241c89 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -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 Termination for Result { +impl Termination for Result<(), E> { fn report(self) -> i32 { match self { Ok(val) => val.report(), @@ -1442,20 +1451,23 @@ impl Termination for Result { #[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 Termination for Result { 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 } } diff --git a/src/test/run-make/atomic-lock-free/Makefile b/src/test/run-make/atomic-lock-free/Makefile index 63b8608afc763..a7df821f92d71 100644 --- a/src/test/run-make/atomic-lock-free/Makefile +++ b/src/test/run-make/atomic-lock-free/Makefile @@ -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 diff --git a/src/test/run-make/long-linker-command-lines-cmd-exe/foo.rs b/src/test/run-make/long-linker-command-lines-cmd-exe/foo.rs index f9168a82e2259..67d8ad0b67255 100644 --- a/src/test/run-make/long-linker-command-lines-cmd-exe/foo.rs +++ b/src/test/run-make/long-linker-command-lines-cmd-exe/foo.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 diff --git a/src/test/run-make/long-linker-command-lines/foo.rs b/src/test/run-make/long-linker-command-lines/foo.rs index e6fd6b653667f..2ac240982afc4 100644 --- a/src/test/run-make/long-linker-command-lines/foo.rs +++ b/src/test/run-make/long-linker-command-lines/foo.rs @@ -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 diff --git a/src/test/run-pass/inlined-main.rs b/src/test/run-pass/inlined-main.rs new file mode 100644 index 0000000000000..1288c37d615cd --- /dev/null +++ b/src/test/run-pass/inlined-main.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[inline(always)] +fn main() {} diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-i32.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs similarity index 81% rename from src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-i32.rs rename to src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs index fa7cb023b447c..30ecc4e89372b 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-i32.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs @@ -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) } diff --git a/src/test/rustdoc/auto-impl-for-trait.rs b/src/test/rustdoc/auto-impl-for-trait.rs new file mode 100644 index 0000000000000..3cd6e7aa4b3d2 --- /dev/null +++ b/src/test/rustdoc/auto-impl-for-trait.rs @@ -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 or the MIT license +// , 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, +} + +impl Deref for AnyValue { + type Target = Any; + + fn deref(&self) -> &Any { + &*self.val + } +} diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 0845179532224..49b054f8b9e50 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -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", diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index e3d453a991d80..304143eaa0bff 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -736,17 +736,12 @@ fn analyze_gdb(gdb: Option) -> (Option, Option, 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),