diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs
index 0650d09003486..fe40c615f79c9 100644
--- a/src/librustc_interface/lib.rs
+++ b/src/librustc_interface/lib.rs
@@ -14,6 +14,7 @@ mod queries;
 pub mod util;
 
 pub use interface::{run_compiler, Config};
+pub use passes::{DEFAULT_EXTERN_QUERY_PROVIDERS, DEFAULT_QUERY_PROVIDERS};
 pub use queries::Queries;
 
 #[cfg(test)]
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 6d85c2f182544..6505803eba8c6 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -3,6 +3,7 @@ use crate::proc_macro_decls;
 use crate::util;
 
 use log::{info, log_enabled, warn};
+use once_cell::sync::Lazy;
 use rustc_ast::mut_visit::MutVisitor;
 use rustc_ast::{self, ast, visit};
 use rustc_codegen_ssa::back::link::emit_metadata;
@@ -19,6 +20,7 @@ use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::DepGraph;
 use rustc_middle::middle;
 use rustc_middle::middle::cstore::{CrateStore, MetadataLoader, MetadataLoaderDyn};
+use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::steal::Steal;
 use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
 use rustc_mir as mir;
@@ -352,13 +354,7 @@ fn configure_and_expand_inner<'a>(
         )
     });
 
-    // If we're actually rustdoc then there's no need to actually compile
-    // anything, so switch everything to just looping
-    let mut should_loop = sess.opts.actually_rustdoc;
     if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty {
-        should_loop |= true;
-    }
-    if should_loop {
         log::debug!("replacing bodies with loop {{}}");
         util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate);
     }
@@ -719,7 +715,8 @@ pub fn prepare_outputs(
     Ok(outputs)
 }
 
-pub fn default_provide(providers: &mut ty::query::Providers) {
+pub static DEFAULT_QUERY_PROVIDERS: Lazy<Providers> = Lazy::new(|| {
+    let providers = &mut Providers::default();
     providers.analysis = analysis;
     proc_macro_decls::provide(providers);
     plugin::build::provide(providers);
@@ -738,12 +735,15 @@ pub fn default_provide(providers: &mut ty::query::Providers) {
     rustc_lint::provide(providers);
     rustc_symbol_mangling::provide(providers);
     rustc_codegen_ssa::provide(providers);
-}
+    *providers
+});
 
-pub fn default_provide_extern(providers: &mut ty::query::Providers) {
-    rustc_metadata::provide_extern(providers);
-    rustc_codegen_ssa::provide_extern(providers);
-}
+pub static DEFAULT_EXTERN_QUERY_PROVIDERS: Lazy<Providers> = Lazy::new(|| {
+    let mut extern_providers = *DEFAULT_QUERY_PROVIDERS;
+    rustc_metadata::provide_extern(&mut extern_providers);
+    rustc_codegen_ssa::provide_extern(&mut extern_providers);
+    extern_providers
+});
 
 pub struct QueryContext<'tcx>(&'tcx GlobalCtxt<'tcx>);
 
@@ -780,12 +780,11 @@ pub fn create_global_ctxt<'tcx>(
     let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
 
     let codegen_backend = compiler.codegen_backend();
-    let mut local_providers = ty::query::Providers::default();
-    default_provide(&mut local_providers);
+    let mut local_providers = *DEFAULT_QUERY_PROVIDERS;
     codegen_backend.provide(&mut local_providers);
 
-    let mut extern_providers = local_providers;
-    default_provide_extern(&mut extern_providers);
+    let mut extern_providers = *DEFAULT_EXTERN_QUERY_PROVIDERS;
+    codegen_backend.provide(&mut extern_providers);
     codegen_backend.provide_extern(&mut extern_providers);
 
     if let Some(callback) = compiler.override_queries {
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index c165a601408fd..274f93dd50b0d 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -394,13 +394,23 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
 
     /// Fields used to add information to diagnostic errors.
     diagnostic_metadata: DiagnosticMetadata<'ast>,
+
+    /// State used to know whether to ignore resolution errors for function bodies.
+    ///
+    /// In particular, rustdoc uses this to avoid giving errors for `cfg()` items.
+    /// In most cases this will be `None`, in which case errors will always be reported.
+    /// If it is `Some(_)`, then it will be updated when entering a nested function or trait body.
+    in_func_body: bool,
 }
 
 /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
 impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
     fn visit_item(&mut self, item: &'ast Item) {
         let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item));
+        // Always report errors in items we just entered.
+        let old_ignore = replace(&mut self.in_func_body, false);
         self.resolve_item(item);
+        self.in_func_body = old_ignore;
         self.diagnostic_metadata.current_item = prev;
     }
     fn visit_arm(&mut self, arm: &'ast Arm) {
@@ -497,6 +507,9 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
 
                 visit::walk_fn_ret_ty(this, &declaration.output);
 
+                // Ignore errors in function bodies if this is rustdoc
+                // Be sure not to set this until the function signature has been resolved.
+                let previous_state = replace(&mut this.in_func_body, true);
                 // Resolve the function body, potentially inside the body of an async closure
                 match fn_kind {
                     FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
@@ -504,6 +517,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                 };
 
                 debug!("(resolving function) leaving function");
+                this.in_func_body = previous_state;
             })
         });
         self.diagnostic_metadata.current_function = previous_value;
@@ -644,6 +658,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             label_ribs: Vec::new(),
             current_trait_ref: None,
             diagnostic_metadata: DiagnosticMetadata::default(),
+            // errors at module scope should always be reported
+            in_func_body: false,
         }
     }
 
@@ -757,7 +773,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 return if self.is_label_valid_from_rib(i) {
                     Some(*id)
                 } else {
-                    self.r.report_error(
+                    self.report_error(
                         original_span,
                         ResolutionError::UnreachableLabel {
                             name: label.name,
@@ -775,7 +791,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label));
         }
 
-        self.r.report_error(
+        self.report_error(
             original_span,
             ResolutionError::UndeclaredLabel { name: label.name, suggestion },
         );
@@ -833,7 +849,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             };
             let report_error = |this: &Self, ns| {
                 let what = if ns == TypeNS { "type parameters" } else { "local variables" };
-                this.r.session.span_err(ident.span, &format!("imports cannot refer to {}", what));
+                if this.should_report_errs() {
+                    this.r
+                        .session
+                        .span_err(ident.span, &format!("imports cannot refer to {}", what));
+                }
             };
 
             for &ns in nss {
@@ -1008,7 +1028,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             if seen_bindings.contains_key(&ident) {
                 let span = seen_bindings.get(&ident).unwrap();
                 let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, *span);
-                self.r.report_error(param.ident.span, err);
+                self.report_error(param.ident.span, err);
             }
             seen_bindings.entry(ident).or_insert(param.ident.span);
 
@@ -1274,7 +1294,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 .is_err()
             {
                 let path = &self.current_trait_ref.as_ref().unwrap().1.path;
-                self.r.report_error(span, err(ident.name, &path_names_to_string(path)));
+                self.report_error(span, err(ident.name, &path_names_to_string(path)));
             }
         }
     }
@@ -1289,6 +1309,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     }
 
     fn resolve_local(&mut self, local: &'ast Local) {
+        debug!("resolving local ({:?})", local);
         // Resolve the type.
         walk_list!(self, visit_ty, &local.ty);
 
@@ -1390,7 +1411,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             if inconsistent_vars.contains_key(name) {
                 v.could_be_path = false;
             }
-            self.r.report_error(
+            self.report_error(
                 *v.origin.iter().next().unwrap(),
                 ResolutionError::VariableNotBoundInPattern(v),
             );
@@ -1400,7 +1421,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>();
         inconsistent_vars.sort();
         for (name, v) in inconsistent_vars {
-            self.r.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
+            self.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
         }
 
         // 5) Finally bubble up all the binding maps.
@@ -1550,7 +1571,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 // `Variant(a, a)`:
                 _ => IdentifierBoundMoreThanOnceInSamePattern,
             };
-            self.r.report_error(ident.span, error(ident.name));
+            self.report_error(ident.span, error(ident.name));
         }
 
         // Record as bound if it's valid:
@@ -1624,7 +1645,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 // to something unusable as a pattern (e.g., constructor function),
                 // but we still conservatively report an error, see
                 // issues/33118#issuecomment-233962221 for one reason why.
-                self.r.report_error(
+                self.report_error(
                     ident.span,
                     ResolutionError::BindingShadowsSomethingUnacceptable(
                         pat_src.descr(),
@@ -1677,18 +1698,27 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         source: PathSource<'ast>,
         crate_lint: CrateLint,
     ) -> PartialRes {
+        log::debug!("smart_resolve_path_fragment(id={:?},qself={:?},path={:?}", id, qself, path);
         let ns = source.namespace();
         let is_expected = &|res| source.is_expected(res);
 
         let report_errors = |this: &mut Self, res: Option<Res>| {
-            let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
-
-            let def_id = this.parent_scope.module.normal_ancestor_id;
-            let instead = res.is_some();
-            let suggestion =
-                if res.is_none() { this.report_missing_type_error(path) } else { None };
-
-            this.r.use_injections.push(UseError { err, candidates, def_id, instead, suggestion });
+            if this.should_report_errs() {
+                let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
+
+                let def_id = this.parent_scope.module.normal_ancestor_id;
+                let instead = res.is_some();
+                let suggestion =
+                    if res.is_none() { this.report_missing_type_error(path) } else { None };
+
+                this.r.use_injections.push(UseError {
+                    err,
+                    candidates,
+                    def_id,
+                    instead,
+                    suggestion,
+                });
+            }
 
             PartialRes::new(Res::Err)
         };
@@ -1746,13 +1776,17 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
             let def_id = this.parent_scope.module.normal_ancestor_id;
 
-            this.r.use_injections.push(UseError {
-                err,
-                candidates,
-                def_id,
-                instead: false,
-                suggestion: None,
-            });
+            if this.should_report_errs() {
+                this.r.use_injections.push(UseError {
+                    err,
+                    candidates,
+                    def_id,
+                    instead: false,
+                    suggestion: None,
+                });
+            } else {
+                err.cancel();
+            }
 
             // We don't return `Some(parent_err)` here, because the error will
             // be already printed as part of the `use` injections
@@ -1809,7 +1843,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
             Err(err) => {
                 if let Some(err) = report_errors_for_call(self, err) {
-                    self.r.report_error(err.span, err.node);
+                    self.report_error(err.span, err.node);
                 }
 
                 PartialRes::new(Res::Err)
@@ -1843,6 +1877,21 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
     }
 
+    /// A wrapper around [`Resolver::report_error`].
+    ///
+    /// This doesn't emit errors for function bodies if this is rustdoc.
+    fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) {
+        if self.should_report_errs() {
+            self.r.report_error(span, resolution_error);
+        }
+    }
+
+    #[inline]
+    /// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items.
+    fn should_report_errs(&self) -> bool {
+        !(self.r.session.opts.actually_rustdoc && self.in_func_body)
+    }
+
     // Resolve in alternative namespaces if resolution in the primary namespace fails.
     fn resolve_qpath_anywhere(
         &mut self,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index a222920c7d292..00315675fafe3 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -5,10 +5,15 @@ use rustc_driver::abort_on_err;
 use rustc_errors::emitter::{Emitter, EmitterWriter};
 use rustc_errors::json::JsonEmitter;
 use rustc_feature::UnstableFeatures;
-use rustc_hir::def::Namespace::TypeNS;
+use rustc_hir::def::{Namespace::TypeNS, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::HirId;
+use rustc_hir::{
+    intravisit::{self, NestedVisitorMap, Visitor},
+    Path,
+};
 use rustc_interface::interface;
+use rustc_middle::hir::map::Map;
 use rustc_middle::middle::cstore::CrateStore;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::{Ty, TyCtxt};
@@ -372,7 +377,35 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
         crate_name,
         lint_caps,
         register_lints: None,
-        override_queries: None,
+        override_queries: Some(|_sess, providers, _external_providers| {
+            // Most lints will require typechecking, so just don't run them.
+            providers.lint_mod = |_, _| {};
+            // Prevent `rustc_typeck::check_crate` from calling `typeck_tables_of` on all bodies.
+            providers.typeck_item_bodies = |_, _| {};
+            // hack so that `used_trait_imports` won't try to call typeck_tables_of
+            providers.used_trait_imports = |_, _| {
+                lazy_static! {
+                    static ref EMPTY_SET: FxHashSet<LocalDefId> = FxHashSet::default();
+                }
+                &EMPTY_SET
+            };
+            // In case typeck does end up being called, don't ICE in case there were name resolution errors
+            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).visit_body(body);
+                (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck_tables_of)(tcx, def_id)
+            };
+        }),
         registry: rustc_driver::diagnostics_registry(),
     };
 
@@ -416,10 +449,17 @@ 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| {
-                tcx.analysis(LOCAL_CRATE).ok();
-
-                // Abort if there were any errors so far
-                sess.abort_if_errors();
+                // Certain queries assume that some checks were run elsewhere
+                // (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425),
+                // so type-check everything other than function bodies in this crate before running lints.
+                // NOTE: this does not call `tcx.analysis()` so that we won't
+                // typeck function 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);
+                });
 
                 let access_levels = tcx.privacy_access_levels(LOCAL_CRATE);
                 // Convert from a HirId set to a DefId set since we don't always have easy access
@@ -570,6 +610,62 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
     })
 }
 
+/// Due to https://github.com/rust-lang/rust/pull/73566,
+/// 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<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> EmitIgnoredResolutionErrors<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>) -> Self {
+        Self { tcx }
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        // We need to recurse into nested closures,
+        // since those will fallback to the parent for type checking.
+        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    }
+
+    fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
+        debug!("visiting path {:?}", path);
+        if path.res == Res::Err {
+            // We have less context here than in rustc_resolve,
+            // so we can only emit the name and span.
+            // However we can give a hint that rustc_resolve will have more info.
+            let label = format!(
+                "could not resolve path `{}`",
+                path.segments
+                    .iter()
+                    .map(|segment| segment.ident.as_str().to_string())
+                    .collect::<Vec<_>>()
+                    .join("::")
+            );
+            let mut err = rustc_errors::struct_span_err!(
+                self.tcx.sess,
+                path.span,
+                E0433,
+                "failed to resolve: {}",
+                label
+            );
+            err.span_label(path.span, label);
+            err.note("this error was originally ignored because you are running `rustdoc`");
+            err.note("try running again with `rustc` or `cargo check` and you may get a more detailed error");
+            err.emit();
+        }
+        // We could have an outer resolution that succeeded,
+        // but with generic parameters that failed.
+        // Recurse into the segments so we catch those too.
+        intravisit::walk_path(self, path);
+    }
+}
+
 /// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter
 /// for `impl Trait` in argument position.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 57151e2b20002..cbf53d52ef009 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;
@@ -94,6 +96,7 @@ pub fn main() {
         32_000_000 // 32MB on other platforms
     };
     rustc_driver::set_sigpipe_handler();
+    rustc_driver::install_ice_hook();
     env_logger::init_from_env("RUSTDOC_LOG");
     let res = std::thread::Builder::new()
         .stack_size(thread_stack_size)
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 0000000000000..1176a4a8c4cf8
--- /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 0000000000000..112a2c494a5c2
--- /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 0000000000000..086db1be72274
--- /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` or `cargo check` 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 0000000000000..df40c121d579e
--- /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 0000000000000..4ee9c4d1f438d
--- /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` or `cargo check` 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/generic-argument.rs b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs
new file mode 100644
index 0000000000000..0ccf2e3866fc9
--- /dev/null
+++ b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs
@@ -0,0 +1,7 @@
+trait ValidTrait {}
+
+/// This has docs
+pub fn f() -> impl ValidTrait {
+    Vec::<DoesNotExist>::new()
+    //~^ ERROR failed to resolve
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr
new file mode 100644
index 0000000000000..72716c258dc1e
--- /dev/null
+++ b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr
@@ -0,0 +1,12 @@
+error[E0433]: failed to resolve: could not resolve path `DoesNotExist`
+  --> $DIR/generic-argument.rs:5:11
+   |
+LL |     Vec::<DoesNotExist>::new()
+   |           ^^^^^^^^^^^^ could not resolve path `DoesNotExist`
+   |
+   = note: this error was originally ignored because you are running `rustdoc`
+   = note: try running again with `rustc` or `cargo check` 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 0000000000000..399fb827517fa
--- /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 0000000000000..55f9b609a1105
--- /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` or `cargo check` 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 0000000000000..24b5734dbd0bf
--- /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 0000000000000..3257079f94219
--- /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` or `cargo check` 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 0000000000000..1498fa4f890d0
--- /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 0000000000000..84b28139dbcd5
--- /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` or `cargo check` 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 0000000000000..cf9bc48c7f872
--- /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 0000000000000..9be6a3d8d6bba
--- /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` or `cargo check` 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/impl-fn-nesting.rs b/src/test/rustdoc-ui/impl-fn-nesting.rs
new file mode 100644
index 0000000000000..a927f6bd79976
--- /dev/null
+++ b/src/test/rustdoc-ui/impl-fn-nesting.rs
@@ -0,0 +1,49 @@
+// Ensure that rustdoc gives errors for trait impls inside function bodies that don't resolve.
+// See https://github.com/rust-lang/rust/pull/73566
+pub struct ValidType;
+pub trait ValidTrait {}
+pub trait NeedsBody {
+    type Item;
+    fn f();
+}
+
+/// This function has docs
+pub fn f<B: UnknownBound>(a: UnknownType, b: B) {
+//~^ ERROR cannot find trait `UnknownBound` in this scope
+//~| ERROR cannot find type `UnknownType` in this scope
+    impl UnknownTrait for ValidType {} //~ ERROR cannot find trait `UnknownTrait`
+    impl<T: UnknownBound> UnknownTrait for T {}
+    //~^ ERROR cannot find trait `UnknownBound` in this scope
+    //~| ERROR cannot find trait `UnknownTrait` in this scope
+    impl ValidTrait for UnknownType {}
+    //~^ ERROR cannot find type `UnknownType` in this scope
+    impl ValidTrait for ValidType where ValidTrait: UnknownBound {}
+    //~^ ERROR cannot find trait `UnknownBound` in this scope
+
+    /// This impl has documentation
+    impl NeedsBody for ValidType {
+        type Item = UnknownType;
+        //~^ ERROR cannot find type `UnknownType` in this scope
+
+        /// This function has documentation
+        fn f() {
+            <UnknownTypeShouldBeIgnored>::a();
+            content::shouldnt::matter();
+            unknown_macro!();
+            //~^ ERROR cannot find macro `unknown_macro` in this scope
+
+            /// This is documentation for a macro
+            macro_rules! can_define_macros_here_too {
+                () => {
+                    this::content::should::also::be::ignored()
+                }
+            }
+            can_define_macros_here_too!();
+
+            /// This also is documented.
+            pub fn doubly_nested(c: UnknownType) {
+            //~^ ERROR cannot find type `UnknownType` in this scope
+            }
+        }
+    }
+}
diff --git a/src/test/rustdoc-ui/impl-fn-nesting.stderr b/src/test/rustdoc-ui/impl-fn-nesting.stderr
new file mode 100644
index 0000000000000..608749af895ed
--- /dev/null
+++ b/src/test/rustdoc-ui/impl-fn-nesting.stderr
@@ -0,0 +1,66 @@
+error: cannot find macro `unknown_macro` in this scope
+  --> $DIR/impl-fn-nesting.rs:32:13
+   |
+LL |             unknown_macro!();
+   |             ^^^^^^^^^^^^^
+
+error[E0405]: cannot find trait `UnknownBound` in this scope
+  --> $DIR/impl-fn-nesting.rs:11:13
+   |
+LL | pub fn f<B: UnknownBound>(a: UnknownType, b: B) {
+   |             ^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `UnknownType` in this scope
+  --> $DIR/impl-fn-nesting.rs:11:30
+   |
+LL | pub fn f<B: UnknownBound>(a: UnknownType, b: B) {
+   |                              ^^^^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `UnknownTrait` in this scope
+  --> $DIR/impl-fn-nesting.rs:14:10
+   |
+LL |     impl UnknownTrait for ValidType {}
+   |          ^^^^^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `UnknownTrait` in this scope
+  --> $DIR/impl-fn-nesting.rs:15:27
+   |
+LL |     impl<T: UnknownBound> UnknownTrait for T {}
+   |                           ^^^^^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `UnknownBound` in this scope
+  --> $DIR/impl-fn-nesting.rs:15:13
+   |
+LL |     impl<T: UnknownBound> UnknownTrait for T {}
+   |             ^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `UnknownType` in this scope
+  --> $DIR/impl-fn-nesting.rs:18:25
+   |
+LL |     impl ValidTrait for UnknownType {}
+   |                         ^^^^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `UnknownBound` in this scope
+  --> $DIR/impl-fn-nesting.rs:20:53
+   |
+LL |     impl ValidTrait for ValidType where ValidTrait: UnknownBound {}
+   |                                                     ^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `UnknownType` in this scope
+  --> $DIR/impl-fn-nesting.rs:25:21
+   |
+LL |         type Item = UnknownType;
+   |                     ^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `UnknownType` in this scope
+  --> $DIR/impl-fn-nesting.rs:44:37
+   |
+LL |             pub fn doubly_nested(c: UnknownType) {
+   |                                     ^^^^^^^^^^^ not found in this scope
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0405, E0412.
+For more information about an error, try `rustc --explain E0405`.
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 0000000000000..32793fc4f76c0
--- /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 0000000000000..897445f200cb7
--- /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`.
diff --git a/src/test/rustdoc/impl-trait-alias.rs b/src/test/rustdoc/impl-trait-alias.rs
new file mode 100644
index 0000000000000..54c3f856ddb3c
--- /dev/null
+++ b/src/test/rustdoc/impl-trait-alias.rs
@@ -0,0 +1,14 @@
+#![feature(type_alias_impl_trait)]
+
+trait MyTrait {}
+impl MyTrait for i32 {}
+
+// @has impl_trait_alias/type.Foo.html 'Foo'
+/// debug type
+pub type Foo = impl MyTrait;
+
+// @has impl_trait_alias/fn.foo.html 'foo'
+/// debug function
+pub fn foo() -> Foo {
+    1
+}
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..b4411d927e271 100644
--- a/src/test/rustdoc/macro-in-closure.rs
+++ b/src/test/rustdoc/macro-in-closure.rs
@@ -6,4 +6,11 @@ fn main() {
     || {
         macro m() {}
     };
+
+    let _ = || {
+        macro n() {}
+    };
+
+    let cond = true;
+    let _ = || if cond { macro n() {} } else { panic!() };
 }
diff --git a/src/test/rustdoc/return-impl-trait.rs b/src/test/rustdoc/return-impl-trait.rs
new file mode 100644
index 0000000000000..1ccf5ac46119a
--- /dev/null
+++ b/src/test/rustdoc/return-impl-trait.rs
@@ -0,0 +1,15 @@
+#![feature(type_alias_impl_trait)]
+
+pub trait Backend {}
+
+impl Backend for () {}
+
+pub struct Module<T>(T);
+
+pub type BackendImpl = impl Backend;
+
+// @has return_impl_trait/fn.make_module.html
+/// Documentation
+pub fn make_module() -> Module<BackendImpl> {
+    Module(())
+}