diff options
| author | Havvy (Ryan Scheel) <ryan.havvy@gmail.com> | 2018-09-10 15:06:49 -0700 |
|---|---|---|
| committer | Havvy (Ryan Scheel) <ryan.havvy@gmail.com> | 2018-10-05 17:29:17 -0700 |
| commit | 1a867dc346a0b9ea5abd8a8504f1908f42ff2dd2 (patch) | |
| tree | df5117610979478bd9f02f14b9eb360c3940b1fa /src/libsyntax | |
| parent | 9568ec6bef514515b14c78c7492186d509048968 (diff) | |
| download | rust-1a867dc346a0b9ea5abd8a8504f1908f42ff2dd2.tar.gz rust-1a867dc346a0b9ea5abd8a8504f1908f42ff2dd2.zip | |
cfg_attr_multi: Basic implementation
Does not implement the warning or a feature flag.
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/config.rs | 59 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 2 |
2 files changed, 44 insertions, 17 deletions
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index a9ce2365577..7a85f628536 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -73,49 +73,76 @@ impl<'a> StripUnconfigured<'a> { if self.in_cfg(node.attrs()) { Some(node) } else { None } } + /// Parse and expand all `cfg_attr` attributes into a list of attributes + /// that are within each `cfg_attr` that has a true configuration predicate. + /// + /// Gives compiler warnigns if any `cfg_attr` does not contain any + /// attributes and is in the original source code. Gives compiler errors if + /// the syntax of any `cfg_attr` is incorrect. pub fn process_cfg_attrs<T: HasAttrs>(&mut self, node: T) -> T { node.map_attrs(|attrs| { - attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect() + attrs.into_iter().flat_map(|attr| self.process_cfg_attr(attr)).collect() }) } - fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> { + /// Parse and expand a single `cfg_attr` attribute into a list of attributes + /// when the configuration predicate is true, or otherwise expand into an + /// empty list of attributes. + /// + /// Gives a compiler warning when the `cfg_attr` contains no attribtes and + /// is in the original source file. Gives a compiler error if the syntax of + /// the attribute is incorrect + fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> { if !attr.check_name("cfg_attr") { - return Some(attr); + return vec![attr]; } - let (cfg, path, tokens, span) = match attr.parse(self.sess, |parser| { + let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| { parser.expect(&token::OpenDelim(token::Paren))?; - let cfg = parser.parse_meta_item()?; + + let cfg_predicate = parser.parse_meta_item()?; parser.expect(&token::Comma)?; - let lo = parser.span.lo(); - let (path, tokens) = parser.parse_meta_item_unrestricted()?; - parser.eat(&token::Comma); // Optional trailing comma + + // Presumably, the majority of the time there will only be one attr. + let mut expanded_attrs = Vec::with_capacity(1); + + while !parser.check(&token::CloseDelim(token::Paren)) { + let lo = parser.span.lo(); + let (path, tokens) = parser.parse_meta_item_unrestricted()?; + expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo))); + parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?; + } + parser.expect(&token::CloseDelim(token::Paren))?; - Ok((cfg, path, tokens, parser.prev_span.with_lo(lo))) + Ok((cfg_predicate, expanded_attrs)) }) { Ok(result) => result, Err(mut e) => { e.emit(); - return None; + return Vec::new(); } }; - if attr::cfg_matches(&cfg, self.sess, self.features) { - self.process_cfg_attr(ast::Attribute { + if attr::cfg_matches(&cfg_predicate, self.sess, self.features) { + // We call `process_cfg_attr` recursively in case there's a + // `cfg_attr` inside of another `cfg_attr`. E.g. + // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. + expanded_attrs.into_iter() + .flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute { id: attr::mk_attr_id(), style: attr.style, path, tokens, is_sugared_doc: false, span, - }) + })) + .collect() } else { - None + Vec::new() } } - // Determine if a node with the given attributes should be included in this configuration. + /// Determine if a node with the given attributes should be included in this configuration. pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { attrs.iter().all(|attr| { if !is_cfg(attr) { @@ -165,7 +192,7 @@ impl<'a> StripUnconfigured<'a> { }) } - // Visit attributes on expression and statements (but not attributes on items in blocks). + /// Visit attributes on expression and statements (but not attributes on items in blocks). fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) { // flag the offending attributes for attr in attrs.iter() { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5571a18b596..a5ee2b0f103 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -678,7 +678,7 @@ impl<'a> Parser<'a> { /// Expect next token to be edible or inedible token. If edible, /// then consume it; if inedible, then return without consuming /// anything. Signal a fatal error if next token is unexpected. - fn expect_one_of(&mut self, + pub fn expect_one_of(&mut self, edible: &[token::Token], inedible: &[token::Token]) -> PResult<'a, ()>{ fn tokens_to_string(tokens: &[TokenType]) -> String { |
