Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 1 addition & 4 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,7 @@ declare_lint_pass!(NonShorthandFieldPatterns => [NON_SHORTHAND_FIELD_PATTERNS]);

impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
// The result shouldn't be tainted, otherwise it will cause ICE.
if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind
&& cx.typeck_results().tainted_by_errors.is_none()
{
if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
let variant = cx
.typeck_results()
.pat_ty(pat)
Expand Down
21 changes: 19 additions & 2 deletions compiler/rustc_lint/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,15 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
// The body and typeck results are also set in `visit_fn`.
// Only fetch the results if this is for a new body.
if old_enclosing_body != Some(body_id) && !self.actually_rustdoc {
self.context.typeck_results = Some(self.context.tcx.typeck_body(body_id));
let typeck_results = self.context.tcx.typeck_body(body_id);

// To avoid ICE, skip visiting the body if the typeck_results is tainted.
if typeck_results.tainted_by_errors.is_some() {
self.context.enclosing_body = old_enclosing_body;
self.context.typeck_results = old_typeck_results;
return;
}
self.context.typeck_results = Some(typeck_results);
}

let body = self.context.tcx.hir_body(body_id);
Expand Down Expand Up @@ -189,7 +197,16 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
let old_enclosing_body = self.context.enclosing_body.replace(body_id);
let old_typeck_results = self.context.typeck_results;
if !self.actually_rustdoc {
self.context.typeck_results = Some(self.context.tcx.typeck_body(body_id));
let typeck_results = self.context.tcx.typeck_body(body_id);

// To avoid ICE, skip visiting the body if the typeck_results is tainted.
if typeck_results.tainted_by_errors.is_some() {
self.context.enclosing_body = old_enclosing_body;
self.context.typeck_results = old_typeck_results;
return;
}

self.context.typeck_results = Some(typeck_results);
}
let body = self.context.tcx.hir_body(body_id);
lint_callback!(self, check_fn, fk, decl, body, span, id);
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_mir_transform/src/dead_store_elimination.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
loc,
);

// The logic in LivenessTransferFunction isn't quite what we need; it ignores call
// destinations that are just locals because they are killed by the call, which makes
// it eligible to be moved-from in the argument list. That's backwards.
if !destination.is_indirect() {
state.insert(destination.local);
}

for (index, arg) in args.iter().map(|a| &a.node).enumerate().rev() {
if let Operand::Copy(place) = *arg
&& !place.is_indirect()
Expand Down
6 changes: 0 additions & 6 deletions tests/crashes/138361.rs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
let mut _0: ();

bb0: {
_1[_2] = passthrough_usize(copy _2) -> [return: bb1, unwind unreachable];
_1[_2] = identity::<usize>(copy _2) -> [return: bb1, unwind unreachable];
}

bb1: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
let mut _0: ();

bb0: {
_1[_2] = passthrough_usize(copy _2) -> [return: bb1, unwind continue];
_1[_2] = identity::<usize>(copy _2) -> [return: bb1, unwind continue];
}

bb1: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
- // MIR for `ret_is_arg` before DeadStoreElimination-final
+ // MIR for `ret_is_arg` after DeadStoreElimination-final

fn ret_is_arg(_1: [u64; 5]) -> [u64; 5] {
let mut _0: [u64; 5];

bb0: {
_1 = identity::<[u64; 5]>(copy _1) -> [return: bb1, unwind unreachable];
}

bb1: {
_0 = copy _1;
return;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
- // MIR for `ret_is_arg` before DeadStoreElimination-final
+ // MIR for `ret_is_arg` after DeadStoreElimination-final

fn ret_is_arg(_1: [u64; 5]) -> [u64; 5] {
let mut _0: [u64; 5];

bb0: {
_1 = identity::<[u64; 5]>(copy _1) -> [return: bb1, unwind unreachable];
}

bb1: {
_0 = copy _1;
return;
}
}

29 changes: 21 additions & 8 deletions tests/mir-opt/dead-store-elimination/call_arg_copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#![feature(custom_mir)]
#![allow(internal_features)]

use std::convert::identity;
use std::intrinsics::mir::*;

#[inline(never)]
Expand Down Expand Up @@ -40,31 +41,43 @@ fn move_packed(packed: Packed) {
}
}

#[inline(never)]
fn passthrough_usize(a: usize) -> usize {
a
}

// EMIT_MIR call_arg_copy.move_index.DeadStoreElimination-final.diff
#[custom_mir(dialect = "analysis")]
fn move_index(a: [usize; 10], b: usize) {
// CHECK-LABEL: fn move_index(
// CHECK: = passthrough_usize(copy _2)
// CHECK: = identity::<usize>(copy _2)
mir! {
{
// The index is used again after the operand is evaluated to
// evaluate the destionation place, so the argument cannot be turned
// evaluate the destination place, so the argument cannot be turned
// into a move.
Call(a[b] = passthrough_usize(b), ReturnTo(ret), UnwindContinue())
Call(a[b] = identity(b), ReturnTo(ret), UnwindContinue())
}
ret = {
Return()
}
}
}

// EMIT_MIR call_arg_copy.ret_is_arg.DeadStoreElimination-final.diff
#[custom_mir(dialect = "runtime")]
fn ret_is_arg(x: [u64; 5]) -> [u64; 5] {
// CHECK-LABEL: fn ret_is_arg(_1
// CHECK: _1 = identity::<[u64; 5]>(copy _1) ->
mir! {
{
Call(x = identity(x), ReturnTo(bb1), UnwindUnreachable())
}
bb1 = {
RET = x;
Return()
}
}
}

fn main() {
move_simple(1);
move_packed(Packed { x: 0, y: 1 });
move_index([0; _], 1);
ret_is_arg([0; 5]);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error: constant evaluation is taking a long time
--> $DIR/do-not-ice-long-constant-evaluation-in-for-loop.rs:10:14
--> $DIR/long-constant-evaluation-cause-dead-code.rs:10:14
|
LL | [(); loop {}];
| ^^^^^^^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/do-not-ice-long-constant-evaluation-in-for-loop.rs:10:14
--> $DIR/long-constant-evaluation-cause-dead-code.rs:10:14
|
LL | [(); loop {}];
| ^^^^^^^
Expand Down
5 changes: 5 additions & 0 deletions tests/ui/consts/long-constant-evaluation-cause-ice-in-sty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// The test confirms ICE-138361 is fixed.
fn main() {
[0; loop{}]; //~ ERROR constant evaluation is taking a long time
std::mem::transmute(4)
}
17 changes: 17 additions & 0 deletions tests/ui/consts/long-constant-evaluation-cause-ice-in-sty.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error: constant evaluation is taking a long time
--> $DIR/long-constant-evaluation-cause-ice-in-sty.rs:3:7
|
LL | [0; loop{}];
| ^^^^^^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/long-constant-evaluation-cause-ice-in-sty.rs:3:7
|
LL | [0; loop{}];
| ^^^^^^
= note: `#[deny(long_running_const_eval)]` on by default

error: aborting due to 1 previous error

Loading