about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJoshua Nelson <jyn514@gmail.com>2020-07-11 00:28:42 -0400
committerJoshua Nelson <jyn514@gmail.com>2020-07-15 10:54:05 -0400
commit02a24c8e2fd370041a24b7d93e8c3710b7b76015 (patch)
tree826bbca890b868214a69ff7ec56cd6745bfd813d
parent2d0e8e2162a2e2be233a63ba5a8cbf3e19770b17 (diff)
downloadrust-02a24c8e2fd370041a24b7d93e8c3710b7b76015.tar.gz
rust-02a24c8e2fd370041a24b7d93e8c3710b7b76015.zip
Don't ICE on infinitely recursive types
`evaluate_obligation` can only be run on types that are already valid.
So rustdoc still has to run typeck even though it doesn't care about the
result.
-rw-r--r--Cargo.lock1
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/core.rs15
-rw-r--r--src/librustdoc/lib.rs2
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type.rs4
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type.stderr17
6 files changed, 40 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5309c03ee23..992421dcd7a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4027,6 +4027,7 @@ name = "rustdoc"
 version = "0.0.0"
 dependencies = [
  "itertools 0.8.0",
+ "lazy_static",
  "minifier",
  "pulldown-cmark",
  "rustc-rayon",
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 4af13e4cd58..baceb13cc61 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -16,3 +16,4 @@ serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 tempfile = "3"
 itertools = "0.8"
+lazy_static = "1"
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 39c214b1fb4..a77b177bd28 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -364,6 +364,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
         ..Options::default()
     };
 
+    lazy_static! {
+        static ref EMPTY_MAP: FxHashSet<LocalDefId> = FxHashSet::default();
+    }
     let config = interface::Config {
         opts: sessopts,
         crate_cfg: interface::parse_cfgspecs(cfgs),
@@ -378,8 +381,13 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
         lint_caps,
         register_lints: None,
         override_queries: Some(|_sess, local_providers, external_providers| {
+            // Most lints will require typechecking, so just don't run them.
             local_providers.lint_mod = |_, _| {};
             external_providers.lint_mod = |_, _| {};
+            local_providers.typeck_item_bodies = |_, _| {};
+            // hack so that `used_trait_imports` won't try to call typeck_tables_of
+            local_providers.used_trait_imports = |_, _| &EMPTY_MAP;
+            // In case typeck does end up being called, don't ICE in case there were name resolution errors
             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".
@@ -439,6 +447,13 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
             let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take();
 
             global_ctxt.enter(|tcx| {
+                // Some queries require that they only run on valid types:
+                // https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425
+                // Therefore typecheck this crate before running lints.
+                // NOTE: this does not typeck item bodies or run the default rustc lints
+                // (see `override_queries` in the `config`)
+                let _ = rustc_typeck::check_crate(tcx);
+                tcx.sess.abort_if_errors();
                 sess.time("missing_docs", || {
                     rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new);
                 });
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 4bd6b1260cc..cbf53d52ef0 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -15,6 +15,8 @@
 #![recursion_limit = "256"]
 
 extern crate env_logger;
+#[macro_use]
+extern crate lazy_static;
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
 extern crate rustc_attr;
diff --git a/src/test/rustdoc-ui/infinite-recursive-type.rs b/src/test/rustdoc-ui/infinite-recursive-type.rs
new file mode 100644
index 00000000000..32793fc4f76
--- /dev/null
+++ b/src/test/rustdoc-ui/infinite-recursive-type.rs
@@ -0,0 +1,4 @@
+enum E {
+//~^ ERROR recursive type `E` has infinite size
+    V(E),
+}
diff --git a/src/test/rustdoc-ui/infinite-recursive-type.stderr b/src/test/rustdoc-ui/infinite-recursive-type.stderr
new file mode 100644
index 00000000000..897445f200c
--- /dev/null
+++ b/src/test/rustdoc-ui/infinite-recursive-type.stderr
@@ -0,0 +1,17 @@
+error[E0072]: recursive type `E` has infinite size
+  --> $DIR/infinite-recursive-type.rs:1:1
+   |
+LL | enum E {
+   | ^^^^^^ recursive type has infinite size
+LL |
+LL |     V(E),
+   |       - recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `E` representable
+   |
+LL |     V(Box<E>),
+   |       ^^^^ ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0072`.