Skip to content

Commit 42ec683

Browse files
committed
Auto merge of rust-lang#64932 - tmandry:rollup-7t8x1nz, r=tmandry
Rollup of 9 pull requests Successful merges: - rust-lang#64377 (Add long error explanation for E0493) - rust-lang#64786 (Use https for curl when building for linux) - rust-lang#64828 (Graphviz debug output for generic dataflow analysis) - rust-lang#64838 (Add long error explanation for E0550) - rust-lang#64891 (Fix `vec![x; n]` with null raw fat pointer zeroing the pointer metadata) - rust-lang#64893 (Zero-initialize `vec![None; n]` for `Option<&T>`, `Option<&mut T>` and `Option<Box<T>>`) - rust-lang#64911 (Fixed a misleading documentation issue rust-lang#64844) - rust-lang#64921 (Add test for issue-64662) - rust-lang#64923 (Add missing links for mem::needs_drop) Failed merges: - rust-lang#64918 (Add long error explanation for E0551) r? @ghost
2 parents 22bc9e1 + 913c095 commit 42ec683

File tree

21 files changed

+719
-36
lines changed

21 files changed

+719
-36
lines changed

src/ci/docker/dist-x86_64-linux/build-curl.sh

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
set -ex
44
source shared.sh
55

6-
VERSION=7.51.0
6+
VERSION=7.66.0
77

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

1012
mkdir curl-build
1113
cd curl-build

src/liballoc/tests/vec.rs

+48
Original file line numberDiff line numberDiff line change
@@ -1281,3 +1281,51 @@ fn test_stable_push_pop() {
12811281
v.pop().unwrap();
12821282
assert_eq!(*v0, 13);
12831283
}
1284+
1285+
// https://github.com/rust-lang/rust/pull/49496 introduced specialization based on:
1286+
//
1287+
// ```
1288+
// unsafe impl<T: ?Sized> IsZero for *mut T {
1289+
// fn is_zero(&self) -> bool {
1290+
// (*self).is_null()
1291+
// }
1292+
// }
1293+
// ```
1294+
//
1295+
// … to call `RawVec::with_capacity_zeroed` for creating `Vec<*mut T>`,
1296+
// which is incorrect for fat pointers since `<*mut T>::is_null` only looks at the data component.
1297+
// That is, a fat pointer can be “null” without being made entirely of zero bits.
1298+
#[test]
1299+
fn vec_macro_repeating_null_raw_fat_pointer() {
1300+
let raw_dyn = &mut (|| ()) as &mut dyn Fn() as *mut dyn Fn();
1301+
let vtable = dbg!(ptr_metadata(raw_dyn));
1302+
let null_raw_dyn = ptr_from_raw_parts(std::ptr::null_mut(), vtable);
1303+
assert!(null_raw_dyn.is_null());
1304+
1305+
let vec = vec![null_raw_dyn; 1];
1306+
dbg!(ptr_metadata(vec[0]));
1307+
assert!(vec[0] == null_raw_dyn);
1308+
1309+
// Polyfill for https://github.com/rust-lang/rfcs/pull/2580
1310+
1311+
fn ptr_metadata(ptr: *mut dyn Fn()) -> *mut () {
1312+
unsafe {
1313+
std::mem::transmute::<*mut dyn Fn(), DynRepr>(ptr).vtable
1314+
}
1315+
}
1316+
1317+
fn ptr_from_raw_parts(data: *mut (), vtable: *mut()) -> *mut dyn Fn() {
1318+
unsafe {
1319+
std::mem::transmute::<DynRepr, *mut dyn Fn()>(DynRepr {
1320+
data,
1321+
vtable
1322+
})
1323+
}
1324+
}
1325+
1326+
#[repr(C)]
1327+
struct DynRepr {
1328+
data: *mut (),
1329+
vtable: *mut (),
1330+
}
1331+
}

src/liballoc/vec.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -1734,20 +1734,45 @@ impl_is_zero!(char, |x| x == '\0');
17341734
impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
17351735
impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
17361736

1737-
unsafe impl<T: ?Sized> IsZero for *const T {
1737+
unsafe impl<T> IsZero for *const T {
17381738
#[inline]
17391739
fn is_zero(&self) -> bool {
17401740
(*self).is_null()
17411741
}
17421742
}
17431743

1744-
unsafe impl<T: ?Sized> IsZero for *mut T {
1744+
unsafe impl<T> IsZero for *mut T {
17451745
#[inline]
17461746
fn is_zero(&self) -> bool {
17471747
(*self).is_null()
17481748
}
17491749
}
17501750

1751+
// `Option<&T>`, `Option<&mut T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
1752+
// For fat pointers, the bytes that would be the pointer metadata in the `Some` variant
1753+
// are padding in the `None` variant, so ignoring them and zero-initializing instead is ok.
1754+
1755+
unsafe impl<T: ?Sized> IsZero for Option<&T> {
1756+
#[inline]
1757+
fn is_zero(&self) -> bool {
1758+
self.is_none()
1759+
}
1760+
}
1761+
1762+
unsafe impl<T: ?Sized> IsZero for Option<&mut T> {
1763+
#[inline]
1764+
fn is_zero(&self) -> bool {
1765+
self.is_none()
1766+
}
1767+
}
1768+
1769+
unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
1770+
#[inline]
1771+
fn is_zero(&self) -> bool {
1772+
self.is_none()
1773+
}
1774+
}
1775+
17511776

17521777
////////////////////////////////////////////////////////////////////////////////
17531778
// Common trait implementations for Vec

src/libcore/mem/mod.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -368,15 +368,17 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
368368
/// make a difference in release builds (where a loop that has no side-effects
369369
/// is easily detected and eliminated), but is often a big win for debug builds.
370370
///
371-
/// Note that `ptr::drop_in_place` already performs this check, so if your workload
372-
/// can be reduced to some small number of drop_in_place calls, using this is
373-
/// unnecessary. In particular note that you can drop_in_place a slice, and that
371+
/// Note that [`drop_in_place`] already performs this check, so if your workload
372+
/// can be reduced to some small number of [`drop_in_place`] calls, using this is
373+
/// unnecessary. In particular note that you can [`drop_in_place`] a slice, and that
374374
/// will do a single needs_drop check for all the values.
375375
///
376376
/// Types like Vec therefore just `drop_in_place(&mut self[..])` without using
377-
/// needs_drop explicitly. Types like `HashMap`, on the other hand, have to drop
377+
/// `needs_drop` explicitly. Types like [`HashMap`], on the other hand, have to drop
378378
/// values one at a time and should use this API.
379379
///
380+
/// [`drop_in_place`]: ../ptr/fn.drop_in_place.html
381+
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
380382
///
381383
/// # Examples
382384
///

src/libcore/option.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
//! # Options and pointers ("nullable" pointers)
4747
//!
4848
//! Rust's pointer types must always point to a valid location; there are
49-
//! no "null" pointers. Instead, Rust has *optional* pointers, like
49+
//! no "null" references. Instead, Rust has *optional* pointers, like
5050
//! the optional owned box, [`Option`]`<`[`Box<T>`]`>`.
5151
//!
5252
//! The following example uses [`Option`] to create an optional box of

src/librustc_mir/dataflow/generic.rs

+115-14
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,24 @@
1616
//! [gk]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems
1717
//! [#64566]: https://github.com/rust-lang/rust/pull/64566
1818
19+
use std::borrow::Borrow;
1920
use std::cmp::Ordering;
20-
use std::ops;
21+
use std::ffi::OsString;
22+
use std::path::{Path, PathBuf};
23+
use std::{fs, io, ops};
2124

25+
use rustc::hir::def_id::DefId;
2226
use rustc::mir::{self, traversal, BasicBlock, Location};
27+
use rustc::ty::{self, TyCtxt};
28+
use rustc_data_structures::work_queue::WorkQueue;
2329
use rustc_index::bit_set::BitSet;
2430
use rustc_index::vec::{Idx, IndexVec};
25-
use rustc_data_structures::work_queue::WorkQueue;
31+
use syntax::symbol::sym;
2632

2733
use crate::dataflow::BottomValue;
2834

35+
mod graphviz;
36+
2937
/// A specific kind of dataflow analysis.
3038
///
3139
/// To run a dataflow analysis, one must set the initial state of the `START_BLOCK` via
@@ -62,6 +70,13 @@ pub trait Analysis<'tcx>: BottomValue {
6270
/// and try to keep it short.
6371
const NAME: &'static str;
6472

73+
/// How each element of your dataflow state will be displayed during debugging.
74+
///
75+
/// By default, this is the `fmt::Debug` representation of `Self::Idx`.
76+
fn pretty_print_idx(&self, w: &mut impl io::Write, idx: Self::Idx) -> io::Result<()> {
77+
write!(w, "{:?}", idx)
78+
}
79+
6580
/// The size of each bitvector allocated for each block.
6681
fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize;
6782

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

80-
/// Updates the current dataflow state with the effect of evaluating a statement.
95+
/// Updates the current dataflow state with the effect of evaluating a terminator.
8196
///
8297
/// Note that the effect of a successful return from a `Call` terminator should **not** be
8398
/// acounted for in this function. That should go in `apply_call_return_effect`. For example,
@@ -180,17 +195,20 @@ impl CursorPosition {
180195
}
181196
}
182197

198+
type ResultsRefCursor<'a, 'mir, 'tcx, A> =
199+
ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>;
200+
183201
/// Inspect the results of dataflow analysis.
184202
///
185203
/// This cursor has linear performance when visiting statements in a block in order. Visiting
186204
/// statements within a block in reverse order is `O(n^2)`, where `n` is the number of statements
187205
/// in that block.
188-
pub struct ResultsCursor<'mir, 'tcx, A>
206+
pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>>
189207
where
190208
A: Analysis<'tcx>,
191209
{
192210
body: &'mir mir::Body<'tcx>,
193-
results: Results<'tcx, A>,
211+
results: R,
194212
state: BitSet<A::Idx>,
195213

196214
pos: CursorPosition,
@@ -202,24 +220,29 @@ where
202220
is_call_return_effect_applied: bool,
203221
}
204222

205-
impl<'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A>
223+
impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
206224
where
207225
A: Analysis<'tcx>,
226+
R: Borrow<Results<'tcx, A>>,
208227
{
209228
/// Returns a new cursor for `results` that points to the start of the `START_BLOCK`.
210-
pub fn new(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self {
229+
pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
211230
ResultsCursor {
212231
body,
213232
pos: CursorPosition::AtBlockStart(mir::START_BLOCK),
214233
is_call_return_effect_applied: false,
215-
state: results.entry_sets[mir::START_BLOCK].clone(),
234+
state: results.borrow().entry_sets[mir::START_BLOCK].clone(),
216235
results,
217236
}
218237
}
219238

239+
pub fn analysis(&self) -> &A {
240+
&self.results.borrow().analysis
241+
}
242+
220243
/// Resets the cursor to the start of the given `block`.
221244
pub fn seek_to_block_start(&mut self, block: BasicBlock) {
222-
self.state.overwrite(&self.results.entry_sets[block]);
245+
self.state.overwrite(&self.results.borrow().entry_sets[block]);
223246
self.pos = CursorPosition::AtBlockStart(block);
224247
self.is_call_return_effect_applied = false;
225248
}
@@ -275,7 +298,7 @@ where
275298
} = &term.kind {
276299
if !self.is_call_return_effect_applied {
277300
self.is_call_return_effect_applied = true;
278-
self.results.analysis.apply_call_return_effect(
301+
self.results.borrow().analysis.apply_call_return_effect(
279302
&mut self.state,
280303
target.block,
281304
func,
@@ -316,7 +339,7 @@ where
316339
};
317340

318341
let block_data = &self.body.basic_blocks()[target_block];
319-
self.results.analysis.apply_partial_block_effect(
342+
self.results.borrow().analysis.apply_partial_block_effect(
320343
&mut self.state,
321344
target_block,
322345
block_data,
@@ -349,7 +372,9 @@ where
349372
{
350373
analysis: A,
351374
bits_per_block: usize,
375+
tcx: TyCtxt<'tcx>,
352376
body: &'a mir::Body<'tcx>,
377+
def_id: DefId,
353378
dead_unwinds: &'a BitSet<BasicBlock>,
354379
entry_sets: IndexVec<BasicBlock, BitSet<A::Idx>>,
355380
}
@@ -359,7 +384,9 @@ where
359384
A: Analysis<'tcx>,
360385
{
361386
pub fn new(
387+
tcx: TyCtxt<'tcx>,
362388
body: &'a mir::Body<'tcx>,
389+
def_id: DefId,
363390
dead_unwinds: &'a BitSet<BasicBlock>,
364391
analysis: A,
365392
) -> Self {
@@ -377,7 +404,9 @@ where
377404
Engine {
378405
analysis,
379406
bits_per_block,
407+
tcx,
380408
body,
409+
def_id,
381410
dead_unwinds,
382411
entry_sets,
383412
}
@@ -413,10 +442,26 @@ where
413442
);
414443
}
415444

416-
Results {
417-
analysis: self.analysis,
418-
entry_sets: self.entry_sets,
445+
let Engine {
446+
tcx,
447+
body,
448+
def_id,
449+
analysis,
450+
entry_sets,
451+
..
452+
} = self;
453+
454+
let results = Results { analysis, entry_sets };
455+
456+
let attrs = tcx.get_attrs(def_id);
457+
if let Some(path) = get_dataflow_graphviz_output_path(tcx, attrs, A::NAME) {
458+
let result = write_dataflow_graphviz_results(body, def_id, &path, &results);
459+
if let Err(e) = result {
460+
warn!("Failed to write dataflow results to {}: {}", path.display(), e);
461+
}
419462
}
463+
464+
results
420465
}
421466

422467
fn propagate_bits_into_graph_successors_of(
@@ -510,3 +555,59 @@ where
510555
}
511556
}
512557
}
558+
559+
/// Looks for attributes like `#[rustc_mir(borrowck_graphviz_postflow="./path/to/suffix.dot")]` and
560+
/// extracts the path with the given analysis name prepended to the suffix.
561+
///
562+
/// Returns `None` if no such attribute exists.
563+
fn get_dataflow_graphviz_output_path(
564+
tcx: TyCtxt<'tcx>,
565+
attrs: ty::Attributes<'tcx>,
566+
analysis: &str,
567+
) -> Option<PathBuf> {
568+
let mut rustc_mir_attrs = attrs
569+
.into_iter()
570+
.filter(|attr| attr.check_name(sym::rustc_mir))
571+
.flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
572+
573+
let borrowck_graphviz_postflow = rustc_mir_attrs
574+
.find(|attr| attr.check_name(sym::borrowck_graphviz_postflow))?;
575+
576+
let path_and_suffix = match borrowck_graphviz_postflow.value_str() {
577+
Some(p) => p,
578+
None => {
579+
tcx.sess.span_err(
580+
borrowck_graphviz_postflow.span(),
581+
"borrowck_graphviz_postflow requires a path",
582+
);
583+
584+
return None;
585+
}
586+
};
587+
588+
// Change "path/suffix.dot" to "path/analysis_name_suffix.dot"
589+
let mut ret = PathBuf::from(path_and_suffix.to_string());
590+
let suffix = ret.file_name().unwrap();
591+
592+
let mut file_name: OsString = analysis.into();
593+
file_name.push("_");
594+
file_name.push(suffix);
595+
ret.set_file_name(file_name);
596+
597+
Some(ret)
598+
}
599+
600+
fn write_dataflow_graphviz_results<A: Analysis<'tcx>>(
601+
body: &mir::Body<'tcx>,
602+
def_id: DefId,
603+
path: &Path,
604+
results: &Results<'tcx, A>
605+
) -> io::Result<()> {
606+
debug!("printing dataflow results for {:?} to {}", def_id, path.display());
607+
608+
let mut buf = Vec::new();
609+
let graphviz = graphviz::Formatter::new(body, def_id, results);
610+
611+
dot::render(&graphviz, &mut buf)?;
612+
fs::write(path, buf)
613+
}

0 commit comments

Comments
 (0)