Skip to content

Commit eb45cff

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 e5351f2 + 6eb4735 commit eb45cff

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
@@ -2009,7 +2009,7 @@ fn clean_extern_crate(
20092009
def_id: crate_def_id,
20102010
visibility: krate.vis.clean(cx),
20112011
kind: box ExternCrateItem { src: orig_name },
2012-
cfg: attrs.cfg(cx.sess().diagnostic()),
2012+
cfg: attrs.cfg(cx.sess()),
20132013
}]
20142014
}
20152015

src/librustdoc/clean/types.rs

+21-33
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ impl Item {
373373
kind,
374374
box ast_attrs.clean(cx),
375375
cx,
376-
ast_attrs.cfg(cx.sess().diagnostic()),
376+
ast_attrs.cfg(cx.sess()),
377377
)
378378
}
379379

@@ -385,7 +385,7 @@ impl Item {
385385
cx: &mut DocContext<'_>,
386386
cfg: Option<Arc<Cfg>>,
387387
) -> Item {
388-
debug!("name={:?}, def_id={:?}", name, def_id);
388+
trace!("name={:?}, def_id={:?}", name, def_id);
389389

390390
Item {
391391
def_id,
@@ -730,7 +730,7 @@ crate trait AttributesExt {
730730

731731
fn other_attrs(&self) -> Vec<ast::Attribute>;
732732

733-
fn cfg(&self, diagnostic: &::rustc_errors::Handler) -> Option<Arc<Cfg>>;
733+
fn cfg(&self, sess: &Session) -> Option<Arc<Cfg>>;
734734
}
735735

736736
impl AttributesExt for [ast::Attribute] {
@@ -755,17 +755,28 @@ impl AttributesExt for [ast::Attribute] {
755755
self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect()
756756
}
757757

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

761761
for attr in self.iter() {
762+
// #[doc]
762763
if attr.doc_str().is_none() && attr.has_name(sym::doc) {
763-
if let Some(mi) = attr.meta() {
764-
if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
765-
// Extracted #[doc(cfg(...))]
766-
match Cfg::parse(cfg_mi) {
767-
Ok(new_cfg) => cfg &= new_cfg,
768-
Err(e) => diagnostic.span_err(e.span, e.msg),
764+
// #[doc(...)]
765+
if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) {
766+
for item in list {
767+
// #[doc(include)]
768+
if !item.has_name(sym::cfg) {
769+
continue;
770+
}
771+
// #[doc(cfg(...))]
772+
if let Some(cfg_mi) = item
773+
.meta_item()
774+
.and_then(|item| rustc_expand::config::parse_cfg(&item, sess))
775+
{
776+
match Cfg::parse(&cfg_mi) {
777+
Ok(new_cfg) => cfg &= new_cfg,
778+
Err(e) => sess.span_err(e.span, e.msg),
779+
}
769780
}
770781
}
771782
}
@@ -932,29 +943,6 @@ impl Attributes {
932943
self.other_attrs.lists(name)
933944
}
934945

935-
/// Extracts the content from an attribute `#[doc(cfg(content))]`.
936-
crate fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
937-
use rustc_ast::NestedMetaItem::MetaItem;
938-
939-
if let ast::MetaItemKind::List(ref nmis) = mi.kind {
940-
if nmis.len() == 1 {
941-
if let MetaItem(ref cfg_mi) = nmis[0] {
942-
if cfg_mi.has_name(sym::cfg) {
943-
if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind {
944-
if cfg_nmis.len() == 1 {
945-
if let MetaItem(ref content_mi) = cfg_nmis[0] {
946-
return Some(content_mi);
947-
}
948-
}
949-
}
950-
}
951-
}
952-
}
953-
}
954-
955-
None
956-
}
957-
958946
/// Reads a `MetaItem` from within an attribute, looks for whether it is a
959947
/// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
960948
/// 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
@@ -154,7 +154,7 @@ impl<'tcx> Context<'tcx> {
154154
&self.cache
155155
}
156156

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

src/librustdoc/html/render/print_item.rs

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

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)