Auto merge of #77372 - jonas-schievink:rollup-e5bdzga, r=jonas-schievink

Rollup of 12 pull requests

Successful merges:

 - #77037 (more tiny clippy cleanups)
 - #77233 (BTreeMap: keep an eye out on the size of the main components)
 - #77280 (Ensure that all LLVM components requested by tests are available on CI)
 - #77284 (library: Forward compiler-builtins "mem" feature)
 - #77296 (liveness: Use Option::None to represent absent live nodes)
 - #77322 (Add unstable book docs for `-Zunsound-mir-opts`)
 - #77328 (Use `rtassert!` instead of `assert!` from the child process after fork() in std::sys::unix::process::Command::spawn())
 - #77331 (Add test for async/await combined with const-generics.)
 - #77338 (Fix typo in alloc vec comment)
 - #77340 (Alloc vec use imported path)
 - #77345 (Add test for issue #74761)
 - #77348 (Update books)

Failed merges:

r? `@ghost`
This commit is contained in:
bors 2020-09-30 20:49:27 +00:00
commit ef663a8a48
17 changed files with 127 additions and 54 deletions

View File

@ -62,8 +62,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
// `self.constraints`, but we also want to be mutating
// `self.member_constraints`. For now, just swap out the value
// we want and replace at the end.
let mut tmp =
std::mem::replace(&mut self.constraints.member_constraints, Default::default());
let mut tmp = std::mem::take(&mut self.constraints.member_constraints);
for member_constraint in member_constraints {
tmp.push_constraint(member_constraint, |r| self.to_region_vid(r));
}

View File

@ -91,7 +91,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
let not_equal_rvalue = Rvalue::BinaryOp(
not_equal,
Operand::Copy(Place::from(second_discriminant_temp)),
Operand::Copy(Place::from(first_descriminant_place)),
Operand::Copy(first_descriminant_place),
);
patch.add_statement(
end_of_block_location,

View File

@ -62,13 +62,13 @@
//! - `reader`: the `LiveNode` ID of some node which will read the value
//! that `V` holds on entry to `N`. Formally: a node `M` such
//! that there exists a path `P` from `N` to `M` where `P` does not
//! write `V`. If the `reader` is `INVALID_NODE`, then the current
//! write `V`. If the `reader` is `None`, then the current
//! value will never be read (the variable is dead, essentially).
//!
//! - `writer`: the `LiveNode` ID of some node which will write the
//! variable `V` and which is reachable from `N`. Formally: a node `M`
//! such that there exists a path `P` from `N` to `M` and `M` writes
//! `V`. If the `writer` is `INVALID_NODE`, then there is no writer
//! `V`. If the `writer` is `None`, then there is no writer
//! of `V` that follows `N`.
//!
//! - `used`: a boolean value indicating whether `V` is *used*. We
@ -114,7 +114,6 @@ rustc_index::newtype_index! {
rustc_index::newtype_index! {
pub struct LiveNode {
DEBUG_FORMAT = "ln({})",
const INVALID_NODE = LiveNode::MAX_AS_U32,
}
}
@ -168,12 +167,6 @@ pub fn provide(providers: &mut Providers) {
// variable must not be assigned if there is some successor
// assignment. And so forth.
impl LiveNode {
fn is_valid(self) -> bool {
self != INVALID_NODE
}
}
struct CaptureInfo {
ln: LiveNode,
var_hid: HirId,
@ -467,8 +460,8 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
#[derive(Clone, Copy)]
struct RWU {
reader: LiveNode,
writer: LiveNode,
reader: Option<LiveNode>,
writer: Option<LiveNode>,
used: bool,
}
@ -490,10 +483,10 @@ struct RWUTable {
unpacked_rwus: Vec<RWU>,
}
// A constant representing `RWU { reader: INVALID_NODE; writer: INVALID_NODE; used: false }`.
// A constant representing `RWU { reader: None; writer: None; used: false }`.
const INV_INV_FALSE: u32 = u32::MAX;
// A constant representing `RWU { reader: INVALID_NODE; writer: INVALID_NODE; used: true }`.
// A constant representing `RWU { reader: None; writer: None; used: true }`.
const INV_INV_TRUE: u32 = u32::MAX - 1;
impl RWUTable {
@ -504,24 +497,24 @@ impl RWUTable {
fn get(&self, idx: usize) -> RWU {
let packed_rwu = self.packed_rwus[idx];
match packed_rwu {
INV_INV_FALSE => RWU { reader: INVALID_NODE, writer: INVALID_NODE, used: false },
INV_INV_TRUE => RWU { reader: INVALID_NODE, writer: INVALID_NODE, used: true },
INV_INV_FALSE => RWU { reader: None, writer: None, used: false },
INV_INV_TRUE => RWU { reader: None, writer: None, used: true },
_ => self.unpacked_rwus[packed_rwu as usize],
}
}
fn get_reader(&self, idx: usize) -> LiveNode {
fn get_reader(&self, idx: usize) -> Option<LiveNode> {
let packed_rwu = self.packed_rwus[idx];
match packed_rwu {
INV_INV_FALSE | INV_INV_TRUE => INVALID_NODE,
INV_INV_FALSE | INV_INV_TRUE => None,
_ => self.unpacked_rwus[packed_rwu as usize].reader,
}
}
fn get_writer(&self, idx: usize) -> LiveNode {
fn get_writer(&self, idx: usize) -> Option<LiveNode> {
let packed_rwu = self.packed_rwus[idx];
match packed_rwu {
INV_INV_FALSE | INV_INV_TRUE => INVALID_NODE,
INV_INV_FALSE | INV_INV_TRUE => None,
_ => self.unpacked_rwus[packed_rwu as usize].writer,
}
}
@ -541,7 +534,7 @@ impl RWUTable {
}
fn assign_unpacked(&mut self, idx: usize, rwu: RWU) {
if rwu.reader == INVALID_NODE && rwu.writer == INVALID_NODE {
if rwu.reader == None && rwu.writer == None {
// When we overwrite an indexing entry in `self.packed_rwus` with
// `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry
// from `self.unpacked_rwus`; it's not worth the effort, and we
@ -570,7 +563,7 @@ struct Liveness<'a, 'tcx> {
typeck_results: &'a ty::TypeckResults<'tcx>,
param_env: ty::ParamEnv<'tcx>,
upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
successors: IndexVec<LiveNode, LiveNode>,
successors: IndexVec<LiveNode, Option<LiveNode>>,
rwu_table: RWUTable,
/// A live node representing a point of execution before closure entry &
@ -606,7 +599,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
typeck_results,
param_env,
upvars,
successors: IndexVec::from_elem_n(INVALID_NODE, num_live_nodes),
successors: IndexVec::from_elem_n(None, num_live_nodes),
rwu_table: RWUTable::new(num_live_nodes * num_vars),
closure_ln,
exit_ln,
@ -651,30 +644,33 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}
fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
assert!(ln.is_valid());
let reader = self.rwu_table.get_reader(self.idx(ln, var));
if reader.is_valid() { Some(self.ir.lnks[reader]) } else { None }
if let Some(reader) = self.rwu_table.get_reader(self.idx(ln, var)) {
Some(self.ir.lnks[reader])
} else {
None
}
}
// Is this variable live on entry to any of its successor nodes?
fn live_on_exit(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
let successor = self.successors[ln];
let successor = self.successors[ln].unwrap();
self.live_on_entry(successor, var)
}
fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool {
assert!(ln.is_valid());
self.rwu_table.get_used(self.idx(ln, var))
}
fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
assert!(ln.is_valid());
let writer = self.rwu_table.get_writer(self.idx(ln, var));
if writer.is_valid() { Some(self.ir.lnks[writer]) } else { None }
if let Some(writer) = self.rwu_table.get_writer(self.idx(ln, var)) {
Some(self.ir.lnks[writer])
} else {
None
}
}
fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
let successor = self.successors[ln];
let successor = self.successors[ln].unwrap();
self.assigned_on_entry(successor, var)
}
@ -709,9 +705,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
{
let wr = &mut wr as &mut dyn Write;
write!(wr, "[{:?} of kind {:?} reads", ln, self.ir.lnks[ln]);
self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_valid());
self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_some());
write!(wr, " writes");
self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_valid());
self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_some());
write!(wr, " uses");
self.write_vars(wr, ln, |idx| self.rwu_table.get_used(idx));
@ -735,7 +731,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}
fn init_empty(&mut self, ln: LiveNode, succ_ln: LiveNode) {
self.successors[ln] = succ_ln;
self.successors[ln] = Some(succ_ln);
// It is not necessary to initialize the RWUs here because they are all
// set to INV_INV_FALSE when they are created, and the sets only grow
@ -744,7 +740,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
fn init_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) {
// more efficient version of init_empty() / merge_from_succ()
self.successors[ln] = succ_ln;
self.successors[ln] = Some(succ_ln);
self.indices2(ln, succ_ln, |this, idx, succ_idx| {
this.rwu_table.copy_packed(idx, succ_idx);
@ -768,12 +764,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
let mut changed = false;
let mut rwu = this.rwu_table.get(idx);
let succ_rwu = this.rwu_table.get(succ_idx);
if succ_rwu.reader.is_valid() && !rwu.reader.is_valid() {
if succ_rwu.reader.is_some() && rwu.reader.is_none() {
rwu.reader = succ_rwu.reader;
changed = true
}
if succ_rwu.writer.is_valid() && !rwu.writer.is_valid() {
if succ_rwu.writer.is_some() && rwu.writer.is_none() {
rwu.writer = succ_rwu.writer;
changed = true
}
@ -817,14 +813,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
let mut rwu = self.rwu_table.get(idx);
if (acc & ACC_WRITE) != 0 {
rwu.reader = INVALID_NODE;
rwu.writer = ln;
rwu.reader = None;
rwu.writer = Some(ln);
}
// Important: if we both read/write, must do read second
// or else the write will override.
if (acc & ACC_READ) != 0 {
rwu.reader = ln;
rwu.reader = Some(ln);
}
if (acc & ACC_USE) != 0 {

View File

@ -70,10 +70,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
wbcx.typeck_results.used_trait_imports = used_trait_imports;
wbcx.typeck_results.closure_captures = mem::replace(
&mut self.typeck_results.borrow_mut().closure_captures,
Default::default(),
);
wbcx.typeck_results.closure_captures =
mem::take(&mut self.typeck_results.borrow_mut().closure_captures);
if self.is_tainted_by_errors() {
// FIXME(eddyb) keep track of `ErrorReported` from where the error was emitted.

View File

@ -23,3 +23,12 @@ fn test_splitpoint() {
assert!(left_len + right_len == CAPACITY);
}
}
#[test]
#[cfg(target_arch = "x86_64")]
fn test_sizes() {
assert_eq!(core::mem::size_of::<LeafNode<(), ()>>(), 16);
assert_eq!(core::mem::size_of::<LeafNode<i64, i64>>(), 16 + CAPACITY * 8 * 2);
assert_eq!(core::mem::size_of::<InternalNode<(), ()>>(), 112);
assert_eq!(core::mem::size_of::<InternalNode<i64, i64>>(), 112 + CAPACITY * 8 * 2);
}

View File

@ -2281,14 +2281,14 @@ where
// use try-fold since
// - it vectorizes better for some iterator adapters
// - unlike most internal iteration methods methods it only takes a &mut self
// - unlike most internal iteration methods, it only takes a &mut self
// - it lets us thread the write pointer through its innards and get it back in the end
let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
let sink = iterator
.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end))
.unwrap();
// iteration succeeded, don't drop head
let dst = mem::ManuallyDrop::new(sink).dst;
let dst = ManuallyDrop::new(sink).dst;
let src = unsafe { iterator.as_inner().as_into_iter() };
// check if SourceIter contract was upheld

View File

@ -59,6 +59,7 @@ gimli-symbolize = []
panic-unwind = ["panic_unwind"]
profiler = ["profiler_builtins"]
compiler-builtins-c = ["alloc/compiler-builtins-c"]
compiler-builtins-mem = ["alloc/compiler-builtins-mem"]
llvm-libunwind = ["unwind/llvm-libunwind"]
# Make panics and failed asserts immediately abort without formatting any message

View File

@ -67,7 +67,7 @@ impl Command {
// pipe I/O up to PIPE_BUF bytes should be atomic, and then
// we want to be sure we *don't* run at_exit destructors as
// we're being torn down regardless
assert!(output.write(&bytes).is_ok());
rtassert!(output.write(&bytes).is_ok());
libc::_exit(1)
}
n => n,

View File

@ -25,6 +25,7 @@ proc_macro = { path = "../proc_macro" }
default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"]
backtrace = ["std/backtrace"]
compiler-builtins-c = ["std/compiler-builtins-c"]
compiler-builtins-mem = ["std/compiler-builtins-mem"]
llvm-libunwind = ["std/llvm-libunwind"]
panic-unwind = ["std/panic_unwind"]
panic_immediate_abort = ["std/panic_immediate_abort"]

View File

@ -104,6 +104,8 @@ if [ "$RUST_RELEASE_CHANNEL" = "nightly" ] || [ "$DIST_REQUIRE_ALL_TOOLS" = "" ]
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-missing-tools"
fi
export COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS=1
# Print the date from the local machine and the date from an external source to
# check for clock drifts. An HTTP URL is used instead of HTTPS since on Azure
# Pipelines it happened that the certificates were marked as expired.

@ -1 +1 @@
Subproject commit 0cd2ca116274b915924c3a7e07c1e046b6f19b77
Subproject commit dd310616308e01f6cf227f46347b744aa56b77d9

@ -1 +1 @@
Subproject commit 19f0a0372af497b34369cf182d9d16156cab2969
Subproject commit 7d3ff1c12db08a847a57a054be4a7951ce532d2d

View File

@ -0,0 +1,8 @@
# `unsound-mir-opts`
--------------------
The `-Zunsound-mir-opts` compiler flag enables [MIR optimization passes] which can cause unsound behavior.
This flag should only be used by MIR optimization tests in the rustc test suite.
[MIR optimization passes]: https://rustc-dev-guide.rust-lang.org/mir/optimizations.html

View File

@ -0,0 +1,25 @@
// edition:2018
// check-pass
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(min, feature(min_const_generics))]
const SIZE: usize = 16;
struct Bar<const H: usize> {}
struct Foo<const H: usize> {}
impl<const H: usize> Foo<H> {
async fn biz(_: &[[u8; SIZE]]) -> Vec<()> {
vec![]
}
pub async fn baz(&self) -> Bar<H> {
Self::biz(&vec![]).await;
Bar {}
}
}
fn main() { }

View File

@ -0,0 +1,16 @@
#![feature(member_constraints)]
#![feature(type_alias_impl_trait)]
pub trait A {
type B;
fn f(&self) -> Self::B;
}
impl<'a, 'b> A for () {
//~^ ERROR the lifetime parameter `'a` is not constrained
//~| ERROR the lifetime parameter `'b` is not constrained
type B = impl core::fmt::Debug;
fn f(&self) -> Self::B {}
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> $DIR/issue-74761.rs:8:6
|
LL | impl<'a, 'b> A for () {
| ^^ unconstrained lifetime parameter
error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates
--> $DIR/issue-74761.rs:8:10
|
LL | impl<'a, 'b> A for () {
| ^^ unconstrained lifetime parameter
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0207`.

View File

@ -208,10 +208,13 @@ impl EarlyProps {
config.parse_name_value_directive(line, "needs-llvm-components")
{
let components: HashSet<_> = config.llvm_components.split_whitespace().collect();
if !needed_components
if let Some(missing_component) = needed_components
.split_whitespace()
.all(|needed_component| components.contains(needed_component))
.find(|needed_component| !components.contains(needed_component))
{
if env::var_os("COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS").is_some() {
panic!("missing LLVM component: {}", missing_component);
}
return true;
}
}