Skip to content

Commit a56bd2b

Browse files
committed
Auto merge of #116849 - oli-obk:error_shenanigans, r=cjgillot
Avoid a `track_errors` by bubbling up most errors from `check_well_formed` I believe `track_errors` is mostly papering over issues that a sufficiently convoluted query graph can hit. I made this change, while the actual change I want to do is to stop bailing out early on errors, and instead use this new `ErrorGuaranteed` to invoke `check_well_formed` for individual items before doing all the `typeck` logic on them. This works towards resolving #97477 and various other ICEs, as well as allowing us to use parallel rustc more (which is currently rather limited/bottlenecked due to the very sequential nature in which we do `rustc_hir_analysis::check_crate`) cc `@SparrowLii` `@Zoxc` for the new `try_par_for_each_in` function
2 parents 6bb4ad6 + fe8ebb1 commit a56bd2b

36 files changed

+425
-310
lines changed

Diff for: compiler/rustc_data_structures/src/sync.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub use worker_local::{Registry, WorkerLocal};
5454
mod parallel;
5555
#[cfg(parallel_compiler)]
5656
pub use parallel::scope;
57-
pub use parallel::{join, par_for_each_in, par_map, parallel_guard};
57+
pub use parallel::{join, par_for_each_in, par_map, parallel_guard, try_par_for_each_in};
5858

5959
pub use std::sync::atomic::Ordering;
6060
pub use std::sync::atomic::Ordering::SeqCst;

Diff for: compiler/rustc_data_structures/src/sync/parallel.rs

+29
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,15 @@ mod disabled {
7777
})
7878
}
7979

80+
pub fn try_par_for_each_in<T: IntoIterator, E: Copy>(
81+
t: T,
82+
mut for_each: impl FnMut(T::Item) -> Result<(), E>,
83+
) -> Result<(), E> {
84+
parallel_guard(|guard| {
85+
t.into_iter().fold(Ok(()), |ret, i| guard.run(|| for_each(i)).unwrap_or(ret).and(ret))
86+
})
87+
}
88+
8089
pub fn par_map<T: IntoIterator, R, C: FromIterator<R>>(
8190
t: T,
8291
mut map: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item) -> R,
@@ -167,6 +176,26 @@ mod enabled {
167176
});
168177
}
169178

179+
pub fn try_par_for_each_in<
180+
T: IntoIterator + IntoParallelIterator<Item = <T as IntoIterator>::Item>,
181+
E: Copy + Send,
182+
>(
183+
t: T,
184+
for_each: impl Fn(<T as IntoIterator>::Item) -> Result<(), E> + DynSync + DynSend,
185+
) -> Result<(), E> {
186+
parallel_guard(|guard| {
187+
if mode::is_dyn_thread_safe() {
188+
let for_each = FromDyn::from(for_each);
189+
t.into_par_iter()
190+
.fold_with(Ok(()), |ret, i| guard.run(|| for_each(i)).unwrap_or(ret).and(ret))
191+
.reduce(|| Ok(()), |a, b| a.and(b))
192+
} else {
193+
t.into_iter()
194+
.fold(Ok(()), |ret, i| guard.run(|| for_each(i)).unwrap_or(ret).and(ret))
195+
}
196+
})
197+
}
198+
170199
pub fn par_map<
171200
I,
172201
T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>,

Diff for: compiler/rustc_hir_analysis/src/check/wfcheck.rs

+124-106
Large diffs are not rendered by default.

Diff for: compiler/rustc_hir_analysis/src/lib.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,8 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
205205
})?;
206206
}
207207

208-
tcx.sess.track_errors(|| {
209-
tcx.sess.time("wf_checking", || {
210-
tcx.hir().par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module))
211-
});
208+
tcx.sess.time("wf_checking", || {
209+
tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module))
212210
})?;
213211

214212
// NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.

Diff for: compiler/rustc_macros/src/query.rs

+10
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ struct QueryModifiers {
114114

115115
/// Generate a `feed` method to set the query's value from another query.
116116
feedable: Option<Ident>,
117+
118+
/// Forward the result on ensure if the query gets recomputed, and
119+
/// return `Ok(())` otherwise. Only applicable to queries returning
120+
/// `Result<(), ErrorGuaranteed>`
121+
ensure_forwards_result_if_red: Option<Ident>,
117122
}
118123

119124
fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
@@ -128,6 +133,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
128133
let mut depth_limit = None;
129134
let mut separate_provide_extern = None;
130135
let mut feedable = None;
136+
let mut ensure_forwards_result_if_red = None;
131137

132138
while !input.is_empty() {
133139
let modifier: Ident = input.parse()?;
@@ -187,6 +193,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
187193
try_insert!(separate_provide_extern = modifier);
188194
} else if modifier == "feedable" {
189195
try_insert!(feedable = modifier);
196+
} else if modifier == "ensure_forwards_result_if_red" {
197+
try_insert!(ensure_forwards_result_if_red = modifier);
190198
} else {
191199
return Err(Error::new(modifier.span(), "unknown query modifier"));
192200
}
@@ -206,6 +214,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
206214
depth_limit,
207215
separate_provide_extern,
208216
feedable,
217+
ensure_forwards_result_if_red,
209218
})
210219
}
211220

@@ -325,6 +334,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
325334
eval_always,
326335
depth_limit,
327336
separate_provide_extern,
337+
ensure_forwards_result_if_red,
328338
);
329339

330340
if modifiers.cache.is_some() {

Diff for: compiler/rustc_middle/src/hir/map/mod.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_ast as ast;
66
use rustc_data_structures::fingerprint::Fingerprint;
77
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
88
use rustc_data_structures::svh::Svh;
9-
use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync};
9+
use rustc_data_structures::sync::{par_for_each_in, try_par_for_each_in, DynSend, DynSync};
1010
use rustc_hir::def::{DefKind, Res};
1111
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, LOCAL_CRATE};
1212
use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
@@ -16,7 +16,7 @@ use rustc_index::Idx;
1616
use rustc_middle::hir::nested_filter;
1717
use rustc_span::def_id::StableCrateId;
1818
use rustc_span::symbol::{kw, sym, Ident, Symbol};
19-
use rustc_span::Span;
19+
use rustc_span::{ErrorGuaranteed, Span};
2020
use rustc_target::spec::abi::Abi;
2121

2222
#[inline]
@@ -632,6 +632,17 @@ impl<'hir> Map<'hir> {
632632
})
633633
}
634634

635+
#[inline]
636+
pub fn try_par_for_each_module(
637+
self,
638+
f: impl Fn(LocalModDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
639+
) -> Result<(), ErrorGuaranteed> {
640+
let crate_items = self.tcx.hir_crate_items(());
641+
try_par_for_each_in(&crate_items.submodules[..], |module| {
642+
f(LocalModDefId::new_unchecked(module.def_id))
643+
})
644+
}
645+
635646
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
636647
/// until the crate root is reached. Prefer this over your own loop using `parent_id`.
637648
#[inline]

Diff for: compiler/rustc_middle/src/hir/mod.rs

+22-10
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ pub mod place;
99
use crate::query::Providers;
1010
use crate::ty::{EarlyBinder, ImplSubject, TyCtxt};
1111
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
12-
use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync};
12+
use rustc_data_structures::sync::{try_par_for_each_in, DynSend, DynSync};
1313
use rustc_hir::def::DefKind;
1414
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
1515
use rustc_hir::*;
1616
use rustc_query_system::ich::StableHashingContext;
17-
use rustc_span::{ExpnId, DUMMY_SP};
17+
use rustc_span::{ErrorGuaranteed, ExpnId, DUMMY_SP};
1818

1919
/// Top-level HIR node for current owner. This only contains the node for which
2020
/// `HirId::local_id == 0`, and excludes bodies.
@@ -78,20 +78,32 @@ impl ModuleItems {
7878
self.owners().map(|id| id.def_id)
7979
}
8080

81-
pub fn par_items(&self, f: impl Fn(ItemId) + DynSend + DynSync) {
82-
par_for_each_in(&self.items[..], |&id| f(id))
81+
pub fn par_items(
82+
&self,
83+
f: impl Fn(ItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
84+
) -> Result<(), ErrorGuaranteed> {
85+
try_par_for_each_in(&self.items[..], |&id| f(id))
8386
}
8487

85-
pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + DynSend + DynSync) {
86-
par_for_each_in(&self.trait_items[..], |&id| f(id))
88+
pub fn par_trait_items(
89+
&self,
90+
f: impl Fn(TraitItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
91+
) -> Result<(), ErrorGuaranteed> {
92+
try_par_for_each_in(&self.trait_items[..], |&id| f(id))
8793
}
8894

89-
pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + DynSend + DynSync) {
90-
par_for_each_in(&self.impl_items[..], |&id| f(id))
95+
pub fn par_impl_items(
96+
&self,
97+
f: impl Fn(ImplItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
98+
) -> Result<(), ErrorGuaranteed> {
99+
try_par_for_each_in(&self.impl_items[..], |&id| f(id))
91100
}
92101

93-
pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + DynSend + DynSync) {
94-
par_for_each_in(&self.foreign_items[..], |&id| f(id))
102+
pub fn par_foreign_items(
103+
&self,
104+
f: impl Fn(ForeignItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
105+
) -> Result<(), ErrorGuaranteed> {
106+
try_par_for_each_in(&self.foreign_items[..], |&id| f(id))
95107
}
96108
}
97109

Diff for: compiler/rustc_middle/src/query/mod.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ use crate::mir::interpret::{
2525
use crate::mir::interpret::{LitToConstError, LitToConstInput};
2626
use crate::mir::mono::CodegenUnit;
2727
use crate::query::erase::{erase, restore, Erase};
28-
use crate::query::plumbing::{query_ensure, query_get_at, CyclePlaceholder, DynamicQuery};
28+
use crate::query::plumbing::{
29+
query_ensure, query_ensure_error_guaranteed, query_get_at, CyclePlaceholder, DynamicQuery,
30+
};
2931
use crate::thir;
3032
use crate::traits::query::{
3133
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
@@ -965,8 +967,9 @@ rustc_queries! {
965967
desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) }
966968
}
967969

968-
query check_mod_type_wf(key: LocalModDefId) -> () {
970+
query check_mod_type_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> {
969971
desc { |tcx| "checking that types are well-formed in {}", describe_as_module(key, tcx) }
972+
ensure_forwards_result_if_red
970973
}
971974

972975
query collect_mod_item_types(key: LocalModDefId) -> () {
@@ -1499,8 +1502,9 @@ rustc_queries! {
14991502
feedable
15001503
}
15011504

1502-
query check_well_formed(key: hir::OwnerId) -> () {
1505+
query check_well_formed(key: hir::OwnerId) -> Result<(), ErrorGuaranteed> {
15031506
desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) }
1507+
ensure_forwards_result_if_red
15041508
}
15051509

15061510
// The `DefId`s of all non-generic functions and statics in the given crate

Diff for: compiler/rustc_middle/src/query/plumbing.rs

+55-3
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,45 @@ pub fn query_ensure<'tcx, Cache>(
173173
}
174174
}
175175

176+
#[inline]
177+
pub fn query_ensure_error_guaranteed<'tcx, Cache>(
178+
tcx: TyCtxt<'tcx>,
179+
execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
180+
query_cache: &Cache,
181+
key: Cache::Key,
182+
check_cache: bool,
183+
) -> Result<(), ErrorGuaranteed>
184+
where
185+
Cache: QueryCache<Value = super::erase::Erase<Result<(), ErrorGuaranteed>>>,
186+
{
187+
let key = key.into_query_param();
188+
if let Some(res) = try_get_cached(tcx, query_cache, &key) {
189+
super::erase::restore(res)
190+
} else {
191+
execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache })
192+
.map(super::erase::restore)
193+
// Either we actually executed the query, which means we got a full `Result`,
194+
// or we can just assume the query succeeded, because it was green in the
195+
// incremental cache. If it is green, that means that the previous compilation
196+
// that wrote to the incremental cache compiles successfully. That is only
197+
// possible if the cache entry was `Ok(())`, so we emit that here, without
198+
// actually encoding the `Result` in the cache or loading it from there.
199+
.unwrap_or(Ok(()))
200+
}
201+
}
202+
203+
macro_rules! query_ensure {
204+
([]$($args:tt)*) => {
205+
query_ensure($($args)*)
206+
};
207+
([(ensure_forwards_result_if_red) $($rest:tt)*]$($args:tt)*) => {
208+
query_ensure_error_guaranteed($($args)*)
209+
};
210+
([$other:tt $($modifiers:tt)*]$($args:tt)*) => {
211+
query_ensure!([$($modifiers)*]$($args)*)
212+
};
213+
}
214+
176215
macro_rules! query_helper_param_ty {
177216
(DefId) => { impl IntoQueryParam<DefId> };
178217
(LocalDefId) => { impl IntoQueryParam<LocalDefId> };
@@ -220,6 +259,18 @@ macro_rules! separate_provide_extern_decl {
220259
};
221260
}
222261

262+
macro_rules! ensure_result {
263+
([][$ty:ty]) => {
264+
()
265+
};
266+
([(ensure_forwards_result_if_red) $($rest:tt)*][$ty:ty]) => {
267+
Result<(), ErrorGuaranteed>
268+
};
269+
([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
270+
ensure_result!([$($modifiers)*][$($args)*])
271+
};
272+
}
273+
223274
macro_rules! separate_provide_extern_default {
224275
([][$name:ident]) => {
225276
()
@@ -343,14 +394,15 @@ macro_rules! define_callbacks {
343394
impl<'tcx> TyCtxtEnsure<'tcx> {
344395
$($(#[$attr])*
345396
#[inline(always)]
346-
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
347-
query_ensure(
397+
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> ensure_result!([$($modifiers)*][$V]) {
398+
query_ensure!(
399+
[$($modifiers)*]
348400
self.tcx,
349401
self.tcx.query_system.fns.engine.$name,
350402
&self.tcx.query_system.caches.$name,
351403
key.into_query_param(),
352404
false,
353-
);
405+
)
354406
})*
355407
}
356408

Diff for: compiler/rustc_span/src/lib.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -2247,7 +2247,7 @@ where
22472247

22482248
/// Useful type to use with `Result<>` indicate that an error has already
22492249
/// been reported to the user, so no need to continue checking.
2250-
#[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq, PartialOrd, Ord)]
2250+
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
22512251
#[derive(HashStable_Generic)]
22522252
pub struct ErrorGuaranteed(());
22532253

@@ -2259,3 +2259,20 @@ impl ErrorGuaranteed {
22592259
ErrorGuaranteed(())
22602260
}
22612261
}
2262+
2263+
impl<E: rustc_serialize::Encoder> Encodable<E> for ErrorGuaranteed {
2264+
#[inline]
2265+
fn encode(&self, _e: &mut E) {
2266+
panic!(
2267+
"should never serialize an `ErrorGuaranteed`, as we do not write metadata or incremental caches in case errors occurred"
2268+
)
2269+
}
2270+
}
2271+
impl<D: rustc_serialize::Decoder> Decodable<D> for ErrorGuaranteed {
2272+
#[inline]
2273+
fn decode(_d: &mut D) -> ErrorGuaranteed {
2274+
panic!(
2275+
"`ErrorGuaranteed` should never have been serialized to metadata or incremental caches"
2276+
)
2277+
}
2278+
}

Diff for: src/tools/clippy/tests/ui/crashes/ice-6252.stderr

+2-12
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,6 @@ help: you might be missing a type parameter
2424
LL | impl<N, M, VAL> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
2525
| +++++
2626

27-
error[E0046]: not all trait items implemented, missing: `VAL`
28-
--> $DIR/ice-6252.rs:11:1
29-
|
30-
LL | const VAL: T;
31-
| ------------ `VAL` from trait
32-
...
33-
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
34-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
35-
36-
error: aborting due to 3 previous errors
27+
error: aborting due to 2 previous errors
3728

38-
Some errors have detailed explanations: E0046, E0412.
39-
For more information about an error, try `rustc --explain E0046`.
29+
For more information about this error, try `rustc --explain E0412`.

Diff for: tests/ui/associated-consts/issue-105330.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,10 @@ impl TraitWAssocConst for impl Demo { //~ ERROR E0404
99
}
1010

1111
fn foo<A: TraitWAssocConst<A=32>>() { //~ ERROR E0658
12-
foo::<Demo>()(); //~ ERROR E0271
13-
//~^ ERROR E0618
14-
//~| ERROR E0277
12+
foo::<Demo>()();
1513
}
1614

17-
fn main<A: TraitWAssocConst<A=32>>() { //~ ERROR E0131
15+
fn main<A: TraitWAssocConst<A=32>>() {
1816
//~^ ERROR E0658
19-
foo::<Demo>(); //~ ERROR E0277
20-
//~^ ERROR E0271
17+
foo::<Demo>();
2118
}

0 commit comments

Comments
 (0)