Skip to content

Commit 097ee3c

Browse files
authored
Rollup merge of rust-lang#84442 - jyn514:doc-cfg, r=petrochenkov
Unify rustc and rustdoc parsing of `cfg()` This extracts a new `parse_cfg` function that's used between both. - Treat `#[doc(cfg(x), cfg(y))]` the same as `#[doc(cfg(x)] #[doc(cfg(y))]`. Previously it would be completely ignored. - Treat `#[doc(inline, cfg(x))]` the same as `#[doc(inline)] #[doc(cfg(x))]`. Previously, the cfg would be ignored. - Pass the cfg predicate through to rustc_expand to be validated Technically this is a breaking change, but doc_cfg is still nightly so I don't think it matters. Fixes rust-lang#84437. r? ````````@petrochenkov````````
2 parents 98bf29d + 6eb4735 commit 097ee3c

File tree

10 files changed

+82
-64
lines changed

10 files changed

+82
-64
lines changed

compiler/rustc_expand/src/config.rs

+29-25
Original file line numberDiff line numberDiff line change
@@ -464,31 +464,9 @@ impl<'a> StripUnconfigured<'a> {
464464
return true;
465465
}
466466
};
467-
let error = |span, msg, suggestion: &str| {
468-
let mut err = self.sess.parse_sess.span_diagnostic.struct_span_err(span, msg);
469-
if !suggestion.is_empty() {
470-
err.span_suggestion(
471-
span,
472-
"expected syntax is",
473-
suggestion.into(),
474-
Applicability::MaybeIncorrect,
475-
);
476-
}
477-
err.emit();
478-
true
479-
};
480-
let span = meta_item.span;
481-
match meta_item.meta_item_list() {
482-
None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"),
483-
Some([]) => error(span, "`cfg` predicate is not specified", ""),
484-
Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""),
485-
Some([single]) => match single.meta_item() {
486-
Some(meta_item) => {
487-
attr::cfg_matches(meta_item, &self.sess.parse_sess, self.features)
488-
}
489-
None => error(single.span(), "`cfg` predicate key cannot be a literal", ""),
490-
},
491-
}
467+
parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
468+
attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.features)
469+
})
492470
})
493471
}
494472

@@ -532,6 +510,32 @@ impl<'a> StripUnconfigured<'a> {
532510
}
533511
}
534512

513+
pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> {
514+
let error = |span, msg, suggestion: &str| {
515+
let mut err = sess.parse_sess.span_diagnostic.struct_span_err(span, msg);
516+
if !suggestion.is_empty() {
517+
err.span_suggestion(
518+
span,
519+
"expected syntax is",
520+
suggestion.into(),
521+
Applicability::HasPlaceholders,
522+
);
523+
}
524+
err.emit();
525+
None
526+
};
527+
let span = meta_item.span;
528+
match meta_item.meta_item_list() {
529+
None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"),
530+
Some([]) => error(span, "`cfg` predicate is not specified", ""),
531+
Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""),
532+
Some([single]) => match single.meta_item() {
533+
Some(meta_item) => Some(meta_item),
534+
None => error(single.span(), "`cfg` predicate key cannot be a literal", ""),
535+
},
536+
}
537+
}
538+
535539
fn is_cfg(sess: &Session, attr: &Attribute) -> bool {
536540
sess.check_name(attr, sym::cfg)
537541
}

src/librustdoc/clean/inline.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,10 @@ fn merge_attrs(
317317
} else {
318318
Attributes::from_ast(&both, None)
319319
},
320-
both.cfg(cx.sess().diagnostic()),
320+
both.cfg(cx.sess()),
321321
)
322322
} else {
323-
(old_attrs.clean(cx), old_attrs.cfg(cx.sess().diagnostic()))
323+
(old_attrs.clean(cx), old_attrs.cfg(cx.sess()))
324324
}
325325
}
326326

src/librustdoc/clean/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2018,7 +2018,7 @@ fn clean_extern_crate(
20182018
def_id: crate_def_id.into(),
20192019
visibility: krate.vis.clean(cx),
20202020
kind: box ExternCrateItem { src: orig_name },
2021-
cfg: attrs.cfg(cx.sess().diagnostic()),
2021+
cfg: attrs.cfg(cx.sess()),
20222022
}]
20232023
}
20242024

src/librustdoc/clean/types.rs

+21-33
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ impl Item {
444444
kind,
445445
box ast_attrs.clean(cx),
446446
cx,
447-
ast_attrs.cfg(cx.sess().diagnostic()),
447+
ast_attrs.cfg(cx.sess()),
448448
)
449449
}
450450

@@ -456,7 +456,7 @@ impl Item {
456456
cx: &mut DocContext<'_>,
457457
cfg: Option<Arc<Cfg>>,
458458
) -> Item {
459-
debug!("name={:?}, def_id={:?}", name, def_id);
459+
trace!("name={:?}, def_id={:?}", name, def_id);
460460

461461
Item {
462462
def_id: def_id.into(),
@@ -795,7 +795,7 @@ crate trait AttributesExt {
795795

796796
fn other_attrs(&self) -> Vec<ast::Attribute>;
797797

798-
fn cfg(&self, diagnostic: &::rustc_errors::Handler) -> Option<Arc<Cfg>>;
798+
fn cfg(&self, sess: &Session) -> Option<Arc<Cfg>>;
799799
}
800800

801801
impl AttributesExt for [ast::Attribute] {
@@ -820,17 +820,28 @@ impl AttributesExt for [ast::Attribute] {
820820
self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect()
821821
}
822822

823-
fn cfg(&self, diagnostic: &::rustc_errors::Handler) -> Option<Arc<Cfg>> {
823+
fn cfg(&self, sess: &Session) -> Option<Arc<Cfg>> {
824824
let mut cfg = Cfg::True;
825825

826826
for attr in self.iter() {
827+
// #[doc]
827828
if attr.doc_str().is_none() && attr.has_name(sym::doc) {
828-
if let Some(mi) = attr.meta() {
829-
if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
830-
// Extracted #[doc(cfg(...))]
831-
match Cfg::parse(cfg_mi) {
832-
Ok(new_cfg) => cfg &= new_cfg,
833-
Err(e) => diagnostic.span_err(e.span, e.msg),
829+
// #[doc(...)]
830+
if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) {
831+
for item in list {
832+
// #[doc(include)]
833+
if !item.has_name(sym::cfg) {
834+
continue;
835+
}
836+
// #[doc(cfg(...))]
837+
if let Some(cfg_mi) = item
838+
.meta_item()
839+
.and_then(|item| rustc_expand::config::parse_cfg(&item, sess))
840+
{
841+
match Cfg::parse(&cfg_mi) {
842+
Ok(new_cfg) => cfg &= new_cfg,
843+
Err(e) => sess.span_err(e.span, e.msg),
844+
}
834845
}
835846
}
836847
}
@@ -997,29 +1008,6 @@ impl Attributes {
9971008
self.other_attrs.lists(name)
9981009
}
9991010

1000-
/// Extracts the content from an attribute `#[doc(cfg(content))]`.
1001-
crate fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
1002-
use rustc_ast::NestedMetaItem::MetaItem;
1003-
1004-
if let ast::MetaItemKind::List(ref nmis) = mi.kind {
1005-
if nmis.len() == 1 {
1006-
if let MetaItem(ref cfg_mi) = nmis[0] {
1007-
if cfg_mi.has_name(sym::cfg) {
1008-
if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind {
1009-
if cfg_nmis.len() == 1 {
1010-
if let MetaItem(ref content_mi) = cfg_nmis[0] {
1011-
return Some(content_mi);
1012-
}
1013-
}
1014-
}
1015-
}
1016-
}
1017-
}
1018-
}
1019-
1020-
None
1021-
}
1022-
10231011
/// Reads a `MetaItem` from within an attribute, looks for whether it is a
10241012
/// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
10251013
/// its expansion.

src/librustdoc/doctest.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1096,7 +1096,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
10961096
let ast_attrs = self.tcx.hir().attrs(hir_id);
10971097
let mut attrs = Attributes::from_ast(ast_attrs, None);
10981098

1099-
if let Some(ref cfg) = ast_attrs.cfg(self.sess.diagnostic()) {
1099+
if let Some(ref cfg) = ast_attrs.cfg(self.sess) {
11001100
if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) {
11011101
return;
11021102
}

src/librustdoc/html/render/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ impl<'tcx> Context<'tcx> {
155155
&self.cache
156156
}
157157

158-
fn sess(&self) -> &'tcx Session {
158+
pub(super) fn sess(&self) -> &'tcx Session {
159159
&self.shared.tcx.sess
160160
}
161161

src/librustdoc/html/render/print_item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
296296
let import_item = clean::Item {
297297
def_id: import_def_id.into(),
298298
attrs: import_attrs,
299-
cfg: ast_attrs.cfg(cx.tcx().sess.diagnostic()),
299+
cfg: ast_attrs.cfg(cx.sess()),
300300
..myitem.clone()
301301
};
302302

src/test/rustdoc-ui/invalid-cfg.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#![feature(doc_cfg)]
2+
#[doc(cfg = "x")] //~ ERROR not followed by parentheses
3+
#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates
4+
struct S {}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: `cfg` is not followed by parentheses
2+
--> $DIR/invalid-cfg.rs:2:7
3+
|
4+
LL | #[doc(cfg = "x")]
5+
| ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
6+
7+
error: multiple `cfg` predicates are specified
8+
--> $DIR/invalid-cfg.rs:3:14
9+
|
10+
LL | #[doc(cfg(x, y))]
11+
| ^
12+
13+
error: aborting due to 2 previous errors
14+

src/test/rustdoc/doc-cfg.rs

+8
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,11 @@ pub unsafe fn uses_target_feature() {
9191
pub fn uses_cfg_target_feature() {
9292
uses_target_feature();
9393
}
94+
95+
// multiple attributes should be allowed
96+
// @has doc_cfg/fn.multiple_attrs.html \
97+
// '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \
98+
// 'This is supported on x and y and z only.'
99+
#[doc(inline, cfg(x))]
100+
#[doc(cfg(y), cfg(z))]
101+
pub fn multiple_attrs() {}

0 commit comments

Comments
 (0)