diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 55b243a84a9a3..4d4c6217ad07a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -517,6 +517,8 @@ pub struct Crate { pub attrs: Vec, pub items: Vec>, pub span: Span, + // Placeholder ID if the crate node is a macro placeholder. + pub is_placeholder: Option, } /// Possible values inside of compile-time attribute lists. diff --git a/compiler/rustc_ast/src/ast_like.rs b/compiler/rustc_ast/src/ast_like.rs index d586426d70ef0..b9c397974a163 100644 --- a/compiler/rustc_ast/src/ast_like.rs +++ b/compiler/rustc_ast/src/ast_like.rs @@ -1,7 +1,7 @@ use super::ptr::P; use super::token::Nonterminal; use super::tokenstream::LazyTokenStream; -use super::{Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant}; +use super::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant}; use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt}; use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility}; use super::{AttrVec, Attribute, Stmt, StmtKind}; @@ -276,7 +276,7 @@ derive_has_tokens_and_attrs! { // These ast nodes only support inert attributes, so they don't // store tokens (since nothing can observe them) derive_has_attrs_no_tokens! { - FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam + FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam, Crate } // These AST nodes don't support attributes, but can diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index fc5cc96399257..205625573a6d9 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -284,6 +284,10 @@ pub trait MutVisitor: Sized { /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful /// when using a `flat_map_*` or `filter_map_*` method within a `visit_` /// method. Abort the program if the closure panics. +/// +/// FIXME: Abort on panic means that any fatal error inside `visit_clobber` will abort the compiler. +/// Instead of aborting on catching a panic we need to reset the visited node to some valid but +/// possibly meaningless value and rethrow the panic. // // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. pub fn visit_clobber(t: &mut T, f: F) @@ -1105,36 +1109,11 @@ pub fn noop_visit_fn_header(header: &mut FnHeader, vis: &mut T) { visit_unsafety(unsafety, vis); } -// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible, -// or make crate visiting first class if necessary. pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { - visit_clobber(krate, |Crate { attrs, items, span }| { - let item_vis = - Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None }; - let item = P(Item { - ident: Ident::empty(), - attrs, - id: DUMMY_NODE_ID, - vis: item_vis, - span, - kind: ItemKind::Mod(Unsafe::No, ModKind::Loaded(items, Inline::Yes, span)), - tokens: None, - }); - let items = vis.flat_map_item(item); - - let len = items.len(); - if len == 0 { - Crate { attrs: vec![], items: vec![], span } - } else if len == 1 { - let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner(); - match kind { - ItemKind::Mod(_, ModKind::Loaded(items, ..)) => Crate { attrs, items, span }, - _ => panic!("visitor converted a module to not a module"), - } - } else { - panic!("a crate cannot expand to more than one item"); - } - }); + let Crate { attrs, items, span, is_placeholder: _ } = krate; + visit_attrs(attrs, vis); + items.flat_map_in_place(|item| vis.flat_map_item(item)); + vis.visit_span(span); } // Mutates one item into possibly many items. diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index be794ed221ae7..6840f092da61b 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -211,6 +211,9 @@ pub trait Visitor<'ast>: Sized { fn visit_pat_field(&mut self, fp: &'ast PatField) { walk_pat_field(self, fp) } + fn visit_crate(&mut self, krate: &'ast Crate) { + walk_crate(self, krate) + } } #[macro_export] diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index e74f38dd89c35..4b5703a429e71 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -75,3 +75,12 @@ pub fn attribute_to_string(attr: &ast::Attribute) -> String { pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { State::new().to_string(f) } + +pub fn crate_to_string_for_macros(krate: &ast::Crate) -> String { + State::new().to_string(|s| { + s.print_inner_attributes(&krate.attrs); + for item in &krate.items { + s.print_item(item); + } + }) +} diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 307730f7f5f14..1dcab17f9ed4c 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -77,6 +77,10 @@ fn flat_map_annotatable( Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param), Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef), Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant), + Annotatable::Crate(mut krate) => { + vis.visit_crate(&mut krate); + Some(Annotatable::Crate(krate)) + } } } @@ -101,6 +105,7 @@ impl CfgFinder { Annotatable::Param(param) => finder.visit_param(¶m), Annotatable::FieldDef(field) => finder.visit_field_def(&field), Annotatable::Variant(variant) => finder.visit_variant(&variant), + Annotatable::Crate(krate) => finder.visit_crate(krate), }; finder.has_cfg_or_cfg_attr } diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 64ccd4331e58a..418729e78436f 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -84,9 +84,35 @@ struct TestHarnessGenerator<'a> { tests: Vec, } +impl TestHarnessGenerator<'_> { + fn add_test_cases(&mut self, node_id: ast::NodeId, span: Span, prev_tests: Vec) { + let mut tests = mem::replace(&mut self.tests, prev_tests); + + if !tests.is_empty() { + // Create an identifier that will hygienically resolve the test + // case name, even in another module. + let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass( + span, + AstPass::TestHarness, + &[], + Some(node_id), + ); + for test in &mut tests { + // See the comment on `mk_main` for why we're using + // `apply_mark` directly. + test.ident.span = + test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque); + } + self.cx.test_cases.extend(tests); + } + } +} + impl<'a> MutVisitor for TestHarnessGenerator<'a> { fn visit_crate(&mut self, c: &mut ast::Crate) { + let prev_tests = mem::take(&mut self.tests); noop_visit_crate(c, self); + self.add_test_cases(ast::CRATE_NODE_ID, c.span, prev_tests); // Create a main function to run our tests c.items.push(mk_main(&mut self.cx)); @@ -103,34 +129,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { // We don't want to recurse into anything other than mods, since // mods or tests inside of functions will break things - if let ast::ItemKind::Mod(..) = item.kind { - let tests = mem::take(&mut self.tests); + if let ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) = item.kind { + let prev_tests = mem::take(&mut self.tests); noop_visit_item_kind(&mut item.kind, self); - let mut tests = mem::replace(&mut self.tests, tests); - - if !tests.is_empty() { - let parent = - if item.id == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { item.id }; - // Create an identifier that will hygienically resolve the test - // case name, even in another module. - let inner_span = match item.kind { - ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) => span, - _ => unreachable!(), - }; - let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass( - inner_span, - AstPass::TestHarness, - &[], - Some(parent), - ); - for test in &mut tests { - // See the comment on `mk_main` for why we're using - // `apply_mark` directly. - test.ident.span = - test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque); - } - self.cx.test_cases.extend(tests); - } + self.add_test_cases(item.id, span, prev_tests); } smallvec![P(item)] } @@ -146,7 +148,7 @@ fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPoin } else if sess.contains_name(&item.attrs, sym::rustc_main) { EntryPointType::MainAttr } else if item.ident.name == sym::main { - if depth == 1 { + if depth == 0 { // This is a top-level function so can be 'main' EntryPointType::MainNamed } else { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b630bc1f4732f..07b5e20b2ddc5 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -48,6 +48,7 @@ pub enum Annotatable { Param(ast::Param), FieldDef(ast::FieldDef), Variant(ast::Variant), + Crate(ast::Crate), } impl Annotatable { @@ -66,6 +67,7 @@ impl Annotatable { Annotatable::Param(ref p) => p.span, Annotatable::FieldDef(ref sf) => sf.span, Annotatable::Variant(ref v) => v.span, + Annotatable::Crate(ref c) => c.span, } } @@ -84,6 +86,7 @@ impl Annotatable { Annotatable::Param(p) => p.visit_attrs(f), Annotatable::FieldDef(sf) => sf.visit_attrs(f), Annotatable::Variant(v) => v.visit_attrs(f), + Annotatable::Crate(c) => c.visit_attrs(f), } } @@ -102,6 +105,7 @@ impl Annotatable { Annotatable::Param(p) => visitor.visit_param(p), Annotatable::FieldDef(sf) => visitor.visit_field_def(sf), Annotatable::Variant(v) => visitor.visit_variant(v), + Annotatable::Crate(c) => visitor.visit_crate(c), } } @@ -122,7 +126,8 @@ impl Annotatable { | Annotatable::GenericParam(..) | Annotatable::Param(..) | Annotatable::FieldDef(..) - | Annotatable::Variant(..) => panic!("unexpected annotatable"), + | Annotatable::Variant(..) + | Annotatable::Crate(..) => panic!("unexpected annotatable"), } } @@ -220,6 +225,13 @@ impl Annotatable { _ => panic!("expected variant"), } } + + pub fn expect_crate(self) -> ast::Crate { + match self { + Annotatable::Crate(krate) => krate, + _ => panic!("expected krate"), + } + } } /// Result of an expansion that may need to be retried. @@ -419,6 +431,11 @@ pub trait MacResult { fn make_variants(self: Box) -> Option> { None } + + fn make_crate(self: Box) -> Option { + // Fn-like macros cannot produce a crate. + unreachable!() + } } macro_rules! make_MacEager { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 89dbd64ed8168..ba675daac41db 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -14,13 +14,13 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs, MacCall}; use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem}; -use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe}; +use rustc_ast::{NodeId, PatKind, Path, StmtKind}; use rustc_ast_pretty::pprust; use rustc_attr::is_builtin_attr; use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, FatalError, PResult}; +use rustc_errors::{Applicability, PResult}; use rustc_feature::Features; use rustc_parse::parser::{ AttemptLocalParseRecovery, ForceCollect, Parser, RecoverColon, RecoverComma, @@ -33,7 +33,7 @@ use rustc_session::Limit; use rustc_span::symbol::{sym, Ident}; use rustc_span::{FileName, LocalExpnId, Span}; -use smallvec::{smallvec, SmallVec}; +use smallvec::SmallVec; use std::ops::DerefMut; use std::path::PathBuf; use std::rc::Rc; @@ -205,6 +205,7 @@ ast_fragments! { Variants(SmallVec<[ast::Variant; 1]>) { "variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants; } + Crate(ast::Crate) { "crate"; one fn visit_crate; fn visit_crate; fn make_crate; } } pub enum SupportsMacroExpansion { @@ -227,9 +228,8 @@ impl AstFragmentKind { AstFragmentKind::Items | AstFragmentKind::TraitItems | AstFragmentKind::ImplItems - | AstFragmentKind::ForeignItems => { - SupportsMacroExpansion::Yes { supports_inner_attrs: true } - } + | AstFragmentKind::ForeignItems + | AstFragmentKind::Crate => SupportsMacroExpansion::Yes { supports_inner_attrs: true }, AstFragmentKind::Arms | AstFragmentKind::Fields | AstFragmentKind::FieldPats @@ -288,6 +288,9 @@ impl AstFragmentKind { AstFragmentKind::OptExpr => { AstFragment::OptExpr(items.next().map(Annotatable::expect_expr)) } + AstFragmentKind::Crate => { + AstFragment::Crate(items.next().expect("expected exactly one crate").expect_crate()) + } AstFragmentKind::Pat | AstFragmentKind::Ty => { panic!("patterns and types aren't annotatable") } @@ -359,9 +362,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { MacroExpander { cx, monotonic } } - // FIXME: Avoid visiting the crate as a `Mod` item, - // make crate a first class expansion target instead. - pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { + pub fn expand_crate(&mut self, krate: ast::Crate) -> ast::Crate { let file_path = match self.cx.source_map().span_to_filename(krate.span) { FileName::Real(name) => name .into_local_path() @@ -375,52 +376,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { file_path_stack: vec![file_path], dir_path, }); - - let krate_item = AstFragment::Items(smallvec![P(ast::Item { - attrs: krate.attrs, - span: krate.span, - kind: ast::ItemKind::Mod( - Unsafe::No, - ModKind::Loaded(krate.items, Inline::Yes, krate.span) - ), - ident: Ident::empty(), - id: ast::DUMMY_NODE_ID, - vis: ast::Visibility { - span: krate.span.shrink_to_lo(), - kind: ast::VisibilityKind::Public, - tokens: None, - }, - tokens: None, - })]); - - match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) { - Some(ast::Item { - attrs, - kind: ast::ItemKind::Mod(_, ModKind::Loaded(items, ..)), - .. - }) => { - krate.attrs = attrs; - krate.items = items; - } - None => { - // Resolution failed so we return an empty expansion - krate.attrs = vec![]; - krate.items = vec![]; - } - Some(ast::Item { span, kind, .. }) => { - krate.attrs = vec![]; - krate.items = vec![]; - self.cx.span_err( - span, - &format!( - "expected crate top-level item to be a module after macro expansion, found {} {}", - kind.article(), kind.descr() - ), - ); - // FIXME: this workaround issue #84569 - FatalError.raise(); - } - }; + let krate = self.fully_expand_fragment(AstFragment::Crate(krate)).make_crate(); self.cx.trace_macros_diag(); krate } @@ -708,26 +664,32 @@ impl<'a, 'b> MacroExpander<'a, 'b> { SyntaxExtensionKind::Attr(expander) => { self.gate_proc_macro_input(&item); self.gate_proc_macro_attr_item(span, &item); - let mut fake_tokens = false; - if let Annotatable::Item(item_inner) = &item { - if let ItemKind::Mod(_, mod_kind) = &item_inner.kind { - // FIXME: Collect tokens and use them instead of generating - // fake ones. These are unstable, so it needs to be - // fixed prior to stabilization - // Fake tokens when we are invoking an inner attribute, and: - fake_tokens = matches!(attr.style, ast::AttrStyle::Inner) && - // We are invoking an attribute on the crate root, or an outline - // module - (item_inner.ident.name.is_empty() || !matches!(mod_kind, ast::ModKind::Loaded(_, Inline::Yes, _))); - } - } - let tokens = if fake_tokens { - rustc_parse::fake_token_stream( + let tokens = match &item { + // FIXME: Collect tokens and use them instead of generating + // fake ones. These are unstable, so it needs to be + // fixed prior to stabilization + // Fake tokens when we are invoking an inner attribute, and + // we are invoking it on an out-of-line module or crate. + Annotatable::Crate(krate) => rustc_parse::fake_token_stream_for_crate( &self.cx.sess.parse_sess, - &item.into_nonterminal(), - ) - } else { - item.into_tokens(&self.cx.sess.parse_sess) + krate, + ), + Annotatable::Item(item_inner) + if matches!(attr.style, ast::AttrStyle::Inner) + && matches!( + item_inner.kind, + ItemKind::Mod( + _, + ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _), + ) + ) => + { + rustc_parse::fake_token_stream( + &self.cx.sess.parse_sess, + &item.into_nonterminal(), + ) + } + _ => item.into_tokens(&self.cx.sess.parse_sess), }; let attr_item = attr.unwrap_normal_item(); if let MacArgs::Eq(..) = attr_item.args { @@ -804,7 +766,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Annotatable::Item(_) | Annotatable::TraitItem(_) | Annotatable::ImplItem(_) - | Annotatable::ForeignItem(_) => return, + | Annotatable::ForeignItem(_) + | Annotatable::Crate(..) => return, Annotatable::Stmt(stmt) => { // Attributes are stable on item statements, // but unstable on all other kinds of statements @@ -949,6 +912,7 @@ pub fn parse_ast_fragment<'a>( RecoverComma::No, RecoverColon::Yes, )?), + AstFragmentKind::Crate => AstFragment::Crate(this.parse_crate_mod()?), AstFragmentKind::Arms | AstFragmentKind::Fields | AstFragmentKind::FieldPats @@ -1195,6 +1159,30 @@ macro_rules! assign_id { } impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { + fn visit_crate(&mut self, krate: &mut ast::Crate) { + let span = krate.span; + let empty_crate = + || ast::Crate { attrs: Vec::new(), items: Vec::new(), span, is_placeholder: None }; + let mut fold_crate = |krate: ast::Crate| { + let mut krate = match self.configure(krate) { + Some(krate) => krate, + None => return empty_crate(), + }; + + if let Some(attr) = self.take_first_attr(&mut krate) { + return self + .collect_attr(attr, Annotatable::Crate(krate), AstFragmentKind::Crate) + .make_crate(); + } + + noop_visit_crate(&mut krate, self); + krate + }; + + // Cannot use `visit_clobber` here, see the FIXME on it. + *krate = fold_crate(mem::replace(krate, empty_crate())); + } + fn visit_expr(&mut self, expr: &mut P) { self.cfg.configure_expr(expr); visit_clobber(expr.deref_mut(), |mut expr| { diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 12b6bc7bbe768..25b3a5820e60a 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -46,6 +46,12 @@ pub fn placeholder( || P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None }); match kind { + AstFragmentKind::Crate => AstFragment::Crate(ast::Crate { + attrs: Default::default(), + items: Default::default(), + span, + is_placeholder: Some(id), + }), AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()), AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())), AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item { @@ -354,4 +360,12 @@ impl MutVisitor for PlaceholderExpander { _ => noop_visit_ty(ty, self), } } + + fn visit_crate(&mut self, krate: &mut ast::Crate) { + if let Some(id) = krate.is_placeholder { + *krate = self.remove(id).make_crate(); + } else { + noop_visit_crate(krate, self) + } + } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index d3917dfb14ab3..dbee92cf598b5 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -323,7 +323,7 @@ pub fn configure_and_expand( let crate_attrs = krate.attrs.clone(); let extern_mod_loaded = |ident: Ident, attrs, items, span| { - let krate = ast::Crate { attrs, items, span }; + let krate = ast::Crate { attrs, items, span, is_placeholder: None }; pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, &ident.name.as_str()); (krate.attrs, krate.items) }; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index a40f47f895bbe..2b1b2f3fce496 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -326,6 +326,12 @@ pub fn fake_token_stream(sess: &ParseSess, nt: &Nonterminal) -> TokenStream { parse_stream_from_source_str(filename, source, sess, Some(nt.span())) } +pub fn fake_token_stream_for_crate(sess: &ParseSess, krate: &ast::Crate) -> TokenStream { + let source = pprust::crate_to_string_for_macros(krate); + let filename = FileName::macro_expansion_source_code(&source); + parse_stream_from_source_str(filename, source, sess, Some(krate.span)) +} + pub fn parse_cfg_attr( attr: &Attribute, parse_sess: &ParseSess, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 24a8df49ac7ee..cbeaf675be4e5 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -26,7 +26,7 @@ impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main entry point for the parser. pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> { let (attrs, items, span) = self.parse_mod(&token::Eof)?; - Ok(ast::Crate { attrs, items, span }) + Ok(ast::Crate { attrs, items, span, is_placeholder: None }) } /// Parses a `mod { ... }` or `mod ;` item. diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 3cf9d324a38da..26a5260b93fd2 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -651,11 +651,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { /// Constructs the reduced graph for one item. fn build_reduced_graph_for_item(&mut self, item: &'b Item) { - if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Empty { - // Fake crate root item from expand. - return; - } - let parent_scope = &self.parent_scope; let parent = parent_scope.module; let expansion = parent_scope.expansion; @@ -1499,4 +1494,13 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { visit::walk_variant(self, variant); } + + fn visit_crate(&mut self, krate: &'b ast::Crate) { + if let Some(id) = krate.is_placeholder { + self.visit_invoc_in_module(id); + } else { + visit::walk_crate(self, krate); + self.contains_macro_use(&krate.attrs); + } + } } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 5879cb1daa582..391baa85c61db 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -7,7 +7,7 @@ use rustc_expand::expand::AstFragment; use rustc_hir::def_id::LocalDefId; use rustc_hir::definitions::*; use rustc_span::hygiene::LocalExpnId; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::sym; use rustc_span::Span; use tracing::debug; @@ -92,10 +92,6 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { // information we encapsulate into, the better let def_data = match &i.kind { ItemKind::Impl { .. } => DefPathData::Impl, - ItemKind::Mod(..) if i.ident.name == kw::Empty => { - // Fake crate root item from expand. - return visit::walk_item(self, i); - } ItemKind::Mod(..) | ItemKind::Trait(..) | ItemKind::TraitAlias(..) @@ -346,4 +342,12 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { fn visit_field_def(&mut self, field: &'a FieldDef) { self.collect_field(field, None); } + + fn visit_crate(&mut self, krate: &'a Crate) { + if let Some(id) = krate.is_placeholder { + self.visit_macro_invoc(id) + } else { + visit::walk_crate(self, krate) + } + } } diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index 8961655ede36f..22484ba6378d3 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0}} +{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index 082f04134ce8f..ae56bef35ffe7 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0}} +{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null} diff --git a/src/test/ui/proc-macro/crate-attrs-multiple.rs b/src/test/ui/proc-macro/crate-attrs-multiple.rs new file mode 100644 index 0000000000000..29a0eca417281 --- /dev/null +++ b/src/test/ui/proc-macro/crate-attrs-multiple.rs @@ -0,0 +1,14 @@ +// Multiple custom crate-level attributes, both inert and active. + +// check-pass +// aux-crate:test_macros=test-macros.rs + +#![feature(custom_inner_attributes)] +#![feature(prelude_import)] + +#![test_macros::identity_attr] +#![rustfmt::skip] +#![test_macros::identity_attr] +#![rustfmt::skip] + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs index 039878af56eb6..a4161d4fc3dcc 100644 --- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs @@ -1,7 +1,10 @@ -// edition:2018 -// aux-crate:issue_59191=issue-59191.rs // Test that using a macro to replace the entire crate tree with a non-'mod' item errors out nicely. // `issue_59191::no_main` replaces whatever's passed in with `fn main() {}`. + +// edition:2018 +// aux-crate:issue_59191=issue-59191.rs +// error-pattern: requires `sized` lang_item + #![feature(custom_inner_attributes)] #![issue_59191::no_main] -//~^ ERROR expected crate top-level item to be a module after macro expansion, found a function +#![issue_59191::no_main] diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr index 126c52db548f7..f7516c7d377da 100644 --- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr @@ -1,10 +1,4 @@ -error: expected crate top-level item to be a module after macro expansion, found a function - --> $DIR/issue-59191-replace-root-with-fn.rs:6:1 - | -LL | #![issue_59191::no_main] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `issue_59191::no_main` (in Nightly builds, run with -Z macro-backtrace for more info) +error: requires `sized` lang_item error: aborting due to previous error