From b31ff95ae6fe3fe9501065b11afb8435ce8f783a Mon Sep 17 00:00:00 2001 From: Jewoo Lee Date: Sun, 18 Feb 2018 20:14:21 +0900 Subject: [PATCH 01/25] Add non-panicking variants of pow to all integer types Currently, calling pow may panic in case of overflow, and the function does not have non-panicking counterparts. Thus, it would be beneficial to add those in. --- src/libcore/num/mod.rs | 308 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 560dcf295b278..2b656fad1719e 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! { From bde855518b9f21fe877e1ed62eaa114861131d15 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Feb 2018 05:52:26 +0100 Subject: [PATCH 02/25] RefCell: document panics in Clone, PartialEq, PartialOrd, Ord. Fixes #47400 --- src/libcore/cell.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index ec0d1b704dceb..e91b2c793c5e5 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 is currently mutably 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 is currently mutably borrowed. #[inline] fn partial_cmp(&self, other: &RefCell) -> Option { self.borrow().partial_cmp(&*other.borrow()) } + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. #[inline] fn lt(&self, other: &RefCell) -> bool { *self.borrow() < *other.borrow() } + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. #[inline] fn le(&self, other: &RefCell) -> bool { *self.borrow() <= *other.borrow() } + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. #[inline] fn gt(&self, other: &RefCell) -> bool { *self.borrow() > *other.borrow() } + /// # Panics + /// + /// Panics if the value is currently mutably 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 is currently mutably borrowed. #[inline] fn cmp(&self, other: &RefCell) -> Ordering { self.borrow().cmp(&*other.borrow()) From 2d3f31df8bdcefdd17b5b6a77eac4c94c08aa38d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 20 Feb 2018 19:29:13 +0100 Subject: [PATCH 03/25] Change local storage name for rustdoc because of conflicts with mdbook --- src/librustdoc/html/static/storage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index 0aa1065b3786a..d60e53ef72cca 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -30,7 +30,7 @@ function getCurrentValue(name) { function switchTheme(styleElem, mainStyleElem, newTheme) { styleElem.href = mainStyleElem.href.replace("rustdoc.css", newTheme + ".css"); - updateLocalStorage('theme', newTheme); + updateLocalStorage('rustdoc-theme', newTheme); } switchTheme(currentTheme, mainTheme, getCurrentValue('theme') || 'main'); From 5b61b615f5701bea9482f27e1a9f5ae36df721a7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 20 Feb 2018 20:11:58 +0100 Subject: [PATCH 04/25] Allow to not switch to a theme if it doesn't exist --- src/librustdoc/html/static/main.js | 8 ------- src/librustdoc/html/static/storage.js | 34 ++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index f688be89beebc..ba2e58eb47576 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/storage.js b/src/librustdoc/html/static/storage.js index d60e53ef72cca..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('rustdoc-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'); From 8d51c331c759210ba320c5662ab3ce3af5e0500b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 20 Feb 2018 20:13:17 +0100 Subject: [PATCH 05/25] Remove theme button outline --- src/librustdoc/html/static/rustdoc.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index cd4f2cfa678e6..a6630902c9794 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1189,6 +1189,10 @@ kbd { top: 19px; } +.theme-picker button { + outline: none; +} + #theme-picker { padding: 4px; width: 27px; From b1a6c8bdd3a76207eff76b004945bc2a13755eca Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Thu, 22 Feb 2018 19:53:44 -0500 Subject: [PATCH 06/25] Stabilize [T]::rotate_{left,right} https://github.com/rust-lang/rust/issues/41891 --- src/liballoc/benches/lib.rs | 1 - src/liballoc/lib.rs | 1 - src/liballoc/slice.rs | 20 +++----------------- src/liballoc/tests/lib.rs | 1 - src/libcore/slice/mod.rs | 4 ++-- src/libcore/tests/lib.rs | 1 - 6 files changed, 5 insertions(+), 23 deletions(-) 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/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 3e901a9d442ce..cb8bac10d2b9a 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -35,7 +35,6 @@ #![feature(refcell_replace_swap)] #![feature(sip_hash_13)] #![feature(slice_patterns)] -#![feature(slice_rotate)] #![feature(sort_internals)] #![feature(specialization)] #![feature(step_trait)] From 2985a1abfb48adeb848386377a8c6a3560c17910 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 16 Feb 2018 12:10:06 +0100 Subject: [PATCH 07/25] Report non-standard compile flags on ICE --- src/librustc_driver/lib.rs | 85 +++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 5 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 05dcaf731352a..8171d135cae38 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, From a05c5538d4df190123a11f391784beab2942dcb1 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 23 Feb 2018 13:20:56 -0600 Subject: [PATCH 08/25] Start moving to the rustc guide! --- CONTRIBUTING.md | 2 + README.md | 4 + src/README.md | 15 + src/librustc/README.md | 204 -------------- src/librustc/hir/README.md | 119 -------- src/librustc/hir/map/README.md | 4 - src/librustc/infer/README.md | 227 ---------------- src/librustc/mir/README.md | 90 ------ src/librustc/traits/README.md | 482 --------------------------------- src/librustc/ty/README.md | 165 ----------- 10 files changed, 21 insertions(+), 1291 deletions(-) create mode 100644 src/README.md delete mode 100644 src/librustc/README.md delete mode 100644 src/librustc/hir/README.md delete mode 100644 src/librustc/hir/map/README.md delete mode 100644 src/librustc/infer/README.md delete mode 100644 src/librustc/mir/README.md delete mode 100644 src/librustc/traits/README.md delete mode 100644 src/librustc/ty/README.md 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/librustc/README.md b/src/librustc/README.md deleted file mode 100644 index 722456a76ce59..0000000000000 --- a/src/librustc/README.md +++ /dev/null @@ -1,204 +0,0 @@ -An informal guide to reading and working on the rustc compiler. -================================================================== - -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`). 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/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/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/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. From 70db41cdf74589c957cb930cdd58ebf6bafee5af Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 23 Feb 2018 23:54:24 +0000 Subject: [PATCH 09/25] Handle gdb command failure gracefully in compiletest Previously, if the gdb command was available, but threw an error, compiletest would panic. This is obviously not good. Now, gdb is treated as missing if calling `gdb --version` does not output anything on stdout. --- src/tools/compiletest/src/main.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) 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), From 23dc694c42954499105072cb2c9a3a0006e56d7e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 23 Feb 2018 18:06:05 +0100 Subject: [PATCH 10/25] Fix auto trait impl rustdoc ice --- src/librustdoc/clean/auto_trait.rs | 2 +- src/librustdoc/clean/mod.rs | 6 +++++- src/test/rustdoc/auto-impl-for-trait.rs | 26 +++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 src/test/rustdoc/auto-impl-for-trait.rs 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/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 + } +} From e20f7b2ea73fbe0077a565c692a3a6f2e20ff4e3 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 24 Feb 2018 00:31:33 -0800 Subject: [PATCH 11/25] Restrict the Termination impls to simplify stabilization Make a minimal commitment for stabilization. More impls are likely in future, but are not necessary at this time. --- src/libstd/process.rs | 24 ++++++++++++++----- ...2.rs => termination-trait-for-exitcode.rs} | 7 ++++-- 2 files changed, 23 insertions(+), 8 deletions(-) rename src/test/run-pass/rfc-1937-termination-trait/{termination-trait-for-i32.rs => termination-trait-for-exitcode.rs} (81%) 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-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) } From 968ce252a849e1890e5701ed92b8861ce4ac1fe2 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sun, 25 Feb 2018 15:24:14 -0600 Subject: [PATCH 12/25] Change links to readmes --- src/librustc/README.md | 3 +++ src/librustc/dep_graph/graph.rs | 4 ++-- src/librustc/hir/mod.rs | 4 ++-- src/librustc/lib.rs | 5 +++-- src/librustc/traits/coherence.rs | 6 +++++- src/librustc/traits/mod.rs | 4 +++- src/librustc/traits/select.rs | 13 +++++++++---- src/librustc/ty/context.rs | 4 ++-- 8 files changed, 29 insertions(+), 14 deletions(-) create mode 100644 src/librustc/README.md diff --git a/src/librustc/README.md b/src/librustc/README.md new file mode 100644 index 0000000000000..9909ff91a18aa --- /dev/null +++ b/src/librustc/README.md @@ -0,0 +1,3 @@ +For more information about how rustc works, see the [rustc guide]. + +[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 55ec8adb5fbf3..08d3a2bb1aa8d 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -166,7 +166,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 @@ -186,7 +186,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/mod.rs b/src/librustc/hir/mod.rs index bc03f7ead8187..b2b8069bf1b88 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -601,9 +601,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/lib.rs b/src/librustc/lib.rs index a7a2619505931..7ab584954d2e2 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/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 41cc8ca601ac0..bb26e9d085510 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 4ed25646d436d..3ffde1521b99e 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::*; @@ -1025,8 +1027,9 @@ 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>) @@ -2312,7 +2315,9 @@ 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/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>, From d6f22a248106b0ade754ad1e3573fac2ebb8f182 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sun, 25 Feb 2018 15:26:53 -0600 Subject: [PATCH 13/25] Make comment into a doc comment and change readme ref --- src/librustc/traits/specialize/mod.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) 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; From 7a82da1c4d3c5cb3e7bfa0dc43337842a677943c Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sun, 25 Feb 2018 15:42:25 -0600 Subject: [PATCH 14/25] tidy fix --- src/librustc/traits/select.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3ffde1521b99e..22e23cc012b44 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1029,7 +1029,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // caller obligations, and so forth and assembling a list of // candidates. See [rustc guide] for more details. // - // [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html#candidate-assembly + // [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>) @@ -2317,7 +2318,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // with the values found in the obligation, possibly yielding a // type error. See [rustc guide] for more details. // - // [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html#confirmation + // [rustc guide]: + // https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html#confirmation fn confirm_candidate(&mut self, obligation: &TraitObligation<'tcx>, From 24666443898c142944b4156c22d04130b9db645b Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 25 Feb 2018 23:05:06 +0000 Subject: [PATCH 15/25] Ensure main() always has external linkage This ensures that the entry function is never elided due to inlining, even with `inline(always)`. Fixes #47783. There were a couple of possible ways of addressing this issue; I simply picked the one that seemed most direct. A warning could be appropriate, but considering using inlining hints in other places it doesn't apply also throws no warnings, and it seems like an edge case anyway, I haven't added one for now. --- src/librustc_mir/monomorphize/item.rs | 5 ++++- src/test/run-pass/inlined-main.rs | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/inlined-main.rs 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/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() {} From 88de279dca86ed5bfd8a0ab6089ff6af2bfc7c2b Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Fri, 23 Feb 2018 22:15:40 +0100 Subject: [PATCH 16/25] bootstrap: Add openssl configuration for powerpc-unknown-linux-gnuspe --- src/bootstrap/native.rs | 1 + 1 file changed, 1 insertion(+) 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", From a22fbf8a9c89e9e7fd19a50b711e6f9cac21c6b5 Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Fri, 23 Feb 2018 22:18:40 +0100 Subject: [PATCH 17/25] librustc_back: Add support for powerpc-linux-gnuspe --- src/librustc_back/target/mod.rs | 1 + .../target/powerpc_unknown_linux_gnuspe.rs | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 src/librustc_back/target/powerpc_unknown_linux_gnuspe.rs diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index d356105e39314..40b1b10c73b76 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), 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, + }) +} From b7683a33ce22d4ca13991abd3ad8c4ba1ec19d39 Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Fri, 23 Feb 2018 22:22:15 +0100 Subject: [PATCH 18/25] build-manifest: Add powerpc-unknown-linux-gnuspe target --- src/tools/build-manifest/src/main.rs | 1 + 1 file changed, 1 insertion(+) 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", From 7c84ba43ce28ee681d307f6db5ce72c06c354c5a Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Fri, 23 Feb 2018 22:46:48 +0100 Subject: [PATCH 19/25] test: Run atomic-lock-free on powerpc-linux-gnuspe --- src/test/run-make/atomic-lock-free/Makefile | 2 ++ 1 file changed, 2 insertions(+) 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 From 5db73fc6dbf9e4ee1a498655cb609efdf5fa93ed Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Thu, 22 Feb 2018 16:37:44 -0700 Subject: [PATCH 20/25] Encode linker arguments as UTF-16 on MSVC platforms --- src/librustc_trans/back/link.rs | 14 ++++++++++- .../long-linker-command-lines-cmd-exe/foo.rs | 25 +++++++++++++++---- .../run-make/long-linker-command-lines/foo.rs | 21 +++++++++++++--- 3 files changed, 50 insertions(+), 10 deletions(-) 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/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 From 2026453bcf7e2479cd2a1a3602985a2fdd9bc241 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 26 Feb 2018 10:20:14 -0800 Subject: [PATCH 21/25] Add specific target option for returning struct as an integer. --- src/librustc_back/target/apple_base.rs | 1 + src/librustc_back/target/mod.rs | 11 +++++------ src/librustc_back/target/openbsd_base.rs | 2 +- src/librustc_back/target/windows_base.rs | 1 + src/librustc_back/target/windows_msvc_base.rs | 1 + src/librustc_trans/cabi_x86.rs | 3 +-- 6 files changed, 10 insertions(+), 9 deletions(-) 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/mod.rs b/src/librustc_back/target/mod.rs index 2872c59157d6b..e734817098043 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -343,9 +343,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, @@ -501,7 +500,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, @@ -756,7 +755,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); @@ -954,7 +953,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/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_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) { From 279e5b0a48cd9883a6e43571a9de25de06bdde22 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 26 Feb 2018 10:21:35 -0800 Subject: [PATCH 22/25] FreeBSD uses Clang which can return small structs as an integer. --- src/librustc_back/target/freebsd_base.rs | 1 + 1 file changed, 1 insertion(+) 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() } } From 9c80019e6c14ba7ecd00f896cfb4bdcce0066101 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Mon, 26 Feb 2018 15:07:24 -0700 Subject: [PATCH 23/25] Fix error-format argument to x.py --- src/bootstrap/compile.rs | 4 ++++ src/bootstrap/flags.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) 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| -> ! { From c133a082a87ac2cb520688e33ed17aa794cab368 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 26 Feb 2018 15:58:16 -0800 Subject: [PATCH 24/25] rustc: Rename `bmi` feature to `bmi1` This is what [Intel calls it][bmi1] and will [remove a special case][stdsimd] when verifying intrinsics in stdsimd. [bmi1]: https://software.intel.com/sites/landingpage/IntrinsicsGuide/#othertechs=BMI1 [stdsimd]: https://github.com/rust-lang-nursery/stdsimd/blob/bed25b2a9f3b28e6ea80de6d87842f739a2e2d58/crates/stdsimd-verify/tests/x86-intel.rs#L252-L258 --- src/librustc_trans/llvm_util.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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, } } From f8ebb3f09fa98cf5583f6bd8d5677a1f4dd0941d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 27 Feb 2018 15:48:50 +0100 Subject: [PATCH 25/25] fix wording on panics in binary operators on RefCells" --- src/libcore/cell.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index e91b2c793c5e5..419ae96b94bd6 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -885,7 +885,7 @@ impl Default for RefCell { impl PartialEq for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn eq(&self, other: &RefCell) -> bool { *self.borrow() == *other.borrow() @@ -899,7 +899,7 @@ impl Eq for RefCell {} impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn partial_cmp(&self, other: &RefCell) -> Option { self.borrow().partial_cmp(&*other.borrow()) @@ -907,7 +907,7 @@ impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn lt(&self, other: &RefCell) -> bool { *self.borrow() < *other.borrow() @@ -915,7 +915,7 @@ impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn le(&self, other: &RefCell) -> bool { *self.borrow() <= *other.borrow() @@ -923,7 +923,7 @@ impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn gt(&self, other: &RefCell) -> bool { *self.borrow() > *other.borrow() @@ -931,7 +931,7 @@ impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn ge(&self, other: &RefCell) -> bool { *self.borrow() >= *other.borrow() @@ -942,7 +942,7 @@ impl PartialOrd for RefCell { impl Ord for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn cmp(&self, other: &RefCell) -> Ordering { self.borrow().cmp(&*other.borrow())