From b8ecc9fefa4c9c763cf74e9c9659ecc00f30ba3a Mon Sep 17 00:00:00 2001 From: Will Crichton Date: Fri, 29 Oct 2021 13:21:50 -0700 Subject: [PATCH] Fix rare ICE during typeck in rustdoc scrape_examples --- src/librustdoc/scrape_examples.rs | 20 +++++++++++++++++-- .../Makefile | 5 +++++ .../examples/ex.rs | 2 ++ .../src/lib.rs | 1 + .../src/lib.rs | 2 ++ 5 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/test/run-make/rustdoc-scrape-examples-invalid-expr/Makefile create mode 100644 src/test/run-make/rustdoc-scrape-examples-invalid-expr/examples/ex.rs create mode 100644 src/test/run-make/rustdoc-scrape-examples-invalid-expr/src/lib.rs diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index fc54e55b87655..05e746573f479 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 0000000000000..dce8b83eefe4e --- /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 0000000000000..b342b5b0aaece --- /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 0000000000000..c30c99dec6038 --- /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 bd59584bbbf4f..bdfeda92d79a0 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() {}