diff options
| author | bors <bors@rust-lang.org> | 2023-07-25 01:35:53 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-07-25 01:35:53 +0000 |
| commit | beef07fe8fb98aca9f2b59c6a1b3e4f3ea4c0e15 (patch) | |
| tree | b72f5884ddfaaf089b8e01ca754424161eec815b /src | |
| parent | 1821920cc8e7dc44b0035da890170bf3eadc2ae9 (diff) | |
| parent | 637ea3f746236611fc5451cfc97c976650c20218 (diff) | |
| download | rust-beef07fe8fb98aca9f2b59c6a1b3e4f3ea4c0e15.tar.gz rust-beef07fe8fb98aca9f2b59c6a1b3e4f3ea4c0e15.zip | |
Auto merge of #113958 - lukas-code:doc-links, r=GuillaumeGomez,petrochenkov
fix intra-doc links on nested `use` and `extern crate` items
This PR fixes two rustdoc ICEs that happen if there are any intra-doc links on nested `use` or `extern crate` items, for example:
```rust
/// Re-export [`fmt`] and [`io`].
pub use std::{fmt, io}; // "nested" use = use with braces
/// Re-export [`std`].
pub extern crate std;
```
Nested use items were incorrectly considered private and therefore didn't have their intra-doc links resolved. I fixed this by always resolving intra-doc links for nested `use` items that are declared `pub`.
<details>
During AST->HIR lowering, nested `use` items are desugared like this:
```rust
pub use std::{}; // "list stem"
pub use std::fmt;
pub use std::io;
```
Each of these HIR nodes has it's own effective visibility and the list stem is always considered private.
To check the effective visibility of an AST node, the AST node is mapped to a HIR node with `Resolver::local_def_id`, which returns the (private) list stem for nested use items.
</details>
For `extern crate`, there was a hack in rustdoc that stored the `DefId` of the crate itself in the cleaned item, instead of the `DefId` of the `extern crate` item. This made rustdoc look at the resolved links of the extern crate's crate root instead of the `extern crate` item. I've removed this hack and instead translate the `DefId` in the appropriate places.
As as side effect of fixing `extern crate`, i've turned
```rust
#[doc(masked)]
extern crate self as _;
```
into a no-op instead of hiding all trait impls. Proper verification for `doc(masked)` is included as a bonus.
fixes https://github.com/rust-lang/rust/issues/113896
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustdoc/clean/mod.rs | 15 | ||||
| -rw-r--r-- | src/librustdoc/clean/utils.rs | 12 | ||||
| -rw-r--r-- | src/librustdoc/html/format.rs | 10 | ||||
| -rw-r--r-- | src/librustdoc/passes/collect_intra_doc_links.rs | 10 |
4 files changed, 31 insertions, 16 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d14953f1bb7..440874df14c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2643,15 +2643,12 @@ fn clean_extern_crate<'tcx>( } } - // FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason - vec![Item { - name: Some(name), - attrs: Box::new(Attributes::from_ast(attrs)), - item_id: crate_def_id.into(), - kind: Box::new(ExternCrateItem { src: orig_name }), - cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), - inline_stmt_id: Some(krate_owner_def_id), - }] + vec![Item::from_def_id_and_parts( + krate_owner_def_id, + Some(name), + ExternCrateItem { src: orig_name }, + cx, + )] } fn clean_use_statement<'tcx>( diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index df9da9e7c7f..5c8db3b8774 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -38,11 +38,15 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { for it in &module.items { // `compiler_builtins` should be masked too, but we can't apply // `#[doc(masked)]` to the injected `extern crate` because it's unstable. - if it.is_extern_crate() - && (it.attrs.has_doc_flag(sym::masked) - || cx.tcx.is_compiler_builtins(it.item_id.krate())) - { + if cx.tcx.is_compiler_builtins(it.item_id.krate()) { cx.cache.masked_crates.insert(it.item_id.krate()); + } else if it.is_extern_crate() + && it.attrs.has_doc_flag(sym::masked) + && let Some(def_id) = it.item_id.as_def_id() + && let Some(local_def_id) = def_id.as_local() + && let Some(cnum) = cx.tcx.extern_mod_stmt_cnum(local_def_id) + { + cx.cache.masked_crates.insert(cnum); } } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 1099c68b004..f60f40267d6 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -18,7 +18,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_metadata::creader::{CStore, LoadedMacro}; use rustc_middle::ty; use rustc_middle::ty::TyCtxt; @@ -662,6 +662,14 @@ pub(crate) fn href_with_root_path( // documented on their parent's page tcx.parent(did) } + DefKind::ExternCrate => { + // Link to the crate itself, not the `extern crate` item. + if let Some(local_did) = did.as_local() { + tcx.extern_mod_stmt_cnum(local_did).unwrap_or(LOCAL_CRATE).as_def_id() + } else { + did + } + } _ => did, }; let cache = cx.cache(); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 91f3729bfa2..4de30e4ed9d 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -14,7 +14,7 @@ use rustc_hir::def::{DefKind, Namespace, PerNS}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::Mutability; use rustc_middle::ty::{Ty, TyCtxt}; -use rustc_middle::{bug, ty}; +use rustc_middle::{bug, span_bug, ty}; use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution}; use rustc_resolve::rustdoc::{strip_generics_from_path, MalformedGenerics}; use rustc_session::lint::Lint; @@ -402,7 +402,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // `doc_link_resolutions` is missing a `path_str`, that means that there are valid links // that are being missed. To fix the ICE, change // `rustc_resolve::rustdoc::attrs_to_preprocessed_links` to cache the link. - .unwrap_or_else(|| panic!("no resolution for {:?} {:?} {:?}", path_str, ns, module_id)) + .unwrap_or_else(|| { + span_bug!( + self.cx.tcx.def_span(item_id), + "no resolution for {path_str:?} {ns:?} {module_id:?}", + ) + }) .and_then(|res| res.try_into().ok()) .or_else(|| resolve_primitive(path_str, ns)); debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); @@ -963,6 +968,7 @@ fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> { } impl LinkCollector<'_, '_> { + #[instrument(level = "debug", skip_all)] fn resolve_links(&mut self, item: &Item) { if !self.cx.render_options.document_private && let Some(def_id) = item.item_id.as_def_id() |
