From 6701d9020f0deb0e8d673fe5ad1247514b3e9db3 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 6 Mar 2018 00:58:01 +0000 Subject: [PATCH 01/19] Remove IdxSet::reset_to_empty --- src/librustc_data_structures/indexed_set.rs | 5 ----- src/librustc_mir/dataflow/at_location.rs | 8 ++++---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 223e08de826ce..7c926cc784b41 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -231,11 +231,6 @@ impl IdxSet { each_bit(self, max_bits, f) } - /// Removes all elements from this set. - pub fn reset_to_empty(&mut self) { - for word in self.words_mut() { *word = 0; } - } - pub fn elems(&self, universe_size: usize) -> Elems { Elems { i: 0, set: self, universe_size: universe_size } } diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs index b1f73bfbe2284..30248ccf931cb 100644 --- a/src/librustc_mir/dataflow/at_location.rs +++ b/src/librustc_mir/dataflow/at_location.rs @@ -147,8 +147,8 @@ impl FlowsAtLocation for FlowAtLocation } fn reconstruct_statement_effect(&mut self, loc: Location) { - self.stmt_gen.reset_to_empty(); - self.stmt_kill.reset_to_empty(); + self.stmt_gen.clear(); + self.stmt_kill.clear(); { let mut sets = BlockSets { on_entry: &mut self.curr_state, @@ -172,8 +172,8 @@ impl FlowsAtLocation for FlowAtLocation } fn reconstruct_terminator_effect(&mut self, loc: Location) { - self.stmt_gen.reset_to_empty(); - self.stmt_kill.reset_to_empty(); + self.stmt_gen.clear(); + self.stmt_kill.clear(); { let mut sets = BlockSets { on_entry: &mut self.curr_state, From 89d12478ac4f56e45da7ece5d5cac983897653d6 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 6 Mar 2018 01:00:44 +0000 Subject: [PATCH 02/19] Remove IdxSet::each_bit --- src/librustc_data_structures/indexed_set.rs | 33 --------------------- src/librustc_mir/dataflow/at_location.rs | 6 ++-- src/librustc_mir/dataflow/mod.rs | 3 +- 3 files changed, 3 insertions(+), 39 deletions(-) diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 7c926cc784b41..34457d94c3aee 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -225,12 +225,6 @@ impl IdxSet { } } - /// Calls `f` on each index value held in this set, up to the - /// bound `max_bits` on the size of universe of indexes. - pub fn each_bit(&self, max_bits: usize, f: F) where F: FnMut(T) { - each_bit(self, max_bits, f) - } - pub fn elems(&self, universe_size: usize) -> Elems { Elems { i: 0, set: self, universe_size: universe_size } } @@ -256,33 +250,6 @@ impl<'a, T: Idx> Iterator for Elems<'a, T> { } } } - -fn each_bit(words: &IdxSet, max_bits: usize, mut f: F) where F: FnMut(T) { - let usize_bits: usize = mem::size_of::() * 8; - - for (word_index, &word) in words.words().iter().enumerate() { - if word != 0 { - let base_index = word_index * usize_bits; - for offset in 0..usize_bits { - let bit = 1 << offset; - if (word & bit) != 0 { - // NB: we round up the total number of bits - // that we store in any given bit set so that - // it is an even multiple of usize::BITS. This - // means that there may be some stray bits at - // the end that do not correspond to any - // actual value; that's why we first check - // that we are in range of bits_per_block. - let bit_index = base_index + offset as usize; - if bit_index >= max_bits { - return; - } else { - f(Idx::new(bit_index)); - } - } - } - } - } } pub struct Iter<'a, T: Idx> { diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs index 30248ccf931cb..32ca513d7df2c 100644 --- a/src/librustc_mir/dataflow/at_location.rs +++ b/src/librustc_mir/dataflow/at_location.rs @@ -81,8 +81,7 @@ where where F: FnMut(BD::Idx), { - self.curr_state - .each_bit(self.base_results.operator().bits_per_block(), f) + self.curr_state.iter().for_each(f) } /// Iterate over each `gen` bit in the current effect (invoke @@ -92,8 +91,7 @@ where where F: FnMut(BD::Idx), { - self.stmt_gen - .each_bit(self.base_results.operator().bits_per_block(), f) + self.stmt_gen.iter().for_each(f) } pub fn new(results: DataflowResults) -> Self { diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index aa7bb6f97786c..7785b6ec17379 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -444,8 +444,7 @@ pub struct DataflowState impl DataflowState { pub fn each_bit(&self, words: &IdxSet, f: F) where F: FnMut(O::Idx) { - let bits_per_block = self.operator.bits_per_block(); - words.each_bit(bits_per_block, f) + words.iter().for_each(f) } pub(crate) fn interpret_set<'c, P>(&self, From f69a0999e742a6fc45fd4b962c30c56d04c2245c Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 6 Mar 2018 01:00:53 +0000 Subject: [PATCH 03/19] Remove IdxSet::elems --- src/librustc_data_structures/indexed_set.rs | 26 --------------------- src/librustc_mir/borrow_check/mod.rs | 10 ++++---- src/librustc_mir/dataflow/at_location.rs | 14 +++++------ 3 files changed, 11 insertions(+), 39 deletions(-) diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 34457d94c3aee..7ab6a2691488e 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -224,32 +224,6 @@ impl IdxSet { _pd: PhantomData, } } - - pub fn elems(&self, universe_size: usize) -> Elems { - Elems { i: 0, set: self, universe_size: universe_size } - } -} - -pub struct Elems<'a, T: Idx> { i: usize, set: &'a IdxSet, universe_size: usize } - -impl<'a, T: Idx> Iterator for Elems<'a, T> { - type Item = T; - fn next(&mut self) -> Option { - if self.i >= self.universe_size { return None; } - let mut i = self.i; - loop { - if i >= self.universe_size { - self.i = i; // (mark iteration as complete.) - return None; - } - if self.set.contains(&T::new(i)) { - self.i = i + 1; // (next element to start at.) - return Some(T::new(i)); - } - i = i + 1; - } - } -} } pub struct Iter<'a, T: Idx> { diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 1ff0ffaaa68b3..f0304ccd0405e 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -555,7 +555,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx // Look for any active borrows to locals let domain = flow_state.borrows.operator(); let data = domain.borrows(); - flow_state.borrows.with_elems_outgoing(|borrows| { + flow_state.borrows.with_iter_outgoing(|borrows| { for i in borrows { let borrow = &data[i.borrow_index()]; self.check_for_local_borrow(borrow, span); @@ -571,7 +571,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx // so this "extra check" serves as a kind of backup. let domain = flow_state.borrows.operator(); let data = domain.borrows(); - flow_state.borrows.with_elems_outgoing(|borrows| { + flow_state.borrows.with_iter_outgoing(|borrows| { for i in borrows { let borrow = &data[i.borrow_index()]; let context = ContextKind::StorageDead.new(loc); @@ -1310,7 +1310,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { place ); - for i in flow_state.ever_inits.elems_incoming() { + for i in flow_state.ever_inits.iter_incoming() { let init = self.move_data.inits[i]; let init_place = &self.move_data.move_paths[init.path].place; if self.places_conflict(&init_place, place, Deep) { @@ -2155,8 +2155,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // check for loan restricting path P being used. Accounts for // borrows of P, P.a.b, etc. - let mut elems_incoming = flow_state.borrows.elems_incoming(); - while let Some(i) = elems_incoming.next() { + let mut iter_incoming = flow_state.borrows.iter_incoming(); + while let Some(i) = iter_incoming.next() { let borrowed = &data[i.borrow_index()]; if self.places_conflict(&borrowed.borrowed_place, place, access) { diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs index 32ca513d7df2c..0fbb54e8e0a08 100644 --- a/src/librustc_mir/dataflow/at_location.rs +++ b/src/librustc_mir/dataflow/at_location.rs @@ -12,7 +12,7 @@ //! locations. use rustc::mir::{BasicBlock, Location}; -use rustc_data_structures::indexed_set::{self, IdxSetBuf}; +use rustc_data_structures::indexed_set::{IdxSetBuf, Iter}; use rustc_data_structures::indexed_vec::Idx; use dataflow::{BitDenotation, BlockSets, DataflowResults}; @@ -117,23 +117,21 @@ where } /// Returns an iterator over the elements present in the current state. - pub fn elems_incoming(&self) -> iter::Peekable> { - let univ = self.base_results.sets().bits_per_block(); - self.curr_state.elems(univ).peekable() + pub fn iter_incoming(&self) -> iter::Peekable> { + self.curr_state.iter().peekable() } /// Creates a clone of the current state and applies the local /// effects to the clone (leaving the state of self intact). /// Invokes `f` with an iterator over the resulting state. - pub fn with_elems_outgoing(&self, f: F) + pub fn with_iter_outgoing(&self, f: F) where - F: FnOnce(indexed_set::Elems), + F: FnOnce(Iter), { let mut curr_state = self.curr_state.clone(); curr_state.union(&self.stmt_gen); curr_state.subtract(&self.stmt_kill); - let univ = self.base_results.sets().bits_per_block(); - f(curr_state.elems(univ)); + f(curr_state.iter()); } } From c97c7bfcf377a37f400f1e1a3e25ace2eba85316 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Tue, 6 Mar 2018 00:01:30 -0500 Subject: [PATCH 04/19] Add info message for -Wall command Users coming from other languages (namely C and C++) often expect to use a -Wall flag. Rustc doesn't support that, and previously it simply printed that it didn't recognize the "all" lint. This change makes rustc print out a help message, explaining: - Why there is no -Wall flag - How to view all the available warnings - Point out that the most commonly used warning is -Wunused - Instead of using a command-line flag, the user should consider a !#[warn(unused)] directive in the root of their crate. --- src/librustc_driver/lib.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index d89a3e9d907ea..b9b36616e69f6 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1136,6 +1136,16 @@ fn usage(verbose: bool, include_unstable_options: bool) { verbose_help); } +fn print_wall_help() { + println!(" +The flag -Wall does not exist in rustc. Most useful lints are enabled by default. +Use `rustc -W help` to see all available lints. The most used lints that are not +enabled by default covered by -Wunused; however, the best practice is to put +warning settings in the crate root using `#![warn(unused)]` instead of using +the command line flag directly. +"); +} + fn describe_lints(sess: &Session, lint_store: &lint::LintStore, loaded_plugins: bool) { println!(" Available lint options: @@ -1379,6 +1389,13 @@ pub fn handle_options(args: &[String]) -> Option { nightly_options::is_unstable_enabled(&matches)); return None; } + + // Handle the special case of -Wall. + let wall = matches.opt_strs("W"); + if wall.iter().any(|x| *x == "all") { + print_wall_help(); + return None; + } // Don't handle -W help here, because we might first load plugins. let r = matches.opt_strs("Z"); From 1246eef9a9508e6eb5ecbf9718f3b320b07aab05 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Tue, 6 Mar 2018 17:24:58 -0500 Subject: [PATCH 05/19] Fix trailing whitespace --- src/librustc_driver/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b9b36616e69f6..47168cb955a0e 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1389,7 +1389,7 @@ pub fn handle_options(args: &[String]) -> Option { nightly_options::is_unstable_enabled(&matches)); return None; } - + // Handle the special case of -Wall. let wall = matches.opt_strs("W"); if wall.iter().any(|x| *x == "all") { From f53f2fa2e894c4709d7b09995331f30c596d0724 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Thu, 8 Mar 2018 11:52:41 +0000 Subject: [PATCH 06/19] librustc_back: bump ISA level of mipsel targets to mips32r2 --- src/librustc_back/target/mipsel_unknown_linux_gnu.rs | 4 ++-- src/librustc_back/target/mipsel_unknown_linux_musl.rs | 4 ++-- src/librustc_back/target/mipsel_unknown_linux_uclibc.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs index 2c38444d050fb..94f82adfacde1 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs @@ -25,8 +25,8 @@ pub fn target() -> TargetResult { linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { - cpu: "mips32".to_string(), - features: "+mips32".to_string(), + cpu: "mips32r2".to_string(), + features: "+mips32r2".to_string(), max_atomic_width: Some(32), // see #36994 diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_back/target/mipsel_unknown_linux_musl.rs index b09d96eb9cbcb..6bef2fe2ea717 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_musl.rs @@ -13,8 +13,8 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); - base.cpu = "mips32".to_string(); - base.features = "+mips32,+soft-float".to_string(); + base.cpu = "mips32r2".to_string(); + base.features = "+mips32r2,+soft-float".to_string(); base.max_atomic_width = Some(32); // see #36994 base.exe_allocation_crate = None; diff --git a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs index 5d2ba548769ff..a5dbdd1118359 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs @@ -25,8 +25,8 @@ pub fn target() -> TargetResult { linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { - cpu: "mips32".to_string(), - features: "+mips32,+soft-float".to_string(), + cpu: "mips32r2".to_string(), + features: "+mips32r2,+soft-float".to_string(), max_atomic_width: Some(32), // see #36994 From fccaf252df7d5426ae5b0d8b8359357fe526fc58 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Thu, 8 Mar 2018 11:53:19 +0000 Subject: [PATCH 07/19] librustc_back: enable fpxx on 32-bit hardfloat mips targets See this page for details about FPXX: https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking Using FPXX is the most compatible floating point mode available and allows the generated code to work in both FR0 and FR1 modes of the processor. Using MSA (MIPS SIMD) requires FR1, so to use any MSA code we need a compatible floating point mode. This commit also sets nooddspreg (disabling the use of odd numbered single precision float registers) as recommended when enabling FPXX. --- src/librustc_back/target/mips_unknown_linux_gnu.rs | 2 +- src/librustc_back/target/mipsel_unknown_linux_gnu.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs index 5a43e1c4c7a0f..cffd1daed99f2 100644 --- a/src/librustc_back/target/mips_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs @@ -25,7 +25,7 @@ pub fn target() -> TargetResult { linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32r2".to_string(), - features: "+mips32r2".to_string(), + features: "+mips32r2,+fpxx,+nooddspreg".to_string(), max_atomic_width: Some(32), // see #36994 diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs index 94f82adfacde1..555855b8f815d 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs @@ -26,7 +26,7 @@ pub fn target() -> TargetResult { options: TargetOptions { cpu: "mips32r2".to_string(), - features: "+mips32r2".to_string(), + features: "+mips32r2,+fpxx,+nooddspreg".to_string(), max_atomic_width: Some(32), // see #36994 From 0711a7a72f5828825357a4eb5db70aedb2dabef4 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Thu, 8 Mar 2018 12:04:09 +0000 Subject: [PATCH 08/19] librustc_trans: add fp64 to mips features whitelist On 32-bit MIPS, enabling MSA requires also enabling the 64-bit FPU. --- src/librustc_trans/llvm_util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 45445a48e233e..afe32f3f66933 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -104,7 +104,7 @@ const POWERPC_WHITELIST: &'static [&'static str] = &["altivec", "power8-vector", "power9-vector", "vsx"]; -const MIPS_WHITELIST: &'static [&'static str] = &["msa"]; +const MIPS_WHITELIST: &'static [&'static str] = &["fp64", "msa"]; pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { let arch = if sess.target.target.arch == "x86_64" { From 366ee8518fe53e821e809812ba80e7696861c93c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Mar 2018 00:11:17 +0100 Subject: [PATCH 09/19] Fix blink when main theme is selected --- src/librustdoc/html/static/storage.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index 7e9cfbd676347..c8571e4cf9181 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -44,8 +44,12 @@ function switchTheme(styleElem, mainStyleElem, newTheme) { var fullBasicCss = "rustdoc" + resourcesSuffix + ".css"; var fullNewTheme = newTheme + resourcesSuffix + ".css"; var newHref = mainStyleElem.href.replace(fullBasicCss, fullNewTheme); - var found = false; + if (styleElem.href === newHref) { + return; + } + + var found = false; if (savedHref.length === 0) { onEach(document.getElementsByTagName("link"), function(el) { savedHref.push(el.href); From c80220436bf68dac572ee2c3d701d40f02e2eb88 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Mon, 12 Mar 2018 16:15:38 -0500 Subject: [PATCH 10/19] big fences to show that ```rust is the same as ``` --- src/doc/rustdoc/src/documentation-tests.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md index e5a603a3709f6..cc7b15812ec34 100644 --- a/src/doc/rustdoc/src/documentation-tests.md +++ b/src/doc/rustdoc/src/documentation-tests.md @@ -19,15 +19,19 @@ running `rustdoc --test foo.rs` will extract this example, and then run it as a Please note that by default, if no language is set for the block code, `rustdoc` assumes it is `Rust` code. So the following: +``````markdown ```rust let x = 5; ``` +`````` is strictly equivalent to: +``````markdown ``` let x = 5; ``` +`````` There's some subtlety though! Read on for more details. From da257b8fecacdb577592032dcaa9e4b5900cab2c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Mar 2018 22:42:23 +0100 Subject: [PATCH 11/19] Add missing examples --- src/libcore/fmt/mod.rs | 136 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 2 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 8ad5a9861a02f..02a1b9e6a9689 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1375,27 +1375,159 @@ impl<'a> Formatter<'a> { } } - /// Optionally specified integer width that the output should be + /// Optionally specified integer width that the output should be. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(i32); + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// if let Some(width) = formatter.width() { + /// // If we received a width, we use it + /// write!(formatter, "{:width$}", &format!("Foo({})", self.0), width = width) + /// } else { + /// // Otherwise we do nothing special + /// write!(formatter, "Foo({})", self.0) + /// } + /// } + /// } + /// + /// assert_eq!(&format!("{:10}", Foo(23)), "Foo(23) "); + /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option { self.width } - /// Optionally specified precision for numeric types + /// Optionally specified precision for numeric types. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(f32); + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// if let Some(precision) = formatter.precision() { + /// // If we received a precision, we use it. + /// write!(formatter, "Foo({1:.*})", precision, self.0) + /// } else { + /// // Otherwise we default to 2. + /// write!(formatter, "Foo({:.2})", self.0) + /// } + /// } + /// } + /// + /// assert_eq!(&format!("{:.4}", Foo(23.2)), "Foo(23.2000)"); + /// assert_eq!(&format!("{}", Foo(23.2)), "Foo(23.20)"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option { self.precision } /// Determines if the `+` flag was specified. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(i32); + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// if formatter.sign_plus() { + /// write!(formatter, + /// "Foo({}{})", + /// if self.0 < 0 { '-' } else { '+' }, + /// self.0) + /// } else { + /// write!(formatter, "Foo({})", self.0) + /// } + /// } + /// } + /// + /// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)"); + /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_plus(&self) -> bool { self.flags & (1 << FlagV1::SignPlus as u32) != 0 } /// Determines if the `-` flag was specified. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(i32); + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// if formatter.sign_minus() { + /// // You want a minus sign? Have one! + /// write!(formatter, "-Foo({})", self.0) + /// } else { + /// write!(formatter, "Foo({})", self.0) + /// } + /// } + /// } + /// + /// assert_eq!(&format!("{:-}", Foo(23)), "-Foo(23)"); + /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_minus(&self) -> bool { self.flags & (1 << FlagV1::SignMinus as u32) != 0 } /// Determines if the `#` flag was specified. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(i32); + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// if formatter.alternate() { + /// write!(formatter, "Foo({})", self.0) + /// } else { + /// write!(formatter, "{}", self.0) + /// } + /// } + /// } + /// + /// assert_eq!(&format!("{:#}", Foo(23)), "Foo(23)"); + /// assert_eq!(&format!("{}", Foo(23)), "23"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn alternate(&self) -> bool { self.flags & (1 << FlagV1::Alternate as u32) != 0 } /// Determines if the `0` flag was specified. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(i32); + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// assert!(formatter.sign_aware_zero_pad()); + /// assert_eq!(formatter.width(), Some(4)); + /// // We ignore the formatter's options. + /// write!(formatter, "{}", self.0) + /// } + /// } + /// + /// assert_eq!(&format!("{:04}", Foo(23)), "23"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_aware_zero_pad(&self) -> bool { self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0 From 5a073d496d0a401980233d8ec3e8569abfc2269f Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Mon, 12 Mar 2018 20:05:18 -0500 Subject: [PATCH 12/19] Move librustc_typeck READMEs to rustc guide --- src/librustc_typeck/README.md | 51 +--- src/librustc_typeck/check/method/README.md | 111 --------- src/librustc_typeck/check/method/mod.rs | 4 +- src/librustc_typeck/variance/README.md | 276 --------------------- src/librustc_typeck/variance/mod.rs | 6 +- src/librustc_typeck/variance/terms.rs | 5 +- 6 files changed, 15 insertions(+), 438 deletions(-) delete mode 100644 src/librustc_typeck/check/method/README.md delete mode 100644 src/librustc_typeck/variance/README.md diff --git a/src/librustc_typeck/README.md b/src/librustc_typeck/README.md index 1abc914e7d661..f00597cb27f0c 100644 --- a/src/librustc_typeck/README.md +++ b/src/librustc_typeck/README.md @@ -1,48 +1,5 @@ -NB: This crate is part of the Rust compiler. For an overview of the -compiler as a whole, see -[the README.md file found in `librustc`](../librustc/README.md). +For high-level intro to how type checking works in rustc, see the +[type checking] chapter of the [rustc guide]. -The `rustc_typeck` crate contains the source for "type collection" and -"type checking", as well as a few other bits of related functionality. -(It draws heavily on the [type inferencing][infer] and -[trait solving][traits] code found in librustc.) - -[infer]: ../librustc/infer/README.md -[traits]: ../librustc/traits/README.md - -## Type collection - -Type "collection" is the process of converting the types found in the -HIR (`hir::Ty`), which represent the syntactic things that the user -wrote, into the **internal representation** used by the compiler -(`Ty<'tcx>`) -- we also do similar conversions for where-clauses and -other bits of the function signature. - -To try and get a sense for the difference, consider this function: - -```rust -struct Foo { } -fn foo(x: Foo, y: self::Foo) { .. } -// ^^^ ^^^^^^^^^ -``` - -Those two parameters `x` and `y` each have the same type: but they -will have distinct `hir::Ty` nodes. Those nodes will have different -spans, and of course they encode the path somewhat differently. But -once they are "collected" into `Ty<'tcx>` nodes, they will be -represented by the exact same internal type. - -Collection is defined as a bundle of queries (e.g., `type_of`) for -computing information about the various functions, traits, and other -items in the crate being compiled. Note that each of these queries is -concerned with *interprocedural* things -- for example, for a function -definition, collection will figure out the type and signature of the -function, but it will not visit the *body* of the function in any way, -nor examine type annotations on local variables (that's the job of -type *checking*). - -For more details, see the `collect` module. - -## Type checking - -TODO +[type checking]: https://rust-lang-nursery.github.io/rustc-guide/type-checking.html +[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/ diff --git a/src/librustc_typeck/check/method/README.md b/src/librustc_typeck/check/method/README.md deleted file mode 100644 index b5d317d602538..0000000000000 --- a/src/librustc_typeck/check/method/README.md +++ /dev/null @@ -1,111 +0,0 @@ -# Method lookup - -Method lookup can be rather complex due to the interaction of a number -of factors, such as self types, autoderef, trait lookup, etc. This -file provides an overview of the process. More detailed notes are in -the code itself, naturally. - -One way to think of method lookup is that we convert an expression of -the form: - - receiver.method(...) - -into a more explicit UFCS form: - - Trait::method(ADJ(receiver), ...) // for a trait call - ReceiverType::method(ADJ(receiver), ...) // for an inherent method call - -Here `ADJ` is some kind of adjustment, which is typically a series of -autoderefs and then possibly an autoref (e.g., `&**receiver`). However -we sometimes do other adjustments and coercions along the way, in -particular unsizing (e.g., converting from `[T; n]` to `[T]`). - -## The Two Phases - -Method lookup is divided into two major phases: probing (`probe.rs`) -and confirmation (`confirm.rs`). The probe phase is when we decide -what method to call and how to adjust the receiver. The confirmation -phase "applies" this selection, updating the side-tables, unifying -type variables, and otherwise doing side-effectful things. - -One reason for this division is to be more amenable to caching. The -probe phase produces a "pick" (`probe::Pick`), which is designed to be -cacheable across method-call sites. Therefore, it does not include -inference variables or other information. - -## Probe phase - -The probe phase (`probe.rs`) decides what method is being called and -how to adjust the receiver. - -### Steps - -The first thing that the probe phase does is to create a series of -*steps*. This is done by progressively dereferencing the receiver type -until it cannot be deref'd anymore, as well as applying an optional -"unsize" step. So if the receiver has type `Rc>`, this -might yield: - - Rc> - Box<[T; 3]> - [T; 3] - [T] - -### Candidate assembly - -We then search along those steps to create a list of *candidates*. A -`Candidate` is a method item that might plausibly be the method being -invoked. For each candidate, we'll derive a "transformed self type" -that takes into account explicit self. - -Candidates are grouped into two kinds, inherent and extension. - -**Inherent candidates** are those that are derived from the -type of the receiver itself. So, if you have a receiver of some -nominal type `Foo` (e.g., a struct), any methods defined within an -impl like `impl Foo` are inherent methods. Nothing needs to be -imported to use an inherent method, they are associated with the type -itself (note that inherent impls can only be defined in the same -module as the type itself). - -FIXME: Inherent candidates are not always derived from impls. If you -have a trait object, such as a value of type `Box`, then the -trait methods (`to_string()`, in this case) are inherently associated -with it. Another case is type parameters, in which case the methods of -their bounds are inherent. However, this part of the rules is subject -to change: when DST's "impl Trait for Trait" is complete, trait object -dispatch could be subsumed into trait matching, and the type parameter -behavior should be reconsidered in light of where clauses. - -**Extension candidates** are derived from imported traits. If I have -the trait `ToString` imported, and I call `to_string()` on a value of -type `T`, then we will go off to find out whether there is an impl of -`ToString` for `T`. These kinds of method calls are called "extension -methods". They can be defined in any module, not only the one that -defined `T`. Furthermore, you must import the trait to call such a -method. - -So, let's continue our example. Imagine that we were calling a method -`foo` with the receiver `Rc>` and there is a trait `Foo` -that defines it with `&self` for the type `Rc` as well as a method -on the type `Box` that defines `Foo` but with `&mut self`. Then we -might have two candidates: - - &Rc> from the impl of `Foo` for `Rc` where `U=Box - &mut Box<[T; 3]>> from the inherent impl on `Box` where `U=[T; 3]` - -### Candidate search - -Finally, to actually pick the method, we will search down the steps, -trying to match the receiver type against the candidate types. At -each step, we also consider an auto-ref and auto-mut-ref to see whether -that makes any of the candidates match. We pick the first step where -we find a match. - -In the case of our example, the first step is `Rc>`, -which does not itself match any candidate. But when we autoref it, we -get the type `&Rc>` which does match. We would then -recursively consider all where-clauses that appear on the impl: if -those match (or we cannot rule out that they do), then this is the -method we would pick. Otherwise, we would continue down the series of -steps. diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index f7bb1a6a23239..1664f46464d15 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Method lookup: the secret sauce of Rust. See `README.md`. +//! Method lookup: the secret sauce of Rust. See the [rustc guide] chapter. +//! +//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/method-lookup.html use check::FnCtxt; use hir::def::Def; diff --git a/src/librustc_typeck/variance/README.md b/src/librustc_typeck/variance/README.md deleted file mode 100644 index 64d3389b34af7..0000000000000 --- a/src/librustc_typeck/variance/README.md +++ /dev/null @@ -1,276 +0,0 @@ -## Variance of type and lifetime parameters - -This file infers the variance of type and lifetime parameters. The -algorithm is taken from Section 4 of the paper "Taming the Wildcards: -Combining Definition- and Use-Site Variance" published in PLDI'11 and -written by Altidor et al., and hereafter referred to as The Paper. - -This inference is explicitly designed *not* to consider the uses of -types within code. To determine the variance of type parameters -defined on type `X`, we only consider the definition of the type `X` -and the definitions of any types it references. - -We only infer variance for type parameters found on *data types* -like structs and enums. In these cases, there is fairly straightforward -explanation for what variance means. The variance of the type -or lifetime parameters defines whether `T` is a subtype of `T` -(resp. `T<'a>` and `T<'b>`) based on the relationship of `A` and `B` -(resp. `'a` and `'b`). - -We do not infer variance for type parameters found on traits, fns, -or impls. Variance on trait parameters can make indeed make sense -(and we used to compute it) but it is actually rather subtle in -meaning and not that useful in practice, so we removed it. See the -addendum for some details. Variances on fn/impl parameters, otoh, -doesn't make sense because these parameters are instantiated and -then forgotten, they don't persist in types or compiled -byproducts. - -### The algorithm - -The basic idea is quite straightforward. We iterate over the types -defined and, for each use of a type parameter X, accumulate a -constraint indicating that the variance of X must be valid for the -variance of that use site. We then iteratively refine the variance of -X until all constraints are met. There is *always* a sol'n, because at -the limit we can declare all type parameters to be invariant and all -constraints will be satisfied. - -As a simple example, consider: - - enum Option { Some(A), None } - enum OptionalFn { Some(|B|), None } - enum OptionalMap { Some(|C| -> C), None } - -Here, we will generate the constraints: - - 1. V(A) <= + - 2. V(B) <= - - 3. V(C) <= + - 4. V(C) <= - - -These indicate that (1) the variance of A must be at most covariant; -(2) the variance of B must be at most contravariant; and (3, 4) the -variance of C must be at most covariant *and* contravariant. All of these -results are based on a variance lattice defined as follows: - - * Top (bivariant) - - + - o Bottom (invariant) - -Based on this lattice, the solution `V(A)=+`, `V(B)=-`, `V(C)=o` is the -optimal solution. Note that there is always a naive solution which -just declares all variables to be invariant. - -You may be wondering why fixed-point iteration is required. The reason -is that the variance of a use site may itself be a function of the -variance of other type parameters. In full generality, our constraints -take the form: - - V(X) <= Term - Term := + | - | * | o | V(X) | Term x Term - -Here the notation `V(X)` indicates the variance of a type/region -parameter `X` with respect to its defining class. `Term x Term` -represents the "variance transform" as defined in the paper: - -> If the variance of a type variable `X` in type expression `E` is `V2` - and the definition-site variance of the [corresponding] type parameter - of a class `C` is `V1`, then the variance of `X` in the type expression - `C` is `V3 = V1.xform(V2)`. - -### Constraints - -If I have a struct or enum with where clauses: - - struct Foo { ... } - -you might wonder whether the variance of `T` with respect to `Bar` -affects the variance `T` with respect to `Foo`. I claim no. The -reason: assume that `T` is invariant w/r/t `Bar` but covariant w/r/t -`Foo`. And then we have a `Foo` that is upcast to `Foo`, where -`X <: Y`. However, while `X : Bar`, `Y : Bar` does not hold. In that -case, the upcast will be illegal, but not because of a variance -failure, but rather because the target type `Foo` is itself just -not well-formed. Basically we get to assume well-formedness of all -types involved before considering variance. - -#### Dependency graph management - -Because variance is a whole-crate inference, its dependency graph -can become quite muddled if we are not careful. To resolve this, we refactor -into two queries: - -- `crate_variances` computes the variance for all items in the current crate. -- `variances_of` accesses the variance for an individual reading; it - works by requesting `crate_variances` and extracting the relevant data. - -If you limit yourself to reading `variances_of`, your code will only -depend then on the inference inferred for that particular item. - -Ultimately, this setup relies on the red-green algorithm. -In particular, every variance query ultimately depends on -- effectively -- -all type definitions in the entire crate (through `crate_variances`), -but since most changes will not result in a change -to the actual results from variance inference, -the `variances_of` query will wind up being considered green after it is re-evaluated. - -### Addendum: Variance on traits - -As mentioned above, we used to permit variance on traits. This was -computed based on the appearance of trait type parameters in -method signatures and was used to represent the compatibility of -vtables in trait objects (and also "virtual" vtables or dictionary -in trait bounds). One complication was that variance for -associated types is less obvious, since they can be projected out -and put to myriad uses, so it's not clear when it is safe to allow -`X::Bar` to vary (or indeed just what that means). Moreover (as -covered below) all inputs on any trait with an associated type had -to be invariant, limiting the applicability. Finally, the -annotations (`MarkerTrait`, `PhantomFn`) needed to ensure that all -trait type parameters had a variance were confusing and annoying -for little benefit. - -Just for historical reference,I am going to preserve some text indicating -how one could interpret variance and trait matching. - -#### Variance and object types - -Just as with structs and enums, we can decide the subtyping -relationship between two object types `&Trait` and `&Trait` -based on the relationship of `A` and `B`. Note that for object -types we ignore the `Self` type parameter -- it is unknown, and -the nature of dynamic dispatch ensures that we will always call a -function that is expected the appropriate `Self` type. However, we -must be careful with the other type parameters, or else we could -end up calling a function that is expecting one type but provided -another. - -To see what I mean, consider a trait like so: - - trait ConvertTo { - fn convertTo(&self) -> A; - } - -Intuitively, If we had one object `O=&ConvertTo` and another -`S=&ConvertTo`, then `S <: O` because `String <: Object` -(presuming Java-like "string" and "object" types, my go to examples -for subtyping). The actual algorithm would be to compare the -(explicit) type parameters pairwise respecting their variance: here, -the type parameter A is covariant (it appears only in a return -position), and hence we require that `String <: Object`. - -You'll note though that we did not consider the binding for the -(implicit) `Self` type parameter: in fact, it is unknown, so that's -good. The reason we can ignore that parameter is precisely because we -don't need to know its value until a call occurs, and at that time (as -you said) the dynamic nature of virtual dispatch means the code we run -will be correct for whatever value `Self` happens to be bound to for -the particular object whose method we called. `Self` is thus different -from `A`, because the caller requires that `A` be known in order to -know the return type of the method `convertTo()`. (As an aside, we -have rules preventing methods where `Self` appears outside of the -receiver position from being called via an object.) - -#### Trait variance and vtable resolution - -But traits aren't only used with objects. They're also used when -deciding whether a given impl satisfies a given trait bound. To set the -scene here, imagine I had a function: - - fn convertAll>(v: &[T]) { - ... - } - -Now imagine that I have an implementation of `ConvertTo` for `Object`: - - impl ConvertTo for Object { ... } - -And I want to call `convertAll` on an array of strings. Suppose -further that for whatever reason I specifically supply the value of -`String` for the type parameter `T`: - - let mut vector = vec!["string", ...]; - convertAll::(vector); - -Is this legal? To put another way, can we apply the `impl` for -`Object` to the type `String`? The answer is yes, but to see why -we have to expand out what will happen: - -- `convertAll` will create a pointer to one of the entries in the - vector, which will have type `&String` -- It will then call the impl of `convertTo()` that is intended - for use with objects. This has the type: - - fn(self: &Object) -> i32 - - It is ok to provide a value for `self` of type `&String` because - `&String <: &Object`. - -OK, so intuitively we want this to be legal, so let's bring this back -to variance and see whether we are computing the correct result. We -must first figure out how to phrase the question "is an impl for -`Object,i32` usable where an impl for `String,i32` is expected?" - -Maybe it's helpful to think of a dictionary-passing implementation of -type classes. In that case, `convertAll()` takes an implicit parameter -representing the impl. In short, we *have* an impl of type: - - V_O = ConvertTo for Object - -and the function prototype expects an impl of type: - - V_S = ConvertTo for String - -As with any argument, this is legal if the type of the value given -(`V_O`) is a subtype of the type expected (`V_S`). So is `V_O <: V_S`? -The answer will depend on the variance of the various parameters. In -this case, because the `Self` parameter is contravariant and `A` is -covariant, it means that: - - V_O <: V_S iff - i32 <: i32 - String <: Object - -These conditions are satisfied and so we are happy. - -#### Variance and associated types - -Traits with associated types -- or at minimum projection -expressions -- must be invariant with respect to all of their -inputs. To see why this makes sense, consider what subtyping for a -trait reference means: - - <: - -means that if I know that `T as Trait`, I also know that `U as -Trait`. Moreover, if you think of it as dictionary passing style, -it means that a dictionary for `` is safe to use where -a dictionary for `` is expected. - -The problem is that when you can project types out from ``, the relationship to types projected out of `` -is completely unknown unless `T==U` (see #21726 for more -details). Making `Trait` invariant ensures that this is true. - -Another related reason is that if we didn't make traits with -associated types invariant, then projection is no longer a -function with a single result. Consider: - -``` -trait Identity { type Out; fn foo(&self); } -impl Identity for T { type Out = T; ... } -``` - -Now if I have `<&'static () as Identity>::Out`, this can be -validly derived as `&'a ()` for any `'a`: - - <&'a () as Identity> <: <&'static () as Identity> - if &'static () < : &'a () -- Identity is contravariant in Self - if 'static : 'a -- Subtyping rules for relations - -This change otoh means that `<'static () as Identity>::Out` is -always `&'static ()` (which might then be upcast to `'a ()`, -separately). This was helpful in solving #21750. - - diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index da243650c839a..fd2b964103a30 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Module for inferring the variance of type and lifetime -//! parameters. See README.md for details. +//! Module for inferring the variance of type and lifetime parameters. See the [rustc guide] +//! chapter for more info. +//! +//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/variance.html use arena; use rustc::hir; diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index ac3d575b64882..b9ab00130b3c3 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -87,7 +87,10 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx> lang_items: lang_items(tcx), }; - // See README.md for a discussion on dep-graph management. + // See the following for a discussion on dep-graph management. + // + // - https://rust-lang-nursery.github.io/rustc-guide/query.html + // - https://rust-lang-nursery.github.io/rustc-guide/variance.html tcx.hir.krate().visit_all_item_likes(&mut terms_cx); terms_cx From c1337cda4ccf349b8a5a80156e32c2499520b621 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Mon, 12 Mar 2018 21:26:51 -0400 Subject: [PATCH 13/19] Update -Wall message based on feedback The reference to -Wunused was removed, and some phrasing was changed. --- src/librustc_driver/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 47168cb955a0e..4b3315cf8d7ac 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1138,10 +1138,9 @@ fn usage(verbose: bool, include_unstable_options: bool) { fn print_wall_help() { println!(" -The flag -Wall does not exist in rustc. Most useful lints are enabled by default. -Use `rustc -W help` to see all available lints. The most used lints that are not -enabled by default covered by -Wunused; however, the best practice is to put -warning settings in the crate root using `#![warn(unused)]` instead of using +The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by +default. Use `rustc -W help` to see all available lints. It's more common to put +warning settings in the crate root using `#![warn(LINT_NAME)]` instead of using the command line flag directly. "); } From 04442af18bf01622288a33faa58caf7e666cac40 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 13 Mar 2018 07:54:03 -0700 Subject: [PATCH 14/19] rustc: Don't invoke `lld` with an `@`-file Looks like LLD doesn't support this yet, so always try to use the OS before we fall back to using `@` --- src/librustc_trans/back/command.rs | 7 +++++++ src/librustc_trans/back/link.rs | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/back/command.rs b/src/librustc_trans/back/command.rs index ecf7bf5036e08..a5649e98baa76 100644 --- a/src/librustc_trans/back/command.rs +++ b/src/librustc_trans/back/command.rs @@ -132,6 +132,13 @@ impl Command { return false } + // Right now LLD doesn't support the `@` syntax of passing an argument + // through files, so regardless of the platform we try to go to the OS + // on this one. + if let Program::Lld(..) = self.program { + return false + } + // Ok so on Windows to spawn a process is 32,768 characters in its // command line [1]. Unfortunately we don't actually have access to that // as it's calculated just before spawning. Instead we perform a diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 867498d0c59e1..bdda7741221f5 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -827,11 +827,14 @@ fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path) if !cmd.very_likely_to_exceed_some_spawn_limit() { match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() { Ok(child) => return child.wait_with_output(), - Err(ref e) if command_line_too_big(e) => {} + Err(ref e) if command_line_too_big(e) => { + info!("command line to linker was too big: {}", e); + } Err(e) => return Err(e) } } + info!("falling back to passing arguments to linker via an @-file"); let mut cmd2 = cmd.clone(); let mut args = String::new(); for arg in cmd2.take_args() { @@ -856,6 +859,7 @@ fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path) }; fs::write(&file, &bytes)?; cmd2.arg(format!("@{}", file.display())); + info!("invoking linker {:?}", cmd2); return cmd2.output(); #[cfg(unix)] From 21a9770d38483eb95d5045b50547058bc7ff7e65 Mon Sep 17 00:00:00 2001 From: bobtwinkles Date: Tue, 13 Mar 2018 14:21:51 -0400 Subject: [PATCH 15/19] Adds a test for #48070 Resolves #48070. The bug itself was fixed by #48770, but that PR didn't add a test for it. --- src/test/run-pass/issue-48070.rs | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/test/run-pass/issue-48070.rs diff --git a/src/test/run-pass/issue-48070.rs b/src/test/run-pass/issue-48070.rs new file mode 100644 index 0000000000000..c2253aa8b4c25 --- /dev/null +++ b/src/test/run-pass/issue-48070.rs @@ -0,0 +1,34 @@ +// 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. + +// revisions: lxl nll + +#![cfg_attr(nll, feature(nll))] + +struct Foo { + x: u32 +} + +impl Foo { + fn twiddle(&mut self) -> &mut Self { self } + fn twaddle(&mut self) -> &mut Self { self } + fn emit(&mut self) { + self.x += 1; + } +} + +fn main() { + let mut foo = Foo { x: 0 }; + match 22 { + 22 => &mut foo, + 44 => foo.twiddle(), + _ => foo.twaddle(), + }.emit(); +} From 52bb99dcc7c918cc9568a3bd26801da07c1ce103 Mon Sep 17 00:00:00 2001 From: bobtwinkles Date: Tue, 13 Mar 2018 14:52:11 -0400 Subject: [PATCH 16/19] Move 48070 test to ui --- src/test/{run-pass => ui/nll}/issue-48070.rs | 1 + 1 file changed, 1 insertion(+) rename src/test/{run-pass => ui/nll}/issue-48070.rs (98%) diff --git a/src/test/run-pass/issue-48070.rs b/src/test/ui/nll/issue-48070.rs similarity index 98% rename from src/test/run-pass/issue-48070.rs rename to src/test/ui/nll/issue-48070.rs index c2253aa8b4c25..71d92c3702e63 100644 --- a/src/test/run-pass/issue-48070.rs +++ b/src/test/ui/nll/issue-48070.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// run-pass // revisions: lxl nll #![cfg_attr(nll, feature(nll))] From 6d534d5880f27c9b1e5a12148572823202e70b4d Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 13 Mar 2018 13:26:07 -0700 Subject: [PATCH 17/19] Clarify usage message for --remap-path-prefix. --- src/librustc/session/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 1c5cfa87ef46f..7058d84f339dd 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1641,7 +1641,7 @@ pub fn rustc_optgroups() -> Vec { opt::multi_s( "", "remap-path-prefix", - "remap source names in output", + "Remap source names in all output (compiler messages and output files)", "FROM=TO", ), ]); From 63f654a495ed868bcd5fb0ee03e1ff581e08e9ee Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Tue, 13 Mar 2018 21:03:22 +0000 Subject: [PATCH 18/19] fix #48816 don't print help on indirect compiler ICE --- src/librustc_driver/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 746f2db4767f9..d39dc8668c0e7 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1457,6 +1457,12 @@ fn extra_compiler_flags() -> Option<(Vec, bool)> { args.push(arg.to_string_lossy().to_string()); } + // Avoid printing help because of empty args. This can suggest the compiler + // itself is not the program root (consider RLS). + if args.len() < 2 { + return None; + } + let matches = if let Some(matches) = handle_options(&args) { matches } else { From 2f2e17341c171c847c201516bec9bf2234704000 Mon Sep 17 00:00:00 2001 From: Peter Hrvola Date: Fri, 23 Feb 2018 20:18:38 +0100 Subject: [PATCH 19/19] Speed up SVH computation by using Fingerprint::combine() Fix #47297 r? @michaelwoerister --- src/librustc/hir/map/collector.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 99b1e5783e01e..e6f95fb99ea7e 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -13,6 +13,7 @@ use dep_graph::{DepGraph, DepKind, DepNodeIndex}; use hir::def_id::{LOCAL_CRATE, CrateNum}; use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::svh::Svh; +use ich::Fingerprint; use middle::cstore::CrateStore; use session::CrateDisambiguator; use std::iter::repeat; @@ -121,21 +122,24 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { collector } - pub(super) fn finalize_and_compute_crate_hash(self, + pub(super) fn finalize_and_compute_crate_hash(mut self, crate_disambiguator: CrateDisambiguator, cstore: &CrateStore, codemap: &CodeMap, commandline_args_hash: u64) -> (Vec>, Svh) { - let mut node_hashes: Vec<_> = self + self .hir_body_nodes - .iter() - .map(|&(def_path_hash, dep_node_index)| { - (def_path_hash, self.dep_graph.fingerprint_of(dep_node_index)) - }) - .collect(); + .sort_unstable_by(|&(ref d1, _), &(ref d2, _)| d1.cmp(d2)); - node_hashes.sort_unstable_by(|&(ref d1, _), &(ref d2, _)| d1.cmp(d2)); + let node_hashes = self + .hir_body_nodes + .iter() + .fold(Fingerprint::ZERO, |fingerprint , &(def_path_hash, dep_node_index)| { + fingerprint.combine( + def_path_hash.0.combine(self.dep_graph.fingerprint_of(dep_node_index)) + ) + }); let mut upstream_crates: Vec<_> = cstore.crates_untracked().iter().map(|&cnum| { let name = cstore.crate_name_untracked(cnum).as_str();