about summary refs log tree commit diff
diff options
context:
space:
mode:
authorWill Crichton <wcrichto@cs.stanford.edu>2021-10-29 13:21:50 -0700
committerWill Crichton <wcrichto@cs.stanford.edu>2021-10-29 13:21:50 -0700
commitb8ecc9fefa4c9c763cf74e9c9659ecc00f30ba3a (patch)
tree16cd23569e2eff56aee692ee68fcac6dd8be35b4
parentfd5d614b7708c2bbd0a7c796af3c3b63f31a19ac (diff)
downloadrust-b8ecc9fefa4c9c763cf74e9c9659ecc00f30ba3a.tar.gz
rust-b8ecc9fefa4c9c763cf74e9c9659ecc00f30ba3a.zip
Fix rare ICE during typeck in rustdoc scrape_examples
-rw-r--r--src/librustdoc/scrape_examples.rs20
-rw-r--r--src/test/run-make/rustdoc-scrape-examples-invalid-expr/Makefile5
-rw-r--r--src/test/run-make/rustdoc-scrape-examples-invalid-expr/examples/ex.rs2
-rw-r--r--src/test/run-make/rustdoc-scrape-examples-invalid-expr/src/lib.rs1
-rw-r--r--src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs2
5 files changed, 28 insertions, 2 deletions
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index fc54e55b876..05e746573f4 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -132,12 +132,28 @@ where
     fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
         intravisit::walk_expr(self, ex);
 
-        // Get type of function if expression is a function call
         let tcx = self.tcx;
+
+        // If we visit an item that contains an expression outside a function body,
+        // then we need to exit before calling typeck (which will panic). See
+        // test/run-make/rustdoc-scrape-examples-invalid-expr for an example.
+        let hir = tcx.hir();
+        let owner = hir.local_def_id_to_hir_id(ex.hir_id.owner);
+        if hir.maybe_body_owned_by(owner).is_none() {
+            return;
+        }
+
+        // Get type of function if expression is a function call
         let (ty, span) = match ex.kind {
             hir::ExprKind::Call(f, _) => {
                 let types = tcx.typeck(ex.hir_id.owner);
-                (types.node_type(f.hir_id), ex.span)
+
+                match types.node_type_opt(f.hir_id) {
+                    Some(ty) => (ty, ex.span),
+                    None => {
+                        return;
+                    }
+                }
             }
             hir::ExprKind::MethodCall(_, _, _, span) => {
                 let types = tcx.typeck(ex.hir_id.owner);
diff --git a/src/test/run-make/rustdoc-scrape-examples-invalid-expr/Makefile b/src/test/run-make/rustdoc-scrape-examples-invalid-expr/Makefile
new file mode 100644
index 00000000000..dce8b83eefe
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-invalid-expr/Makefile
@@ -0,0 +1,5 @@
+deps := ex
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
diff --git a/src/test/run-make/rustdoc-scrape-examples-invalid-expr/examples/ex.rs b/src/test/run-make/rustdoc-scrape-examples-invalid-expr/examples/ex.rs
new file mode 100644
index 00000000000..b342b5b0aae
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-invalid-expr/examples/ex.rs
@@ -0,0 +1,2 @@
+pub struct Foo([usize; foobar::f()]);
+fn main() {}
diff --git a/src/test/run-make/rustdoc-scrape-examples-invalid-expr/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-invalid-expr/src/lib.rs
new file mode 100644
index 00000000000..c30c99dec60
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-invalid-expr/src/lib.rs
@@ -0,0 +1 @@
+pub const fn f() -> usize { 5 }
diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs
index bd59584bbbf..bdfeda92d79 100644
--- a/src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs
+++ b/src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs
@@ -1,4 +1,6 @@
 // @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]//*[@class="prev"]' ''
 // @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' ''
+// @has src/ex/ex.rs.html
+// @has foobar/fn.ok.html '//a[@href="../src/ex/ex.rs.html#2"]' ''
 
 pub fn ok() {}