Skip to content

Commit 89b364d

Browse files
authored
Rollup merge of #41050 - jseyfried:fix_derive_parsing, r=petrochenkov
macros: fix bug parsing `#[derive]` invocations Fixes #40962 (introduced in #40346). r? @nrc
2 parents e4a6210 + 6a9448b commit 89b364d

File tree

4 files changed

+46
-3
lines changed

4 files changed

+46
-3
lines changed

src/librustc_resolve/macros.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,10 @@ impl<'a> base::Resolver for Resolver<'a> {
222222
let name = unwrap_or!(attrs[i].name(), continue);
223223

224224
if name == "derive" {
225-
let result = attrs[i].parse_list(&self.session.parse_sess,
226-
|parser| parser.parse_path(PathStyle::Mod));
225+
let result = attrs[i].parse_list(&self.session.parse_sess, |parser| {
226+
parser.parse_path_allowing_meta(PathStyle::Mod)
227+
});
228+
227229
let mut traits = match result {
228230
Ok(traits) => traits,
229231
Err(mut e) => {

src/libsyntax/ext/derive.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec
2626
return true;
2727
}
2828

29-
match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) {
29+
match attr.parse_list(cx.parse_sess,
30+
|parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
3031
Ok(ref traits) if traits.is_empty() => {
3132
cx.span_warn(attr.span, "empty trait list in `derive`");
3233
false

src/libsyntax/parse/parser.rs

+20
Original file line numberDiff line numberDiff line change
@@ -1767,6 +1767,26 @@ impl<'a> Parser<'a> {
17671767
})
17681768
}
17691769

1770+
/// Like `parse_path`, but also supports parsing `Word` meta items into paths for back-compat.
1771+
/// This is used when parsing derive macro paths in `#[derive]` attributes.
1772+
pub fn parse_path_allowing_meta(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> {
1773+
let meta_ident = match self.token {
1774+
token::Interpolated(ref nt) => match **nt {
1775+
token::NtMeta(ref meta) => match meta.node {
1776+
ast::MetaItemKind::Word => Some(ast::Ident::with_empty_ctxt(meta.name)),
1777+
_ => None,
1778+
},
1779+
_ => None,
1780+
},
1781+
_ => None,
1782+
};
1783+
if let Some(ident) = meta_ident {
1784+
self.bump();
1785+
return Ok(ast::Path::from_ident(self.prev_span, ident));
1786+
}
1787+
self.parse_path(mode)
1788+
}
1789+
17701790
/// Examples:
17711791
/// - `a::b<T,U>::c<V,W>`
17721792
/// - `a::b<T,U>::c(V) -> W`

src/test/run-pass/issue-40962.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
macro_rules! m {
12+
($i:meta) => {
13+
#[derive($i)]
14+
struct S;
15+
}
16+
}
17+
18+
m!(Clone);
19+
20+
fn main() {}

0 commit comments

Comments
 (0)