Rollup merge of #91313 - petrochenkov:cratexp, r=Aaron1011
expand: Turn `ast::Crate` into a first class expansion target And stop creating a fake `mod` item for the crate root when expanding a crate, thus addressing FIXMEs left in https://github.com/rust-lang/rust/pull/82238, and making a step towards a proper support for crate-level macro attributes (cc #54726). I haven't added token collection support for the whole crate in this PR, maybe later. r? `@Aaron1011`
This commit is contained in:
commit
519a842c50
@ -517,6 +517,8 @@ pub struct Crate {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub items: Vec<P<Item>>,
|
||||
pub span: Span,
|
||||
// Placeholder ID if the crate node is a macro placeholder.
|
||||
pub is_placeholder: Option<NodeId>,
|
||||
}
|
||||
|
||||
/// Possible values inside of compile-time attribute lists.
|
||||
|
@ -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 @@ fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
|
||||
// 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
|
||||
|
@ -284,6 +284,10 @@ fn visit_span(&mut self, _sp: &mut Span) {
|
||||
/// 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, F>(t: &mut T, f: F)
|
||||
@ -1105,36 +1109,11 @@ pub fn noop_visit_fn_header<T: MutVisitor>(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<T: MutVisitor>(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.
|
||||
|
@ -211,6 +211,9 @@ fn visit_expr_field(&mut self, f: &'ast ExprField) {
|
||||
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]
|
||||
|
@ -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);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
|
||||
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
|
||||
}
|
||||
|
@ -84,9 +84,35 @@ struct TestHarnessGenerator<'a> {
|
||||
tests: Vec<Test>,
|
||||
}
|
||||
|
||||
impl TestHarnessGenerator<'_> {
|
||||
fn add_test_cases(&mut self, node_id: ast::NodeId, span: Span, prev_tests: Vec<Test>) {
|
||||
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 @@ fn visit_crate(&mut self, c: &mut ast::Crate) {
|
||||
|
||||
// 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 {
|
||||
|
@ -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 @@ pub fn span(&self) -> Span {
|
||||
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 @@ pub fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
|
||||
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 @@ pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
|
||||
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 @@ pub fn into_nonterminal(self) -> Nonterminal {
|
||||
| Annotatable::GenericParam(..)
|
||||
| Annotatable::Param(..)
|
||||
| Annotatable::FieldDef(..)
|
||||
| Annotatable::Variant(..) => panic!("unexpected annotatable"),
|
||||
| Annotatable::Variant(..)
|
||||
| Annotatable::Crate(..) => panic!("unexpected annotatable"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,6 +225,13 @@ pub fn expect_variant(self) -> ast::Variant {
|
||||
_ => 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 @@ fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> {
|
||||
fn make_variants(self: Box<Self>) -> Option<SmallVec<[ast::Variant; 1]>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn make_crate(self: Box<Self>) -> Option<ast::Crate> {
|
||||
// Fn-like macros cannot produce a crate.
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! make_MacEager {
|
||||
|
@ -14,13 +14,13 @@
|
||||
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_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 @@ impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> {
|
||||
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 @@ pub fn supports_macro_expansion(self) -> SupportsMacroExpansion {
|
||||
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 @@ fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(
|
||||
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 @@ pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
|
||||
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 @@ pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
|
||||
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 @@ fn expand_invoc(
|
||||
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 @@ fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
|
||||
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<ast::Expr>) {
|
||||
self.cfg.configure_expr(expr);
|
||||
visit_clobber(expr.deref_mut(), |mut expr| {
|
||||
|
@ -46,6 +46,12 @@ fn mac_placeholder() -> ast::MacCall {
|
||||
|| 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 @@ fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
|
||||
_ => 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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 <foo> { ... }` or `mod <foo>;` item.
|
||||
|
@ -651,11 +651,6 @@ fn build_reduced_graph_for_use_tree(
|
||||
|
||||
/// 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 @@ fn visit_variant(&mut self, variant: &'b ast::Variant) {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
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 @@ fn visit_item(&mut self, i: &'a Item) {
|
||||
// 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 @@ fn visit_param(&mut self, p: &'a Param) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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}
|
||||
|
@ -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}
|
||||
|
14
src/test/ui/proc-macro/crate-attrs-multiple.rs
Normal file
14
src/test/ui/proc-macro/crate-attrs-multiple.rs
Normal file
@ -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() {}
|
@ -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]
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user