From 5d74990cebb82b9573ea6a9d509bb8e05fd6681e Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Sat, 10 Mar 2018 18:16:26 -0800 Subject: [PATCH] expand macro invocations in `extern {}` blocks --- src/librustc/hir/lowering.rs | 1 + src/librustc/hir/map/def_collector.rs | 4 + src/librustc_passes/ast_validation.rs | 18 ++- src/librustc_resolve/build_reduced_graph.rs | 6 + src/librustc_resolve/lib.rs | 1 + src/librustc_save_analysis/dump_visitor.rs | 1 + src/librustc_save_analysis/lib.rs | 1 + src/librustc_save_analysis/sig.rs | 1 + src/libsyntax/ast.rs | 3 + src/libsyntax/ext/base.rs | 28 ++++ src/libsyntax/ext/expand.rs | 58 ++++++++ src/libsyntax/ext/placeholders.rs | 11 ++ src/libsyntax/feature_gate.rs | 11 ++ src/libsyntax/fold.rs | 20 ++- src/libsyntax/parse/parser.rs | 124 ++++++++++-------- src/libsyntax/parse/token.rs | 2 + src/libsyntax/print/pprust.rs | 9 ++ src/libsyntax/visit.rs | 1 + src/libsyntax_ext/deriving/custom.rs | 1 + .../auxiliary/macro_crate_test.rs | 6 +- .../proc-macro/auxiliary/test-macros.rs | 36 +++++ .../proc-macro/macros-in-extern.rs | 38 ++++++ src/test/compile-fail/macros-in-extern.rs | 42 ++++++ src/test/parse-fail/duplicate-visibility.rs | 2 +- src/test/parse-fail/extern-no-fn.rs | 4 +- .../auxiliary/macro_crate_test.rs | 8 +- .../proc-macro/auxiliary/test-macros.rs | 36 +++++ .../proc-macro/macros-in-extern.rs | 35 +++++ src/test/run-pass/macros-in-extern.rs | 39 ++++++ src/test/ui/feature-gate-macros_in_extern.rs | 35 +++++ .../ui/feature-gate-macros_in_extern.stderr | 27 ++++ 31 files changed, 544 insertions(+), 65 deletions(-) create mode 100644 src/test/compile-fail-fulldeps/proc-macro/auxiliary/test-macros.rs create mode 100644 src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs create mode 100644 src/test/compile-fail/macros-in-extern.rs create mode 100644 src/test/run-pass-fulldeps/proc-macro/auxiliary/test-macros.rs create mode 100644 src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs create mode 100644 src/test/run-pass/macros-in-extern.rs create mode 100644 src/test/ui/feature-gate-macros_in_extern.rs create mode 100644 src/test/ui/feature-gate-macros_in_extern.stderr diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 536d682566a72..bbc1b9211886a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -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, diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 3619a7fb0c603..20f46cb348d1d 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -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, diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 37274d1fc4479..b34decc1c69a5 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -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) @@ -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) { + // 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`. @@ -522,6 +530,10 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { } } } + + fn visit_mac(&mut self, _mac: &Spanned) { + // covered in AstValidator + } } // Bans `impl Trait` in path projections like `::Item` or `Foo::Bar`. @@ -583,6 +595,10 @@ impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> { _ => visit::walk_ty(self, t), } } + + fn visit_mac(&mut self, _mac: &Spanned) { + // covered in AstValidator + } } pub fn check_crate(session: &Session, krate: &Crate) { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index c192f349c2019..397590012fd73 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -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); @@ -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); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 97dcf081f8c8d..74cfe57665274 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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); diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3d4d8571c6e42..5e51797d72066 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -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(..) => {} } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 953747756517d..fb4cb2afe5a66 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -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, } } diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 0c890ce19d081..fd4d3e7638642 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -822,6 +822,7 @@ impl Sig for ast::ForeignItem { refs: vec![], }) } + ast::ForeignItemKind::Macro(..) => Err("macro"), } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c90b0aecfc044..b55a502d11851 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2195,6 +2195,8 @@ pub enum ForeignItemKind { Static(P, bool), /// A foreign type Ty, + /// A macro invocation + Macro(Mac), } impl ForeignItemKind { @@ -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", } } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index d3157af984e80..5a735be55c0e6 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -38,6 +38,7 @@ pub enum Annotatable { Item(P), TraitItem(P), ImplItem(P), + ForeignItem(P), Stmt(P), Expr(P), } @@ -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, } @@ -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)), } @@ -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, } @@ -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 { @@ -317,6 +329,9 @@ pub trait MacResult { None } + /// Create zero or more items in an `extern {}` block + fn make_foreign_items(self: Box) -> Option> { None } + /// Create a pattern. fn make_pat(self: Box) -> Option> { None @@ -365,6 +380,7 @@ make_MacEager! { items: SmallVector>, impl_items: SmallVector, trait_items: SmallVector, + foreign_items: SmallVector, stmts: SmallVector, ty: P, } @@ -386,6 +402,10 @@ impl MacResult for MacEager { self.trait_items } + fn make_foreign_items(self: Box) -> Option> { + self.foreign_items + } + fn make_stmts(self: Box) -> Option> { match self.stmts.as_ref().map_or(0, |s| s.len()) { 0 => make_stmts_default!(self), @@ -502,6 +522,14 @@ impl MacResult for DummyResult { } } + fn make_foreign_items(self: Box) -> Option> { + if self.expr_only { + None + } else { + Some(SmallVector::new()) + } + } + fn make_stmts(self: Box) -> Option> { Some(SmallVector::one(ast::Stmt { id: ast::DUMMY_NODE_ID, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 864969c40750b..105de13b976a1 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -133,6 +133,8 @@ expansions! { "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item; ImplItems: SmallVector [SmallVector, ast::ImplItem], "impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item; + ForeignItems: SmallVector [SmallVector, ast::ForeignItem], + "foreign item", .make_foreign_items, lift .fold_foreign_item, lift .visit_foreign_item; } impl ExpansionKind { @@ -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!(), } } @@ -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())) } @@ -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(); @@ -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 && @@ -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 { + 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, @@ -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, } } diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 9c2c22476e9d9..9f60882ca29fc 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -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()), })), @@ -132,6 +136,13 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { } } + fn fold_foreign_item(&mut self, item: ast::ForeignItem) -> SmallVector { + 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) -> P { match expr.node { ast::ExprKind::Mac(_) => self.remove(expr.id).make_expr(), diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 463e76e14618a..d88305529ede4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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! ( @@ -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>, } @@ -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) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 05a3150c139c9..72f695b4fdbc5 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -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 { 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) -> SmallVector> { noop_fold_item(i, self) } @@ -414,7 +418,7 @@ pub fn noop_fold_foreign_mod(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)), } } @@ -648,6 +652,10 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) token::NtArg(arg) => token::NtArg(fld.fold_arg(arg)), token::NtVis(vis) => token::NtVis(fld.fold_vis(vis)), 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(Item {id, ident, attrs, node, vis, span, } } -pub fn noop_fold_foreign_item(ni: ForeignItem, folder: &mut T) -> ForeignItem { +pub fn noop_fold_foreign_item(ni: ForeignItem, folder: &mut T) +-> SmallVector { + SmallVector::one(folder.fold_foreign_item_simple(ni)) +} + +pub fn noop_fold_foreign_item_simple(ni: ForeignItem, folder: &mut T) -> ForeignItem { ForeignItem { id: folder.new_id(ni.id), vis: folder.fold_vis(ni.vis), @@ -1086,6 +1099,7 @@ pub fn noop_fold_foreign_item(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) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f7cdd4ba2b449..6e44fe7344f61 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -26,7 +26,7 @@ use ast::{Ident, ImplItem, IsAuto, Item, ItemKind}; use ast::{Label, Lifetime, LifetimeDef, Lit, LitKind, UintTy}; use ast::Local; use ast::MacStmtStyle; -use ast::Mac_; +use ast::{Mac, Mac_}; use ast::{MutTy, Mutability}; use ast::{Pat, PatKind, PathSegment}; use ast::{PolyTraitRef, QSelf}; @@ -1417,28 +1417,8 @@ impl<'a> Parser<'a> { None }; (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. - // 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()) } else { 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) -> 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 // setting the visibility of a macro invocation, but rather // a mistyped method declaration. @@ -5418,9 +5404,9 @@ impl<'a> Parser<'a> { let sp = prev_span.between(self.prev_span); let mut err = self.diagnostic().struct_span_err( sp, - &format!("missing `fn`, `type`, or `const` for {}-item declaration", - item_type)); - err.span_label(sp, "missing `fn`, `type`, or `const`"); + &format!("{} for {}-item declaration", + expected_kinds, item_type)); + err.span_label(sp, expected_kinds); err } @@ -5429,31 +5415,8 @@ impl<'a> Parser<'a> { -> PResult<'a, (Ident, Vec, ast::Generics, ast::ImplItemKind)> { // 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. - - 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(), ast::ImplItemKind::Macro(mac))) } else { @@ -6799,7 +6762,9 @@ impl<'a> Parser<'a> { } /// Parse a foreign item. - fn parse_foreign_item(&mut self) -> PResult<'a, Option> { + pub fn parse_foreign_item(&mut self) -> PResult<'a, Option> { + maybe_whole!(self, NtForeignItem, |ni| Some(ni)); + let attrs = self.parse_outer_attributes()?; let lo = self.span; 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)?)); } - // FIXME #5668: this will occur for a macro invocation: - match self.parse_macro_use_or_failure(attrs, true, false, lo, visibility)? { - Some(item) => { - return Err(self.span_fatal(item.span, "macros cannot expand to foreign items")); + match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? { + Some(mac) => { + Ok(Some( + 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) } + /// 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> + { + 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(&mut self, f: F) -> PResult<'a, (R, TokenStream)> where F: FnOnce(&mut Self) -> PResult<'a, R> { diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index e2dfca5d10a3c..5fe2b081566a1 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -581,6 +581,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), @@ -603,6 +604,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(..)"), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ae045fc095a50..fbcd251f1085e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -281,6 +281,7 @@ pub fn token_to_string(tok: &Token) -> String { token::NtArg(ref e) => arg_to_string(e), token::NtVis(ref e) => vis_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)) } +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 { 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 outer cbox } + ast::ForeignItemKind::Macro(ref m) => { + self.print_mac(m, token::Paren)?; + self.s.word(";") + } } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index bbf1fe124f1ba..9004ad022f701 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -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::Ty => (), + ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac), } walk_list!(visitor, visit_attribute, &foreign_item.attrs); diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index 80557078d5463..5fd5e29948852 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -55,6 +55,7 @@ impl MultiItemModifier for ProcMacroDerive { Annotatable::Item(item) => item, Annotatable::ImplItem(_) | Annotatable::TraitItem(_) | + Annotatable::ForeignItem(_) | Annotatable::Stmt(_) | Annotatable::Expr(_) => { ecx.span_err(span, "proc-macro derives may only be \ diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs index 77ea301941938..bc51b4061ed6b 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs @@ -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") } } @@ -147,6 +149,8 @@ fn expand_duplicate(cx: &mut ExtCtxt, new_it.ident = copy_name; 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 Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item") } diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/test-macros.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/test-macros.rs new file mode 100644 index 0000000000000..d1c5b9050aa87 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/test-macros.rs @@ -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 or the MIT license +// , 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 +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs b/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs new file mode 100644 index 0000000000000..4c88df332460b --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs @@ -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 or the MIT license +// , 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. +} diff --git a/src/test/compile-fail/macros-in-extern.rs b/src/test/compile-fail/macros-in-extern.rs new file mode 100644 index 0000000000000..7d7f95cbbf5cb --- /dev/null +++ b/src/test/compile-fail/macros-in-extern.rs @@ -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 or the MIT license +// , 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. +} diff --git a/src/test/parse-fail/duplicate-visibility.rs b/src/test/parse-fail/duplicate-visibility.rs index 5ee84cd5543ba..6899caa7153bb 100644 --- a/src/test/parse-fail/duplicate-visibility.rs +++ b/src/test/parse-fail/duplicate-visibility.rs @@ -10,7 +10,7 @@ // compile-flags: -Z parse-only -// error-pattern:unmatched visibility `pub` +// error-pattern:expected one of `(`, `fn`, `static`, `type`, or `}` here extern { pub pub fn foo(); } diff --git a/src/test/parse-fail/extern-no-fn.rs b/src/test/parse-fail/extern-no-fn.rs index ff3fefde40ece..aa0dbd4d4fc1b 100644 --- a/src/test/parse-fail/extern-no-fn.rs +++ b/src/test/parse-fail/extern-no-fn.rs @@ -10,8 +10,8 @@ // compile-flags: -Z parse-only -extern { - f(); //~ ERROR expected one of `!` or `::`, found `(` +extern { //~ ERROR missing `fn`, `type`, or `static` for extern-item declaration + f(); } fn main() { diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs index 5ebd32921329d..6612fe45b81d3 100644 --- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs @@ -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"), } } @@ -142,7 +144,9 @@ fn expand_duplicate(cx: &mut ExtCtxt, new_it.ident = copy_name; 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") } } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/test-macros.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/test-macros.rs new file mode 100644 index 0000000000000..d1c5b9050aa87 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/test-macros.rs @@ -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 or the MIT license +// , 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 +} diff --git a/src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs b/src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs new file mode 100644 index 0000000000000..59b9b0baa8a45 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs @@ -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 or the MIT license +// , 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;); +} diff --git a/src/test/run-pass/macros-in-extern.rs b/src/test/run-pass/macros-in-extern.rs new file mode 100644 index 0000000000000..d9094934356fc --- /dev/null +++ b/src/test/run-pass/macros-in-extern.rs @@ -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 or the MIT license +// , 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!(); +} diff --git a/src/test/ui/feature-gate-macros_in_extern.rs b/src/test/ui/feature-gate-macros_in_extern.rs new file mode 100644 index 0000000000000..9c758241ea1b8 --- /dev/null +++ b/src/test/ui/feature-gate-macros_in_extern.rs @@ -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 or the MIT license +// , 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. +} diff --git a/src/test/ui/feature-gate-macros_in_extern.stderr b/src/test/ui/feature-gate-macros_in_extern.stderr new file mode 100644 index 0000000000000..49aca0db2d46c --- /dev/null +++ b/src/test/ui/feature-gate-macros_in_extern.stderr @@ -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`.