From 393564b3bbdab0c66290768e8cc144caf7880dd5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 Jan 2023 09:36:05 +0000 Subject: [PATCH 1/7] Remove a dummy use of LazyLock --- src/librustdoc/core.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 10b606f425ea4..1df34e90a76b9 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -6,7 +6,7 @@ use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::json::JsonEmitter; use rustc_feature::UnstableFeatures; use rustc_hir::def::{Namespace, Res}; -use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId}; +use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{HirId, Path, TraitCandidate}; use rustc_interface::interface; @@ -22,7 +22,6 @@ use rustc_span::{source_map, Span, Symbol}; use std::cell::RefCell; use std::mem; use std::rc::Rc; -use std::sync::LazyLock; use crate::clean::inline::build_external_trait; use crate::clean::{self, ItemId}; @@ -284,10 +283,7 @@ pub(crate) fn create_config( // Prevent `rustc_hir_analysis::check_crate` from calling `typeck` on all bodies. providers.typeck_item_bodies = |_, _| {}; // hack so that `used_trait_imports` won't try to call typeck - providers.used_trait_imports = |_, _| { - static EMPTY_SET: LazyLock> = LazyLock::new(UnordSet::default); - &EMPTY_SET - }; + providers.used_trait_imports = |_, _| Box::leak(Box::new(UnordSet::default())); // In case typeck does end up being called, don't ICE in case there were name resolution errors providers.typeck = move |tcx, def_id| { // Closures' tables come from their outermost function, From 8f383fbe8b6125b88a2fd73f7306c03853ce3023 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 Jan 2023 09:51:23 +0000 Subject: [PATCH 2/7] Avoid wf checking item signatures in rustdoc --- compiler/rustc_hir_analysis/src/check/check.rs | 8 -------- src/librustdoc/core.rs | 10 +++------- tests/rustdoc-ui/issue-79494.rs | 3 ++- tests/rustdoc-ui/issue-79494.stderr | 12 ------------ tests/rustdoc-ui/track-diagnostics.rs | 6 +----- tests/rustdoc-ui/track-diagnostics.stderr | 10 ---------- tests/rustdoc/issue-96381.rs | 3 --- 7 files changed, 6 insertions(+), 46 deletions(-) delete mode 100644 tests/rustdoc-ui/issue-79494.stderr delete mode 100644 tests/rustdoc-ui/track-diagnostics.stderr diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index abc1c2d7b8d17..31cea96abef26 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -219,14 +219,6 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) { return; }; - // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting - // `async-std` (and `pub async fn` in general). - // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it! - // See https://github.com/rust-lang/rust/issues/75100 - if tcx.sess.opts.actually_rustdoc { - return; - } - let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id()); let span = tcx.def_span(item.owner_id.def_id); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 1df34e90a76b9..f5b8b5c2fdc57 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -282,6 +282,8 @@ pub(crate) fn create_config( providers.lint_mod = |_, _| {}; // Prevent `rustc_hir_analysis::check_crate` from calling `typeck` on all bodies. providers.typeck_item_bodies = |_, _| {}; + providers.check_mod_item_types = + |_, _| panic!("check_mod_item_types should not get called at all in rustdoc"); // hack so that `used_trait_imports` won't try to call typeck providers.used_trait_imports = |_, _| Box::leak(Box::new(UnordSet::default())); // In case typeck does end up being called, don't ICE in case there were name resolution errors @@ -322,14 +324,8 @@ pub(crate) fn run_global_ctxt( // typeck function bodies or run the default rustc lints. // (see `override_queries` in the `config`) - // HACK(jynelson) this calls an _extremely_ limited subset of `typeck` + // HACK(jynelson) this calls an _extremely_ limited subset of what the `analysis` query does // and might break if queries change their assumptions in the future. - - // NOTE: This is copy/pasted from typeck/lib.rs and should be kept in sync with those changes. - tcx.sess.time("item_types_checking", || { - tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) - }); - tcx.sess.abort_if_errors(); tcx.sess.time("missing_docs", || { rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new); }); diff --git a/tests/rustdoc-ui/issue-79494.rs b/tests/rustdoc-ui/issue-79494.rs index fc39424b793f6..bcce46778469a 100644 --- a/tests/rustdoc-ui/issue-79494.rs +++ b/tests/rustdoc-ui/issue-79494.rs @@ -1,5 +1,6 @@ // only-x86_64-unknown-linux-gnu +// check-pass #![feature(const_transmute)] -const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; //~ ERROR cannot transmute between types of different sizes, or dependently-sized types +const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; diff --git a/tests/rustdoc-ui/issue-79494.stderr b/tests/rustdoc-ui/issue-79494.stderr deleted file mode 100644 index 7ed5ed3824716..0000000000000 --- a/tests/rustdoc-ui/issue-79494.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/issue-79494.rs:5:29 - | -LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^ - | - = note: source type: `usize` (64 bits) - = note: target type: `&[u8]` (128 bits) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0512`. diff --git a/tests/rustdoc-ui/track-diagnostics.rs b/tests/rustdoc-ui/track-diagnostics.rs index fcc50a7aba07d..5736d7d4f18f7 100644 --- a/tests/rustdoc-ui/track-diagnostics.rs +++ b/tests/rustdoc-ui/track-diagnostics.rs @@ -1,9 +1,5 @@ // compile-flags: -Z track-diagnostics -// error-pattern: created at - -// Normalize the emitted location so this doesn't need -// updating everytime someone adds or removes a line. -// normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC" +// check-pass struct A; struct B; diff --git a/tests/rustdoc-ui/track-diagnostics.stderr b/tests/rustdoc-ui/track-diagnostics.stderr deleted file mode 100644 index ec30318625311..0000000000000 --- a/tests/rustdoc-ui/track-diagnostics.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/track-diagnostics.rs:LL:CC - | -LL | const S: A = B; - | ^ expected struct `A`, found struct `B` --Ztrack-diagnostics: created at compiler/rustc_infer/src/infer/error_reporting/mod.rs:LL:CC - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/rustdoc/issue-96381.rs b/tests/rustdoc/issue-96381.rs index f0f123f85a03f..e43a1fd4a3fe0 100644 --- a/tests/rustdoc/issue-96381.rs +++ b/tests/rustdoc/issue-96381.rs @@ -1,5 +1,3 @@ -// should-fail - #![allow(unused)] trait Foo: Sized { @@ -8,7 +6,6 @@ trait Foo: Sized { impl Foo for () { fn bar(i: _, t: _, s: _) -> _ { - //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions (1, 2) } } From 6781998fdd5bbe52b0a6fc92d0fec21ae9db1beb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 Jan 2023 10:05:45 +0000 Subject: [PATCH 3/7] prefer `mem::take` over `mem::replace(.., Default::default())` --- compiler/rustc_errors/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 535812fb0e228..fa7e65ee550a5 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -511,7 +511,7 @@ impl Drop for HandlerInner { self.emit_stashed_diagnostics(); if !self.has_errors() { - let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new()); + let bugs = std::mem::take(&mut self.delayed_span_bugs); self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued"); } @@ -521,7 +521,7 @@ impl Drop for HandlerInner { // lints can be `#[allow]`'d, potentially leading to this triggering. // Also, "good path" should be replaced with a better naming. if !self.has_any_message() && !self.suppressed_expected_diag { - let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new()); + let bugs = std::mem::take(&mut self.delayed_good_path_bugs); self.flush_delayed( bugs, "no warnings or errors encountered even though `delayed_good_path_bugs` issued", @@ -1231,7 +1231,7 @@ impl Handler { pub fn flush_delayed(&self) { let mut inner = self.inner.lock(); - let bugs = std::mem::replace(&mut inner.delayed_span_bugs, Vec::new()); + let bugs = std::mem::take(&mut inner.delayed_span_bugs); inner.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued"); } } From c77ee070aa0d83ec34b64b8c4468cef32cbb7c97 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 Jan 2023 10:06:14 +0000 Subject: [PATCH 4/7] Remove more uses of `actually_rustdoc` by hiding delayed bugs in rustdoc --- compiler/rustc_errors/src/lib.rs | 13 ++++++++++ .../src/traits/query/normalize.rs | 24 +++++++------------ src/librustdoc/lib.rs | 8 ++++++- tests/{rustdoc => rustdoc-ui}/issue-96381.rs | 2 ++ 4 files changed, 30 insertions(+), 17 deletions(-) rename tests/{rustdoc => rustdoc-ui}/issue-96381.rs (92%) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index fa7e65ee550a5..c34886d039734 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -661,6 +661,19 @@ impl Handler { inner.stashed_diagnostics = Default::default(); } + /// Avoid failing compilation in the presence of delayed bugs. + /// + /// NOTE: *do not* call this function from rustc. It is only meant to be called from rustdoc. + /// Rustdoc documents multiple targets at once, meaning there may be multiple versions + /// of the same function in scope at the same time, which isn't legal Rust otherwise. See + /// https://doc.rust-lang.org/beta/rustdoc/advanced-features.html#interactions-between-platform-specific-docs + /// for details + pub fn reset_delayed_bugs(&self) { + let mut inner = self.inner.borrow_mut(); + inner.delayed_span_bugs = Default::default(); + inner.delayed_good_path_bugs = Default::default(); + } + /// Stash a given diagnostic with the given `Span` and [`StashKey`] as the key. /// Retrieve a stashed diagnostic with `steal_diagnostic`. pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 27247271d1f4d..756668c4870cb 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -262,14 +262,10 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let result = tcx.normalize_projection_ty(c_data)?; // We don't expect ambiguity. if result.is_ambiguous() { - // Rustdoc normalizes possibly not well-formed types, so only - // treat this as a bug if we're not in rustdoc. - if !tcx.sess.opts.actually_rustdoc { - tcx.sess.delay_span_bug( - DUMMY_SP, - format!("unexpected ambiguity: {:?} {:?}", c_data, result), - ); - } + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("unexpected ambiguity: {:?} {:?}", c_data, result), + ); return Err(NoSolution); } let InferOk { value: result, obligations } = @@ -313,14 +309,10 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let result = tcx.normalize_projection_ty(c_data)?; // We don't expect ambiguity. if result.is_ambiguous() { - // Rustdoc normalizes possibly not well-formed types, so only - // treat this as a bug if we're not in rustdoc. - if !tcx.sess.opts.actually_rustdoc { - tcx.sess.delay_span_bug( - DUMMY_SP, - format!("unexpected ambiguity: {:?} {:?}", c_data, result), - ); - } + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("unexpected ambiguity: {:?} {:?}", c_data, result), + ); return Err(NoSolution); } let InferOk { value: result, obligations } = diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 86454e1f2eb73..460c47207bafc 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -862,6 +862,12 @@ fn main_args(at_args: &[String]) -> MainResult { }), } }) - }) + })?; + // than ICEing. Rustdoc documents multiple targets at once, meaning there may be multiple versions + // of the same function in scope at the same time, which isn't legal Rust otherwise. See + // https://doc.rust-lang.org/beta/rustdoc/advanced-features.html#interactions-between-platform-specific-docs + // for details + sess.diagnostic().reset_delayed_bugs(); + Ok(()) }) } diff --git a/tests/rustdoc/issue-96381.rs b/tests/rustdoc-ui/issue-96381.rs similarity index 92% rename from tests/rustdoc/issue-96381.rs rename to tests/rustdoc-ui/issue-96381.rs index e43a1fd4a3fe0..a36acf472ce97 100644 --- a/tests/rustdoc/issue-96381.rs +++ b/tests/rustdoc-ui/issue-96381.rs @@ -1,5 +1,7 @@ #![allow(unused)] +// check-pass + trait Foo: Sized { fn bar(i: i32, t: T, s: &Self) -> (T, i32); } From 1e60d58f541bb9c8c74c29c7827c1e604f4d7a78 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 Jan 2023 10:32:45 +0000 Subject: [PATCH 5/7] Remove another `actually_rustdoc` usage --- compiler/rustc_privacy/src/lib.rs | 6 +----- src/librustdoc/core.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9a5d3cceb914e..85618745331b5 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -692,11 +692,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // The interface is empty. hir::ItemKind::GlobalAsm(..) => {} hir::ItemKind::OpaqueTy(ref opaque) => { - // HACK(jynelson): trying to infer the type of `impl trait` breaks `async-std` (and `pub async fn` in general) - // Since rustdoc never needs to do codegen and doesn't care about link-time reachability, - // mark this as unreachable. - // See https://github.com/rust-lang/rust/issues/75100 - if !opaque.in_trait && !self.tcx.sess.opts.actually_rustdoc { + if !opaque.in_trait { // FIXME: This is some serious pessimization intended to workaround deficiencies // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time // reachable if they are returned via `impl Trait`, even from private functions. diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index f5b8b5c2fdc57..02777eccff63c 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -302,6 +302,21 @@ pub(crate) fn create_config( EmitIgnoredResolutionErrors::new(tcx).visit_body(body); (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id) }; + providers.type_of = |tcx, def_id| { + let did = def_id.expect_local(); + use rustc_hir::*; + + let hir_id = tcx.hir().local_def_id_to_hir_id(did); + + match tcx.hir().get(hir_id) { + Node::Item(item) => match item.kind { + ItemKind::OpaqueTy(_) => return tcx.ty_error(), + _ => {} + }, + _ => {} + } + (rustc_interface::DEFAULT_QUERY_PROVIDERS.type_of)(tcx, def_id) + }; }), make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), From af249016a74d04cc83fbf71dc736bdf3be4e75a7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 Jan 2023 10:43:48 +0000 Subject: [PATCH 6/7] Replace a query in rustdoc instead of using actually_rustdoc within. --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 6 +--- .../rustc_codegen_ssa/src/target_features.rs | 29 +------------------ src/librustdoc/core.rs | 7 +++++ 3 files changed, 9 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 8808ad2dcd135..451ef186fea73 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -268,7 +268,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { if !tcx.is_closure(did.to_def_id()) && tcx.fn_sig(did).unsafety() == hir::Unsafety::Normal { - if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { + if tcx.sess.target.is_like_wasm { // The `#[target_feature]` attribute is allowed on // WebAssembly targets on all functions, including safe // ones. Other targets require that `#[target_feature]` is @@ -282,10 +282,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { // deterministic trap. There is no undefined behavior when // executing WebAssembly so `#[target_feature]` is allowed // on safe functions (but again, only for WebAssembly) - // - // Note that this is also allowed if `actually_rustdoc` so - // if a target is documenting some wasm-specific code then - // it's not spuriously denied. } else if !tcx.features().target_feature_11 { let mut err = feature_err( &tcx.sess.parse_sess, diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 739963fffd132..67e2751b0e4a6 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -293,24 +293,6 @@ const WASM_ALLOWED_FEATURES: &[(&str, Option)] = &[ const BPF_ALLOWED_FEATURES: &[(&str, Option)] = &[("alu32", Some(sym::bpf_target_feature))]; -/// When rustdoc is running, provide a list of all known features so that all their respective -/// primitives may be documented. -/// -/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator! -pub fn all_known_features() -> impl Iterator)> { - std::iter::empty() - .chain(ARM_ALLOWED_FEATURES.iter()) - .chain(AARCH64_ALLOWED_FEATURES.iter()) - .chain(X86_ALLOWED_FEATURES.iter()) - .chain(HEXAGON_ALLOWED_FEATURES.iter()) - .chain(POWERPC_ALLOWED_FEATURES.iter()) - .chain(MIPS_ALLOWED_FEATURES.iter()) - .chain(RISCV_ALLOWED_FEATURES.iter()) - .chain(WASM_ALLOWED_FEATURES.iter()) - .chain(BPF_ALLOWED_FEATURES.iter()) - .cloned() -} - pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option)] { match &*sess.target.arch { "arm" => ARM_ALLOWED_FEATURES, @@ -462,16 +444,7 @@ pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { supported_target_features: |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - if tcx.sess.opts.actually_rustdoc { - // rustdoc needs to be able to document functions that use all the features, so - // whitelist them all - all_known_features().map(|(a, b)| (a.to_string(), b)).collect() - } else { - supported_target_features(tcx.sess) - .iter() - .map(|&(a, b)| (a.to_string(), b)) - .collect() - } + supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect() }, asm_target_features, ..*providers diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 02777eccff63c..5db0fd8db3b61 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -11,6 +11,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{HirId, Path, TraitCandidate}; use rustc_interface::interface; use rustc_middle::hir::nested_filter; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_resolve as resolve; use rustc_session::config::{self, CrateType, ErrorOutputType}; @@ -317,6 +318,12 @@ pub(crate) fn create_config( } (rustc_interface::DEFAULT_QUERY_PROVIDERS.type_of)(tcx, def_id) }; + providers.codegen_fn_attrs = |_, did| { + assert!(did.is_local()); + CodegenFnAttrs::new() + }; + providers.supported_target_features = + |_, _| panic!("supported_target_features should not get called by rustdoc"); }), make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), From 100fed7d50242bc716d3f6a00dd4c87fb38eb634 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 Jan 2023 12:59:38 +0000 Subject: [PATCH 7/7] Make url in documentation actually be a markdown url --- compiler/rustc_errors/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index c34886d039734..f3229dfa33ae2 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -666,7 +666,7 @@ impl Handler { /// NOTE: *do not* call this function from rustc. It is only meant to be called from rustdoc. /// Rustdoc documents multiple targets at once, meaning there may be multiple versions /// of the same function in scope at the same time, which isn't legal Rust otherwise. See - /// https://doc.rust-lang.org/beta/rustdoc/advanced-features.html#interactions-between-platform-specific-docs + /// /// for details pub fn reset_delayed_bugs(&self) { let mut inner = self.inner.borrow_mut();