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:
commit
ef663a8a48
@ -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));
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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"]
|
||||
|
@ -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
|
@ -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
|
25
src/test/ui/const-generics/issue-74906.rs
Normal file
25
src/test/ui/const-generics/issue-74906.rs
Normal 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() { }
|
16
src/test/ui/type-alias-impl-trait/issue-74761.rs
Normal file
16
src/test/ui/type-alias-impl-trait/issue-74761.rs
Normal 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() {}
|
15
src/test/ui/type-alias-impl-trait/issue-74761.stderr
Normal file
15
src/test/ui/type-alias-impl-trait/issue-74761.stderr
Normal 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`.
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user