From 1941a43941cd789ab773b46948b06dd45853758f Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sat, 9 May 2020 12:00:42 +0100 Subject: [PATCH] Do not remove closures during `ReplaceBodyWithLoop` pass Fixes #71820 --- src/librustc_ast/ast.rs | 9 +++++++++ src/librustc_interface/util.rs | 19 ++++++++++++++++++- src/librustc_privacy/lib.rs | 7 ++----- src/test/rustdoc/macro-in-async-block.rs | 9 +++++++++ src/test/rustdoc/macro-in-closure.rs | 3 +++ 5 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 src/test/rustdoc/macro-in-async-block.rs diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index c63bbd53a3148..5cfece92b939f 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -899,6 +899,15 @@ impl Stmt { _ => false, } } + + pub fn as_expr(&self) -> Option<&Expr> { + match self.kind { + StmtKind::Local(ref l) => l.init.as_ref().map(|e| &**e), + StmtKind::Expr(ref e) => Some(e), + StmtKind::Semi(ref e) => Some(e), + _ => None, + } + } } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 0797ab33827fd..c2181c141d019 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -719,6 +719,19 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { } } + // We need to keep certain Expr nodes because they can contain + // exported macros. If we were to remove a parent of a MacroDef + // node, we would end up with in a case where the macro is properly + // lowered but not its parent, causing some surprising bug while + // trying to access the parent HirId. See issue #71820. + fn expr_to_keep(e: &ast::Expr) -> bool { + match e.kind { + ast::ExprKind::Closure(..) => true, + ast::ExprKind::Async(..) => true, + _ => false, + } + } + let empty_block = stmt_to_block(BlockCheckMode::Default, None, self.resolver); let loop_expr = P(ast::Expr { kind: ast::ExprKind::Loop(P(empty_block), None), @@ -741,7 +754,11 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { for s in b.stmts { let old_blocks = self.nested_blocks.replace(vec![]); - stmts.extend(self.flat_map_stmt(s).into_iter().filter(|s| s.is_item())); + stmts.extend( + self.flat_map_stmt(s).into_iter().filter(|s| { + s.is_item() || s.as_expr().map_or(false, |e| expr_to_keep(e)) + }), + ); // we put a Some in there earlier with that replace(), so this is valid let new_blocks = self.nested_blocks.take().unwrap(); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 82b45cf7cf884..0f37ef237d911 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -944,11 +944,8 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { let macro_module_def_id = ty::DefIdTree::parent(self.tcx, self.tcx.hir().local_def_id(md.hir_id).to_def_id()) .unwrap(); - // FIXME(#71104) Should really be using just `as_local_hir_id` but - // some `DefId` do not seem to have a corresponding HirId. - let hir_id = macro_module_def_id - .as_local() - .and_then(|def_id| self.tcx.hir().opt_local_def_id_to_hir_id(def_id)); + let hir_id = + macro_module_def_id.as_local().map(|def_id| self.tcx.hir().as_local_hir_id(def_id)); let mut module_id = match hir_id { Some(module_id) if self.tcx.hir().is_hir_id_module(module_id) => module_id, // `module_id` doesn't correspond to a `mod`, return early (#63164, #65252). diff --git a/src/test/rustdoc/macro-in-async-block.rs b/src/test/rustdoc/macro-in-async-block.rs new file mode 100644 index 0000000000000..b4aaacf7b3d40 --- /dev/null +++ b/src/test/rustdoc/macro-in-async-block.rs @@ -0,0 +1,9 @@ +// Regression issue for rustdoc ICE encountered in PR #72088. +// edition:2018 +#![feature(decl_macro)] + +fn main() { + async { + macro m() {} + }; +} diff --git a/src/test/rustdoc/macro-in-closure.rs b/src/test/rustdoc/macro-in-closure.rs index 298ff601de89f..e58a97fa591c5 100644 --- a/src/test/rustdoc/macro-in-closure.rs +++ b/src/test/rustdoc/macro-in-closure.rs @@ -6,4 +6,7 @@ fn main() { || { macro m() {} }; + let _ = || { + macro n() {} + }; }