about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJoshua Nelson <jyn514@gmail.com>2020-07-09 09:13:59 -0400
committerJoshua Nelson <jyn514@gmail.com>2020-07-15 10:54:05 -0400
commita93bcc9a7b8e48865d3df59fc936a0553e4d1e37 (patch)
tree4cfa88cff7c79c7bcbc74dbe4b89908d84468a07
parent768d6a4950d66f1a0e1e7793a984fb638494d1c5 (diff)
downloadrust-a93bcc9a7b8e48865d3df59fc936a0553e4d1e37.tar.gz
rust-a93bcc9a7b8e48865d3df59fc936a0553e4d1e37.zip
Recurse into function bodies, but don't typeck closures
Previously, rustdoc would issue a delay_span_bug ICE on the following code:

```rust
pub fn a() -> impl Fn() -> u32 {
    || content::doesnt::matter()
}
```

This wasn't picked up earlier because having `type Alias = impl Trait;`
in the same module caused _all closures_ to be typechecked, even if they
wouldn't normally. Additionally, if _any_ error was emitted, no
delay_span_bug would be emitted. So as part of this commit all of the
tests were separated out into different files.
-rw-r--r--src/librustdoc/core.rs28
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait.rs28
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait.stderr39
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/README.md7
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/async.rs10
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/async.stderr12
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/closure.rs5
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/closure.stderr12
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs6
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr12
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs6
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr12
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs10
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr12
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs10
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr12
16 files changed, 145 insertions, 76 deletions
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 @@ thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(rustc_middle::ty::TyCtxt<'tcx>
 /// 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<Self::Map> {
-        // 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<Output = u32>`, 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<Output = u32>`, 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`.