Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand macros in extern {} blocks #49350

Merged
merged 1 commit into from
Apr 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2724,6 +2724,7 @@ impl<'a> LoweringContext<'a> {
hir::ForeignItemStatic(this.lower_ty(t, ImplTraitContext::Disallowed), m)
}
ForeignItemKind::Ty => hir::ForeignItemType,
ForeignItemKind::Macro(_) => panic!("shouldn't exist here"),
},
vis: this.lower_visibility(&i.vis, None),
span: i.span,
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/hir/map/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
}

fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
if let ForeignItemKind::Macro(_) = foreign_item.node {
return self.visit_macro_invoc(foreign_item.id, false);
}

let def = self.create_def(foreign_item.id,
DefPathData::ValueNs(foreign_item.ident.name.as_str()),
REGULAR_SPACE,
Expand Down
18 changes: 17 additions & 1 deletion src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
.span_label(span, "pattern not allowed in foreign function").emit();
});
}
ForeignItemKind::Static(..) | ForeignItemKind::Ty => {}
ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {}
}

visit::walk_foreign_item(self, fi)
Expand Down Expand Up @@ -460,6 +460,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
visit::walk_poly_trait_ref(self, t, m);
}

fn visit_mac(&mut self, mac: &Spanned<Mac_>) {
// when a new macro kind is added but the author forgets to set it up for expansion
// because that's the only part that won't cause a compiler error
self.session.diagnostic()
.span_bug(mac.span, "macro invocation missed in expansion; did you forget to override \
the relevant `fold_*()` method in `PlaceholderExpander`?");
}
}

// Bans nested `impl Trait`, e.g. `impl Into<impl Debug>`.
Expand Down Expand Up @@ -522,6 +530,10 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> {
}
}
}

fn visit_mac(&mut self, _mac: &Spanned<Mac_>) {
// covered in AstValidator
}
}

// Bans `impl Trait` in path projections like `<impl Iterator>::Item` or `Foo::Bar<impl Trait>`.
Expand Down Expand Up @@ -583,6 +595,10 @@ impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> {
_ => visit::walk_ty(self, t),
}
}

fn visit_mac(&mut self, _mac: &Spanned<Mac_>) {
// covered in AstValidator
}
}

pub fn check_crate(session: &Session, krate: &Crate) {
Expand Down
6 changes: 6 additions & 0 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ impl<'a> Resolver<'a> {
ForeignItemKind::Ty => {
(Def::TyForeign(self.definitions.local_def_id(item.id)), TypeNS)
}
ForeignItemKind::Macro(_) => unreachable!(),
};
let parent = self.current_module;
let vis = self.resolve_visibility(&item.vis);
Expand Down Expand Up @@ -816,6 +817,11 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
}

fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
if let ForeignItemKind::Macro(_) = foreign_item.node {
self.visit_invoc(foreign_item.id);
return;
}

self.resolver.build_reduced_graph_for_foreign_item(foreign_item, self.expansion);
visit::walk_foreign_item(self, foreign_item);
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
}
ForeignItemKind::Static(..) => NoTypeParameters,
ForeignItemKind::Ty => NoTypeParameters,
ForeignItemKind::Macro(..) => NoTypeParameters,
};
self.with_type_parameter_rib(type_parameters, |this| {
visit::walk_foreign_item(this, foreign_item);
Expand Down
1 change: 1 addition & 0 deletions src/librustc_save_analysis/dump_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1812,6 +1812,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
self.dumper.dump_def(&access, var_data);
}
}
ast::ForeignItemKind::Macro(..) => {}
}
}
}
1 change: 1 addition & 0 deletions src/librustc_save_analysis/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
}
// FIXME(plietar): needs a new DefKind in rls-data
ast::ForeignItemKind::Ty => None,
ast::ForeignItemKind::Macro(..) => None,
}
}

Expand Down
1 change: 1 addition & 0 deletions src/librustc_save_analysis/sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,7 @@ impl Sig for ast::ForeignItem {
refs: vec![],
})
}
ast::ForeignItemKind::Macro(..) => Err("macro"),
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2195,6 +2195,8 @@ pub enum ForeignItemKind {
Static(P<Ty>, bool),
/// A foreign type
Ty,
/// A macro invocation
Macro(Mac),
}

impl ForeignItemKind {
Expand All @@ -2203,6 +2205,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>),
Stmt(P<ast::Stmt>),
Expr(P<ast::Expr>),
}
Expand All @@ -48,6 +49,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,
Annotatable::Stmt(ref stmt) => stmt.attrs(),
Annotatable::Expr(ref expr) => &expr.attrs,
}
Expand All @@ -58,6 +60,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(foreign_item) =>
Annotatable::ForeignItem(foreign_item.map_attrs(f)),
Annotatable::Stmt(stmt) => Annotatable::Stmt(stmt.map_attrs(f)),
Annotatable::Expr(expr) => Annotatable::Expr(expr.map_attrs(f)),
}
Expand All @@ -70,6 +74,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,
Annotatable::Stmt(ref stmt) => stmt.span,
Annotatable::Expr(ref expr) => expr.span,
}
Expand Down Expand Up @@ -106,6 +111,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 @@ -317,6 +329,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 @@ -365,6 +380,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 @@ -386,6 +402,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 @@ -502,6 +522,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
58 changes: 58 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 All @@ -149,6 +151,8 @@ impl ExpansionKind {
Expansion::ImplItems(items.map(Annotatable::expect_impl_item).collect()),
ExpansionKind::TraitItems =>
Expansion::TraitItems(items.map(Annotatable::expect_trait_item).collect()),
ExpansionKind::ForeignItems =>
Expansion::ForeignItems(items.map(Annotatable::expect_foreign_item).collect()),
_ => unreachable!(),
}
}
Expand Down Expand Up @@ -435,6 +439,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())
)
}
Annotatable::Stmt(stmt) => {
Annotatable::Stmt(stmt.map(|stmt| cfg.fold_stmt(stmt).pop().unwrap()))
}
Expand Down Expand Up @@ -509,6 +518,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()),
Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()),
Annotatable::Expr(expr) => token::NtExpr(expr),
})).into();
Expand Down Expand Up @@ -793,6 +803,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 @@ -1166,6 +1185,44 @@ 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);

let explain = if self.cx.ecfg.proc_macro_enabled() {
feature_gate::EXPLAIN_PROC_MACROS_IN_EXTERN
} else {
feature_gate::EXPLAIN_MACROS_IN_EXTERN
};

if attr.is_some() || !traits.is_empty() {
if !self.cx.ecfg.macros_in_extern_enabled() {
if let Some(ref attr) = attr {
emit_feature_err(&self.cx.parse_sess, "macros_in_extern", attr.span,
GateIssue::Language, explain);
}
}

let item = Annotatable::ForeignItem(P(foreign_item));
return self.collect_attr(attr, traits, item, ExpansionKind::ForeignItems)
.make_foreign_items();
}

if let ast::ForeignItemKind::Macro(mac) = foreign_item.node {
self.check_attributes(&foreign_item.attrs);

if !self.cx.ecfg.macros_in_extern_enabled() {
emit_feature_err(&self.cx.parse_sess, "macros_in_extern", foreign_item.span,
GateIssue::Language, explain);
}

return self.collect_bang(mac, foreign_item.span, ExpansionKind::ForeignItems)
.make_foreign_items();
}

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 Expand Up @@ -1311,6 +1368,7 @@ impl<'feat> ExpansionConfig<'feat> {
fn enable_allow_internal_unstable = allow_internal_unstable,
fn enable_custom_derive = custom_derive,
fn proc_macro_enabled = proc_macro,
fn macros_in_extern_enabled = macros_in_extern,
}
}

Expand Down
11 changes: 11 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 Expand Up @@ -132,6 +136,13 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
}
}

fn fold_foreign_item(&mut self, item: ast::ForeignItem) -> SmallVector<ast::ForeignItem> {
match item.node {
ast::ForeignItemKind::Macro(_) => self.remove(item.id).make_foreign_items(),
_ => noop_fold_foreign_item(item, self),
}
}

fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
match expr.node {
ast::ExprKind::Mac(_) => self.remove(expr.id).make_expr(),
Expand Down
11 changes: 11 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,9 @@ declare_features! (

// Allows keywords to be escaped for use as identifiers
(active, raw_identifiers, "1.26.0", Some(48589), None),

// Allows macro invocations in `extern {}` blocks
(active, macros_in_extern, "1.27.0", Some(49476), None),
);

declare_features! (
Expand Down Expand Up @@ -1296,6 +1299,13 @@ pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
pub const EXPLAIN_MACRO_AT_MOST_ONCE_REP: &'static str =
"Using the `?` macro Kleene operator for \"at most one\" repetition is unstable";

pub const EXPLAIN_MACROS_IN_EXTERN: &'static str =
"Macro invocations in `extern {}` blocks are experimental.";

// mention proc-macros when enabled
pub const EXPLAIN_PROC_MACROS_IN_EXTERN: &'static str =
"Macro and proc-macro invocations in `extern {}` blocks are experimental.";

struct PostExpansionVisitor<'a> {
context: &'a Context<'a>,
}
Expand Down Expand Up @@ -1600,6 +1610,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
gate_feature_post!(&self, extern_types, i.span,
"extern types are experimental");
}
ast::ForeignItemKind::Macro(..) => {}
}

visit::walk_foreign_item(self, i)
Expand Down
Loading