Skip to content

Commit

Permalink
WIP: expand attribute macros in extern {} blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
abonander committed Mar 16, 2018
1 parent d0b50ee commit 3e20e2f
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 8 deletions.
3 changes: 3 additions & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2172,6 +2172,8 @@ pub enum ForeignItemKind {
Static(P<Ty>, bool),
/// A foreign type
Ty,
/// A macro invocation (not really supported)
Macro(Mac),
}

impl ForeignItemKind {
Expand All @@ -2180,6 +2182,7 @@ impl ForeignItemKind {
ForeignItemKind::Fn(..) => "foreign function",
ForeignItemKind::Static(..) => "foreign static item",
ForeignItemKind::Ty => "foreign type",
ForeignItemKind::Macro(..) => "macro in foreign module",
}
}
}
Expand Down
28 changes: 28 additions & 0 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub enum Annotatable {
Item(P<ast::Item>),
TraitItem(P<ast::TraitItem>),
ImplItem(P<ast::ImplItem>),
ForeignItem(P<ast::ForeignItem>),
}

impl HasAttrs for Annotatable {
Expand All @@ -46,6 +47,7 @@ impl HasAttrs for Annotatable {
Annotatable::Item(ref item) => &item.attrs,
Annotatable::TraitItem(ref trait_item) => &trait_item.attrs,
Annotatable::ImplItem(ref impl_item) => &impl_item.attrs,
Annotatable::ForeignItem(ref foreign_item) => &foreign_item.attrs,
}
}

Expand All @@ -54,6 +56,8 @@ impl HasAttrs for Annotatable {
Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)),
Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)),
Annotatable::ImplItem(impl_item) => Annotatable::ImplItem(impl_item.map_attrs(f)),
Annotatable::ForeignItem(ref foreign_item) =>
Annotatable::ForeignItem(foreign_item.map_attrs(f)),
}
}
}
Expand All @@ -64,6 +68,7 @@ impl Annotatable {
Annotatable::Item(ref item) => item.span,
Annotatable::TraitItem(ref trait_item) => trait_item.span,
Annotatable::ImplItem(ref impl_item) => impl_item.span,
Annotatable::ForeignItem(ref foreign_item) => foreign_item.span,
}
}

Expand Down Expand Up @@ -98,6 +103,13 @@ impl Annotatable {
}
}

pub fn expect_foreign_item(self) -> ast::ForeignItem {
match self {
Annotatable::ForeignItem(i) => i.into_inner(),
_ => panic!("expected foreign item")
}
}

pub fn derive_allowed(&self) -> bool {
match *self {
Annotatable::Item(ref item) => match item.node {
Expand Down Expand Up @@ -308,6 +320,9 @@ pub trait MacResult {
None
}

/// Create zero or more items in an `extern {}` block
fn make_foreign_items(self: Box<Self>) -> Option<SmallVector<ast::ForeignItem>> { None }

/// Create a pattern.
fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> {
None
Expand Down Expand Up @@ -356,6 +371,7 @@ make_MacEager! {
items: SmallVector<P<ast::Item>>,
impl_items: SmallVector<ast::ImplItem>,
trait_items: SmallVector<ast::TraitItem>,
foreign_items: SmallVector<ast::ForeignItem>,
stmts: SmallVector<ast::Stmt>,
ty: P<ast::Ty>,
}
Expand All @@ -377,6 +393,10 @@ impl MacResult for MacEager {
self.trait_items
}

fn make_foreign_items(self: Box<Self>) -> Option<SmallVector<ast::ForeignItem>> {
self.foreign_items
}

fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> {
match self.stmts.as_ref().map_or(0, |s| s.len()) {
0 => make_stmts_default!(self),
Expand Down Expand Up @@ -493,6 +513,14 @@ impl MacResult for DummyResult {
}
}

fn make_foreign_items(self: Box<Self>) -> Option<SmallVector<ast::ForeignItem>> {
if self.expr_only {
None
} else {
Some(SmallVector::new())
}
}

fn make_stmts(self: Box<DummyResult>) -> Option<SmallVector<ast::Stmt>> {
Some(SmallVector::one(ast::Stmt {
id: ast::DUMMY_NODE_ID,
Expand Down
29 changes: 29 additions & 0 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ expansions! {
"trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
ImplItems: SmallVector<ast::ImplItem> [SmallVector, ast::ImplItem],
"impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item;
ForeignItems: SmallVector<ast::ForeignItem> [SmallVector, ast::ForeignItem],
"foreign item", .make_foreign_items, lift .fold_foreign_item, lift .visit_foreign_item;
}

impl ExpansionKind {
Expand Down Expand Up @@ -434,6 +436,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
Annotatable::ImplItem(item) => {
Annotatable::ImplItem(item.map(|item| cfg.fold_impl_item(item).pop().unwrap()))
}
Annotatable::ForeignItem(item) => {
Annotatable::ForeignItem(
item.map(|item| cfg.fold_foreign_item(item).pop().unwrap())
)
}
}
}

Expand Down Expand Up @@ -500,6 +507,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
Annotatable::Item(item) => token::NtItem(item),
Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()),
Annotatable::ImplItem(item) => token::NtImplItem(item.into_inner()),
Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()),
})).into();
let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_tok);
self.parse_expansion(tok_result, kind, &attr.path, attr.span)
Expand Down Expand Up @@ -758,6 +766,15 @@ impl<'a> Parser<'a> {
}
Expansion::ImplItems(items)
}
ExpansionKind::ForeignItems => {
let mut items = SmallVector::new();
while self.token != token::Eof {
if let Some(item) = self.parse_foreign_item()? {
items.push(item);
}
}
Expansion::ForeignItems(items)
}
ExpansionKind::Stmts => {
let mut stmts = SmallVector::new();
while self.token != token::Eof &&
Expand Down Expand Up @@ -1089,6 +1106,18 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
noop_fold_foreign_mod(self.cfg.configure_foreign_mod(foreign_mod), self)
}

fn fold_foreign_item(&mut self, foreign_item: ast::ForeignItem) -> SmallVector<ast::ForeignItem> {
let (attr, traits, foreign_item) = self.classify_item(foreign_item);

if attr.is_some() || !traits.is_empty() {
let item = Annotatable::ForeignItem(P(foreign_item));
return self.collect_attr(attr, traits, item, ExpansionKind::ForeignItems)
.make_foreign_items();
}

return noop_fold_foreign_item(foreign_item, self);
}

fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
match item {
ast::ItemKind::MacroDef(..) => item,
Expand Down
4 changes: 4 additions & 0 deletions src/libsyntax/ext/placeholders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
defaultness: ast::Defaultness::Final,
tokens: None,
})),
ExpansionKind::ForeignItems => Expansion::ForeignItems(SmallVector::one(ast::ForeignItem {
id, span, ident, vis, attrs,
node: ast::ForeignItemKind::Macro(mac_placeholder()),
})),
ExpansionKind::Pat => Expansion::Pat(P(ast::Pat {
id, span, node: ast::PatKind::Mac(mac_placeholder()),
})),
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1556,6 +1556,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
gate_feature_post!(&self, extern_types, i.span,
"extern types are experimental");
}
ast::ForeignItemKind::Macro(..) => {
// FIXME: do we allow macro invocs in `extern {}`?
}
}

visit::walk_foreign_item(self, i)
Expand Down
16 changes: 13 additions & 3 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,14 @@ pub trait Folder : Sized {
noop_fold_use_tree(use_tree, self)
}

fn fold_foreign_item(&mut self, ni: ForeignItem) -> ForeignItem {
fn fold_foreign_item(&mut self, ni: ForeignItem) -> SmallVector<ForeignItem> {
noop_fold_foreign_item(ni, self)
}

fn fold_foreign_item_simple(&mut self, ni: ForeignItem) -> ForeignItem {
noop_fold_foreign_item_simple(ni, self)
}

fn fold_item(&mut self, i: P<Item>) -> SmallVector<P<Item>> {
noop_fold_item(i, self)
}
Expand Down Expand Up @@ -413,7 +417,7 @@ pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod {abi, items}: ForeignMod,
fld: &mut T) -> ForeignMod {
ForeignMod {
abi,
items: items.move_map(|x| fld.fold_foreign_item(x)),
items: items.move_flat_map(|x| fld.fold_foreign_item(x)),
}
}

Expand Down Expand Up @@ -1070,7 +1074,12 @@ pub fn noop_fold_item_simple<T: Folder>(Item {id, ident, attrs, node, vis, span,
}
}

pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> ForeignItem {
pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T)
-> SmallVector<ForeignItem> {
SmallVector::one(folder.fold_foreign_item_simple(ni))
}

pub fn noop_fold_foreign_item_simple<T: Folder>(ni: ForeignItem, folder: &mut T) -> ForeignItem {
ForeignItem {
id: folder.new_id(ni.id),
vis: folder.fold_vis(ni.vis),
Expand All @@ -1084,6 +1093,7 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> For
ForeignItemKind::Static(folder.fold_ty(t), m)
}
ForeignItemKind::Ty => ForeignItemKind::Ty,
ForeignItemKind::Macro(mac) => ForeignItemKind::Macro(folder.fold_mac(mac)),
},
span: folder.new_span(ni.span)
}
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6776,7 +6776,7 @@ impl<'a> Parser<'a> {
}

/// Parse a foreign item.
fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> {
pub fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> {
let attrs = self.parse_outer_attributes()?;
let lo = self.span;
let visibility = self.parse_visibility(false)?;
Expand Down
2 changes: 2 additions & 0 deletions src/libsyntax/parse/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,7 @@ pub enum Nonterminal {
NtArm(ast::Arm),
NtImplItem(ast::ImplItem),
NtTraitItem(ast::TraitItem),
NtForeignItem(ast::ForeignItem),
NtGenerics(ast::Generics),
NtWhereClause(ast::WhereClause),
NtArg(ast::Arg),
Expand All @@ -561,6 +562,7 @@ impl fmt::Debug for Nonterminal {
NtArm(..) => f.pad("NtArm(..)"),
NtImplItem(..) => f.pad("NtImplItem(..)"),
NtTraitItem(..) => f.pad("NtTraitItem(..)"),
NtForeignItem(..) => f.pad("NtForeignItem(..)"),
NtGenerics(..) => f.pad("NtGenerics(..)"),
NtWhereClause(..) => f.pad("NtWhereClause(..)"),
NtArg(..) => f.pad("NtArg(..)"),
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1126,6 +1126,9 @@ impl<'a> State<'a> {
self.end()?; // end the head-ibox
self.end() // end the outer cbox
}
ast::ForeignItemKind::Macro(..) => {
// FIXME: stub for now
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a
}
ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
ForeignItemKind::Ty => (),
ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac),
}

walk_list!(visitor, visit_attribute, &foreign_item.attrs);
Expand Down
11 changes: 7 additions & 4 deletions src/test/run-pass-fulldeps/proc-macro/attr-more-places.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,25 @@

// aux-build:nop-attr.rs
// ignore-stage1
#![feature(proc_macro)]

extern crate nop_attr;

use nop_attr::{nop_attr, no_output};

fn main() {
#[nop_attr]
println!("Hello, world!");
let string = "Hello, world!";

This comment has been minimized.

Copy link
@abonander

abonander Mar 16, 2018

Author Owner

I'm doing attributes on statements/expressions on a separate branch now so this test has some redundancies.


#[nop_attr]
println!("{}", string);

#[no_output]
{
println!("Hello, world!");
unsafe { some_definitely_unknown_symbol_which_should_be_removed() };
}
}

extern {
#[no_output]
fn read();
fn some_definitely_unknown_symbol_which_should_be_removed();
}

0 comments on commit 3e20e2f

Please sign in to comment.