parse_meta: ditch parse_in_attr
This commit is contained in:
parent
cbc9f68312
commit
99191c2e71
9 changed files with 99 additions and 48 deletions
|
@ -18,7 +18,6 @@ use syntax::ast::{self, Attribute, AttrItem, MetaItem};
|
||||||
use syntax::edition::Edition;
|
use syntax::edition::Edition;
|
||||||
use syntax::mut_visit::*;
|
use syntax::mut_visit::*;
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
use syntax::tokenstream::DelimSpan;
|
|
||||||
use syntax::sess::ParseSess;
|
use syntax::sess::ParseSess;
|
||||||
use syntax::util::map_in_place::MapInPlace;
|
use syntax::util::map_in_place::MapInPlace;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
@ -139,11 +138,10 @@ impl<'a> StripUnconfigured<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
|
fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
|
||||||
match &attr.get_normal_item().args {
|
match attr.get_normal_item().args {
|
||||||
ast::MacArgs::Delimited(dspan, delim, tts) if !tts.is_empty() => {
|
ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => {
|
||||||
if let ast::MacDelimiter::Brace | ast::MacDelimiter::Bracket = delim {
|
let msg = "wrong `cfg_attr` delimiters";
|
||||||
self.error_malformed_cfg_attr_wrong_delim(*dspan);
|
validate_attr::check_meta_bad_delim(self.sess, dspan, delim, msg);
|
||||||
}
|
|
||||||
match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
|
match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
|
||||||
Ok(r) => return Some(r),
|
Ok(r) => return Some(r),
|
||||||
Err(mut e) => e
|
Err(mut e) => e
|
||||||
|
@ -157,21 +155,6 @@ impl<'a> StripUnconfigured<'a> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_malformed_cfg_attr_wrong_delim(&self, dspan: DelimSpan) {
|
|
||||||
self.sess
|
|
||||||
.span_diagnostic
|
|
||||||
.struct_span_err(dspan.entire(), "wrong `cfg_attr` delimiters")
|
|
||||||
.multipart_suggestion(
|
|
||||||
"the delimiters should be `(` and `)`",
|
|
||||||
vec![
|
|
||||||
(dspan.open, "(".to_string()),
|
|
||||||
(dspan.close, ")".to_string()),
|
|
||||||
],
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn error_malformed_cfg_attr_missing(&self, span: Span) {
|
fn error_malformed_cfg_attr_missing(&self, span: Span) {
|
||||||
self.sess
|
self.sess
|
||||||
.span_diagnostic
|
.span_diagnostic
|
||||||
|
|
|
@ -284,17 +284,6 @@ pub fn parse_in<'a, T>(
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the given subparser `f` on the tokens of the given `attr`'s item.
|
|
||||||
fn parse_in_attr<'a, T>(
|
|
||||||
sess: &'a ParseSess,
|
|
||||||
attr: &ast::Attribute,
|
|
||||||
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
|
||||||
) -> PResult<'a, T> {
|
|
||||||
// FIXME(#66940, Centril | petrochenkov): refactor this function so it doesn't
|
|
||||||
// require reconstructing and immediately re-parsing delimiters.
|
|
||||||
parse_in(sess, attr.get_normal_item().args.outer_tokens(), "attribute", f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE(Centril): The following probably shouldn't be here but it acknowledges the
|
// NOTE(Centril): The following probably shouldn't be here but it acknowledges the
|
||||||
// fact that architecturally, we are using parsing (read on below to understand why).
|
// fact that architecturally, we are using parsing (read on below to understand why).
|
||||||
|
|
||||||
|
|
|
@ -220,7 +220,7 @@ impl<'a> Parser<'a> {
|
||||||
Ok(attrs)
|
Ok(attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
|
crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
|
||||||
let lit = self.parse_lit()?;
|
let lit = self.parse_lit()?;
|
||||||
debug!("checking if {:?} is unusuffixed", lit);
|
debug!("checking if {:?} is unusuffixed", lit);
|
||||||
|
|
||||||
|
@ -247,12 +247,27 @@ impl<'a> Parser<'a> {
|
||||||
let lo = self.token.span;
|
let lo = self.token.span;
|
||||||
let item = self.parse_attr_item()?;
|
let item = self.parse_attr_item()?;
|
||||||
expanded_attrs.push((item, lo.to(self.prev_span)));
|
expanded_attrs.push((item, lo.to(self.prev_span)));
|
||||||
self.eat(&token::Comma);
|
if !self.eat(&token::Comma) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((cfg_predicate, expanded_attrs))
|
Ok((cfg_predicate, expanded_attrs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Matches `COMMASEP(meta_item_inner)`.
|
||||||
|
crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
|
||||||
|
// Presumably, the majority of the time there will only be one attr.
|
||||||
|
let mut nmis = Vec::with_capacity(1);
|
||||||
|
while self.token.kind != token::Eof {
|
||||||
|
nmis.push(self.parse_meta_item_inner()?);
|
||||||
|
if !self.eat(&token::Comma) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(nmis)
|
||||||
|
}
|
||||||
|
|
||||||
/// Matches the following grammar (per RFC 1559).
|
/// Matches the following grammar (per RFC 1559).
|
||||||
///
|
///
|
||||||
/// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
|
/// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
//! Meta-syntax validation logic of attributes for post-expansion.
|
//! Meta-syntax validation logic of attributes for post-expansion.
|
||||||
|
|
||||||
|
use crate::parse_in;
|
||||||
|
|
||||||
use rustc_errors::{PResult, Applicability};
|
use rustc_errors::{PResult, Applicability};
|
||||||
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
|
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
|
||||||
use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MetaItem, MetaItemKind};
|
use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MacDelimiter, MetaItem, MetaItemKind};
|
||||||
use syntax::attr::mk_name_value_item_str;
|
use syntax::attr::mk_name_value_item_str;
|
||||||
use syntax::early_buffered_lints::ILL_FORMED_ATTRIBUTE_INPUT;
|
use syntax::early_buffered_lints::ILL_FORMED_ATTRIBUTE_INPUT;
|
||||||
|
use syntax::tokenstream::DelimSpan;
|
||||||
use syntax::sess::ParseSess;
|
use syntax::sess::ParseSess;
|
||||||
use syntax_pos::{Symbol, sym};
|
use syntax_pos::{Symbol, sym};
|
||||||
|
|
||||||
|
@ -27,9 +30,20 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) {
|
||||||
pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> {
|
pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> {
|
||||||
Ok(match attr.kind {
|
Ok(match attr.kind {
|
||||||
AttrKind::Normal(ref item) => MetaItem {
|
AttrKind::Normal(ref item) => MetaItem {
|
||||||
path: item.path.clone(),
|
|
||||||
kind: super::parse_in_attr(sess, attr, |p| p.parse_meta_item_kind())?,
|
|
||||||
span: attr.span,
|
span: attr.span,
|
||||||
|
path: item.path.clone(),
|
||||||
|
kind: match &attr.get_normal_item().args {
|
||||||
|
MacArgs::Empty => MetaItemKind::Word,
|
||||||
|
MacArgs::Eq(_, t) => {
|
||||||
|
let v = parse_in(sess, t.clone(), "name value", |p| p.parse_unsuffixed_lit())?;
|
||||||
|
MetaItemKind::NameValue(v)
|
||||||
|
}
|
||||||
|
MacArgs::Delimited(dspan, delim, t) => {
|
||||||
|
check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters");
|
||||||
|
let nmis = parse_in(sess, t.clone(), "meta list", |p| p.parse_meta_seq_top())?;
|
||||||
|
MetaItemKind::List(nmis)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
AttrKind::DocComment(comment) => {
|
AttrKind::DocComment(comment) => {
|
||||||
mk_name_value_item_str(Ident::new(sym::doc, attr.span), comment, attr.span)
|
mk_name_value_item_str(Ident::new(sym::doc, attr.span), comment, attr.span)
|
||||||
|
@ -37,6 +51,24 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) {
|
||||||
|
if let ast::MacDelimiter::Parenthesis = delim {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sess.span_diagnostic
|
||||||
|
.struct_span_err(span.entire(), msg)
|
||||||
|
.multipart_suggestion(
|
||||||
|
"the delimiters should be `(` and `)`",
|
||||||
|
vec![
|
||||||
|
(span.open, "(".to_string()),
|
||||||
|
(span.close, ")".to_string()),
|
||||||
|
],
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks that the given meta-item is compatible with this `AttributeTemplate`.
|
/// Checks that the given meta-item is compatible with this `AttributeTemplate`.
|
||||||
fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool {
|
fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool {
|
||||||
match meta {
|
match meta {
|
||||||
|
|
|
@ -188,14 +188,14 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>)
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut retain_in_fm = true;
|
let mut error_reported_filter_map = false;
|
||||||
let mut retain_in_map = true;
|
let mut error_reported_map = false;
|
||||||
let traits = nmis
|
let traits = nmis
|
||||||
.into_iter()
|
.into_iter()
|
||||||
// 2) Moreover, let's ensure we have a path and not `#[derive("foo")]`.
|
// 2) Moreover, let's ensure we have a path and not `#[derive("foo")]`.
|
||||||
.filter_map(|nmi| match nmi {
|
.filter_map(|nmi| match nmi {
|
||||||
NestedMetaItem::Literal(lit) => {
|
NestedMetaItem::Literal(lit) => {
|
||||||
retain_in_fm = false;
|
error_reported_filter_map = true;
|
||||||
cx.struct_span_err(lit.span, "expected path to a trait, found literal")
|
cx.struct_span_err(lit.span, "expected path to a trait, found literal")
|
||||||
.help("for example, write `#[derive(Debug)]` for `Debug`")
|
.help("for example, write `#[derive(Debug)]` for `Debug`")
|
||||||
.emit();
|
.emit();
|
||||||
|
@ -209,7 +209,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>)
|
||||||
// wanted this trait to be derived, so let's keep it.
|
// wanted this trait to be derived, so let's keep it.
|
||||||
.map(|mi| {
|
.map(|mi| {
|
||||||
let mut traits_dont_accept = |title, action| {
|
let mut traits_dont_accept = |title, action| {
|
||||||
retain_in_map = false;
|
error_reported_map = true;
|
||||||
let sp = mi.span.with_lo(mi.path.span.hi());
|
let sp = mi.span.with_lo(mi.path.span.hi());
|
||||||
cx.struct_span_err(sp, title)
|
cx.struct_span_err(sp, title)
|
||||||
.span_suggestion(
|
.span_suggestion(
|
||||||
|
@ -235,7 +235,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>)
|
||||||
});
|
});
|
||||||
|
|
||||||
result.extend(traits);
|
result.extend(traits);
|
||||||
retain_in_fm && retain_in_map
|
!error_reported_filter_map && !error_reported_map
|
||||||
});
|
});
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
11
src/test/ui/malformed/malformed-meta-delim.rs
Normal file
11
src/test/ui/malformed/malformed-meta-delim.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
#[allow { foo_lint } ]
|
||||||
|
//~^ ERROR wrong meta list delimiters
|
||||||
|
//~| HELP the delimiters should be `(` and `)`
|
||||||
|
fn delim_brace() {}
|
||||||
|
|
||||||
|
#[allow [ foo_lint ] ]
|
||||||
|
//~^ ERROR wrong meta list delimiters
|
||||||
|
//~| HELP the delimiters should be `(` and `)`
|
||||||
|
fn delim_bracket() {}
|
24
src/test/ui/malformed/malformed-meta-delim.stderr
Normal file
24
src/test/ui/malformed/malformed-meta-delim.stderr
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
error: wrong meta list delimiters
|
||||||
|
--> $DIR/malformed-meta-delim.rs:3:9
|
||||||
|
|
|
||||||
|
LL | #[allow { foo_lint } ]
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: the delimiters should be `(` and `)`
|
||||||
|
|
|
||||||
|
LL | #[allow ( foo_lint ) ]
|
||||||
|
| ^ ^
|
||||||
|
|
||||||
|
error: wrong meta list delimiters
|
||||||
|
--> $DIR/malformed-meta-delim.rs:8:9
|
||||||
|
|
|
||||||
|
LL | #[allow [ foo_lint ] ]
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: the delimiters should be `(` and `)`
|
||||||
|
|
|
||||||
|
LL | #[allow ( foo_lint ) ]
|
||||||
|
| ^ ^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#[rustc_on_unimplemented(
|
#[rustc_on_unimplemented(
|
||||||
message="the message"
|
message="the message"
|
||||||
label="the label" //~ ERROR expected one of `)` or `,`, found `label`
|
label="the label" //~ ERROR expected `,`, found `label`
|
||||||
)]
|
)]
|
||||||
trait T {}
|
trait T {}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
error: expected one of `)` or `,`, found `label`
|
error: expected `,`, found `label`
|
||||||
--> $DIR/expected-comma-found-token.rs:9:5
|
--> $DIR/expected-comma-found-token.rs:9:5
|
||||||
|
|
|
|
||||||
LL | message="the message"
|
LL | message="the message"
|
||||||
| -
|
| - expected `,`
|
||||||
| |
|
|
||||||
| expected one of `)` or `,`
|
|
||||||
| help: missing `,`
|
|
||||||
LL | label="the label"
|
LL | label="the label"
|
||||||
| ^^^^^ unexpected token
|
| ^^^^^ unexpected token
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue