Skip to content
Open
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: 4 additions & 1 deletion compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,10 @@ declare_lint_pass!(NonShorthandFieldPatterns => [NON_SHORTHAND_FIELD_PATTERNS]);

impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
// 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()
{
let variant = cx
.typeck_results()
.pat_ty(pat)
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1200,10 +1200,10 @@ rustc_queries! {
/// Return the live symbols in the crate for dead code check.
///
/// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone).
query live_symbols_and_ignored_derived_traits(_: ()) -> &'tcx (
query live_symbols_and_ignored_derived_traits(_: ()) -> &'tcx Result<(
LocalDefIdSet,
LocalDefIdMap<FxIndexSet<DefId>>,
) {
), ErrorGuaranteed> {
arena_cache
desc { "finding live symbols in crate" }
}
Expand Down
121 changes: 78 additions & 43 deletions compiler/rustc_passes/src/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
// is dead.

use std::mem;
use std::ops::ControlFlow;

use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
use rustc_abi::FieldIdx;
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::MultiSpan;
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, Visitor};
Expand Down Expand Up @@ -178,12 +179,12 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
.iter()
.any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_)))
{
self.visit_expr(expr);
let _ = self.visit_expr(expr);
} else if let hir::ExprKind::Field(base, ..) = expr.kind {
// Ignore write to field
self.handle_assign(base);
} else {
self.visit_expr(expr);
let _ = self.visit_expr(expr);
}
}

Expand Down Expand Up @@ -318,7 +319,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
}
}

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

Expand Down Expand Up @@ -366,8 +367,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
continue;
}

self.visit_node(self.tcx.hir_node_by_def_id(id));
let visit_result = self.visit_node(self.tcx.hir_node_by_def_id(id));
if visit_result.is_break() {
return visit_result;
}
}

ControlFlow::Continue(())
}

/// Automatically generated items marked with `rustc_trivial_field_reads`
Expand Down Expand Up @@ -395,19 +401,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
false
}

fn visit_node(&mut self, node: Node<'tcx>) {
fn visit_node(
&mut self,
node: Node<'tcx>,
) -> <MarkSymbolVisitor<'tcx> as Visitor<'tcx>>::Result {
if let Node::ImplItem(hir::ImplItem { owner_id, .. }) = node
&& self.should_ignore_item(owner_id.to_def_id())
{
return;
return ControlFlow::Continue(());
}

let unconditionally_treated_fields_as_live =
self.repr_unconditionally_treats_fields_as_live;
let had_repr_simd = self.repr_has_repr_simd;
self.repr_unconditionally_treats_fields_as_live = false;
self.repr_has_repr_simd = false;
match node {
let walk_result = match node {
Node::Item(item) => match item.kind {
hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
let def = self.tcx.adt_def(item.owner_id);
Expand All @@ -417,7 +426,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {

intravisit::walk_item(self, item)
}
hir::ItemKind::ForeignMod { .. } => {}
hir::ItemKind::ForeignMod { .. } => ControlFlow::Continue(()),
hir::ItemKind::Trait(.., trait_item_refs) => {
// mark assoc ty live if the trait is live
for trait_item in trait_item_refs {
Expand All @@ -435,7 +444,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
if let Some(trait_id) = self.tcx.trait_of_assoc(trait_item_id) {
self.check_def_id(trait_id);
}
intravisit::walk_trait_item(self, trait_item);
intravisit::walk_trait_item(self, trait_item)
}
Node::ImplItem(impl_item) => {
let item = self.tcx.local_parent(impl_item.owner_id.def_id);
Expand All @@ -456,16 +465,16 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
_ => {}
}
}
intravisit::walk_impl_item(self, impl_item);
}
Node::ForeignItem(foreign_item) => {
intravisit::walk_foreign_item(self, foreign_item);
intravisit::walk_impl_item(self, impl_item)
}
Node::ForeignItem(foreign_item) => intravisit::walk_foreign_item(self, foreign_item),
Node::OpaqueTy(opaq) => intravisit::walk_opaque_ty(self, opaq),
_ => {}
}
_ => ControlFlow::Continue(()),
};
self.repr_has_repr_simd = had_repr_simd;
self.repr_unconditionally_treats_fields_as_live = unconditionally_treated_fields_as_live;

walk_result
}

fn mark_as_used_if_union(&mut self, adt: ty::AdtDef<'tcx>, fields: &[hir::ExprField<'_>]) {
Expand Down Expand Up @@ -520,15 +529,25 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
}

impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
fn visit_nested_body(&mut self, body: hir::BodyId) {
let old_maybe_typeck_results =
self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
type Result = ControlFlow<ErrorGuaranteed>;

fn visit_nested_body(&mut self, body: hir::BodyId) -> Self::Result {
let typeck_results = self.tcx.typeck_body(body);

// The result shouldn't be tainted, otherwise it will cause ICE.
if let Some(guar) = typeck_results.tainted_by_errors {
return ControlFlow::Break(guar);
}

let old_maybe_typeck_results = self.maybe_typeck_results.replace(typeck_results);
let body = self.tcx.hir_body(body);
self.visit_body(body);
let result = self.visit_body(body);
self.maybe_typeck_results = old_maybe_typeck_results;

result
}

fn visit_variant_data(&mut self, def: &'tcx hir::VariantData<'tcx>) {
fn visit_variant_data(&mut self, def: &'tcx hir::VariantData<'tcx>) -> Self::Result {
let tcx = self.tcx;
let unconditionally_treat_fields_as_live = self.repr_unconditionally_treats_fields_as_live;
let has_repr_simd = self.repr_has_repr_simd;
Expand All @@ -545,10 +564,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
});
self.live_symbols.extend(live_fields);

intravisit::walk_struct_def(self, def);
intravisit::walk_struct_def(self, def)
}

fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result {
match expr.kind {
hir::ExprKind::Path(ref qpath @ QPath::TypeRelative(..)) => {
let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
Expand Down Expand Up @@ -584,20 +603,22 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
_ => (),
}

intravisit::walk_expr(self, expr);
intravisit::walk_expr(self, expr)
}

fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> Self::Result {
// Inside the body, ignore constructions of variants
// necessary for the pattern to match. Those construction sites
// can't be reached unless the variant is constructed elsewhere.
let len = self.ignore_variant_stack.len();
self.ignore_variant_stack.extend(arm.pat.necessary_variants());
intravisit::walk_arm(self, arm);
let result = intravisit::walk_arm(self, arm);
self.ignore_variant_stack.truncate(len);

result
}

fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Self::Result {
self.in_pat = true;
match pat.kind {
PatKind::Struct(ref path, fields, _) => {
Expand All @@ -611,11 +632,13 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
_ => (),
}

intravisit::walk_pat(self, pat);
let result = intravisit::walk_pat(self, pat);
self.in_pat = false;

result
}

fn visit_pat_expr(&mut self, expr: &'tcx rustc_hir::PatExpr<'tcx>) {
fn visit_pat_expr(&mut self, expr: &'tcx rustc_hir::PatExpr<'tcx>) -> Self::Result {
match &expr.kind {
rustc_hir::PatExprKind::Path(qpath) => {
// mark the type of variant live when meeting E::V in expr
Expand All @@ -628,37 +651,41 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
}
_ => {}
}
intravisit::walk_pat_expr(self, expr);
intravisit::walk_pat_expr(self, expr)
}

fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) -> Self::Result {
self.handle_res(path.res);
intravisit::walk_path(self, path);
intravisit::walk_path(self, path)
}

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

self.live_symbols.insert(c.def_id);
intravisit::walk_anon_const(self, c);
let result = intravisit::walk_anon_const(self, c);

self.in_pat = in_pat;

result
}

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

self.live_symbols.insert(c.def_id);
intravisit::walk_inline_const(self, c);
let result = intravisit::walk_inline_const(self, c);

self.in_pat = in_pat;

result
}

fn visit_trait_ref(&mut self, t: &'tcx hir::TraitRef<'tcx>) {
fn visit_trait_ref(&mut self, t: &'tcx hir::TraitRef<'tcx>) -> Self::Result {
if let Some(trait_def_id) = t.path.res.opt_def_id()
&& let Some(segment) = t.path.segments.last()
&& let Some(args) = segment.args
Expand All @@ -680,7 +707,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
}
}

intravisit::walk_trait_ref(self, t);
intravisit::walk_trait_ref(self, t)
}
}

Expand Down Expand Up @@ -827,7 +854,7 @@ fn create_and_seed_worklist(
fn live_symbols_and_ignored_derived_traits(
tcx: TyCtxt<'_>,
(): (),
) -> (LocalDefIdSet, LocalDefIdMap<FxIndexSet<DefId>>) {
) -> Result<(LocalDefIdSet, LocalDefIdMap<FxIndexSet<DefId>>), ErrorGuaranteed> {
let (worklist, mut unsolved_items) = create_and_seed_worklist(tcx);
let mut symbol_visitor = MarkSymbolVisitor {
worklist,
Expand All @@ -841,7 +868,9 @@ fn live_symbols_and_ignored_derived_traits(
ignore_variant_stack: vec![],
ignored_derived_traits: Default::default(),
};
symbol_visitor.mark_live_symbols();
if let ControlFlow::Break(guar) = symbol_visitor.mark_live_symbols() {
return Err(guar);
}

// We have marked the primary seeds as live. We now need to process unsolved items from traits
// and trait impls: add them to the work list if the trait or the implemented type is live.
Expand All @@ -855,14 +884,16 @@ fn live_symbols_and_ignored_derived_traits(
symbol_visitor
.worklist
.extend(items_to_check.drain(..).map(|id| (id, ComesFromAllowExpect::No)));
symbol_visitor.mark_live_symbols();
if let ControlFlow::Break(guar) = symbol_visitor.mark_live_symbols() {
return Err(guar);
}

items_to_check.extend(unsolved_items.extract_if(.., |&mut local_def_id| {
symbol_visitor.check_impl_or_impl_item_live(local_def_id)
}));
}

(symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits)
Ok((symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits))
}

struct DeadItem {
Expand Down Expand Up @@ -1142,7 +1173,11 @@ impl<'tcx> DeadVisitor<'tcx> {
}

fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
let (live_symbols, ignored_derived_traits) = tcx.live_symbols_and_ignored_derived_traits(());
let live_symbols_result = tcx.live_symbols_and_ignored_derived_traits(());
if live_symbols_result.is_err() {
return;
}
let (live_symbols, ignored_derived_traits) = live_symbols_result.as_ref().unwrap();
let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits };

let module_items = tcx.hir_module_items(module);
Expand Down
6 changes: 0 additions & 6 deletions tests/crashes/125323.rs

This file was deleted.

13 changes: 13 additions & 0 deletions tests/ui/consts/do-not-ice-long-constant-evaluation-in-for-loop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// The test confirms ICE-125323 is fixed.
//
// This warning makes sure the fix doesn't throw everything with errors to dead.
#![warn(unused)]
fn should_not_be_dead() {}

fn main() {
for _ in 0..0 {
[(); loop {}]; //~ ERROR constant evaluation is taking a long time
}

should_not_be_dead();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error: constant evaluation is taking a long time
--> $DIR/do-not-ice-long-constant-evaluation-in-for-loop.rs:9: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:9:14
|
LL | [(); loop {}];
| ^^^^^^^
= note: `#[deny(long_running_const_eval)]` on by default

error: aborting due to 1 previous error

Loading