Skip to content

Commit

Permalink
Rollup merge of #41050 - jseyfried:fix_derive_parsing, r=petrochenkov
Browse files Browse the repository at this point in the history
macros: fix bug parsing `#[derive]` invocations

Fixes #40962 (introduced in #40346).
r? @nrc
  • Loading branch information
frewsxcv committed Apr 6, 2017
2 parents e4a6210 + 6a9448b commit 89b364d
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 3 deletions.
6 changes: 4 additions & 2 deletions src/librustc_resolve/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,10 @@ impl<'a> base::Resolver for Resolver<'a> {
let name = unwrap_or!(attrs[i].name(), continue);

if name == "derive" {
let result = attrs[i].parse_list(&self.session.parse_sess,
|parser| parser.parse_path(PathStyle::Mod));
let result = attrs[i].parse_list(&self.session.parse_sess, |parser| {
parser.parse_path_allowing_meta(PathStyle::Mod)
});

let mut traits = match result {
Ok(traits) => traits,
Err(mut e) => {
Expand Down
3 changes: 2 additions & 1 deletion src/libsyntax/ext/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec
return true;
}

match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) {
match attr.parse_list(cx.parse_sess,
|parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
Ok(ref traits) if traits.is_empty() => {
cx.span_warn(attr.span, "empty trait list in `derive`");
false
Expand Down
20 changes: 20 additions & 0 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1767,6 +1767,26 @@ impl<'a> Parser<'a> {
})
}

/// Like `parse_path`, but also supports parsing `Word` meta items into paths for back-compat.
/// This is used when parsing derive macro paths in `#[derive]` attributes.
pub fn parse_path_allowing_meta(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> {
let meta_ident = match self.token {
token::Interpolated(ref nt) => match **nt {
token::NtMeta(ref meta) => match meta.node {
ast::MetaItemKind::Word => Some(ast::Ident::with_empty_ctxt(meta.name)),
_ => None,
},
_ => None,
},
_ => None,
};
if let Some(ident) = meta_ident {
self.bump();
return Ok(ast::Path::from_ident(self.prev_span, ident));
}
self.parse_path(mode)
}

/// Examples:
/// - `a::b<T,U>::c<V,W>`
/// - `a::b<T,U>::c(V) -> W`
Expand Down
20 changes: 20 additions & 0 deletions src/test/run-pass/issue-40962.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

macro_rules! m {
($i:meta) => {
#[derive($i)]
struct S;
}
}

m!(Clone);

fn main() {}

0 comments on commit 89b364d

Please sign in to comment.