Skip to content

Commit bb45796

Browse files
authored
Unrolled build for #151120
Rollup merge of #151120 - ice-deprecated-note-on-reexport, r=lolbinarycat Fix deprecated attribute intra-doc link not resolved in the right location on reexported item Fixes #151028. Follow-up of #150721. So when we resolve an intra-doc link, its current context (the module from which we resolve in short) is very important. However, when we use an intra-doc link in a `#[deprecated]` attribute on a reexported item, we were using the context of the reexported item and not of the `use` itself. Meaning that if you have an intra-doc link `std::mem::drop` on an item from another crate (let's say `core`), then the import will simply fail since there is no `std` dependency. Now comes the not so funny fix: at this point, we don't know anymore where the attribute came from (ie, from the reexport or from the reexported item) since we already merged the attribute at this point. The solution I found to go around this problem is to check if the item span contains the attribute, and if not, then we use the `inline_stmt_id` as context instead of the item's ID. I'm not super happy and I'm sure we'll find corner cases in the future (like with macros), however there are a few things that mitigate this fix: 1. The only way to generate an attribute with a macro with its item while having different spans is by using proc-macros. In that case, we can always default to the `inline_stmt_id` as context and be fine, but I guess we'll see when get there. 2. It only concerns reexports, so the area of the problem is quite restricted. Hopefully this explanation made sense. :) cc @folkertdev r? @lolbinarycat
2 parents 1a9f168 + c341745 commit bb45796

File tree

2 files changed

+36
-7
lines changed

2 files changed

+36
-7
lines changed

src/librustdoc/passes/collect_intra_doc_links.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use std::fmt::Display;
77
use std::mem;
88
use std::ops::Range;
99

10-
use rustc_ast::attr::AttributeExt;
1110
use rustc_ast::util::comments::may_have_doc_links;
1211
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
1312
use rustc_data_structures::intern::Interned;
@@ -1062,20 +1061,21 @@ fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> {
10621061
impl LinkCollector<'_, '_> {
10631062
#[instrument(level = "debug", skip_all)]
10641063
fn resolve_links(&mut self, item: &Item) {
1064+
let tcx = self.cx.tcx;
10651065
if !self.cx.document_private()
10661066
&& let Some(def_id) = item.item_id.as_def_id()
10671067
&& let Some(def_id) = def_id.as_local()
1068-
&& !self.cx.tcx.effective_visibilities(()).is_exported(def_id)
1068+
&& !tcx.effective_visibilities(()).is_exported(def_id)
10691069
&& !has_primitive_or_keyword_or_attribute_docs(&item.attrs.other_attrs)
10701070
{
10711071
// Skip link resolution for non-exported items.
10721072
return;
10731073
}
10741074

10751075
let mut insert_links = |item_id, doc: &str| {
1076-
let module_id = match self.cx.tcx.def_kind(item_id) {
1077-
DefKind::Mod if item.inner_docs(self.cx.tcx) => item_id,
1078-
_ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(),
1076+
let module_id = match tcx.def_kind(item_id) {
1077+
DefKind::Mod if item.inner_docs(tcx) => item_id,
1078+
_ => find_nearest_parent_module(tcx, item_id).unwrap(),
10791079
};
10801080
for md_link in preprocessed_markdown_links(&doc) {
10811081
let link = self.resolve_link(&doc, item, item_id, module_id, &md_link);
@@ -1108,15 +1108,33 @@ impl LinkCollector<'_, '_> {
11081108

11091109
// Also resolve links in the note text of `#[deprecated]`.
11101110
for attr in &item.attrs.other_attrs {
1111-
let Some(note_sym) = attr.deprecation_note() else { continue };
1111+
let rustc_hir::Attribute::Parsed(rustc_hir::attrs::AttributeKind::Deprecation {
1112+
span,
1113+
deprecation,
1114+
}) = attr
1115+
else {
1116+
continue;
1117+
};
1118+
let Some(note_sym) = deprecation.note else { continue };
11121119
let note = note_sym.as_str();
11131120

11141121
if !may_have_doc_links(note) {
11151122
continue;
11161123
}
11171124

11181125
debug!("deprecated_note={note}");
1119-
insert_links(item.item_id.expect_def_id(), note)
1126+
// When resolving an intra-doc link inside a deprecation note that is on an inlined
1127+
// `use` statement, we need to use the `def_id` of the `use` statement, not the
1128+
// inlined item.
1129+
// <https://github.com/rust-lang/rust/pull/151120>
1130+
let item_id = if let Some(inline_stmt_id) = item.inline_stmt_id
1131+
&& item.span(tcx).is_none_or(|item_span| !item_span.inner().contains(*span))
1132+
{
1133+
inline_stmt_id.to_def_id()
1134+
} else {
1135+
item.item_id.expect_def_id()
1136+
};
1137+
insert_links(item_id, note)
11201138
}
11211139
}
11221140

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// This test ensures that the intra-doc link in `deprecated` note is resolved at the correct
2+
// location (ie in the current crate and not in the reexported item's location/crate) and
3+
// therefore doesn't crash.
4+
//
5+
// This is a regression test for <https://github.com/rust-lang/rust/issues/151028>.
6+
7+
#![crate_name = "foo"]
8+
9+
#[deprecated(note = "use [`std::mem::forget`]")]
10+
#[doc(inline)]
11+
pub use std::mem::drop;

0 commit comments

Comments
 (0)