Skip to content

Commit

Permalink
Rollup merge of rust-lang#101279 - GuillaumeGomez:doc_auto_cfg_nested…
Browse files Browse the repository at this point in the history
…_impl, r=notriddle

Fix doc_auto_cfg for impl blocks in different modules with different `cfg`

Fixes rust-lang#101129.

Just like reexports, impl blocks don't necessarily share the same "space" as the item they implement so we need to merge attributes from its parents as well.

r? `@notriddle`
  • Loading branch information
matthiaskrgr committed Sep 1, 2022
2 parents e9df5dd + 68d0094 commit 8f8a5d2
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 20 deletions.
60 changes: 40 additions & 20 deletions src/librustdoc/passes/propagate_doc_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::sync::Arc;

use crate::clean::cfg::Cfg;
use crate::clean::inline::{load_attrs, merge_attrs};
use crate::clean::{Crate, Item};
use crate::clean::{Crate, Item, ItemKind};
use crate::core::DocContext;
use crate::fold::DocFolder;
use crate::passes::Pass;
Expand All @@ -26,30 +26,50 @@ struct CfgPropagator<'a, 'tcx> {
cx: &'a mut DocContext<'tcx>,
}

impl<'a, 'tcx> DocFolder for CfgPropagator<'a, 'tcx> {
fn fold_item(&mut self, mut item: Item) -> Option<Item> {
let old_parent_cfg = self.parent_cfg.clone();
impl<'a, 'tcx> CfgPropagator<'a, 'tcx> {
// Some items need to merge their attributes with their parents' otherwise a few of them
// (mostly `cfg` ones) will be missing.
fn merge_with_parent_attributes(&mut self, item: &mut Item) {
let check_parent = match &*item.kind {
// impl blocks can be in different modules with different cfg and we need to get them
// as well.
ItemKind::ImplItem(_) => false,
kind if kind.is_non_assoc() => true,
_ => return,
};

if item.kind.is_non_assoc() &&
let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) {
let hir = self.cx.tcx.hir();
let hir_id = hir.local_def_id_to_hir_id(def_id);
let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local())
else { return };

let hir = self.cx.tcx.hir();
let hir_id = hir.local_def_id_to_hir_id(def_id);

if check_parent {
let expected_parent = hir.get_parent_item(hir_id);
// If parents are different, it means that `item` is a reexport and we need
// to compute the actual `cfg` by iterating through its "real" parents.
if self.parent == Some(expected_parent) {
return;
}
}

// If parents are different, it means that `item` is a reexport and we need to compute
// the actual `cfg` by iterating through its "real" parents.
if self.parent != Some(expected_parent) {
let mut attrs = Vec::new();
for (parent_hir_id, _) in hir.parent_iter(hir_id) {
if let Some(def_id) = hir.opt_local_def_id(parent_hir_id) {
attrs.extend_from_slice(load_attrs(self.cx, def_id.to_def_id()));
}
}
let (_, cfg) =
merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs));
item.cfg = cfg;
let mut attrs = Vec::new();
for (parent_hir_id, _) in hir.parent_iter(hir_id) {
if let Some(def_id) = hir.opt_local_def_id(parent_hir_id) {
attrs.extend_from_slice(load_attrs(self.cx, def_id.to_def_id()));
}
}
let (_, cfg) = merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs));
item.cfg = cfg;
}
}

impl<'a, 'tcx> DocFolder for CfgPropagator<'a, 'tcx> {
fn fold_item(&mut self, mut item: Item) -> Option<Item> {
let old_parent_cfg = self.parent_cfg.clone();

self.merge_with_parent_attributes(&mut item);

let new_cfg = match (self.parent_cfg.take(), item.cfg.take()) {
(None, None) => None,
(Some(rc), None) | (None, Some(rc)) => Some(rc),
Expand Down
24 changes: 24 additions & 0 deletions src/test/rustdoc/doc_auto_cfg_nested_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Regression test for <https://github.com/rust-lang/rust/issues/101129>.

#![feature(doc_auto_cfg)]
#![crate_type = "lib"]
#![crate_name = "foo"]

pub struct S;
pub trait MyTrait1 {}
pub trait MyTrait2 {}

// @has foo/struct.S.html
// @has - '//*[@id="impl-MyTrait1-for-S"]//*[@class="stab portability"]' \
// 'Available on non-crate feature coolstuff only.'
#[cfg(not(feature = "coolstuff"))]
impl MyTrait1 for S {}

#[cfg(not(feature = "coolstuff"))]
mod submod {
use crate::{S, MyTrait2};
// This impl should also have the `not(feature = "coolstuff")`.
// @has - '//*[@id="impl-MyTrait2-for-S"]//*[@class="stab portability"]' \
// 'Available on non-crate feature coolstuff only.'
impl MyTrait2 for S {}
}

0 comments on commit 8f8a5d2

Please sign in to comment.