Skip to content

Commit 4c9be35

Browse files
authored
Unrolled build for #140894
Rollup merge of #140894 - Urgau:check-cfg-rustdoc, r=GuillaumeGomez Make check-cfg diagnostics work in `#[doc(cfg(..))]` This PR makes it so that the check-cfg `unexpected_cfgs` lint, is correctly emitted in `rustdoc`'s `#[doc(cfg(..))]`. This is achieved by adding a custom trait to `cfg_matches` (the method that emits the lint) which permits `rustc` and `rustdoc` to each have their way to emitting lints (via buffered lints/AST for `rustc` and via `TyCtxt`/HIR for `rustdoc`). The reason this is required is because buffered lints operates on the AST but `rustdoc` uses the HIR and by the time `rustdoc` calls `cfg_matches` we are way passed the point where buffered lints have been drain and emitted. Best reviewed commit by commit. r? `@jieyouxu` (for the compiler part) r? `@GuillaumeGomez` (for the rustdoc part)
2 parents be42293 + 3fd0265 commit 4c9be35

File tree

12 files changed

+120
-28
lines changed

12 files changed

+120
-28
lines changed

compiler/rustc_attr_parsing/src/attributes/cfg.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,29 @@ use rustc_attr_data_structures::RustcVersion;
44
use rustc_feature::{Features, GatedCfg, find_gated_cfg};
55
use rustc_session::Session;
66
use rustc_session::config::ExpectedValues;
7-
use rustc_session::lint::BuiltinLintDiag;
87
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
8+
use rustc_session::lint::{BuiltinLintDiag, Lint};
99
use rustc_session::parse::feature_err;
1010
use rustc_span::{Span, Symbol, sym};
1111

1212
use crate::session_diagnostics::{self, UnsupportedLiteralReason};
1313
use crate::{fluent_generated, parse_version};
1414

15+
/// Emitter of a builtin lint from `cfg_matches`.
16+
///
17+
/// Used to support emiting a lint (currently on check-cfg), either:
18+
/// - as an early buffered lint (in `rustc`)
19+
/// - or has a "normal" lint from HIR (in `rustdoc`)
20+
pub trait CfgMatchesLintEmitter {
21+
fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag);
22+
}
23+
24+
impl CfgMatchesLintEmitter for NodeId {
25+
fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag) {
26+
sess.psess.buffer_lint(lint, sp, *self, diag);
27+
}
28+
}
29+
1530
#[derive(Clone, Debug)]
1631
pub struct Condition {
1732
pub name: Symbol,
@@ -25,28 +40,28 @@ pub struct Condition {
2540
pub fn cfg_matches(
2641
cfg: &MetaItemInner,
2742
sess: &Session,
28-
lint_node_id: NodeId,
43+
lint_emitter: impl CfgMatchesLintEmitter,
2944
features: Option<&Features>,
3045
) -> bool {
3146
eval_condition(cfg, sess, features, &mut |cfg| {
3247
try_gate_cfg(cfg.name, cfg.span, sess, features);
3348
match sess.psess.check_config.expecteds.get(&cfg.name) {
3449
Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
35-
sess.psess.buffer_lint(
50+
lint_emitter.emit_span_lint(
51+
sess,
3652
UNEXPECTED_CFGS,
3753
cfg.span,
38-
lint_node_id,
3954
BuiltinLintDiag::UnexpectedCfgValue(
4055
(cfg.name, cfg.name_span),
4156
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
4257
),
4358
);
4459
}
4560
None if sess.psess.check_config.exhaustive_names => {
46-
sess.psess.buffer_lint(
61+
lint_emitter.emit_span_lint(
62+
sess,
4763
UNEXPECTED_CFGS,
4864
cfg.span,
49-
lint_node_id,
5065
BuiltinLintDiag::UnexpectedCfgName(
5166
(cfg.name, cfg.name_span),
5267
cfg.value.map(|v| (v, cfg.value_span.unwrap())),

compiler/rustc_lint/src/early.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use tracing::debug;
1818
use crate::context::{EarlyContext, LintContext, LintStore};
1919
use crate::passes::{EarlyLintPass, EarlyLintPassObject};
2020

21-
mod diagnostics;
21+
pub(super) mod diagnostics;
2222

2323
macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
2424
$cx.pass.$f(&$cx.context, $($args),*);
@@ -40,7 +40,7 @@ impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> {
4040
for early_lint in self.context.buffered.take(id) {
4141
let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint;
4242
self.context.opt_span_lint(lint_id.lint, span, |diag| {
43-
diagnostics::decorate_lint(self.context.sess(), self.tcx, diagnostic, diag);
43+
diagnostics::decorate_builtin_lint(self.context.sess(), self.tcx, diagnostic, diag);
4444
});
4545
}
4646
}

compiler/rustc_lint/src/early/diagnostics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::lints::{self, ElidedNamedLifetime};
1818

1919
mod check_cfg;
2020

21-
pub(super) fn decorate_lint(
21+
pub fn decorate_builtin_lint(
2222
sess: &Session,
2323
tcx: Option<TyCtxt<'_>>,
2424
diagnostic: BuiltinLintDiag,

compiler/rustc_lint/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ use unused::*;
126126
#[rustfmt::skip]
127127
pub use builtin::{MissingDoc, SoftLints};
128128
pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore};
129+
pub use early::diagnostics::decorate_builtin_lint;
129130
pub use early::{EarlyCheckNode, check_ast_node};
130131
pub use late::{check_crate, late_lint_mod, unerased_lint_store};
131132
pub use levels::LintLevelsBuilder;

src/librustdoc/clean/inline.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,12 +409,12 @@ pub(crate) fn merge_attrs(
409409
} else {
410410
Attributes::from_hir(&both)
411411
},
412-
extract_cfg_from_attrs(both.iter(), cx.tcx, &cx.cache.hidden_cfg),
412+
extract_cfg_from_attrs(both.iter(), cx.tcx, None, &cx.cache.hidden_cfg),
413413
)
414414
} else {
415415
(
416416
Attributes::from_hir(old_attrs),
417-
extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
417+
extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, None, &cx.cache.hidden_cfg),
418418
)
419419
}
420420
}

src/librustdoc/clean/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ fn generate_item_with_correct_attrs(
210210
Cow::Owned(attr) => attr,
211211
}),
212212
cx.tcx,
213+
def_id.as_local().map(|did| cx.tcx.local_def_id_to_hir_id(did)),
213214
&cx.cache.hidden_cfg,
214215
);
215216
let attrs = Attributes::from_hir_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false);

src/librustdoc/clean/types.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
1212
use rustc_hir::def::{CtorKind, DefKind, Res};
1313
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
1414
use rustc_hir::lang_items::LangItem;
15-
use rustc_hir::{BodyId, Mutability};
15+
use rustc_hir::{BodyId, HirId, Mutability};
1616
use rustc_index::IndexVec;
17+
use rustc_lint_defs::{BuiltinLintDiag, Lint};
1718
use rustc_metadata::rendered_const;
1819
use rustc_middle::span_bug;
1920
use rustc_middle::ty::fast_reject::SimplifiedType;
@@ -477,7 +478,12 @@ impl Item {
477478
name,
478479
kind,
479480
Attributes::from_hir(hir_attrs),
480-
extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
481+
extract_cfg_from_attrs(
482+
hir_attrs.iter(),
483+
cx.tcx,
484+
def_id.as_local().map(|did| cx.tcx.local_def_id_to_hir_id(did)),
485+
&cx.cache.hidden_cfg,
486+
),
481487
)
482488
}
483489

@@ -1033,6 +1039,7 @@ pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
10331039
pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
10341040
attrs: I,
10351041
tcx: TyCtxt<'_>,
1042+
hir_id: Option<HirId>,
10361043
hidden_cfg: &FxHashSet<Cfg>,
10371044
) -> Option<Arc<Cfg>> {
10381045
let doc_cfg_active = tcx.features().doc_cfg();
@@ -1056,6 +1063,32 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
10561063
.peekable();
10571064
if doc_cfg.peek().is_some() && doc_cfg_active {
10581065
let sess = tcx.sess;
1066+
1067+
struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, Option<HirId>);
1068+
1069+
impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> {
1070+
fn emit_span_lint(
1071+
&self,
1072+
sess: &Session,
1073+
lint: &'static Lint,
1074+
sp: rustc_span::Span,
1075+
builtin_diag: BuiltinLintDiag,
1076+
) {
1077+
if let Some(hir_id) = self.1 {
1078+
self.0.node_span_lint(lint, hir_id, sp, |diag| {
1079+
rustc_lint::decorate_builtin_lint(
1080+
sess,
1081+
Some(self.0),
1082+
builtin_diag,
1083+
diag,
1084+
)
1085+
});
1086+
} else {
1087+
// No HIR id. Probably in another crate. Don't lint.
1088+
}
1089+
}
1090+
}
1091+
10591092
doc_cfg.fold(Cfg::True, |mut cfg, item| {
10601093
if let Some(cfg_mi) =
10611094
item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
@@ -1064,7 +1097,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
10641097
rustc_attr_parsing::cfg_matches(
10651098
cfg_mi,
10661099
tcx.sess,
1067-
rustc_ast::CRATE_NODE_ID,
1100+
RustdocCfgMatchesLintEmitter(tcx, hir_id),
10681101
Some(tcx.features()),
10691102
);
10701103
match Cfg::parse(cfg_mi) {

src/librustdoc/doctest/rust.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,12 @@ impl HirCollector<'_> {
116116
nested: F,
117117
) {
118118
let ast_attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
119-
if let Some(ref cfg) =
120-
extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &FxHashSet::default())
121-
&& !cfg.matches(&self.tcx.sess.psess)
119+
if let Some(ref cfg) = extract_cfg_from_attrs(
120+
ast_attrs.iter(),
121+
self.tcx,
122+
Some(self.tcx.local_def_id_to_hir_id(def_id)),
123+
&FxHashSet::default(),
124+
) && !cfg.matches(&self.tcx.sess.psess)
122125
{
123126
return;
124127
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
warning: unexpected `cfg` condition name: `foo`
2+
--> $DIR/doc-cfg-check-cfg.rs:13:11
3+
|
4+
LL | #[doc(cfg(foo))]
5+
| ^^^
6+
|
7+
= help: to expect this configuration use `--check-cfg=cfg(foo)`
8+
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
9+
= note: `#[warn(unexpected_cfgs)]` on by default
10+
11+
warning: 1 warning emitted
12+

tests/rustdoc-ui/doc-cfg-check-cfg.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
// Ensure that `doc(cfg())` respects `check-cfg`
22
// Currently not properly working
3-
#![feature(doc_cfg)]
4-
#![deny(unexpected_cfgs)]
53

6-
//@revisions: no_check cfg_empty cfg_foo
4+
//@ check-pass
5+
//@ no-auto-check-cfg
6+
7+
//@ revisions: no_check cfg_empty cfg_foo
78
//@[cfg_empty] compile-flags: --check-cfg cfg()
89
//@[cfg_foo] compile-flags: --check-cfg cfg(foo)
910

10-
//@[no_check] check-pass
11-
//@[cfg_empty] check-pass
12-
//@[cfg_empty] known-bug: #138358
13-
//@[cfg_foo] check-pass
11+
#![feature(doc_cfg)]
1412

1513
#[doc(cfg(foo))]
14+
//[cfg_empty]~^ WARN unexpected `cfg` condition name: `foo`
1615
pub fn foo() {}
16+
17+
pub mod module {
18+
#[allow(unexpected_cfgs)]
19+
#[doc(cfg(bar))]
20+
pub fn bar() {}
21+
}

tests/rustdoc-ui/doc-cfg.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
#[doc(cfg(), cfg(foo, bar))]
44
//~^ ERROR
55
//~^^ ERROR
6-
#[doc(cfg(foo), cfg(bar))] // ok!
6+
#[doc(cfg(foo), cfg(bar))]
7+
//~^ WARN unexpected `cfg` condition name: `foo`
8+
//~^^ WARN unexpected `cfg` condition name: `bar`
79
#[doc(cfg())] //~ ERROR
810
#[doc(cfg(foo, bar))] //~ ERROR
911
pub fn foo() {}

tests/rustdoc-ui/doc-cfg.stderr

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,37 @@ error: multiple `cfg` predicates are specified
1010
LL | #[doc(cfg(), cfg(foo, bar))]
1111
| ^^^
1212

13+
warning: unexpected `cfg` condition name: `foo`
14+
--> $DIR/doc-cfg.rs:6:11
15+
|
16+
LL | #[doc(cfg(foo), cfg(bar))]
17+
| ^^^
18+
|
19+
= help: expected names are: `FALSE` and `test` and 31 more
20+
= help: to expect this configuration use `--check-cfg=cfg(foo)`
21+
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
22+
= note: `#[warn(unexpected_cfgs)]` on by default
23+
24+
warning: unexpected `cfg` condition name: `bar`
25+
--> $DIR/doc-cfg.rs:6:21
26+
|
27+
LL | #[doc(cfg(foo), cfg(bar))]
28+
| ^^^
29+
|
30+
= help: to expect this configuration use `--check-cfg=cfg(bar)`
31+
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
32+
1333
error: `cfg` predicate is not specified
14-
--> $DIR/doc-cfg.rs:7:7
34+
--> $DIR/doc-cfg.rs:9:7
1535
|
1636
LL | #[doc(cfg())]
1737
| ^^^^^ help: expected syntax is: `cfg(/* predicate */)`
1838

1939
error: multiple `cfg` predicates are specified
20-
--> $DIR/doc-cfg.rs:8:16
40+
--> $DIR/doc-cfg.rs:10:16
2141
|
2242
LL | #[doc(cfg(foo, bar))]
2343
| ^^^
2444

25-
error: aborting due to 4 previous errors
45+
error: aborting due to 4 previous errors; 2 warnings emitted
2646

0 commit comments

Comments
 (0)