Skip to content

Commit 10f12fe

Browse files
committed
Auto merge of #65661 - JohnTitor:rollup-68la1fq, r=JohnTitor
Rollup of 5 pull requests Successful merges: - #65544 (Added doc on keyword break) - #65620 (Correctly note code as Ok not error for E0573) - #65624 ([mir-opt] Improve SimplifyLocals pass so it can remove unused consts) - #65650 (use unwrap_or in lint code) - #65652 (Fix `canonicalize_const_var` leaking inference variables) Failed merges: r? @ghost
2 parents b7a9c28 + 1c94a44 commit 10f12fe

18 files changed

+298
-57
lines changed

src/librustc/infer/canonical/canonicalizer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
701701
self.tcx().mk_const(
702702
ty::Const {
703703
val: ConstValue::Infer(InferConst::Canonical(self.binder_index, var.into())),
704-
ty: const_var.ty,
704+
ty: self.fold_ty(const_var.ty),
705705
}
706706
)
707707
}

src/librustc/lint/levels.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,7 @@ impl<'a> LintLevelsBuilder<'a> {
202202
let meta = unwrap_or!(attr.meta(), continue);
203203
attr::mark_used(attr);
204204

205-
let mut metas = if let Some(metas) = meta.meta_item_list() {
206-
metas
207-
} else {
208-
continue;
209-
};
205+
let mut metas = unwrap_or!(meta.meta_item_list(), continue);
210206

211207
if metas.is_empty() {
212208
// FIXME (#55112): issue unused-attributes lint for `#[level()]`

src/librustc_mir/transform/const_prop.rs

+9-17
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
431431
place_layout: TyLayout<'tcx>,
432432
source_info: SourceInfo,
433433
place: &Place<'tcx>,
434-
) -> Option<Const<'tcx>> {
434+
) -> Option<()> {
435435
let span = source_info.span;
436436

437437
let overflow_check = self.tcx.sess.overflow_checks();
@@ -540,20 +540,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
540540
}
541541
}
542542

543-
// Work around: avoid extra unnecessary locals. FIXME(wesleywiser)
544-
// Const eval will turn this into a `const Scalar(<ZST>)` that
545-
// `SimplifyLocals` doesn't know it can remove.
546-
Rvalue::Aggregate(_, operands) if operands.len() == 0 => {
547-
return None;
548-
}
549-
550543
_ => { }
551544
}
552545

553546
self.use_ecx(source_info, |this| {
554547
trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place);
555548
this.ecx.eval_rvalue_into_place(rvalue, place)?;
556-
this.ecx.eval_place_to_op(place, Some(place_layout))
549+
Ok(())
557550
})
558551
}
559552

@@ -717,24 +710,23 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
717710
base: PlaceBase::Local(local),
718711
projection: box [],
719712
} = *place {
720-
if let Some(value) = self.const_prop(rval,
721-
place_layout,
722-
statement.source_info,
723-
place) {
724-
trace!("checking whether {:?} can be stored to {:?}", value, local);
713+
let source = statement.source_info;
714+
if let Some(()) = self.const_prop(rval, place_layout, source, place) {
725715
if self.can_const_prop[local] {
726-
trace!("stored {:?} to {:?}", value, local);
727-
assert_eq!(self.get_const(local), Some(value));
716+
trace!("propagated into {:?}", local);
728717

729718
if self.should_const_prop() {
719+
let value =
720+
self.get_const(local).expect("local was dead/uninitialized");
721+
trace!("replacing {:?} with {:?}", rval, value);
730722
self.replace_with_const(
731723
rval,
732724
value,
733725
statement.source_info,
734726
);
735727
}
736728
} else {
737-
trace!("can't propagate {:?} to {:?}", value, local);
729+
trace!("can't propagate into {:?}", local);
738730
self.remove_const(local);
739731
}
740732
}

src/librustc_mir/transform/simplify.rs

+54-22
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use rustc_index::bit_set::BitSet;
3131
use rustc_index::vec::{Idx, IndexVec};
3232
use rustc::ty::TyCtxt;
3333
use rustc::mir::*;
34-
use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext};
34+
use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext, MutatingUseContext};
3535
use rustc::session::config::DebugInfo;
3636
use std::borrow::Cow;
3737
use crate::transform::{MirPass, MirSource};
@@ -293,23 +293,31 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
293293
pub struct SimplifyLocals;
294294

295295
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
296-
fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
297-
let mut marker = DeclMarker { locals: BitSet::new_empty(body.local_decls.len()) };
298-
marker.visit_body(body);
299-
// Return pointer and arguments are always live
300-
marker.locals.insert(RETURN_PLACE);
301-
for arg in body.args_iter() {
302-
marker.locals.insert(arg);
303-
}
296+
fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
297+
trace!("running SimplifyLocals on {:?}", source);
298+
let locals = {
299+
let mut marker = DeclMarker {
300+
locals: BitSet::new_empty(body.local_decls.len()),
301+
body,
302+
};
303+
marker.visit_body(body);
304+
// Return pointer and arguments are always live
305+
marker.locals.insert(RETURN_PLACE);
306+
for arg in body.args_iter() {
307+
marker.locals.insert(arg);
308+
}
304309

305-
// We may need to keep dead user variables live for debuginfo.
306-
if tcx.sess.opts.debuginfo == DebugInfo::Full {
307-
for local in body.vars_iter() {
308-
marker.locals.insert(local);
310+
// We may need to keep dead user variables live for debuginfo.
311+
if tcx.sess.opts.debuginfo == DebugInfo::Full {
312+
for local in body.vars_iter() {
313+
marker.locals.insert(local);
314+
}
309315
}
310-
}
311316

312-
let map = make_local_map(&mut body.local_decls, marker.locals);
317+
marker.locals
318+
};
319+
320+
let map = make_local_map(&mut body.local_decls, locals);
313321
// Update references to all vars and tmps now
314322
LocalUpdater { map }.visit_body(body);
315323
body.local_decls.shrink_to_fit();
@@ -334,18 +342,35 @@ fn make_local_map<V>(
334342
map
335343
}
336344

337-
struct DeclMarker {
345+
struct DeclMarker<'a, 'tcx> {
338346
pub locals: BitSet<Local>,
347+
pub body: &'a Body<'tcx>,
339348
}
340349

341-
impl<'tcx> Visitor<'tcx> for DeclMarker {
342-
fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) {
350+
impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> {
351+
fn visit_local(&mut self, local: &Local, ctx: PlaceContext, location: Location) {
343352
// Ignore storage markers altogether, they get removed along with their otherwise unused
344353
// decls.
345354
// FIXME: Extend this to all non-uses.
346-
if !ctx.is_storage_marker() {
347-
self.locals.insert(*local);
355+
if ctx.is_storage_marker() {
356+
return;
348357
}
358+
359+
// Ignore stores of constants because `ConstProp` and `CopyProp` can remove uses of many
360+
// of these locals. However, if the local is still needed, then it will be referenced in
361+
// another place and we'll mark it as being used there.
362+
if ctx == PlaceContext::MutatingUse(MutatingUseContext::Store) {
363+
let stmt =
364+
&self.body.basic_blocks()[location.block].statements[location.statement_index];
365+
if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(c)))) = &stmt.kind {
366+
if p.as_local().is_some() {
367+
trace!("skipping store of const value {:?} to {:?}", c, local);
368+
return;
369+
}
370+
}
371+
}
372+
373+
self.locals.insert(*local);
349374
}
350375
}
351376

@@ -357,9 +382,16 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
357382
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
358383
// Remove unnecessary StorageLive and StorageDead annotations.
359384
data.statements.retain(|stmt| {
360-
match stmt.kind {
385+
match &stmt.kind {
361386
StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => {
362-
self.map[l].is_some()
387+
self.map[*l].is_some()
388+
}
389+
StatementKind::Assign(box (place, _)) => {
390+
if let Some(local) = place.as_local() {
391+
self.map[local].is_some()
392+
} else {
393+
true
394+
}
363395
}
364396
_ => true
365397
}

src/librustc_resolve/error_codes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1682,7 +1682,7 @@ enum Wizard {
16821682
}
16831683
16841684
trait Isengard {
1685-
fn wizard(w: Wizard) { // error!
1685+
fn wizard(w: Wizard) { // ok!
16861686
match w {
16871687
Wizard::Saruman => {
16881688
// do something

src/libstd/keyword_docs.rs

+65-2
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,72 @@ mod as_keyword { }
3333
//
3434
/// Exit early from a loop.
3535
///
36-
/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
36+
/// When `break` is encountered, execution of the associated loop body is
37+
/// immediately terminated.
38+
///
39+
/// ```rust
40+
/// let mut last = 0;
41+
///
42+
/// for x in 1..100 {
43+
/// if x > 12 {
44+
/// break;
45+
/// }
46+
/// last = x;
47+
/// }
48+
///
49+
/// assert_eq!(last, 12);
50+
/// println!("{}", last);
51+
/// ```
52+
///
53+
/// A break expression is normally associated with the innermost loop enclosing the
54+
/// `break` but a label can be used to specify which enclosing loop is affected.
55+
///
56+
///```rust
57+
/// 'outer: for i in 1..=5 {
58+
/// println!("outer iteration (i): {}", i);
59+
///
60+
/// 'inner: for j in 1..=200 {
61+
/// println!(" inner iteration (j): {}", j);
62+
/// if j >= 3 {
63+
/// // breaks from inner loop, let's outer loop continue.
64+
/// break;
65+
/// }
66+
/// if i >= 2 {
67+
/// // breaks from outer loop, and directly to "Bye".
68+
/// break 'outer;
69+
/// }
70+
/// }
71+
/// }
72+
/// println!("Bye.");
73+
///```
74+
///
75+
/// When associated with `loop`, a break expression may be used to return a value from that loop.
76+
/// This is only valid with `loop` and not with any other type of loop.
77+
/// If no value is specified, `break;` returns `()`.
78+
/// Every `break` within a loop must return the same type.
79+
///
80+
/// ```rust
81+
/// let (mut a, mut b) = (1, 1);
82+
/// let result = loop {
83+
/// if b > 10 {
84+
/// break b;
85+
/// }
86+
/// let c = a + b;
87+
/// a = b;
88+
/// b = c;
89+
/// };
90+
/// // first number in Fibonacci sequence over 10:
91+
/// assert_eq!(result, 13);
92+
/// println!("{}", result);
93+
/// ```
94+
///
95+
/// For more details consult the [Reference on "break expression"] and the [Reference on "break and
96+
/// loop values"].
97+
///
98+
/// [Reference on "break expression"]: ../reference/expressions/loop-expr.html#break-expressions
99+
/// [Reference on "break and loop values"]:
100+
/// ../reference/expressions/loop-expr.html#break-and-loop-values
37101
///
38-
/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
39102
mod break_keyword { }
40103

41104
#[doc(keyword = "const")]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// revisions:rpass1
2+
3+
#![feature(const_generics)]
4+
5+
struct Struct<T>(T);
6+
7+
impl<T, const N: usize> Struct<[T; N]> {
8+
fn f() {}
9+
fn g() { Self::f(); }
10+
}
11+
12+
fn main() {
13+
Struct::<[u32; 3]>::g();
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// revisions:rpass1
2+
3+
#![feature(const_generics)]
4+
5+
struct FakeArray<T, const N: usize>(T);
6+
7+
impl<T, const N: usize> FakeArray<T, { N }> {
8+
fn len(&self) -> usize {
9+
N
10+
}
11+
}
12+
13+
fn main() {
14+
let fa = FakeArray::<u32, { 32 }>(1);
15+
assert_eq!(fa.len(), 32);
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// revisions:cfail1
2+
#![feature(const_generics)]
3+
//[cfail1]~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
4+
5+
struct S<T, const N: usize>([T; N]);
6+
7+
fn f<T, const N: usize>(x: T) -> S<T, {N}> { panic!() }
8+
9+
fn main() {
10+
f(0u8);
11+
//[cfail1]~^ ERROR type annotations needed
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// revisions:cfail1
2+
#![feature(const_generics)]
3+
//[cfail1]~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
4+
5+
fn combinator<T, const S: usize>() -> [T; S] {}
6+
//[cfail1]~^ ERROR mismatched types
7+
8+
fn main() {
9+
combinator().into_iter();
10+
//[cfail1]~^ ERROR type annotations needed
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// revisions:rpass1
2+
#![feature(const_generics)]
3+
4+
pub struct Foo<T, const N: usize>([T; 0]);
5+
6+
impl<T, const N: usize> Foo<T, {N}> {
7+
pub fn new() -> Self {
8+
Foo([])
9+
}
10+
}
11+
12+
fn main() {
13+
let _: Foo<u32, 0> = Foo::new();
14+
}

src/test/incremental/hashes/for_loops.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub fn change_loop_body() {
2525
}
2626

2727
#[cfg(not(cfail1))]
28-
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
28+
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")]
2929
#[rustc_clean(cfg="cfail3")]
3030
pub fn change_loop_body() {
3131
let mut _x = 0;

0 commit comments

Comments
 (0)