pub expansion_data: ExpansionData,
}
-// Needed for feature-gating attributes used after derives or together with test/bench
-#[derive(Clone, Copy, PartialEq)]
-pub enum TogetherWith {
- None,
- Derive,
- TestBench,
-}
-
pub enum InvocationKind {
Bang {
mac: ast::Mac,
attr: Option<ast::Attribute>,
traits: Vec<Path>,
item: Annotatable,
- together_with: TogetherWith,
+ // We temporarily report errors for attribute macros placed after derives
+ after_derive: bool,
},
Derive {
path: Path,
let (kind, gate) = match *item {
Annotatable::Item(ref item) => {
match item.node {
- ItemKind::Mod(_) if self.cx.ecfg.proc_macro_mod() => return,
- ItemKind::Mod(_) => ("modules", "proc_macro_mod"),
+ ItemKind::Mod(_) if self.cx.ecfg.proc_macro_hygiene() => return,
+ ItemKind::Mod(_) => ("modules", "proc_macro_hygiene"),
_ => return,
}
}
Annotatable::ImplItem(_) => return,
Annotatable::ForeignItem(_) => return,
Annotatable::Stmt(_) |
- Annotatable::Expr(_) if self.cx.ecfg.proc_macro_expr() => return,
- Annotatable::Stmt(_) => ("statements", "proc_macro_expr"),
- Annotatable::Expr(_) => ("expressions", "proc_macro_expr"),
+ Annotatable::Expr(_) if self.cx.ecfg.proc_macro_hygiene() => return,
+ Annotatable::Stmt(_) => ("statements", "proc_macro_hygiene"),
+ Annotatable::Expr(_) => ("expressions", "proc_macro_hygiene"),
};
emit_feature_err(
self.cx.parse_sess,
}
fn gate_proc_macro_expansion(&self, span: Span, fragment: &Option<AstFragment>) {
- if self.cx.ecfg.proc_macro_gen() {
+ if self.cx.ecfg.proc_macro_hygiene() {
return
}
let fragment = match fragment {
if let ast::ItemKind::MacroDef(_) = i.node {
emit_feature_err(
self.parse_sess,
- "proc_macro_gen",
+ "proc_macro_hygiene",
self.span,
GateIssue::Language,
&format!("procedural macros cannot expand to macro definitions"),
edition) {
dummy_span
} else {
- kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
+ kind.make_from(expander.expand(self.cx, span, mac.node.stream(), None))
}
}
edition) {
dummy_span
} else {
- kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
+ kind.make_from(expander.expand(
+ self.cx,
+ span,
+ mac.node.stream(),
+ def_info.map(|(_, s)| s),
+ ))
}
}
AstFragmentKind::ImplItems => return,
AstFragmentKind::ForeignItems => return,
};
- if self.cx.ecfg.proc_macro_non_items() {
+ if self.cx.ecfg.proc_macro_hygiene() {
return
}
emit_feature_err(
self.cx.parse_sess,
- "proc_macro_non_items",
+ "proc_macro_hygiene",
span,
GateIssue::Language,
&format!("procedural macros cannot be expanded to {}", kind),
AstFragmentKind::ForeignItems => {
let mut items = SmallVec::new();
while self.token != token::Eof {
- if let Some(item) = self.parse_foreign_item()? {
- items.push(item);
- }
+ items.push(self.parse_foreign_item()?);
}
AstFragment::ForeignItems(items)
}
}
},
AstFragmentKind::Ty => AstFragment::Ty(self.parse_ty()?),
- AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat()?),
+ AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat(None)?),
})
}
// Avoid emitting backtrace info twice.
let def_site_span = self.span.with_ctxt(SyntaxContext::empty());
let mut err = self.diagnostic().struct_span_err(def_site_span, &msg);
- let msg = format!("caused by the macro expansion here; the usage \
- of `{}!` is likely invalid in {} context",
- macro_path, kind_name);
- err.span_note(span, &msg).emit();
+ err.span_label(span, "caused by the macro expansion here");
+ let msg = format!(
+ "the usage of `{}!` is likely invalid in {} context",
+ macro_path,
+ kind_name,
+ );
+ err.note(&msg);
+ let semi_span = self.sess.source_map().next_point(span);
+
+ let semi_full_span = semi_span.to(self.sess.source_map().next_point(semi_span));
+ match self.sess.source_map().span_to_snippet(semi_full_span) {
+ Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => {
+ err.span_suggestion_with_applicability(
+ semi_span,
+ "you might be missing a semicolon here",
+ ";".to_owned(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {}
+ }
+ err.emit();
}
}
}
traits: Vec<Path>,
item: Annotatable,
kind: AstFragmentKind,
- together_with: TogetherWith)
+ after_derive: bool)
-> AstFragment {
- self.collect(kind, InvocationKind::Attr { attr, traits, item, together_with })
+ self.collect(kind, InvocationKind::Attr { attr, traits, item, after_derive })
}
- fn find_attr_invoc(&self, attrs: &mut Vec<ast::Attribute>, together_with: &mut TogetherWith)
+ fn find_attr_invoc(&self, attrs: &mut Vec<ast::Attribute>, after_derive: &mut bool)
-> Option<ast::Attribute> {
let attr = attrs.iter()
.position(|a| {
if a.path == "derive" {
- *together_with = TogetherWith::Derive
- } else if a.path == "rustc_test_marker2" {
- *together_with = TogetherWith::TestBench
+ *after_derive = true;
}
!attr::is_known(a) && !is_builtin_attr(a)
})
"non-builtin inner attributes are unstable");
}
}
- if together_with == &TogetherWith::None &&
- attrs.iter().any(|a| a.path == "rustc_test_marker2") {
- *together_with = TogetherWith::TestBench;
- }
attr
}
/// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
fn classify_item<T>(&mut self, mut item: T)
- -> (Option<ast::Attribute>, Vec<Path>, T, TogetherWith)
+ -> (Option<ast::Attribute>, Vec<Path>, T, /* after_derive */ bool)
where T: HasAttrs,
{
- let (mut attr, mut traits, mut together_with) = (None, Vec::new(), TogetherWith::None);
+ let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false);
item = item.map_attrs(|mut attrs| {
if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs,
return attrs;
}
- attr = self.find_attr_invoc(&mut attrs, &mut together_with);
+ attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
traits = collect_derives(&mut self.cx, &mut attrs);
attrs
});
- (attr, traits, item, together_with)
+ (attr, traits, item, after_derive)
}
/// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough
/// to the unused-attributes lint (making it an error on statements and expressions
/// is a breaking change)
fn classify_nonitem<T: HasAttrs>(&mut self, mut item: T)
- -> (Option<ast::Attribute>, T, TogetherWith) {
- let (mut attr, mut together_with) = (None, TogetherWith::None);
+ -> (Option<ast::Attribute>, T, /* after_derive */ bool) {
+ let (mut attr, mut after_derive) = (None, false);
item = item.map_attrs(|mut attrs| {
if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs,
return attrs;
}
- attr = self.find_attr_invoc(&mut attrs, &mut together_with);
+ attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
attrs
});
- (attr, item, together_with)
+ (attr, item, after_derive)
}
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
expr.node = self.cfg.configure_expr_kind(expr.node);
// ignore derives so they remain unused
- let (attr, expr, together_with) = self.classify_nonitem(expr);
+ let (attr, expr, after_derive) = self.classify_nonitem(expr);
if attr.is_some() {
// collect the invoc regardless of whether or not attributes are permitted here
// AstFragmentKind::Expr requires the macro to emit an expression
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
- AstFragmentKind::Expr, together_with).make_expr();
+ AstFragmentKind::Expr, after_derive).make_expr();
}
if let ast::ExprKind::Mac(mac) = expr.node {
expr.node = self.cfg.configure_expr_kind(expr.node);
// ignore derives so they remain unused
- let (attr, expr, together_with) = self.classify_nonitem(expr);
+ let (attr, expr, after_derive) = self.classify_nonitem(expr);
if attr.is_some() {
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
- AstFragmentKind::OptExpr, together_with).make_opt_expr();
+ AstFragmentKind::OptExpr, after_derive).make_opt_expr();
}
if let ast::ExprKind::Mac(mac) = expr.node {
// we'll expand attributes on expressions separately
if !stmt.is_expr() {
- let (attr, derives, stmt_, together_with) = if stmt.is_item() {
+ let (attr, derives, stmt_, after_derive) = if stmt.is_item() {
self.classify_item(stmt)
} else {
// ignore derives on non-item statements so it falls through
// to the unused-attributes lint
- let (attr, stmt, together_with) = self.classify_nonitem(stmt);
- (attr, vec![], stmt, together_with)
+ let (attr, stmt, after_derive) = self.classify_nonitem(stmt);
+ (attr, vec![], stmt, after_derive)
};
if attr.is_some() || !derives.is_empty() {
return self.collect_attr(attr, derives, Annotatable::Stmt(P(stmt_)),
- AstFragmentKind::Stmts, together_with).make_stmts();
+ AstFragmentKind::Stmts, after_derive).make_stmts();
}
stmt = stmt_;
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
let item = configure!(self, item);
- let (attr, traits, item, together_with) = self.classify_item(item);
+ let (attr, traits, item, after_derive) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
return self.collect_attr(attr, traits, Annotatable::Item(item),
- AstFragmentKind::Items, together_with).make_items();
+ AstFragmentKind::Items, after_derive).make_items();
}
match item.node {
fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
let item = configure!(self, item);
- let (attr, traits, item, together_with) = self.classify_item(item);
+ let (attr, traits, item, after_derive) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
return self.collect_attr(attr, traits, Annotatable::TraitItem(P(item)),
- AstFragmentKind::TraitItems, together_with).make_trait_items()
+ AstFragmentKind::TraitItems, after_derive).make_trait_items()
}
match item.node {
fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
let item = configure!(self, item);
- let (attr, traits, item, together_with) = self.classify_item(item);
+ let (attr, traits, item, after_derive) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
return self.collect_attr(attr, traits, Annotatable::ImplItem(P(item)),
- AstFragmentKind::ImplItems, together_with).make_impl_items();
+ AstFragmentKind::ImplItems, after_derive).make_impl_items();
}
match item.node {
fn fold_foreign_item(&mut self, foreign_item: ast::ForeignItem)
-> SmallVec<[ast::ForeignItem; 1]>
{
- let (attr, traits, foreign_item, together_with) = self.classify_item(foreign_item);
+ let (attr, traits, foreign_item, after_derive) = self.classify_item(foreign_item);
if attr.is_some() || !traits.is_empty() {
return self.collect_attr(attr, traits, Annotatable::ForeignItem(P(foreign_item)),
- AstFragmentKind::ForeignItems, together_with)
+ AstFragmentKind::ForeignItems, after_derive)
.make_foreign_items();
}
fn enable_custom_derive = custom_derive,
fn enable_format_args_nl = format_args_nl,
fn macros_in_extern_enabled = macros_in_extern,
- fn proc_macro_mod = proc_macro_mod,
- fn proc_macro_gen = proc_macro_gen,
- fn proc_macro_expr = proc_macro_expr,
- fn proc_macro_non_items = proc_macro_non_items,
+ fn proc_macro_hygiene = proc_macro_hygiene,
}
fn enable_custom_inner_attributes(&self) -> bool {