diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 55b243a84a9..4d4c6217ad0 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 d586426d70e..b9c397974a1 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 fc5cc963992..205625573a6 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 be794ed221a..6840f092da6 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 e74f38dd89c..4b5703a429e 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 8cc761dfd51..5933a49ea58 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 64ccd4331e5..418729e7843 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_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index bb3d3a415e7..82a02c3e543 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1013,7 +1013,9 @@ impl HandlerInner { } fn treat_err_as_bug(&self) -> bool { - self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c.get()) + self.flags + .treat_err_as_bug + .map_or(false, |c| self.err_count() + self.lint_err_count >= c.get()) } fn print_error_count(&mut self, registry: &Registry) { @@ -1205,7 +1207,10 @@ impl HandlerInner { fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug() { - match (self.err_count(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0)) { + match ( + self.err_count() + self.lint_err_count, + self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0), + ) { (1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"), (0, _) | (1, _) => {} (count, as_bug) => panic!( diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b630bc1f473..07b5e20b2dd 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 89dbd64ed81..ba675daac41 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 12b6bc7bbe7..25b3a5820e6 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 d3917dfb14a..dbee92cf598 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 a40f47f895b..2b1b2f3fce4 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 24a8df49ac7..cbeaf675be4 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 3cf9d324a38..26a5260b93f 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 5879cb1daa5..391baa85c61 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/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index bd7feb8b183..6c866031370 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -181,6 +181,9 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; #[stable(feature = "inclusive_range", since = "1.26.0")] pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; +#[unstable(feature = "one_sided_range", issue = "69780")] +pub use self::range::OneSidedRange; + #[unstable(feature = "try_trait_v2", issue = "84277")] pub use self::try_trait::{FromResidual, Try}; diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index b74ba92c76e..11367220678 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -971,3 +971,21 @@ impl RangeBounds for RangeToInclusive<&T> { Included(self.end) } } + +/// `OneSidedRange` is implemented for built-in range types that are unbounded +/// on one side. For example, `a..`, `..b` and `..=c` implement `OneSidedRange`, +/// but `..`, `d..e`, and `f..=g` do not. +/// +/// Types that implement `OneSidedRange` must return `Bound::Unbounded` +/// from one of `RangeBounds::start_bound` or `RangeBounds::end_bound`. +#[unstable(feature = "one_sided_range", issue = "69780")] +pub trait OneSidedRange: RangeBounds {} + +#[unstable(feature = "one_sided_range", issue = "69780")] +impl OneSidedRange for RangeTo where Self: RangeBounds {} + +#[unstable(feature = "one_sided_range", issue = "69780")] +impl OneSidedRange for RangeFrom where Self: RangeBounds {} + +#[unstable(feature = "one_sided_range", issue = "69780")] +impl OneSidedRange for RangeToInclusive where Self: RangeBounds {} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 34754cffae1..a3f59d30759 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -10,7 +10,7 @@ use crate::cmp::Ordering::{self, Greater, Less}; use crate::marker::Copy; use crate::mem; use crate::num::NonZeroUsize; -use crate::ops::{FnMut, Range, RangeBounds}; +use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds}; use crate::option::Option; use crate::option::Option::{None, Some}; use crate::ptr; @@ -82,6 +82,29 @@ pub use index::range; #[unstable(feature = "inherent_ascii_escape", issue = "77174")] pub use ascii::EscapeAscii; +/// Calculates the direction and split point of a one-sided range. +/// +/// This is a helper function for `take` and `take_mut` that returns +/// the direction of the split (front or back) as well as the index at +/// which to split. Returns `None` if the split index would overflow. +#[inline] +fn split_point_of(range: impl OneSidedRange) -> Option<(Direction, usize)> { + use Bound::*; + + Some(match (range.start_bound(), range.end_bound()) { + (Unbounded, Excluded(i)) => (Direction::Front, *i), + (Unbounded, Included(i)) => (Direction::Front, i.checked_add(1)?), + (Excluded(i), Unbounded) => (Direction::Back, i.checked_add(1)?), + (Included(i), Unbounded) => (Direction::Back, *i), + _ => unreachable!(), + }) +} + +enum Direction { + Front, + Back, +} + #[lang = "slice"] #[cfg(not(test))] impl [T] { @@ -3517,6 +3540,245 @@ impl [T] { { self.binary_search_by(|x| if pred(x) { Less } else { Greater }).unwrap_or_else(|i| i) } + + /// Removes the subslice corresponding to the given range + /// and returns a reference to it. + /// + /// Returns `None` and does not modify the slice if the given + /// range is out of bounds. + /// + /// Note that this method only accepts one-sided ranges such as + /// `2..` or `..6`, but not `2..6`. + /// + /// # Examples + /// + /// Taking the first three elements of a slice: + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// let mut first_three = slice.take(..3).unwrap(); + /// + /// assert_eq!(slice, &['d']); + /// assert_eq!(first_three, &['a', 'b', 'c']); + /// ``` + /// + /// Taking the last two elements of a slice: + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// let mut tail = slice.take(2..).unwrap(); + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(tail, &['c', 'd']); + /// ``` + /// + /// Getting `None` when `range` is out of bounds: + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// + /// assert_eq!(None, slice.take(5..)); + /// assert_eq!(None, slice.take(..5)); + /// assert_eq!(None, slice.take(..=4)); + /// let expected: &[char] = &['a', 'b', 'c', 'd']; + /// assert_eq!(Some(expected), slice.take(..4)); + /// ``` + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[unstable(feature = "slice_take", issue = "62280")] + pub fn take<'a, R: OneSidedRange>(self: &mut &'a Self, range: R) -> Option<&'a Self> { + let (direction, split_index) = split_point_of(range)?; + if split_index > self.len() { + return None; + } + let (front, back) = self.split_at(split_index); + match direction { + Direction::Front => { + *self = back; + Some(front) + } + Direction::Back => { + *self = front; + Some(back) + } + } + } + + /// Removes the subslice corresponding to the given range + /// and returns a mutable reference to it. + /// + /// Returns `None` and does not modify the slice if the given + /// range is out of bounds. + /// + /// Note that this method only accepts one-sided ranges such as + /// `2..` or `..6`, but not `2..6`. + /// + /// # Examples + /// + /// Taking the first three elements of a slice: + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// let mut first_three = slice.take_mut(..3).unwrap(); + /// + /// assert_eq!(slice, &mut ['d']); + /// assert_eq!(first_three, &mut ['a', 'b', 'c']); + /// ``` + /// + /// Taking the last two elements of a slice: + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// let mut tail = slice.take_mut(2..).unwrap(); + /// + /// assert_eq!(slice, &mut ['a', 'b']); + /// assert_eq!(tail, &mut ['c', 'd']); + /// ``` + /// + /// Getting `None` when `range` is out of bounds: + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// + /// assert_eq!(None, slice.take_mut(5..)); + /// assert_eq!(None, slice.take_mut(..5)); + /// assert_eq!(None, slice.take_mut(..=4)); + /// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// assert_eq!(Some(expected), slice.take_mut(..4)); + /// ``` + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[unstable(feature = "slice_take", issue = "62280")] + pub fn take_mut<'a, R: OneSidedRange>( + self: &mut &'a mut Self, + range: R, + ) -> Option<&'a mut Self> { + let (direction, split_index) = split_point_of(range)?; + if split_index > self.len() { + return None; + } + let (front, back) = mem::take(self).split_at_mut(split_index); + match direction { + Direction::Front => { + *self = back; + Some(front) + } + Direction::Back => { + *self = front; + Some(back) + } + } + } + + /// Removes the first element of the slice and returns a reference + /// to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &[_] = &['a', 'b', 'c']; + /// let first = slice.take_first().unwrap(); + /// + /// assert_eq!(slice, &['b', 'c']); + /// assert_eq!(first, &'a'); + /// ``` + #[inline] + #[unstable(feature = "slice_take", issue = "62280")] + pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> { + let (first, rem) = self.split_first()?; + *self = rem; + Some(first) + } + + /// Removes the first element of the slice and returns a mutable + /// reference to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; + /// let first = slice.take_first_mut().unwrap(); + /// *first = 'd'; + /// + /// assert_eq!(slice, &['b', 'c']); + /// assert_eq!(first, &'d'); + /// ``` + #[inline] + #[unstable(feature = "slice_take", issue = "62280")] + pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + let (first, rem) = mem::take(self).split_first_mut()?; + *self = rem; + Some(first) + } + + /// Removes the last element of the slice and returns a reference + /// to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &[_] = &['a', 'b', 'c']; + /// let last = slice.take_last().unwrap(); + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(last, &'c'); + /// ``` + #[inline] + #[unstable(feature = "slice_take", issue = "62280")] + pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> { + let (last, rem) = self.split_last()?; + *self = rem; + Some(last) + } + + /// Removes the last element of the slice and returns a mutable + /// reference to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; + /// let last = slice.take_last_mut().unwrap(); + /// *last = 'd'; + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(last, &'d'); + /// ``` + #[inline] + #[unstable(feature = "slice_take", issue = "62280")] + pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + let (last, rem) = mem::take(self).split_last_mut()?; + *self = rem; + Some(last) + } } trait CloneFromSpec { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 00d0259321d..414995e8f7a 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -36,6 +36,7 @@ #![feature(pattern)] #![feature(sort_internals)] #![feature(slice_partition_at_index)] +#![feature(slice_take)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_array_assume_init)] #![feature(maybe_uninit_extra)] diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 66f03c68cbe..7ba01caeefd 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -2234,3 +2234,112 @@ fn slice_split_array_mut_out_of_bounds() { v.split_array_mut::<7>(); } + +macro_rules! take_tests { + (slice: &[], $($tts:tt)*) => { + take_tests!(ty: &[()], slice: &[], $($tts)*); + }; + (slice: &mut [], $($tts:tt)*) => { + take_tests!(ty: &mut [()], slice: &mut [], $($tts)*); + }; + (slice: &$slice:expr, $($tts:tt)*) => { + take_tests!(ty: &[_], slice: &$slice, $($tts)*); + }; + (slice: &mut $slice:expr, $($tts:tt)*) => { + take_tests!(ty: &mut [_], slice: &mut $slice, $($tts)*); + }; + (ty: $ty:ty, slice: $slice:expr, method: $method:ident, $(($test_name:ident, ($($args:expr),*), $output:expr, $remaining:expr),)*) => { + $( + #[test] + fn $test_name() { + let mut slice: $ty = $slice; + assert_eq!($output, slice.$method($($args)*)); + let remaining: $ty = $remaining; + assert_eq!(remaining, slice); + } + )* + }; +} + +take_tests! { + slice: &[0, 1, 2, 3], method: take, + (take_in_bounds_range_to, (..1), Some(&[0] as _), &[1, 2, 3]), + (take_in_bounds_range_to_inclusive, (..=0), Some(&[0] as _), &[1, 2, 3]), + (take_in_bounds_range_from, (2..), Some(&[2, 3] as _), &[0, 1]), + (take_oob_range_to, (..5), None, &[0, 1, 2, 3]), + (take_oob_range_to_inclusive, (..=4), None, &[0, 1, 2, 3]), + (take_oob_range_from, (5..), None, &[0, 1, 2, 3]), +} + +take_tests! { + slice: &mut [0, 1, 2, 3], method: take_mut, + (take_mut_in_bounds_range_to, (..1), Some(&mut [0] as _), &mut [1, 2, 3]), + (take_mut_in_bounds_range_to_inclusive, (..=0), Some(&mut [0] as _), &mut [1, 2, 3]), + (take_mut_in_bounds_range_from, (2..), Some(&mut [2, 3] as _), &mut [0, 1]), + (take_mut_oob_range_to, (..5), None, &mut [0, 1, 2, 3]), + (take_mut_oob_range_to_inclusive, (..=4), None, &mut [0, 1, 2, 3]), + (take_mut_oob_range_from, (5..), None, &mut [0, 1, 2, 3]), +} + +take_tests! { + slice: &[1, 2], method: take_first, + (take_first_nonempty, (), Some(&1), &[2]), +} + +take_tests! { + slice: &mut [1, 2], method: take_first_mut, + (take_first_mut_nonempty, (), Some(&mut 1), &mut [2]), +} + +take_tests! { + slice: &[1, 2], method: take_last, + (take_last_nonempty, (), Some(&2), &[1]), +} + +take_tests! { + slice: &mut [1, 2], method: take_last_mut, + (take_last_mut_nonempty, (), Some(&mut 2), &mut [1]), +} + +take_tests! { + slice: &[], method: take_first, + (take_first_empty, (), None, &[]), +} + +take_tests! { + slice: &mut [], method: take_first_mut, + (take_first_mut_empty, (), None, &mut []), +} + +take_tests! { + slice: &[], method: take_last, + (take_last_empty, (), None, &[]), +} + +take_tests! { + slice: &mut [], method: take_last_mut, + (take_last_mut_empty, (), None, &mut []), +} + +const EMPTY_MAX: &'static [()] = &[(); usize::MAX]; + +// can't be a constant due to const mutability rules +macro_rules! empty_max_mut { + () => { + &mut [(); usize::MAX] as _ + }; +} + +take_tests! { + slice: &[(); usize::MAX], method: take, + (take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]), + (take_oob_max_range_to_inclusive, (..=usize::MAX), None, EMPTY_MAX), + (take_in_bounds_max_range_from, (usize::MAX..), Some(&[] as _), EMPTY_MAX), +} + +take_tests! { + slice: &mut [(); usize::MAX], method: take_mut, + (take_mut_in_bounds_max_range_to, (..usize::MAX), Some(empty_max_mut!()), &mut [(); 0]), + (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), + (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), +} diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9b05716a67b..e131089f361 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1337,25 +1337,15 @@ fn normalize(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option> { return None; } - use crate::rustc_trait_selection::infer::TyCtxtInferExt; - use crate::rustc_trait_selection::traits::query::normalize::AtExt; - use rustc_middle::traits::ObligationCause; - // Try to normalize `::T` to a type let lifted = ty.lift_to_tcx(cx.tcx).unwrap(); - let normalized = cx.tcx.infer_ctxt().enter(|infcx| { - infcx - .at(&ObligationCause::dummy(), cx.param_env) - .normalize(lifted) - .map(|resolved| infcx.resolve_vars_if_possible(resolved.value)) - }); - match normalized { + match cx.tcx.try_normalize_erasing_regions(cx.param_env, lifted) { Ok(normalized_value) => { - debug!("normalized {:?} to {:?}", ty, normalized_value); + trace!("normalized {:?} to {:?}", ty, normalized_value); Some(normalized_value) } Err(err) => { - debug!("failed to normalize {:?}: {:?}", ty, err); + info!("failed to normalize {:?}: {:?}", ty, err); None } } diff --git a/src/llvm-project b/src/llvm-project index f9b03d0e2d7..01c8b654f9a 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit f9b03d0e2d7378f8dd5697ceb72b310060f7598f +Subproject commit 01c8b654f9a01371414d1fd69cba38b289510a9e diff --git a/src/test/rustdoc-ui/auxiliary/overflow.rs b/src/test/rustdoc-ui/auxiliary/overflow.rs new file mode 100644 index 00000000000..ff65936bec9 --- /dev/null +++ b/src/test/rustdoc-ui/auxiliary/overflow.rs @@ -0,0 +1,20 @@ +pub struct B0; +pub struct B1; +use std::ops::Shl; +use std::ops::Sub; +pub type Shleft = >::Output; +pub type Sub1 = >::Output; +pub struct UInt { + pub(crate) msb: U, + pub(crate) lsb: B, +} +impl Shl> for UInt +where + UInt: Sub, + UInt, B0>: Shl>>, +{ + type Output = Shleft, B0>, Sub1>>; + fn shl(self, rhs: UInt) -> Self::Output { + unimplemented!() + } +} diff --git a/src/test/rustdoc-ui/normalize-cycle.rs b/src/test/rustdoc-ui/normalize-cycle.rs new file mode 100644 index 00000000000..f48cad373cd --- /dev/null +++ b/src/test/rustdoc-ui/normalize-cycle.rs @@ -0,0 +1,25 @@ +// check-pass +// Regresion test for . +pub trait Query {} + +pub trait AsQuery { + type Query; +} + +impl AsQuery for T { + type Query = T; +} + +pub trait SelectDsl { + type Output; +} + +impl SelectDsl for T +where + T: AsQuery, + T::Query: SelectDsl, +{ + type Output = >::Output; +} + +pub type Select = >::Output; diff --git a/src/test/rustdoc-ui/normalize-overflow.rs b/src/test/rustdoc-ui/normalize-overflow.rs new file mode 100644 index 00000000000..0cdcc88e314 --- /dev/null +++ b/src/test/rustdoc-ui/normalize-overflow.rs @@ -0,0 +1,3 @@ +// aux-crate:overflow=overflow.rs +// check-pass +// Regression test for . 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 8961655ede3..22484ba6378 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 082f04134ce..ae56bef35ff 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 00000000000..29a0eca4172 --- /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 039878af56e..a4161d4fc3d 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 126c52db548..f7516c7d377 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