Skip to content

Commit 768d6a4

Browse files
committed
Don't ICE on errors in function returning impl trait
Instead, report the error. This emits the errors on-demand, without special-casing `impl Trait`, so it should catch all ICEs of this kind, including ones that haven't been found yet. Since the error is emitted during type-checking there is less info about the error; see comments in the code for details. - Add test case for -> impl Trait - Add test for impl trait with alias - Move EmitIgnoredResolutionErrors to rustdoc This makes `fn typeck_item_bodies` public, which is not desired behavior. That change should be removed once rust-lang#74070 is merged. - Don't visit nested closures twice
1 parent 14a8707 commit 768d6a4

File tree

7 files changed

+162
-2
lines changed

7 files changed

+162
-2
lines changed

src/librustc_typeck/check/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,7 @@ where
955955
val.fold_with(&mut FixupFolder { tcx })
956956
}
957957

958-
fn typeck_tables_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckTables<'tcx> {
958+
pub fn typeck_tables_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckTables<'tcx> {
959959
let fallback = move || tcx.type_of(def_id.to_def_id());
960960
typeck_tables_of_with_fallback(tcx, def_id, fallback)
961961
}

src/librustc_typeck/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ extern crate rustc_middle;
7878
pub mod expr_use_visitor;
7979

8080
mod astconv;
81-
mod check;
81+
pub mod check;
8282
mod check_unused;
8383
mod coherence;
8484
mod collect;

src/librustdoc/core.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,15 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
375375
override_queries: Some(|_sess, local_providers, external_providers| {
376376
local_providers.lint_mod = |_, _| {};
377377
external_providers.lint_mod = |_, _| {};
378+
//let old_typeck = local_providers.typeck_tables_of;
379+
local_providers.typeck_tables_of = move |tcx, def_id| {
380+
let hir = tcx.hir();
381+
let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id)));
382+
debug!("visiting body for {:?}", def_id);
383+
EmitIgnoredResolutionErrors::new(&tcx.sess).visit_body(body);
384+
rustc_typeck::check::typeck_tables_of(tcx, def_id)
385+
//DEFAULT_TYPECK.with(|typeck| typeck(tcx, def_id))
386+
};
378387
}),
379388
registry: rustc_driver::diagnostics_registry(),
380389
};
@@ -572,6 +581,75 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
572581
})
573582
}
574583

584+
use rustc_hir::def::Res;
585+
use rustc_hir::{
586+
intravisit::{NestedVisitorMap, Visitor},
587+
Path,
588+
};
589+
use rustc_middle::hir::map::Map;
590+
591+
/*
592+
thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(rustc_middle::ty::TyCtxt<'tcx>, rustc_span::def_id::LocalDefId) -> &'tcx rustc_middle::ty::TypeckTables<'tcx> = {
593+
let mut providers = rustc_middle::ty::query::Providers::default();
594+
rustc_typeck::provide(&mut providers);
595+
providers.typeck_tables_of
596+
});
597+
*/
598+
599+
/// Due to https://github.com/rust-lang/rust/pull/73566,
600+
/// the name resolution pass may find errors that are never emitted.
601+
/// If typeck is called after this happens, then we'll get an ICE:
602+
/// 'Res::Error found but not reported'. To avoid this, emit the errors now.
603+
struct EmitIgnoredResolutionErrors<'a> {
604+
session: &'a Session,
605+
}
606+
607+
impl<'a> EmitIgnoredResolutionErrors<'a> {
608+
fn new(session: &'a Session) -> Self {
609+
Self { session }
610+
}
611+
}
612+
613+
impl<'a> Visitor<'a> for EmitIgnoredResolutionErrors<'_> {
614+
type Map = Map<'a>;
615+
616+
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
617+
// If we visit nested bodies, then we will report errors twice for e.g. nested closures
618+
NestedVisitorMap::None
619+
}
620+
621+
fn visit_path(&mut self, path: &'v Path<'v>, _id: HirId) {
622+
log::debug!("visiting path {:?}", path);
623+
if path.res == Res::Err {
624+
// We have less context here than in rustc_resolve,
625+
// so we can only emit the name and span.
626+
// However we can give a hint that rustc_resolve will have more info.
627+
// NOTE: this is a very rare case (only 4 out of several hundred thousand crates in a crater run)
628+
// NOTE: so it's ok for it to be slow
629+
let label = format!(
630+
"could not resolve path `{}`",
631+
path.segments
632+
.iter()
633+
.map(|segment| segment.ident.as_str().to_string())
634+
.collect::<Vec<_>>()
635+
.join("::")
636+
);
637+
let mut err = rustc_errors::struct_span_err!(
638+
self.session,
639+
path.span,
640+
E0433,
641+
"failed to resolve: {}",
642+
label
643+
);
644+
err.span_label(path.span, label);
645+
err.note("this error was originally ignored because you are running `rustdoc`");
646+
err.note("try running again with `rustc` and you may get a more detailed error");
647+
err.emit();
648+
}
649+
// NOTE: this does _not_ visit the path segments
650+
}
651+
}
652+
575653
/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter
576654
/// for `impl Trait` in argument position.
577655
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]

src/librustdoc/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ pub fn main() {
9494
32_000_000 // 32MB on other platforms
9595
};
9696
rustc_driver::set_sigpipe_handler();
97+
rustc_driver::install_ice_hook();
9798
env_logger::init_from_env("RUSTDOC_LOG");
9899
let res = std::thread::Builder::new()
99100
.stack_size(thread_stack_size)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// edition:2018
2+
#![feature(type_alias_impl_trait)]
3+
4+
pub trait ValidTrait {}
5+
type ImplTrait = impl ValidTrait;
6+
7+
/// This returns impl trait
8+
pub fn g() -> impl ValidTrait {
9+
error::_in::impl_trait()
10+
//~^ ERROR failed to resolve
11+
}
12+
13+
/// This returns impl trait, but using a type alias
14+
pub fn h() -> ImplTrait {
15+
error::_in::impl_trait::alias();
16+
//~^ ERROR failed to resolve
17+
(|| error::_in::impl_trait::alias::nested::closure())()
18+
//~^ ERROR failed to resolve
19+
}
20+
21+
/// This used to work with ResolveBodyWithLoop.
22+
/// However now that we ignore type checking instead of modifying the function body,
23+
/// the return type is seen as `impl Future<Output = u32>`, not a `u32`.
24+
/// So it no longer allows errors in the function body.
25+
pub async fn a() -> u32 {
26+
error::_in::async_fn()
27+
//~^ ERROR failed to resolve
28+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait`
2+
--> $DIR/error-in-impl-trait.rs:9:5
3+
|
4+
LL | error::_in::impl_trait()
5+
| ^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait`
6+
|
7+
= note: this error was originally ignored because you are running `rustdoc`
8+
= note: try running again with `rustc` and you may get a more detailed error
9+
10+
error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias`
11+
--> $DIR/error-in-impl-trait.rs:15:5
12+
|
13+
LL | error::_in::impl_trait::alias();
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias`
15+
|
16+
= note: this error was originally ignored because you are running `rustdoc`
17+
= note: try running again with `rustc` and you may get a more detailed error
18+
19+
error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure`
20+
--> $DIR/error-in-impl-trait.rs:17:9
21+
|
22+
LL | (|| error::_in::impl_trait::alias::nested::closure())()
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure`
24+
|
25+
= note: this error was originally ignored because you are running `rustdoc`
26+
= note: try running again with `rustc` and you may get a more detailed error
27+
28+
error[E0433]: failed to resolve: could not resolve path `error::_in::async_fn`
29+
--> $DIR/error-in-impl-trait.rs:26:5
30+
|
31+
LL | error::_in::async_fn()
32+
| ^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::async_fn`
33+
|
34+
= note: this error was originally ignored because you are running `rustdoc`
35+
= note: try running again with `rustc` and you may get a more detailed error
36+
37+
error: aborting due to 4 previous errors
38+
39+
For more information about this error, try `rustc --explain E0433`.

src/test/rustdoc/impl-trait-alias.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(type_alias_impl_trait)]
2+
3+
trait MyTrait {}
4+
impl MyTrait for i32 {}
5+
6+
// @has impl_trait_alias/type.Foo.html 'Foo'
7+
/// debug type
8+
pub type Foo = impl MyTrait;
9+
10+
// @has impl_trait_alias/fn.foo.html 'foo'
11+
/// debug function
12+
pub fn foo() -> Foo {
13+
1
14+
}

0 commit comments

Comments
 (0)