Skip to content

Rollup of 13 pull requests #65009

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 38 commits into from
Oct 2, 2019
Merged
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
4aa526f
Improve sidebar styling to make its integration easier
GuillaumeGomez Oct 1, 2019
9fe138a
regression test for 64453 borrow check error.
pnkfelix Sep 30, 2019
4808106
fix typo
ztlpn Sep 16, 2019
057569e
fix spurious unreachable_code lints for try{} block ok-wrapping
ztlpn Sep 18, 2019
c474c6e
add tests
ztlpn Sep 18, 2019
ffa5269
address review comments
ztlpn Sep 18, 2019
cb4ed52
fix test after rebase
ztlpn Sep 22, 2019
6acdea4
Make comment about dummy type a bit more clear
spastorino Oct 1, 2019
738baa7
Update src/librustc/ty/mod.rs
spastorino Oct 1, 2019
75fdb95
change .node -> .kind after rebase
ztlpn Oct 1, 2019
a1ad38f
Pass attrs to `do_dataflow` in new const checker
ecstatic-morse Oct 1, 2019
8d84646
Don't mark zero-sized arrays as indirectly mutable when borrowed
ecstatic-morse Oct 1, 2019
4eeedd0
Add test cases for #64945
ecstatic-morse Oct 1, 2019
2427029
Fix typo passing flags to rustc
ecstatic-morse Oct 1, 2019
cf984d2
This needs to be build-pass since it involves debuginfo
ecstatic-morse Oct 1, 2019
f18535f
Refactor `rustc_peek`
ecstatic-morse Jul 6, 2019
767550e
Add `rustc_peek` support for `IndirectlyMutableLocals`
ecstatic-morse Oct 2, 2019
33aa5e8
Add test exposing unsoundness in `IndirectlyMutableLocals`
ecstatic-morse Oct 2, 2019
8e67180
Fix async/await ICE #64964
sinkuu Oct 2, 2019
f0fddb1
Do not collect to vec for debug output
sinkuu Oct 2, 2019
3a8932d
[const-prop] Correctly handle locals that can't be propagated
wesleywiser Oct 2, 2019
675ed48
Remove inline annotations from dep_node
Mark-Simulacrum Sep 30, 2019
70dcb99
Remove rustdoc warning
GuillaumeGomez Oct 2, 2019
8e9f635
rustc book: nitpick SLP vectorization
Oct 2, 2019
79dc862
Use PlaceBuilder to avoid a lot of slice -> vec -> slice convertions
spastorino Sep 30, 2019
18d0c03
Rollup merge of #64581 - ztlpn:fix-ok-wrapping-unreachable-code, r=Ce…
Centril Oct 2, 2019
b7290a0
Rollup merge of #64850 - Mark-Simulacrum:dedup-dep-node, r=michaelwoe…
Centril Oct 2, 2019
fe5fad8
Rollup merge of #64914 - pnkfelix:issue-64453-regression-test, r=niko…
Centril Oct 2, 2019
19d035c
Rollup merge of #64922 - spastorino:make-place-builder, r=nikomatsakis
Centril Oct 2, 2019
1c8ef98
Rollup merge of #64948 - GuillaumeGomez:improve-sidebar-styling, r=Ma…
Centril Oct 2, 2019
475f5d4
Rollup merge of #64961 - rust-lang:spastorino-patch-1, r=oli-obk
Centril Oct 2, 2019
ccf1d9c
Rollup merge of #64967 - ecstatic-morse:issue-64945, r=oli-obk
Centril Oct 2, 2019
10b0fe9
Rollup merge of #64973 - ecstatic-morse:fix-debuginfo-test, r=alexcri…
Centril Oct 2, 2019
7daf2e8
Rollup merge of #64980 - ecstatic-morse:better-rustc-peek, r=oli-obk
Centril Oct 2, 2019
028ffd1
Rollup merge of #64989 - sinkuu:fix_ice_64964, r=davidtwco
Centril Oct 2, 2019
34ea559
Rollup merge of #64991 - wesleywiser:fix_too_eager_const_prop, r=oli-obk
Centril Oct 2, 2019
ebbc9ce
Rollup merge of #64995 - GuillaumeGomez:libtest-rustdoc-warning, r=Ma…
Centril Oct 2, 2019
b961f96
Rollup merge of #64997 - rust-lang:nitpick-slp, r=jonas-schievink
Centril Oct 2, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactor rustc_peek
We now use `DataflowResultsCursor` to get the dataflow state before
calls to `rustc_peek`. The original version used a custom implementation
that only looked at assignment statements. This also extends
`rustc_peek` to take arguments by-value as well as by-reference, and
allows *all* dataflow analyses, not just those dependent on `MoveData`,
to be inspected.
ecstatic-morse committed Oct 2, 2019
commit f18535fa46752ac33ceaebe71386cf77a6df8f9a
284 changes: 153 additions & 131 deletions src/librustc_mir/transform/rustc_peek.rs
Original file line number Diff line number Diff line change
@@ -3,16 +3,17 @@ use syntax::ast;
use syntax::symbol::sym;
use syntax_pos::Span;

use rustc::ty::{self, TyCtxt};
use rustc::ty::{self, TyCtxt, Ty};
use rustc::hir::def_id::DefId;
use rustc::mir::{self, Body, Location};
use rustc::mir::{self, Body, Location, Local};
use rustc_index::bit_set::BitSet;
use crate::transform::{MirPass, MirSource};

use crate::dataflow::{do_dataflow, DebugFormatted};
use crate::dataflow::MoveDataParamEnv;
use crate::dataflow::BitDenotation;
use crate::dataflow::DataflowResults;
use crate::dataflow::DataflowResultsCursor;
use crate::dataflow::{
DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces
};
@@ -88,151 +89,172 @@ pub fn sanity_check_via_rustc_peek<'tcx, O>(
def_id: DefId,
_attributes: &[ast::Attribute],
results: &DataflowResults<'tcx, O>,
) where
O: BitDenotation<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>,
{
) where O: RustcPeekAt<'tcx> {
debug!("sanity_check_via_rustc_peek def_id: {:?}", def_id);
// FIXME: this is not DRY. Figure out way to abstract this and
// `dataflow::build_sets`. (But note it is doing non-standard
// stuff, so such generalization may not be realistic.)

for bb in body.basic_blocks().indices() {
each_block(tcx, body, results, bb);
}
}
let mut cursor = DataflowResultsCursor::new(results, body);

fn each_block<'tcx, O>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
results: &DataflowResults<'tcx, O>,
bb: mir::BasicBlock,
) where
O: BitDenotation<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>,
{
let move_data = results.0.operator.move_data();
let mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = body[bb];

let (args, span) = match is_rustc_peek(tcx, terminator) {
Some(args_and_span) => args_and_span,
None => return,
};
assert!(args.len() == 1);
let peek_arg_place = match args[0] {
mir::Operand::Copy(ref place @ mir::Place {
base: mir::PlaceBase::Local(_),
projection: box [],
}) |
mir::Operand::Move(ref place @ mir::Place {
base: mir::PlaceBase::Local(_),
projection: box [],
}) => Some(place),
_ => None,
};

let peek_arg_place = match peek_arg_place {
Some(arg) => arg,
None => {
tcx.sess.diagnostic().span_err(
span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
return;
}
};

let mut on_entry = results.0.sets.entry_set_for(bb.index()).to_owned();
let mut trans = results.0.sets.trans_for(bb.index()).clone();

// Emulate effect of all statements in the block up to (but not
// including) the borrow within `peek_arg_place`. Do *not* include
// call to `peek_arg_place` itself (since we are peeking the state
// of the argument at time immediate preceding Call to
// `rustc_peek`).

for (j, stmt) in statements.iter().enumerate() {
debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
let (place, rvalue) = match stmt.kind {
mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
(place, rvalue)
let peek_calls = body
.basic_blocks()
.iter_enumerated()
.filter_map(|(bb, block_data)| {
PeekCall::from_terminator(tcx, block_data.terminator())
.map(|call| (bb, block_data, call))
});

for (bb, block_data, call) in peek_calls {
// Look for a sequence like the following to indicate that we should be peeking at `_1`:
// _2 = &_1;
// rustc_peek(_2);
//
// /* or */
//
// _2 = _1;
// rustc_peek(_2);
let (statement_index, peek_rval) = block_data
.statements
.iter()
.enumerate()
.filter_map(|(i, stmt)| value_assigned_to_local(stmt, call.arg).map(|rval| (i, rval)))
.next()
.expect("call to rustc_peek should be preceded by \
assignment to temporary holding its argument");

match (call.kind, peek_rval) {
| (PeekCallKind::ByRef, mir::Rvalue::Ref(_, _, place))
| (PeekCallKind::ByVal, mir::Rvalue::Use(mir::Operand::Move(place)))
| (PeekCallKind::ByVal, mir::Rvalue::Use(mir::Operand::Copy(place)))
=> {
let loc = Location { block: bb, statement_index };
cursor.seek(loc);
let state = cursor.get();
results.operator().peek_at(tcx, place, state, call);
}
mir::StatementKind::FakeRead(..) |
mir::StatementKind::StorageLive(_) |
mir::StatementKind::StorageDead(_) |
mir::StatementKind::InlineAsm { .. } |
mir::StatementKind::Retag { .. } |
mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => continue,
mir::StatementKind::SetDiscriminant{ .. } =>
span_bug!(stmt.source_info.span,
"sanity_check should run before Deaggregator inserts SetDiscriminant"),
};

if place == peek_arg_place {
if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = *rvalue {
// Okay, our search is over.
match move_data.rev_lookup.find(peeking_at_place.as_ref()) {
LookupResult::Exact(peek_mpi) => {
let bit_state = on_entry.contains(peek_mpi);
debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
place, peeking_at_place, bit_state);
if !bit_state {
tcx.sess.span_err(span, "rustc_peek: bit not set");
}
}
LookupResult::Parent(..) => {
tcx.sess.span_err(span, "rustc_peek: argument untracked");
}
}
return;
} else {
// Our search should have been over, but the input
// does not match expectations of `rustc_peek` for
// this sanity_check.

_ => {
let msg = "rustc_peek: argument expression \
must be immediate borrow of form `&expr`";
tcx.sess.span_err(span, msg);
must be either `place` or `&place`";
tcx.sess.span_err(call.span, msg);
}
}
}
}

let lhs_mpi = move_data.rev_lookup.find(place.as_ref());

debug!("rustc_peek: computing effect on place: {:?} ({:?}) in stmt: {:?}",
place, lhs_mpi, stmt);
// reset GEN and KILL sets before emulating their effect.
trans.clear();
results.0.operator.before_statement_effect(
&mut trans,
Location { block: bb, statement_index: j });
results.0.operator.statement_effect(
&mut trans,
Location { block: bb, statement_index: j });
trans.apply(&mut on_entry);
/// If `stmt` is an assignment where the LHS is the given local (with no projections), returns the
/// RHS of the assignment.
fn value_assigned_to_local<'a, 'tcx>(
stmt: &'a mir::Statement<'tcx>,
local: Local,
) -> Option<&'a mir::Rvalue<'tcx>> {
if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
if let mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } = place {
if local == *l {
return Some(&*rvalue);
}
}
}

results.0.operator.before_terminator_effect(
&mut trans,
Location { block: bb, statement_index: statements.len() });
None
}

tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \
anticipated pattern; note that \
rustc_peek expects input of \
form `&expr`"));
#[derive(Clone, Copy, Debug)]
enum PeekCallKind {
ByVal,
ByRef,
}

fn is_rustc_peek<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
terminator: &'a Option<mir::Terminator<'tcx>>,
) -> Option<(&'a [mir::Operand<'tcx>], Span)> {
if let Some(mir::Terminator { ref kind, source_info, .. }) = *terminator {
if let mir::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind {
if let mir::Operand::Constant(ref func) = *oper {
if let ty::FnDef(def_id, _) = func.literal.ty.kind {
let abi = tcx.fn_sig(def_id).abi();
let name = tcx.item_name(def_id);
if abi == Abi::RustIntrinsic && name == sym::rustc_peek {
return Some((args, source_info.span));
impl PeekCallKind {
fn from_arg_ty(arg: Ty<'_>) -> Self {
match arg.kind {
ty::Ref(_, _, _) => PeekCallKind::ByRef,
_ => PeekCallKind::ByVal,
}
}
}

#[derive(Clone, Copy, Debug)]
pub struct PeekCall {
arg: Local,
kind: PeekCallKind,
span: Span,
}

impl PeekCall {
fn from_terminator<'tcx>(
tcx: TyCtxt<'tcx>,
terminator: &mir::Terminator<'tcx>,
) -> Option<Self> {
use mir::{Operand, Place, PlaceBase};

let span = terminator.source_info.span;
if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
&terminator.kind
{
if let ty::FnDef(def_id, substs) = func.literal.ty.kind {
let sig = tcx.fn_sig(def_id);
let name = tcx.item_name(def_id);
if sig.abi() != Abi::RustIntrinsic || name != sym::rustc_peek {
return None;
}

assert_eq!(args.len(), 1);
let kind = PeekCallKind::from_arg_ty(substs.type_at(0));
let arg = match args[0] {
| Operand::Copy(Place { base: PlaceBase::Local(local), projection: box [] })
| Operand::Move(Place { base: PlaceBase::Local(local), projection: box [] })
=> local,

_ => {
tcx.sess.diagnostic().span_err(
span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
return None;
}
};

return Some(PeekCall {
arg,
kind,
span,
});
}
}

None
}
}

pub trait RustcPeekAt<'tcx>: BitDenotation<'tcx> {
fn peek_at(
&self,
tcx: TyCtxt<'tcx>,
place: &mir::Place<'tcx>,
flow_state: &BitSet<Self::Idx>,
call: PeekCall,
);
}

impl<'tcx, O> RustcPeekAt<'tcx> for O
where O: BitDenotation<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>,
{
fn peek_at(
&self,
tcx: TyCtxt<'tcx>,
place: &mir::Place<'tcx>,
flow_state: &BitSet<Self::Idx>,
call: PeekCall,
) {
match self.move_data().rev_lookup.find(place.as_ref()) {
LookupResult::Exact(peek_mpi) => {
let bit_state = flow_state.contains(peek_mpi);
debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
call.arg, place, bit_state);
if !bit_state {
tcx.sess.span_err(call.span, "rustc_peek: bit not set");
}
}
LookupResult::Parent(..) => {
tcx.sess.span_err(call.span, "rustc_peek: argument untracked");
}
}
}
return None;
}