Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify rustc and rustdoc parsing of cfg() #84442

Merged
merged 1 commit into from
May 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 29 additions & 25 deletions compiler/rustc_expand/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,31 +464,9 @@ impl<'a> StripUnconfigured<'a> {
return true;
}
};
let error = |span, msg, suggestion: &str| {
let mut err = self.sess.parse_sess.span_diagnostic.struct_span_err(span, msg);
if !suggestion.is_empty() {
err.span_suggestion(
span,
"expected syntax is",
suggestion.into(),
Applicability::MaybeIncorrect,
);
}
err.emit();
true
};
let span = meta_item.span;
match meta_item.meta_item_list() {
None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"),
Some([]) => error(span, "`cfg` predicate is not specified", ""),
Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""),
Some([single]) => match single.meta_item() {
Some(meta_item) => {
attr::cfg_matches(meta_item, &self.sess.parse_sess, self.features)
}
None => error(single.span(), "`cfg` predicate key cannot be a literal", ""),
},
}
parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.features)
})
})
}

Expand Down Expand Up @@ -532,6 +510,32 @@ impl<'a> StripUnconfigured<'a> {
}
}

pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> {
let error = |span, msg, suggestion: &str| {
let mut err = sess.parse_sess.span_diagnostic.struct_span_err(span, msg);
if !suggestion.is_empty() {
err.span_suggestion(
span,
"expected syntax is",
suggestion.into(),
Applicability::HasPlaceholders,
petrochenkov marked this conversation as resolved.
Show resolved Hide resolved
);
}
err.emit();
None
};
let span = meta_item.span;
match meta_item.meta_item_list() {
None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"),
Some([]) => error(span, "`cfg` predicate is not specified", ""),
Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""),
Some([single]) => match single.meta_item() {
Some(meta_item) => Some(meta_item),
None => error(single.span(), "`cfg` predicate key cannot be a literal", ""),
},
}
}

fn is_cfg(sess: &Session, attr: &Attribute) -> bool {
sess.check_name(attr, sym::cfg)
}
4 changes: 2 additions & 2 deletions src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,10 @@ fn merge_attrs(
} else {
Attributes::from_ast(&both, None)
},
both.cfg(cx.sess().diagnostic()),
both.cfg(cx.sess()),
)
} else {
(old_attrs.clean(cx), old_attrs.cfg(cx.sess().diagnostic()))
(old_attrs.clean(cx), old_attrs.cfg(cx.sess()))
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2006,7 +2006,7 @@ fn clean_extern_crate(
def_id: crate_def_id,
visibility: krate.vis.clean(cx),
kind: box ExternCrateItem { src: orig_name },
cfg: attrs.cfg(cx.sess().diagnostic()),
cfg: attrs.cfg(cx.sess()),
}]
}

Expand Down
54 changes: 21 additions & 33 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ impl Item {
kind,
box ast_attrs.clean(cx),
cx,
ast_attrs.cfg(cx.sess().diagnostic()),
ast_attrs.cfg(cx.sess()),
)
}

Expand All @@ -332,7 +332,7 @@ impl Item {
cx: &mut DocContext<'_>,
cfg: Option<Arc<Cfg>>,
) -> Item {
debug!("name={:?}, def_id={:?}", name, def_id);
trace!("name={:?}, def_id={:?}", name, def_id);

Item {
def_id,
Expand Down Expand Up @@ -681,7 +681,7 @@ crate trait AttributesExt {

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

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

impl AttributesExt for [ast::Attribute] {
Expand All @@ -706,17 +706,28 @@ impl AttributesExt for [ast::Attribute] {
self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect()
}

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

for attr in self.iter() {
// #[doc]
if attr.doc_str().is_none() && attr.has_name(sym::doc) {
if let Some(mi) = attr.meta() {
if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
// Extracted #[doc(cfg(...))]
match Cfg::parse(cfg_mi) {
Ok(new_cfg) => cfg &= new_cfg,
Err(e) => diagnostic.span_err(e.span, e.msg),
// #[doc(...)]
if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) {
for item in list {
// #[doc(include)]
if !item.has_name(sym::cfg) {
continue;
}
// #[doc(cfg(...))]
if let Some(cfg_mi) = item
.meta_item()
.and_then(|item| rustc_expand::config::parse_cfg(&item, sess))
{
match Cfg::parse(&cfg_mi) {
Ok(new_cfg) => cfg &= new_cfg,
Err(e) => sess.span_err(e.span, e.msg),
}
}
}
}
Expand Down Expand Up @@ -883,29 +894,6 @@ impl Attributes {
self.other_attrs.lists(name)
}

/// Extracts the content from an attribute `#[doc(cfg(content))]`.
crate fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
use rustc_ast::NestedMetaItem::MetaItem;

if let ast::MetaItemKind::List(ref nmis) = mi.kind {
if nmis.len() == 1 {
if let MetaItem(ref cfg_mi) = nmis[0] {
if cfg_mi.has_name(sym::cfg) {
if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind {
if cfg_nmis.len() == 1 {
if let MetaItem(ref content_mi) = cfg_nmis[0] {
return Some(content_mi);
}
}
}
}
}
}
}

None
}

/// Reads a `MetaItem` from within an attribute, looks for whether it is a
/// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
/// its expansion.
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/doctest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
let ast_attrs = self.tcx.hir().attrs(hir_id);
let mut attrs = Attributes::from_ast(ast_attrs, None);

if let Some(ref cfg) = ast_attrs.cfg(self.sess.diagnostic()) {
if let Some(ref cfg) = ast_attrs.cfg(self.sess) {
if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/render/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ impl<'tcx> Context<'tcx> {
&self.cache
}

fn sess(&self) -> &'tcx Session {
pub(super) fn sess(&self) -> &'tcx Session {
&self.shared.tcx.sess
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
let import_item = clean::Item {
def_id: import_def_id,
attrs: import_attrs,
cfg: ast_attrs.cfg(cx.tcx().sess.diagnostic()),
cfg: ast_attrs.cfg(cx.sess()),
..myitem.clone()
};

Expand Down
4 changes: 4 additions & 0 deletions src/test/rustdoc-ui/invalid-cfg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#![feature(doc_cfg)]
#[doc(cfg = "x")] //~ ERROR not followed by parentheses
#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates
struct S {}
14 changes: 14 additions & 0 deletions src/test/rustdoc-ui/invalid-cfg.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error: `cfg` is not followed by parentheses
--> $DIR/invalid-cfg.rs:2:7
|
LL | #[doc(cfg = "x")]
| ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)`

error: multiple `cfg` predicates are specified
--> $DIR/invalid-cfg.rs:3:14
|
LL | #[doc(cfg(x, y))]
| ^

error: aborting due to 2 previous errors

8 changes: 8 additions & 0 deletions src/test/rustdoc/doc-cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,11 @@ pub unsafe fn uses_target_feature() {
pub fn uses_cfg_target_feature() {
uses_target_feature();
}

// multiple attributes should be allowed
// @has doc_cfg/fn.multiple_attrs.html \
// '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \
// 'This is supported on x and y and z only.'
#[doc(inline, cfg(x))]
#[doc(cfg(y), cfg(z))]
pub fn multiple_attrs() {}