expand macro invocations in extern {}
blocks
This commit is contained in:
parent
5ee891cfea
commit
5d74990ceb
31 changed files with 544 additions and 65 deletions
|
@ -2724,6 +2724,7 @@ impl<'a> LoweringContext<'a> {
|
||||||
hir::ForeignItemStatic(this.lower_ty(t, ImplTraitContext::Disallowed), m)
|
hir::ForeignItemStatic(this.lower_ty(t, ImplTraitContext::Disallowed), m)
|
||||||
}
|
}
|
||||||
ForeignItemKind::Ty => hir::ForeignItemType,
|
ForeignItemKind::Ty => hir::ForeignItemType,
|
||||||
|
ForeignItemKind::Macro(_) => panic!("shouldn't exist here"),
|
||||||
},
|
},
|
||||||
vis: this.lower_visibility(&i.vis, None),
|
vis: this.lower_visibility(&i.vis, None),
|
||||||
span: i.span,
|
span: i.span,
|
||||||
|
|
|
@ -181,6 +181,10 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
|
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,
|
let def = self.create_def(foreign_item.id,
|
||||||
DefPathData::ValueNs(foreign_item.ident.name.as_str()),
|
DefPathData::ValueNs(foreign_item.ident.name.as_str()),
|
||||||
REGULAR_SPACE,
|
REGULAR_SPACE,
|
||||||
|
|
|
@ -381,7 +381,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
.span_label(span, "pattern not allowed in foreign function").emit();
|
.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)
|
visit::walk_foreign_item(self, fi)
|
||||||
|
@ -460,6 +460,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
|
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
|
||||||
visit::walk_poly_trait_ref(self, t, m);
|
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>`.
|
// Bans nested `impl Trait`, e.g. `impl Into<impl Debug>`.
|
||||||
|
@ -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>`.
|
// Bans `impl Trait` in path projections like `<impl Iterator>::Item` or `Foo::Bar<impl Trait>`.
|
||||||
|
@ -583,6 +595,10 @@ impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> {
|
||||||
_ => visit::walk_ty(self, t),
|
_ => visit::walk_ty(self, t),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_mac(&mut self, _mac: &Spanned<Mac_>) {
|
||||||
|
// covered in AstValidator
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_crate(session: &Session, krate: &Crate) {
|
pub fn check_crate(session: &Session, krate: &Crate) {
|
||||||
|
|
|
@ -456,6 +456,7 @@ impl<'a> Resolver<'a> {
|
||||||
ForeignItemKind::Ty => {
|
ForeignItemKind::Ty => {
|
||||||
(Def::TyForeign(self.definitions.local_def_id(item.id)), TypeNS)
|
(Def::TyForeign(self.definitions.local_def_id(item.id)), TypeNS)
|
||||||
}
|
}
|
||||||
|
ForeignItemKind::Macro(_) => unreachable!(),
|
||||||
};
|
};
|
||||||
let parent = self.current_module;
|
let parent = self.current_module;
|
||||||
let vis = self.resolve_visibility(&item.vis);
|
let vis = self.resolve_visibility(&item.vis);
|
||||||
|
@ -816,6 +817,11 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
|
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);
|
self.resolver.build_reduced_graph_for_foreign_item(foreign_item, self.expansion);
|
||||||
visit::walk_foreign_item(self, foreign_item);
|
visit::walk_foreign_item(self, foreign_item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -863,6 +863,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
||||||
}
|
}
|
||||||
ForeignItemKind::Static(..) => NoTypeParameters,
|
ForeignItemKind::Static(..) => NoTypeParameters,
|
||||||
ForeignItemKind::Ty => NoTypeParameters,
|
ForeignItemKind::Ty => NoTypeParameters,
|
||||||
|
ForeignItemKind::Macro(..) => NoTypeParameters,
|
||||||
};
|
};
|
||||||
self.with_type_parameter_rib(type_parameters, |this| {
|
self.with_type_parameter_rib(type_parameters, |this| {
|
||||||
visit::walk_foreign_item(this, foreign_item);
|
visit::walk_foreign_item(this, foreign_item);
|
||||||
|
|
|
@ -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);
|
self.dumper.dump_def(&access, var_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast::ForeignItemKind::Macro(..) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,6 +182,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
||||||
}
|
}
|
||||||
// FIXME(plietar): needs a new DefKind in rls-data
|
// FIXME(plietar): needs a new DefKind in rls-data
|
||||||
ast::ForeignItemKind::Ty => None,
|
ast::ForeignItemKind::Ty => None,
|
||||||
|
ast::ForeignItemKind::Macro(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -822,6 +822,7 @@ impl Sig for ast::ForeignItem {
|
||||||
refs: vec![],
|
refs: vec![],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ast::ForeignItemKind::Macro(..) => Err("macro"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2195,6 +2195,8 @@ pub enum ForeignItemKind {
|
||||||
Static(P<Ty>, bool),
|
Static(P<Ty>, bool),
|
||||||
/// A foreign type
|
/// A foreign type
|
||||||
Ty,
|
Ty,
|
||||||
|
/// A macro invocation
|
||||||
|
Macro(Mac),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ForeignItemKind {
|
impl ForeignItemKind {
|
||||||
|
@ -2203,6 +2205,7 @@ impl ForeignItemKind {
|
||||||
ForeignItemKind::Fn(..) => "foreign function",
|
ForeignItemKind::Fn(..) => "foreign function",
|
||||||
ForeignItemKind::Static(..) => "foreign static item",
|
ForeignItemKind::Static(..) => "foreign static item",
|
||||||
ForeignItemKind::Ty => "foreign type",
|
ForeignItemKind::Ty => "foreign type",
|
||||||
|
ForeignItemKind::Macro(..) => "macro in foreign module",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ pub enum Annotatable {
|
||||||
Item(P<ast::Item>),
|
Item(P<ast::Item>),
|
||||||
TraitItem(P<ast::TraitItem>),
|
TraitItem(P<ast::TraitItem>),
|
||||||
ImplItem(P<ast::ImplItem>),
|
ImplItem(P<ast::ImplItem>),
|
||||||
|
ForeignItem(P<ast::ForeignItem>),
|
||||||
Stmt(P<ast::Stmt>),
|
Stmt(P<ast::Stmt>),
|
||||||
Expr(P<ast::Expr>),
|
Expr(P<ast::Expr>),
|
||||||
}
|
}
|
||||||
|
@ -48,6 +49,7 @@ impl HasAttrs for Annotatable {
|
||||||
Annotatable::Item(ref item) => &item.attrs,
|
Annotatable::Item(ref item) => &item.attrs,
|
||||||
Annotatable::TraitItem(ref trait_item) => &trait_item.attrs,
|
Annotatable::TraitItem(ref trait_item) => &trait_item.attrs,
|
||||||
Annotatable::ImplItem(ref impl_item) => &impl_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::Stmt(ref stmt) => stmt.attrs(),
|
||||||
Annotatable::Expr(ref expr) => &expr.attrs,
|
Annotatable::Expr(ref expr) => &expr.attrs,
|
||||||
}
|
}
|
||||||
|
@ -58,6 +60,8 @@ impl HasAttrs for Annotatable {
|
||||||
Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)),
|
Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)),
|
||||||
Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_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::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::Stmt(stmt) => Annotatable::Stmt(stmt.map_attrs(f)),
|
||||||
Annotatable::Expr(expr) => Annotatable::Expr(expr.map_attrs(f)),
|
Annotatable::Expr(expr) => Annotatable::Expr(expr.map_attrs(f)),
|
||||||
}
|
}
|
||||||
|
@ -70,6 +74,7 @@ impl Annotatable {
|
||||||
Annotatable::Item(ref item) => item.span,
|
Annotatable::Item(ref item) => item.span,
|
||||||
Annotatable::TraitItem(ref trait_item) => trait_item.span,
|
Annotatable::TraitItem(ref trait_item) => trait_item.span,
|
||||||
Annotatable::ImplItem(ref impl_item) => impl_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::Stmt(ref stmt) => stmt.span,
|
||||||
Annotatable::Expr(ref expr) => expr.span,
|
Annotatable::Expr(ref expr) => expr.span,
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
pub fn derive_allowed(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Annotatable::Item(ref item) => match item.node {
|
Annotatable::Item(ref item) => match item.node {
|
||||||
|
@ -317,6 +329,9 @@ pub trait MacResult {
|
||||||
None
|
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.
|
/// Create a pattern.
|
||||||
fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> {
|
fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> {
|
||||||
None
|
None
|
||||||
|
@ -365,6 +380,7 @@ make_MacEager! {
|
||||||
items: SmallVector<P<ast::Item>>,
|
items: SmallVector<P<ast::Item>>,
|
||||||
impl_items: SmallVector<ast::ImplItem>,
|
impl_items: SmallVector<ast::ImplItem>,
|
||||||
trait_items: SmallVector<ast::TraitItem>,
|
trait_items: SmallVector<ast::TraitItem>,
|
||||||
|
foreign_items: SmallVector<ast::ForeignItem>,
|
||||||
stmts: SmallVector<ast::Stmt>,
|
stmts: SmallVector<ast::Stmt>,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
}
|
}
|
||||||
|
@ -386,6 +402,10 @@ impl MacResult for MacEager {
|
||||||
self.trait_items
|
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>> {
|
fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> {
|
||||||
match self.stmts.as_ref().map_or(0, |s| s.len()) {
|
match self.stmts.as_ref().map_or(0, |s| s.len()) {
|
||||||
0 => make_stmts_default!(self),
|
0 => make_stmts_default!(self),
|
||||||
|
@ -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>> {
|
fn make_stmts(self: Box<DummyResult>) -> Option<SmallVector<ast::Stmt>> {
|
||||||
Some(SmallVector::one(ast::Stmt {
|
Some(SmallVector::one(ast::Stmt {
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
|
|
@ -133,6 +133,8 @@ expansions! {
|
||||||
"trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
|
"trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
|
||||||
ImplItems: SmallVector<ast::ImplItem> [SmallVector, ast::ImplItem],
|
ImplItems: SmallVector<ast::ImplItem> [SmallVector, ast::ImplItem],
|
||||||
"impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item;
|
"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 {
|
impl ExpansionKind {
|
||||||
|
@ -149,6 +151,8 @@ impl ExpansionKind {
|
||||||
Expansion::ImplItems(items.map(Annotatable::expect_impl_item).collect()),
|
Expansion::ImplItems(items.map(Annotatable::expect_impl_item).collect()),
|
||||||
ExpansionKind::TraitItems =>
|
ExpansionKind::TraitItems =>
|
||||||
Expansion::TraitItems(items.map(Annotatable::expect_trait_item).collect()),
|
Expansion::TraitItems(items.map(Annotatable::expect_trait_item).collect()),
|
||||||
|
ExpansionKind::ForeignItems =>
|
||||||
|
Expansion::ForeignItems(items.map(Annotatable::expect_foreign_item).collect()),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,6 +439,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
Annotatable::ImplItem(item) => {
|
Annotatable::ImplItem(item) => {
|
||||||
Annotatable::ImplItem(item.map(|item| cfg.fold_impl_item(item).pop().unwrap()))
|
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) => {
|
||||||
Annotatable::Stmt(stmt.map(|stmt| cfg.fold_stmt(stmt).pop().unwrap()))
|
Annotatable::Stmt(stmt.map(|stmt| cfg.fold_stmt(stmt).pop().unwrap()))
|
||||||
}
|
}
|
||||||
|
@ -509,6 +518,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
Annotatable::Item(item) => token::NtItem(item),
|
Annotatable::Item(item) => token::NtItem(item),
|
||||||
Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()),
|
Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()),
|
||||||
Annotatable::ImplItem(item) => token::NtImplItem(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::Stmt(stmt) => token::NtStmt(stmt.into_inner()),
|
||||||
Annotatable::Expr(expr) => token::NtExpr(expr),
|
Annotatable::Expr(expr) => token::NtExpr(expr),
|
||||||
})).into();
|
})).into();
|
||||||
|
@ -793,6 +803,15 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
Expansion::ImplItems(items)
|
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 => {
|
ExpansionKind::Stmts => {
|
||||||
let mut stmts = SmallVector::new();
|
let mut stmts = SmallVector::new();
|
||||||
while self.token != token::Eof &&
|
while self.token != token::Eof &&
|
||||||
|
@ -1166,6 +1185,44 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||||
noop_fold_foreign_mod(self.cfg.configure_foreign_mod(foreign_mod), self)
|
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 {
|
fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
|
||||||
match item {
|
match item {
|
||||||
ast::ItemKind::MacroDef(..) => item,
|
ast::ItemKind::MacroDef(..) => item,
|
||||||
|
@ -1311,6 +1368,7 @@ impl<'feat> ExpansionConfig<'feat> {
|
||||||
fn enable_allow_internal_unstable = allow_internal_unstable,
|
fn enable_allow_internal_unstable = allow_internal_unstable,
|
||||||
fn enable_custom_derive = custom_derive,
|
fn enable_custom_derive = custom_derive,
|
||||||
fn proc_macro_enabled = proc_macro,
|
fn proc_macro_enabled = proc_macro,
|
||||||
|
fn macros_in_extern_enabled = macros_in_extern,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,10 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
|
||||||
defaultness: ast::Defaultness::Final,
|
defaultness: ast::Defaultness::Final,
|
||||||
tokens: None,
|
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 {
|
ExpansionKind::Pat => Expansion::Pat(P(ast::Pat {
|
||||||
id, span, node: ast::PatKind::Mac(mac_placeholder()),
|
id, span, node: ast::PatKind::Mac(mac_placeholder()),
|
||||||
})),
|
})),
|
||||||
|
@ -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> {
|
fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
|
||||||
match expr.node {
|
match expr.node {
|
||||||
ast::ExprKind::Mac(_) => self.remove(expr.id).make_expr(),
|
ast::ExprKind::Mac(_) => self.remove(expr.id).make_expr(),
|
||||||
|
|
|
@ -447,6 +447,9 @@ declare_features! (
|
||||||
|
|
||||||
// Allows keywords to be escaped for use as identifiers
|
// Allows keywords to be escaped for use as identifiers
|
||||||
(active, raw_identifiers, "1.26.0", Some(48589), None),
|
(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! (
|
declare_features! (
|
||||||
|
@ -1296,6 +1299,13 @@ pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
|
||||||
pub const EXPLAIN_MACRO_AT_MOST_ONCE_REP: &'static str =
|
pub const EXPLAIN_MACRO_AT_MOST_ONCE_REP: &'static str =
|
||||||
"Using the `?` macro Kleene operator for \"at most one\" repetition is unstable";
|
"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> {
|
struct PostExpansionVisitor<'a> {
|
||||||
context: &'a Context<'a>,
|
context: &'a Context<'a>,
|
||||||
}
|
}
|
||||||
|
@ -1600,6 +1610,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
gate_feature_post!(&self, extern_types, i.span,
|
gate_feature_post!(&self, extern_types, i.span,
|
||||||
"extern types are experimental");
|
"extern types are experimental");
|
||||||
}
|
}
|
||||||
|
ast::ForeignItemKind::Macro(..) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
visit::walk_foreign_item(self, i)
|
visit::walk_foreign_item(self, i)
|
||||||
|
|
|
@ -60,10 +60,14 @@ pub trait Folder : Sized {
|
||||||
noop_fold_use_tree(use_tree, self)
|
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)
|
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>> {
|
fn fold_item(&mut self, i: P<Item>) -> SmallVector<P<Item>> {
|
||||||
noop_fold_item(i, self)
|
noop_fold_item(i, self)
|
||||||
}
|
}
|
||||||
|
@ -414,7 +418,7 @@ pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod {abi, items}: ForeignMod,
|
||||||
fld: &mut T) -> ForeignMod {
|
fld: &mut T) -> ForeignMod {
|
||||||
ForeignMod {
|
ForeignMod {
|
||||||
abi,
|
abi,
|
||||||
items: items.move_map(|x| fld.fold_foreign_item(x)),
|
items: items.move_flat_map(|x| fld.fold_foreign_item(x)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,6 +652,10 @@ pub fn noop_fold_interpolated<T: Folder>(nt: token::Nonterminal, fld: &mut T)
|
||||||
token::NtArg(arg) => token::NtArg(fld.fold_arg(arg)),
|
token::NtArg(arg) => token::NtArg(fld.fold_arg(arg)),
|
||||||
token::NtVis(vis) => token::NtVis(fld.fold_vis(vis)),
|
token::NtVis(vis) => token::NtVis(fld.fold_vis(vis)),
|
||||||
token::NtLifetime(lifetime) => token::NtLifetime(fld.fold_lifetime(lifetime)),
|
token::NtLifetime(lifetime) => token::NtLifetime(fld.fold_lifetime(lifetime)),
|
||||||
|
token::NtForeignItem(ni) =>
|
||||||
|
token::NtForeignItem(fld.fold_foreign_item(ni)
|
||||||
|
// see reasoning above
|
||||||
|
.expect_one("expected fold to produce exactly one item")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1072,7 +1080,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 {
|
ForeignItem {
|
||||||
id: folder.new_id(ni.id),
|
id: folder.new_id(ni.id),
|
||||||
vis: folder.fold_vis(ni.vis),
|
vis: folder.fold_vis(ni.vis),
|
||||||
|
@ -1086,6 +1099,7 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> For
|
||||||
ForeignItemKind::Static(folder.fold_ty(t), m)
|
ForeignItemKind::Static(folder.fold_ty(t), m)
|
||||||
}
|
}
|
||||||
ForeignItemKind::Ty => ForeignItemKind::Ty,
|
ForeignItemKind::Ty => ForeignItemKind::Ty,
|
||||||
|
ForeignItemKind::Macro(mac) => ForeignItemKind::Macro(folder.fold_mac(mac)),
|
||||||
},
|
},
|
||||||
span: folder.new_span(ni.span)
|
span: folder.new_span(ni.span)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ use ast::{Ident, ImplItem, IsAuto, Item, ItemKind};
|
||||||
use ast::{Label, Lifetime, LifetimeDef, Lit, LitKind, UintTy};
|
use ast::{Label, Lifetime, LifetimeDef, Lit, LitKind, UintTy};
|
||||||
use ast::Local;
|
use ast::Local;
|
||||||
use ast::MacStmtStyle;
|
use ast::MacStmtStyle;
|
||||||
use ast::Mac_;
|
use ast::{Mac, Mac_};
|
||||||
use ast::{MutTy, Mutability};
|
use ast::{MutTy, Mutability};
|
||||||
use ast::{Pat, PatKind, PathSegment};
|
use ast::{Pat, PatKind, PathSegment};
|
||||||
use ast::{PolyTraitRef, QSelf};
|
use ast::{PolyTraitRef, QSelf};
|
||||||
|
@ -1417,28 +1417,8 @@ impl<'a> Parser<'a> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
(ident, TraitItemKind::Const(ty, default), ast::Generics::default())
|
(ident, TraitItemKind::Const(ty, default), ast::Generics::default())
|
||||||
} else if self.token.is_path_start() && !self.is_extern_non_path() {
|
} else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? {
|
||||||
// trait item macro.
|
// trait item macro.
|
||||||
// code copied from parse_macro_use_or_failure... abstraction!
|
|
||||||
let prev_span = self.prev_span;
|
|
||||||
let lo = self.span;
|
|
||||||
let pth = self.parse_path(PathStyle::Mod)?;
|
|
||||||
|
|
||||||
if pth.segments.len() == 1 {
|
|
||||||
if !self.eat(&token::Not) {
|
|
||||||
return Err(self.missing_assoc_item_kind_err("trait", prev_span));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.expect(&token::Not)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eat a matched-delimiter token tree:
|
|
||||||
let (delim, tts) = self.expect_delimited_token_tree()?;
|
|
||||||
if delim != token::Brace {
|
|
||||||
self.expect(&token::Semi)?
|
|
||||||
}
|
|
||||||
|
|
||||||
let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts });
|
|
||||||
(keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default())
|
(keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default())
|
||||||
} else {
|
} else {
|
||||||
let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
|
let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
|
||||||
|
@ -5406,6 +5386,12 @@ impl<'a> Parser<'a> {
|
||||||
fn missing_assoc_item_kind_err(&mut self, item_type: &str, prev_span: Span)
|
fn missing_assoc_item_kind_err(&mut self, item_type: &str, prev_span: Span)
|
||||||
-> DiagnosticBuilder<'a>
|
-> DiagnosticBuilder<'a>
|
||||||
{
|
{
|
||||||
|
let expected_kinds = if item_type == "extern" {
|
||||||
|
"missing `fn`, `type`, or `static`"
|
||||||
|
} else {
|
||||||
|
"missing `fn`, `type`, or `const`"
|
||||||
|
};
|
||||||
|
|
||||||
// Given this code `path(`, it seems like this is not
|
// Given this code `path(`, it seems like this is not
|
||||||
// setting the visibility of a macro invocation, but rather
|
// setting the visibility of a macro invocation, but rather
|
||||||
// a mistyped method declaration.
|
// a mistyped method declaration.
|
||||||
|
@ -5418,9 +5404,9 @@ impl<'a> Parser<'a> {
|
||||||
let sp = prev_span.between(self.prev_span);
|
let sp = prev_span.between(self.prev_span);
|
||||||
let mut err = self.diagnostic().struct_span_err(
|
let mut err = self.diagnostic().struct_span_err(
|
||||||
sp,
|
sp,
|
||||||
&format!("missing `fn`, `type`, or `const` for {}-item declaration",
|
&format!("{} for {}-item declaration",
|
||||||
item_type));
|
expected_kinds, item_type));
|
||||||
err.span_label(sp, "missing `fn`, `type`, or `const`");
|
err.span_label(sp, expected_kinds);
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5429,31 +5415,8 @@ impl<'a> Parser<'a> {
|
||||||
-> PResult<'a, (Ident, Vec<Attribute>, ast::Generics,
|
-> PResult<'a, (Ident, Vec<Attribute>, ast::Generics,
|
||||||
ast::ImplItemKind)> {
|
ast::ImplItemKind)> {
|
||||||
// code copied from parse_macro_use_or_failure... abstraction!
|
// code copied from parse_macro_use_or_failure... abstraction!
|
||||||
if self.token.is_path_start() && !self.is_extern_non_path() {
|
if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? {
|
||||||
// Method macro.
|
// Method macro.
|
||||||
|
|
||||||
let prev_span = self.prev_span;
|
|
||||||
|
|
||||||
let lo = self.span;
|
|
||||||
let pth = self.parse_path(PathStyle::Mod)?;
|
|
||||||
if pth.segments.len() == 1 {
|
|
||||||
if !self.eat(&token::Not) {
|
|
||||||
return Err(self.missing_assoc_item_kind_err("impl", prev_span));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.expect(&token::Not)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.complain_if_pub_macro(&vis.node, prev_span);
|
|
||||||
|
|
||||||
// eat a matched-delimiter token tree:
|
|
||||||
*at_end = true;
|
|
||||||
let (delim, tts) = self.expect_delimited_token_tree()?;
|
|
||||||
if delim != token::Brace {
|
|
||||||
self.expect(&token::Semi)?
|
|
||||||
}
|
|
||||||
|
|
||||||
let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts });
|
|
||||||
Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(),
|
Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(),
|
||||||
ast::ImplItemKind::Macro(mac)))
|
ast::ImplItemKind::Macro(mac)))
|
||||||
} else {
|
} else {
|
||||||
|
@ -6799,7 +6762,9 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a foreign item.
|
/// 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>> {
|
||||||
|
maybe_whole!(self, NtForeignItem, |ni| Some(ni));
|
||||||
|
|
||||||
let attrs = self.parse_outer_attributes()?;
|
let attrs = self.parse_outer_attributes()?;
|
||||||
let lo = self.span;
|
let lo = self.span;
|
||||||
let visibility = self.parse_visibility(false)?;
|
let visibility = self.parse_visibility(false)?;
|
||||||
|
@ -6825,12 +6790,26 @@ impl<'a> Parser<'a> {
|
||||||
return Ok(Some(self.parse_item_foreign_type(visibility, lo, attrs)?));
|
return Ok(Some(self.parse_item_foreign_type(visibility, lo, attrs)?));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME #5668: this will occur for a macro invocation:
|
match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? {
|
||||||
match self.parse_macro_use_or_failure(attrs, true, false, lo, visibility)? {
|
Some(mac) => {
|
||||||
Some(item) => {
|
Ok(Some(
|
||||||
return Err(self.span_fatal(item.span, "macros cannot expand to foreign items"));
|
ForeignItem {
|
||||||
|
ident: keywords::Invalid.ident(),
|
||||||
|
span: lo.to(self.prev_span),
|
||||||
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
attrs,
|
||||||
|
vis: visibility,
|
||||||
|
node: ForeignItemKind::Macro(mac),
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if !attrs.is_empty() {
|
||||||
|
self.expected_item_err(&attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
None => Ok(None)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6894,6 +6873,41 @@ impl<'a> Parser<'a> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a macro invocation inside a `trait`, `impl` or `extern` block
|
||||||
|
fn parse_assoc_macro_invoc(&mut self, item_kind: &str, vis: Option<&Visibility>,
|
||||||
|
at_end: &mut bool) -> PResult<'a, Option<Mac>>
|
||||||
|
{
|
||||||
|
if self.token.is_path_start() && !self.is_extern_non_path() {
|
||||||
|
let prev_span = self.prev_span;
|
||||||
|
let lo = self.span;
|
||||||
|
let pth = self.parse_path(PathStyle::Mod)?;
|
||||||
|
|
||||||
|
if pth.segments.len() == 1 {
|
||||||
|
if !self.eat(&token::Not) {
|
||||||
|
return Err(self.missing_assoc_item_kind_err(item_kind, prev_span));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.expect(&token::Not)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(vis) = vis {
|
||||||
|
self.complain_if_pub_macro(&vis.node, prev_span);
|
||||||
|
}
|
||||||
|
|
||||||
|
*at_end = true;
|
||||||
|
|
||||||
|
// eat a matched-delimiter token tree:
|
||||||
|
let (delim, tts) = self.expect_delimited_token_tree()?;
|
||||||
|
if delim != token::Brace {
|
||||||
|
self.expect(&token::Semi)?
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some(respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts })))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn collect_tokens<F, R>(&mut self, f: F) -> PResult<'a, (R, TokenStream)>
|
fn collect_tokens<F, R>(&mut self, f: F) -> PResult<'a, (R, TokenStream)>
|
||||||
where F: FnOnce(&mut Self) -> PResult<'a, R>
|
where F: FnOnce(&mut Self) -> PResult<'a, R>
|
||||||
{
|
{
|
||||||
|
|
|
@ -581,6 +581,7 @@ pub enum Nonterminal {
|
||||||
NtArm(ast::Arm),
|
NtArm(ast::Arm),
|
||||||
NtImplItem(ast::ImplItem),
|
NtImplItem(ast::ImplItem),
|
||||||
NtTraitItem(ast::TraitItem),
|
NtTraitItem(ast::TraitItem),
|
||||||
|
NtForeignItem(ast::ForeignItem),
|
||||||
NtGenerics(ast::Generics),
|
NtGenerics(ast::Generics),
|
||||||
NtWhereClause(ast::WhereClause),
|
NtWhereClause(ast::WhereClause),
|
||||||
NtArg(ast::Arg),
|
NtArg(ast::Arg),
|
||||||
|
@ -603,6 +604,7 @@ impl fmt::Debug for Nonterminal {
|
||||||
NtArm(..) => f.pad("NtArm(..)"),
|
NtArm(..) => f.pad("NtArm(..)"),
|
||||||
NtImplItem(..) => f.pad("NtImplItem(..)"),
|
NtImplItem(..) => f.pad("NtImplItem(..)"),
|
||||||
NtTraitItem(..) => f.pad("NtTraitItem(..)"),
|
NtTraitItem(..) => f.pad("NtTraitItem(..)"),
|
||||||
|
NtForeignItem(..) => f.pad("NtForeignItem(..)"),
|
||||||
NtGenerics(..) => f.pad("NtGenerics(..)"),
|
NtGenerics(..) => f.pad("NtGenerics(..)"),
|
||||||
NtWhereClause(..) => f.pad("NtWhereClause(..)"),
|
NtWhereClause(..) => f.pad("NtWhereClause(..)"),
|
||||||
NtArg(..) => f.pad("NtArg(..)"),
|
NtArg(..) => f.pad("NtArg(..)"),
|
||||||
|
|
|
@ -281,6 +281,7 @@ pub fn token_to_string(tok: &Token) -> String {
|
||||||
token::NtArg(ref e) => arg_to_string(e),
|
token::NtArg(ref e) => arg_to_string(e),
|
||||||
token::NtVis(ref e) => vis_to_string(e),
|
token::NtVis(ref e) => vis_to_string(e),
|
||||||
token::NtLifetime(ref e) => lifetime_to_string(e),
|
token::NtLifetime(ref e) => lifetime_to_string(e),
|
||||||
|
token::NtForeignItem(ref ni) => foreign_item_to_string(ni),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -422,6 +423,10 @@ pub fn mac_to_string(arg: &ast::Mac) -> String {
|
||||||
to_string(|s| s.print_mac(arg, ::parse::token::Paren))
|
to_string(|s| s.print_mac(arg, ::parse::token::Paren))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn foreign_item_to_string(arg: &ast::ForeignItem) -> String {
|
||||||
|
to_string(|s| s.print_foreign_item(arg))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
|
pub fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
|
||||||
format!("{}{}", to_string(|s| s.print_visibility(vis)), s)
|
format!("{}{}", to_string(|s| s.print_visibility(vis)), s)
|
||||||
}
|
}
|
||||||
|
@ -1127,6 +1132,10 @@ impl<'a> State<'a> {
|
||||||
self.end()?; // end the head-ibox
|
self.end()?; // end the head-ibox
|
||||||
self.end() // end the outer cbox
|
self.end() // end the outer cbox
|
||||||
}
|
}
|
||||||
|
ast::ForeignItemKind::Macro(ref m) => {
|
||||||
|
self.print_mac(m, token::Paren)?;
|
||||||
|
self.s.word(";")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -460,6 +460,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::Static(ref typ, _) => visitor.visit_ty(typ),
|
||||||
ForeignItemKind::Ty => (),
|
ForeignItemKind::Ty => (),
|
||||||
|
ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac),
|
||||||
}
|
}
|
||||||
|
|
||||||
walk_list!(visitor, visit_attribute, &foreign_item.attrs);
|
walk_list!(visitor, visit_attribute, &foreign_item.attrs);
|
||||||
|
|
|
@ -55,6 +55,7 @@ impl MultiItemModifier for ProcMacroDerive {
|
||||||
Annotatable::Item(item) => item,
|
Annotatable::Item(item) => item,
|
||||||
Annotatable::ImplItem(_) |
|
Annotatable::ImplItem(_) |
|
||||||
Annotatable::TraitItem(_) |
|
Annotatable::TraitItem(_) |
|
||||||
|
Annotatable::ForeignItem(_) |
|
||||||
Annotatable::Stmt(_) |
|
Annotatable::Stmt(_) |
|
||||||
Annotatable::Expr(_) => {
|
Annotatable::Expr(_) => {
|
||||||
ecx.span_err(span, "proc-macro derives may only be \
|
ecx.span_err(span, "proc-macro derives may only be \
|
||||||
|
|
|
@ -93,7 +93,9 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// these are covered in proc_macro/attr-stmt-expr.rs
|
// covered in proc_macro/macros-in-extern.rs
|
||||||
|
Annotatable::ForeignItem(_) => unimplemented!(),
|
||||||
|
// covered in proc_macro/attr-stmt-expr.rs
|
||||||
Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item")
|
Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,6 +149,8 @@ fn expand_duplicate(cx: &mut ExtCtxt,
|
||||||
new_it.ident = copy_name;
|
new_it.ident = copy_name;
|
||||||
push(Annotatable::TraitItem(P(new_it)));
|
push(Annotatable::TraitItem(P(new_it)));
|
||||||
}
|
}
|
||||||
|
// covered in proc_macro/macros-in-extern.rs
|
||||||
|
Annotatable::ForeignItem(_) => unimplemented!(),
|
||||||
// covered in proc_macro/attr-stmt-expr.rs
|
// covered in proc_macro/attr-stmt-expr.rs
|
||||||
Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item")
|
Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item")
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
#![feature(proc_macro)]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn nop_attr(_attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
|
assert!(_attr.to_string().is_empty());
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn no_output(_attr: TokenStream, _input: TokenStream) -> TokenStream {
|
||||||
|
assert!(_attr.to_string().is_empty());
|
||||||
|
assert!(!_input.to_string().is_empty());
|
||||||
|
"".parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn emit_input(input: TokenStream) -> TokenStream {
|
||||||
|
input
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
// aux-build:test-macros.rs
|
||||||
|
// ignore-stage1
|
||||||
|
// ignore-wasm32
|
||||||
|
|
||||||
|
#![feature(proc_macro)]
|
||||||
|
|
||||||
|
extern crate test_macros;
|
||||||
|
|
||||||
|
use test_macros::{nop_attr, no_output, emit_input};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(unsafe { rust_get_test_int() }, 0isize);
|
||||||
|
assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[link(name = "rust_test_helpers", kind = "static")]
|
||||||
|
extern {
|
||||||
|
#[no_output]
|
||||||
|
//~^ ERROR Macro and proc-macro invocations in `extern {}` blocks are experimental.
|
||||||
|
fn some_definitely_unknown_symbol_which_should_be_removed();
|
||||||
|
|
||||||
|
#[nop_attr]
|
||||||
|
//~^ ERROR Macro and proc-macro invocations in `extern {}` blocks are experimental.
|
||||||
|
fn rust_get_test_int() -> isize;
|
||||||
|
|
||||||
|
emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;);
|
||||||
|
//~^ ERROR Macro and proc-macro invocations in `extern {}` blocks are experimental.
|
||||||
|
}
|
42
src/test/compile-fail/macros-in-extern.rs
Normal file
42
src/test/compile-fail/macros-in-extern.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
// ignore-wasm32
|
||||||
|
|
||||||
|
#![feature(decl_macro)]
|
||||||
|
|
||||||
|
macro_rules! returns_isize(
|
||||||
|
($ident:ident) => (
|
||||||
|
fn $ident() -> isize;
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
macro takes_u32_returns_u32($ident:ident) {
|
||||||
|
fn $ident (arg: u32) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! emits_nothing(
|
||||||
|
() => ()
|
||||||
|
);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(unsafe { rust_get_test_int() }, 0isize);
|
||||||
|
assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[link(name = "rust_test_helpers", kind = "static")]
|
||||||
|
extern {
|
||||||
|
returns_isize!(rust_get_test_int);
|
||||||
|
//~^ ERROR Macro invocations in `extern {}` blocks are experimental.
|
||||||
|
takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
|
||||||
|
//~^ ERROR Macro invocations in `extern {}` blocks are experimental.
|
||||||
|
emits_nothing!();
|
||||||
|
//~^ ERROR Macro invocations in `extern {}` blocks are experimental.
|
||||||
|
}
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
// error-pattern:unmatched visibility `pub`
|
// error-pattern:expected one of `(`, `fn`, `static`, `type`, or `}` here
|
||||||
extern {
|
extern {
|
||||||
pub pub fn foo();
|
pub pub fn foo();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
extern {
|
extern { //~ ERROR missing `fn`, `type`, or `static` for extern-item declaration
|
||||||
f(); //~ ERROR expected one of `!` or `::`, found `(`
|
f();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -96,7 +96,9 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
// these are covered in proc_macro/attr-stmt-expr.rs
|
// covered in proc_macro/macros-in-extern.rs
|
||||||
|
Annotatable::ForeignItem(..) => unimplemented!(),
|
||||||
|
// covered in proc_macro/attr-stmt-expr.rs
|
||||||
Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item"),
|
Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +144,9 @@ fn expand_duplicate(cx: &mut ExtCtxt,
|
||||||
new_it.ident = copy_name;
|
new_it.ident = copy_name;
|
||||||
push(Annotatable::TraitItem(P(new_it)));
|
push(Annotatable::TraitItem(P(new_it)));
|
||||||
}
|
}
|
||||||
// these are covered in proc_macro/attr-stmt-expr.rs
|
// covered in proc_macro/macros-in-extern.rs
|
||||||
|
Annotatable::ForeignItem(..) => unimplemented!(),
|
||||||
|
// covered in proc_macro/attr-stmt-expr.rs
|
||||||
Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item")
|
Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
#![feature(proc_macro)]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn nop_attr(_attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
|
assert!(_attr.to_string().is_empty());
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn no_output(_attr: TokenStream, _input: TokenStream) -> TokenStream {
|
||||||
|
assert!(_attr.to_string().is_empty());
|
||||||
|
assert!(!_input.to_string().is_empty());
|
||||||
|
"".parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn emit_input(input: TokenStream) -> TokenStream {
|
||||||
|
input
|
||||||
|
}
|
35
src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs
Normal file
35
src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
// aux-build:test-macros.rs
|
||||||
|
// ignore-stage1
|
||||||
|
// ignore-wasm32
|
||||||
|
|
||||||
|
#![feature(proc_macro, macros_in_extern)]
|
||||||
|
|
||||||
|
extern crate test_macros;
|
||||||
|
|
||||||
|
use test_macros::{nop_attr, no_output, emit_input};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(unsafe { rust_get_test_int() }, 1isize);
|
||||||
|
assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[link(name = "rust_test_helpers", kind = "static")]
|
||||||
|
extern {
|
||||||
|
#[no_output]
|
||||||
|
fn some_definitely_unknown_symbol_which_should_be_removed();
|
||||||
|
|
||||||
|
#[nop_attr]
|
||||||
|
fn rust_get_test_int() -> isize;
|
||||||
|
|
||||||
|
emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;);
|
||||||
|
}
|
39
src/test/run-pass/macros-in-extern.rs
Normal file
39
src/test/run-pass/macros-in-extern.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
// ignore-wasm32
|
||||||
|
|
||||||
|
#![feature(decl_macro, macros_in_extern)]
|
||||||
|
|
||||||
|
macro_rules! returns_isize(
|
||||||
|
($ident:ident) => (
|
||||||
|
fn $ident() -> isize;
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
macro takes_u32_returns_u32($ident:ident) {
|
||||||
|
fn $ident (arg: u32) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! emits_nothing(
|
||||||
|
() => ()
|
||||||
|
);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(unsafe { rust_get_test_int() }, 1isize);
|
||||||
|
assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[link(name = "rust_test_helpers", kind = "static")]
|
||||||
|
extern {
|
||||||
|
returns_isize!(rust_get_test_int);
|
||||||
|
takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
|
||||||
|
emits_nothing!();
|
||||||
|
}
|
35
src/test/ui/feature-gate-macros_in_extern.rs
Normal file
35
src/test/ui/feature-gate-macros_in_extern.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
#![feature(decl_macro)]
|
||||||
|
|
||||||
|
macro_rules! returns_isize(
|
||||||
|
($ident:ident) => (
|
||||||
|
fn $ident() -> isize;
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
macro takes_u32_returns_u32($ident:ident) {
|
||||||
|
fn $ident (arg: u32) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! emits_nothing(
|
||||||
|
() => ()
|
||||||
|
);
|
||||||
|
|
||||||
|
#[link(name = "rust_test_helpers", kind = "static")]
|
||||||
|
extern {
|
||||||
|
returns_isize!(rust_get_test_int);
|
||||||
|
//~^ ERROR Macro invocations in `extern {}` blocks are experimental.
|
||||||
|
takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
|
||||||
|
//~^ ERROR Macro invocations in `extern {}` blocks are experimental.
|
||||||
|
emits_nothing!();
|
||||||
|
//~^ ERROR Macro invocations in `extern {}` blocks are experimental.
|
||||||
|
}
|
27
src/test/ui/feature-gate-macros_in_extern.stderr
Normal file
27
src/test/ui/feature-gate-macros_in_extern.stderr
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
error[E0658]: Macro invocations in `extern {}` blocks are experimental. (see issue #49476)
|
||||||
|
--> $DIR/feature-gate-macros_in_extern.rs:29:5
|
||||||
|
|
|
||||||
|
LL | returns_isize!(rust_get_test_int);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(macros_in_extern)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: Macro invocations in `extern {}` blocks are experimental. (see issue #49476)
|
||||||
|
--> $DIR/feature-gate-macros_in_extern.rs:31:5
|
||||||
|
|
|
||||||
|
LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(macros_in_extern)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: Macro invocations in `extern {}` blocks are experimental. (see issue #49476)
|
||||||
|
--> $DIR/feature-gate-macros_in_extern.rs:33:5
|
||||||
|
|
|
||||||
|
LL | emits_nothing!();
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(macros_in_extern)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
Loading…
Add table
Add a link
Reference in a new issue