Skip to content

Commit 32d330d

Browse files
committed
Avoid ICEs when we emit errors constructing the specialization graph
1 parent c24b4bf commit 32d330d

File tree

6 files changed

+79
-56
lines changed

6 files changed

+79
-56
lines changed

src/librustc/traits/specialization_graph.rs

+19-10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::ty::{self, TyCtxt};
44
use rustc_ast::ast::Ident;
55
use rustc_data_structures::fx::FxHashMap;
66
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
7+
use rustc_errors::ErrorReported;
78
use rustc_hir::def_id::{DefId, DefIdMap};
89

910
/// A per-trait graph of impls in specialization order. At the moment, this
@@ -23,17 +24,20 @@ use rustc_hir::def_id::{DefId, DefIdMap};
2324
/// has at most one parent.
2425
#[derive(RustcEncodable, RustcDecodable, HashStable)]
2526
pub struct Graph {
26-
// All impls have a parent; the "root" impls have as their parent the `def_id`
27-
// of the trait.
27+
/// All impls have a parent; the "root" impls have as their parent the `def_id`
28+
/// of the trait.
2829
pub parent: DefIdMap<DefId>,
2930

30-
// The "root" impls are found by looking up the trait's def_id.
31+
/// The "root" impls are found by looking up the trait's def_id.
3132
pub children: DefIdMap<Children>,
33+
34+
/// Whether an error was emitted while constructing the graph.
35+
pub has_errored: bool,
3236
}
3337

3438
impl Graph {
3539
pub fn new() -> Graph {
36-
Graph { parent: Default::default(), children: Default::default() }
40+
Graph { parent: Default::default(), children: Default::default(), has_errored: false }
3741
}
3842

3943
/// The parent of a given impl, which is the `DefId` of the trait when the
@@ -179,17 +183,22 @@ impl<'tcx> Ancestors<'tcx> {
179183
}
180184

181185
/// Walk up the specialization ancestors of a given impl, starting with that
182-
/// impl itself.
186+
/// impl itself. Returns `None` if an error was reported while building the
187+
/// specialization graph.
183188
pub fn ancestors(
184189
tcx: TyCtxt<'tcx>,
185190
trait_def_id: DefId,
186191
start_from_impl: DefId,
187-
) -> Ancestors<'tcx> {
192+
) -> Result<Ancestors<'tcx>, ErrorReported> {
188193
let specialization_graph = tcx.specialization_graph_of(trait_def_id);
189-
Ancestors {
190-
trait_def_id,
191-
specialization_graph,
192-
current_source: Some(Node::Impl(start_from_impl)),
194+
if specialization_graph.has_errored {
195+
Err(ErrorReported)
196+
} else {
197+
Ok(Ancestors {
198+
trait_def_id,
199+
specialization_graph,
200+
current_source: Some(Node::Impl(start_from_impl)),
201+
})
193202
}
194203
}
195204

src/librustc/ty/trait_def.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_hir::def_id::DefId;
99

1010
use rustc_data_structures::fx::FxHashMap;
1111
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
12+
use rustc_errors::ErrorReported;
1213
use rustc_macros::HashStable;
1314

1415
/// A trait's definition with type information.
@@ -92,7 +93,7 @@ impl<'tcx> TraitDef {
9293
&self,
9394
tcx: TyCtxt<'tcx>,
9495
of_impl: DefId,
95-
) -> specialization_graph::Ancestors<'tcx> {
96+
) -> Result<specialization_graph::Ancestors<'tcx>, ErrorReported> {
9697
specialization_graph::ancestors(tcx, self.def_id, of_impl)
9798
}
9899
}

src/librustc_metadata/rmeta/encoder.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -1077,12 +1077,13 @@ impl EncodeContext<'tcx> {
10771077
let polarity = self.tcx.impl_polarity(def_id);
10781078
let parent = if let Some(trait_ref) = trait_ref {
10791079
let trait_def = self.tcx.trait_def(trait_ref.def_id);
1080-
trait_def.ancestors(self.tcx, def_id).nth(1).and_then(|node| {
1081-
match node {
1082-
specialization_graph::Node::Impl(parent) => Some(parent),
1083-
_ => None,
1084-
}
1085-
})
1080+
trait_def.ancestors(self.tcx, def_id).ok()
1081+
.and_then(|mut an| an.nth(1).and_then(|node| {
1082+
match node {
1083+
specialization_graph::Node::Impl(parent) => Some(parent),
1084+
_ => None,
1085+
}
1086+
}))
10861087
} else {
10871088
None
10881089
};

src/librustc_trait_selection/traits/project.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc::ty::fold::{TypeFoldable, TypeFolder};
2121
use rustc::ty::subst::{InternalSubsts, Subst};
2222
use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
2323
use rustc_ast::ast::Ident;
24+
use rustc_errors::ErrorReported;
2425
use rustc_hir::def_id::DefId;
2526
use rustc_span::symbol::sym;
2627
use rustc_span::DUMMY_SP;
@@ -1010,7 +1011,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
10101011
// NOTE: This should be kept in sync with the similar code in
10111012
// `rustc::ty::instance::resolve_associated_item()`.
10121013
let node_item =
1013-
assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id);
1014+
assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id)
1015+
.map_err(|ErrorReported| ())?;
10141016

10151017
let is_default = if node_item.node.is_from_trait() {
10161018
// If true, the impl inherited a `type Foo = Bar`
@@ -1405,7 +1407,10 @@ fn confirm_impl_candidate<'cx, 'tcx>(
14051407
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
14061408

14071409
let param_env = obligation.param_env;
1408-
let assoc_ty = assoc_ty_def(selcx, impl_def_id, assoc_item_id);
1410+
let assoc_ty = match assoc_ty_def(selcx, impl_def_id, assoc_item_id) {
1411+
Ok(assoc_ty) => assoc_ty,
1412+
Err(ErrorReported) => return Progress { ty: tcx.types.err, obligations: nested },
1413+
};
14091414

14101415
if !assoc_ty.item.defaultness.has_value() {
14111416
// This means that the impl is missing a definition for the
@@ -1444,14 +1449,14 @@ fn assoc_ty_def(
14441449
selcx: &SelectionContext<'_, '_>,
14451450
impl_def_id: DefId,
14461451
assoc_ty_def_id: DefId,
1447-
) -> specialization_graph::NodeItem<ty::AssocItem> {
1452+
) -> Result<specialization_graph::NodeItem<ty::AssocItem>, ErrorReported> {
14481453
let tcx = selcx.tcx();
14491454
let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident;
14501455
let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
14511456
let trait_def = tcx.trait_def(trait_def_id);
14521457

14531458
// This function may be called while we are still building the
1454-
// specialization graph that is queried below (via TraidDef::ancestors()),
1459+
// specialization graph that is queried below (via TraitDef::ancestors()),
14551460
// so, in order to avoid unnecessary infinite recursion, we manually look
14561461
// for the associated item at the given impl.
14571462
// If there is no such item in that impl, this function will fail with a
@@ -1461,17 +1466,16 @@ fn assoc_ty_def(
14611466
if matches!(item.kind, ty::AssocKind::Type | ty::AssocKind::OpaqueTy)
14621467
&& tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id)
14631468
{
1464-
return specialization_graph::NodeItem {
1469+
return Ok(specialization_graph::NodeItem {
14651470
node: specialization_graph::Node::Impl(impl_def_id),
14661471
item: *item,
1467-
};
1472+
});
14681473
}
14691474
}
14701475

1471-
if let Some(assoc_item) =
1472-
trait_def.ancestors(tcx, impl_def_id).leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type)
1473-
{
1474-
assoc_item
1476+
let ancestors = trait_def.ancestors(tcx, impl_def_id)?;
1477+
if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) {
1478+
Ok(assoc_item)
14751479
} else {
14761480
// This is saying that neither the trait nor
14771481
// the impl contain a definition for this

src/librustc_trait_selection/traits/specialize/mod.rs

+21-17
Original file line numberDiff line numberDiff line change
@@ -130,24 +130,27 @@ pub fn find_associated_item<'tcx>(
130130
let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
131131
let trait_def = tcx.trait_def(trait_def_id);
132132

133-
let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id);
134-
match ancestors.leaf_def(tcx, item.ident, item.kind) {
135-
Some(node_item) => {
136-
let substs = tcx.infer_ctxt().enter(|infcx| {
137-
let param_env = param_env.with_reveal_all();
138-
let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
139-
let substs = translate_substs(
140-
&infcx,
141-
param_env,
142-
impl_data.impl_def_id,
143-
substs,
144-
node_item.node,
145-
);
146-
infcx.tcx.erase_regions(&substs)
147-
});
148-
(node_item.item.def_id, substs)
133+
if let Ok(ancestors) = trait_def.ancestors(tcx, impl_data.impl_def_id) {
134+
match ancestors.leaf_def(tcx, item.ident, item.kind) {
135+
Some(node_item) => {
136+
let substs = tcx.infer_ctxt().enter(|infcx| {
137+
let param_env = param_env.with_reveal_all();
138+
let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
139+
let substs = translate_substs(
140+
&infcx,
141+
param_env,
142+
impl_data.impl_def_id,
143+
substs,
144+
node_item.node,
145+
);
146+
infcx.tcx.erase_regions(&substs)
147+
});
148+
(node_item.item.def_id, substs)
149+
}
150+
None => bug!("{:?} not found in {:?}", item, impl_data.impl_def_id),
149151
}
150-
None => bug!("{:?} not found in {:?}", item, impl_data.impl_def_id),
152+
} else {
153+
(item.def_id, substs)
151154
}
152155
}
153156

@@ -382,6 +385,7 @@ pub(super) fn specialization_graph_provider(
382385

383386
match used_to_be_allowed {
384387
None => {
388+
sg.has_errored = true;
385389
let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
386390
decorate(LintDiagnosticBuilder::new(err));
387391
}

src/librustc_typeck/check/mod.rs

+16-12
Original file line numberDiff line numberDiff line change
@@ -1901,8 +1901,11 @@ fn check_specialization_validity<'tcx>(
19011901
hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type,
19021902
};
19031903

1904-
let mut ancestor_impls = trait_def
1905-
.ancestors(tcx, impl_id)
1904+
let ancestors = match trait_def.ancestors(tcx, impl_id) {
1905+
Ok(ancestors) => ancestors,
1906+
Err(_) => return,
1907+
};
1908+
let mut ancestor_impls = ancestors
19061909
.skip(1)
19071910
.filter_map(|parent| {
19081911
if parent.is_from_trait() {
@@ -2083,16 +2086,17 @@ fn check_impl_items_against_trait<'tcx>(
20832086

20842087
// Check for missing items from trait
20852088
let mut missing_items = Vec::new();
2086-
for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
2087-
let is_implemented = trait_def
2088-
.ancestors(tcx, impl_id)
2089-
.leaf_def(tcx, trait_item.ident, trait_item.kind)
2090-
.map(|node_item| !node_item.node.is_from_trait())
2091-
.unwrap_or(false);
2092-
2093-
if !is_implemented && !traits::impl_is_default(tcx, impl_id) {
2094-
if !trait_item.defaultness.has_value() {
2095-
missing_items.push(*trait_item);
2089+
if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id) {
2090+
for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
2091+
let is_implemented = ancestors
2092+
.leaf_def(tcx, trait_item.ident, trait_item.kind)
2093+
.map(|node_item| !node_item.node.is_from_trait())
2094+
.unwrap_or(false);
2095+
2096+
if !is_implemented && !traits::impl_is_default(tcx, impl_id) {
2097+
if !trait_item.defaultness.has_value() {
2098+
missing_items.push(*trait_item);
2099+
}
20962100
}
20972101
}
20982102
}

0 commit comments

Comments
 (0)