Skip to content

Commit 1dad788

Browse files
Fix ICE for intra-doc link on intermediate re-export
1 parent 84dd6df commit 1dad788

File tree

2 files changed

+80
-35
lines changed

2 files changed

+80
-35
lines changed

src/librustdoc/clean/mod.rs

+44-20
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ use std::hash::Hash;
3939
use std::mem;
4040
use thin_vec::ThinVec;
4141

42-
use crate::clean::inline::merge_attrs;
4342
use crate::core::{self, DocContext, ImplTraitParam};
4443
use crate::formats::item_type::ItemType;
4544
use crate::visit_ast::Module as DocModule;
@@ -2168,32 +2167,40 @@ impl<'hir> hir::intravisit::Visitor<'hir> for OneLevelVisitor<'hir> {
21682167
/// documentation. Otherwise, we repeat the same operation until we find the "end item".
21692168
fn get_all_import_attributes<'hir>(
21702169
mut item: &hir::Item<'hir>,
2171-
tcx: TyCtxt<'hir>,
2170+
cx: &mut DocContext<'hir>,
21722171
target_def_id: LocalDefId,
2173-
attributes: &mut Vec<ast::Attribute>,
21742172
is_inline: bool,
2175-
) {
2173+
mut prev_import: LocalDefId,
2174+
) -> Vec<(ast::Attribute, Option<DefId>)> {
2175+
let mut attributes: Vec<(ast::Attribute, Option<DefId>)> = Vec::new();
21762176
let mut first = true;
2177-
let hir_map = tcx.hir();
2177+
let hir_map = cx.tcx.hir();
21782178
let mut visitor = OneLevelVisitor::new(hir_map, target_def_id);
21792179
let mut visited = FxHashSet::default();
2180+
let mut import_attrs = Vec::new();
21802181

21812182
// If the item is an import and has at least a path with two parts, we go into it.
21822183
while let hir::ItemKind::Use(path, _) = item.kind && visited.insert(item.hir_id()) {
2184+
let import_parent = cx.tcx.opt_local_parent(prev_import).map(|def_id| def_id.to_def_id());
21832185
if first {
21842186
// This is the "original" reexport so we get all its attributes without filtering them.
2185-
attributes.extend_from_slice(hir_map.attrs(item.hir_id()));
2187+
attributes = hir_map.attrs(item.hir_id()).iter().cloned().map(|attr| (attr, import_parent)).collect::<Vec<_>>();
21862188
first = false;
21872189
} else {
2188-
add_without_unwanted_attributes(attributes, hir_map.attrs(item.hir_id()), is_inline);
2190+
add_without_unwanted_attributes(&mut import_attrs, hir_map.attrs(item.hir_id()), is_inline);
2191+
for attr in import_attrs.drain(..) {
2192+
attributes.push((attr, import_parent));
2193+
}
21892194
}
21902195

2191-
if let Some(i) = visitor.find_target(tcx, item.owner_id.def_id.to_def_id(), path) {
2196+
if let Some(i) = visitor.find_target(cx.tcx, item.owner_id.def_id.to_def_id(), path) {
21922197
item = i;
21932198
} else {
21942199
break;
21952200
}
2201+
prev_import = item.owner_id.def_id;
21962202
}
2203+
attributes
21972204
}
21982205

21992206
fn filter_tokens_from_list(
@@ -2244,7 +2251,7 @@ fn add_without_unwanted_attributes(
22442251
new_attrs: &[ast::Attribute],
22452252
is_inline: bool,
22462253
) {
2247-
// If it's `#[doc(inline)]`, we don't want all attributes, otherwise we keep everything.
2254+
// If it's not `#[doc(inline)]`, we don't want all attributes, otherwise we keep everything.
22482255
if !is_inline {
22492256
attrs.extend_from_slice(new_attrs);
22502257
return;
@@ -2374,26 +2381,43 @@ fn clean_maybe_renamed_item<'tcx>(
23742381
_ => unreachable!("not yet converted"),
23752382
};
23762383

2377-
let mut import_attrs = Vec::new();
2378-
let mut target_attrs = Vec::new();
2379-
if let Some(import_id) = import_id &&
2384+
let attrs = if let Some(import_id) = import_id &&
23802385
let Some(hir::Node::Item(use_node)) = cx.tcx.hir().find_by_def_id(import_id)
23812386
{
2382-
let is_inline = inline::load_attrs(cx, import_id.to_def_id()).lists(sym::doc).get_word_attr(sym::inline).is_some();
2387+
let is_inline = inline::load_attrs(cx, import_id.to_def_id())
2388+
.lists(sym::doc)
2389+
.get_word_attr(sym::inline)
2390+
.is_some();
23832391
// Then we get all the various imports' attributes.
2384-
get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut import_attrs, is_inline);
2385-
add_without_unwanted_attributes(&mut target_attrs, inline::load_attrs(cx, def_id), is_inline);
2392+
let mut attrs = get_all_import_attributes(
2393+
use_node,
2394+
cx,
2395+
item.owner_id.def_id,
2396+
is_inline,
2397+
import_id,
2398+
);
2399+
2400+
let mut target_attrs = Vec::new();
2401+
add_without_unwanted_attributes(
2402+
&mut target_attrs,
2403+
inline::load_attrs(cx, def_id),
2404+
is_inline,
2405+
);
2406+
for attr in target_attrs.into_iter() {
2407+
attrs.push((attr, None));
2408+
}
2409+
attrs
23862410
} else {
23872411
// We only keep the item's attributes.
2388-
target_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
2389-
}
2412+
inline::load_attrs(cx, def_id).iter().cloned().map(|attr| (attr, None)).collect::<Vec<_>>()
2413+
};
23902414

2391-
let import_id = import_id.map(|def_id| def_id.to_def_id());
2392-
let (attrs, cfg) = merge_attrs(cx, &target_attrs, Some((&import_attrs, import_id)));
2415+
let cfg = attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
2416+
let attrs = Attributes::from_ast_iter(attrs.iter().map(|(attr, did)| (attr, *did)), false);
23932417

23942418
let mut item =
23952419
Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg);
2396-
item.inline_stmt_id = import_id;
2420+
item.inline_stmt_id = import_id.map(|local| local.to_def_id());
23972421
vec![item]
23982422
})
23992423
}

src/librustdoc/clean/types.rs

+36-15
Original file line numberDiff line numberDiff line change
@@ -867,27 +867,16 @@ pub(crate) struct Module {
867867

868868
pub(crate) trait AttributesExt {
869869
type AttributeIterator<'a>: Iterator<Item = ast::NestedMetaItem>
870+
where
871+
Self: 'a;
872+
type Attributes<'a>: Iterator<Item = &'a ast::Attribute>
870873
where
871874
Self: 'a;
872875

873876
fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a>;
874877

875-
fn span(&self) -> Option<rustc_span::Span>;
876-
877-
fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>>;
878-
}
879-
880-
impl AttributesExt for [ast::Attribute] {
881-
type AttributeIterator<'a> = impl Iterator<Item = ast::NestedMetaItem> + 'a;
878+
fn iter<'a>(&'a self) -> Self::Attributes<'a>;
882879

883-
fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a> {
884-
self.iter()
885-
.filter(move |attr| attr.has_name(name))
886-
.filter_map(ast::Attribute::meta_item_list)
887-
.flatten()
888-
}
889-
890-
/// Return the span of the first doc-comment, if it exists.
891880
fn span(&self) -> Option<rustc_span::Span> {
892881
self.iter().find(|attr| attr.doc_str().is_some()).map(|attr| attr.span)
893882
}
@@ -980,6 +969,38 @@ impl AttributesExt for [ast::Attribute] {
980969
}
981970
}
982971

972+
impl AttributesExt for [ast::Attribute] {
973+
type AttributeIterator<'a> = impl Iterator<Item = ast::NestedMetaItem> + 'a;
974+
type Attributes<'a> = impl Iterator<Item = &'a ast::Attribute> + 'a;
975+
976+
fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a> {
977+
self.iter()
978+
.filter(move |attr| attr.has_name(name))
979+
.filter_map(ast::Attribute::meta_item_list)
980+
.flatten()
981+
}
982+
983+
fn iter<'a>(&'a self) -> Self::Attributes<'a> {
984+
self.into_iter()
985+
}
986+
}
987+
988+
impl AttributesExt for [(ast::Attribute, Option<DefId>)] {
989+
type AttributeIterator<'a> = impl Iterator<Item = ast::NestedMetaItem> + 'a;
990+
type Attributes<'a> = impl Iterator<Item = &'a ast::Attribute> + 'a;
991+
992+
fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a> {
993+
AttributesExt::iter(self)
994+
.filter(move |attr| attr.has_name(name))
995+
.filter_map(ast::Attribute::meta_item_list)
996+
.flatten()
997+
}
998+
999+
fn iter<'a>(&'a self) -> Self::Attributes<'a> {
1000+
self.into_iter().map(|(attr, _)| attr)
1001+
}
1002+
}
1003+
9831004
pub(crate) trait NestedAttributesExt {
9841005
/// Returns `true` if the attribute list contains a specific `word`
9851006
fn has_word(self, word: Symbol) -> bool

0 commit comments

Comments
 (0)