diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 3d0da0e9157..413faff283e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -377,10 +377,18 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt external_providers.lint_mod = |_, _| {}; //let old_typeck = local_providers.typeck_tables_of; local_providers.typeck_tables_of = move |tcx, def_id| { + // Closures' tables come from their outermost function, + // as they are part of the same "inference environment". + // This avoids emitting errors for the parent twice (see similar code in `typeck_tables_of_with_fallback`) + let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local(); + if outer_def_id != def_id { + return tcx.typeck_tables_of(outer_def_id); + } + let hir = tcx.hir(); let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id))); debug!("visiting body for {:?}", def_id); - EmitIgnoredResolutionErrors::new(&tcx.sess).visit_body(body); + EmitIgnoredResolutionErrors::new(&tcx.sess, hir).visit_body(body); rustc_typeck::check::typeck_tables_of(tcx, def_id) //DEFAULT_TYPECK.with(|typeck| typeck(tcx, def_id)) }; @@ -600,22 +608,24 @@ fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler) { /// the name resolution pass may find errors that are never emitted. /// If typeck is called after this happens, then we'll get an ICE: /// 'Res::Error found but not reported'. To avoid this, emit the errors now. -struct EmitIgnoredResolutionErrors<'a> { +struct EmitIgnoredResolutionErrors<'a, 'hir> { session: &'a Session, + hir_map: Map<'hir>, } -impl<'a> EmitIgnoredResolutionErrors<'a> { - fn new(session: &'a Session) -> Self { - Self { session } +impl<'a, 'hir> EmitIgnoredResolutionErrors<'a, 'hir> { + fn new(session: &'a Session, hir_map: Map<'hir>) -> Self { + Self { session, hir_map } } } -impl<'a> Visitor<'a> for EmitIgnoredResolutionErrors<'_> { - type Map = Map<'a>; +impl<'hir> Visitor<'hir> for EmitIgnoredResolutionErrors<'_, 'hir> { + type Map = Map<'hir>; fn nested_visit_map(&mut self) -> NestedVisitorMap { - // If we visit nested bodies, then we will report errors twice for e.g. nested closures - NestedVisitorMap::None + // We need to recurse into nested closures, + // since those will fallback to the parent for type checking. + NestedVisitorMap::OnlyBodies(self.hir_map) } fn visit_path(&mut self, path: &'v Path<'v>, _id: HirId) { diff --git a/src/test/rustdoc-ui/error-in-impl-trait.rs b/src/test/rustdoc-ui/error-in-impl-trait.rs deleted file mode 100644 index fbe663a6189..00000000000 --- a/src/test/rustdoc-ui/error-in-impl-trait.rs +++ /dev/null @@ -1,28 +0,0 @@ -// edition:2018 -#![feature(type_alias_impl_trait)] - -pub trait ValidTrait {} -type ImplTrait = impl ValidTrait; - -/// This returns impl trait -pub fn g() -> impl ValidTrait { - error::_in::impl_trait() - //~^ ERROR failed to resolve -} - -/// This returns impl trait, but using a type alias -pub fn h() -> ImplTrait { - error::_in::impl_trait::alias(); - //~^ ERROR failed to resolve - (|| error::_in::impl_trait::alias::nested::closure())() - //~^ ERROR failed to resolve -} - -/// This used to work with ResolveBodyWithLoop. -/// However now that we ignore type checking instead of modifying the function body, -/// the return type is seen as `impl Future`, not a `u32`. -/// So it no longer allows errors in the function body. -pub async fn a() -> u32 { - error::_in::async_fn() - //~^ ERROR failed to resolve -} diff --git a/src/test/rustdoc-ui/error-in-impl-trait.stderr b/src/test/rustdoc-ui/error-in-impl-trait.stderr deleted file mode 100644 index 4df40da9b7c..00000000000 --- a/src/test/rustdoc-ui/error-in-impl-trait.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait` - --> $DIR/error-in-impl-trait.rs:9:5 - | -LL | error::_in::impl_trait() - | ^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait` - | - = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error - -error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias` - --> $DIR/error-in-impl-trait.rs:15:5 - | -LL | error::_in::impl_trait::alias(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias` - | - = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error - -error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure` - --> $DIR/error-in-impl-trait.rs:17:9 - | -LL | (|| error::_in::impl_trait::alias::nested::closure())() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure` - | - = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error - -error[E0433]: failed to resolve: could not resolve path `error::_in::async_fn` - --> $DIR/error-in-impl-trait.rs:26:5 - | -LL | error::_in::async_fn() - | ^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::async_fn` - | - = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/README.md b/src/test/rustdoc-ui/error-in-impl-trait/README.md new file mode 100644 index 00000000000..1176a4a8c4c --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/README.md @@ -0,0 +1,7 @@ +Each of these needs to be in a separate file, +because the `delay_span_bug` ICE in rustdoc won't be triggerred +if even a single other error was emitted. + +However, conceptually they are all testing basically the same thing. +See https://github.com/rust-lang/rust/pull/73566#issuecomment-653689128 +for more details. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.rs b/src/test/rustdoc-ui/error-in-impl-trait/async.rs new file mode 100644 index 00000000000..112a2c494a5 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/async.rs @@ -0,0 +1,10 @@ +// edition:2018 + +/// This used to work with ResolveBodyWithLoop. +/// However now that we ignore type checking instead of modifying the function body, +/// the return type is seen as `impl Future`, not a `u32`. +/// So it no longer allows errors in the function body. +pub async fn a() -> u32 { + error::_in::async_fn() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.stderr b/src/test/rustdoc-ui/error-in-impl-trait/async.stderr new file mode 100644 index 00000000000..eae3cadf653 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/async.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::async_fn` + --> $DIR/async.rs:8:5 + | +LL | error::_in::async_fn() + | ^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::async_fn` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs new file mode 100644 index 00000000000..df40c121d57 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs @@ -0,0 +1,5 @@ +// manually desugared version of an `async fn` (but with a closure instead of a generator) +pub fn a() -> impl Fn() -> u32 { + || content::doesnt::matter() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr new file mode 100644 index 00000000000..9355165997a --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `content::doesnt::matter` + --> $DIR/closure.rs:3:8 + | +LL | || content::doesnt::matter() + | ^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `content::doesnt::matter` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs new file mode 100644 index 00000000000..399fb827517 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs @@ -0,0 +1,6 @@ +pub trait ValidTrait {} +/// This returns impl trait +pub fn g() -> impl ValidTrait { + (|| error::_in::impl_trait::alias::nested::closure())() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr new file mode 100644 index 00000000000..569f2ab8ff8 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure` + --> $DIR/impl-keyword-closure.rs:4:9 + | +LL | (|| error::_in::impl_trait::alias::nested::closure())() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs new file mode 100644 index 00000000000..24b5734dbd0 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs @@ -0,0 +1,6 @@ +pub trait ValidTrait {} +/// This returns impl trait +pub fn g() -> impl ValidTrait { + error::_in::impl_trait() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr new file mode 100644 index 00000000000..68bc71f90b2 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait` + --> $DIR/impl-keyword.rs:4:5 + | +LL | error::_in::impl_trait() + | ^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs new file mode 100644 index 00000000000..1498fa4f890 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs @@ -0,0 +1,10 @@ +#![feature(type_alias_impl_trait)] + +pub trait ValidTrait {} +type ImplTrait = impl ValidTrait; + +/// This returns impl trait, but using a type alias +pub fn h() -> ImplTrait { + (|| error::_in::impl_trait::alias::nested::closure())() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr new file mode 100644 index 00000000000..f3edb0385c8 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure` + --> $DIR/trait-alias-closure.rs:8:9 + | +LL | (|| error::_in::impl_trait::alias::nested::closure())() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs new file mode 100644 index 00000000000..cf9bc48c7f8 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs @@ -0,0 +1,10 @@ +#![feature(type_alias_impl_trait)] + +pub trait ValidTrait {} +type ImplTrait = impl ValidTrait; + +/// This returns impl trait, but using a type alias +pub fn h() -> ImplTrait { + error::_in::impl_trait::alias() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr new file mode 100644 index 00000000000..ddb0fb88cc7 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias` + --> $DIR/trait-alias.rs:8:5 + | +LL | error::_in::impl_trait::alias() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`.