Skip to content

Commit 5829792

Browse files
committed
treat an error taint from const eval lint in late_lint and check_mod_deathness
error from const eval lint causes ICE at check_pat in late_lint, because the function expects the typeck result isn't tainted by error but it is. To avoid the ICE, check_pat returns earlier if the typeck_result is tainted. check_mod_deathness also has an issue from the same reason. visit_body for making live symbols expects the typeck result has no error. So this commit adds a check in visit_nested_body to avoid the ICE. However, if visit_nested_body just returns without doing anything, all codes with the error are marked as dead, because live_symbols is empty. To avoid this side effect, visit_nested_body and other visit_* functions in MarkSymbolVistior should return appropriate error. If a function returns ControlFlow::Break, live_symbols_and_ignore_derived_traits returns earlier with error, then check_mod_deathness, the caller of the function returns earlier without pushing everything into dead_codes.
1 parent 4cd91ef commit 5829792

File tree

6 files changed

+114
-52
lines changed

6 files changed

+114
-52
lines changed

compiler/rustc_lint/src/builtin.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,10 @@ declare_lint_pass!(NonShorthandFieldPatterns => [NON_SHORTHAND_FIELD_PATTERNS]);
152152

153153
impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
154154
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
155-
if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
155+
// The result shouldn't be tainted, otherwise it will cause ICE.
156+
if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind
157+
&& cx.typeck_results().tainted_by_errors.is_none()
158+
{
156159
let variant = cx
157160
.typeck_results()
158161
.pat_ty(pat)

compiler/rustc_middle/src/query/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,10 +1202,10 @@ rustc_queries! {
12021202
/// Return the live symbols in the crate for dead code check.
12031203
///
12041204
/// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone).
1205-
query live_symbols_and_ignored_derived_traits(_: ()) -> &'tcx (
1205+
query live_symbols_and_ignored_derived_traits(_: ()) -> &'tcx Result<(
12061206
LocalDefIdSet,
12071207
LocalDefIdMap<FxIndexSet<DefId>>,
1208-
) {
1208+
), ErrorGuaranteed> {
12091209
arena_cache
12101210
desc { "finding live symbols in crate" }
12111211
}

compiler/rustc_passes/src/dead.rs

Lines changed: 78 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
// is dead.
55

66
use std::mem;
7+
use std::ops::ControlFlow;
78

89
use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
910
use rustc_abi::FieldIdx;
1011
use rustc_data_structures::fx::FxIndexSet;
11-
use rustc_errors::MultiSpan;
12+
use rustc_errors::{ErrorGuaranteed, MultiSpan};
1213
use rustc_hir::def::{CtorOf, DefKind, Res};
1314
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
1415
use rustc_hir::intravisit::{self, Visitor};
@@ -178,12 +179,12 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
178179
.iter()
179180
.any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_)))
180181
{
181-
self.visit_expr(expr);
182+
let _ = self.visit_expr(expr);
182183
} else if let hir::ExprKind::Field(base, ..) = expr.kind {
183184
// Ignore write to field
184185
self.handle_assign(base);
185186
} else {
186-
self.visit_expr(expr);
187+
let _ = self.visit_expr(expr);
187188
}
188189
}
189190

@@ -318,7 +319,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
318319
}
319320
}
320321

321-
fn mark_live_symbols(&mut self) {
322+
fn mark_live_symbols(&mut self) -> <MarkSymbolVisitor<'tcx> as Visitor<'tcx>>::Result {
322323
while let Some(work) = self.worklist.pop() {
323324
let (mut id, comes_from_allow_expect) = work;
324325

@@ -366,8 +367,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
366367
continue;
367368
}
368369

369-
self.visit_node(self.tcx.hir_node_by_def_id(id));
370+
let visit_result = self.visit_node(self.tcx.hir_node_by_def_id(id));
371+
if visit_result.is_break() {
372+
return visit_result;
373+
}
370374
}
375+
376+
ControlFlow::Continue(())
371377
}
372378

373379
/// Automatically generated items marked with `rustc_trivial_field_reads`
@@ -391,19 +397,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
391397
false
392398
}
393399

394-
fn visit_node(&mut self, node: Node<'tcx>) {
400+
fn visit_node(
401+
&mut self,
402+
node: Node<'tcx>,
403+
) -> <MarkSymbolVisitor<'tcx> as Visitor<'tcx>>::Result {
395404
if let Node::ImplItem(impl_item) = node
396405
&& self.should_ignore_impl_item(impl_item)
397406
{
398-
return;
407+
return ControlFlow::Continue(());
399408
}
400409

401410
let unconditionally_treated_fields_as_live =
402411
self.repr_unconditionally_treats_fields_as_live;
403412
let had_repr_simd = self.repr_has_repr_simd;
404413
self.repr_unconditionally_treats_fields_as_live = false;
405414
self.repr_has_repr_simd = false;
406-
match node {
415+
let walk_result = match node {
407416
Node::Item(item) => match item.kind {
408417
hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
409418
let def = self.tcx.adt_def(item.owner_id);
@@ -413,7 +422,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
413422

414423
intravisit::walk_item(self, item)
415424
}
416-
hir::ItemKind::ForeignMod { .. } => {}
425+
hir::ItemKind::ForeignMod { .. } => ControlFlow::Continue(()),
417426
hir::ItemKind::Trait(.., trait_item_refs) => {
418427
// mark assoc ty live if the trait is live
419428
for trait_item in trait_item_refs {
@@ -431,7 +440,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
431440
if let Some(trait_id) = self.tcx.trait_of_assoc(trait_item_id) {
432441
self.check_def_id(trait_id);
433442
}
434-
intravisit::walk_trait_item(self, trait_item);
443+
intravisit::walk_trait_item(self, trait_item)
435444
}
436445
Node::ImplItem(impl_item) => {
437446
let item = self.tcx.local_parent(impl_item.owner_id.def_id);
@@ -452,16 +461,16 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
452461
_ => {}
453462
}
454463
}
455-
intravisit::walk_impl_item(self, impl_item);
456-
}
457-
Node::ForeignItem(foreign_item) => {
458-
intravisit::walk_foreign_item(self, foreign_item);
464+
intravisit::walk_impl_item(self, impl_item)
459465
}
466+
Node::ForeignItem(foreign_item) => intravisit::walk_foreign_item(self, foreign_item),
460467
Node::OpaqueTy(opaq) => intravisit::walk_opaque_ty(self, opaq),
461-
_ => {}
462-
}
468+
_ => ControlFlow::Continue(()),
469+
};
463470
self.repr_has_repr_simd = had_repr_simd;
464471
self.repr_unconditionally_treats_fields_as_live = unconditionally_treated_fields_as_live;
472+
473+
walk_result
465474
}
466475

467476
fn mark_as_used_if_union(&mut self, adt: ty::AdtDef<'tcx>, fields: &[hir::ExprField<'_>]) {
@@ -514,15 +523,25 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
514523
}
515524

516525
impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
517-
fn visit_nested_body(&mut self, body: hir::BodyId) {
518-
let old_maybe_typeck_results =
519-
self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
526+
type Result = ControlFlow<ErrorGuaranteed>;
527+
528+
fn visit_nested_body(&mut self, body: hir::BodyId) -> Self::Result {
529+
let typeck_results = self.tcx.typeck_body(body);
530+
531+
// The result shouldn't be tainted, otherwise it will cause ICE.
532+
if let Some(guar) = typeck_results.tainted_by_errors {
533+
return ControlFlow::Break(guar);
534+
}
535+
536+
let old_maybe_typeck_results = self.maybe_typeck_results.replace(typeck_results);
520537
let body = self.tcx.hir_body(body);
521-
self.visit_body(body);
538+
let result = self.visit_body(body);
522539
self.maybe_typeck_results = old_maybe_typeck_results;
540+
541+
result
523542
}
524543

525-
fn visit_variant_data(&mut self, def: &'tcx hir::VariantData<'tcx>) {
544+
fn visit_variant_data(&mut self, def: &'tcx hir::VariantData<'tcx>) -> Self::Result {
526545
let tcx = self.tcx;
527546
let unconditionally_treat_fields_as_live = self.repr_unconditionally_treats_fields_as_live;
528547
let has_repr_simd = self.repr_has_repr_simd;
@@ -539,10 +558,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
539558
});
540559
self.live_symbols.extend(live_fields);
541560

542-
intravisit::walk_struct_def(self, def);
561+
intravisit::walk_struct_def(self, def)
543562
}
544563

545-
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
564+
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result {
546565
match expr.kind {
547566
hir::ExprKind::Path(ref qpath @ QPath::TypeRelative(..)) => {
548567
let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
@@ -578,20 +597,22 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
578597
_ => (),
579598
}
580599

581-
intravisit::walk_expr(self, expr);
600+
intravisit::walk_expr(self, expr)
582601
}
583602

584-
fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
603+
fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> Self::Result {
585604
// Inside the body, ignore constructions of variants
586605
// necessary for the pattern to match. Those construction sites
587606
// can't be reached unless the variant is constructed elsewhere.
588607
let len = self.ignore_variant_stack.len();
589608
self.ignore_variant_stack.extend(arm.pat.necessary_variants());
590-
intravisit::walk_arm(self, arm);
609+
let result = intravisit::walk_arm(self, arm);
591610
self.ignore_variant_stack.truncate(len);
611+
612+
result
592613
}
593614

594-
fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
615+
fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Self::Result {
595616
self.in_pat = true;
596617
match pat.kind {
597618
PatKind::Struct(ref path, fields, _) => {
@@ -605,11 +626,13 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
605626
_ => (),
606627
}
607628

608-
intravisit::walk_pat(self, pat);
629+
let result = intravisit::walk_pat(self, pat);
609630
self.in_pat = false;
631+
632+
result
610633
}
611634

612-
fn visit_pat_expr(&mut self, expr: &'tcx rustc_hir::PatExpr<'tcx>) {
635+
fn visit_pat_expr(&mut self, expr: &'tcx rustc_hir::PatExpr<'tcx>) -> Self::Result {
613636
match &expr.kind {
614637
rustc_hir::PatExprKind::Path(qpath) => {
615638
// mark the type of variant live when meeting E::V in expr
@@ -622,37 +645,41 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
622645
}
623646
_ => {}
624647
}
625-
intravisit::walk_pat_expr(self, expr);
648+
intravisit::walk_pat_expr(self, expr)
626649
}
627650

628-
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
651+
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) -> Self::Result {
629652
self.handle_res(path.res);
630-
intravisit::walk_path(self, path);
653+
intravisit::walk_path(self, path)
631654
}
632655

633-
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
656+
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) -> Self::Result {
634657
// When inline const blocks are used in pattern position, paths
635658
// referenced by it should be considered as used.
636659
let in_pat = mem::replace(&mut self.in_pat, false);
637660

638661
self.live_symbols.insert(c.def_id);
639-
intravisit::walk_anon_const(self, c);
662+
let result = intravisit::walk_anon_const(self, c);
640663

641664
self.in_pat = in_pat;
665+
666+
result
642667
}
643668

644-
fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
669+
fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) -> Self::Result {
645670
// When inline const blocks are used in pattern position, paths
646671
// referenced by it should be considered as used.
647672
let in_pat = mem::replace(&mut self.in_pat, false);
648673

649674
self.live_symbols.insert(c.def_id);
650-
intravisit::walk_inline_const(self, c);
675+
let result = intravisit::walk_inline_const(self, c);
651676

652677
self.in_pat = in_pat;
678+
679+
result
653680
}
654681

655-
fn visit_trait_ref(&mut self, t: &'tcx hir::TraitRef<'tcx>) {
682+
fn visit_trait_ref(&mut self, t: &'tcx hir::TraitRef<'tcx>) -> Self::Result {
656683
if let Some(trait_def_id) = t.path.res.opt_def_id()
657684
&& let Some(segment) = t.path.segments.last()
658685
&& let Some(args) = segment.args
@@ -674,7 +701,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
674701
}
675702
}
676703

677-
intravisit::walk_trait_ref(self, t);
704+
intravisit::walk_trait_ref(self, t)
678705
}
679706
}
680707

@@ -821,7 +848,7 @@ fn create_and_seed_worklist(
821848
fn live_symbols_and_ignored_derived_traits(
822849
tcx: TyCtxt<'_>,
823850
(): (),
824-
) -> (LocalDefIdSet, LocalDefIdMap<FxIndexSet<DefId>>) {
851+
) -> Result<(LocalDefIdSet, LocalDefIdMap<FxIndexSet<DefId>>), ErrorGuaranteed> {
825852
let (worklist, mut unsolved_items) = create_and_seed_worklist(tcx);
826853
let mut symbol_visitor = MarkSymbolVisitor {
827854
worklist,
@@ -835,7 +862,9 @@ fn live_symbols_and_ignored_derived_traits(
835862
ignore_variant_stack: vec![],
836863
ignored_derived_traits: Default::default(),
837864
};
838-
symbol_visitor.mark_live_symbols();
865+
if let ControlFlow::Break(guar) = symbol_visitor.mark_live_symbols() {
866+
return Err(guar);
867+
}
839868

840869
// We have marked the primary seeds as live. We now need to process unsolved items from traits
841870
// and trait impls: add them to the work list if the trait or the implemented type is live.
@@ -849,14 +878,16 @@ fn live_symbols_and_ignored_derived_traits(
849878
symbol_visitor
850879
.worklist
851880
.extend(items_to_check.drain(..).map(|id| (id, ComesFromAllowExpect::No)));
852-
symbol_visitor.mark_live_symbols();
881+
if let ControlFlow::Break(guar) = symbol_visitor.mark_live_symbols() {
882+
return Err(guar);
883+
}
853884

854885
items_to_check.extend(unsolved_items.extract_if(.., |&mut local_def_id| {
855886
symbol_visitor.check_impl_or_impl_item_live(local_def_id)
856887
}));
857888
}
858889

859-
(symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits)
890+
Ok((symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits))
860891
}
861892

862893
struct DeadItem {
@@ -1136,7 +1167,11 @@ impl<'tcx> DeadVisitor<'tcx> {
11361167
}
11371168

11381169
fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
1139-
let (live_symbols, ignored_derived_traits) = tcx.live_symbols_and_ignored_derived_traits(());
1170+
let live_symbols_result = tcx.live_symbols_and_ignored_derived_traits(());
1171+
if live_symbols_result.is_err() {
1172+
return;
1173+
}
1174+
let (live_symbols, ignored_derived_traits) = live_symbols_result.as_ref().unwrap();
11401175
let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits };
11411176

11421177
let module_items = tcx.hir_module_items(module);

tests/crashes/125323.rs

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// The test confirms ICE-125323 is fixed.
2+
//
3+
// This warning makes sure the fix doesn't throw everything with errors to dead.
4+
#![warn(unused)]
5+
fn should_not_be_dead() {}
6+
7+
fn main() {
8+
for _ in 0..0 {
9+
[(); loop {}]; //~ ERROR constant evaluation is taking a long time
10+
}
11+
12+
should_not_be_dead();
13+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: constant evaluation is taking a long time
2+
--> $DIR/do-not-ice-long-constant-evaluation-in-for-loop.rs:9:14
3+
|
4+
LL | [(); loop {}];
5+
| ^^^^^^^
6+
|
7+
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
8+
If your compilation actually takes a long time, you can safely allow the lint.
9+
help: the constant being evaluated
10+
--> $DIR/do-not-ice-long-constant-evaluation-in-for-loop.rs:9:14
11+
|
12+
LL | [(); loop {}];
13+
| ^^^^^^^
14+
= note: `#[deny(long_running_const_eval)]` on by default
15+
16+
error: aborting due to 1 previous error
17+

0 commit comments

Comments
 (0)