From 166719ad9fe3137ef4fe18cbf9fed1c050f8855a Mon Sep 17 00:00:00 2001 From: Andreas Jonson Date: Sat, 31 Aug 2019 08:50:02 +0200 Subject: [PATCH 01/19] Update installed compiler dependencies there is a soft-error for older toolchains from https://reviews.llvm.org/D57264 in preparation for the hard error in https://reviews.llvm.org/D66188 --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 724bc36ecc6fb..2df9e6a37379d 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ or reading the [rustc guide][rustcguidebuild]. ### Building on *nix 1. Make sure you have installed the dependencies: - * `g++` 4.7 or later or `clang++` 3.x or later + * `g++` 5.1 or later or `clang++` 3.5 or later * `python` 2.7 (but not 3.x) * GNU `make` 3.81 or later * `cmake` 3.4.3 or later @@ -148,6 +148,17 @@ by manually calling the appropriate vcvars file before running the bootstrap. > python x.py build ``` +### Building rustc with older host toolchains +It is still possible to build Rust with the older toolchain versions listed below, but only if the +LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN option is set to true in the config.toml file. + +* Clang 3.1 +* Apple Clang 3.1 +* GCC 4.8 +* Visual Studio 2015 (Update 3) + +Toolchain versions older than what is listed above cannot be used to build rustc. + #### Specifying an ABI Each specific ABI can also be used from either environment (for example, using From 9f4351d406fe904a99a7588ebb1411e369ba71f7 Mon Sep 17 00:00:00 2001 From: lqd Date: Tue, 17 Sep 2019 19:28:49 +0200 Subject: [PATCH 02/19] Bless output of test borrowck/return-local-binding-from-desugaring.rs for Polonius --- ...rrowck-escaping-closure-error.polonius.stderr | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/test/ui/async-await/async-borrowck-escaping-closure-error.polonius.stderr diff --git a/src/test/ui/async-await/async-borrowck-escaping-closure-error.polonius.stderr b/src/test/ui/async-await/async-borrowck-escaping-closure-error.polonius.stderr new file mode 100644 index 0000000000000..5f20367b6aba9 --- /dev/null +++ b/src/test/ui/async-await/async-borrowck-escaping-closure-error.polonius.stderr @@ -0,0 +1,16 @@ +error[E0597]: `x` does not live long enough + --> $DIR/async-borrowck-escaping-closure-error.rs:5:24 + | +LL | Box::new((async || x)()) + | -------------------^---- + | | | | + | | | borrowed value does not live long enough + | | value captured here + | borrow later used here +LL | +LL | } + | - `x` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From 222e9201511bb9a6eaca7fc2c0ee0b85d78c4fd7 Mon Sep 17 00:00:00 2001 From: lqd Date: Tue, 17 Sep 2019 19:30:34 +0200 Subject: [PATCH 03/19] Bless output of test borrowck/return-local-binding-from-desugaring.rs for Polonius --- ...local-binding-from-desugaring.polonius.stderr | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/test/ui/borrowck/return-local-binding-from-desugaring.polonius.stderr diff --git a/src/test/ui/borrowck/return-local-binding-from-desugaring.polonius.stderr b/src/test/ui/borrowck/return-local-binding-from-desugaring.polonius.stderr new file mode 100644 index 0000000000000..c818379762c9d --- /dev/null +++ b/src/test/ui/borrowck/return-local-binding-from-desugaring.polonius.stderr @@ -0,0 +1,16 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/return-local-binding-from-desugaring.rs:26:18 + | +LL | for ref x in xs { + | ^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement +LL | result + | ------ borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. From 3ef980aeaae3ae92c1ed3bdbefe35c6175ed24fb Mon Sep 17 00:00:00 2001 From: lqd Date: Tue, 17 Sep 2019 19:32:36 +0200 Subject: [PATCH 04/19] Update expectations of test ui/dropck/dropck_trait_cycle_checked.rs for Polonius as its output was changed by https://github.com/rust-lang/rust/commit/2ff337a8e286a5b472f71b3bbdc3d4b6b840870f#diff-bd3f80b956148a5d1567aa8698b8a507 --- .../dropck_trait_cycle_checked.polonius.stderr | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/test/ui/dropck/dropck_trait_cycle_checked.polonius.stderr b/src/test/ui/dropck/dropck_trait_cycle_checked.polonius.stderr index dbcb0fcebb73d..5e93a0234259c 100644 --- a/src/test/ui/dropck/dropck_trait_cycle_checked.polonius.stderr +++ b/src/test/ui/dropck/dropck_trait_cycle_checked.polonius.stderr @@ -8,7 +8,9 @@ LL | } | - | | | `o2` dropped here while still borrowed - | borrow might be used here, when `o2` is dropped and runs the destructor for type `std::boxed::Box>` + | borrow might be used here, when `o1` is dropped and runs the destructor for type `std::boxed::Box>` + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:112:13 @@ -20,7 +22,9 @@ LL | } | - | | | `o3` dropped here while still borrowed - | borrow might be used here, when `o3` is dropped and runs the destructor for type `std::boxed::Box>` + | borrow might be used here, when `o1` is dropped and runs the destructor for type `std::boxed::Box>` + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:113:13 @@ -38,7 +42,7 @@ error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:114:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o3` is borrowed for `'static` + | -------- cast requires that `o3` is borrowed for `'static` ... LL | o2.set1(&o3); | ^^^ borrowed value does not live long enough @@ -62,7 +66,7 @@ error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:116:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` + | -------- cast requires that `o2` is borrowed for `'static` ... LL | o3.set1(&o2); | ^^^ borrowed value does not live long enough From 34d31673684a34b3858ba8dbc05fff8804a50508 Mon Sep 17 00:00:00 2001 From: lqd Date: Tue, 17 Sep 2019 19:34:12 +0200 Subject: [PATCH 05/19] Bless json output of test ui/json-multiple.rs for Polonius --- src/test/ui/json-multiple.polonius.stderr | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/test/ui/json-multiple.polonius.stderr diff --git a/src/test/ui/json-multiple.polonius.stderr b/src/test/ui/json-multiple.polonius.stderr new file mode 100644 index 0000000000000..0e4d442f299c3 --- /dev/null +++ b/src/test/ui/json-multiple.polonius.stderr @@ -0,0 +1 @@ +{"artifact":"$TEST_BUILD_DIR/json-multiple.polonius/libjson_multiple.rlib","emit":"link"} From f9c73293e231f1179c426311bd7ab11f46473e9a Mon Sep 17 00:00:00 2001 From: lqd Date: Tue, 17 Sep 2019 19:35:16 +0200 Subject: [PATCH 06/19] Bless json output of test ui/json-options.rs for Polonius --- src/test/ui/json-options.polonius.stderr | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/test/ui/json-options.polonius.stderr diff --git a/src/test/ui/json-options.polonius.stderr b/src/test/ui/json-options.polonius.stderr new file mode 100644 index 0000000000000..e21f6f85d162d --- /dev/null +++ b/src/test/ui/json-options.polonius.stderr @@ -0,0 +1 @@ +{"artifact":"$TEST_BUILD_DIR/json-options.polonius/libjson_options.rlib","emit":"link"} From ceb72e4ad144f4887f67e539bcd143b4d303dade Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 17 Sep 2019 16:25:29 -0700 Subject: [PATCH 07/19] Add generic dataflow impl --- src/librustc_mir/dataflow/generic.rs | 444 +++++++++++++++++++++++++++ src/librustc_mir/dataflow/mod.rs | 1 + src/librustc_mir/lib.rs | 1 + 3 files changed, 446 insertions(+) create mode 100644 src/librustc_mir/dataflow/generic.rs diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs new file mode 100644 index 0000000000000..7819fd11845e6 --- /dev/null +++ b/src/librustc_mir/dataflow/generic.rs @@ -0,0 +1,444 @@ +use std::cmp::Ordering; +use std::ops; + +use rustc::mir::{self, traversal, BasicBlock, Location}; +use rustc_data_structures::bit_set::BitSet; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::work_queue::WorkQueue; + +use crate::dataflow::BottomValue; + +pub trait Analysis<'tcx>: BottomValue { + type Idx: Idx; + + fn name() -> &'static str; + + fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize; + + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet); + + fn apply_statement_effect( + &self, + state: &mut BitSet, + statement: &mir::Statement<'tcx>, + location: Location, + ); + + fn apply_terminator_effect( + &self, + state: &mut BitSet, + terminator: &mir::Terminator<'tcx>, + location: Location, + ); + + fn apply_call_return_effect( + &self, + state: &mut BitSet, + block: BasicBlock, + func: &mir::Operand<'tcx>, + args: &[mir::Operand<'tcx>], + return_place: &mir::Place<'tcx>, + ); + + /// Applies the cumulative effect of an entire basic block to the dataflow state (except for + /// `call_return_effect`, which is handled in the `Engine`). + /// + /// The default implementation calls `statement_effect` for every statement in the block before + /// finally calling `terminator_effect`. However, some dataflow analyses are able to coalesce + /// transfer functions for an entire block and apply them at once. Such analyses should + /// override `block_effect`. + fn apply_whole_block_effect( + &self, + state: &mut BitSet, + block: BasicBlock, + block_data: &mir::BasicBlockData<'tcx>, + ) { + for (statement_index, stmt) in block_data.statements.iter().enumerate() { + let location = Location { block, statement_index }; + self.apply_statement_effect(state, stmt, location); + } + + let location = Location { block, statement_index: block_data.statements.len() }; + self.apply_terminator_effect(state, block_data.terminator(), location); + } + + /// Applies the cumulative effect of a sequence of statements (and possibly a terminator) + /// within a single basic block. + /// + /// When called with `0..block_data.statements.len() + 1` as the statement range, this function + /// is equivalent to `apply_whole_block_effect`. + fn apply_partial_block_effect( + &self, + state: &mut BitSet, + block: BasicBlock, + block_data: &mir::BasicBlockData<'tcx>, + mut range: ops::Range, + ) { + if range.is_empty() { + return; + } + + // The final location might be a terminator, so iterate through all statements until the + // final one, then check to see whether the final one is a statement or terminator. + // + // This can't cause the range to wrap-around since we check that the range contains at + // least one element above. + range.end -= 1; + let final_location = Location { block, statement_index: range.end }; + + for statement_index in range { + let location = Location { block, statement_index }; + let stmt = &block_data.statements[statement_index]; + self.apply_statement_effect(state, stmt, location); + } + + if final_location.statement_index == block_data.statements.len() { + let terminator = block_data.terminator(); + self.apply_terminator_effect(state, terminator, final_location); + } else { + let stmt = &block_data.statements[final_location.statement_index]; + self.apply_statement_effect(state, stmt, final_location); + } + } +} + +#[derive(Clone, Copy, Debug)] +enum CursorPosition { + AtBlockStart(BasicBlock), + After(Location), +} + +impl CursorPosition { + fn block(&self) -> BasicBlock { + match *self { + Self::AtBlockStart(block) => block, + Self::After(Location { block, .. }) => block, + } + } +} + +pub struct ResultsCursor<'mir, 'tcx, A> +where + A: Analysis<'tcx>, +{ + body: &'mir mir::Body<'tcx>, + results: Results<'tcx, A>, + state: BitSet, + + pos: CursorPosition, + + /// Whether the effects of `apply_call_return_effect` are currently stored in `state`. + /// + /// This flag ensures that multiple calls to `seek_after_assume_call_returns` with the same + /// target only result in one invocation of `apply_call_return_effect`. + is_call_return_effect_applied: bool, +} + +impl<'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A> +where + A: Analysis<'tcx>, +{ + /// Returns a new cursor for `results` that points to the start of the `START_BLOCK`. + pub fn new(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self { + ResultsCursor { + body, + pos: CursorPosition::AtBlockStart(mir::START_BLOCK), + is_call_return_effect_applied: false, + state: results.entry_sets[mir::START_BLOCK].clone(), + results, + } + } + + /// Resets the cursor to the start of the given `block`. + pub fn seek_to_block_start(&mut self, block: BasicBlock) { + self.state.overwrite(&self.results.entry_sets[block]); + self.pos = CursorPosition::AtBlockStart(block); + self.is_call_return_effect_applied = false; + } + + /// Updates the cursor to hold the dataflow state immediately before `target`. + #[allow(unused)] + pub fn seek_before(&mut self, target: Location) { + assert!(target <= self.body.terminator_loc(target.block)); + + if target.statement_index == 0 { + self.seek_to_block_start(target.block); + } else { + self._seek_after(Location { + block: target.block, + statement_index: target.statement_index - 1, + }); + } + } + + /// Updates the cursor to hold the dataflow state at `target`. + /// + /// If `target` is a `Call` terminator, `apply_call_return_effect` will not be called. See + /// `seek_after_assume_call_returns` if you wish to observe the dataflow state upon a + /// successful return. + #[allow(unused)] + pub fn seek_after(&mut self, target: Location) { + assert!(target <= self.body.terminator_loc(target.block)); + + // This check ensures the correctness of a call to `seek_after_assume_call_returns` + // followed by one to `seek_after` with the same target. + if self.is_call_return_effect_applied { + self.seek_to_block_start(target.block); + } + + self._seek_after(target); + } + + /// Equivalent to `seek_after`, but also calls `apply_call_return_effect` if `target` is a + /// `Call` terminator whose callee is convergent. + #[allow(unused)] + pub fn seek_after_assume_call_returns(&mut self, target: Location) { + assert!(target <= self.body.terminator_loc(target.block)); + + self._seek_after(target); + + if target != self.body.terminator_loc(target.block) { + return; + } + + let term = self.body.basic_blocks()[target.block].terminator(); + if let mir::TerminatorKind::Call { + destination: Some((return_place, _)), + func, + args, + .. + } = &term.kind { + if !self.is_call_return_effect_applied { + self.results.analysis.apply_call_return_effect( + &mut self.state, + target.block, + func, + args, + return_place, + ); + } + } + } + + fn _seek_after(&mut self, target: Location) { + let Location { block: target_block, statement_index: target_index } = target; + + if self.pos.block() != target_block { + self.seek_to_block_start(target_block); + } + + // If we're in the same block but after the target statement, we need to reset to the start + // of the block. + if let CursorPosition::After(Location { statement_index: curr_index, .. }) = self.pos { + match curr_index.cmp(&target_index) { + Ordering::Equal => return, + Ordering::Less => {}, + Ordering::Greater => self.seek_to_block_start(target_block), + } + } + + // The cursor is now in the same block as the target location pointing at an earlier + // statement. + debug_assert_eq!(self.pos.block(), target_block); + if let CursorPosition::After(Location { statement_index, .. }) = self.pos { + debug_assert!(statement_index < target_index); + } + + let first_unapplied_statement = match self.pos { + CursorPosition::AtBlockStart(_) => 0, + CursorPosition::After(Location { statement_index, .. }) => statement_index + 1, + }; + + let block_data = &self.body.basic_blocks()[target_block]; + self.results.analysis.apply_partial_block_effect( + &mut self.state, + target_block, + block_data, + first_unapplied_statement..target_index + 1, + ); + + self.pos = CursorPosition::After(target); + self.is_call_return_effect_applied = false; + } + + /// Gets the dataflow state at the current location. + pub fn get(&self) -> &BitSet { + &self.state + } +} + +pub struct Results<'tcx, A> +where + A: Analysis<'tcx>, +{ + analysis: A, + entry_sets: IndexVec>, +} + +pub struct Engine<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + analysis: A, + bits_per_block: usize, + body: &'a mir::Body<'tcx>, + dead_unwinds: &'a BitSet, + entry_sets: IndexVec>, +} + +impl Engine<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + pub fn new( + body: &'a mir::Body<'tcx>, + dead_unwinds: &'a BitSet, + analysis: A, + ) -> Self { + let bits_per_block = analysis.bits_per_block(body); + + let bottom_value_set = if A::BOTTOM_VALUE == true { + BitSet::new_filled(bits_per_block) + } else { + BitSet::new_empty(bits_per_block) + }; + + let mut entry_sets = IndexVec::from_elem(bottom_value_set, body.basic_blocks()); + analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); + + Engine { + analysis, + bits_per_block, + body, + dead_unwinds, + entry_sets, + } + } + + pub fn iterate_to_fixpoint(mut self) -> Results<'tcx, A> { + let mut temp_state = BitSet::new_empty(self.bits_per_block); + + let mut dirty_queue: WorkQueue = + WorkQueue::with_none(self.body.basic_blocks().len()); + + for (bb, _) in traversal::reverse_postorder(self.body) { + dirty_queue.insert(bb); + } + + // Add blocks that are not reachable from START_BLOCK to the work queue. These blocks will + // be processed after the ones added above. + for bb in self.body.basic_blocks().indices() { + dirty_queue.insert(bb); + } + + while let Some(bb) = dirty_queue.pop() { + let bb_data = &self.body[bb]; + let on_entry = &self.entry_sets[bb]; + + temp_state.overwrite(on_entry); + self.analysis.apply_whole_block_effect(&mut temp_state, bb, bb_data); + + self.propagate_bits_into_graph_successors_of( + &mut temp_state, + (bb, bb_data), + &mut dirty_queue, + ); + } + + Results { + analysis: self.analysis, + entry_sets: self.entry_sets, + } + } + + fn propagate_bits_into_graph_successors_of( + &mut self, + in_out: &mut BitSet, + (bb, bb_data): (BasicBlock, &'a mir::BasicBlockData<'tcx>), + dirty_list: &mut WorkQueue, + ) { + match bb_data.terminator().kind { + mir::TerminatorKind::Return + | mir::TerminatorKind::Resume + | mir::TerminatorKind::Abort + | mir::TerminatorKind::GeneratorDrop + | mir::TerminatorKind::Unreachable => {} + + mir::TerminatorKind::Goto { target } + | mir::TerminatorKind::Assert { target, cleanup: None, .. } + | mir::TerminatorKind::Yield { resume: target, drop: None, .. } + | mir::TerminatorKind::Drop { target, location: _, unwind: None } + | mir::TerminatorKind::DropAndReplace { target, value: _, location: _, unwind: None } => + { + self.propagate_bits_into_entry_set_for(in_out, target, dirty_list); + } + + mir::TerminatorKind::Yield { resume: target, drop: Some(drop), .. } => { + self.propagate_bits_into_entry_set_for(in_out, target, dirty_list); + self.propagate_bits_into_entry_set_for(in_out, drop, dirty_list); + } + + mir::TerminatorKind::Assert { target, cleanup: Some(unwind), .. } + | mir::TerminatorKind::Drop { target, location: _, unwind: Some(unwind) } + | mir::TerminatorKind::DropAndReplace { + target, + value: _, + location: _, + unwind: Some(unwind), + } => { + self.propagate_bits_into_entry_set_for(in_out, target, dirty_list); + if !self.dead_unwinds.contains(bb) { + self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list); + } + } + + mir::TerminatorKind::SwitchInt { ref targets, .. } => { + for target in targets { + self.propagate_bits_into_entry_set_for(in_out, *target, dirty_list); + } + } + + mir::TerminatorKind::Call { cleanup, ref destination, ref func, ref args, .. } => { + if let Some(unwind) = cleanup { + if !self.dead_unwinds.contains(bb) { + self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list); + } + } + + if let Some((ref dest_place, dest_bb)) = *destination { + // N.B.: This must be done *last*, after all other + // propagation, as documented in comment above. + self.analysis.apply_call_return_effect(in_out, bb, func, args, dest_place); + self.propagate_bits_into_entry_set_for(in_out, dest_bb, dirty_list); + } + } + + mir::TerminatorKind::FalseEdges { real_target, imaginary_target } => { + self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list); + self.propagate_bits_into_entry_set_for(in_out, imaginary_target, dirty_list); + } + + mir::TerminatorKind::FalseUnwind { real_target, unwind } => { + self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list); + if let Some(unwind) = unwind { + if !self.dead_unwinds.contains(bb) { + self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list); + } + } + } + } + } + + fn propagate_bits_into_entry_set_for( + &mut self, + in_out: &BitSet, + bb: BasicBlock, + dirty_queue: &mut WorkQueue, + ) { + let entry_set = &mut self.entry_sets[bb]; + let set_changed = self.analysis.join(entry_set, &in_out); + if set_changed { + dirty_queue.insert(bb); + } + } +} diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 7fe2a890a5371..55baeef8860d0 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -30,6 +30,7 @@ use self::move_paths::MoveData; mod at_location; pub mod drop_flag_effects; +pub mod generic; mod graphviz; mod impls; pub mod move_paths; diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index f27db351b74db..c4738d846be63 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -23,6 +23,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(try_blocks)] #![feature(mem_take)] #![feature(associated_type_bounds)] +#![feature(range_is_empty)] #![recursion_limit="256"] From 5496a1fbbe3facc09dfc23be80707905eb844a62 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 17 Sep 2019 17:22:05 -0700 Subject: [PATCH 08/19] Document new dataflow analysis --- src/librustc_mir/dataflow/generic.rs | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs index 7819fd11845e6..696b44ac2efc2 100644 --- a/src/librustc_mir/dataflow/generic.rs +++ b/src/librustc_mir/dataflow/generic.rs @@ -8,15 +8,48 @@ use rustc_data_structures::work_queue::WorkQueue; use crate::dataflow::BottomValue; +/// A specific kind of dataflow analysis. +/// +/// To run a dataflow analysis, one must set the initial state of the `START_BLOCK` via +/// `initialize_start_block` and define a transfer function for each statement or terminator via +/// the various `effect` methods. The entry set for all other basic blocks is initialized to +/// `Self::BOTTOM_VALUE`. The dataflow `Engine` then iteratively updates the various entry sets for +/// each block with the cumulative effects of the transfer functions of all preceding blocks. +/// +/// You should use an `Engine` to actually run an analysis, and a `ResultsCursor` to inspect the +/// results of that analysis like so: +/// +/// ```ignore +/// fn do_my_analysis(body: &mir::Body<'tcx>, dead_unwinds: &BitSet) { +/// let analysis = MyAnalysis::new(); +/// let results = Engine::new(body, dead_unwinds, analysis).iterate_to_fixpoint(); +/// let mut cursor = dataflow::ResultsCursor::new(body, results); +/// +/// for statement_index in body.block_data[START_BLOCK].statements.iter() { +/// cursor.seek_after(Location { block: START_BLOCK, statement_index }); +/// let state = cursor.get(); +/// println!("{:?}", state); +/// } +/// } +/// ``` pub trait Analysis<'tcx>: BottomValue { + /// The index type used to access the dataflow state. type Idx: Idx; + /// A name describing the dataflow analysis being implemented. + /// + /// The name should be suitable as part of a filename, so avoid whitespace, slashes or periods + /// and try to keep it short. fn name() -> &'static str; + /// The size of each bitvector allocated for each block. fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize; + /// Mutates the entry set of the `START_BLOCK` to containthe initial state for dataflow + /// analysis. fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet); + /// Updates the current dataflow state with the effect of evaluating a statement. fn apply_statement_effect( &self, state: &mut BitSet, @@ -24,6 +57,11 @@ pub trait Analysis<'tcx>: BottomValue { location: Location, ); + /// Updates the current dataflow state with the effect of evaluating a statement. + /// + /// Note that the effect of a successful return from a `Call` terminator should **not** be + /// acounted for in this function. That should go in `apply_call_return_effect`. For example, + /// in the `InitializedPlaces` analyses, the return place is not marked as initialized here. fn apply_terminator_effect( &self, state: &mut BitSet, @@ -31,6 +69,11 @@ pub trait Analysis<'tcx>: BottomValue { location: Location, ); + /// Updates the current dataflow state with the effect of a successful return from a `Call` + /// terminator. + /// + /// This is separated from `apply_terminator_effect` to properly track state across + /// unwind edges for `Call`s. fn apply_call_return_effect( &self, state: &mut BitSet, @@ -117,6 +160,11 @@ impl CursorPosition { } } +/// Inspect the results of dataflow analysis. +/// +/// This cursor has linear performance when visiting statements in a block in order. Visiting +/// statements within a block in reverse order is `O(n^2)`, where `n` is the number of statements +/// in that block. pub struct ResultsCursor<'mir, 'tcx, A> where A: Analysis<'tcx>, @@ -267,6 +315,7 @@ where } } +/// A completed dataflow analysis. pub struct Results<'tcx, A> where A: Analysis<'tcx>, @@ -275,6 +324,7 @@ where entry_sets: IndexVec>, } +/// All information required to iterate a dataflow analysis to fixpoint. pub struct Engine<'a, 'tcx, A> where A: Analysis<'tcx>, From 288603709ecb1fc8fb4cf342ff681e112468e593 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 17 Sep 2019 17:22:20 -0700 Subject: [PATCH 09/19] Temporarily add `#[allow(unused)]` for CI This can be removed once dataflow-based const validation is merged. --- src/librustc_mir/dataflow/generic.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs index 696b44ac2efc2..e890b2c66e61c 100644 --- a/src/librustc_mir/dataflow/generic.rs +++ b/src/librustc_mir/dataflow/generic.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + use std::cmp::Ordering; use std::ops; From d583fefa59e87cf39714c92c90fd9449f0975ea2 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 17 Sep 2019 17:49:13 -0700 Subject: [PATCH 10/19] Add ignore reason to placate `tidy` --- src/librustc_mir/dataflow/generic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs index e890b2c66e61c..47d6bd9caba43 100644 --- a/src/librustc_mir/dataflow/generic.rs +++ b/src/librustc_mir/dataflow/generic.rs @@ -21,7 +21,7 @@ use crate::dataflow::BottomValue; /// You should use an `Engine` to actually run an analysis, and a `ResultsCursor` to inspect the /// results of that analysis like so: /// -/// ```ignore +/// ```ignore(cross-crate-imports) /// fn do_my_analysis(body: &mir::Body<'tcx>, dead_unwinds: &BitSet) { /// let analysis = MyAnalysis::new(); /// let results = Engine::new(body, dead_unwinds, analysis).iterate_to_fixpoint(); From cbaaf05b9425996d8d14bbd5fe435ac7d3d955f1 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 18 Sep 2019 07:32:15 -0700 Subject: [PATCH 11/19] Fix `Analysis` example --- src/librustc_mir/dataflow/generic.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs index 47d6bd9caba43..73f17e75afe37 100644 --- a/src/librustc_mir/dataflow/generic.rs +++ b/src/librustc_mir/dataflow/generic.rs @@ -23,11 +23,13 @@ use crate::dataflow::BottomValue; /// /// ```ignore(cross-crate-imports) /// fn do_my_analysis(body: &mir::Body<'tcx>, dead_unwinds: &BitSet) { +/// // `MyAnalysis` implements `Analysis`. /// let analysis = MyAnalysis::new(); +/// /// let results = Engine::new(body, dead_unwinds, analysis).iterate_to_fixpoint(); -/// let mut cursor = dataflow::ResultsCursor::new(body, results); +/// let mut cursor = ResultsCursor::new(body, results); /// -/// for statement_index in body.block_data[START_BLOCK].statements.iter() { +/// for (_, statement_index) in body.block_data[START_BLOCK].statements.iter_enumerated() { /// cursor.seek_after(Location { block: START_BLOCK, statement_index }); /// let state = cursor.get(); /// println!("{:?}", state); From a526e4faa6b69f1b6ea60e5e692b679e24bb1994 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 18 Sep 2019 07:32:42 -0700 Subject: [PATCH 12/19] Use an associated const for `name` --- src/librustc_mir/dataflow/generic.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs index 73f17e75afe37..6ee81de19f138 100644 --- a/src/librustc_mir/dataflow/generic.rs +++ b/src/librustc_mir/dataflow/generic.rs @@ -40,11 +40,11 @@ pub trait Analysis<'tcx>: BottomValue { /// The index type used to access the dataflow state. type Idx: Idx; - /// A name describing the dataflow analysis being implemented. + /// A name, used for debugging, that describes this dataflow analysis. /// /// The name should be suitable as part of a filename, so avoid whitespace, slashes or periods /// and try to keep it short. - fn name() -> &'static str; + const NAME: &'static str; /// The size of each bitvector allocated for each block. fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize; From 19bf0f4c905aa17fb9f975432c1d32e210e2deb8 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 18 Sep 2019 07:32:57 -0700 Subject: [PATCH 13/19] Fix typo --- src/librustc_mir/dataflow/generic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs index 6ee81de19f138..901467d52dc51 100644 --- a/src/librustc_mir/dataflow/generic.rs +++ b/src/librustc_mir/dataflow/generic.rs @@ -49,7 +49,7 @@ pub trait Analysis<'tcx>: BottomValue { /// The size of each bitvector allocated for each block. fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize; - /// Mutates the entry set of the `START_BLOCK` to containthe initial state for dataflow + /// Mutates the entry set of the `START_BLOCK` to contain the initial state for dataflow /// analysis. fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet); From 08aff1afe5edb5c31ebb2b1bcdf6025fa323a8fe Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 18 Sep 2019 07:35:44 -0700 Subject: [PATCH 14/19] Publish `rustc_mir::dataflow` and remove `#[allow(unused)]` --- src/librustc_mir/dataflow/generic.rs | 5 ----- src/librustc_mir/lib.rs | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs index 901467d52dc51..a4b81968d727c 100644 --- a/src/librustc_mir/dataflow/generic.rs +++ b/src/librustc_mir/dataflow/generic.rs @@ -1,5 +1,3 @@ -#![allow(unused)] - use std::cmp::Ordering; use std::ops; @@ -209,7 +207,6 @@ where } /// Updates the cursor to hold the dataflow state immediately before `target`. - #[allow(unused)] pub fn seek_before(&mut self, target: Location) { assert!(target <= self.body.terminator_loc(target.block)); @@ -228,7 +225,6 @@ where /// If `target` is a `Call` terminator, `apply_call_return_effect` will not be called. See /// `seek_after_assume_call_returns` if you wish to observe the dataflow state upon a /// successful return. - #[allow(unused)] pub fn seek_after(&mut self, target: Location) { assert!(target <= self.body.terminator_loc(target.block)); @@ -243,7 +239,6 @@ where /// Equivalent to `seek_after`, but also calls `apply_call_return_effect` if `target` is a /// `Call` terminator whose callee is convergent. - #[allow(unused)] pub fn seek_after_assume_call_returns(&mut self, target: Location) { assert!(target <= self.body.terminator_loc(target.block)); diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index c4738d846be63..091dfbea5a88e 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -36,7 +36,7 @@ pub mod error_codes; mod borrow_check; mod build; -mod dataflow; +pub mod dataflow; mod hair; mod lints; mod shim; From a7f52520d5433a2bd3e4e6727b311047ef066500 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 18 Sep 2019 08:41:38 -0700 Subject: [PATCH 15/19] Add summary of the current state and future plans --- src/librustc_mir/dataflow/generic.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs index a4b81968d727c..5a28df42f20a5 100644 --- a/src/librustc_mir/dataflow/generic.rs +++ b/src/librustc_mir/dataflow/generic.rs @@ -1,3 +1,21 @@ +//! Dataflow analysis with arbitrary transfer functions. +//! +//! This module is a work in progress. You should instead use `BitDenotation` in +//! `librustc_mir/dataflow/mod.rs` and encode your transfer function as a [gen/kill set][gk]. In +//! doing so, your analysis will run faster and you will be able to generate graphviz diagrams for +//! debugging with no extra effort. The interface in this module is intended only for dataflow +//! problems that cannot be expressed using gen/kill sets. +//! +//! FIXME(ecstaticmorse): In the long term, the plan is to preserve the existing `BitDenotation` +//! interface, but make `Engine` and `ResultsCursor` the canonical way to perform and inspect a +//! dataflow analysis. This requires porting the graphviz debugging logic to this module, deciding +//! on a way to handle the `before` methods in `BitDenotation` and creating an adapter so that +//! gen-kill problems can still be evaluated efficiently. See the discussion in [#64566][] for more +//! information. +//! +//! [gk]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems +//! [#64566]: https://github.com/rust-lang/rust/pull/64566 + use std::cmp::Ordering; use std::ops; From b4e94d9a3a04798201676be8f18ee483eb292104 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 18 Sep 2019 09:22:02 -0700 Subject: [PATCH 16/19] Fix bug where `is_call_return_effect_applied` was never set --- src/librustc_mir/dataflow/generic.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs index 5a28df42f20a5..886044c069282 100644 --- a/src/librustc_mir/dataflow/generic.rs +++ b/src/librustc_mir/dataflow/generic.rs @@ -274,6 +274,7 @@ where .. } = &term.kind { if !self.is_call_return_effect_applied { + self.is_call_return_effect_applied = true; self.results.analysis.apply_call_return_effect( &mut self.state, target.block, From f233a4c18bec906dab0b8531f326a15fadece547 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 19 Sep 2019 00:16:16 +0200 Subject: [PATCH 17/19] Fix a minor grammar nit, update UI tests --- src/librustc/traits/select.rs | 2 +- src/test/ui/codemap_tests/overlapping_inherent_impls.stderr | 2 +- .../coherence/coherence-overlap-upstream-inherent.old.stderr | 2 +- .../coherence/coherence-overlap-upstream-inherent.re.stderr | 2 +- src/test/ui/coherence/coherence-overlap-upstream.old.stderr | 2 +- src/test/ui/coherence/coherence-overlap-upstream.re.stderr | 2 +- .../coherence/coherence-projection-conflict-orphan.old.stderr | 4 ++-- .../coherence/coherence-projection-conflict-orphan.re.stderr | 4 ++-- ...oherence_copy_like_err_fundamental_struct_tuple.old.stderr | 2 +- ...coherence_copy_like_err_fundamental_struct_tuple.re.stderr | 2 +- .../ui/coherence/coherence_copy_like_err_struct.old.stderr | 2 +- .../ui/coherence/coherence_copy_like_err_struct.re.stderr | 2 +- .../ui/coherence/coherence_copy_like_err_tuple.old.stderr | 2 +- src/test/ui/coherence/coherence_copy_like_err_tuple.re.stderr | 2 +- src/test/ui/issues/issue-48728.stderr | 2 +- src/test/ui/specialization/issue-52050.stderr | 4 ++-- 16 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 217c887d5254e..a54bc05f16961 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -134,7 +134,7 @@ impl IntercrateAmbiguityCause { String::new() }; format!( - "upstream crates may add new impl of trait `{}`{} \ + "upstream crates may add a new impl of trait `{}`{} \ in future versions", trait_desc, self_desc ) diff --git a/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr index 70c1093e9ed48..8fe24bae7c6ca 100644 --- a/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr +++ b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr @@ -25,7 +25,7 @@ LL | fn baz(&self) {} LL | fn baz(&self) {} | ---------------- other definition for `baz` | - = note: upstream crates may add new impl of trait `std::marker::Copy` for type `std::vec::Vec<_>` in future versions + = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::vec::Vec<_>` in future versions error: aborting due to 3 previous errors diff --git a/src/test/ui/coherence/coherence-overlap-upstream-inherent.old.stderr b/src/test/ui/coherence/coherence-overlap-upstream-inherent.old.stderr index 928b65e003918..3a3e1a4afc3bb 100644 --- a/src/test/ui/coherence/coherence-overlap-upstream-inherent.old.stderr +++ b/src/test/ui/coherence/coherence-overlap-upstream-inherent.old.stderr @@ -7,7 +7,7 @@ LL | impl A where T: Remote { fn dummy(&self) { } } LL | impl A { fn dummy(&self) { } } | ------------------- other definition for `dummy` | - = note: upstream crates may add new impl of trait `coherence_lib::Remote` for type `i16` in future versions + = note: upstream crates may add a new impl of trait `coherence_lib::Remote` for type `i16` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-overlap-upstream-inherent.re.stderr b/src/test/ui/coherence/coherence-overlap-upstream-inherent.re.stderr index 928b65e003918..3a3e1a4afc3bb 100644 --- a/src/test/ui/coherence/coherence-overlap-upstream-inherent.re.stderr +++ b/src/test/ui/coherence/coherence-overlap-upstream-inherent.re.stderr @@ -7,7 +7,7 @@ LL | impl A where T: Remote { fn dummy(&self) { } } LL | impl A { fn dummy(&self) { } } | ------------------- other definition for `dummy` | - = note: upstream crates may add new impl of trait `coherence_lib::Remote` for type `i16` in future versions + = note: upstream crates may add a new impl of trait `coherence_lib::Remote` for type `i16` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-overlap-upstream.old.stderr b/src/test/ui/coherence/coherence-overlap-upstream.old.stderr index 6c3484c2d8c4d..bd6f59f346b6d 100644 --- a/src/test/ui/coherence/coherence-overlap-upstream.old.stderr +++ b/src/test/ui/coherence/coherence-overlap-upstream.old.stderr @@ -6,7 +6,7 @@ LL | impl Foo for T where T: Remote {} LL | impl Foo for i16 {} | ^^^^^^^^^^^^^^^^ conflicting implementation for `i16` | - = note: upstream crates may add new impl of trait `coherence_lib::Remote` for type `i16` in future versions + = note: upstream crates may add a new impl of trait `coherence_lib::Remote` for type `i16` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-overlap-upstream.re.stderr b/src/test/ui/coherence/coherence-overlap-upstream.re.stderr index 6c3484c2d8c4d..bd6f59f346b6d 100644 --- a/src/test/ui/coherence/coherence-overlap-upstream.re.stderr +++ b/src/test/ui/coherence/coherence-overlap-upstream.re.stderr @@ -6,7 +6,7 @@ LL | impl Foo for T where T: Remote {} LL | impl Foo for i16 {} | ^^^^^^^^^^^^^^^^ conflicting implementation for `i16` | - = note: upstream crates may add new impl of trait `coherence_lib::Remote` for type `i16` in future versions + = note: upstream crates may add a new impl of trait `coherence_lib::Remote` for type `i16` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-projection-conflict-orphan.old.stderr b/src/test/ui/coherence/coherence-projection-conflict-orphan.old.stderr index cde9360ddf2c8..26dadec5bba7e 100644 --- a/src/test/ui/coherence/coherence-projection-conflict-orphan.old.stderr +++ b/src/test/ui/coherence/coherence-projection-conflict-orphan.old.stderr @@ -3,11 +3,11 @@ error[E0119]: conflicting implementations of trait `Foo` for type `i32`: | LL | impl Foo for i32 { } | --------------------- first implementation here -LL | +LL | LL | impl Foo for A { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | - = note: upstream crates may add new impl of trait `std::iter::Iterator` for type `i32` in future versions + = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-projection-conflict-orphan.re.stderr b/src/test/ui/coherence/coherence-projection-conflict-orphan.re.stderr index cde9360ddf2c8..26dadec5bba7e 100644 --- a/src/test/ui/coherence/coherence-projection-conflict-orphan.re.stderr +++ b/src/test/ui/coherence/coherence-projection-conflict-orphan.re.stderr @@ -3,11 +3,11 @@ error[E0119]: conflicting implementations of trait `Foo` for type `i32`: | LL | impl Foo for i32 { } | --------------------- first implementation here -LL | +LL | LL | impl Foo for A { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | - = note: upstream crates may add new impl of trait `std::iter::Iterator` for type `i32` in future versions + = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.old.stderr b/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.old.stderr index 12c7a1f977c3f..4d9f55c121547 100644 --- a/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.old.stderr +++ b/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.old.stderr @@ -7,7 +7,7 @@ LL | impl MyTrait for T { } LL | impl MyTrait for lib::MyFundamentalStruct<(MyType,)> { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `lib::MyFundamentalStruct<(MyType,)>` | - = note: upstream crates may add new impl of trait `lib::MyCopy` for type `lib::MyFundamentalStruct<(MyType,)>` in future versions + = note: upstream crates may add a new impl of trait `lib::MyCopy` for type `lib::MyFundamentalStruct<(MyType,)>` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.re.stderr b/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.re.stderr index 12c7a1f977c3f..4d9f55c121547 100644 --- a/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.re.stderr +++ b/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_tuple.re.stderr @@ -7,7 +7,7 @@ LL | impl MyTrait for T { } LL | impl MyTrait for lib::MyFundamentalStruct<(MyType,)> { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `lib::MyFundamentalStruct<(MyType,)>` | - = note: upstream crates may add new impl of trait `lib::MyCopy` for type `lib::MyFundamentalStruct<(MyType,)>` in future versions + = note: upstream crates may add a new impl of trait `lib::MyCopy` for type `lib::MyFundamentalStruct<(MyType,)>` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_copy_like_err_struct.old.stderr b/src/test/ui/coherence/coherence_copy_like_err_struct.old.stderr index 1b6c62e9bf3a8..f0bcf659bb696 100644 --- a/src/test/ui/coherence/coherence_copy_like_err_struct.old.stderr +++ b/src/test/ui/coherence/coherence_copy_like_err_struct.old.stderr @@ -7,7 +7,7 @@ LL | impl MyTrait for T { } LL | impl MyTrait for lib::MyStruct { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `lib::MyStruct` | - = note: upstream crates may add new impl of trait `lib::MyCopy` for type `lib::MyStruct` in future versions + = note: upstream crates may add a new impl of trait `lib::MyCopy` for type `lib::MyStruct` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_copy_like_err_struct.re.stderr b/src/test/ui/coherence/coherence_copy_like_err_struct.re.stderr index 1b6c62e9bf3a8..f0bcf659bb696 100644 --- a/src/test/ui/coherence/coherence_copy_like_err_struct.re.stderr +++ b/src/test/ui/coherence/coherence_copy_like_err_struct.re.stderr @@ -7,7 +7,7 @@ LL | impl MyTrait for T { } LL | impl MyTrait for lib::MyStruct { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `lib::MyStruct` | - = note: upstream crates may add new impl of trait `lib::MyCopy` for type `lib::MyStruct` in future versions + = note: upstream crates may add a new impl of trait `lib::MyCopy` for type `lib::MyStruct` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_copy_like_err_tuple.old.stderr b/src/test/ui/coherence/coherence_copy_like_err_tuple.old.stderr index 11bd788c76153..a40153af2cf30 100644 --- a/src/test/ui/coherence/coherence_copy_like_err_tuple.old.stderr +++ b/src/test/ui/coherence/coherence_copy_like_err_tuple.old.stderr @@ -7,7 +7,7 @@ LL | impl MyTrait for T { } LL | impl MyTrait for (MyType,) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(MyType,)` | - = note: upstream crates may add new impl of trait `lib::MyCopy` for type `(MyType,)` in future versions + = note: upstream crates may add a new impl of trait `lib::MyCopy` for type `(MyType,)` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_copy_like_err_tuple.re.stderr b/src/test/ui/coherence/coherence_copy_like_err_tuple.re.stderr index 11bd788c76153..a40153af2cf30 100644 --- a/src/test/ui/coherence/coherence_copy_like_err_tuple.re.stderr +++ b/src/test/ui/coherence/coherence_copy_like_err_tuple.re.stderr @@ -7,7 +7,7 @@ LL | impl MyTrait for T { } LL | impl MyTrait for (MyType,) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(MyType,)` | - = note: upstream crates may add new impl of trait `lib::MyCopy` for type `(MyType,)` in future versions + = note: upstream crates may add a new impl of trait `lib::MyCopy` for type `(MyType,)` in future versions error: aborting due to previous error diff --git a/src/test/ui/issues/issue-48728.stderr b/src/test/ui/issues/issue-48728.stderr index 99a9bf9903e25..84c10d8fbc477 100644 --- a/src/test/ui/issues/issue-48728.stderr +++ b/src/test/ui/issues/issue-48728.stderr @@ -7,7 +7,7 @@ LL | #[derive(Clone)] LL | impl Clone for Node<[T]> { | ------------------------------------------- first implementation here | - = note: upstream crates may add new impl of trait `std::clone::Clone` for type `[_]` in future versions + = note: upstream crates may add a new impl of trait `std::clone::Clone` for type `[_]` in future versions error: aborting due to previous error diff --git a/src/test/ui/specialization/issue-52050.stderr b/src/test/ui/specialization/issue-52050.stderr index dcb34f3ad4836..2a0f127bdaf60 100644 --- a/src/test/ui/specialization/issue-52050.stderr +++ b/src/test/ui/specialization/issue-52050.stderr @@ -7,11 +7,11 @@ LL | | I: Iterator, LL | | { LL | | } | |_- first implementation here -LL | +LL | LL | impl IntoPyDictPointer for () | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` | - = note: upstream crates may add new impl of trait `std::iter::Iterator` for type `()` in future versions + = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions error: aborting due to previous error From 333230fd140b3b39aa655bcfcda3ee6810b0ac3c Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 19 Sep 2019 00:50:03 +0200 Subject: [PATCH 18/19] Restore whitespace --- .../coherence/coherence-projection-conflict-orphan.old.stderr | 2 +- .../ui/coherence/coherence-projection-conflict-orphan.re.stderr | 2 +- src/test/ui/specialization/issue-52050.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/ui/coherence/coherence-projection-conflict-orphan.old.stderr b/src/test/ui/coherence/coherence-projection-conflict-orphan.old.stderr index 26dadec5bba7e..728eae5e547da 100644 --- a/src/test/ui/coherence/coherence-projection-conflict-orphan.old.stderr +++ b/src/test/ui/coherence/coherence-projection-conflict-orphan.old.stderr @@ -3,7 +3,7 @@ error[E0119]: conflicting implementations of trait `Foo` for type `i32`: | LL | impl Foo for i32 { } | --------------------- first implementation here -LL | +LL | LL | impl Foo for A { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | diff --git a/src/test/ui/coherence/coherence-projection-conflict-orphan.re.stderr b/src/test/ui/coherence/coherence-projection-conflict-orphan.re.stderr index 26dadec5bba7e..728eae5e547da 100644 --- a/src/test/ui/coherence/coherence-projection-conflict-orphan.re.stderr +++ b/src/test/ui/coherence/coherence-projection-conflict-orphan.re.stderr @@ -3,7 +3,7 @@ error[E0119]: conflicting implementations of trait `Foo` for type `i32`: | LL | impl Foo for i32 { } | --------------------- first implementation here -LL | +LL | LL | impl Foo for A { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | diff --git a/src/test/ui/specialization/issue-52050.stderr b/src/test/ui/specialization/issue-52050.stderr index 2a0f127bdaf60..36f96b011983f 100644 --- a/src/test/ui/specialization/issue-52050.stderr +++ b/src/test/ui/specialization/issue-52050.stderr @@ -7,7 +7,7 @@ LL | | I: Iterator, LL | | { LL | | } | |_- first implementation here -LL | +LL | LL | impl IntoPyDictPointer for () | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` | From d440e136e753210882d930c6f4884a43984f6ba0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 16 Sep 2019 14:45:40 -0400 Subject: [PATCH 19/19] Update Cargo This pulls in https://github.com/rust-lang/cargo/pull/7159, which ensures that documenting proc macros works correctly. --- Cargo.lock | 32 ++++++++++++++++++++--- src/tools/cargo | 2 +- src/tools/rustc-workspace-hack/Cargo.toml | 1 + 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0fe3138427468..894dcf937de50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -272,6 +272,7 @@ dependencies = [ "atty", "bytesize", "cargo-test-macro", + "cargo-test-support", "clap", "core-foundation", "crates-io", @@ -288,8 +289,9 @@ dependencies = [ "git2", "git2-curl", "glob", - "hex", + "hex 0.4.0", "home", + "humantime", "ignore", "im-rc", "jobserver", @@ -329,6 +331,23 @@ dependencies = [ name = "cargo-test-macro" version = "0.1.0" +[[package]] +name = "cargo-test-support" +version = "0.1.0" +dependencies = [ + "cargo", + "cargo-test-macro", + "filetime", + "flate2", + "git2", + "glob", + "lazy_static 1.3.0", + "remove_dir_all", + "serde_json", + "tar", + "url 2.1.0", +] + [[package]] name = "cargo_metadata" version = "0.8.0" @@ -700,7 +719,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4" dependencies = [ "commoncrypto", - "hex", + "hex 0.3.2", "openssl", "winapi 0.3.6", ] @@ -1262,6 +1281,12 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" +[[package]] +name = "hex" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e" + [[package]] name = "home" version = "0.5.0" @@ -2064,7 +2089,7 @@ dependencies = [ "directories", "env_logger", "getrandom", - "hex", + "hex 0.3.2", "log", "num-traits", "rand 0.7.0", @@ -3259,6 +3284,7 @@ dependencies = [ "serde", "serde_json", "smallvec", + "url 2.1.0", "winapi 0.3.6", ] diff --git a/src/tools/cargo b/src/tools/cargo index 9655d70af8a6d..3596cb86b2e87 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 9655d70af8a6dddac238e3afa2fec75088c9226f +Subproject commit 3596cb86b2e87dd9b9c1bb90d4a9d73ec2c1512f diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 930279c0ca27b..980c9753761ed 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -62,6 +62,7 @@ crossbeam-utils = { version = "0.6.5", features = ["nightly"] } serde = { version = "1.0.82", features = ['derive'] } serde_json = { version = "1.0.31", features = ["raw_value"] } smallvec = { version = "0.6", features = ['union', 'may_dangle'] } +url = { version = "2.0", features = ['serde'] } [target.'cfg(not(windows))'.dependencies]