Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit dc3d878

Browse files
author
Joseph Dunne
committedJun 13, 2016
Add support for macro expansion inside trait items
1 parent 0740a93 commit dc3d878

File tree

15 files changed

+238
-87
lines changed

15 files changed

+238
-87
lines changed
 

‎src/librustc/hir/lowering.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,7 @@ impl<'a> LoweringContext<'a> {
700700
hir::TypeTraitItem(this.lower_bounds(bounds),
701701
default.as_ref().map(|x| this.lower_ty(x)))
702702
}
703+
TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
703704
},
704705
span: i.span,
705706
}

‎src/librustc/hir/map/def_collector.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ impl<'ast> visit::Visitor<'ast> for DefCollector<'ast> {
204204
TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
205205
DefPathData::ValueNs(ti.ident.name),
206206
TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name),
207+
TraitItemKind::Macro(..) => DefPathData::MacroDef(ti.ident.name),
207208
};
208209

209210
let def = self.create_def(ti.id, def_data);

‎src/librustc_resolve/build_reduced_graph.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ impl<'b> Resolver<'b> {
313313
(Def::Method(item_def_id), ValueNS)
314314
}
315315
TraitItemKind::Type(..) => (Def::AssociatedTy(def_id, item_def_id), TypeNS),
316+
TraitItemKind::Macro(_) => panic!("unexpanded macro in resolve!"),
316317
};
317318

318319
self.define(module_parent, item.ident.name, ns, (def, item.span, vis));

‎src/librustc_resolve/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,7 @@ impl<'a> Resolver<'a> {
16921692
visit::walk_trait_item(this, trait_item)
16931693
});
16941694
}
1695+
TraitItemKind::Macro(_) => panic!("unexpanded macro in resolve!"),
16951696
};
16961697
}
16971698
});

‎src/librustc_save_analysis/dump_visitor.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1204,7 +1204,8 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx,
12041204
trait_item.span);
12051205
}
12061206
ast::TraitItemKind::Const(_, None) |
1207-
ast::TraitItemKind::Type(..) => {}
1207+
ast::TraitItemKind::Type(..) |
1208+
ast::TraitItemKind::Macro(_) => {}
12081209
}
12091210
}
12101211

‎src/libsyntax/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,7 @@ pub enum TraitItemKind {
13901390
Const(P<Ty>, Option<P<Expr>>),
13911391
Method(MethodSig, Option<P<Block>>),
13921392
Type(TyParamBounds, Option<P<Ty>>),
1393+
Macro(Mac),
13931394
}
13941395

13951396
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]

‎src/libsyntax/ext/base.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,11 @@ pub trait MacResult {
227227
None
228228
}
229229

230+
/// Create zero or more trait items.
231+
fn make_trait_items(self: Box<Self>) -> Option<SmallVector<ast::TraitItem>> {
232+
None
233+
}
234+
230235
/// Create a pattern.
231236
fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> {
232237
None
@@ -274,6 +279,7 @@ make_MacEager! {
274279
pat: P<ast::Pat>,
275280
items: SmallVector<P<ast::Item>>,
276281
impl_items: SmallVector<ast::ImplItem>,
282+
trait_items: SmallVector<ast::TraitItem>,
277283
stmts: SmallVector<ast::Stmt>,
278284
ty: P<ast::Ty>,
279285
}
@@ -291,6 +297,10 @@ impl MacResult for MacEager {
291297
self.impl_items
292298
}
293299

300+
fn make_trait_items(self: Box<Self>) -> Option<SmallVector<ast::TraitItem>> {
301+
self.trait_items
302+
}
303+
294304
fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> {
295305
match self.stmts.as_ref().map_or(0, |s| s.len()) {
296306
0 => make_stmts_default!(self),
@@ -399,6 +409,14 @@ impl MacResult for DummyResult {
399409
}
400410
}
401411

412+
fn make_trait_items(self: Box<DummyResult>) -> Option<SmallVector<ast::TraitItem>> {
413+
if self.expr_only {
414+
None
415+
} else {
416+
Some(SmallVector::zero())
417+
}
418+
}
419+
402420
fn make_stmts(self: Box<DummyResult>) -> Option<SmallVector<ast::Stmt>> {
403421
Some(SmallVector::one(
404422
codemap::respan(self.span,

‎src/libsyntax/ext/expand.rs

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ impl_macro_generable! {
7070
P<ast::Ty>: "type", .make_ty, .fold_ty, |span| DummyResult::raw_ty(span);
7171
SmallVector<ast::ImplItem>:
7272
"impl item", .make_impl_items, lift .fold_impl_item, |_span| SmallVector::zero();
73+
SmallVector<ast::TraitItem>:
74+
"trait item", .make_trait_items, lift .fold_trait_item, |_span| SmallVector::zero();
7375
SmallVector<P<ast::Item>>:
7476
"item", .make_items, lift .fold_item, |_span| SmallVector::zero();
7577
SmallVector<ast::Stmt>:
@@ -760,25 +762,10 @@ fn expand_annotatable(a: Annotatable,
760762
_ => noop_fold_item(it, fld),
761763
}.into_iter().map(|i| Annotatable::Item(i)).collect(),
762764

763-
Annotatable::TraitItem(it) => match it.node {
764-
ast::TraitItemKind::Method(_, Some(_)) => {
765-
let ti = it.unwrap();
766-
SmallVector::one(ast::TraitItem {
767-
id: ti.id,
768-
ident: ti.ident,
769-
attrs: ti.attrs,
770-
node: match ti.node {
771-
ast::TraitItemKind::Method(sig, Some(body)) => {
772-
let (sig, body) = expand_and_rename_method(sig, body, fld);
773-
ast::TraitItemKind::Method(sig, Some(body))
774-
}
775-
_ => unreachable!()
776-
},
777-
span: ti.span,
778-
})
779-
}
780-
_ => fold::noop_fold_trait_item(it.unwrap(), fld)
781-
}.into_iter().map(|ti| Annotatable::TraitItem(P(ti))).collect(),
765+
Annotatable::TraitItem(it) => {
766+
expand_trait_item(it.unwrap(), fld).into_iter().
767+
map(|it| Annotatable::TraitItem(P(it))).collect()
768+
}
782769

783770
Annotatable::ImplItem(ii) => {
784771
expand_impl_item(ii.unwrap(), fld).into_iter().
@@ -934,6 +921,31 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
934921
}
935922
}
936923

924+
fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
925+
-> SmallVector<ast::TraitItem> {
926+
match ti.node {
927+
ast::TraitItemKind::Method(_, Some(_)) => {
928+
SmallVector::one(ast::TraitItem {
929+
id: ti.id,
930+
ident: ti.ident,
931+
attrs: ti.attrs,
932+
node: match ti.node {
933+
ast::TraitItemKind::Method(sig, Some(body)) => {
934+
let (sig, body) = expand_and_rename_method(sig, body, fld);
935+
ast::TraitItemKind::Method(sig, Some(body))
936+
}
937+
_ => unreachable!()
938+
},
939+
span: ti.span,
940+
})
941+
}
942+
ast::TraitItemKind::Macro(mac) => {
943+
expand_mac_invoc(mac, None, ti.attrs, ti.span, fld)
944+
}
945+
_ => fold::noop_fold_trait_item(ti, fld)
946+
}
947+
}
948+
937949
/// Given a fn_decl and a block and a MacroExpander, expand the fn_decl, then use the
938950
/// PatIdents in its arguments to perform renaming in the FnDecl and
939951
/// the block, returning both the new FnDecl and the new Block.

‎src/libsyntax/ext/tt/macro_rules.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,21 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
100100
Some(ret)
101101
}
102102

103+
fn make_trait_items(self: Box<ParserAnyMacro<'a>>)
104+
-> Option<SmallVector<ast::TraitItem>> {
105+
let mut ret = SmallVector::zero();
106+
loop {
107+
let mut parser = self.parser.borrow_mut();
108+
match parser.token {
109+
token::Eof => break,
110+
_ => ret.push(panictry!(parser.parse_trait_item()))
111+
}
112+
}
113+
self.ensure_complete_parse(false, "item");
114+
Some(ret)
115+
}
116+
117+
103118
fn make_stmts(self: Box<ParserAnyMacro<'a>>)
104119
-> Option<SmallVector<ast::Stmt>> {
105120
let mut ret = SmallVector::zero();

‎src/libsyntax/fold.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,9 @@ pub fn noop_fold_trait_item<T: Folder>(i: TraitItem, folder: &mut T)
945945
TraitItemKind::Type(folder.fold_bounds(bounds),
946946
default.map(|x| folder.fold_ty(x)))
947947
}
948+
ast::TraitItemKind::Macro(mac) => {
949+
TraitItemKind::Macro(folder.fold_mac(mac))
950+
}
948951
},
949952
span: folder.new_span(i.span)
950953
})

‎src/libsyntax/parse/parser.rs

Lines changed: 91 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,73 +1232,88 @@ impl<'a> Parser<'a> {
12321232
}
12331233

12341234
/// Parse the items in a trait declaration
1235-
pub fn parse_trait_items(&mut self) -> PResult<'a, Vec<TraitItem>> {
1236-
self.parse_unspanned_seq(
1237-
&token::OpenDelim(token::Brace),
1238-
&token::CloseDelim(token::Brace),
1239-
SeqSep::none(),
1240-
|p| -> PResult<'a, TraitItem> {
1241-
maybe_whole!(no_clone_from_p p, NtTraitItem);
1242-
let mut attrs = p.parse_outer_attributes()?;
1243-
let lo = p.span.lo;
1244-
1245-
let (name, node) = if p.eat_keyword(keywords::Type) {
1246-
let TyParam {ident, bounds, default, ..} = p.parse_ty_param()?;
1247-
p.expect(&token::Semi)?;
1248-
(ident, TraitItemKind::Type(bounds, default))
1249-
} else if p.is_const_item() {
1250-
p.expect_keyword(keywords::Const)?;
1251-
let ident = p.parse_ident()?;
1252-
p.expect(&token::Colon)?;
1253-
let ty = p.parse_ty_sum()?;
1254-
let default = if p.check(&token::Eq) {
1255-
p.bump();
1256-
let expr = p.parse_expr()?;
1257-
p.commit_expr_expecting(&expr, token::Semi)?;
1258-
Some(expr)
1259-
} else {
1260-
p.expect(&token::Semi)?;
1261-
None
1262-
};
1263-
(ident, TraitItemKind::Const(ty, default))
1235+
pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> {
1236+
maybe_whole!(no_clone_from_p self, NtTraitItem);
1237+
let mut attrs = self.parse_outer_attributes()?;
1238+
let lo = self.span.lo;
1239+
1240+
let (name, node) = if self.eat_keyword(keywords::Type) {
1241+
let TyParam {ident, bounds, default, ..} = self.parse_ty_param()?;
1242+
self.expect(&token::Semi)?;
1243+
(ident, TraitItemKind::Type(bounds, default))
1244+
} else if self.is_const_item() {
1245+
self.expect_keyword(keywords::Const)?;
1246+
let ident = self.parse_ident()?;
1247+
self.expect(&token::Colon)?;
1248+
let ty = self.parse_ty_sum()?;
1249+
let default = if self.check(&token::Eq) {
1250+
self.bump();
1251+
let expr = self.parse_expr()?;
1252+
self.commit_expr_expecting(&expr, token::Semi)?;
1253+
Some(expr)
1254+
} else {
1255+
self.expect(&token::Semi)?;
1256+
None
1257+
};
1258+
(ident, TraitItemKind::Const(ty, default))
1259+
} else if !self.token.is_any_keyword()
1260+
&& self.look_ahead(1, |t| *t == token::Not)
1261+
&& (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
1262+
|| self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) {
1263+
// trait item macro.
1264+
// code copied from parse_macro_use_or_failure... abstraction!
1265+
let lo = self.span.lo;
1266+
let pth = self.parse_ident_into_path()?;
1267+
self.expect(&token::Not)?;
1268+
1269+
// eat a matched-delimiter token tree:
1270+
let delim = self.expect_open_delim()?;
1271+
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
1272+
SeqSep::none(),
1273+
|pp| pp.parse_token_tree())?;
1274+
let m_ = Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT };
1275+
let m: ast::Mac = codemap::Spanned { node: m_,
1276+
span: mk_sp(lo,
1277+
self.last_span.hi) };
1278+
if delim != token::Brace {
1279+
self.expect(&token::Semi)?
1280+
}
1281+
(keywords::Invalid.ident(), ast::TraitItemKind::Macro(m))
12641282
} else {
1265-
let (constness, unsafety, abi) = match p.parse_fn_front_matter() {
1283+
let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
12661284
Ok(cua) => cua,
12671285
Err(e) => {
12681286
loop {
1269-
match p.token {
1287+
match self.token {
12701288
token::Eof => break,
1271-
12721289
token::CloseDelim(token::Brace) |
12731290
token::Semi => {
1274-
p.bump();
1291+
self.bump();
12751292
break;
12761293
}
1277-
12781294
token::OpenDelim(token::Brace) => {
1279-
p.parse_token_tree()?;
1295+
self.parse_token_tree()?;
12801296
break;
12811297
}
1282-
1283-
_ => p.bump()
1298+
_ => self.bump()
12841299
}
12851300
}
12861301

12871302
return Err(e);
12881303
}
12891304
};
12901305

1291-
let ident = p.parse_ident()?;
1292-
let mut generics = p.parse_generics()?;
1306+
let ident = self.parse_ident()?;
1307+
let mut generics = self.parse_generics()?;
12931308

1294-
let d = p.parse_fn_decl_with_self(|p: &mut Parser<'a>|{
1309+
let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{
12951310
// This is somewhat dubious; We don't want to allow
12961311
// argument names to be left off if there is a
12971312
// definition...
12981313
p.parse_arg_general(false)
12991314
})?;
13001315

1301-
generics.where_clause = p.parse_where_clause()?;
1316+
generics.where_clause = self.parse_where_clause()?;
13021317
let sig = ast::MethodSig {
13031318
unsafety: unsafety,
13041319
constness: constness,
@@ -1307,37 +1322,47 @@ impl<'a> Parser<'a> {
13071322
abi: abi,
13081323
};
13091324

1310-
let body = match p.token {
1311-
token::Semi => {
1312-
p.bump();
1313-
debug!("parse_trait_methods(): parsing required method");
1314-
None
1315-
}
1316-
token::OpenDelim(token::Brace) => {
1317-
debug!("parse_trait_methods(): parsing provided method");
1318-
let (inner_attrs, body) =
1319-
p.parse_inner_attrs_and_block()?;
1320-
attrs.extend(inner_attrs.iter().cloned());
1321-
Some(body)
1322-
}
1325+
let body = match self.token {
1326+
token::Semi => {
1327+
self.bump();
1328+
debug!("parse_trait_methods(): parsing required method");
1329+
None
1330+
}
1331+
token::OpenDelim(token::Brace) => {
1332+
debug!("parse_trait_methods(): parsing provided method");
1333+
let (inner_attrs, body) =
1334+
self.parse_inner_attrs_and_block()?;
1335+
attrs.extend(inner_attrs.iter().cloned());
1336+
Some(body)
1337+
}
13231338

1324-
_ => {
1325-
let token_str = p.this_token_to_string();
1326-
return Err(p.fatal(&format!("expected `;` or `{{`, found `{}`",
1327-
token_str)[..]))
1328-
}
1339+
_ => {
1340+
let token_str = self.this_token_to_string();
1341+
return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`",
1342+
token_str)[..]))
1343+
}
13291344
};
13301345
(ident, ast::TraitItemKind::Method(sig, body))
13311346
};
1347+
Ok(TraitItem {
1348+
id: ast::DUMMY_NODE_ID,
1349+
ident: name,
1350+
attrs: attrs,
1351+
node: node,
1352+
span: mk_sp(lo, self.last_span.hi),
1353+
})
1354+
}
13321355

1333-
Ok(TraitItem {
1334-
id: ast::DUMMY_NODE_ID,
1335-
ident: name,
1336-
attrs: attrs,
1337-
node: node,
1338-
span: mk_sp(lo, p.last_span.hi),
1356+
1357+
/// Parse the items in a trait declaration
1358+
pub fn parse_trait_items(&mut self) -> PResult<'a, Vec<TraitItem>> {
1359+
self.parse_unspanned_seq(
1360+
&token::OpenDelim(token::Brace),
1361+
&token::CloseDelim(token::Brace),
1362+
SeqSep::none(),
1363+
|p| -> PResult<'a, TraitItem> {
1364+
p.parse_trait_item()
13391365
})
1340-
})
13411366
}
13421367

13431368
/// Parse a possibly mutable type
@@ -4940,7 +4965,6 @@ impl<'a> Parser<'a> {
49404965

49414966
/// Parse trait Foo { ... }
49424967
fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
4943-
49444968
let ident = self.parse_ident()?;
49454969
let mut tps = self.parse_generics()?;
49464970

‎src/libsyntax/print/pprust.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,6 +1549,17 @@ impl<'a> State<'a> {
15491549
self.print_associated_type(ti.ident, Some(bounds),
15501550
default.as_ref().map(|ty| &**ty))?;
15511551
}
1552+
ast::TraitItemKind::Macro(codemap::Spanned { ref node, .. }) => {
1553+
// code copied from ItemKind::Mac:
1554+
self.print_path(&node.path, false, 0)?;
1555+
word(&mut self.s, "! ")?;
1556+
self.cbox(INDENT_UNIT)?;
1557+
self.popen()?;
1558+
self.print_tts(&node.tts[..])?;
1559+
self.pclose()?;
1560+
word(&mut self.s, ";")?;
1561+
self.end()?
1562+
}
15521563
}
15531564
self.ann.post(self, NodeSubItem(ti.id))
15541565
}

‎src/libsyntax/visit.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,9 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
565565
walk_list!(visitor, visit_ty_param_bound, bounds);
566566
walk_list!(visitor, visit_ty, default);
567567
}
568+
TraitItemKind::Macro(ref mac) => {
569+
visitor.visit_mac(mac);
570+
}
568571
}
569572
}
570573

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2015 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! bah {
12+
($a:expr) => ($a)
13+
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `2`
14+
}
15+
16+
trait bar {
17+
bah!(2);
18+
}
19+
20+
fn main() {}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2015 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+
// Issue #34183
12+
13+
macro_rules! foo {
14+
() => {
15+
fn foo() { }
16+
}
17+
}
18+
19+
macro_rules! bar {
20+
() => {
21+
fn bar();
22+
}
23+
}
24+
25+
trait Bleh {
26+
foo!();
27+
bar!();
28+
}
29+
30+
struct Test;
31+
32+
impl Bleh for Test {
33+
fn bar() {}
34+
}
35+
36+
fn main() {
37+
Test::bar();
38+
Test::foo();
39+
}

0 commit comments

Comments
 (0)
Please sign in to comment.