2022-11-20 13:06:44 +01:00
|
|
|
use std::ops::Deref;
|
2021-02-22 19:06:36 +03:00
|
|
|
use std::path::PathBuf;
|
|
|
|
use std::rc::Rc;
|
2025-02-03 06:44:41 +03:00
|
|
|
use std::sync::Arc;
|
2019-10-16 10:59:30 +02:00
|
|
|
use std::{iter, mem};
|
|
|
|
|
2020-11-14 14:47:14 +03:00
|
|
|
use rustc_ast as ast;
|
2020-02-29 20:37:32 +03:00
|
|
|
use rustc_ast::mut_visit::*;
|
|
|
|
use rustc_ast::ptr::P;
|
2022-04-26 15:40:14 +03:00
|
|
|
use rustc_ast::token::{self, Delimiter};
|
2020-03-03 23:22:32 +03:00
|
|
|
use rustc_ast::tokenstream::TokenStream;
|
2024-02-24 15:22:42 -05:00
|
|
|
use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list};
|
2022-11-18 11:24:21 +11:00
|
|
|
use rustc_ast::{
|
|
|
|
AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, ExprKind, ForeignItemKind,
|
2024-10-04 21:59:04 +09:00
|
|
|
HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind,
|
2022-01-20 11:06:45 -05:00
|
|
|
NodeId, PatKind, StmtKind, TyKind,
|
|
|
|
};
|
2020-01-11 17:02:46 +01:00
|
|
|
use rustc_ast_pretty::pprust;
|
2023-03-08 15:53:56 +11:00
|
|
|
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
2022-11-15 14:24:33 +01:00
|
|
|
use rustc_errors::PResult;
|
2019-11-30 00:23:38 +01:00
|
|
|
use rustc_feature::Features;
|
2021-07-13 13:18:03 +02:00
|
|
|
use rustc_parse::parser::{
|
2022-01-12 20:43:24 +00:00
|
|
|
AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma,
|
2024-04-17 17:08:58 +10:00
|
|
|
token_descr,
|
2021-07-13 13:18:03 +02:00
|
|
|
};
|
2019-10-15 22:48:13 +02:00
|
|
|
use rustc_parse::validate_attr;
|
2024-02-29 16:40:44 +11:00
|
|
|
use rustc_session::lint::BuiltinLintDiag;
|
2021-07-14 19:51:45 -05:00
|
|
|
use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
|
2024-01-10 00:37:30 -05:00
|
|
|
use rustc_session::parse::feature_err;
|
|
|
|
use rustc_session::{Limit, Session};
|
2024-04-30 08:48:27 +10:00
|
|
|
use rustc_span::hygiene::SyntaxContext;
|
2024-12-13 10:29:23 +11:00
|
|
|
use rustc_span::{ErrorGuaranteed, FileName, Ident, LocalExpnId, Span, sym};
|
2021-10-17 19:32:34 +03:00
|
|
|
use smallvec::SmallVec;
|
2024-07-29 08:13:50 +10:00
|
|
|
|
2019-10-16 10:59:30 +02:00
|
|
|
use crate::base::*;
|
2025-03-22 21:42:34 +03:00
|
|
|
use crate::config::{StripUnconfigured, attr_into_trace};
|
2022-11-15 14:24:33 +01:00
|
|
|
use crate::errors::{
|
2024-06-22 19:14:16 +03:00
|
|
|
EmptyDelegationMac, GlobDelegationOutsideImpls, GlobDelegationTraitlessQpath, IncompleteParse,
|
2022-01-05 14:15:44 +08:00
|
|
|
RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue,
|
2024-06-22 19:14:16 +03:00
|
|
|
WrongFragmentKind,
|
2024-07-29 08:13:50 +10:00
|
|
|
};
|
2024-08-09 00:53:15 +03:00
|
|
|
use crate::fluent_generated;
|
2022-01-05 14:15:44 +08:00
|
|
|
use crate::mbe::diagnostics::annotate_err_with_kind;
|
2024-09-11 12:36:40 -07:00
|
|
|
use crate::module::{
|
|
|
|
DirOwnership, ParsedExternalMod, mod_dir_path, mod_file_path_from_attr, parse_external_mod,
|
|
|
|
};
|
2021-05-18 21:46:41 -04:00
|
|
|
use crate::placeholders::{PlaceholderExpander, placeholder};
|
2016-08-31 09:02:45 +00:00
|
|
|
|
2023-12-01 21:19:22 -03:00
|
|
|
macro_rules! ast_fragments {
|
|
|
|
(
|
|
|
|
$($Kind:ident($AstTy:ty) {
|
|
|
|
$kind_name:expr;
|
|
|
|
$(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)?
|
|
|
|
$(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)?
|
|
|
|
fn $make_ast:ident;
|
|
|
|
})*
|
|
|
|
) => {
|
|
|
|
/// A fragment of AST that can be produced by a single macro expansion.
|
|
|
|
/// Can also serve as an input and intermediate result for macro expansion operations.
|
|
|
|
pub enum AstFragment {
|
|
|
|
OptExpr(Option<P<ast::Expr>>),
|
|
|
|
MethodReceiverExpr(P<ast::Expr>),
|
|
|
|
$($Kind($AstTy),)*
|
|
|
|
}
|
|
|
|
|
|
|
|
/// "Discriminant" of an AST fragment.
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
|
|
pub enum AstFragmentKind {
|
|
|
|
OptExpr,
|
|
|
|
MethodReceiverExpr,
|
|
|
|
$($Kind,)*
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AstFragmentKind {
|
|
|
|
pub fn name(self) -> &'static str {
|
|
|
|
match self {
|
|
|
|
AstFragmentKind::OptExpr => "expression",
|
|
|
|
AstFragmentKind::MethodReceiverExpr => "expression",
|
|
|
|
$(AstFragmentKind::$Kind => $kind_name,)*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn make_from<'a>(self, result: Box<dyn MacResult + 'a>) -> Option<AstFragment> {
|
|
|
|
match self {
|
|
|
|
AstFragmentKind::OptExpr =>
|
|
|
|
result.make_expr().map(Some).map(AstFragment::OptExpr),
|
|
|
|
AstFragmentKind::MethodReceiverExpr =>
|
|
|
|
result.make_expr().map(AstFragment::MethodReceiverExpr),
|
|
|
|
$(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AstFragment {
|
2024-05-01 09:39:07 +10:00
|
|
|
fn add_placeholders(&mut self, placeholders: &[NodeId]) {
|
2023-12-01 21:19:22 -03:00
|
|
|
if placeholders.is_empty() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
match self {
|
|
|
|
$($(AstFragment::$Kind(ast) => ast.extend(placeholders.iter().flat_map(|id| {
|
|
|
|
${ignore($flat_map_ast_elt)}
|
|
|
|
placeholder(AstFragmentKind::$Kind, *id, None).$make_ast()
|
|
|
|
})),)?)*
|
|
|
|
_ => panic!("unexpected AST fragment kind")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-01 09:39:07 +10:00
|
|
|
pub(crate) fn make_opt_expr(self) -> Option<P<ast::Expr>> {
|
2023-12-01 21:19:22 -03:00
|
|
|
match self {
|
|
|
|
AstFragment::OptExpr(expr) => expr,
|
|
|
|
_ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-01 09:39:07 +10:00
|
|
|
pub(crate) fn make_method_receiver_expr(self) -> P<ast::Expr> {
|
2023-12-01 21:19:22 -03:00
|
|
|
match self {
|
|
|
|
AstFragment::MethodReceiverExpr(expr) => expr,
|
|
|
|
_ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-23 01:05:07 +03:00
|
|
|
$(pub fn $make_ast(self) -> $AstTy {
|
2016-08-27 05:27:59 +00:00
|
|
|
match self {
|
2018-06-23 01:05:07 +03:00
|
|
|
AstFragment::$Kind(ast) => ast,
|
2018-06-20 02:08:08 +03:00
|
|
|
_ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
|
2016-08-27 05:27:59 +00:00
|
|
|
}
|
2018-06-23 01:05:07 +03:00
|
|
|
})*
|
2016-05-19 09:45:37 +00:00
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn make_ast<T: InvocationCollectorNode>(self) -> T::OutputTy {
|
|
|
|
T::fragment_to_output(self)
|
|
|
|
}
|
|
|
|
|
2024-05-01 09:39:07 +10:00
|
|
|
pub(crate) fn mut_visit_with<F: MutVisitor>(&mut self, vis: &mut F) {
|
2016-08-27 05:27:59 +00:00
|
|
|
match self {
|
Overhaul `syntax::fold::Folder`.
This commit changes `syntax::fold::Folder` from a functional style
(where most methods take a `T` and produce a new `T`) to a more
imperative style (where most methods take and modify a `&mut T`), and
renames it `syntax::mut_visit::MutVisitor`.
The first benefit is speed. The functional style does not require any
reallocations, due to the use of `P::map` and
`MoveMap::move_{,flat_}map`. However, every field in the AST must be
overwritten; even those fields that are unchanged are overwritten with
the same value. This causes a lot of unnecessary memory writes. The
imperative style reduces instruction counts by 1--3% across a wide range
of workloads, particularly incremental workloads.
The second benefit is conciseness; the imperative style is usually more
concise. E.g. compare the old functional style:
```
fn fold_abc(&mut self, abc: ABC) {
ABC {
a: fold_a(abc.a),
b: fold_b(abc.b),
c: abc.c,
}
}
```
with the imperative style:
```
fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
visit_a(a);
visit_b(b);
}
```
(The reductions get larger in more complex examples.)
Overall, the patch removes over 200 lines of code -- even though the new
code has more comments -- and a lot of the remaining lines have fewer
characters.
Some notes:
- The old style used methods called `fold_*`. The new style mostly uses
methods called `visit_*`, but there are a few methods that map a `T`
to something other than a `T`, which are called `flat_map_*` (`T` maps
to multiple `T`s) or `filter_map_*` (`T` maps to 0 or 1 `T`s).
- `move_map.rs`/`MoveMap`/`move_map`/`move_flat_map` are renamed
`map_in_place.rs`/`MapInPlace`/`map_in_place`/`flat_map_in_place` to
reflect their slightly changed signatures.
- Although this commit renames the `fold` module as `mut_visit`, it
keeps it in the `fold.rs` file, so as not to confuse git. The next
commit will rename the file.
2019-02-05 15:20:55 +11:00
|
|
|
AstFragment::OptExpr(opt_expr) => {
|
|
|
|
visit_clobber(opt_expr, |opt_expr| {
|
|
|
|
if let Some(expr) = opt_expr {
|
|
|
|
vis.filter_map_expr(expr)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2022-10-23 09:22:19 +00:00
|
|
|
AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr),
|
2019-05-29 20:05:43 +02:00
|
|
|
$($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)*
|
2018-06-23 01:05:07 +03:00
|
|
|
$($(AstFragment::$Kind(ast) =>
|
2024-07-08 10:40:37 +00:00
|
|
|
ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast, $($args)*)),)?)*
|
2016-08-27 05:27:59 +00:00
|
|
|
}
|
2016-05-19 09:45:37 +00:00
|
|
|
}
|
2016-09-07 23:21:59 +00:00
|
|
|
|
2024-02-18 03:12:44 -05:00
|
|
|
pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) -> V::Result {
|
2022-12-23 17:34:23 +00:00
|
|
|
match self {
|
2024-02-18 03:12:44 -05:00
|
|
|
AstFragment::OptExpr(Some(expr)) => try_visit!(visitor.visit_expr(expr)),
|
2018-06-20 02:08:08 +03:00
|
|
|
AstFragment::OptExpr(None) => {}
|
2024-02-18 03:12:44 -05:00
|
|
|
AstFragment::MethodReceiverExpr(expr) => try_visit!(visitor.visit_method_receiver_expr(expr)),
|
|
|
|
$($(AstFragment::$Kind(ast) => try_visit!(visitor.$visit_ast(ast)),)?)*
|
|
|
|
$($(AstFragment::$Kind(ast) => walk_list!(visitor, $visit_ast_elt, &ast[..], $($args)*),)?)*
|
2016-09-07 23:21:59 +00:00
|
|
|
}
|
2024-02-18 03:12:44 -05:00
|
|
|
V::Result::output()
|
2016-09-07 23:21:59 +00:00
|
|
|
}
|
2016-05-19 09:45:37 +00:00
|
|
|
}
|
2016-09-02 09:12:47 +00:00
|
|
|
|
2019-10-16 10:59:30 +02:00
|
|
|
impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> {
|
|
|
|
$(fn $make_ast(self: Box<crate::mbe::macro_rules::ParserAnyMacro<'a>>)
|
2018-06-23 01:05:07 +03:00
|
|
|
-> Option<$AstTy> {
|
|
|
|
Some(self.make(AstFragmentKind::$Kind).$make_ast())
|
2016-09-23 09:32:58 +00:00
|
|
|
})*
|
|
|
|
}
|
2016-08-27 05:27:59 +00:00
|
|
|
}
|
2016-05-19 09:45:37 +00:00
|
|
|
}
|
|
|
|
|
2018-06-20 02:08:08 +03:00
|
|
|
ast_fragments! {
|
Overhaul `syntax::fold::Folder`.
This commit changes `syntax::fold::Folder` from a functional style
(where most methods take a `T` and produce a new `T`) to a more
imperative style (where most methods take and modify a `&mut T`), and
renames it `syntax::mut_visit::MutVisitor`.
The first benefit is speed. The functional style does not require any
reallocations, due to the use of `P::map` and
`MoveMap::move_{,flat_}map`. However, every field in the AST must be
overwritten; even those fields that are unchanged are overwritten with
the same value. This causes a lot of unnecessary memory writes. The
imperative style reduces instruction counts by 1--3% across a wide range
of workloads, particularly incremental workloads.
The second benefit is conciseness; the imperative style is usually more
concise. E.g. compare the old functional style:
```
fn fold_abc(&mut self, abc: ABC) {
ABC {
a: fold_a(abc.a),
b: fold_b(abc.b),
c: abc.c,
}
}
```
with the imperative style:
```
fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
visit_a(a);
visit_b(b);
}
```
(The reductions get larger in more complex examples.)
Overall, the patch removes over 200 lines of code -- even though the new
code has more comments -- and a lot of the remaining lines have fewer
characters.
Some notes:
- The old style used methods called `fold_*`. The new style mostly uses
methods called `visit_*`, but there are a few methods that map a `T`
to something other than a `T`, which are called `flat_map_*` (`T` maps
to multiple `T`s) or `filter_map_*` (`T` maps to 0 or 1 `T`s).
- `move_map.rs`/`MoveMap`/`move_map`/`move_flat_map` are renamed
`map_in_place.rs`/`MapInPlace`/`map_in_place`/`flat_map_in_place` to
reflect their slightly changed signatures.
- Although this commit renames the `fold` module as `mut_visit`, it
keeps it in the `fold.rs` file, so as not to confuse git. The next
commit will rename the file.
2019-02-05 15:20:55 +11:00
|
|
|
Expr(P<ast::Expr>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; }
|
|
|
|
Pat(P<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; }
|
|
|
|
Ty(P<ast::Ty>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; }
|
2018-08-30 11:42:16 +02:00
|
|
|
Stmts(SmallVec<[ast::Stmt; 1]>) {
|
2020-01-30 00:18:54 +01:00
|
|
|
"statement"; many fn flat_map_stmt; fn visit_stmt(); fn make_stmts;
|
2018-08-30 11:42:16 +02:00
|
|
|
}
|
|
|
|
Items(SmallVec<[P<ast::Item>; 1]>) {
|
2020-01-30 00:18:54 +01:00
|
|
|
"item"; many fn flat_map_item; fn visit_item(); fn make_items;
|
2018-08-30 11:42:16 +02:00
|
|
|
}
|
2019-12-12 16:41:18 +11:00
|
|
|
TraitItems(SmallVec<[P<ast::AssocItem>; 1]>) {
|
2020-01-30 00:18:54 +01:00
|
|
|
"trait item";
|
2024-07-08 10:40:37 +00:00
|
|
|
many fn flat_map_assoc_item;
|
2020-01-30 00:18:54 +01:00
|
|
|
fn visit_assoc_item(AssocCtxt::Trait);
|
|
|
|
fn make_trait_items;
|
2018-06-23 01:05:07 +03:00
|
|
|
}
|
2019-12-12 16:41:18 +11:00
|
|
|
ImplItems(SmallVec<[P<ast::AssocItem>; 1]>) {
|
2020-01-30 00:18:54 +01:00
|
|
|
"impl item";
|
2024-07-08 10:40:37 +00:00
|
|
|
many fn flat_map_assoc_item;
|
2025-03-25 09:00:35 +00:00
|
|
|
fn visit_assoc_item(AssocCtxt::Impl { of_trait: false });
|
2020-01-30 00:18:54 +01:00
|
|
|
fn make_impl_items;
|
2018-06-23 01:05:07 +03:00
|
|
|
}
|
2025-03-25 09:00:35 +00:00
|
|
|
TraitImplItems(SmallVec<[P<ast::AssocItem>; 1]>) {
|
|
|
|
"impl item";
|
|
|
|
many fn flat_map_assoc_item;
|
|
|
|
fn visit_assoc_item(AssocCtxt::Impl { of_trait: true });
|
|
|
|
fn make_trait_impl_items;
|
|
|
|
}
|
2019-12-12 16:41:18 +11:00
|
|
|
ForeignItems(SmallVec<[P<ast::ForeignItem>; 1]>) {
|
2019-09-09 09:26:25 -03:00
|
|
|
"foreign item";
|
|
|
|
many fn flat_map_foreign_item;
|
2020-01-30 00:18:54 +01:00
|
|
|
fn visit_foreign_item();
|
2019-09-09 09:26:25 -03:00
|
|
|
fn make_foreign_items;
|
|
|
|
}
|
|
|
|
Arms(SmallVec<[ast::Arm; 1]>) {
|
2020-01-30 00:18:54 +01:00
|
|
|
"match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms;
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
2022-01-05 13:56:45 +08:00
|
|
|
ExprFields(SmallVec<[ast::ExprField; 1]>) {
|
2021-03-16 00:36:07 +03:00
|
|
|
"field expression"; many fn flat_map_expr_field; fn visit_expr_field(); fn make_expr_fields;
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
2022-01-05 13:56:45 +08:00
|
|
|
PatFields(SmallVec<[ast::PatField; 1]>) {
|
2019-09-09 09:26:25 -03:00
|
|
|
"field pattern";
|
2021-03-16 00:36:07 +03:00
|
|
|
many fn flat_map_pat_field;
|
|
|
|
fn visit_pat_field();
|
|
|
|
fn make_pat_fields;
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
|
|
|
GenericParams(SmallVec<[ast::GenericParam; 1]>) {
|
|
|
|
"generic parameter";
|
|
|
|
many fn flat_map_generic_param;
|
2020-01-30 00:18:54 +01:00
|
|
|
fn visit_generic_param();
|
2019-09-09 09:26:25 -03:00
|
|
|
fn make_generic_params;
|
|
|
|
}
|
|
|
|
Params(SmallVec<[ast::Param; 1]>) {
|
2020-01-30 00:18:54 +01:00
|
|
|
"function parameter"; many fn flat_map_param; fn visit_param(); fn make_params;
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
2022-01-05 13:56:45 +08:00
|
|
|
FieldDefs(SmallVec<[ast::FieldDef; 1]>) {
|
2019-09-09 09:26:25 -03:00
|
|
|
"field";
|
2021-03-16 00:36:07 +03:00
|
|
|
many fn flat_map_field_def;
|
|
|
|
fn visit_field_def();
|
|
|
|
fn make_field_defs;
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
|
|
|
Variants(SmallVec<[ast::Variant; 1]>) {
|
2020-01-30 00:18:54 +01:00
|
|
|
"variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants;
|
2018-06-23 01:05:07 +03:00
|
|
|
}
|
2025-02-05 18:58:29 +08:00
|
|
|
WherePredicates(SmallVec<[ast::WherePredicate; 1]>) {
|
|
|
|
"where predicate";
|
|
|
|
many fn flat_map_where_predicate;
|
|
|
|
fn visit_where_predicate();
|
|
|
|
fn make_where_predicates;
|
|
|
|
}
|
2021-10-17 19:32:34 +03:00
|
|
|
Crate(ast::Crate) { "crate"; one fn visit_crate; fn visit_crate; fn make_crate; }
|
2016-05-19 09:45:37 +00:00
|
|
|
}
|
|
|
|
|
2021-03-01 16:02:09 -05:00
|
|
|
pub enum SupportsMacroExpansion {
|
|
|
|
No,
|
|
|
|
Yes { supports_inner_attrs: bool },
|
|
|
|
}
|
|
|
|
|
2018-06-20 02:08:08 +03:00
|
|
|
impl AstFragmentKind {
|
2024-02-25 22:22:11 +01:00
|
|
|
pub(crate) fn dummy(self, span: Span, guar: ErrorGuaranteed) -> AstFragment {
|
|
|
|
self.make_from(DummyResult::any(span, guar)).expect("couldn't create a dummy AST fragment")
|
2016-06-11 22:59:33 +00:00
|
|
|
}
|
2016-09-02 06:14:38 +00:00
|
|
|
|
2021-03-01 16:02:09 -05:00
|
|
|
pub fn supports_macro_expansion(self) -> SupportsMacroExpansion {
|
2020-11-19 01:49:20 +03:00
|
|
|
match self {
|
|
|
|
AstFragmentKind::OptExpr
|
|
|
|
| AstFragmentKind::Expr
|
2022-10-23 09:22:19 +00:00
|
|
|
| AstFragmentKind::MethodReceiverExpr
|
2020-11-19 01:49:20 +03:00
|
|
|
| AstFragmentKind::Stmts
|
2021-03-01 16:02:09 -05:00
|
|
|
| AstFragmentKind::Ty
|
|
|
|
| AstFragmentKind::Pat => SupportsMacroExpansion::Yes { supports_inner_attrs: false },
|
|
|
|
AstFragmentKind::Items
|
2020-11-19 01:49:20 +03:00
|
|
|
| AstFragmentKind::TraitItems
|
|
|
|
| AstFragmentKind::ImplItems
|
2025-03-25 09:00:35 +00:00
|
|
|
| AstFragmentKind::TraitImplItems
|
2021-10-17 19:32:34 +03:00
|
|
|
| AstFragmentKind::ForeignItems
|
|
|
|
| AstFragmentKind::Crate => SupportsMacroExpansion::Yes { supports_inner_attrs: true },
|
2020-11-19 01:49:20 +03:00
|
|
|
AstFragmentKind::Arms
|
2022-01-05 13:56:45 +08:00
|
|
|
| AstFragmentKind::ExprFields
|
|
|
|
| AstFragmentKind::PatFields
|
2020-11-19 01:49:20 +03:00
|
|
|
| AstFragmentKind::GenericParams
|
|
|
|
| AstFragmentKind::Params
|
2022-01-05 13:56:45 +08:00
|
|
|
| AstFragmentKind::FieldDefs
|
2025-02-05 18:58:29 +08:00
|
|
|
| AstFragmentKind::Variants
|
|
|
|
| AstFragmentKind::WherePredicates => SupportsMacroExpansion::No,
|
2020-11-19 01:49:20 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-20 02:08:08 +03:00
|
|
|
fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(
|
|
|
|
self,
|
|
|
|
items: I,
|
|
|
|
) -> AstFragment {
|
2018-04-17 23:19:21 -07:00
|
|
|
let mut items = items.into_iter();
|
2016-09-02 06:14:38 +00:00
|
|
|
match self {
|
2019-09-09 09:26:25 -03:00
|
|
|
AstFragmentKind::Arms => {
|
|
|
|
AstFragment::Arms(items.map(Annotatable::expect_arm).collect())
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2022-01-05 13:56:45 +08:00
|
|
|
AstFragmentKind::ExprFields => {
|
|
|
|
AstFragment::ExprFields(items.map(Annotatable::expect_expr_field).collect())
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2022-01-05 13:56:45 +08:00
|
|
|
AstFragmentKind::PatFields => {
|
|
|
|
AstFragment::PatFields(items.map(Annotatable::expect_pat_field).collect())
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2019-09-09 09:26:25 -03:00
|
|
|
AstFragmentKind::GenericParams => {
|
|
|
|
AstFragment::GenericParams(items.map(Annotatable::expect_generic_param).collect())
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2019-09-09 09:26:25 -03:00
|
|
|
AstFragmentKind::Params => {
|
|
|
|
AstFragment::Params(items.map(Annotatable::expect_param).collect())
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2022-01-05 13:56:45 +08:00
|
|
|
AstFragmentKind::FieldDefs => {
|
|
|
|
AstFragment::FieldDefs(items.map(Annotatable::expect_field_def).collect())
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2019-09-09 09:26:25 -03:00
|
|
|
AstFragmentKind::Variants => {
|
|
|
|
AstFragment::Variants(items.map(Annotatable::expect_variant).collect())
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2025-02-05 18:58:29 +08:00
|
|
|
AstFragmentKind::WherePredicates => AstFragment::WherePredicates(
|
|
|
|
items.map(Annotatable::expect_where_predicate).collect(),
|
|
|
|
),
|
2018-06-20 02:08:08 +03:00
|
|
|
AstFragmentKind::Items => {
|
|
|
|
AstFragment::Items(items.map(Annotatable::expect_item).collect())
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2018-06-20 02:08:08 +03:00
|
|
|
AstFragmentKind::ImplItems => {
|
|
|
|
AstFragment::ImplItems(items.map(Annotatable::expect_impl_item).collect())
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2025-03-25 09:00:35 +00:00
|
|
|
AstFragmentKind::TraitImplItems => {
|
|
|
|
AstFragment::TraitImplItems(items.map(Annotatable::expect_impl_item).collect())
|
|
|
|
}
|
2018-06-20 02:08:08 +03:00
|
|
|
AstFragmentKind::TraitItems => {
|
|
|
|
AstFragment::TraitItems(items.map(Annotatable::expect_trait_item).collect())
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2018-06-20 02:08:08 +03:00
|
|
|
AstFragmentKind::ForeignItems => {
|
|
|
|
AstFragment::ForeignItems(items.map(Annotatable::expect_foreign_item).collect())
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2018-06-20 02:08:08 +03:00
|
|
|
AstFragmentKind::Stmts => {
|
|
|
|
AstFragment::Stmts(items.map(Annotatable::expect_stmt).collect())
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2018-06-20 02:08:08 +03:00
|
|
|
AstFragmentKind::Expr => AstFragment::Expr(
|
2018-04-17 23:19:21 -07:00
|
|
|
items.next().expect("expected exactly one expression").expect_expr(),
|
|
|
|
),
|
2022-10-23 09:22:19 +00:00
|
|
|
AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(
|
|
|
|
items.next().expect("expected exactly one expression").expect_expr(),
|
|
|
|
),
|
2018-06-20 02:08:08 +03:00
|
|
|
AstFragmentKind::OptExpr => {
|
|
|
|
AstFragment::OptExpr(items.next().map(Annotatable::expect_expr))
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2021-10-17 19:32:34 +03:00
|
|
|
AstFragmentKind::Crate => {
|
|
|
|
AstFragment::Crate(items.next().expect("expected exactly one crate").expect_crate())
|
|
|
|
}
|
2018-06-20 02:08:08 +03:00
|
|
|
AstFragmentKind::Pat | AstFragmentKind::Ty => {
|
2018-04-17 23:19:21 -07:00
|
|
|
panic!("patterns and types aren't annotatable")
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2016-09-02 06:14:38 +00:00
|
|
|
}
|
|
|
|
}
|
2016-05-16 10:09:23 +00:00
|
|
|
}
|
2015-01-27 01:22:12 +01:00
|
|
|
|
2016-08-27 05:27:59 +00:00
|
|
|
pub struct Invocation {
|
2016-09-07 23:21:59 +00:00
|
|
|
pub kind: InvocationKind,
|
2019-09-09 09:26:25 -03:00
|
|
|
pub fragment_kind: AstFragmentKind,
|
2017-03-01 23:48:16 +00:00
|
|
|
pub expansion_data: ExpansionData,
|
2016-09-02 06:14:38 +00:00
|
|
|
}
|
|
|
|
|
2016-09-07 23:21:59 +00:00
|
|
|
pub enum InvocationKind {
|
2016-09-02 06:14:38 +00:00
|
|
|
Bang {
|
2022-08-12 12:20:10 +10:00
|
|
|
mac: P<ast::MacCall>,
|
2016-09-02 06:14:38 +00:00
|
|
|
span: Span,
|
|
|
|
},
|
|
|
|
Attr {
|
2019-07-08 01:00:43 +03:00
|
|
|
attr: ast::Attribute,
|
2025-03-25 09:00:35 +00:00
|
|
|
/// Re-insertion position for inert attributes.
|
2021-02-23 00:54:09 +03:00
|
|
|
pos: usize,
|
2016-09-02 06:14:38 +00:00
|
|
|
item: Annotatable,
|
2025-03-25 09:00:35 +00:00
|
|
|
/// Required for resolving derive helper attributes.
|
2022-01-07 14:54:16 +08:00
|
|
|
derives: Vec<ast::Path>,
|
2016-09-02 06:14:38 +00:00
|
|
|
},
|
2017-02-01 21:03:09 +10:30
|
|
|
Derive {
|
2022-01-07 14:54:16 +08:00
|
|
|
path: ast::Path,
|
2022-09-20 11:55:07 +00:00
|
|
|
is_const: bool,
|
2017-02-01 21:03:09 +10:30
|
|
|
item: Annotatable,
|
|
|
|
},
|
2024-03-15 14:21:03 +03:00
|
|
|
GlobDelegation {
|
|
|
|
item: P<ast::AssocItem>,
|
2025-03-25 09:00:35 +00:00
|
|
|
/// Whether this is a trait impl or an inherent impl
|
|
|
|
of_trait: bool,
|
2024-03-15 14:21:03 +03:00
|
|
|
},
|
2011-07-06 15:22:23 -07:00
|
|
|
}
|
2013-07-29 17:25:00 -07:00
|
|
|
|
2019-11-23 16:54:24 +03:00
|
|
|
impl InvocationKind {
|
|
|
|
fn placeholder_visibility(&self) -> Option<ast::Visibility> {
|
|
|
|
// HACK: For unnamed fields placeholders should have the same visibility as the actual
|
|
|
|
// fields because for tuple structs/variants resolve determines visibilities of their
|
2022-10-14 00:25:34 +08:00
|
|
|
// constructor using these field visibilities before attributes on them are expanded.
|
2019-11-23 16:54:24 +03:00
|
|
|
// The assumption is that the attribute expansion cannot change field visibilities,
|
|
|
|
// and it holds because only inert attributes are supported in this position.
|
|
|
|
match self {
|
2021-03-16 00:36:07 +03:00
|
|
|
InvocationKind::Attr { item: Annotatable::FieldDef(field), .. }
|
|
|
|
| InvocationKind::Derive { item: Annotatable::FieldDef(field), .. }
|
2019-11-23 16:54:24 +03:00
|
|
|
if field.ident.is_none() =>
|
2019-12-22 17:42:04 -05:00
|
|
|
{
|
2019-11-23 16:54:24 +03:00
|
|
|
Some(field.vis.clone())
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2019-11-23 16:54:24 +03:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-07 23:21:59 +00:00
|
|
|
impl Invocation {
|
2018-07-12 13:24:59 +03:00
|
|
|
pub fn span(&self) -> Span {
|
2019-07-08 01:00:43 +03:00
|
|
|
match &self.kind {
|
|
|
|
InvocationKind::Bang { span, .. } => *span,
|
|
|
|
InvocationKind::Attr { attr, .. } => attr.span,
|
|
|
|
InvocationKind::Derive { path, .. } => path.span,
|
2025-03-25 09:00:35 +00:00
|
|
|
InvocationKind::GlobDelegation { item, .. } => item.span,
|
2016-09-07 23:21:59 +00:00
|
|
|
}
|
|
|
|
}
|
2024-05-01 10:57:08 +10:00
|
|
|
|
|
|
|
fn span_mut(&mut self) -> &mut Span {
|
|
|
|
match &mut self.kind {
|
|
|
|
InvocationKind::Bang { span, .. } => span,
|
|
|
|
InvocationKind::Attr { attr, .. } => &mut attr.span,
|
|
|
|
InvocationKind::Derive { path, .. } => &mut path.span,
|
2025-03-25 09:00:35 +00:00
|
|
|
InvocationKind::GlobDelegation { item, .. } => &mut item.span,
|
2024-05-01 10:57:08 +10:00
|
|
|
}
|
|
|
|
}
|
2016-09-07 23:21:59 +00:00
|
|
|
}
|
|
|
|
|
2019-06-14 19:39:39 +03:00
|
|
|
pub struct MacroExpander<'a, 'b> {
|
2014-03-27 15:39:48 -07:00
|
|
|
pub cx: &'a mut ExtCtxt<'b>,
|
2018-10-22 00:45:24 +01:00
|
|
|
monotonic: bool, // cf. `cx.monotonic_expander()`
|
2014-12-14 15:42:41 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'b> MacroExpander<'a, 'b> {
|
2016-09-06 05:42:45 +00:00
|
|
|
pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
|
2019-06-25 23:22:45 +02:00
|
|
|
MacroExpander { cx, monotonic }
|
2014-12-14 15:42:41 +13:00
|
|
|
}
|
2016-05-16 10:09:23 +00:00
|
|
|
|
2021-10-17 19:32:34 +03:00
|
|
|
pub fn expand_crate(&mut self, krate: ast::Crate) -> ast::Crate {
|
2022-03-03 18:45:25 -05:00
|
|
|
let file_path = match self.cx.source_map().span_to_filename(krate.spans.inner_span) {
|
2021-04-09 00:54:51 +01:00
|
|
|
FileName::Real(name) => name
|
|
|
|
.into_local_path()
|
|
|
|
.expect("attempting to resolve a file path in an external file"),
|
2021-04-19 23:27:02 +01:00
|
|
|
other => PathBuf::from(other.prefer_local().to_string()),
|
2016-09-29 00:22:46 +00:00
|
|
|
};
|
2021-02-21 19:15:43 +03:00
|
|
|
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();
|
|
|
|
self.cx.root_path = dir_path.clone();
|
|
|
|
self.cx.current_expansion.module = Rc::new(ModuleData {
|
|
|
|
mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)],
|
|
|
|
file_path_stack: vec![file_path],
|
|
|
|
dir_path,
|
|
|
|
});
|
2021-10-17 19:32:34 +03:00
|
|
|
let krate = self.fully_expand_fragment(AstFragment::Crate(krate)).make_crate();
|
2022-01-05 16:09:55 +08:00
|
|
|
assert_eq!(krate.id, ast::CRATE_NODE_ID);
|
2017-05-05 21:49:59 -07:00
|
|
|
self.cx.trace_macros_diag();
|
2016-09-02 09:12:47 +00:00
|
|
|
krate
|
|
|
|
}
|
|
|
|
|
2022-11-27 11:15:06 +00:00
|
|
|
/// Recursively expand all macro invocations in this AST fragment.
|
2019-08-14 02:30:09 +03:00
|
|
|
pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment {
|
2016-09-07 23:21:59 +00:00
|
|
|
let orig_expansion_data = self.cx.current_expansion.clone();
|
2020-11-14 14:47:14 +03:00
|
|
|
let orig_force_mode = self.cx.force_mode;
|
2016-09-07 23:21:59 +00:00
|
|
|
|
2018-06-23 19:27:01 +03:00
|
|
|
// Collect all macro invocations and replace them with placeholders.
|
Overhaul `syntax::fold::Folder`.
This commit changes `syntax::fold::Folder` from a functional style
(where most methods take a `T` and produce a new `T`) to a more
imperative style (where most methods take and modify a `&mut T`), and
renames it `syntax::mut_visit::MutVisitor`.
The first benefit is speed. The functional style does not require any
reallocations, due to the use of `P::map` and
`MoveMap::move_{,flat_}map`. However, every field in the AST must be
overwritten; even those fields that are unchanged are overwritten with
the same value. This causes a lot of unnecessary memory writes. The
imperative style reduces instruction counts by 1--3% across a wide range
of workloads, particularly incremental workloads.
The second benefit is conciseness; the imperative style is usually more
concise. E.g. compare the old functional style:
```
fn fold_abc(&mut self, abc: ABC) {
ABC {
a: fold_a(abc.a),
b: fold_b(abc.b),
c: abc.c,
}
}
```
with the imperative style:
```
fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
visit_a(a);
visit_b(b);
}
```
(The reductions get larger in more complex examples.)
Overall, the patch removes over 200 lines of code -- even though the new
code has more comments -- and a lot of the remaining lines have fewer
characters.
Some notes:
- The old style used methods called `fold_*`. The new style mostly uses
methods called `visit_*`, but there are a few methods that map a `T`
to something other than a `T`, which are called `flat_map_*` (`T` maps
to multiple `T`s) or `filter_map_*` (`T` maps to 0 or 1 `T`s).
- `move_map.rs`/`MoveMap`/`move_map`/`move_flat_map` are renamed
`map_in_place.rs`/`MapInPlace`/`map_in_place`/`flat_map_in_place` to
reflect their slightly changed signatures.
- Although this commit renames the `fold` module as `mut_visit`, it
keeps it in the `fold.rs` file, so as not to confuse git. The next
commit will rename the file.
2019-02-05 15:20:55 +11:00
|
|
|
let (mut fragment_with_placeholders, mut invocations) =
|
2018-06-20 02:08:08 +03:00
|
|
|
self.collect_invocations(input_fragment, &[]);
|
2018-06-23 19:27:01 +03:00
|
|
|
|
|
|
|
// Optimization: if we resolve all imports now,
|
|
|
|
// we'll be able to immediately resolve most of imported macros.
|
2016-11-10 10:11:25 +00:00
|
|
|
self.resolve_imports();
|
2016-09-02 09:12:47 +00:00
|
|
|
|
2018-08-19 15:30:23 +02:00
|
|
|
// Resolve paths in all invocations and produce output expanded fragments for them, but
|
2018-06-23 19:27:01 +03:00
|
|
|
// do not insert them into our input AST fragment yet, only store in `expanded_fragments`.
|
|
|
|
// The output fragments also go through expansion recursively until no invocations are left.
|
|
|
|
// Unresolved macros produce dummy outputs as a recovery measure.
|
|
|
|
invocations.reverse();
|
2018-06-20 02:08:08 +03:00
|
|
|
let mut expanded_fragments = Vec::new();
|
2016-10-11 03:41:48 +00:00
|
|
|
let mut undetermined_invocations = Vec::new();
|
|
|
|
let (mut progress, mut force) = (false, !self.monotonic);
|
|
|
|
loop {
|
2021-10-16 03:45:14 +02:00
|
|
|
let Some((invoc, ext)) = invocations.pop() else {
|
2016-11-10 10:11:25 +00:00
|
|
|
self.resolve_imports();
|
|
|
|
if undetermined_invocations.is_empty() {
|
|
|
|
break;
|
|
|
|
}
|
2019-06-30 11:30:01 -07:00
|
|
|
invocations = mem::take(&mut undetermined_invocations);
|
2024-05-01 10:50:05 +10:00
|
|
|
force = !progress;
|
|
|
|
progress = false;
|
2020-11-14 14:47:14 +03:00
|
|
|
if force && self.monotonic {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.cx.dcx().span_delayed_bug(
|
2020-11-14 14:47:14 +03:00
|
|
|
invocations.last().unwrap().0.span(),
|
|
|
|
"expansion entered force mode without producing any errors",
|
|
|
|
);
|
|
|
|
}
|
2016-10-11 03:41:48 +00:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
2020-11-14 14:47:14 +03:00
|
|
|
let ext = match ext {
|
|
|
|
Some(ext) => ext,
|
2020-03-09 20:50:12 +03:00
|
|
|
None => {
|
|
|
|
let eager_expansion_root = if self.monotonic {
|
|
|
|
invoc.expansion_data.id
|
|
|
|
} else {
|
|
|
|
orig_expansion_data.id
|
|
|
|
};
|
|
|
|
match self.cx.resolver.resolve_macro_invocation(
|
|
|
|
&invoc,
|
|
|
|
eager_expansion_root,
|
|
|
|
force,
|
|
|
|
) {
|
2020-11-14 14:47:14 +03:00
|
|
|
Ok(ext) => ext,
|
2020-03-09 20:50:12 +03:00
|
|
|
Err(Indeterminate) => {
|
|
|
|
// Cannot resolve, will retry this invocation later.
|
|
|
|
undetermined_invocations.push((invoc, None));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2016-10-11 03:41:48 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-07-16 01:42:58 +03:00
|
|
|
let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data;
|
2021-06-21 02:05:37 +08:00
|
|
|
let depth = depth - orig_expansion_data.depth;
|
2016-09-07 23:21:59 +00:00
|
|
|
self.cx.current_expansion = invoc.expansion_data.clone();
|
2020-11-14 14:47:14 +03:00
|
|
|
self.cx.force_mode = force;
|
2019-07-03 12:47:24 +03:00
|
|
|
|
2020-11-19 01:54:19 +03:00
|
|
|
let fragment_kind = invoc.fragment_kind;
|
2024-05-01 10:25:55 +10:00
|
|
|
match self.expand_invoc(invoc, &ext.kind) {
|
2020-11-14 14:47:14 +03:00
|
|
|
ExpandResult::Ready(fragment) => {
|
2021-04-08 21:35:24 -04:00
|
|
|
let mut derive_invocations = Vec::new();
|
2020-11-14 14:47:14 +03:00
|
|
|
let derive_placeholders = self
|
|
|
|
.cx
|
|
|
|
.resolver
|
|
|
|
.take_derive_resolutions(expn_id)
|
|
|
|
.map(|derives| {
|
2021-04-08 21:35:24 -04:00
|
|
|
derive_invocations.reserve(derives.len());
|
2020-11-14 14:47:14 +03:00
|
|
|
derives
|
|
|
|
.into_iter()
|
2024-04-25 15:13:53 +10:00
|
|
|
.map(|DeriveResolution { path, item, exts: _, is_const }| {
|
2020-11-14 14:47:14 +03:00
|
|
|
// FIXME: Consider using the derive resolutions (`_exts`)
|
|
|
|
// instead of enqueuing the derives to be resolved again later.
|
2021-06-25 20:43:04 +02:00
|
|
|
let expn_id = LocalExpnId::fresh_empty();
|
2021-04-08 21:35:24 -04:00
|
|
|
derive_invocations.push((
|
2020-11-14 14:47:14 +03:00
|
|
|
Invocation {
|
2022-09-20 11:55:07 +00:00
|
|
|
kind: InvocationKind::Derive { path, item, is_const },
|
2020-11-14 14:47:14 +03:00
|
|
|
fragment_kind,
|
|
|
|
expansion_data: ExpansionData {
|
|
|
|
id: expn_id,
|
|
|
|
..self.cx.current_expansion.clone()
|
|
|
|
},
|
2020-11-19 01:54:19 +03:00
|
|
|
},
|
2020-11-14 14:47:14 +03:00
|
|
|
None,
|
|
|
|
));
|
|
|
|
NodeId::placeholder_from_expn_id(expn_id)
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
})
|
|
|
|
.unwrap_or_default();
|
2019-08-24 21:12:13 +03:00
|
|
|
|
2024-05-01 10:25:55 +10:00
|
|
|
let (expanded_fragment, collected_invocations) =
|
2021-04-08 21:35:24 -04:00
|
|
|
self.collect_invocations(fragment, &derive_placeholders);
|
2024-05-01 09:27:20 +10:00
|
|
|
// We choose to expand any derive invocations associated with this macro
|
|
|
|
// invocation *before* any macro invocations collected from the output
|
|
|
|
// fragment.
|
2021-04-08 21:35:24 -04:00
|
|
|
derive_invocations.extend(collected_invocations);
|
2024-05-01 10:25:55 +10:00
|
|
|
|
|
|
|
progress = true;
|
|
|
|
if expanded_fragments.len() < depth {
|
|
|
|
expanded_fragments.push(Vec::new());
|
|
|
|
}
|
|
|
|
expanded_fragments[depth - 1].push((expn_id, expanded_fragment));
|
|
|
|
invocations.extend(derive_invocations.into_iter().rev());
|
2017-02-02 07:01:15 +00:00
|
|
|
}
|
2020-11-14 14:47:14 +03:00
|
|
|
ExpandResult::Retry(invoc) => {
|
|
|
|
if force {
|
2023-12-18 20:54:03 +11:00
|
|
|
self.cx.dcx().span_bug(
|
2020-11-14 14:47:14 +03:00
|
|
|
invoc.span(),
|
|
|
|
"expansion entered force mode but is still stuck",
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// Cannot expand, will retry this invocation later.
|
|
|
|
undetermined_invocations.push((invoc, Some(ext)));
|
|
|
|
}
|
|
|
|
}
|
2016-09-02 03:35:59 +00:00
|
|
|
}
|
2016-09-02 09:12:47 +00:00
|
|
|
}
|
|
|
|
|
2016-09-07 23:21:59 +00:00
|
|
|
self.cx.current_expansion = orig_expansion_data;
|
2020-11-14 14:47:14 +03:00
|
|
|
self.cx.force_mode = orig_force_mode;
|
2016-09-07 23:21:59 +00:00
|
|
|
|
2018-06-23 19:27:01 +03:00
|
|
|
// Finally incorporate all the expanded macros into the input AST fragment.
|
2021-08-26 17:18:03 +03:00
|
|
|
let mut placeholder_expander = PlaceholderExpander::default();
|
2018-06-20 02:08:08 +03:00
|
|
|
while let Some(expanded_fragments) = expanded_fragments.pop() {
|
2019-08-17 20:49:00 +03:00
|
|
|
for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() {
|
|
|
|
placeholder_expander
|
|
|
|
.add(NodeId::placeholder_from_expn_id(expn_id), expanded_fragment);
|
2016-09-02 03:35:59 +00:00
|
|
|
}
|
|
|
|
}
|
Overhaul `syntax::fold::Folder`.
This commit changes `syntax::fold::Folder` from a functional style
(where most methods take a `T` and produce a new `T`) to a more
imperative style (where most methods take and modify a `&mut T`), and
renames it `syntax::mut_visit::MutVisitor`.
The first benefit is speed. The functional style does not require any
reallocations, due to the use of `P::map` and
`MoveMap::move_{,flat_}map`. However, every field in the AST must be
overwritten; even those fields that are unchanged are overwritten with
the same value. This causes a lot of unnecessary memory writes. The
imperative style reduces instruction counts by 1--3% across a wide range
of workloads, particularly incremental workloads.
The second benefit is conciseness; the imperative style is usually more
concise. E.g. compare the old functional style:
```
fn fold_abc(&mut self, abc: ABC) {
ABC {
a: fold_a(abc.a),
b: fold_b(abc.b),
c: abc.c,
}
}
```
with the imperative style:
```
fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
visit_a(a);
visit_b(b);
}
```
(The reductions get larger in more complex examples.)
Overall, the patch removes over 200 lines of code -- even though the new
code has more comments -- and a lot of the remaining lines have fewer
characters.
Some notes:
- The old style used methods called `fold_*`. The new style mostly uses
methods called `visit_*`, but there are a few methods that map a `T`
to something other than a `T`, which are called `flat_map_*` (`T` maps
to multiple `T`s) or `filter_map_*` (`T` maps to 0 or 1 `T`s).
- `move_map.rs`/`MoveMap`/`move_map`/`move_flat_map` are renamed
`map_in_place.rs`/`MapInPlace`/`map_in_place`/`flat_map_in_place` to
reflect their slightly changed signatures.
- Although this commit renames the `fold` module as `mut_visit`, it
keeps it in the `fold.rs` file, so as not to confuse git. The next
commit will rename the file.
2019-02-05 15:20:55 +11:00
|
|
|
fragment_with_placeholders.mut_visit_with(&mut placeholder_expander);
|
|
|
|
fragment_with_placeholders
|
2016-09-02 09:12:47 +00:00
|
|
|
}
|
|
|
|
|
2016-11-10 10:11:25 +00:00
|
|
|
fn resolve_imports(&mut self) {
|
|
|
|
if self.monotonic {
|
|
|
|
self.cx.resolver.resolve_imports();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Collects all macro invocations reachable at this time in this AST fragment, and replace
|
2018-06-23 19:27:01 +03:00
|
|
|
/// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s.
|
|
|
|
/// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and
|
|
|
|
/// prepares data for resolving paths of macro invocations.
|
2019-08-17 20:49:00 +03:00
|
|
|
fn collect_invocations(
|
|
|
|
&mut self,
|
|
|
|
mut fragment: AstFragment,
|
|
|
|
extra_placeholders: &[NodeId],
|
2025-02-03 06:44:41 +03:00
|
|
|
) -> (AstFragment, Vec<(Invocation, Option<Arc<SyntaxExtension>>)>) {
|
2019-01-26 16:29:34 +03:00
|
|
|
// Resolve `$crate`s in the fragment for pretty-printing.
|
2019-07-05 03:09:24 +03:00
|
|
|
self.cx.resolver.resolve_dollar_crates();
|
2019-01-26 16:29:34 +03:00
|
|
|
|
2021-05-02 21:19:28 +02:00
|
|
|
let mut invocations = {
|
2016-09-07 22:24:01 +00:00
|
|
|
let mut collector = InvocationCollector {
|
2020-11-28 18:33:17 -05:00
|
|
|
// Non-derive macro invocations cannot see the results of cfg expansion - they
|
|
|
|
// will either be removed along with the item, or invoked before the cfg/cfg_attr
|
|
|
|
// attribute is expanded. Therefore, we don't need to configure the tokens
|
|
|
|
// Derive macros *can* see the results of cfg-expansion - they are handled
|
|
|
|
// specially in `fully_expand_fragment`
|
2016-09-07 22:24:01 +00:00
|
|
|
cx: self.cx,
|
|
|
|
invocations: Vec::new(),
|
2016-09-06 05:42:45 +00:00
|
|
|
monotonic: self.monotonic,
|
2016-09-07 22:24:01 +00:00
|
|
|
};
|
Overhaul `syntax::fold::Folder`.
This commit changes `syntax::fold::Folder` from a functional style
(where most methods take a `T` and produce a new `T`) to a more
imperative style (where most methods take and modify a `&mut T`), and
renames it `syntax::mut_visit::MutVisitor`.
The first benefit is speed. The functional style does not require any
reallocations, due to the use of `P::map` and
`MoveMap::move_{,flat_}map`. However, every field in the AST must be
overwritten; even those fields that are unchanged are overwritten with
the same value. This causes a lot of unnecessary memory writes. The
imperative style reduces instruction counts by 1--3% across a wide range
of workloads, particularly incremental workloads.
The second benefit is conciseness; the imperative style is usually more
concise. E.g. compare the old functional style:
```
fn fold_abc(&mut self, abc: ABC) {
ABC {
a: fold_a(abc.a),
b: fold_b(abc.b),
c: abc.c,
}
}
```
with the imperative style:
```
fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
visit_a(a);
visit_b(b);
}
```
(The reductions get larger in more complex examples.)
Overall, the patch removes over 200 lines of code -- even though the new
code has more comments -- and a lot of the remaining lines have fewer
characters.
Some notes:
- The old style used methods called `fold_*`. The new style mostly uses
methods called `visit_*`, but there are a few methods that map a `T`
to something other than a `T`, which are called `flat_map_*` (`T` maps
to multiple `T`s) or `filter_map_*` (`T` maps to 0 or 1 `T`s).
- `move_map.rs`/`MoveMap`/`move_map`/`move_flat_map` are renamed
`map_in_place.rs`/`MapInPlace`/`map_in_place`/`flat_map_in_place` to
reflect their slightly changed signatures.
- Although this commit renames the `fold` module as `mut_visit`, it
keeps it in the `fold.rs` file, so as not to confuse git. The next
commit will rename the file.
2019-02-05 15:20:55 +11:00
|
|
|
fragment.mut_visit_with(&mut collector);
|
2019-10-10 01:41:47 +03:00
|
|
|
fragment.add_placeholders(extra_placeholders);
|
Overhaul `syntax::fold::Folder`.
This commit changes `syntax::fold::Folder` from a functional style
(where most methods take a `T` and produce a new `T`) to a more
imperative style (where most methods take and modify a `&mut T`), and
renames it `syntax::mut_visit::MutVisitor`.
The first benefit is speed. The functional style does not require any
reallocations, due to the use of `P::map` and
`MoveMap::move_{,flat_}map`. However, every field in the AST must be
overwritten; even those fields that are unchanged are overwritten with
the same value. This causes a lot of unnecessary memory writes. The
imperative style reduces instruction counts by 1--3% across a wide range
of workloads, particularly incremental workloads.
The second benefit is conciseness; the imperative style is usually more
concise. E.g. compare the old functional style:
```
fn fold_abc(&mut self, abc: ABC) {
ABC {
a: fold_a(abc.a),
b: fold_b(abc.b),
c: abc.c,
}
}
```
with the imperative style:
```
fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
visit_a(a);
visit_b(b);
}
```
(The reductions get larger in more complex examples.)
Overall, the patch removes over 200 lines of code -- even though the new
code has more comments -- and a lot of the remaining lines have fewer
characters.
Some notes:
- The old style used methods called `fold_*`. The new style mostly uses
methods called `visit_*`, but there are a few methods that map a `T`
to something other than a `T`, which are called `flat_map_*` (`T` maps
to multiple `T`s) or `filter_map_*` (`T` maps to 0 or 1 `T`s).
- `move_map.rs`/`MoveMap`/`move_map`/`move_flat_map` are renamed
`map_in_place.rs`/`MapInPlace`/`map_in_place`/`flat_map_in_place` to
reflect their slightly changed signatures.
- Although this commit renames the `fold` module as `mut_visit`, it
keeps it in the `fold.rs` file, so as not to confuse git. The next
commit will rename the file.
2019-02-05 15:20:55 +11:00
|
|
|
collector.invocations
|
2016-09-07 22:24:01 +00:00
|
|
|
};
|
2016-09-07 23:21:59 +00:00
|
|
|
|
2016-09-19 07:27:20 +00:00
|
|
|
if self.monotonic {
|
2018-12-16 20:23:27 +03:00
|
|
|
self.cx
|
|
|
|
.resolver
|
|
|
|
.visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment);
|
2021-05-02 21:19:28 +02:00
|
|
|
|
2023-09-07 20:13:57 +00:00
|
|
|
if self.cx.sess.opts.incremental.is_some() {
|
2021-05-02 21:19:28 +02:00
|
|
|
for (invoc, _) in invocations.iter_mut() {
|
|
|
|
let expn_id = invoc.expansion_data.id;
|
|
|
|
let parent_def = self.cx.resolver.invocation_parent(expn_id);
|
2024-05-01 10:57:08 +10:00
|
|
|
let span = invoc.span_mut();
|
2021-05-02 21:19:28 +02:00
|
|
|
*span = span.with_parent(Some(parent_def));
|
|
|
|
}
|
|
|
|
}
|
2016-09-19 07:27:20 +00:00
|
|
|
}
|
|
|
|
|
Overhaul `syntax::fold::Folder`.
This commit changes `syntax::fold::Folder` from a functional style
(where most methods take a `T` and produce a new `T`) to a more
imperative style (where most methods take and modify a `&mut T`), and
renames it `syntax::mut_visit::MutVisitor`.
The first benefit is speed. The functional style does not require any
reallocations, due to the use of `P::map` and
`MoveMap::move_{,flat_}map`. However, every field in the AST must be
overwritten; even those fields that are unchanged are overwritten with
the same value. This causes a lot of unnecessary memory writes. The
imperative style reduces instruction counts by 1--3% across a wide range
of workloads, particularly incremental workloads.
The second benefit is conciseness; the imperative style is usually more
concise. E.g. compare the old functional style:
```
fn fold_abc(&mut self, abc: ABC) {
ABC {
a: fold_a(abc.a),
b: fold_b(abc.b),
c: abc.c,
}
}
```
with the imperative style:
```
fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
visit_a(a);
visit_b(b);
}
```
(The reductions get larger in more complex examples.)
Overall, the patch removes over 200 lines of code -- even though the new
code has more comments -- and a lot of the remaining lines have fewer
characters.
Some notes:
- The old style used methods called `fold_*`. The new style mostly uses
methods called `visit_*`, but there are a few methods that map a `T`
to something other than a `T`, which are called `flat_map_*` (`T` maps
to multiple `T`s) or `filter_map_*` (`T` maps to 0 or 1 `T`s).
- `move_map.rs`/`MoveMap`/`move_map`/`move_flat_map` are renamed
`map_in_place.rs`/`MapInPlace`/`map_in_place`/`flat_map_in_place` to
reflect their slightly changed signatures.
- Although this commit renames the `fold` module as `mut_visit`, it
keeps it in the `fold.rs` file, so as not to confuse git. The next
commit will rename the file.
2019-02-05 15:20:55 +11:00
|
|
|
(fragment, invocations)
|
2016-05-16 10:09:23 +00:00
|
|
|
}
|
2016-06-12 01:50:52 +00:00
|
|
|
|
2024-02-25 22:22:11 +01:00
|
|
|
fn error_recursion_limit_reached(&mut self) -> ErrorGuaranteed {
|
2019-12-31 08:25:49 +01:00
|
|
|
let expn_data = self.cx.current_expansion.id.expn_data();
|
2021-09-28 22:16:42 +02:00
|
|
|
let suggested_limit = match self.cx.ecfg.recursion_limit {
|
|
|
|
Limit(0) => Limit(2),
|
|
|
|
limit => limit * 2,
|
|
|
|
};
|
2022-11-15 14:24:33 +01:00
|
|
|
|
2024-02-25 22:22:11 +01:00
|
|
|
let guar = self.cx.dcx().emit_err(RecursionLimitReached {
|
2022-11-15 14:24:33 +01:00
|
|
|
span: expn_data.call_site,
|
|
|
|
descr: expn_data.kind.descr(),
|
|
|
|
suggested_limit,
|
|
|
|
crate_name: &self.cx.ecfg.crate_name,
|
|
|
|
});
|
|
|
|
|
2019-12-31 08:25:49 +01:00
|
|
|
self.cx.trace_macros_diag();
|
2024-02-25 22:22:11 +01:00
|
|
|
guar
|
2019-12-31 08:25:49 +01:00
|
|
|
}
|
|
|
|
|
2019-12-31 08:43:33 +01:00
|
|
|
/// A macro's expansion does not fit in this fragment kind.
|
|
|
|
/// For example, a non-type macro in a type position.
|
2024-02-25 22:22:11 +01:00
|
|
|
fn error_wrong_fragment_kind(
|
|
|
|
&mut self,
|
|
|
|
kind: AstFragmentKind,
|
|
|
|
mac: &ast::MacCall,
|
|
|
|
span: Span,
|
|
|
|
) -> ErrorGuaranteed {
|
|
|
|
let guar =
|
|
|
|
self.cx.dcx().emit_err(WrongFragmentKind { span, kind: kind.name(), name: &mac.path });
|
2019-12-31 08:43:33 +01:00
|
|
|
self.cx.trace_macros_diag();
|
2024-02-25 22:22:11 +01:00
|
|
|
guar
|
2019-12-31 08:43:33 +01:00
|
|
|
}
|
|
|
|
|
2020-03-09 20:50:12 +03:00
|
|
|
fn expand_invoc(
|
|
|
|
&mut self,
|
|
|
|
invoc: Invocation,
|
|
|
|
ext: &SyntaxExtensionKind,
|
|
|
|
) -> ExpandResult<AstFragment, Invocation> {
|
2024-02-25 22:22:11 +01:00
|
|
|
let recursion_limit = match self.cx.reduced_recursion_limit {
|
|
|
|
Some((limit, _)) => limit,
|
|
|
|
None => self.cx.ecfg.recursion_limit,
|
|
|
|
};
|
|
|
|
|
2020-05-26 19:48:08 +01:00
|
|
|
if !recursion_limit.value_within_limit(self.cx.current_expansion.depth) {
|
2024-02-25 22:22:11 +01:00
|
|
|
let guar = match self.cx.reduced_recursion_limit {
|
|
|
|
Some((_, guar)) => guar,
|
|
|
|
None => self.error_recursion_limit_reached(),
|
|
|
|
};
|
2020-02-26 23:43:49 +01:00
|
|
|
|
|
|
|
// Reduce the recursion limit by half each time it triggers.
|
2024-02-25 22:22:11 +01:00
|
|
|
self.cx.reduced_recursion_limit = Some((recursion_limit / 2, guar));
|
2020-02-26 23:43:49 +01:00
|
|
|
|
2024-02-25 22:22:11 +01:00
|
|
|
return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span(), guar));
|
2016-09-01 07:01:45 +00:00
|
|
|
}
|
2017-03-17 04:04:41 +00:00
|
|
|
|
2019-08-27 02:07:26 +03:00
|
|
|
let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
|
2020-03-09 20:50:12 +03:00
|
|
|
ExpandResult::Ready(match invoc.kind {
|
2024-03-12 10:55:17 +08:00
|
|
|
InvocationKind::Bang { mac, span } => match ext {
|
2019-07-07 18:55:29 +03:00
|
|
|
SyntaxExtensionKind::Bang(expander) => {
|
2024-02-25 22:22:11 +01:00
|
|
|
match expander.expand(self.cx, span, mac.args.tokens.clone()) {
|
|
|
|
Ok(tok_result) => {
|
|
|
|
self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span)
|
|
|
|
}
|
|
|
|
Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
|
|
|
|
}
|
2019-07-07 18:55:29 +03:00
|
|
|
}
|
|
|
|
SyntaxExtensionKind::LegacyBang(expander) => {
|
2024-03-12 10:55:17 +08:00
|
|
|
let tok_result = match expander.expand(self.cx, span, mac.args.tokens.clone()) {
|
|
|
|
ExpandResult::Ready(tok_result) => tok_result,
|
|
|
|
ExpandResult::Retry(_) => {
|
|
|
|
// retry the original
|
|
|
|
return ExpandResult::Retry(Invocation {
|
|
|
|
kind: InvocationKind::Bang { mac, span },
|
|
|
|
..invoc
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
2019-07-18 18:36:19 -07:00
|
|
|
let result = if let Some(result) = fragment_kind.make_from(tok_result) {
|
2019-07-07 18:55:29 +03:00
|
|
|
result
|
|
|
|
} else {
|
2024-02-25 22:22:11 +01:00
|
|
|
let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span);
|
|
|
|
fragment_kind.dummy(span, guar)
|
2019-07-18 18:36:19 -07:00
|
|
|
};
|
|
|
|
result
|
2019-06-16 18:58:39 +03:00
|
|
|
}
|
2019-07-07 18:55:29 +03:00
|
|
|
_ => unreachable!(),
|
2018-07-23 02:52:51 +03:00
|
|
|
},
|
2021-02-23 00:54:09 +03:00
|
|
|
InvocationKind::Attr { attr, pos, mut item, derives } => match ext {
|
2019-07-07 18:55:29 +03:00
|
|
|
SyntaxExtensionKind::Attr(expander) => {
|
2019-09-08 01:42:12 +03:00
|
|
|
self.gate_proc_macro_input(&item);
|
2019-07-07 18:55:29 +03:00
|
|
|
self.gate_proc_macro_attr_item(span, &item);
|
2021-10-17 19:32:34 +03:00
|
|
|
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.
|
2024-03-04 16:31:49 +11:00
|
|
|
Annotatable::Crate(krate) => {
|
|
|
|
rustc_parse::fake_token_stream_for_crate(&self.cx.sess.psess, krate)
|
|
|
|
}
|
2021-10-17 19:32:34 +03:00
|
|
|
Annotatable::Item(item_inner)
|
2022-01-07 14:54:16 +08:00
|
|
|
if matches!(attr.style, AttrStyle::Inner)
|
2021-10-17 19:32:34 +03:00
|
|
|
&& matches!(
|
|
|
|
item_inner.kind,
|
|
|
|
ItemKind::Mod(
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
_,
|
2021-10-17 19:32:34 +03:00
|
|
|
_,
|
2024-12-05 21:19:08 +00:00
|
|
|
ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _, _),
|
2021-10-17 19:32:34 +03:00
|
|
|
)
|
|
|
|
) =>
|
|
|
|
{
|
2024-03-04 16:31:49 +11:00
|
|
|
rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)
|
2021-10-17 19:32:34 +03:00
|
|
|
}
|
2022-05-21 15:50:39 +03:00
|
|
|
_ => item.to_tokens(),
|
2020-11-23 01:43:55 -05:00
|
|
|
};
|
2020-03-03 23:22:32 +03:00
|
|
|
let attr_item = attr.unwrap_normal_item();
|
2024-12-02 10:06:26 +00:00
|
|
|
if let AttrArgs::Eq { .. } = attr_item.args {
|
2023-12-18 20:54:03 +11:00
|
|
|
self.cx.dcx().emit_err(UnsupportedKeyValue { span });
|
2019-12-01 17:07:38 +03:00
|
|
|
}
|
2020-03-17 10:56:00 +01:00
|
|
|
let inner_tokens = attr_item.args.inner_tokens();
|
2024-02-25 22:22:11 +01:00
|
|
|
match expander.expand(self.cx, span, inner_tokens, tokens) {
|
|
|
|
Ok(tok_result) => self.parse_ast_fragment(
|
|
|
|
tok_result,
|
|
|
|
fragment_kind,
|
|
|
|
&attr_item.path,
|
|
|
|
span,
|
|
|
|
),
|
|
|
|
Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
|
|
|
|
}
|
2019-07-07 18:55:29 +03:00
|
|
|
}
|
|
|
|
SyntaxExtensionKind::LegacyAttr(expander) => {
|
2024-03-04 16:31:49 +11:00
|
|
|
match validate_attr::parse_meta(&self.cx.sess.psess, &attr) {
|
2019-07-07 18:55:29 +03:00
|
|
|
Ok(meta) => {
|
2022-09-20 11:55:07 +00:00
|
|
|
let items = match expander.expand(self.cx, span, &meta, item, false) {
|
2020-03-09 20:50:12 +03:00
|
|
|
ExpandResult::Ready(items) => items,
|
2020-11-14 14:47:14 +03:00
|
|
|
ExpandResult::Retry(item) => {
|
2020-03-09 20:50:12 +03:00
|
|
|
// Reassemble the original invocation for retrying.
|
2020-11-14 14:47:14 +03:00
|
|
|
return ExpandResult::Retry(Invocation {
|
2021-02-23 00:54:09 +03:00
|
|
|
kind: InvocationKind::Attr { attr, pos, item, derives },
|
2020-11-14 14:47:14 +03:00
|
|
|
..invoc
|
|
|
|
});
|
2020-03-09 20:50:12 +03:00
|
|
|
}
|
|
|
|
};
|
2023-05-19 21:21:05 +08:00
|
|
|
if matches!(
|
|
|
|
fragment_kind,
|
|
|
|
AstFragmentKind::Expr | AstFragmentKind::MethodReceiverExpr
|
|
|
|
) && items.is_empty()
|
|
|
|
{
|
2024-02-25 22:22:11 +01:00
|
|
|
let guar = self.cx.dcx().emit_err(RemoveExprNotSupported { span });
|
|
|
|
fragment_kind.dummy(span, guar)
|
2021-04-03 18:46:25 +03:00
|
|
|
} else {
|
|
|
|
fragment_kind.expect_from_annotatables(items)
|
|
|
|
}
|
2019-07-07 18:55:29 +03:00
|
|
|
}
|
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 12:17:35 +11:00
|
|
|
Err(err) => {
|
2025-02-25 10:22:19 +00:00
|
|
|
let _guar = err.emit();
|
|
|
|
fragment_kind.expect_from_annotatables(iter::once(item))
|
2019-07-07 18:55:29 +03:00
|
|
|
}
|
2019-07-07 18:29:22 +03:00
|
|
|
}
|
2019-07-07 18:55:29 +03:00
|
|
|
}
|
2021-08-05 17:58:59 -05:00
|
|
|
SyntaxExtensionKind::NonMacroAttr => {
|
2021-07-22 17:40:01 -05:00
|
|
|
self.cx.expanded_inert_attrs.mark(&attr);
|
2021-02-23 00:54:09 +03:00
|
|
|
item.visit_attrs(|attrs| attrs.insert(pos, attr));
|
2019-07-07 18:55:29 +03:00
|
|
|
fragment_kind.expect_from_annotatables(iter::once(item))
|
2019-07-07 18:29:22 +03:00
|
|
|
}
|
2019-07-07 18:55:29 +03:00
|
|
|
_ => unreachable!(),
|
2016-09-01 07:01:45 +00:00
|
|
|
},
|
2022-09-20 11:55:07 +00:00
|
|
|
InvocationKind::Derive { path, item, is_const } => match ext {
|
2019-07-07 18:55:29 +03:00
|
|
|
SyntaxExtensionKind::Derive(expander)
|
|
|
|
| SyntaxExtensionKind::LegacyDerive(expander) => {
|
2019-09-08 01:42:12 +03:00
|
|
|
if let SyntaxExtensionKind::Derive(..) = ext {
|
|
|
|
self.gate_proc_macro_input(&item);
|
|
|
|
}
|
2024-04-23 07:50:53 -05:00
|
|
|
// The `MetaItem` representing the trait to derive can't
|
|
|
|
// have an unsafe around it (as of now).
|
2024-04-20 23:54:50 -05:00
|
|
|
let meta = ast::MetaItem {
|
2024-05-21 08:37:05 -05:00
|
|
|
unsafety: ast::Safety::Default,
|
2024-04-20 23:54:50 -05:00
|
|
|
kind: MetaItemKind::Word,
|
|
|
|
span,
|
|
|
|
path,
|
|
|
|
};
|
2022-09-20 11:55:07 +00:00
|
|
|
let items = match expander.expand(self.cx, span, &meta, item, is_const) {
|
2020-03-09 20:50:12 +03:00
|
|
|
ExpandResult::Ready(items) => items,
|
2020-11-14 14:47:14 +03:00
|
|
|
ExpandResult::Retry(item) => {
|
2020-03-09 20:50:12 +03:00
|
|
|
// Reassemble the original invocation for retrying.
|
2020-11-14 14:47:14 +03:00
|
|
|
return ExpandResult::Retry(Invocation {
|
2022-09-20 11:55:07 +00:00
|
|
|
kind: InvocationKind::Derive { path: meta.path, item, is_const },
|
2020-11-14 14:47:14 +03:00
|
|
|
..invoc
|
|
|
|
});
|
2020-03-09 20:50:12 +03:00
|
|
|
}
|
|
|
|
};
|
2019-07-07 18:55:29 +03:00
|
|
|
fragment_kind.expect_from_annotatables(items)
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
2016-08-29 16:16:43 +12:00
|
|
|
},
|
2025-03-25 09:00:35 +00:00
|
|
|
InvocationKind::GlobDelegation { item, of_trait } => {
|
2024-03-15 14:21:03 +03:00
|
|
|
let AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() };
|
|
|
|
let suffixes = match ext {
|
|
|
|
SyntaxExtensionKind::GlobDelegation(expander) => match expander.expand(self.cx)
|
|
|
|
{
|
|
|
|
ExpandResult::Ready(suffixes) => suffixes,
|
|
|
|
ExpandResult::Retry(()) => {
|
|
|
|
// Reassemble the original invocation for retrying.
|
|
|
|
return ExpandResult::Retry(Invocation {
|
2025-03-25 09:00:35 +00:00
|
|
|
kind: InvocationKind::GlobDelegation { item, of_trait },
|
2024-03-15 14:21:03 +03:00
|
|
|
..invoc
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
SyntaxExtensionKind::LegacyBang(..) => {
|
|
|
|
let msg = "expanded a dummy glob delegation";
|
|
|
|
let guar = self.cx.dcx().span_delayed_bug(span, msg);
|
|
|
|
return ExpandResult::Ready(fragment_kind.dummy(span, guar));
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
|
|
|
|
type Node = AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>;
|
|
|
|
let single_delegations = build_single_delegations::<Node>(
|
|
|
|
self.cx, deleg, &item, &suffixes, item.span, true,
|
|
|
|
);
|
|
|
|
fragment_kind.expect_from_annotatables(
|
2025-03-25 09:00:35 +00:00
|
|
|
single_delegations
|
|
|
|
.map(|item| Annotatable::AssocItem(P(item), AssocCtxt::Impl { of_trait })),
|
2024-03-15 14:21:03 +03:00
|
|
|
)
|
|
|
|
}
|
2020-03-09 20:50:12 +03:00
|
|
|
})
|
2016-09-01 07:01:45 +00:00
|
|
|
}
|
|
|
|
|
2024-02-20 14:12:50 +11:00
|
|
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
rustc: Tweak custom attribute capabilities
This commit starts to lay some groundwork for the stabilization of custom
attribute invocations and general procedural macros. It applies a number of
changes discussed on [internals] as well as a [recent issue][issue], namely:
* The path used to specify a custom attribute must be of length one and cannot
be a global path. This'll help future-proof us against any ambiguities and
give us more time to settle the precise syntax. In the meantime though a bare
identifier can be used and imported to invoke a custom attribute macro. A new
feature gate, `proc_macro_path_invoc`, was added to gate multi-segment paths
and absolute paths.
* The set of items which can be annotated by a custom procedural attribute has
been restricted. Statements, expressions, and modules are disallowed behind
two new feature gates: `proc_macro_expr` and `proc_macro_mod`.
* The input to procedural macro attributes has been restricted and adjusted.
Today an invocation like `#[foo(bar)]` will receive `(bar)` as the input token
stream, but after this PR it will only receive `bar` (the delimiters were
removed). Invocations like `#[foo]` are still allowed and will be invoked in
the same way as `#[foo()]`. This is a **breaking change** for all nightly
users as the syntax coming in to procedural macros will be tweaked slightly.
* Procedural macros (`foo!()` style) can only be expanded to item-like items by
default. A separate feature gate, `proc_macro_non_items`, is required to
expand to items like expressions, statements, etc.
Closes #50038
[internals]: https://internals.rust-lang.org/t/help-stabilize-a-subset-of-macros-2-0/7252
[issue]: https://github.com/rust-lang/rust/issues/50038
2018-04-20 07:50:39 -07:00
|
|
|
fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
|
2019-09-08 01:42:12 +03:00
|
|
|
let kind = match item {
|
2019-09-08 01:42:12 +03:00
|
|
|
Annotatable::Item(_)
|
2024-07-08 10:40:37 +00:00
|
|
|
| Annotatable::AssocItem(..)
|
2021-10-17 19:32:34 +03:00
|
|
|
| Annotatable::ForeignItem(_)
|
|
|
|
| Annotatable::Crate(..) => return,
|
2020-11-24 14:47:49 -05:00
|
|
|
Annotatable::Stmt(stmt) => {
|
|
|
|
// Attributes are stable on item statements,
|
|
|
|
// but unstable on all other kinds of statements
|
|
|
|
if stmt.is_item() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
"statements"
|
|
|
|
}
|
2019-09-08 01:42:12 +03:00
|
|
|
Annotatable::Expr(_) => "expressions",
|
2019-09-09 09:26:25 -03:00
|
|
|
Annotatable::Arm(..)
|
2021-03-16 00:36:07 +03:00
|
|
|
| Annotatable::ExprField(..)
|
|
|
|
| Annotatable::PatField(..)
|
2019-09-09 09:26:25 -03:00
|
|
|
| Annotatable::GenericParam(..)
|
|
|
|
| Annotatable::Param(..)
|
2021-03-16 00:36:07 +03:00
|
|
|
| Annotatable::FieldDef(..)
|
2025-02-05 18:58:29 +08:00
|
|
|
| Annotatable::Variant(..)
|
|
|
|
| Annotatable::WherePredicate(..) => panic!("unexpected annotatable"),
|
rustc: Tweak custom attribute capabilities
This commit starts to lay some groundwork for the stabilization of custom
attribute invocations and general procedural macros. It applies a number of
changes discussed on [internals] as well as a [recent issue][issue], namely:
* The path used to specify a custom attribute must be of length one and cannot
be a global path. This'll help future-proof us against any ambiguities and
give us more time to settle the precise syntax. In the meantime though a bare
identifier can be used and imported to invoke a custom attribute macro. A new
feature gate, `proc_macro_path_invoc`, was added to gate multi-segment paths
and absolute paths.
* The set of items which can be annotated by a custom procedural attribute has
been restricted. Statements, expressions, and modules are disallowed behind
two new feature gates: `proc_macro_expr` and `proc_macro_mod`.
* The input to procedural macro attributes has been restricted and adjusted.
Today an invocation like `#[foo(bar)]` will receive `(bar)` as the input token
stream, but after this PR it will only receive `bar` (the delimiters were
removed). Invocations like `#[foo]` are still allowed and will be invoked in
the same way as `#[foo()]`. This is a **breaking change** for all nightly
users as the syntax coming in to procedural macros will be tweaked slightly.
* Procedural macros (`foo!()` style) can only be expanded to item-like items by
default. A separate feature gate, `proc_macro_non_items`, is required to
expand to items like expressions, statements, etc.
Closes #50038
[internals]: https://internals.rust-lang.org/t/help-stabilize-a-subset-of-macros-2-0/7252
[issue]: https://github.com/rust-lang/rust/issues/50038
2018-04-20 07:50:39 -07:00
|
|
|
};
|
2024-10-09 09:01:57 +02:00
|
|
|
if self.cx.ecfg.features.proc_macro_hygiene() {
|
2019-09-08 01:42:12 +03:00
|
|
|
return;
|
|
|
|
}
|
2019-11-30 07:40:28 +01:00
|
|
|
feature_err(
|
2024-01-10 00:37:30 -05:00
|
|
|
&self.cx.sess,
|
2019-09-08 01:42:12 +03:00
|
|
|
sym::proc_macro_hygiene,
|
rustc: Tweak custom attribute capabilities
This commit starts to lay some groundwork for the stabilization of custom
attribute invocations and general procedural macros. It applies a number of
changes discussed on [internals] as well as a [recent issue][issue], namely:
* The path used to specify a custom attribute must be of length one and cannot
be a global path. This'll help future-proof us against any ambiguities and
give us more time to settle the precise syntax. In the meantime though a bare
identifier can be used and imported to invoke a custom attribute macro. A new
feature gate, `proc_macro_path_invoc`, was added to gate multi-segment paths
and absolute paths.
* The set of items which can be annotated by a custom procedural attribute has
been restricted. Statements, expressions, and modules are disallowed behind
two new feature gates: `proc_macro_expr` and `proc_macro_mod`.
* The input to procedural macro attributes has been restricted and adjusted.
Today an invocation like `#[foo(bar)]` will receive `(bar)` as the input token
stream, but after this PR it will only receive `bar` (the delimiters were
removed). Invocations like `#[foo]` are still allowed and will be invoked in
the same way as `#[foo()]`. This is a **breaking change** for all nightly
users as the syntax coming in to procedural macros will be tweaked slightly.
* Procedural macros (`foo!()` style) can only be expanded to item-like items by
default. A separate feature gate, `proc_macro_non_items`, is required to
expand to items like expressions, statements, etc.
Closes #50038
[internals]: https://internals.rust-lang.org/t/help-stabilize-a-subset-of-macros-2-0/7252
[issue]: https://github.com/rust-lang/rust/issues/50038
2018-04-20 07:50:39 -07:00
|
|
|
span,
|
2023-07-25 22:00:13 +02:00
|
|
|
format!("custom attributes cannot be applied to {kind}"),
|
2019-11-30 07:40:28 +01:00
|
|
|
)
|
|
|
|
.emit();
|
rustc: Tweak custom attribute capabilities
This commit starts to lay some groundwork for the stabilization of custom
attribute invocations and general procedural macros. It applies a number of
changes discussed on [internals] as well as a [recent issue][issue], namely:
* The path used to specify a custom attribute must be of length one and cannot
be a global path. This'll help future-proof us against any ambiguities and
give us more time to settle the precise syntax. In the meantime though a bare
identifier can be used and imported to invoke a custom attribute macro. A new
feature gate, `proc_macro_path_invoc`, was added to gate multi-segment paths
and absolute paths.
* The set of items which can be annotated by a custom procedural attribute has
been restricted. Statements, expressions, and modules are disallowed behind
two new feature gates: `proc_macro_expr` and `proc_macro_mod`.
* The input to procedural macro attributes has been restricted and adjusted.
Today an invocation like `#[foo(bar)]` will receive `(bar)` as the input token
stream, but after this PR it will only receive `bar` (the delimiters were
removed). Invocations like `#[foo]` are still allowed and will be invoked in
the same way as `#[foo()]`. This is a **breaking change** for all nightly
users as the syntax coming in to procedural macros will be tweaked slightly.
* Procedural macros (`foo!()` style) can only be expanded to item-like items by
default. A separate feature gate, `proc_macro_non_items`, is required to
expand to items like expressions, statements, etc.
Closes #50038
[internals]: https://internals.rust-lang.org/t/help-stabilize-a-subset-of-macros-2-0/7252
[issue]: https://github.com/rust-lang/rust/issues/50038
2018-04-20 07:50:39 -07:00
|
|
|
}
|
|
|
|
|
2019-09-08 01:42:12 +03:00
|
|
|
fn gate_proc_macro_input(&self, annotatable: &Annotatable) {
|
|
|
|
struct GateProcMacroInput<'a> {
|
2024-01-10 00:37:30 -05:00
|
|
|
sess: &'a Session,
|
2019-09-08 01:42:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {
|
|
|
|
fn visit_item(&mut self, item: &'ast ast::Item) {
|
|
|
|
match &item.kind {
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ItemKind::Mod(_, _, mod_kind)
|
2024-12-05 21:19:08 +00:00
|
|
|
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) =>
|
2021-02-17 00:56:07 +03:00
|
|
|
{
|
2019-11-30 07:40:28 +01:00
|
|
|
feature_err(
|
2024-01-10 00:37:30 -05:00
|
|
|
self.sess,
|
2019-09-08 01:42:12 +03:00
|
|
|
sym::proc_macro_hygiene,
|
|
|
|
item.span,
|
2024-08-09 00:53:15 +03:00
|
|
|
fluent_generated::expand_non_inline_modules_in_proc_macro_input_are_unstable,
|
2019-11-30 07:40:28 +01:00
|
|
|
)
|
|
|
|
.emit();
|
2019-09-08 01:42:12 +03:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
visit::walk_item(self, item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-09 09:01:57 +02:00
|
|
|
if !self.cx.ecfg.features.proc_macro_hygiene() {
|
2024-01-10 00:37:30 -05:00
|
|
|
annotatable.visit_with(&mut GateProcMacroInput { sess: &self.cx.sess });
|
2019-09-08 01:42:12 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-08 18:24:00 -07:00
|
|
|
fn parse_ast_fragment(
|
|
|
|
&mut self,
|
|
|
|
toks: TokenStream,
|
|
|
|
kind: AstFragmentKind,
|
2022-01-07 14:54:16 +08:00
|
|
|
path: &ast::Path,
|
2019-08-08 18:24:00 -07:00
|
|
|
span: Span,
|
|
|
|
) -> AstFragment {
|
2019-08-31 20:08:06 +03:00
|
|
|
let mut parser = self.cx.new_parser_from_tts(toks);
|
2019-12-03 18:47:44 +01:00
|
|
|
match parse_ast_fragment(&mut parser, kind) {
|
2018-06-20 02:08:08 +03:00
|
|
|
Ok(fragment) => {
|
compiler: fix few needless_pass_by_ref_mut clippy lints
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_session\src\config.rs:2013:16
|
2013 | early_dcx: &mut EarlyDiagCtxt,
| ^^^^^^^^^^^^^^^^^^ help: consider changing to: `&EarlyDiagCtxt`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_ast_passes\src\ast_validation.rs:1555:11
|
1555 | this: &mut AstValidator<'_>,
| ^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&AstValidator<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_infer\src\infer\snapshot\fudge.rs:16:12
|
16 | table: &mut UnificationTable<'_, 'tcx, T>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&UnificationTable<'_, 'tcx, T>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_expand\src\expand.rs:961:13
|
961 | parser: &mut Parser<'a>,
| ^^^^^^^^^^^^^^^ help: consider changing to: `&Parser<'a>`
|
= warning: changing this function will impact semver compatibility
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
2024-03-28 11:30:49 +03:00
|
|
|
ensure_complete_parse(&parser, path, kind.name(), span);
|
2019-07-07 18:29:22 +03:00
|
|
|
fragment
|
2017-12-26 16:47:32 +09:00
|
|
|
}
|
2016-09-26 04:16:55 +00:00
|
|
|
Err(mut err) => {
|
2021-01-31 15:21:28 -05:00
|
|
|
if err.span.is_dummy() {
|
2023-12-24 09:08:41 +11:00
|
|
|
err.span(span);
|
2021-01-31 15:21:28 -05:00
|
|
|
}
|
2019-08-09 09:39:30 -07:00
|
|
|
annotate_err_with_kind(&mut err, kind, span);
|
2024-02-25 22:22:11 +01:00
|
|
|
let guar = err.emit();
|
2017-09-02 18:13:25 +02:00
|
|
|
self.cx.trace_macros_diag();
|
2024-02-25 22:22:11 +01:00
|
|
|
kind.dummy(span, guar)
|
2016-09-26 04:16:55 +00:00
|
|
|
}
|
2017-12-26 16:47:32 +09:00
|
|
|
}
|
2016-09-26 04:16:55 +00:00
|
|
|
}
|
2016-09-02 09:12:47 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 10:59:30 +02:00
|
|
|
pub fn parse_ast_fragment<'a>(
|
|
|
|
this: &mut Parser<'a>,
|
|
|
|
kind: AstFragmentKind,
|
|
|
|
) -> PResult<'a, AstFragment> {
|
|
|
|
Ok(match kind {
|
|
|
|
AstFragmentKind::Items => {
|
|
|
|
let mut items = SmallVec::new();
|
2021-01-18 16:47:37 -05:00
|
|
|
while let Some(item) = this.parse_item(ForceCollect::No)? {
|
2019-10-16 10:59:30 +02:00
|
|
|
items.push(item);
|
|
|
|
}
|
|
|
|
AstFragment::Items(items)
|
|
|
|
}
|
|
|
|
AstFragmentKind::TraitItems => {
|
|
|
|
let mut items = SmallVec::new();
|
2020-11-28 18:33:17 -05:00
|
|
|
while let Some(item) = this.parse_trait_item(ForceCollect::No)? {
|
2020-02-22 08:16:39 +01:00
|
|
|
items.extend(item);
|
2016-09-23 09:32:58 +00:00
|
|
|
}
|
2019-10-16 10:59:30 +02:00
|
|
|
AstFragment::TraitItems(items)
|
|
|
|
}
|
|
|
|
AstFragmentKind::ImplItems => {
|
|
|
|
let mut items = SmallVec::new();
|
2020-11-28 18:33:17 -05:00
|
|
|
while let Some(item) = this.parse_impl_item(ForceCollect::No)? {
|
2020-02-22 08:16:39 +01:00
|
|
|
items.extend(item);
|
2016-09-23 09:32:58 +00:00
|
|
|
}
|
2019-10-16 10:59:30 +02:00
|
|
|
AstFragment::ImplItems(items)
|
|
|
|
}
|
2025-03-25 09:00:35 +00:00
|
|
|
AstFragmentKind::TraitImplItems => {
|
|
|
|
let mut items = SmallVec::new();
|
|
|
|
while let Some(item) = this.parse_impl_item(ForceCollect::No)? {
|
|
|
|
items.extend(item);
|
|
|
|
}
|
|
|
|
AstFragment::TraitImplItems(items)
|
|
|
|
}
|
2019-10-16 10:59:30 +02:00
|
|
|
AstFragmentKind::ForeignItems => {
|
|
|
|
let mut items = SmallVec::new();
|
2020-11-28 18:33:17 -05:00
|
|
|
while let Some(item) = this.parse_foreign_item(ForceCollect::No)? {
|
2020-02-22 06:57:31 +01:00
|
|
|
items.extend(item);
|
2016-09-23 09:32:58 +00:00
|
|
|
}
|
2019-10-16 10:59:30 +02:00
|
|
|
AstFragment::ForeignItems(items)
|
|
|
|
}
|
|
|
|
AstFragmentKind::Stmts => {
|
|
|
|
let mut stmts = SmallVec::new();
|
2019-12-03 18:47:44 +01:00
|
|
|
// Won't make progress on a `}`.
|
2022-04-26 15:40:14 +03:00
|
|
|
while this.token != token::Eof && this.token != token::CloseDelim(Delimiter::Brace) {
|
2020-08-12 15:39:15 -07:00
|
|
|
if let Some(stmt) = this.parse_full_stmt(AttemptLocalParseRecovery::Yes)? {
|
2019-10-16 10:59:30 +02:00
|
|
|
stmts.push(stmt);
|
2018-10-23 10:07:34 -07:00
|
|
|
}
|
|
|
|
}
|
2019-10-16 10:59:30 +02:00
|
|
|
AstFragment::Stmts(stmts)
|
|
|
|
}
|
|
|
|
AstFragmentKind::Expr => AstFragment::Expr(this.parse_expr()?),
|
2022-10-23 09:22:19 +00:00
|
|
|
AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(this.parse_expr()?),
|
2019-10-16 10:59:30 +02:00
|
|
|
AstFragmentKind::OptExpr => {
|
|
|
|
if this.token != token::Eof {
|
|
|
|
AstFragment::OptExpr(Some(this.parse_expr()?))
|
|
|
|
} else {
|
|
|
|
AstFragment::OptExpr(None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AstFragmentKind::Ty => AstFragment::Ty(this.parse_ty()?),
|
2024-11-24 17:36:52 +01:00
|
|
|
AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat_allow_top_guard(
|
2021-07-13 13:18:03 +02:00
|
|
|
None,
|
|
|
|
RecoverComma::No,
|
|
|
|
RecoverColon::Yes,
|
2022-01-12 20:43:24 +00:00
|
|
|
CommaRecoveryMode::LikelyTuple,
|
2021-07-13 13:18:03 +02:00
|
|
|
)?),
|
2021-10-17 19:32:34 +03:00
|
|
|
AstFragmentKind::Crate => AstFragment::Crate(this.parse_crate_mod()?),
|
2019-10-16 10:59:30 +02:00
|
|
|
AstFragmentKind::Arms
|
2022-01-05 13:56:45 +08:00
|
|
|
| AstFragmentKind::ExprFields
|
|
|
|
| AstFragmentKind::PatFields
|
2019-10-16 10:59:30 +02:00
|
|
|
| AstFragmentKind::GenericParams
|
|
|
|
| AstFragmentKind::Params
|
2022-01-05 13:56:45 +08:00
|
|
|
| AstFragmentKind::FieldDefs
|
2025-02-05 18:58:29 +08:00
|
|
|
| AstFragmentKind::Variants
|
|
|
|
| AstFragmentKind::WherePredicates => panic!("unexpected AST fragment kind"),
|
2019-10-16 10:59:30 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-05-01 09:39:07 +10:00
|
|
|
pub(crate) fn ensure_complete_parse<'a>(
|
compiler: fix few needless_pass_by_ref_mut clippy lints
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_session\src\config.rs:2013:16
|
2013 | early_dcx: &mut EarlyDiagCtxt,
| ^^^^^^^^^^^^^^^^^^ help: consider changing to: `&EarlyDiagCtxt`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_ast_passes\src\ast_validation.rs:1555:11
|
1555 | this: &mut AstValidator<'_>,
| ^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&AstValidator<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_infer\src\infer\snapshot\fudge.rs:16:12
|
16 | table: &mut UnificationTable<'_, 'tcx, T>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&UnificationTable<'_, 'tcx, T>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_expand\src\expand.rs:961:13
|
961 | parser: &mut Parser<'a>,
| ^^^^^^^^^^^^^^^ help: consider changing to: `&Parser<'a>`
|
= warning: changing this function will impact semver compatibility
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
2024-03-28 11:30:49 +03:00
|
|
|
parser: &Parser<'a>,
|
2022-01-07 14:54:16 +08:00
|
|
|
macro_path: &ast::Path,
|
2019-10-16 10:59:30 +02:00
|
|
|
kind_name: &str,
|
|
|
|
span: Span,
|
|
|
|
) {
|
2022-11-15 14:24:33 +01:00
|
|
|
if parser.token != token::Eof {
|
2024-04-17 17:08:58 +10:00
|
|
|
let descr = token_descr(&parser.token);
|
2019-10-16 10:59:30 +02:00
|
|
|
// Avoid emitting backtrace info twice.
|
2022-11-15 14:24:33 +01:00
|
|
|
let def_site_span = parser.token.span.with_ctxt(SyntaxContext::root());
|
2019-10-16 10:59:30 +02:00
|
|
|
|
2024-03-04 16:31:49 +11:00
|
|
|
let semi_span = parser.psess.source_map().next_point(span);
|
|
|
|
let add_semicolon = match &parser.psess.source_map().span_to_snippet(semi_span) {
|
2022-12-23 17:34:23 +00:00
|
|
|
Ok(snippet) if &snippet[..] != ";" && kind_name == "expression" => {
|
2022-11-15 14:24:33 +01:00
|
|
|
Some(span.shrink_to_hi())
|
2019-10-16 10:59:30 +02:00
|
|
|
}
|
2022-11-15 14:24:33 +01:00
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
|
2023-11-27 00:50:51 +01:00
|
|
|
let expands_to_match_arm = kind_name == "pattern" && parser.token == token::FatArrow;
|
|
|
|
|
2023-12-18 21:14:02 +11:00
|
|
|
parser.dcx().emit_err(IncompleteParse {
|
2022-11-15 14:24:33 +01:00
|
|
|
span: def_site_span,
|
2024-04-17 17:08:58 +10:00
|
|
|
descr,
|
2022-11-15 14:24:33 +01:00
|
|
|
label_span: span,
|
|
|
|
macro_path,
|
|
|
|
kind_name,
|
2024-08-21 00:57:58 -04:00
|
|
|
expands_to_match_arm,
|
2022-11-15 14:24:33 +01:00
|
|
|
add_semicolon,
|
|
|
|
});
|
2016-09-26 11:24:10 +00:00
|
|
|
}
|
2016-09-02 09:12:47 +00:00
|
|
|
}
|
|
|
|
|
2024-07-10 08:17:13 +00:00
|
|
|
/// Wraps a call to `walk_*` / `walk_flat_map_*`
|
2022-01-05 14:15:44 +08:00
|
|
|
/// for an AST node that supports attributes
|
|
|
|
/// (see the `Annotatable` enum)
|
|
|
|
/// This method assigns a `NodeId`, and sets that `NodeId`
|
|
|
|
/// as our current 'lint node id'. If a macro call is found
|
|
|
|
/// inside this AST node, we will use this AST node's `NodeId`
|
|
|
|
/// to emit lints associated with that macro (allowing
|
|
|
|
/// `#[allow]` / `#[deny]` to be applied close to
|
|
|
|
/// the macro invocation).
|
|
|
|
///
|
|
|
|
/// Do *not* call this for a macro AST node
|
|
|
|
/// (e.g. `ExprKind::MacCall`) - we cannot emit lints
|
|
|
|
/// at these AST nodes, since they are removed and
|
|
|
|
/// replaced with the result of macro expansion.
|
|
|
|
///
|
|
|
|
/// All other `NodeId`s are assigned by `visit_id`.
|
|
|
|
/// * `self` is the 'self' parameter for the current method,
|
|
|
|
/// * `id` is a mutable reference to the `NodeId` field
|
|
|
|
/// of the current AST node.
|
|
|
|
/// * `closure` is a closure that executes the
|
2024-07-10 08:17:13 +00:00
|
|
|
/// `walk_*` / `walk_flat_map_*` method
|
2022-01-05 14:15:44 +08:00
|
|
|
/// for the current AST node.
|
|
|
|
macro_rules! assign_id {
|
|
|
|
($self:ident, $id:expr, $closure:expr) => {{
|
|
|
|
let old_id = $self.cx.current_expansion.lint_node_id;
|
|
|
|
if $self.monotonic {
|
|
|
|
debug_assert_eq!(*$id, ast::DUMMY_NODE_ID);
|
|
|
|
let new_id = $self.cx.resolver.next_node_id();
|
|
|
|
*$id = new_id;
|
|
|
|
$self.cx.current_expansion.lint_node_id = new_id;
|
|
|
|
}
|
|
|
|
let ret = ($closure)();
|
|
|
|
$self.cx.current_expansion.lint_node_id = old_id;
|
|
|
|
ret
|
|
|
|
}};
|
|
|
|
}
|
|
|
|
|
|
|
|
enum AddSemicolon {
|
|
|
|
Yes,
|
|
|
|
No,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A trait implemented for all `AstFragment` nodes and providing all pieces
|
|
|
|
/// of functionality used by `InvocationCollector`.
|
2022-05-01 20:58:24 +03:00
|
|
|
trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
|
2022-01-05 14:15:44 +08:00
|
|
|
type OutputTy = SmallVec<[Self; 1]>;
|
2022-08-17 12:34:33 +10:00
|
|
|
type AttrsTy: Deref<Target = [ast::Attribute]> = ast::AttrVec;
|
2024-03-15 14:21:03 +03:00
|
|
|
type ItemKind = ItemKind;
|
2022-01-05 14:15:44 +08:00
|
|
|
const KIND: AstFragmentKind;
|
|
|
|
fn to_annotatable(self) -> Annotatable;
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy;
|
2021-12-29 18:47:19 +08:00
|
|
|
fn descr() -> &'static str {
|
|
|
|
unreachable!()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(self, _visitor: &mut V) -> Self::OutputTy {
|
2022-01-05 14:15:44 +08:00
|
|
|
unreachable!()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk<V: MutVisitor>(&mut self, _visitor: &mut V) {
|
2022-01-05 14:15:44 +08:00
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
fn is_mac_call(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
2022-08-12 12:20:10 +10:00
|
|
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
2022-01-05 14:15:44 +08:00
|
|
|
unreachable!()
|
|
|
|
}
|
2024-03-15 14:21:03 +03:00
|
|
|
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
2024-03-15 14:21:03 +03:00
|
|
|
None
|
|
|
|
}
|
|
|
|
fn delegation_item_kind(_deleg: Box<ast::Delegation>) -> Self::ItemKind {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
fn from_item(_item: ast::Item<Self::ItemKind>) -> Self {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
fn flatten_outputs(_outputs: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
|
|
|
|
unreachable!()
|
|
|
|
}
|
2022-01-05 14:15:44 +08:00
|
|
|
fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {}
|
|
|
|
fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) {
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn wrap_flat_map_node_walk_flat_map(
|
2022-01-05 14:15:44 +08:00
|
|
|
node: Self,
|
|
|
|
collector: &mut InvocationCollector<'_, '_>,
|
2024-07-10 08:17:13 +00:00
|
|
|
walk_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
|
2022-01-05 14:15:44 +08:00
|
|
|
) -> Result<Self::OutputTy, Self> {
|
2024-07-10 08:17:13 +00:00
|
|
|
Ok(walk_flat_map(node, collector))
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
2023-04-10 14:20:38 +03:00
|
|
|
fn expand_cfg_false(
|
|
|
|
&mut self,
|
|
|
|
collector: &mut InvocationCollector<'_, '_>,
|
|
|
|
_pos: usize,
|
|
|
|
span: Span,
|
|
|
|
) {
|
2023-12-18 20:54:03 +11:00
|
|
|
collector.cx.dcx().emit_err(RemoveNodeNotSupported { span, descr: Self::descr() });
|
2023-03-14 16:53:04 +04:00
|
|
|
}
|
2023-03-10 22:39:14 +01:00
|
|
|
|
|
|
|
/// All of the names (items) declared by this node.
|
|
|
|
/// This is an approximation and should only be used for diagnostics.
|
|
|
|
fn declared_names(&self) -> Vec<Ident> {
|
|
|
|
vec![]
|
|
|
|
}
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl InvocationCollectorNode for P<ast::Item> {
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::Items;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::Item(self)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_items()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
2024-07-22 14:34:45 +00:00
|
|
|
walk_flat_map_item(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
fn is_mac_call(&self) -> bool {
|
2022-01-07 14:54:16 +08:00
|
|
|
matches!(self.kind, ItemKind::MacCall(..))
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
2022-08-12 12:20:10 +10:00
|
|
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
2022-01-05 14:15:44 +08:00
|
|
|
let node = self.into_inner();
|
|
|
|
match node.kind {
|
2022-01-07 14:54:16 +08:00
|
|
|
ItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
|
2022-01-05 14:15:44 +08:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
2024-03-15 14:21:03 +03:00
|
|
|
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
2024-03-15 14:21:03 +03:00
|
|
|
match &self.kind {
|
|
|
|
ItemKind::DelegationMac(deleg) => Some((deleg, self)),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
|
|
|
|
ItemKind::Delegation(deleg)
|
|
|
|
}
|
|
|
|
fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
|
|
|
|
P(item)
|
|
|
|
}
|
|
|
|
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
|
|
|
|
items.flatten().collect()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn wrap_flat_map_node_walk_flat_map(
|
2022-01-05 14:15:44 +08:00
|
|
|
mut node: Self,
|
|
|
|
collector: &mut InvocationCollector<'_, '_>,
|
2024-07-10 08:17:13 +00:00
|
|
|
walk_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
|
2022-01-05 14:15:44 +08:00
|
|
|
) -> Result<Self::OutputTy, Self> {
|
2022-01-07 14:54:16 +08:00
|
|
|
if !matches!(node.kind, ItemKind::Mod(..)) {
|
2024-07-10 08:17:13 +00:00
|
|
|
return Ok(walk_flat_map(node, collector));
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Work around borrow checker not seeing through `P`'s deref.
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
let (span, mut attrs) = (node.span, mem::take(&mut node.attrs));
|
2025-04-01 14:49:58 +11:00
|
|
|
let ItemKind::Mod(_, ident, ref mut mod_kind) = node.kind else { unreachable!() };
|
2022-01-05 14:15:44 +08:00
|
|
|
let ecx = &mut collector.cx;
|
|
|
|
let (file_path, dir_path, dir_ownership) = match mod_kind {
|
2024-12-05 21:19:08 +00:00
|
|
|
ModKind::Loaded(_, inline, _, _) => {
|
2022-01-05 14:15:44 +08:00
|
|
|
// Inline `mod foo { ... }`, but we still need to push directories.
|
|
|
|
let (dir_path, dir_ownership) = mod_dir_path(
|
2023-11-21 20:07:32 +01:00
|
|
|
ecx.sess,
|
2022-01-05 14:15:44 +08:00
|
|
|
ident,
|
|
|
|
&attrs,
|
|
|
|
&ecx.current_expansion.module,
|
|
|
|
ecx.current_expansion.dir_ownership,
|
|
|
|
*inline,
|
|
|
|
);
|
2024-09-11 12:36:40 -07:00
|
|
|
// If the module was parsed from an external file, recover its path.
|
|
|
|
// This lets `parse_external_mod` catch cycles if it's self-referential.
|
|
|
|
let file_path = match inline {
|
|
|
|
Inline::Yes => None,
|
|
|
|
Inline::No => mod_file_path_from_attr(ecx.sess, &attrs, &dir_path),
|
|
|
|
};
|
2022-01-05 14:15:44 +08:00
|
|
|
node.attrs = attrs;
|
2024-09-11 12:36:40 -07:00
|
|
|
(file_path, dir_path, dir_ownership)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
ModKind::Unloaded => {
|
|
|
|
// We have an outline `mod foo;` so we need to parse the file.
|
|
|
|
let old_attrs_len = attrs.len();
|
2024-12-05 21:19:08 +00:00
|
|
|
let ParsedExternalMod {
|
|
|
|
items,
|
|
|
|
spans,
|
|
|
|
file_path,
|
|
|
|
dir_path,
|
|
|
|
dir_ownership,
|
|
|
|
had_parse_error,
|
|
|
|
} = parse_external_mod(
|
|
|
|
ecx.sess,
|
|
|
|
ident,
|
|
|
|
span,
|
|
|
|
&ecx.current_expansion.module,
|
|
|
|
ecx.current_expansion.dir_ownership,
|
|
|
|
&mut attrs,
|
|
|
|
);
|
2022-01-05 14:15:44 +08:00
|
|
|
|
2021-12-11 15:32:48 +08:00
|
|
|
if let Some(lint_store) = ecx.lint_store {
|
|
|
|
lint_store.pre_expansion_lint(
|
|
|
|
ecx.sess,
|
2023-08-09 20:28:00 +08:00
|
|
|
ecx.ecfg.features,
|
2021-12-11 15:32:48 +08:00
|
|
|
ecx.resolver.registered_tools(),
|
2021-12-07 18:28:12 +08:00
|
|
|
ecx.current_expansion.lint_node_id,
|
2021-12-11 15:32:48 +08:00
|
|
|
&attrs,
|
|
|
|
&items,
|
2022-12-06 12:46:10 +00:00
|
|
|
ident.name,
|
2021-12-07 18:28:12 +08:00
|
|
|
);
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
|
2024-12-05 21:19:08 +00:00
|
|
|
*mod_kind = ModKind::Loaded(items, Inline::No, spans, had_parse_error);
|
2022-01-05 14:15:44 +08:00
|
|
|
node.attrs = attrs;
|
|
|
|
if node.attrs.len() > old_attrs_len {
|
|
|
|
// If we loaded an out-of-line module and added some inner attributes,
|
|
|
|
// then we need to re-configure it and re-collect attributes for
|
|
|
|
// resolution and expansion.
|
|
|
|
return Err(node);
|
|
|
|
}
|
|
|
|
(Some(file_path), dir_path, dir_ownership)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Set the module info before we flat map.
|
|
|
|
let mut module = ecx.current_expansion.module.with_dir_path(dir_path);
|
|
|
|
module.mod_path.push(ident);
|
|
|
|
if let Some(file_path) = file_path {
|
|
|
|
module.file_path_stack.push(file_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
let orig_module = mem::replace(&mut ecx.current_expansion.module, Rc::new(module));
|
|
|
|
let orig_dir_ownership =
|
|
|
|
mem::replace(&mut ecx.current_expansion.dir_ownership, dir_ownership);
|
|
|
|
|
2024-07-10 08:17:13 +00:00
|
|
|
let res = Ok(walk_flat_map(node, collector));
|
2022-01-05 14:15:44 +08:00
|
|
|
|
|
|
|
collector.cx.current_expansion.dir_ownership = orig_dir_ownership;
|
|
|
|
collector.cx.current_expansion.module = orig_module;
|
|
|
|
res
|
|
|
|
}
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
|
2023-03-10 22:39:14 +01:00
|
|
|
fn declared_names(&self) -> Vec<Ident> {
|
|
|
|
if let ItemKind::Use(ut) = &self.kind {
|
|
|
|
fn collect_use_tree_leaves(ut: &ast::UseTree, idents: &mut Vec<Ident>) {
|
|
|
|
match &ut.kind {
|
|
|
|
ast::UseTreeKind::Glob => {}
|
|
|
|
ast::UseTreeKind::Simple(_) => idents.push(ut.ident()),
|
2024-04-02 00:26:10 +02:00
|
|
|
ast::UseTreeKind::Nested { items, .. } => {
|
|
|
|
for (ut, _) in items {
|
2023-11-21 20:07:32 +01:00
|
|
|
collect_use_tree_leaves(ut, idents);
|
2023-03-10 22:39:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut idents = Vec::new();
|
2023-11-21 20:07:32 +01:00
|
|
|
collect_use_tree_leaves(ut, &mut idents);
|
2023-03-10 22:39:14 +01:00
|
|
|
return idents;
|
|
|
|
}
|
|
|
|
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
if let Some(ident) = self.kind.ident() { vec![ident] } else { vec![] }
|
2023-03-10 22:39:14 +01:00
|
|
|
}
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
struct TraitItemTag;
|
2022-05-01 20:58:24 +03:00
|
|
|
impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> {
|
2022-01-05 14:15:44 +08:00
|
|
|
type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
|
2024-03-15 14:21:03 +03:00
|
|
|
type ItemKind = AssocItemKind;
|
2022-01-05 14:15:44 +08:00
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::TraitItems;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
2024-07-08 10:40:37 +00:00
|
|
|
Annotatable::AssocItem(self.wrapped, AssocCtxt::Trait)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_trait_items()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
2024-11-08 18:51:28 -03:00
|
|
|
walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Trait)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
fn is_mac_call(&self) -> bool {
|
2022-01-07 14:54:16 +08:00
|
|
|
matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
2022-08-12 12:20:10 +10:00
|
|
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
2022-01-05 14:15:44 +08:00
|
|
|
let item = self.wrapped.into_inner();
|
|
|
|
match item.kind {
|
2022-01-07 14:54:16 +08:00
|
|
|
AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
|
2022-01-05 14:15:44 +08:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
2024-03-15 14:21:03 +03:00
|
|
|
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
2024-03-15 14:21:03 +03:00
|
|
|
match &self.wrapped.kind {
|
|
|
|
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
|
|
|
|
AssocItemKind::Delegation(deleg)
|
|
|
|
}
|
|
|
|
fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
|
|
|
|
AstNodeWrapper::new(P(item), TraitItemTag)
|
|
|
|
}
|
|
|
|
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
|
|
|
|
items.flatten().collect()
|
|
|
|
}
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
struct ImplItemTag;
|
2022-05-01 20:58:24 +03:00
|
|
|
impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> {
|
2022-01-05 14:15:44 +08:00
|
|
|
type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
|
2024-03-15 14:21:03 +03:00
|
|
|
type ItemKind = AssocItemKind;
|
2022-01-05 14:15:44 +08:00
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::ImplItems;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
2025-03-25 09:00:35 +00:00
|
|
|
Annotatable::AssocItem(self.wrapped, AssocCtxt::Impl { of_trait: false })
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_impl_items()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
2025-03-25 09:00:35 +00:00
|
|
|
walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl { of_trait: false })
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
fn is_mac_call(&self) -> bool {
|
2022-01-07 14:54:16 +08:00
|
|
|
matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
2022-08-12 12:20:10 +10:00
|
|
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
2022-01-05 14:15:44 +08:00
|
|
|
let item = self.wrapped.into_inner();
|
|
|
|
match item.kind {
|
2022-01-07 14:54:16 +08:00
|
|
|
AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
|
2022-01-05 14:15:44 +08:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
2024-03-15 14:21:03 +03:00
|
|
|
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
2024-03-15 14:21:03 +03:00
|
|
|
match &self.wrapped.kind {
|
|
|
|
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
|
|
|
|
AssocItemKind::Delegation(deleg)
|
|
|
|
}
|
|
|
|
fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
|
|
|
|
AstNodeWrapper::new(P(item), ImplItemTag)
|
|
|
|
}
|
|
|
|
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
|
|
|
|
items.flatten().collect()
|
|
|
|
}
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
|
2025-03-25 09:00:35 +00:00
|
|
|
struct TraitImplItemTag;
|
|
|
|
impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitImplItemTag> {
|
|
|
|
type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
|
|
|
|
type ItemKind = AssocItemKind;
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::TraitImplItems;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::AssocItem(self.wrapped, AssocCtxt::Impl { of_trait: true })
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_trait_impl_items()
|
|
|
|
}
|
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
|
|
|
walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl { of_trait: true })
|
|
|
|
}
|
|
|
|
fn is_mac_call(&self) -> bool {
|
|
|
|
matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
|
|
|
|
}
|
|
|
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
|
|
|
let item = self.wrapped.into_inner();
|
|
|
|
match item.kind {
|
|
|
|
AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
|
|
|
match &self.wrapped.kind {
|
|
|
|
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
|
|
|
|
AssocItemKind::Delegation(deleg)
|
|
|
|
}
|
|
|
|
fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
|
|
|
|
AstNodeWrapper::new(P(item), TraitImplItemTag)
|
|
|
|
}
|
|
|
|
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
|
|
|
|
items.flatten().collect()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
impl InvocationCollectorNode for P<ast::ForeignItem> {
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::ForeignItems;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::ForeignItem(self)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_foreign_items()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
2024-11-17 20:11:49 -03:00
|
|
|
walk_flat_map_foreign_item(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
fn is_mac_call(&self) -> bool {
|
2022-01-07 14:54:16 +08:00
|
|
|
matches!(self.kind, ForeignItemKind::MacCall(..))
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
2022-08-12 12:20:10 +10:00
|
|
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
2022-01-05 14:15:44 +08:00
|
|
|
let node = self.into_inner();
|
|
|
|
match node.kind {
|
2022-01-07 14:54:16 +08:00
|
|
|
ForeignItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
|
2022-01-05 14:15:44 +08:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvocationCollectorNode for ast::Variant {
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::Variants;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::Variant(self)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_variants()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_flat_map_variant(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-05 18:58:29 +08:00
|
|
|
impl InvocationCollectorNode for ast::WherePredicate {
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::WherePredicates;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::WherePredicate(self)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_where_predicates()
|
|
|
|
}
|
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
|
|
|
walk_flat_map_where_predicate(visitor, self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
impl InvocationCollectorNode for ast::FieldDef {
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::FieldDefs;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::FieldDef(self)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_field_defs()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_flat_map_field_def(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvocationCollectorNode for ast::PatField {
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::PatFields;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::PatField(self)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_pat_fields()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_flat_map_pat_field(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvocationCollectorNode for ast::ExprField {
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::ExprFields;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::ExprField(self)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_expr_fields()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_flat_map_expr_field(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvocationCollectorNode for ast::Param {
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::Params;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::Param(self)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_params()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_flat_map_param(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvocationCollectorNode for ast::GenericParam {
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::GenericParams;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::GenericParam(self)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_generic_params()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_flat_map_generic_param(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvocationCollectorNode for ast::Arm {
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::Arms;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::Arm(self)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_arms()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_flat_map_arm(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvocationCollectorNode for ast::Stmt {
|
|
|
|
type AttrsTy = ast::AttrVec;
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::Stmts;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::Stmt(P(self))
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_stmts()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_flat_map_stmt(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
fn is_mac_call(&self) -> bool {
|
|
|
|
match &self.kind {
|
|
|
|
StmtKind::MacCall(..) => true,
|
|
|
|
StmtKind::Item(item) => matches!(item.kind, ItemKind::MacCall(..)),
|
2022-01-07 14:54:16 +08:00
|
|
|
StmtKind::Semi(expr) => matches!(expr.kind, ExprKind::MacCall(..)),
|
2022-01-05 14:15:44 +08:00
|
|
|
StmtKind::Expr(..) => unreachable!(),
|
2024-03-14 11:25:05 +01:00
|
|
|
StmtKind::Let(..) | StmtKind::Empty => false,
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
}
|
2022-08-12 12:20:10 +10:00
|
|
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
2022-01-05 14:15:44 +08:00
|
|
|
// We pull macro invocations (both attributes and fn-like macro calls) out of their
|
|
|
|
// `StmtKind`s and treat them as statement macro invocations, not as items or expressions.
|
|
|
|
let (add_semicolon, mac, attrs) = match self.kind {
|
|
|
|
StmtKind::MacCall(mac) => {
|
2022-01-07 14:54:16 +08:00
|
|
|
let ast::MacCallStmt { mac, style, attrs, .. } = mac.into_inner();
|
2022-01-05 14:15:44 +08:00
|
|
|
(style == MacStmtStyle::Semicolon, mac, attrs)
|
|
|
|
}
|
|
|
|
StmtKind::Item(item) => match item.into_inner() {
|
|
|
|
ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => {
|
2022-08-17 12:34:33 +10:00
|
|
|
(mac.args.need_semicolon(), mac, attrs)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
},
|
|
|
|
StmtKind::Semi(expr) => match expr.into_inner() {
|
2022-01-07 14:54:16 +08:00
|
|
|
ast::Expr { kind: ExprKind::MacCall(mac), attrs, .. } => {
|
2022-01-05 14:15:44 +08:00
|
|
|
(mac.args.need_semicolon(), mac, attrs)
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
},
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
(mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No })
|
|
|
|
}
|
2024-03-15 14:21:03 +03:00
|
|
|
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
2024-03-15 14:21:03 +03:00
|
|
|
match &self.kind {
|
|
|
|
StmtKind::Item(item) => match &item.kind {
|
|
|
|
ItemKind::DelegationMac(deleg) => Some((deleg, item)),
|
|
|
|
_ => None,
|
|
|
|
},
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
|
|
|
|
ItemKind::Delegation(deleg)
|
|
|
|
}
|
|
|
|
fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
|
|
|
|
ast::Stmt { id: ast::DUMMY_NODE_ID, span: item.span, kind: StmtKind::Item(P(item)) }
|
|
|
|
}
|
|
|
|
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
|
|
|
|
items.flatten().collect()
|
|
|
|
}
|
2022-01-05 14:15:44 +08:00
|
|
|
fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) {
|
|
|
|
// If this is a macro invocation with a semicolon, then apply that
|
|
|
|
// semicolon to the final statement produced by expansion.
|
|
|
|
if matches!(add_semicolon, AddSemicolon::Yes) {
|
|
|
|
if let Some(stmt) = stmts.pop() {
|
|
|
|
stmts.push(stmt.add_trailing_semicolon());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvocationCollectorNode for ast::Crate {
|
|
|
|
type OutputTy = ast::Crate;
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::Crate;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::Crate(self)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_crate()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_crate(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
2023-04-10 14:20:38 +03:00
|
|
|
fn expand_cfg_false(
|
|
|
|
&mut self,
|
|
|
|
collector: &mut InvocationCollector<'_, '_>,
|
|
|
|
pos: usize,
|
|
|
|
_span: Span,
|
|
|
|
) {
|
|
|
|
// Attributes above `cfg(FALSE)` are left in place, because we may want to configure
|
|
|
|
// some global crate properties even on fully unconfigured crates.
|
|
|
|
self.attrs.truncate(pos);
|
2023-03-14 16:53:04 +04:00
|
|
|
// Standard prelude imports are left in the crate for backward compatibility.
|
|
|
|
self.items.truncate(collector.cx.num_standard_library_imports);
|
|
|
|
}
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl InvocationCollectorNode for P<ast::Ty> {
|
|
|
|
type OutputTy = P<ast::Ty>;
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::Ty;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_ty()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_ty(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
fn is_mac_call(&self) -> bool {
|
|
|
|
matches!(self.kind, ast::TyKind::MacCall(..))
|
|
|
|
}
|
2022-08-12 12:20:10 +10:00
|
|
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
2022-01-05 14:15:44 +08:00
|
|
|
let node = self.into_inner();
|
|
|
|
match node.kind {
|
2022-08-17 12:34:33 +10:00
|
|
|
TyKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No),
|
2022-01-05 14:15:44 +08:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvocationCollectorNode for P<ast::Pat> {
|
|
|
|
type OutputTy = P<ast::Pat>;
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::Pat;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_pat()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_pat(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
fn is_mac_call(&self) -> bool {
|
2022-01-07 14:54:16 +08:00
|
|
|
matches!(self.kind, PatKind::MacCall(..))
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
2022-08-12 12:20:10 +10:00
|
|
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
2022-01-05 14:15:44 +08:00
|
|
|
let node = self.into_inner();
|
|
|
|
match node.kind {
|
2022-08-17 12:34:33 +10:00
|
|
|
PatKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No),
|
2022-01-05 14:15:44 +08:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvocationCollectorNode for P<ast::Expr> {
|
|
|
|
type OutputTy = P<ast::Expr>;
|
|
|
|
type AttrsTy = ast::AttrVec;
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::Expr;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::Expr(self)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_expr()
|
|
|
|
}
|
2021-12-29 18:47:19 +08:00
|
|
|
fn descr() -> &'static str {
|
|
|
|
"an expression"
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_expr(visitor, self)
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
fn is_mac_call(&self) -> bool {
|
2022-01-07 14:54:16 +08:00
|
|
|
matches!(self.kind, ExprKind::MacCall(..))
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
2022-08-12 12:20:10 +10:00
|
|
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
2022-01-05 14:15:44 +08:00
|
|
|
let node = self.into_inner();
|
|
|
|
match node.kind {
|
2022-01-07 14:54:16 +08:00
|
|
|
ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
|
2022-01-05 14:15:44 +08:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct OptExprTag;
|
2022-05-01 20:58:24 +03:00
|
|
|
impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> {
|
2022-01-05 14:15:44 +08:00
|
|
|
type OutputTy = Option<P<ast::Expr>>;
|
|
|
|
type AttrsTy = ast::AttrVec;
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::OptExpr;
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::Expr(self.wrapped)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
fragment.make_opt_expr()
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk_flat_map<V: MutVisitor>(mut self, visitor: &mut V) -> Self::OutputTy {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_expr(visitor, &mut self.wrapped);
|
2022-01-05 14:15:44 +08:00
|
|
|
Some(self.wrapped)
|
|
|
|
}
|
|
|
|
fn is_mac_call(&self) -> bool {
|
|
|
|
matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
|
|
|
|
}
|
2022-08-12 12:20:10 +10:00
|
|
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
2022-01-05 14:15:44 +08:00
|
|
|
let node = self.wrapped.into_inner();
|
|
|
|
match node.kind {
|
2022-01-07 14:54:16 +08:00
|
|
|
ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
|
2022-01-05 14:15:44 +08:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn pre_flat_map_node_collect_attr(cfg: &StripUnconfigured<'_>, attr: &ast::Attribute) {
|
2023-11-21 20:07:32 +01:00
|
|
|
cfg.maybe_emit_expr_attr_err(attr);
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-23 09:22:19 +00:00
|
|
|
/// This struct is a hack to workaround unstable of `stmt_expr_attributes`.
|
|
|
|
/// It can be removed once that feature is stabilized.
|
|
|
|
struct MethodReceiverTag;
|
|
|
|
impl DummyAstNode for MethodReceiverTag {
|
|
|
|
fn dummy() -> MethodReceiverTag {
|
|
|
|
MethodReceiverTag
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag> {
|
|
|
|
type OutputTy = Self;
|
|
|
|
type AttrsTy = ast::AttrVec;
|
|
|
|
const KIND: AstFragmentKind = AstFragmentKind::MethodReceiverExpr;
|
|
|
|
fn descr() -> &'static str {
|
|
|
|
"an expression"
|
|
|
|
}
|
|
|
|
fn to_annotatable(self) -> Annotatable {
|
|
|
|
Annotatable::Expr(self.wrapped)
|
|
|
|
}
|
|
|
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
|
|
|
AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag)
|
|
|
|
}
|
2024-07-10 08:17:13 +00:00
|
|
|
fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_expr(visitor, &mut self.wrapped)
|
2022-10-23 09:22:19 +00:00
|
|
|
}
|
|
|
|
fn is_mac_call(&self) -> bool {
|
|
|
|
matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
|
|
|
|
}
|
|
|
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
|
|
|
let node = self.wrapped.into_inner();
|
|
|
|
match node.kind {
|
|
|
|
ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-15 14:21:03 +03:00
|
|
|
fn build_single_delegations<'a, Node: InvocationCollectorNode>(
|
|
|
|
ecx: &ExtCtxt<'_>,
|
|
|
|
deleg: &'a ast::DelegationMac,
|
|
|
|
item: &'a ast::Item<Node::ItemKind>,
|
|
|
|
suffixes: &'a [(Ident, Option<Ident>)],
|
|
|
|
item_span: Span,
|
|
|
|
from_glob: bool,
|
|
|
|
) -> impl Iterator<Item = ast::Item<Node::ItemKind>> + 'a {
|
|
|
|
if suffixes.is_empty() {
|
|
|
|
// Report an error for now, to avoid keeping stem for resolution and
|
|
|
|
// stability checks.
|
|
|
|
let kind = String::from(if from_glob { "glob" } else { "list" });
|
|
|
|
ecx.dcx().emit_err(EmptyDelegationMac { span: item.span, kind });
|
|
|
|
}
|
|
|
|
|
|
|
|
suffixes.iter().map(move |&(ident, rename)| {
|
|
|
|
let mut path = deleg.prefix.clone();
|
|
|
|
path.segments.push(ast::PathSegment { ident, id: ast::DUMMY_NODE_ID, args: None });
|
|
|
|
|
|
|
|
ast::Item {
|
|
|
|
attrs: item.attrs.clone(),
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
span: if from_glob { item_span } else { ident.span },
|
|
|
|
vis: item.vis.clone(),
|
|
|
|
kind: Node::delegation_item_kind(Box::new(ast::Delegation {
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
qself: deleg.qself.clone(),
|
|
|
|
path,
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ident: rename.unwrap_or(ident),
|
2024-03-15 14:21:03 +03:00
|
|
|
rename,
|
|
|
|
body: deleg.body.clone(),
|
|
|
|
from_glob,
|
|
|
|
})),
|
|
|
|
tokens: None,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-06-14 19:39:39 +03:00
|
|
|
struct InvocationCollector<'a, 'b> {
|
2016-09-02 09:12:47 +00:00
|
|
|
cx: &'a mut ExtCtxt<'b>,
|
2025-02-03 06:44:41 +03:00
|
|
|
invocations: Vec<(Invocation, Option<Arc<SyntaxExtension>>)>,
|
2016-09-06 05:42:45 +00:00
|
|
|
monotonic: bool,
|
2016-09-02 09:12:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'b> InvocationCollector<'a, 'b> {
|
2022-02-27 22:26:24 +01:00
|
|
|
fn cfg(&self) -> StripUnconfigured<'_> {
|
|
|
|
StripUnconfigured {
|
2023-11-21 20:07:32 +01:00
|
|
|
sess: self.cx.sess,
|
2023-08-09 20:28:00 +08:00
|
|
|
features: Some(self.cx.ecfg.features),
|
2022-02-27 22:26:24 +01:00
|
|
|
config_tokens: false,
|
|
|
|
lint_node_id: self.cx.current_expansion.lint_node_id,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-20 02:08:08 +03:00
|
|
|
fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment {
|
2021-06-25 20:43:04 +02:00
|
|
|
let expn_id = LocalExpnId::fresh_empty();
|
2024-03-15 14:21:03 +03:00
|
|
|
if matches!(kind, InvocationKind::GlobDelegation { .. }) {
|
|
|
|
// In resolver we need to know which invocation ids are delegations early,
|
|
|
|
// before their `ExpnData` is filled.
|
|
|
|
self.cx.resolver.register_glob_delegation(expn_id);
|
|
|
|
}
|
2019-11-23 16:54:24 +03:00
|
|
|
let vis = kind.placeholder_visibility();
|
2020-03-09 20:50:12 +03:00
|
|
|
self.invocations.push((
|
|
|
|
Invocation {
|
|
|
|
kind,
|
|
|
|
fragment_kind,
|
|
|
|
expansion_data: ExpansionData {
|
|
|
|
id: expn_id,
|
|
|
|
depth: self.cx.current_expansion.depth + 1,
|
|
|
|
..self.cx.current_expansion.clone()
|
|
|
|
},
|
2016-09-26 22:54:36 +00:00
|
|
|
},
|
2020-03-09 20:50:12 +03:00
|
|
|
None,
|
|
|
|
));
|
2019-11-23 16:54:24 +03:00
|
|
|
placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis)
|
2016-09-02 09:12:47 +00:00
|
|
|
}
|
2016-09-01 07:01:45 +00:00
|
|
|
|
2022-08-12 12:20:10 +10:00
|
|
|
fn collect_bang(&mut self, mac: P<ast::MacCall>, kind: AstFragmentKind) -> AstFragment {
|
2021-10-13 13:58:19 -05:00
|
|
|
// cache the macro call span so that it can be
|
|
|
|
// easily adjusted for incremental compilation
|
|
|
|
let span = mac.span();
|
2019-07-01 01:08:49 +03:00
|
|
|
self.collect(kind, InvocationKind::Bang { mac, span })
|
2016-09-02 09:12:47 +00:00
|
|
|
}
|
2016-09-01 07:01:45 +00:00
|
|
|
|
2017-02-02 07:01:15 +00:00
|
|
|
fn collect_attr(
|
|
|
|
&mut self,
|
2022-01-07 14:54:16 +08:00
|
|
|
(attr, pos, derives): (ast::Attribute, usize, Vec<ast::Path>),
|
2017-02-02 07:01:15 +00:00
|
|
|
item: Annotatable,
|
2018-09-16 17:15:07 +03:00
|
|
|
kind: AstFragmentKind,
|
2018-06-20 02:08:08 +03:00
|
|
|
) -> AstFragment {
|
2021-02-23 00:54:09 +03:00
|
|
|
self.collect(kind, InvocationKind::Attr { attr, pos, item, derives })
|
2016-09-02 09:12:47 +00:00
|
|
|
}
|
|
|
|
|
2024-03-15 14:21:03 +03:00
|
|
|
fn collect_glob_delegation(
|
|
|
|
&mut self,
|
|
|
|
item: P<ast::AssocItem>,
|
2025-03-25 09:00:35 +00:00
|
|
|
of_trait: bool,
|
2024-03-15 14:21:03 +03:00
|
|
|
kind: AstFragmentKind,
|
|
|
|
) -> AstFragment {
|
2025-03-25 09:00:35 +00:00
|
|
|
self.collect(kind, InvocationKind::GlobDelegation { item, of_trait })
|
2024-03-15 14:21:03 +03:00
|
|
|
}
|
|
|
|
|
2020-11-14 14:47:14 +03:00
|
|
|
/// If `item` is an attribute invocation, remove the attribute and return it together with
|
2021-02-23 00:54:09 +03:00
|
|
|
/// its position and derives following it. We have to collect the derives in order to resolve
|
|
|
|
/// legacy derive helpers (helpers written before derives that introduce them).
|
|
|
|
fn take_first_attr(
|
2022-01-05 14:10:07 +08:00
|
|
|
&self,
|
2022-05-01 20:58:24 +03:00
|
|
|
item: &mut impl HasAttrs,
|
2022-01-07 14:54:16 +08:00
|
|
|
) -> Option<(ast::Attribute, usize, Vec<ast::Path>)> {
|
2020-11-14 14:47:14 +03:00
|
|
|
let mut attr = None;
|
|
|
|
|
2021-12-29 18:47:19 +08:00
|
|
|
let mut cfg_pos = None;
|
|
|
|
let mut attr_pos = None;
|
|
|
|
for (pos, attr) in item.attrs().iter().enumerate() {
|
|
|
|
if !attr.is_doc_comment() && !self.cx.expanded_inert_attrs.is_marked(attr) {
|
|
|
|
let name = attr.ident().map(|ident| ident.name);
|
|
|
|
if name == Some(sym::cfg) || name == Some(sym::cfg_attr) {
|
|
|
|
cfg_pos = Some(pos); // a cfg attr found, no need to search anymore
|
|
|
|
break;
|
|
|
|
} else if attr_pos.is_none()
|
2023-05-24 14:19:22 +00:00
|
|
|
&& !name.is_some_and(rustc_feature::is_builtin_attr_name)
|
2021-12-29 18:47:19 +08:00
|
|
|
{
|
|
|
|
attr_pos = Some(pos); // a non-cfg attr found, still may find a cfg attr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-14 14:47:14 +03:00
|
|
|
item.visit_attrs(|attrs| {
|
2021-12-29 18:47:19 +08:00
|
|
|
attr = Some(match (cfg_pos, attr_pos) {
|
|
|
|
(Some(pos), _) => (attrs.remove(pos), pos, Vec::new()),
|
|
|
|
(_, Some(pos)) => {
|
|
|
|
let attr = attrs.remove(pos);
|
|
|
|
let following_derives = attrs[pos..]
|
2020-11-14 14:47:14 +03:00
|
|
|
.iter()
|
|
|
|
.filter(|a| a.has_name(sym::derive))
|
|
|
|
.flat_map(|a| a.meta_item_list().unwrap_or_default())
|
2024-10-07 08:49:47 +09:00
|
|
|
.filter_map(|meta_item_inner| match meta_item_inner {
|
2024-10-04 21:59:04 +09:00
|
|
|
MetaItemInner::MetaItem(ast::MetaItem {
|
2020-11-14 14:47:14 +03:00
|
|
|
kind: MetaItemKind::Word,
|
|
|
|
path,
|
|
|
|
..
|
|
|
|
}) => Some(path),
|
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
2021-12-29 18:47:19 +08:00
|
|
|
(attr, pos, following_derives)
|
|
|
|
}
|
|
|
|
_ => return,
|
|
|
|
});
|
2018-04-17 23:19:21 -07:00
|
|
|
});
|
|
|
|
|
2020-11-14 14:47:14 +03:00
|
|
|
attr
|
2018-04-17 23:19:21 -07:00
|
|
|
}
|
|
|
|
|
2016-12-01 11:20:04 +00:00
|
|
|
// Detect use of feature-gated or invalid attributes on macro invocations
|
|
|
|
// since they will not be detected after macro expansion.
|
2022-01-07 14:54:16 +08:00
|
|
|
fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
|
2023-08-09 20:28:00 +08:00
|
|
|
let features = self.cx.ecfg.features;
|
2021-04-04 02:39:55 +09:00
|
|
|
let mut attrs = attrs.iter().peekable();
|
|
|
|
let mut span: Option<Span> = None;
|
|
|
|
while let Some(attr) = attrs.next() {
|
2020-07-30 11:27:50 +10:00
|
|
|
rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
|
2024-08-07 01:36:28 -05:00
|
|
|
validate_attr::check_attr(&self.cx.sess.psess, attr);
|
2021-04-04 02:39:55 +09:00
|
|
|
|
|
|
|
let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
|
|
|
|
span = Some(current_span);
|
|
|
|
|
2023-05-24 14:19:22 +00:00
|
|
|
if attrs.peek().is_some_and(|next_attr| next_attr.doc_str().is_some()) {
|
2021-04-04 02:39:55 +09:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-07-14 19:51:45 -05:00
|
|
|
if attr.is_doc_comment() {
|
2024-05-20 17:47:54 +00:00
|
|
|
self.cx.sess.psess.buffer_lint(
|
2023-11-21 20:07:32 +01:00
|
|
|
UNUSED_DOC_COMMENTS,
|
2021-04-04 02:39:55 +09:00
|
|
|
current_span,
|
2021-07-14 19:51:45 -05:00
|
|
|
self.cx.current_expansion.lint_node_id,
|
2024-02-29 16:40:44 +11:00
|
|
|
BuiltinLintDiag::UnusedDocComment(attr.span),
|
2020-02-21 16:46:14 -08:00
|
|
|
);
|
2024-12-13 14:47:11 +01:00
|
|
|
} else if rustc_attr_parsing::is_builtin_attr(attr) {
|
2021-07-14 19:51:45 -05:00
|
|
|
let attr_name = attr.ident().unwrap().name;
|
|
|
|
// `#[cfg]` and `#[cfg_attr]` are special - they are
|
|
|
|
// eagerly evaluated.
|
2025-03-22 21:42:34 +03:00
|
|
|
if attr_name != sym::cfg_trace && attr_name != sym::cfg_attr_trace {
|
2024-05-20 17:47:54 +00:00
|
|
|
self.cx.sess.psess.buffer_lint(
|
2023-11-21 20:07:32 +01:00
|
|
|
UNUSED_ATTRIBUTES,
|
2021-07-14 19:51:45 -05:00
|
|
|
attr.span,
|
|
|
|
self.cx.current_expansion.lint_node_id,
|
2024-02-29 16:40:44 +11:00
|
|
|
BuiltinLintDiag::UnusedBuiltinAttribute {
|
2021-07-14 19:51:45 -05:00
|
|
|
attr_name,
|
|
|
|
macro_name: pprust::path_to_string(&call.path),
|
|
|
|
invoc_span: call.path.span,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2020-02-15 15:29:45 +03:00
|
|
|
}
|
2016-12-01 11:20:04 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-29 12:10:02 -07:00
|
|
|
|
2021-12-29 18:47:19 +08:00
|
|
|
fn expand_cfg_true(
|
|
|
|
&mut self,
|
2022-05-01 20:58:24 +03:00
|
|
|
node: &mut impl HasAttrs,
|
2021-12-29 18:47:19 +08:00
|
|
|
attr: ast::Attribute,
|
|
|
|
pos: usize,
|
2023-03-10 22:39:14 +01:00
|
|
|
) -> (bool, Option<ast::MetaItem>) {
|
|
|
|
let (res, meta_item) = self.cfg().cfg_true(&attr);
|
2021-12-29 18:47:19 +08:00
|
|
|
if res {
|
2025-03-22 21:42:34 +03:00
|
|
|
// A trace attribute left in AST in place of the original `cfg` attribute.
|
|
|
|
// It can later be used by lints or other diagnostics.
|
|
|
|
let trace_attr = attr_into_trace(attr, sym::cfg_trace);
|
|
|
|
node.visit_attrs(|attrs| attrs.insert(pos, trace_attr));
|
2021-12-29 18:47:19 +08:00
|
|
|
}
|
2023-03-10 22:39:14 +01:00
|
|
|
|
|
|
|
(res, meta_item)
|
2021-12-29 18:47:19 +08:00
|
|
|
}
|
|
|
|
|
2023-02-18 16:23:57 +04:00
|
|
|
fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) {
|
2021-12-29 18:47:19 +08:00
|
|
|
node.visit_attrs(|attrs| {
|
2022-08-17 12:34:33 +10:00
|
|
|
// Repeated `insert` calls is inefficient, but the number of
|
|
|
|
// insertions is almost always 0 or 1 in practice.
|
|
|
|
for cfg in self.cfg().expand_cfg_attr(attr, false).into_iter().rev() {
|
|
|
|
attrs.insert(pos, cfg)
|
|
|
|
}
|
2021-12-29 18:47:19 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn flat_map_node<Node: InvocationCollectorNode<OutputTy: Default>>(
|
|
|
|
&mut self,
|
2021-12-29 18:47:19 +08:00
|
|
|
mut node: Node,
|
2022-01-05 14:15:44 +08:00
|
|
|
) -> Node::OutputTy {
|
2021-12-29 18:47:19 +08:00
|
|
|
loop {
|
|
|
|
return match self.take_first_attr(&mut node) {
|
|
|
|
Some((attr, pos, derives)) => match attr.name_or_empty() {
|
|
|
|
sym::cfg => {
|
2023-03-10 22:39:14 +01:00
|
|
|
let (res, meta_item) = self.expand_cfg_true(&mut node, attr, pos);
|
|
|
|
if res {
|
2021-12-29 18:47:19 +08:00
|
|
|
continue;
|
|
|
|
}
|
2023-03-10 22:39:14 +01:00
|
|
|
|
|
|
|
if let Some(meta_item) = meta_item {
|
|
|
|
for name in node.declared_names() {
|
|
|
|
self.cx.resolver.append_stripped_cfg_item(
|
|
|
|
self.cx.current_expansion.lint_node_id,
|
|
|
|
name,
|
|
|
|
meta_item.clone(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2021-12-29 18:47:19 +08:00
|
|
|
Default::default()
|
|
|
|
}
|
|
|
|
sym::cfg_attr => {
|
2023-02-18 16:23:57 +04:00
|
|
|
self.expand_cfg_attr(&mut node, &attr, pos);
|
2021-12-29 18:47:19 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
_ => {
|
2022-02-27 22:26:24 +01:00
|
|
|
Node::pre_flat_map_node_collect_attr(&self.cfg(), &attr);
|
2021-12-29 18:47:19 +08:00
|
|
|
self.collect_attr((attr, pos, derives), node.to_annotatable(), Node::KIND)
|
|
|
|
.make_ast::<Node>()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
None if node.is_mac_call() => {
|
|
|
|
let (mac, attrs, add_semicolon) = node.take_mac_call();
|
|
|
|
self.check_attributes(&attrs, &mac);
|
|
|
|
let mut res = self.collect_bang(mac, Node::KIND).make_ast::<Node>();
|
|
|
|
Node::post_flat_map_node_collect_bang(&mut res, add_semicolon);
|
|
|
|
res
|
|
|
|
}
|
2024-03-15 14:21:03 +03:00
|
|
|
None if let Some((deleg, item)) = node.delegation() => {
|
|
|
|
let Some(suffixes) = &deleg.suffixes else {
|
2024-06-22 19:14:16 +03:00
|
|
|
let traitless_qself =
|
|
|
|
matches!(&deleg.qself, Some(qself) if qself.position == 0);
|
2025-03-25 09:00:35 +00:00
|
|
|
let (item, of_trait) = match node.to_annotatable() {
|
|
|
|
Annotatable::AssocItem(item, AssocCtxt::Impl { of_trait }) => {
|
|
|
|
(item, of_trait)
|
|
|
|
}
|
2024-03-15 14:21:03 +03:00
|
|
|
ann @ (Annotatable::Item(_)
|
2024-07-08 10:40:37 +00:00
|
|
|
| Annotatable::AssocItem(..)
|
2024-03-15 14:21:03 +03:00
|
|
|
| Annotatable::Stmt(_)) => {
|
|
|
|
let span = ann.span();
|
|
|
|
self.cx.dcx().emit_err(GlobDelegationOutsideImpls { span });
|
|
|
|
return Default::default();
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
2024-06-22 19:14:16 +03:00
|
|
|
if traitless_qself {
|
|
|
|
let span = item.span;
|
|
|
|
self.cx.dcx().emit_err(GlobDelegationTraitlessQpath { span });
|
|
|
|
return Default::default();
|
|
|
|
}
|
2025-03-25 09:00:35 +00:00
|
|
|
return self
|
|
|
|
.collect_glob_delegation(item, of_trait, Node::KIND)
|
|
|
|
.make_ast::<Node>();
|
2024-03-15 14:21:03 +03:00
|
|
|
};
|
2024-03-15 14:21:03 +03:00
|
|
|
|
2024-03-15 14:21:03 +03:00
|
|
|
let single_delegations = build_single_delegations::<Node>(
|
|
|
|
self.cx, deleg, item, suffixes, item.span, false,
|
|
|
|
);
|
|
|
|
Node::flatten_outputs(single_delegations.map(|item| {
|
|
|
|
let mut item = Node::from_item(item);
|
2024-07-10 08:17:13 +00:00
|
|
|
assign_id!(self, item.node_id_mut(), || item.walk_flat_map(self))
|
2024-03-15 14:21:03 +03:00
|
|
|
}))
|
|
|
|
}
|
2021-12-29 18:47:19 +08:00
|
|
|
None => {
|
2024-07-10 08:17:13 +00:00
|
|
|
match Node::wrap_flat_map_node_walk_flat_map(node, self, |mut node, this| {
|
|
|
|
assign_id!(this, node.node_id_mut(), || node.walk_flat_map(this))
|
2021-12-29 18:47:19 +08:00
|
|
|
}) {
|
|
|
|
Ok(output) => output,
|
|
|
|
Err(returned_node) => {
|
|
|
|
node = returned_node;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2021-07-14 18:24:12 -05:00
|
|
|
}
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_node<Node: InvocationCollectorNode<OutputTy = Node> + DummyAstNode>(
|
|
|
|
&mut self,
|
|
|
|
node: &mut Node,
|
|
|
|
) {
|
2021-12-29 18:47:19 +08:00
|
|
|
loop {
|
|
|
|
return match self.take_first_attr(node) {
|
|
|
|
Some((attr, pos, derives)) => match attr.name_or_empty() {
|
|
|
|
sym::cfg => {
|
|
|
|
let span = attr.span;
|
2023-03-10 22:39:14 +01:00
|
|
|
if self.expand_cfg_true(node, attr, pos).0 {
|
2021-12-29 18:47:19 +08:00
|
|
|
continue;
|
|
|
|
}
|
2022-11-15 14:24:33 +01:00
|
|
|
|
2023-04-10 14:20:38 +03:00
|
|
|
node.expand_cfg_false(self, pos, span);
|
2021-12-29 18:47:19 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
sym::cfg_attr => {
|
2023-02-18 16:23:57 +04:00
|
|
|
self.expand_cfg_attr(node, &attr, pos);
|
2021-12-29 18:47:19 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
_ => visit_clobber(node, |node| {
|
|
|
|
self.collect_attr((attr, pos, derives), node.to_annotatable(), Node::KIND)
|
|
|
|
.make_ast::<Node>()
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
None if node.is_mac_call() => {
|
|
|
|
visit_clobber(node, |node| {
|
|
|
|
// Do not clobber unless it's actually a macro (uncommon case).
|
|
|
|
let (mac, attrs, _) = node.take_mac_call();
|
|
|
|
self.check_attributes(&attrs, &mac);
|
|
|
|
self.collect_bang(mac, Node::KIND).make_ast::<Node>()
|
|
|
|
})
|
|
|
|
}
|
2024-03-15 14:21:03 +03:00
|
|
|
None if node.delegation().is_some() => unreachable!(),
|
2021-12-29 18:47:19 +08:00
|
|
|
None => {
|
2024-07-10 08:17:13 +00:00
|
|
|
assign_id!(self, node.node_id_mut(), || node.walk(self))
|
2021-12-29 18:47:19 +08:00
|
|
|
}
|
|
|
|
};
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-14 18:24:12 -05:00
|
|
|
}
|
|
|
|
|
Overhaul `syntax::fold::Folder`.
This commit changes `syntax::fold::Folder` from a functional style
(where most methods take a `T` and produce a new `T`) to a more
imperative style (where most methods take and modify a `&mut T`), and
renames it `syntax::mut_visit::MutVisitor`.
The first benefit is speed. The functional style does not require any
reallocations, due to the use of `P::map` and
`MoveMap::move_{,flat_}map`. However, every field in the AST must be
overwritten; even those fields that are unchanged are overwritten with
the same value. This causes a lot of unnecessary memory writes. The
imperative style reduces instruction counts by 1--3% across a wide range
of workloads, particularly incremental workloads.
The second benefit is conciseness; the imperative style is usually more
concise. E.g. compare the old functional style:
```
fn fold_abc(&mut self, abc: ABC) {
ABC {
a: fold_a(abc.a),
b: fold_b(abc.b),
c: abc.c,
}
}
```
with the imperative style:
```
fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
visit_a(a);
visit_b(b);
}
```
(The reductions get larger in more complex examples.)
Overall, the patch removes over 200 lines of code -- even though the new
code has more comments -- and a lot of the remaining lines have fewer
characters.
Some notes:
- The old style used methods called `fold_*`. The new style mostly uses
methods called `visit_*`, but there are a few methods that map a `T`
to something other than a `T`, which are called `flat_map_*` (`T` maps
to multiple `T`s) or `filter_map_*` (`T` maps to 0 or 1 `T`s).
- `move_map.rs`/`MoveMap`/`move_map`/`move_flat_map` are renamed
`map_in_place.rs`/`MapInPlace`/`map_in_place`/`flat_map_in_place` to
reflect their slightly changed signatures.
- Although this commit renames the `fold` module as `mut_visit`, it
keeps it in the `fold.rs` file, so as not to confuse git. The next
commit will rename the file.
2019-02-05 15:20:55 +11:00
|
|
|
impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
2022-01-05 14:15:44 +08:00
|
|
|
fn flat_map_item(&mut self, node: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
|
|
|
|
self.flat_map_node(node)
|
2021-10-17 19:32:34 +03:00
|
|
|
}
|
|
|
|
|
2024-07-08 10:40:37 +00:00
|
|
|
fn flat_map_assoc_item(
|
|
|
|
&mut self,
|
|
|
|
node: P<ast::AssocItem>,
|
|
|
|
ctxt: AssocCtxt,
|
|
|
|
) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
|
|
|
match ctxt {
|
|
|
|
AssocCtxt::Trait => self.flat_map_node(AstNodeWrapper::new(node, TraitItemTag)),
|
2025-03-25 09:00:35 +00:00
|
|
|
AssocCtxt::Impl { of_trait: false } => {
|
|
|
|
self.flat_map_node(AstNodeWrapper::new(node, ImplItemTag))
|
|
|
|
}
|
|
|
|
AssocCtxt::Impl { of_trait: true } => {
|
|
|
|
self.flat_map_node(AstNodeWrapper::new(node, TraitImplItemTag))
|
|
|
|
}
|
2024-07-08 10:40:37 +00:00
|
|
|
}
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn flat_map_foreign_item(
|
|
|
|
&mut self,
|
|
|
|
node: P<ast::ForeignItem>,
|
|
|
|
) -> SmallVec<[P<ast::ForeignItem>; 1]> {
|
|
|
|
self.flat_map_node(node)
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn flat_map_variant(&mut self, node: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
|
|
|
|
self.flat_map_node(node)
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
|
|
|
|
2025-02-05 18:58:29 +08:00
|
|
|
fn flat_map_where_predicate(
|
|
|
|
&mut self,
|
|
|
|
node: ast::WherePredicate,
|
|
|
|
) -> SmallVec<[ast::WherePredicate; 1]> {
|
|
|
|
self.flat_map_node(node)
|
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn flat_map_field_def(&mut self, node: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
|
|
|
|
self.flat_map_node(node)
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn flat_map_pat_field(&mut self, node: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
|
|
|
|
self.flat_map_node(node)
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn flat_map_expr_field(&mut self, node: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
|
|
|
|
self.flat_map_node(node)
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn flat_map_param(&mut self, node: ast::Param) -> SmallVec<[ast::Param; 1]> {
|
|
|
|
self.flat_map_node(node)
|
2013-08-29 12:10:02 -07:00
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn flat_map_generic_param(
|
|
|
|
&mut self,
|
|
|
|
node: ast::GenericParam,
|
|
|
|
) -> SmallVec<[ast::GenericParam; 1]> {
|
|
|
|
self.flat_map_node(node)
|
2013-08-29 12:10:02 -07:00
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn flat_map_arm(&mut self, node: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
|
|
|
|
self.flat_map_node(node)
|
|
|
|
}
|
2016-09-07 22:24:01 +00:00
|
|
|
|
2022-03-03 11:52:09 +01:00
|
|
|
fn flat_map_stmt(&mut self, node: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
|
2021-08-26 17:18:03 +03:00
|
|
|
// FIXME: invocations in semicolon-less expressions positions are expanded as expressions,
|
|
|
|
// changing that requires some compatibility measures.
|
2022-01-05 14:15:44 +08:00
|
|
|
if node.is_expr() {
|
|
|
|
// The only way that we can end up with a `MacCall` expression statement,
|
|
|
|
// (as opposed to a `StmtKind::MacCall`) is if we have a macro as the
|
2022-03-30 01:39:38 -04:00
|
|
|
// trailing expression in a block (e.g. `fn foo() { my_macro!() }`).
|
2022-01-05 14:15:44 +08:00
|
|
|
// Record this information, so that we can report a more specific
|
|
|
|
// `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed.
|
|
|
|
// See #78991 for an investigation of treating macros in this position
|
|
|
|
// as statements, rather than expressions, during parsing.
|
|
|
|
return match &node.kind {
|
|
|
|
StmtKind::Expr(expr)
|
2022-01-07 14:54:16 +08:00
|
|
|
if matches!(**expr, ast::Expr { kind: ExprKind::MacCall(..), .. }) =>
|
2022-01-05 14:15:44 +08:00
|
|
|
{
|
|
|
|
self.cx.current_expansion.is_trailing_mac = true;
|
|
|
|
// Don't use `assign_id` for this statement - it may get removed
|
|
|
|
// entirely due to a `#[cfg]` on the contained expression
|
2024-07-17 11:23:35 +00:00
|
|
|
let res = walk_flat_map_stmt(self, node);
|
2022-01-05 14:15:44 +08:00
|
|
|
self.cx.current_expansion.is_trailing_mac = false;
|
|
|
|
res
|
2018-03-15 23:20:56 -07:00
|
|
|
}
|
2024-07-17 11:23:35 +00:00
|
|
|
_ => walk_flat_map_stmt(self, node),
|
2022-01-05 14:15:44 +08:00
|
|
|
};
|
2016-08-30 23:03:52 +00:00
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
self.flat_map_node(node)
|
2014-12-02 10:07:41 -08:00
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn visit_crate(&mut self, node: &mut ast::Crate) {
|
|
|
|
self.visit_node(node)
|
2016-08-30 23:03:52 +00:00
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn visit_ty(&mut self, node: &mut P<ast::Ty>) {
|
|
|
|
self.visit_node(node)
|
2014-07-04 11:24:28 -07:00
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn visit_pat(&mut self, node: &mut P<ast::Pat>) {
|
|
|
|
self.visit_node(node)
|
2015-07-25 21:54:19 -07:00
|
|
|
}
|
2016-09-07 22:24:01 +00:00
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn visit_expr(&mut self, node: &mut P<ast::Expr>) {
|
2021-12-29 18:47:19 +08:00
|
|
|
// FIXME: Feature gating is performed inconsistently between `Expr` and `OptExpr`.
|
|
|
|
if let Some(attr) = node.attrs.first() {
|
2022-02-27 22:26:24 +01:00
|
|
|
self.cfg().maybe_emit_expr_attr_err(attr);
|
2021-12-29 18:47:19 +08:00
|
|
|
}
|
2022-01-05 14:15:44 +08:00
|
|
|
self.visit_node(node)
|
2018-03-10 18:16:26 -08:00
|
|
|
}
|
|
|
|
|
2022-10-23 09:22:19 +00:00
|
|
|
fn visit_method_receiver_expr(&mut self, node: &mut P<ast::Expr>) {
|
|
|
|
visit_clobber(node, |node| {
|
|
|
|
let mut wrapper = AstNodeWrapper::new(node, MethodReceiverTag);
|
|
|
|
self.visit_node(&mut wrapper);
|
|
|
|
wrapper.wrapped
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-01-05 14:15:44 +08:00
|
|
|
fn filter_map_expr(&mut self, node: P<ast::Expr>) -> Option<P<ast::Expr>> {
|
2022-05-01 20:58:24 +03:00
|
|
|
self.flat_map_node(AstNodeWrapper::new(node, OptExprTag))
|
2022-01-05 14:15:44 +08:00
|
|
|
}
|
2019-09-09 09:26:25 -03:00
|
|
|
|
2022-01-07 14:54:16 +08:00
|
|
|
fn visit_block(&mut self, node: &mut P<ast::Block>) {
|
2022-01-05 14:15:44 +08:00
|
|
|
let orig_dir_ownership = mem::replace(
|
|
|
|
&mut self.cx.current_expansion.dir_ownership,
|
|
|
|
DirOwnership::UnownedViaBlock,
|
|
|
|
);
|
2024-07-17 11:23:35 +00:00
|
|
|
walk_block(self, node);
|
2022-01-05 14:15:44 +08:00
|
|
|
self.cx.current_expansion.dir_ownership = orig_dir_ownership;
|
2018-06-02 05:10:29 +08:00
|
|
|
}
|
|
|
|
|
2022-01-07 14:54:16 +08:00
|
|
|
fn visit_id(&mut self, id: &mut NodeId) {
|
2021-07-14 18:24:12 -05:00
|
|
|
// We may have already assigned a `NodeId`
|
|
|
|
// by calling `assign_id`
|
|
|
|
if self.monotonic && *id == ast::DUMMY_NODE_ID {
|
|
|
|
*id = self.cx.resolver.next_node_id();
|
2016-09-06 05:42:45 +00:00
|
|
|
}
|
2016-09-05 00:10:27 +00:00
|
|
|
}
|
2013-07-16 15:05:50 +10:00
|
|
|
}
|
|
|
|
|
2015-02-15 21:30:45 +01:00
|
|
|
pub struct ExpansionConfig<'feat> {
|
2014-06-06 13:21:18 -07:00
|
|
|
pub crate_name: String,
|
2023-08-09 20:28:00 +08:00
|
|
|
pub features: &'feat Features,
|
2020-05-26 19:48:08 +01:00
|
|
|
pub recursion_limit: Limit,
|
2015-04-14 15:36:38 +02:00
|
|
|
pub trace_mac: bool,
|
2022-11-27 11:15:06 +00:00
|
|
|
/// If false, strip `#[test]` nodes
|
|
|
|
pub should_test: bool,
|
|
|
|
/// If true, use verbose debugging for `proc_macro::Span`
|
|
|
|
pub span_debug: bool,
|
|
|
|
/// If true, show backtraces for proc-macro panics
|
|
|
|
pub proc_macro_backtrace: bool,
|
2014-09-26 17:14:23 -07:00
|
|
|
}
|
|
|
|
|
2023-08-09 20:28:00 +08:00
|
|
|
impl ExpansionConfig<'_> {
|
|
|
|
pub fn default(crate_name: String, features: &Features) -> ExpansionConfig<'_> {
|
2014-09-26 17:14:23 -07:00
|
|
|
ExpansionConfig {
|
2017-08-06 22:54:09 -07:00
|
|
|
crate_name,
|
2023-08-09 20:28:00 +08:00
|
|
|
features,
|
2020-05-26 19:48:08 +01:00
|
|
|
recursion_limit: Limit::new(1024),
|
2015-04-14 15:36:38 +02:00
|
|
|
trace_mac: false,
|
2016-06-01 01:27:12 +00:00
|
|
|
should_test: false,
|
2020-05-31 16:20:50 -04:00
|
|
|
span_debug: false,
|
2020-08-30 22:17:24 -04:00
|
|
|
proc_macro_backtrace: false,
|
2014-09-26 17:14:23 -07:00
|
|
|
}
|
|
|
|
}
|
2014-02-28 23:17:38 -08:00
|
|
|
}
|