Skip to content
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

Rollup of 9 pull requests #64932

Merged
merged 25 commits into from
Oct 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ce60da4
Fix `vec![x; n]` with null raw fat pointer zeroing the pointer metadata
SimonSapin Sep 29, 2019
6c01c0e
Zero-initialize `vec![None; n]` for `Option<&T>`, `Option<&mut T>` an…
SimonSapin Sep 29, 2019
2185710
Use https for curl when building for linux
tmandry Sep 28, 2019
6c6d27d
Fixed a misleading documentation issue #64844
hman523 Sep 30, 2019
cc9db52
Add long error explanation for E0493
GuillaumeGomez Sep 11, 2019
9f978b7
update tests
GuillaumeGomez Sep 12, 2019
67eabe1
Add long error explanation for E0550
GuillaumeGomez Sep 27, 2019
e67ae0e
update ui tests
GuillaumeGomez Sep 27, 2019
5bf4397
Add test for issue-64662
JohnTitor Sep 30, 2019
cdf1852
Add missing links for mem::needs_drop
tesuji Sep 30, 2019
f33d94d
Fix typo in docs
ecstatic-morse Sep 26, 2019
3e88aa2
Allow `ResultsCursor` to borrow the underlying `Results`
ecstatic-morse Sep 26, 2019
d37c318
Add graphviz debug output for generic dataflow
ecstatic-morse Sep 26, 2019
cd24cd4
Update consumers of `generic::Engine` API
ecstatic-morse Sep 30, 2019
cf5f5c5
Use separate files for debugging `Qualif` dataflow results
ecstatic-morse Sep 30, 2019
2b8e023
Stop printing `Qualif` results in debug logs
ecstatic-morse Sep 30, 2019
30ba6fd
Rollup merge of #64377 - GuillaumeGomez:E0493, r=estebank
tmandry Sep 30, 2019
fb8f9b4
Rollup merge of #64786 - tmandry:patch-1, r=alexcrichton
tmandry Sep 30, 2019
686ad4d
Rollup merge of #64828 - ecstatic-morse:generic-dataflow-graphviz, r=…
tmandry Sep 30, 2019
3add979
Rollup merge of #64838 - GuillaumeGomez:long-err-explanation-e0550, r…
tmandry Sep 30, 2019
1cd9b4b
Rollup merge of #64891 - SimonSapin:vec-of-fat-raw-ptr, r=sfackler
tmandry Sep 30, 2019
a8ed9bf
Rollup merge of #64893 - SimonSapin:vec-of-option-box, r=sfackler
tmandry Sep 30, 2019
5560f8c
Rollup merge of #64911 - hman523:64844, r=Dylan-DPC
tmandry Sep 30, 2019
e9d2879
Rollup merge of #64921 - JohnTitor:add-test-enum, r=varkor
tmandry Sep 30, 2019
913c095
Rollup merge of #64923 - lzutao:improve-doc-needs_drop, r=jonas-schie…
tmandry Sep 30, 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
6 changes: 4 additions & 2 deletions src/ci/docker/dist-x86_64-linux/build-curl.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
set -ex
source shared.sh

VERSION=7.51.0
VERSION=7.66.0

curl http://cool.haxx.se/download/curl-$VERSION.tar.bz2 | tar xjf -
curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/curl-$VERSION.tar.xz \
| xz --decompress \
| tar xf -

mkdir curl-build
cd curl-build
Expand Down
48 changes: 48 additions & 0 deletions src/liballoc/tests/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1281,3 +1281,51 @@ fn test_stable_push_pop() {
v.pop().unwrap();
assert_eq!(*v0, 13);
}

// https://github.com/rust-lang/rust/pull/49496 introduced specialization based on:
//
// ```
// unsafe impl<T: ?Sized> IsZero for *mut T {
// fn is_zero(&self) -> bool {
// (*self).is_null()
// }
// }
// ```
//
// … to call `RawVec::with_capacity_zeroed` for creating `Vec<*mut T>`,
// which is incorrect for fat pointers since `<*mut T>::is_null` only looks at the data component.
// That is, a fat pointer can be “null” without being made entirely of zero bits.
#[test]
fn vec_macro_repeating_null_raw_fat_pointer() {
let raw_dyn = &mut (|| ()) as &mut dyn Fn() as *mut dyn Fn();
let vtable = dbg!(ptr_metadata(raw_dyn));
let null_raw_dyn = ptr_from_raw_parts(std::ptr::null_mut(), vtable);
assert!(null_raw_dyn.is_null());

let vec = vec![null_raw_dyn; 1];
dbg!(ptr_metadata(vec[0]));
assert!(vec[0] == null_raw_dyn);

// Polyfill for https://github.com/rust-lang/rfcs/pull/2580

fn ptr_metadata(ptr: *mut dyn Fn()) -> *mut () {
unsafe {
std::mem::transmute::<*mut dyn Fn(), DynRepr>(ptr).vtable
}
}

fn ptr_from_raw_parts(data: *mut (), vtable: *mut()) -> *mut dyn Fn() {
unsafe {
std::mem::transmute::<DynRepr, *mut dyn Fn()>(DynRepr {
data,
vtable
})
}
}

#[repr(C)]
struct DynRepr {
data: *mut (),
vtable: *mut (),
}
}
29 changes: 27 additions & 2 deletions src/liballoc/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1734,20 +1734,45 @@ impl_is_zero!(char, |x| x == '\0');
impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
impl_is_zero!(f64, |x: f64| x.to_bits() == 0);

unsafe impl<T: ?Sized> IsZero for *const T {
unsafe impl<T> IsZero for *const T {
#[inline]
fn is_zero(&self) -> bool {
(*self).is_null()
}
}

unsafe impl<T: ?Sized> IsZero for *mut T {
unsafe impl<T> IsZero for *mut T {
#[inline]
fn is_zero(&self) -> bool {
(*self).is_null()
}
}

// `Option<&T>`, `Option<&mut T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
// For fat pointers, the bytes that would be the pointer metadata in the `Some` variant
// are padding in the `None` variant, so ignoring them and zero-initializing instead is ok.

unsafe impl<T: ?Sized> IsZero for Option<&T> {
#[inline]
fn is_zero(&self) -> bool {
self.is_none()
}
}

unsafe impl<T: ?Sized> IsZero for Option<&mut T> {
#[inline]
fn is_zero(&self) -> bool {
self.is_none()
}
}

unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
#[inline]
fn is_zero(&self) -> bool {
self.is_none()
}
}


////////////////////////////////////////////////////////////////////////////////
// Common trait implementations for Vec
Expand Down
10 changes: 6 additions & 4 deletions src/libcore/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,15 +368,17 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
/// make a difference in release builds (where a loop that has no side-effects
/// is easily detected and eliminated), but is often a big win for debug builds.
///
/// Note that `ptr::drop_in_place` already performs this check, so if your workload
/// can be reduced to some small number of drop_in_place calls, using this is
/// unnecessary. In particular note that you can drop_in_place a slice, and that
/// Note that [`drop_in_place`] already performs this check, so if your workload
/// can be reduced to some small number of [`drop_in_place`] calls, using this is
/// unnecessary. In particular note that you can [`drop_in_place`] a slice, and that
/// will do a single needs_drop check for all the values.
///
/// Types like Vec therefore just `drop_in_place(&mut self[..])` without using
/// needs_drop explicitly. Types like `HashMap`, on the other hand, have to drop
/// `needs_drop` explicitly. Types like [`HashMap`], on the other hand, have to drop
/// values one at a time and should use this API.
///
/// [`drop_in_place`]: ../ptr/fn.drop_in_place.html
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
///
/// # Examples
///
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
//! # Options and pointers ("nullable" pointers)
//!
//! Rust's pointer types must always point to a valid location; there are
//! no "null" pointers. Instead, Rust has *optional* pointers, like
//! no "null" references. Instead, Rust has *optional* pointers, like
//! the optional owned box, [`Option`]`<`[`Box<T>`]`>`.
//!
//! The following example uses [`Option`] to create an optional box of
Expand Down
129 changes: 115 additions & 14 deletions src/librustc_mir/dataflow/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,24 @@
//! [gk]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems
//! [#64566]: https://github.com/rust-lang/rust/pull/64566

use std::borrow::Borrow;
use std::cmp::Ordering;
use std::ops;
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::{fs, io, ops};

use rustc::hir::def_id::DefId;
use rustc::mir::{self, traversal, BasicBlock, Location};
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::work_queue::WorkQueue;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc_data_structures::work_queue::WorkQueue;
use syntax::symbol::sym;

use crate::dataflow::BottomValue;

mod graphviz;

/// A specific kind of dataflow analysis.
///
/// To run a dataflow analysis, one must set the initial state of the `START_BLOCK` via
Expand Down Expand Up @@ -62,6 +70,13 @@ pub trait Analysis<'tcx>: BottomValue {
/// and try to keep it short.
const NAME: &'static str;

/// How each element of your dataflow state will be displayed during debugging.
///
/// By default, this is the `fmt::Debug` representation of `Self::Idx`.
fn pretty_print_idx(&self, w: &mut impl io::Write, idx: Self::Idx) -> io::Result<()> {
write!(w, "{:?}", idx)
}

/// The size of each bitvector allocated for each block.
fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize;

Expand All @@ -77,7 +92,7 @@ pub trait Analysis<'tcx>: BottomValue {
location: Location,
);

/// Updates the current dataflow state with the effect of evaluating a statement.
/// Updates the current dataflow state with the effect of evaluating a terminator.
///
/// 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,
Expand Down Expand Up @@ -180,17 +195,20 @@ impl CursorPosition {
}
}

type ResultsRefCursor<'a, 'mir, 'tcx, A> =
ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>;

/// 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>
pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>>
where
A: Analysis<'tcx>,
{
body: &'mir mir::Body<'tcx>,
results: Results<'tcx, A>,
results: R,
state: BitSet<A::Idx>,

pos: CursorPosition,
Expand All @@ -202,24 +220,29 @@ where
is_call_return_effect_applied: bool,
}

impl<'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A>
impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
where
A: Analysis<'tcx>,
R: Borrow<Results<'tcx, A>>,
{
/// 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 {
pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
ResultsCursor {
body,
pos: CursorPosition::AtBlockStart(mir::START_BLOCK),
is_call_return_effect_applied: false,
state: results.entry_sets[mir::START_BLOCK].clone(),
state: results.borrow().entry_sets[mir::START_BLOCK].clone(),
results,
}
}

pub fn analysis(&self) -> &A {
&self.results.borrow().analysis
}

/// 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.state.overwrite(&self.results.borrow().entry_sets[block]);
self.pos = CursorPosition::AtBlockStart(block);
self.is_call_return_effect_applied = false;
}
Expand Down Expand Up @@ -275,7 +298,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(
self.results.borrow().analysis.apply_call_return_effect(
&mut self.state,
target.block,
func,
Expand Down Expand Up @@ -316,7 +339,7 @@ where
};

let block_data = &self.body.basic_blocks()[target_block];
self.results.analysis.apply_partial_block_effect(
self.results.borrow().analysis.apply_partial_block_effect(
&mut self.state,
target_block,
block_data,
Expand Down Expand Up @@ -349,7 +372,9 @@ where
{
analysis: A,
bits_per_block: usize,
tcx: TyCtxt<'tcx>,
body: &'a mir::Body<'tcx>,
def_id: DefId,
dead_unwinds: &'a BitSet<BasicBlock>,
entry_sets: IndexVec<BasicBlock, BitSet<A::Idx>>,
}
Expand All @@ -359,7 +384,9 @@ where
A: Analysis<'tcx>,
{
pub fn new(
tcx: TyCtxt<'tcx>,
body: &'a mir::Body<'tcx>,
def_id: DefId,
dead_unwinds: &'a BitSet<BasicBlock>,
analysis: A,
) -> Self {
Expand All @@ -377,7 +404,9 @@ where
Engine {
analysis,
bits_per_block,
tcx,
body,
def_id,
dead_unwinds,
entry_sets,
}
Expand Down Expand Up @@ -413,10 +442,26 @@ where
);
}

Results {
analysis: self.analysis,
entry_sets: self.entry_sets,
let Engine {
tcx,
body,
def_id,
analysis,
entry_sets,
..
} = self;

let results = Results { analysis, entry_sets };

let attrs = tcx.get_attrs(def_id);
if let Some(path) = get_dataflow_graphviz_output_path(tcx, attrs, A::NAME) {
let result = write_dataflow_graphviz_results(body, def_id, &path, &results);
if let Err(e) = result {
warn!("Failed to write dataflow results to {}: {}", path.display(), e);
}
}

results
}

fn propagate_bits_into_graph_successors_of(
Expand Down Expand Up @@ -510,3 +555,59 @@ where
}
}
}

/// Looks for attributes like `#[rustc_mir(borrowck_graphviz_postflow="./path/to/suffix.dot")]` and
/// extracts the path with the given analysis name prepended to the suffix.
///
/// Returns `None` if no such attribute exists.
fn get_dataflow_graphviz_output_path(
tcx: TyCtxt<'tcx>,
attrs: ty::Attributes<'tcx>,
analysis: &str,
) -> Option<PathBuf> {
let mut rustc_mir_attrs = attrs
.into_iter()
.filter(|attr| attr.check_name(sym::rustc_mir))
.flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));

let borrowck_graphviz_postflow = rustc_mir_attrs
.find(|attr| attr.check_name(sym::borrowck_graphviz_postflow))?;

let path_and_suffix = match borrowck_graphviz_postflow.value_str() {
Some(p) => p,
None => {
tcx.sess.span_err(
borrowck_graphviz_postflow.span(),
"borrowck_graphviz_postflow requires a path",
);

return None;
}
};

// Change "path/suffix.dot" to "path/analysis_name_suffix.dot"
let mut ret = PathBuf::from(path_and_suffix.to_string());
let suffix = ret.file_name().unwrap();

let mut file_name: OsString = analysis.into();
file_name.push("_");
file_name.push(suffix);
ret.set_file_name(file_name);

Some(ret)
}

fn write_dataflow_graphviz_results<A: Analysis<'tcx>>(
body: &mir::Body<'tcx>,
def_id: DefId,
path: &Path,
results: &Results<'tcx, A>
) -> io::Result<()> {
debug!("printing dataflow results for {:?} to {}", def_id, path.display());

let mut buf = Vec::new();
let graphviz = graphviz::Formatter::new(body, def_id, results);

dot::render(&graphviz, &mut buf)?;
fs::write(path, buf)
}
Loading