summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_expand
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_expand')
-rw-r--r--compiler/rustc_expand/messages.ftl5
-rw-r--r--compiler/rustc_expand/src/base.rs58
-rw-r--r--compiler/rustc_expand/src/build.rs8
-rw-r--r--compiler/rustc_expand/src/config.rs116
-rw-r--r--compiler/rustc_expand/src/errors.rs12
-rw-r--r--compiler/rustc_expand/src/expand.rs147
-rw-r--r--compiler/rustc_expand/src/lib.rs9
-rw-r--r--compiler/rustc_expand/src/mbe.rs6
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs10
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs25
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs10
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs75
-rw-r--r--compiler/rustc_expand/src/mbe/metavar_expr.rs53
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs34
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs111
-rw-r--r--compiler/rustc_expand/src/module.rs4
-rw-r--r--compiler/rustc_expand/src/parse/tests.rs35
-rw-r--r--compiler/rustc_expand/src/placeholders.rs4
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs6
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs65
-rw-r--r--compiler/rustc_expand/src/tests.rs14
21 files changed, 477 insertions, 330 deletions
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 8b9382962..475dd348e 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -35,9 +35,6 @@ expand_explain_doc_comment_outer =
expand_expr_repeat_no_syntax_vars =
attempted to repeat an expression containing no syntax variables matched as repeating at this depth
-expand_feature_included_in_edition =
- the feature `{$feature}` is included in the Rust {$edition} edition
-
expand_feature_not_allowed =
the feature `{$name}` is not in the list of allowed features
@@ -71,6 +68,8 @@ expand_macro_const_stability =
.label = invalid const stability attribute
.label2 = const stability attribute affects this macro
+expand_macro_expands_to_match_arm = macros cannot expand to match arms
+
expand_malformed_feature_attribute =
malformed `feature` attribute input
.expected = expected just one word
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index c4d2a374f..b63609c48 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -21,7 +21,7 @@ use rustc_errors::{
use rustc_feature::Features;
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, RegisteredTools};
-use rustc_parse::{self, parser, MACRO_ARGUMENTS};
+use rustc_parse::{parser, MACRO_ARGUMENTS};
use rustc_session::errors::report_lit_error;
use rustc_session::{parse::ParseSess, Limit, Session};
use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
@@ -777,7 +777,7 @@ impl SyntaxExtension {
attrs: &[ast::Attribute],
) -> SyntaxExtension {
let allow_internal_unstable =
- attr::allow_internal_unstable(sess, &attrs).collect::<Vec<Symbol>>();
+ attr::allow_internal_unstable(sess, attrs).collect::<Vec<Symbol>>();
let allow_internal_unsafe = attr::contains_name(attrs, sym::allow_internal_unsafe);
let local_inner_macros = attr::find_by_name(attrs, sym::macro_export)
@@ -790,15 +790,15 @@ impl SyntaxExtension {
.map(|attr| {
// Override `helper_attrs` passed above if it's a built-in macro,
// marking `proc_macro_derive` macros as built-in is not a realistic use case.
- parse_macro_name_and_helper_attrs(sess.diagnostic(), attr, "built-in").map_or_else(
+ parse_macro_name_and_helper_attrs(sess.dcx(), attr, "built-in").map_or_else(
|| (Some(name), Vec::new()),
|(name, helper_attrs)| (Some(name), helper_attrs),
)
})
.unwrap_or_else(|| (None, helper_attrs));
- let stability = attr::find_stability(&sess, attrs, span);
- let const_stability = attr::find_const_stability(&sess, attrs, span);
- let body_stability = attr::find_body_stability(&sess, attrs);
+ let stability = attr::find_stability(sess, attrs, span);
+ let const_stability = attr::find_const_stability(sess, attrs, span);
+ let body_stability = attr::find_body_stability(sess, attrs);
if let Some((_, sp)) = const_stability {
sess.emit_err(errors::MacroConstStability {
span: sp,
@@ -818,7 +818,7 @@ impl SyntaxExtension {
allow_internal_unstable: (!allow_internal_unstable.is_empty())
.then(|| allow_internal_unstable.into()),
stability: stability.map(|(s, _)| s),
- deprecation: attr::find_deprecation(&sess, features, attrs).map(|(d, _)| d),
+ deprecation: attr::find_deprecation(sess, features, attrs).map(|(d, _)| d),
helper_attrs,
edition,
builtin_name,
@@ -1119,7 +1119,7 @@ impl<'a> ExtCtxt<'a> {
sp: S,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
- self.sess.parse_sess.span_diagnostic.struct_span_err(sp, msg)
+ self.sess.dcx().struct_span_err(sp, msg)
}
#[track_caller]
@@ -1143,15 +1143,10 @@ impl<'a> ExtCtxt<'a> {
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
- self.sess.parse_sess.span_diagnostic.span_err(sp, msg);
+ self.sess.dcx().span_err(sp, msg);
}
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
- self.sess.parse_sess.span_diagnostic.span_warn(sp, msg);
- }
- pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<String>) -> ! {
- self.sess.parse_sess.span_diagnostic.span_bug(sp, msg);
+ pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
+ self.sess.dcx().span_bug(sp, msg);
}
pub fn trace_macros_diag(&mut self) {
for (span, notes) in self.expansions.iter() {
@@ -1165,7 +1160,7 @@ impl<'a> ExtCtxt<'a> {
self.expansions.clear();
}
pub fn bug(&self, msg: &'static str) -> ! {
- self.sess.parse_sess.span_diagnostic.bug(msg);
+ self.sess.dcx().bug(msg);
}
pub fn trace_macros(&self) -> bool {
self.ecfg.trace_mac
@@ -1213,7 +1208,7 @@ pub fn resolve_path(
span,
path: parse_sess.source_map().filename_for_diagnostics(&other).to_string(),
}
- .into_diagnostic(&parse_sess.span_diagnostic));
+ .into_diagnostic(&parse_sess.dcx));
}
};
result.pop();
@@ -1286,9 +1281,8 @@ pub fn expr_to_string(
/// Non-fatally assert that `tts` is empty. Note that this function
/// returns even when `tts` is non-empty, macros that *need* to stop
-/// compilation should call
-/// `cx.parse_sess.span_diagnostic.abort_if_errors()` (this should be
-/// done as rarely as possible).
+/// compilation should call `cx.diagnostic().abort_if_errors()`
+/// (this should be done as rarely as possible).
pub fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) {
if !tts.is_empty() {
cx.emit_err(errors::TakesNoArguments { span, name });
@@ -1356,7 +1350,7 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, tts: TokenStream) -> Option<Vec<
}
pub fn parse_macro_name_and_helper_attrs(
- diag: &rustc_errors::Handler,
+ dcx: &rustc_errors::DiagCtxt,
attr: &Attribute,
macro_type: &str,
) -> Option<(Symbol, Vec<Symbol>)> {
@@ -1365,23 +1359,23 @@ pub fn parse_macro_name_and_helper_attrs(
// `#[proc_macro_derive(Foo, attributes(A, ..))]`
let list = attr.meta_item_list()?;
if list.len() != 1 && list.len() != 2 {
- diag.emit_err(errors::AttrNoArguments { span: attr.span });
+ dcx.emit_err(errors::AttrNoArguments { span: attr.span });
return None;
}
let Some(trait_attr) = list[0].meta_item() else {
- diag.emit_err(errors::NotAMetaItem { span: list[0].span() });
+ dcx.emit_err(errors::NotAMetaItem { span: list[0].span() });
return None;
};
let trait_ident = match trait_attr.ident() {
Some(trait_ident) if trait_attr.is_word() => trait_ident,
_ => {
- diag.emit_err(errors::OnlyOneWord { span: trait_attr.span });
+ dcx.emit_err(errors::OnlyOneWord { span: trait_attr.span });
return None;
}
};
if !trait_ident.name.can_be_raw() {
- diag.emit_err(errors::CannotBeNameOfMacro {
+ dcx.emit_err(errors::CannotBeNameOfMacro {
span: trait_attr.span,
trait_ident,
macro_type,
@@ -1391,29 +1385,29 @@ pub fn parse_macro_name_and_helper_attrs(
let attributes_attr = list.get(1);
let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
if !attr.has_name(sym::attributes) {
- diag.emit_err(errors::ArgumentNotAttributes { span: attr.span() });
+ dcx.emit_err(errors::ArgumentNotAttributes { span: attr.span() });
}
attr.meta_item_list()
.unwrap_or_else(|| {
- diag.emit_err(errors::AttributesWrongForm { span: attr.span() });
+ dcx.emit_err(errors::AttributesWrongForm { span: attr.span() });
&[]
})
.iter()
.filter_map(|attr| {
let Some(attr) = attr.meta_item() else {
- diag.emit_err(errors::AttributeMetaItem { span: attr.span() });
+ dcx.emit_err(errors::AttributeMetaItem { span: attr.span() });
return None;
};
let ident = match attr.ident() {
Some(ident) if attr.is_word() => ident,
_ => {
- diag.emit_err(errors::AttributeSingleWord { span: attr.span });
+ dcx.emit_err(errors::AttributeSingleWord { span: attr.span });
return None;
}
};
if !ident.name.can_be_raw() {
- diag.emit_err(errors::HelperAttributeNameInvalid {
+ dcx.emit_err(errors::HelperAttributeNameInvalid {
span: attr.span,
name: ident,
});
@@ -1464,7 +1458,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &ParseSess) -> bool {
if crate_matches {
sess.buffer_lint_with_diagnostic(
- &PROC_MACRO_BACK_COMPAT,
+ PROC_MACRO_BACK_COMPAT,
item.ident.span,
ast::CRATE_NODE_ID,
"using an old version of `rental`",
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 7de469944..86f555fa0 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -4,7 +4,7 @@ use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, PatKind,
use rustc_ast::{attr, token, util::literal};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
use thin_vec::{thin_vec, ThinVec};
impl<'a> ExtCtxt<'a> {
@@ -135,7 +135,7 @@ impl<'a> ExtCtxt<'a> {
ast::GenericBound::Trait(
self.poly_trait_ref(path.span, path),
if is_const {
- ast::TraitBoundModifier::MaybeConst
+ ast::TraitBoundModifier::MaybeConst(DUMMY_SP)
} else {
ast::TraitBoundModifier::None
},
@@ -505,7 +505,7 @@ impl<'a> ExtCtxt<'a> {
attrs: AttrVec::new(),
pat,
guard: None,
- body: expr,
+ body: Some(expr),
span,
id: ast::DUMMY_NODE_ID,
is_placeholder: false,
@@ -547,7 +547,7 @@ impl<'a> ExtCtxt<'a> {
binder: ast::ClosureBinder::NotPresent,
capture_clause: ast::CaptureBy::Ref,
constness: ast::Const::No,
- asyncness: ast::Async::No,
+ coroutine_kind: None,
movability: ast::Movability::Movable,
fn_decl,
body,
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index bef487659..0b56dbb2c 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -1,25 +1,22 @@
//! Conditional compilation stripping.
use crate::errors::{
- FeatureIncludedInEdition, FeatureNotAllowed, FeatureRemoved, FeatureRemovedReason, InvalidCfg,
- MalformedFeatureAttribute, MalformedFeatureAttributeHelp, RemoveExprNotSupported,
+ FeatureNotAllowed, FeatureRemoved, FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute,
+ MalformedFeatureAttributeHelp, RemoveExprNotSupported,
};
use rustc_ast::ptr::P;
use rustc_ast::token::{Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree};
-use rustc_ast::tokenstream::{DelimSpan, Spacing};
+use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, DelimSpacing, DelimSpan, Spacing};
use rustc_ast::tokenstream::{LazyAttrTokenStream, TokenTree};
use rustc_ast::NodeId;
use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem};
use rustc_attr as attr;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
-use rustc_data_structures::fx::FxHashSet;
use rustc_feature::Features;
use rustc_feature::{ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES};
use rustc_parse::validate_attr;
use rustc_session::parse::feature_err;
use rustc_session::Session;
-use rustc_span::edition::ALL_EDITIONS;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use thin_vec::ThinVec;
@@ -48,40 +45,6 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
let mut features = Features::default();
- // The edition from `--edition`.
- let crate_edition = sess.edition();
-
- // The maximum of (a) the edition from `--edition` and (b) any edition
- // umbrella feature-gates declared in the code.
- // - E.g. if `crate_edition` is 2015 but `rust_2018_preview` is present,
- // `feature_edition` is 2018
- let mut features_edition = crate_edition;
- for attr in krate_attrs {
- for mi in feature_list(attr) {
- if mi.is_word() {
- let name = mi.name_or_empty();
- let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
- if let Some(edition) = edition
- && edition > features_edition
- {
- features_edition = edition;
- }
- }
- }
- }
-
- // Enable edition-dependent features based on `features_edition`.
- // - E.g. enable `test_2018_feature` if `features_edition` is 2018 or higher
- let mut edition_enabled_features = FxHashSet::default();
- for f in UNSTABLE_FEATURES {
- if let Some(edition) = f.feature.edition && edition <= features_edition {
- // FIXME(Manishearth) there is currently no way to set lib features by
- // edition.
- edition_enabled_features.insert(f.feature.name);
- (f.set_enabled)(&mut features);
- }
- }
-
// Process all features declared in the code.
for attr in krate_attrs {
for mi in feature_list(attr) {
@@ -106,38 +69,6 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
}
};
- // If the declared feature is an edition umbrella feature-gate,
- // warn if it was redundant w.r.t. `crate_edition`.
- // - E.g. warn if `rust_2018_preview` is declared when
- // `crate_edition` is 2018
- // - E.g. don't warn if `rust_2018_preview` is declared when
- // `crate_edition` is 2015.
- if let Some(&edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
- if edition <= crate_edition {
- sess.emit_warning(FeatureIncludedInEdition {
- span: mi.span(),
- feature: name,
- edition,
- });
- }
- features.set_declared_lang_feature(name, mi.span(), None);
- continue;
- }
-
- // If the declared feature is edition-dependent and was already
- // enabled due to `feature_edition`, give a warning.
- // - E.g. warn if `test_2018_feature` is declared when
- // `feature_edition` is 2018 or higher.
- if edition_enabled_features.contains(&name) {
- sess.emit_warning(FeatureIncludedInEdition {
- span: mi.span(),
- feature: name,
- edition: features_edition,
- });
- features.set_declared_lang_feature(name, mi.span(), None);
- continue;
- }
-
// If the declared feature has been removed, issue an error.
if let Some(f) = REMOVED_FEATURES.iter().find(|f| name == f.feature.name) {
sess.emit_err(FeatureRemoved {
@@ -240,7 +171,7 @@ impl<'a> StripUnconfigured<'a> {
stream.0.iter().all(|tree| match tree {
AttrTokenTree::Attributes(_) => false,
AttrTokenTree::Token(..) => true,
- AttrTokenTree::Delimited(_, _, inner) => can_skip(inner),
+ AttrTokenTree::Delimited(.., inner) => can_skip(inner),
})
}
@@ -251,8 +182,7 @@ impl<'a> StripUnconfigured<'a> {
let trees: Vec<_> = stream
.0
.iter()
- .flat_map(|tree| {
- match tree.clone() {
+ .flat_map(|tree| match tree.clone() {
AttrTokenTree::Attributes(mut data) => {
data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
@@ -265,9 +195,9 @@ impl<'a> StripUnconfigured<'a> {
None.into_iter()
}
}
- AttrTokenTree::Delimited(sp, delim, mut inner) => {
+ AttrTokenTree::Delimited(sp, spacing, delim, mut inner) => {
inner = self.configure_tokens(&inner);
- Some(AttrTokenTree::Delimited(sp, delim, inner)).into_iter()
+ Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)).into_iter()
}
AttrTokenTree::Token(ref token, _)
if let TokenKind::Interpolated(nt) = &token.kind =>
@@ -277,7 +207,6 @@ impl<'a> StripUnconfigured<'a> {
AttrTokenTree::Token(token, spacing) => {
Some(AttrTokenTree::Token(token, spacing)).into_iter()
}
- }
})
.collect();
AttrTokenStream::new(trees)
@@ -372,27 +301,32 @@ impl<'a> StripUnconfigured<'a> {
};
let pound_span = pound_token.span;
- let mut trees = vec![AttrTokenTree::Token(pound_token, Spacing::Alone)];
- if attr.style == AttrStyle::Inner {
- // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
- let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) =
- orig_trees.next().unwrap().clone()
- else {
- panic!("Bad tokens for attribute {attr:?}");
- };
- trees.push(AttrTokenTree::Token(bang_token, Spacing::Alone));
- }
// We don't really have a good span to use for the synthesized `[]`
// in `#[attr]`, so just use the span of the `#` token.
let bracket_group = AttrTokenTree::Delimited(
DelimSpan::from_single(pound_span),
+ DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
Delimiter::Bracket,
item.tokens
.as_ref()
.unwrap_or_else(|| panic!("Missing tokens for {item:?}"))
.to_attr_token_stream(),
);
- trees.push(bracket_group);
+ let trees = if attr.style == AttrStyle::Inner {
+ // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
+ let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) =
+ orig_trees.next().unwrap().clone()
+ else {
+ panic!("Bad tokens for attribute {attr:?}");
+ };
+ vec![
+ AttrTokenTree::Token(pound_token, Spacing::Joint),
+ AttrTokenTree::Token(bang_token, Spacing::JointHidden),
+ bracket_group,
+ ]
+ } else {
+ vec![AttrTokenTree::Token(pound_token, Spacing::JointHidden), bracket_group]
+ };
let tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::new(trees)));
let attr = attr::mk_attr_from_item(
&self.sess.parse_sess.attr_id_generator,
@@ -434,9 +368,9 @@ impl<'a> StripUnconfigured<'a> {
}
};
(
- parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
+ parse_cfg(&meta_item, self.sess).map_or(true, |meta_item| {
attr::cfg_matches(
- &meta_item,
+ meta_item,
&self.sess.parse_sess,
self.lint_node_id,
self.features,
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index d86632c47..2b43fae68 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -1,7 +1,6 @@
use rustc_ast::ast;
use rustc_macros::Diagnostic;
use rustc_session::Limit;
-use rustc_span::edition::Edition;
use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent};
use rustc_span::{Span, Symbol};
use std::borrow::Cow;
@@ -169,15 +168,6 @@ pub(crate) struct TakesNoArguments<'a> {
}
#[derive(Diagnostic)]
-#[diag(expand_feature_included_in_edition, code = "E0705")]
-pub(crate) struct FeatureIncludedInEdition {
- #[primary_span]
- pub span: Span,
- pub feature: Symbol,
- pub edition: Edition,
-}
-
-#[derive(Diagnostic)]
#[diag(expand_feature_removed, code = "E0557")]
pub(crate) struct FeatureRemoved<'a> {
#[primary_span]
@@ -304,6 +294,8 @@ pub(crate) struct IncompleteParse<'a> {
pub label_span: Span,
pub macro_path: &'a ast::Path,
pub kind_name: &'a str,
+ #[note(expand_macro_expands_to_match_arm)]
+ pub expands_to_match_arm: Option<()>,
#[suggestion(
expand_suggestion_add_semi,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index f87f4aba2..89caf8aa2 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -41,6 +41,7 @@ use std::path::PathBuf;
use std::rc::Rc;
use std::{iter, mem};
+#[cfg(bootstrap)]
macro_rules! ast_fragments {
(
$($Kind:ident($AstTy:ty) {
@@ -165,6 +166,131 @@ macro_rules! ast_fragments {
}
}
+#[cfg(not(bootstrap))]
+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 {
+ pub fn add_placeholders(&mut self, placeholders: &[NodeId]) {
+ 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")
+ }
+ }
+
+ pub fn make_opt_expr(self) -> Option<P<ast::Expr>> {
+ match self {
+ AstFragment::OptExpr(expr) => expr,
+ _ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
+ }
+ }
+
+ pub fn make_method_receiver_expr(self) -> P<ast::Expr> {
+ match self {
+ AstFragment::MethodReceiverExpr(expr) => expr,
+ _ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
+ }
+ }
+
+ $(pub fn $make_ast(self) -> $AstTy {
+ match self {
+ AstFragment::$Kind(ast) => ast,
+ _ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
+ }
+ })*
+
+ fn make_ast<T: InvocationCollectorNode>(self) -> T::OutputTy {
+ T::fragment_to_output(self)
+ }
+
+ pub fn mut_visit_with<F: MutVisitor>(&mut self, vis: &mut F) {
+ match self {
+ AstFragment::OptExpr(opt_expr) => {
+ visit_clobber(opt_expr, |opt_expr| {
+ if let Some(expr) = opt_expr {
+ vis.filter_map_expr(expr)
+ } else {
+ None
+ }
+ });
+ }
+ AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr),
+ $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)*
+ $($(AstFragment::$Kind(ast) =>
+ ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)*
+ }
+ }
+
+ pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
+ match self {
+ AstFragment::OptExpr(Some(expr)) => visitor.visit_expr(expr),
+ AstFragment::OptExpr(None) => {}
+ AstFragment::MethodReceiverExpr(expr) => visitor.visit_method_receiver_expr(expr),
+ $($(AstFragment::$Kind(ast) => visitor.$visit_ast(ast),)?)*
+ $($(AstFragment::$Kind(ast) => for ast_elt in &ast[..] {
+ visitor.$visit_ast_elt(ast_elt, $($args)*);
+ })?)*
+ }
+ }
+ }
+
+ impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> {
+ $(fn $make_ast(self: Box<crate::mbe::macro_rules::ParserAnyMacro<'a>>)
+ -> Option<$AstTy> {
+ Some(self.make(AstFragmentKind::$Kind).$make_ast())
+ })*
+ }
+ }
+}
+
ast_fragments! {
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; }
@@ -435,7 +561,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
invocations = mem::take(&mut undetermined_invocations);
force = !mem::replace(&mut progress, false);
if force && self.monotonic {
- self.cx.sess.delay_span_bug(
+ self.cx.sess.span_delayed_bug(
invocations.last().unwrap().0.span(),
"expansion entered force mode without producing any errors",
);
@@ -955,12 +1081,15 @@ pub fn ensure_complete_parse<'a>(
_ => None,
};
+ let expands_to_match_arm = kind_name == "pattern" && parser.token == token::FatArrow;
+
parser.sess.emit_err(IncompleteParse {
span: def_site_span,
token,
label_span: span,
macro_path,
kind_name,
+ expands_to_match_arm: expands_to_match_arm.then_some(()),
add_semicolon,
});
}
@@ -1096,7 +1225,7 @@ impl InvocationCollectorNode for P<ast::Item> {
ModKind::Loaded(_, inline, _) => {
// Inline `mod foo { ... }`, but we still need to push directories.
let (dir_path, dir_ownership) = mod_dir_path(
- &ecx.sess,
+ ecx.sess,
ident,
&attrs,
&ecx.current_expansion.module,
@@ -1111,7 +1240,7 @@ impl InvocationCollectorNode for P<ast::Item> {
let old_attrs_len = attrs.len();
let ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership } =
parse_external_mod(
- &ecx.sess,
+ ecx.sess,
ident,
span,
&ecx.current_expansion.module,
@@ -1168,14 +1297,14 @@ impl InvocationCollectorNode for P<ast::Item> {
ast::UseTreeKind::Simple(_) => idents.push(ut.ident()),
ast::UseTreeKind::Nested(nested) => {
for (ut, _) in nested {
- collect_use_tree_leaves(&ut, idents);
+ collect_use_tree_leaves(ut, idents);
}
}
}
}
let mut idents = Vec::new();
- collect_use_tree_leaves(&ut, &mut idents);
+ collect_use_tree_leaves(ut, &mut idents);
return idents;
}
@@ -1531,7 +1660,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> {
}
}
fn pre_flat_map_node_collect_attr(cfg: &StripUnconfigured<'_>, attr: &ast::Attribute) {
- cfg.maybe_emit_expr_attr_err(&attr);
+ cfg.maybe_emit_expr_attr_err(attr);
}
}
@@ -1580,7 +1709,7 @@ struct InvocationCollector<'a, 'b> {
impl<'a, 'b> InvocationCollector<'a, 'b> {
fn cfg(&self) -> StripUnconfigured<'_> {
StripUnconfigured {
- sess: &self.cx.sess,
+ sess: self.cx.sess,
features: Some(self.cx.ecfg.features),
config_tokens: false,
lint_node_id: self.cx.current_expansion.lint_node_id,
@@ -1693,7 +1822,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
if attr.is_doc_comment() {
self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
- &UNUSED_DOC_COMMENTS,
+ UNUSED_DOC_COMMENTS,
current_span,
self.cx.current_expansion.lint_node_id,
"unused doc comment",
@@ -1705,7 +1834,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
// eagerly evaluated.
if attr_name != sym::cfg && attr_name != sym::cfg_attr {
self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
- &UNUSED_ATTRIBUTES,
+ UNUSED_ATTRIBUTES,
attr.span,
self.cx.current_expansion.lint_node_id,
format!("unused attribute `{attr_name}`"),
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 5a774164a..bed667048 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,5 +1,5 @@
-#![cfg_attr(not(bootstrap), doc(rust_logo))]
-#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![doc(rust_logo)]
+#![feature(rustdoc_internals)]
#![feature(array_windows)]
#![feature(associated_type_bounds)]
#![feature(associated_type_defaults)]
@@ -23,9 +23,6 @@ extern crate tracing;
extern crate proc_macro as pm;
-use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_fluent_macro::fluent_messages;
-
mod placeholders;
mod proc_macro_server;
@@ -67,4 +64,4 @@ mod mut_visit {
mod tests;
}
-fluent_messages! { "../messages.ftl" }
+rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs
index a43b2a001..ca4a1f327 100644
--- a/compiler/rustc_expand/src/mbe.rs
+++ b/compiler/rustc_expand/src/mbe.rs
@@ -13,7 +13,7 @@ pub(crate) mod transcribe;
use metavar_expr::MetaVarExpr;
use rustc_ast::token::{Delimiter, NonterminalKind, Token, TokenKind};
-use rustc_ast::tokenstream::DelimSpan;
+use rustc_ast::tokenstream::{DelimSpacing, DelimSpan};
use rustc_span::symbol::Ident;
use rustc_span::Span;
@@ -68,7 +68,7 @@ pub(crate) enum KleeneOp {
enum TokenTree {
Token(Token),
/// A delimited sequence, e.g. `($e:expr)` (RHS) or `{ $e }` (LHS).
- Delimited(DelimSpan, Delimited),
+ Delimited(DelimSpan, DelimSpacing, Delimited),
/// A kleene-style repetition sequence, e.g. `$($e:expr)*` (RHS) or `$($e),*` (LHS).
Sequence(DelimSpan, SequenceRepetition),
/// e.g., `$var`.
@@ -99,7 +99,7 @@ impl TokenTree {
TokenTree::Token(Token { span, .. })
| TokenTree::MetaVar(span, _)
| TokenTree::MetaVarDecl(span, _, _) => span,
- TokenTree::Delimited(span, _)
+ TokenTree::Delimited(span, ..)
| TokenTree::MetaVarExpr(span, _)
| TokenTree::Sequence(span, _) => span.entire(),
}
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index e06037564..8f80e6e29 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -34,7 +34,7 @@ pub(super) fn failed_to_match_macro<'cx>(
if try_success_result.is_ok() {
// Nonterminal parser recovery might turn failed matches into successful ones,
// but for that it must have emitted an error already
- tracker.cx.sess.delay_span_bug(sp, "Macro matching returned a success on the second try");
+ tracker.cx.sess.span_delayed_bug(sp, "Macro matching returned a success on the second try");
}
if let Some(result) = tracker.result {
@@ -67,6 +67,12 @@ pub(super) fn failed_to_match_macro<'cx>(
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|| matches!(token.kind, TokenKind::Interpolated(_)))
{
+ if let TokenKind::Interpolated(node) = &expected_token.kind {
+ err.span_label(node.1, "");
+ }
+ if let TokenKind::Interpolated(node) = &token.kind {
+ err.span_label(node.1, "");
+ }
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
@@ -145,7 +151,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
Success(_) => {
// Nonterminal parser recovery might turn failed matches into successful ones,
// but for that it must have emitted an error already
- self.cx.sess.delay_span_bug(
+ self.cx.sess.span_delayed_bug(
self.root_span,
"should not collect detailed info for successful macro match",
);
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index 95f5bb2d2..e66cfbe6f 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -205,7 +205,7 @@ pub(super) fn check_meta_variables(
rhses: &[TokenTree],
) -> bool {
if lhses.len() != rhses.len() {
- sess.span_diagnostic.span_bug(span, "length mismatch between LHSes and RHSes")
+ sess.dcx.span_bug(span, "length mismatch between LHSes and RHSes")
}
let mut valid = true;
for (lhs, rhs) in iter::zip(lhses, rhses) {
@@ -244,7 +244,7 @@ fn check_binders(
// MetaVar(fragment) and not as MetaVarDecl(y, fragment).
TokenTree::MetaVar(span, name) => {
if macros.is_empty() {
- sess.span_diagnostic.span_bug(span, "unexpected MetaVar in lhs");
+ sess.dcx.span_bug(span, "unexpected MetaVar in lhs");
}
let name = MacroRulesNormalizedIdent::new(name);
// There are 3 possibilities:
@@ -275,14 +275,13 @@ fn check_binders(
);
}
if !macros.is_empty() {
- sess.span_diagnostic.span_bug(span, "unexpected MetaVarDecl in nested lhs");
+ sess.dcx.span_bug(span, "unexpected MetaVarDecl in nested lhs");
}
let name = MacroRulesNormalizedIdent::new(name);
if let Some(prev_info) = get_binder_info(macros, binders, name) {
// Duplicate binders at the top-level macro definition are errors. The lint is only
// for nested macro definitions.
- sess.span_diagnostic
- .emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span });
+ sess.dcx.emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span });
*valid = false;
} else {
binders.insert(name, BinderInfo { span, ops: ops.into() });
@@ -290,7 +289,7 @@ fn check_binders(
}
// `MetaVarExpr` can not appear in the LHS of a macro arm
TokenTree::MetaVarExpr(..) => {}
- TokenTree::Delimited(_, ref del) => {
+ TokenTree::Delimited(.., ref del) => {
for tt in &del.tts {
check_binders(sess, node_id, tt, macros, binders, ops, valid);
}
@@ -341,7 +340,7 @@ fn check_occurrences(
match *rhs {
TokenTree::Token(..) => {}
TokenTree::MetaVarDecl(span, _name, _kind) => {
- sess.span_diagnostic.span_bug(span, "unexpected MetaVarDecl in rhs")
+ sess.dcx.span_bug(span, "unexpected MetaVarDecl in rhs")
}
TokenTree::MetaVar(span, name) => {
let name = MacroRulesNormalizedIdent::new(name);
@@ -353,7 +352,7 @@ fn check_occurrences(
};
check_ops_is_prefix(sess, node_id, macros, binders, ops, dl.entire(), name);
}
- TokenTree::Delimited(_, ref del) => {
+ TokenTree::Delimited(.., ref del) => {
check_nested_occurrences(sess, node_id, &del.tts, macros, binders, ops, valid);
}
TokenTree::Sequence(_, ref seq) => {
@@ -435,8 +434,8 @@ fn check_nested_occurrences(
// We check that the meta-variable is correctly used.
check_occurrences(sess, node_id, tt, macros, binders, ops, valid);
}
- (NestedMacroState::MacroRulesNotName, TokenTree::Delimited(_, del))
- | (NestedMacroState::MacroName, TokenTree::Delimited(_, del))
+ (NestedMacroState::MacroRulesNotName, TokenTree::Delimited(.., del))
+ | (NestedMacroState::MacroName, TokenTree::Delimited(.., del))
if del.delim == Delimiter::Brace =>
{
let macro_rules = state == NestedMacroState::MacroRulesNotName;
@@ -466,7 +465,7 @@ fn check_nested_occurrences(
// We check that the meta-variable is correctly used.
check_occurrences(sess, node_id, tt, macros, binders, ops, valid);
}
- (NestedMacroState::MacroName, TokenTree::Delimited(_, del))
+ (NestedMacroState::MacroName, TokenTree::Delimited(.., del))
if del.delim == Delimiter::Parenthesis =>
{
state = NestedMacroState::MacroNameParen;
@@ -481,7 +480,7 @@ fn check_nested_occurrences(
valid,
);
}
- (NestedMacroState::MacroNameParen, TokenTree::Delimited(_, del))
+ (NestedMacroState::MacroNameParen, TokenTree::Delimited(.., del))
if del.delim == Delimiter::Brace =>
{
state = NestedMacroState::Empty;
@@ -650,6 +649,6 @@ fn buffer_lint(
) {
// Macros loaded from other crates have dummy node ids.
if node_id != DUMMY_NODE_ID {
- sess.buffer_lint(&META_VARIABLE_MISUSE, span, node_id, message);
+ sess.buffer_lint(META_VARIABLE_MISUSE, span, node_id, message);
}
}
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 7e85beaad..b248a1fe3 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -184,7 +184,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> {
TokenTree::Token(token) => {
locs.push(MatcherLoc::Token { token: token.clone() });
}
- TokenTree::Delimited(span, delimited) => {
+ TokenTree::Delimited(span, _, delimited) => {
let open_token = Token::new(token::OpenDelim(delimited.delim), span.open);
let close_token = Token::new(token::CloseDelim(delimited.delim), span.close);
@@ -335,7 +335,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
.map(|tt| match tt {
TokenTree::MetaVarDecl(..) => 1,
TokenTree::Sequence(_, seq) => seq.num_captures,
- TokenTree::Delimited(_, delim) => count_metavar_decls(&delim.tts),
+ TokenTree::Delimited(.., delim) => count_metavar_decls(&delim.tts),
TokenTree::Token(..) => 0,
TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
})
@@ -397,7 +397,7 @@ pub(crate) enum NamedMatch {
MatchedTokenTree(rustc_ast::tokenstream::TokenTree),
// A metavar match of any type other than `tt`.
- MatchedNonterminal(Lrc<Nonterminal>),
+ MatchedNonterminal(Lrc<(Nonterminal, rustc_span::Span)>),
}
/// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
@@ -483,7 +483,7 @@ impl TtParser {
if matches!(t, Token { kind: DocComment(..), .. }) {
mp.idx += 1;
self.cur_mps.push(mp);
- } else if token_name_eq(&t, token) {
+ } else if token_name_eq(t, token) {
mp.idx += 1;
self.next_mps.push(mp);
}
@@ -692,7 +692,7 @@ impl TtParser {
Ok(nt) => nt,
};
let m = match nt {
- ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new(nt)),
+ ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new((nt, span))),
ParseNtResult::Tt(tt) => MatchedTokenTree(tt),
};
mp.push_match(next_metavar, seq_depth, m);
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index ebdd3cb54..44f10e7d3 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -207,13 +207,13 @@ fn expand_macro<'cx>(
match try_success_result {
Ok((i, named_matches)) => {
let (rhs, rhs_span): (&mbe::Delimited, DelimSpan) = match &rhses[i] {
- mbe::TokenTree::Delimited(span, delimited) => (&delimited, *span),
+ mbe::TokenTree::Delimited(span, _, delimited) => (&delimited, *span),
_ => cx.span_bug(sp, "malformed macro rhs"),
};
let arm_span = rhses[i].span();
// rhs has holes ( `$id` and `$(...)` that need filled)
- let mut tts = match transcribe(cx, &named_matches, &rhs, rhs_span, transparency) {
+ let mut tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) {
Ok(tts) => tts,
Err(mut err) => {
err.emit();
@@ -236,6 +236,13 @@ fn expand_macro<'cx>(
target_sp.open = source_sp.open.with_ctxt(ctxt);
target_sp.close = source_sp.close.with_ctxt(ctxt);
}
+ (
+ TokenTree::Delimited(target_sp, ..),
+ mbe::TokenTree::MetaVar(source_sp, ..),
+ ) => {
+ target_sp.open = source_sp.with_ctxt(ctxt);
+ target_sp.close = source_sp.with_ctxt(ctxt).shrink_to_hi();
+ }
_ => {
let sp = rhs_tt.span().with_ctxt(ctxt);
tt.set_span(sp);
@@ -395,7 +402,7 @@ pub fn compile_declarative_macro(
};
let dummy_syn_ext = || (mk_syn_ext(Box::new(macro_rules_dummy_expander)), Vec::new());
- let diag = &sess.parse_sess.span_diagnostic;
+ let dcx = &sess.parse_sess.dcx;
let lhs_nm = Ident::new(sym::lhs, def.span);
let rhs_nm = Ident::new(sym::rhs, def.span);
let tt_spec = Some(NonterminalKind::TT);
@@ -475,17 +482,14 @@ pub fn compile_declarative_macro(
let s = parse_failure_msg(&token);
let sp = token.span.substitute_dummy(def.span);
- let mut err = sess.parse_sess.span_diagnostic.struct_span_err(sp, s);
+ let mut err = sess.dcx().struct_span_err(sp, s);
err.span_label(sp, msg);
annotate_doc_comment(&mut err, sess.source_map(), sp);
err.emit();
return dummy_syn_ext();
}
Error(sp, msg) => {
- sess.parse_sess
- .span_diagnostic
- .struct_span_err(sp.substitute_dummy(def.span), msg)
- .emit();
+ sess.dcx().struct_span_err(sp.substitute_dummy(def.span), msg).emit();
return dummy_syn_ext();
}
ErrorReported(_) => {
@@ -511,13 +515,13 @@ pub fn compile_declarative_macro(
)
.pop()
.unwrap();
- valid &= check_lhs_nt_follows(&sess.parse_sess, &def, &tt);
+ valid &= check_lhs_nt_follows(&sess.parse_sess, def, &tt);
return tt;
}
- sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
+ sess.dcx().span_bug(def.span, "wrong-structured lhs")
})
.collect::<Vec<mbe::TokenTree>>(),
- _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"),
+ _ => sess.dcx().span_bug(def.span, "wrong-structured lhs"),
};
let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] {
@@ -536,10 +540,10 @@ pub fn compile_declarative_macro(
.pop()
.unwrap();
}
- sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs")
+ sess.dcx().span_bug(def.span, "wrong-structured rhs")
})
.collect::<Vec<mbe::TokenTree>>(),
- _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"),
+ _ => sess.dcx().span_bug(def.span, "wrong-structured rhs"),
};
for rhs in &rhses {
@@ -556,10 +560,10 @@ pub fn compile_declarative_macro(
let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules);
match transparency_error {
Some(TransparencyError::UnknownTransparency(value, span)) => {
- diag.span_err(span, format!("unknown macro transparency: `{value}`"));
+ dcx.span_err(span, format!("unknown macro transparency: `{value}`"));
}
Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) => {
- diag.span_err(vec![old_span, new_span], "multiple macro transparency attributes");
+ dcx.span_err(vec![old_span, new_span], "multiple macro transparency attributes");
}
None => {}
}
@@ -592,10 +596,10 @@ pub fn compile_declarative_macro(
.map(|lhs| {
// Ignore the delimiters around the matcher.
match lhs {
- mbe::TokenTree::Delimited(_, delimited) => {
+ mbe::TokenTree::Delimited(.., delimited) => {
mbe::macro_parser::compute_locs(&delimited.tts)
}
- _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "malformed macro lhs"),
+ _ => sess.dcx().span_bug(def.span, "malformed macro lhs"),
}
})
.collect()
@@ -618,11 +622,11 @@ pub fn compile_declarative_macro(
fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree) -> bool {
// lhs is going to be like TokenTree::Delimited(...), where the
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
- if let mbe::TokenTree::Delimited(_, delimited) = lhs {
+ if let mbe::TokenTree::Delimited(.., delimited) = lhs {
check_matcher(sess, def, &delimited.tts)
} else {
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
- sess.span_diagnostic.span_err(lhs.span(), msg);
+ sess.dcx.span_err(lhs.span(), msg);
false
}
// we don't abort on errors on rejection, the driver will do that for us
@@ -648,10 +652,7 @@ fn is_empty_token_tree(sess: &ParseSess, seq: &mbe::SequenceRepetition) -> bool
iter.next();
}
let span = t.span.to(now.span);
- sess.span_diagnostic.span_note_without_error(
- span,
- "doc comments are ignored in matcher position",
- );
+ sess.dcx.span_note(span, "doc comments are ignored in matcher position");
}
mbe::TokenTree::Sequence(_, sub_seq)
if (sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
@@ -673,7 +674,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
| TokenTree::MetaVar(..)
| TokenTree::MetaVarDecl(..)
| TokenTree::MetaVarExpr(..) => (),
- TokenTree::Delimited(_, del) => {
+ TokenTree::Delimited(.., del) => {
if !check_lhs_no_empty_seq(sess, &del.tts) {
return false;
}
@@ -681,7 +682,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
TokenTree::Sequence(span, seq) => {
if is_empty_token_tree(sess, seq) {
let sp = span.entire();
- sess.span_diagnostic.span_err(sp, "repetition matches empty token tree");
+ sess.dcx.span_err(sp, "repetition matches empty token tree");
return false;
}
if !check_lhs_no_empty_seq(sess, &seq.tts) {
@@ -698,7 +699,7 @@ fn check_rhs(sess: &ParseSess, rhs: &mbe::TokenTree) -> bool {
match *rhs {
mbe::TokenTree::Delimited(..) => return true,
_ => {
- sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited");
+ sess.dcx.span_err(rhs.span(), "macro rhs must be delimited");
}
}
false
@@ -707,21 +708,21 @@ fn check_rhs(sess: &ParseSess, rhs: &mbe::TokenTree) -> bool {
fn check_matcher(sess: &ParseSess, def: &ast::Item, matcher: &[mbe::TokenTree]) -> bool {
let first_sets = FirstSets::new(matcher);
let empty_suffix = TokenSet::empty();
- let err = sess.span_diagnostic.err_count();
+ let err = sess.dcx.err_count();
check_matcher_core(sess, def, &first_sets, matcher, &empty_suffix);
- err == sess.span_diagnostic.err_count()
+ err == sess.dcx.err_count()
}
fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool {
match rhs {
- mbe::TokenTree::Delimited(_sp, d) => {
+ mbe::TokenTree::Delimited(.., d) => {
let has_compile_error = d.tts.array_windows::<3>().any(|[ident, bang, args]| {
if let mbe::TokenTree::Token(ident) = ident
&& let TokenKind::Ident(ident, _) = ident.kind
&& ident == sym::compile_error
&& let mbe::TokenTree::Token(bang) = bang
&& let TokenKind::Not = bang.kind
- && let mbe::TokenTree::Delimited(_, del) = args
+ && let mbe::TokenTree::Delimited(.., del) = args
&& del.delim != Delimiter::Invisible
{
true
@@ -778,7 +779,7 @@ impl<'tt> FirstSets<'tt> {
| TokenTree::MetaVarExpr(..) => {
first.replace_with(TtHandle::TtRef(tt));
}
- TokenTree::Delimited(span, delimited) => {
+ TokenTree::Delimited(span, _, delimited) => {
build_recur(sets, &delimited.tts);
first.replace_with(TtHandle::from_token_kind(
token::OpenDelim(delimited.delim),
@@ -847,7 +848,7 @@ impl<'tt> FirstSets<'tt> {
first.add_one(TtHandle::TtRef(tt));
return first;
}
- TokenTree::Delimited(span, delimited) => {
+ TokenTree::Delimited(span, _, delimited) => {
first.add_one(TtHandle::from_token_kind(
token::OpenDelim(delimited.delim),
span.open,
@@ -927,7 +928,7 @@ impl<'tt> TtHandle<'tt> {
fn get(&'tt self) -> &'tt mbe::TokenTree {
match self {
TtHandle::TtRef(tt) => tt,
- TtHandle::Token(token_tt) => &token_tt,
+ TtHandle::Token(token_tt) => token_tt,
}
}
}
@@ -1092,7 +1093,7 @@ fn check_matcher_core<'tt>(
suffix_first = build_suffix_first();
}
}
- TokenTree::Delimited(span, d) => {
+ TokenTree::Delimited(span, _, d) => {
let my_suffix = TokenSet::singleton(TtHandle::from_token_kind(
token::CloseDelim(d.delim),
span.close,
@@ -1170,7 +1171,7 @@ fn check_matcher_core<'tt>(
Some(NonterminalKind::PatParam { inferred: false }),
));
sess.buffer_lint_with_diagnostic(
- &RUST_2021_INCOMPATIBLE_OR_PATTERNS,
+ RUST_2021_INCOMPATIBLE_OR_PATTERNS,
span,
ast::CRATE_NODE_ID,
"the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro",
@@ -1188,7 +1189,7 @@ fn check_matcher_core<'tt>(
};
let sp = next_token.span();
- let mut err = sess.span_diagnostic.struct_span_err(
+ let mut err = sess.dcx.struct_span_err(
sp,
format!(
"`${name}:{frag}` {may_be} followed by `{next}`, which \
@@ -1407,7 +1408,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
match tt {
- mbe::TokenTree::Token(token) => pprust::token_to_string(&token).into(),
+ mbe::TokenTree::Token(token) => pprust::token_to_string(token).into(),
mbe::TokenTree::MetaVar(_, name) => format!("${name}"),
mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${name}:{kind}"),
mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${name}:"),
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index 7cb279a98..e3dc73d0d 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -10,9 +10,8 @@ use rustc_span::Span;
/// A meta-variable expression, for expansions based on properties of meta-variables.
#[derive(Debug, Clone, PartialEq, Encodable, Decodable)]
pub(crate) enum MetaVarExpr {
- /// The number of repetitions of an identifier, optionally limited to a number
- /// of outer-most repetition depths. If the depth limit is `None` then the depth is unlimited.
- Count(Ident, Option<usize>),
+ /// The number of repetitions of an identifier.
+ Count(Ident, usize),
/// Ignore a meta-variable for repetition without expansion.
Ignore(Ident),
@@ -35,20 +34,23 @@ impl MetaVarExpr {
) -> PResult<'sess, MetaVarExpr> {
let mut tts = input.trees();
let ident = parse_ident(&mut tts, sess, outer_span)?;
- let Some(TokenTree::Delimited(_, Delimiter::Parenthesis, args)) = tts.next() else {
+ let Some(TokenTree::Delimited(.., Delimiter::Parenthesis, args)) = tts.next() else {
let msg = "meta-variable expression parameter must be wrapped in parentheses";
- return Err(sess.span_diagnostic.struct_span_err(ident.span, msg));
+ return Err(sess.dcx.struct_span_err(ident.span, msg));
};
check_trailing_token(&mut tts, sess)?;
let mut iter = args.trees();
let rslt = match ident.as_str() {
"count" => parse_count(&mut iter, sess, ident.span)?,
- "ignore" => MetaVarExpr::Ignore(parse_ident(&mut iter, sess, ident.span)?),
+ "ignore" => {
+ eat_dollar(&mut iter, sess, ident.span)?;
+ MetaVarExpr::Ignore(parse_ident(&mut iter, sess, ident.span)?)
+ }
"index" => MetaVarExpr::Index(parse_depth(&mut iter, sess, ident.span)?),
"length" => MetaVarExpr::Length(parse_depth(&mut iter, sess, ident.span)?),
_ => {
let err_msg = "unrecognized meta-variable expression";
- let mut err = sess.span_diagnostic.struct_span_err(ident.span, err_msg);
+ let mut err = sess.dcx.struct_span_err(ident.span, err_msg);
err.span_suggestion(
ident.span,
"supported expressions are count, ignore, index and length",
@@ -77,7 +79,7 @@ fn check_trailing_token<'sess>(
) -> PResult<'sess, ()> {
if let Some(tt) = iter.next() {
let mut diag = sess
- .span_diagnostic
+ .dcx
.struct_span_err(tt.span(), format!("unexpected token: {}", pprust::tt_to_string(tt)));
diag.span_note(tt.span(), "meta-variable expression must not have trailing tokens");
Err(diag)
@@ -92,17 +94,18 @@ fn parse_count<'sess>(
sess: &'sess ParseSess,
span: Span,
) -> PResult<'sess, MetaVarExpr> {
+ eat_dollar(iter, sess, span)?;
let ident = parse_ident(iter, sess, span)?;
let depth = if try_eat_comma(iter) {
if iter.look_ahead(0).is_none() {
- return Err(sess.span_diagnostic.struct_span_err(
+ return Err(sess.dcx.struct_span_err(
span,
"`count` followed by a comma must have an associated index indicating its depth",
));
}
- Some(parse_depth(iter, sess, span)?)
+ parse_depth(iter, sess, span)?
} else {
- None
+ 0
};
Ok(MetaVarExpr::Count(ident, depth))
}
@@ -116,7 +119,7 @@ fn parse_depth<'sess>(
let Some(tt) = iter.next() else { return Ok(0) };
let TokenTree::Token(token::Token { kind: token::TokenKind::Literal(lit), .. }, _) = tt else {
return Err(sess
- .span_diagnostic
+ .dcx
.struct_span_err(span, "meta-variable expression depth must be a literal"));
};
if let Ok(lit_kind) = LitKind::from_token_lit(*lit)
@@ -126,7 +129,7 @@ fn parse_depth<'sess>(
Ok(n_usize)
} else {
let msg = "only unsuffixes integer literals are supported in meta-variable expressions";
- Err(sess.span_diagnostic.struct_span_err(span, msg))
+ Err(sess.dcx.struct_span_err(span, msg))
}
}
@@ -143,9 +146,8 @@ fn parse_ident<'sess>(
return Ok(elem);
}
let token_str = pprust::token_to_string(token);
- let mut err = sess
- .span_diagnostic
- .struct_span_err(span, format!("expected identifier, found `{}`", &token_str));
+ let mut err =
+ sess.dcx.struct_span_err(span, format!("expected identifier, found `{}`", &token_str));
err.span_suggestion(
token.span,
format!("try removing `{}`", &token_str),
@@ -154,7 +156,7 @@ fn parse_ident<'sess>(
);
return Err(err);
}
- Err(sess.span_diagnostic.struct_span_err(span, "expected identifier"))
+ Err(sess.dcx.struct_span_err(span, "expected identifier"))
}
/// Tries to move the iterator forward returning `true` if there is a comma. If not, then the
@@ -166,3 +168,20 @@ fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool {
}
false
}
+
+/// Expects that the next item is a dollar sign.
+fn eat_dollar<'sess>(
+ iter: &mut RefTokenTreeCursor<'_>,
+ sess: &'sess ParseSess,
+ span: Span,
+) -> PResult<'sess, ()> {
+ if let Some(TokenTree::Token(token::Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0)
+ {
+ let _ = iter.next();
+ return Ok(());
+ }
+ Err(sess.dcx.struct_span_err(
+ span,
+ "meta-variables within meta-variable expressions must be referenced using a dollar sign",
+ ))
+}
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 6546199f5..445be01bc 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -84,7 +84,7 @@ pub(super) fn parse(
"invalid fragment specifier `{}`",
frag.name
);
- sess.span_diagnostic
+ sess.dcx
.struct_span_err(span, msg)
.help(VALID_FRAGMENT_NAMES_MSG)
.emit();
@@ -116,7 +116,7 @@ pub(super) fn parse(
fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &ParseSess, span: Span) {
if !features.macro_metavar_expr {
let msg = "meta-variable expressions are unstable";
- feature_err(&sess, sym::macro_metavar_expr, span, msg).emit();
+ feature_err(sess, sym::macro_metavar_expr, span, msg).emit();
}
}
@@ -151,7 +151,7 @@ fn parse_tree<'a>(
// during parsing.
let mut next = outer_trees.next();
let mut trees: Box<dyn Iterator<Item = &tokenstream::TokenTree>>;
- if let Some(tokenstream::TokenTree::Delimited(_, Delimiter::Invisible, tts)) = next {
+ if let Some(tokenstream::TokenTree::Delimited(.., Delimiter::Invisible, tts)) = next {
trees = Box::new(tts.trees());
next = trees.next();
} else {
@@ -160,7 +160,7 @@ fn parse_tree<'a>(
match next {
// `tree` is followed by a delimited set of token trees.
- Some(&tokenstream::TokenTree::Delimited(delim_span, delim, ref tts)) => {
+ Some(&tokenstream::TokenTree::Delimited(delim_span, _, delim, ref tts)) => {
if parsing_patterns {
if delim != Delimiter::Parenthesis {
span_dollar_dollar_or_metavar_in_the_lhs_err(
@@ -174,7 +174,7 @@ fn parse_tree<'a>(
// The delimiter is `{`. This indicates the beginning
// of a meta-variable expression (e.g. `${count(ident)}`).
// Try to parse the meta-variable expression.
- match MetaVarExpr::parse(&tts, delim_span.entire(), sess) {
+ match MetaVarExpr::parse(tts, delim_span.entire(), sess) {
Err(mut err) => {
err.emit();
// Returns early the same read `$` to avoid spanning
@@ -195,7 +195,7 @@ fn parse_tree<'a>(
_ => {
let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
let msg = format!("expected `(` or `{{`, found `{tok}`");
- sess.span_diagnostic.span_err(delim_span.entire(), msg);
+ sess.dcx.span_err(delim_span.entire(), msg);
}
}
}
@@ -242,11 +242,9 @@ fn parse_tree<'a>(
// `tree` is followed by some other token. This is an error.
Some(tokenstream::TokenTree::Token(token, _)) => {
- let msg = format!(
- "expected identifier, found `{}`",
- pprust::token_to_string(&token),
- );
- sess.span_diagnostic.span_err(token.span, msg);
+ let msg =
+ format!("expected identifier, found `{}`", pprust::token_to_string(token),);
+ sess.dcx.span_err(token.span, msg);
TokenTree::MetaVar(token.span, Ident::empty())
}
@@ -260,8 +258,9 @@ fn parse_tree<'a>(
// `tree` is the beginning of a delimited set of tokens (e.g., `(` or `{`). We need to
// descend into the delimited set and further parse it.
- &tokenstream::TokenTree::Delimited(span, delim, ref tts) => TokenTree::Delimited(
+ &tokenstream::TokenTree::Delimited(span, spacing, delim, ref tts) => TokenTree::Delimited(
span,
+ spacing,
Delimited {
delim,
tts: parse(tts, parsing_patterns, sess, node_id, features, edition),
@@ -291,7 +290,7 @@ fn parse_kleene_op<'a>(
span: Span,
) -> Result<Result<(KleeneOp, Span), Token>, Span> {
match input.next() {
- Some(tokenstream::TokenTree::Token(token, _)) => match kleene_op(&token) {
+ Some(tokenstream::TokenTree::Token(token, _)) => match kleene_op(token) {
Some(op) => Ok(Ok((op, token.span))),
None => Ok(Err(token.clone())),
},
@@ -326,7 +325,7 @@ fn parse_sep_and_kleene_op<'a>(
// #2 is the `?` Kleene op, which does not take a separator (error)
Ok(Ok((KleeneOp::ZeroOrOne, span))) => {
// Error!
- sess.span_diagnostic.span_err(
+ sess.dcx.span_err(
token.span,
"the `?` macro repetition operator does not take a separator",
);
@@ -347,7 +346,7 @@ fn parse_sep_and_kleene_op<'a>(
};
// If we ever get to this point, we have experienced an "unexpected token" error
- sess.span_diagnostic.span_err(span, "expected one of: `*`, `+`, or `?`");
+ sess.dcx.span_err(span, "expected one of: `*`, `+`, or `?`");
// Return a dummy
(None, KleeneToken::new(KleeneOp::ZeroOrMore, span))
@@ -357,9 +356,8 @@ fn parse_sep_and_kleene_op<'a>(
//
// For example, `macro_rules! foo { ( ${length()} ) => {} }`
fn span_dollar_dollar_or_metavar_in_the_lhs_err(sess: &ParseSess, token: &Token) {
- sess.span_diagnostic
- .span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token)));
- sess.span_diagnostic.span_note_without_error(
+ sess.dcx.span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token)));
+ sess.dcx.span_note(
token.span,
"`$$` and meta-variable expressions are not allowed inside macro parameter definitions",
);
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 15e7ab3fe..80fd82e03 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -7,7 +7,7 @@ use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, MatchedTokenTree,
use crate::mbe::{self, MetaVarExpr};
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree};
+use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, PResult};
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
@@ -31,14 +31,24 @@ impl MutVisitor for Marker {
/// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
enum Frame<'a> {
- Delimited { tts: &'a [mbe::TokenTree], idx: usize, delim: Delimiter, span: DelimSpan },
- Sequence { tts: &'a [mbe::TokenTree], idx: usize, sep: Option<Token> },
+ Delimited {
+ tts: &'a [mbe::TokenTree],
+ idx: usize,
+ delim: Delimiter,
+ span: DelimSpan,
+ spacing: DelimSpacing,
+ },
+ Sequence {
+ tts: &'a [mbe::TokenTree],
+ idx: usize,
+ sep: Option<Token>,
+ },
}
impl<'a> Frame<'a> {
/// Construct a new frame around the delimited set of tokens.
- fn new(src: &'a mbe::Delimited, span: DelimSpan) -> Frame<'a> {
- Frame::Delimited { tts: &src.tts, idx: 0, delim: src.delim, span }
+ fn new(src: &'a mbe::Delimited, span: DelimSpan, spacing: DelimSpacing) -> Frame<'a> {
+ Frame::Delimited { tts: &src.tts, idx: 0, delim: src.delim, span, spacing }
}
}
@@ -89,8 +99,10 @@ pub(super) fn transcribe<'a>(
}
// We descend into the RHS (`src`), expanding things as we go. This stack contains the things
- // we have yet to expand/are still expanding. We start the stack off with the whole RHS.
- let mut stack: SmallVec<[Frame<'_>; 1]> = smallvec![Frame::new(&src, src_span)];
+ // we have yet to expand/are still expanding. We start the stack off with the whole RHS. The
+ // choice of spacing values doesn't matter.
+ let mut stack: SmallVec<[Frame<'_>; 1]> =
+ smallvec![Frame::new(src, src_span, DelimSpacing::new(Spacing::Alone, Spacing::Alone))];
// As we descend in the RHS, we will need to be able to match nested sequences of matchers.
// `repeats` keeps track of where we are in matching at each level, with the last element being
@@ -144,14 +156,19 @@ pub(super) fn transcribe<'a>(
// We are done processing a Delimited. If this is the top-level delimited, we are
// done. Otherwise, we unwind the result_stack to append what we have produced to
// any previous results.
- Frame::Delimited { delim, span, .. } => {
+ Frame::Delimited { delim, span, mut spacing, .. } => {
+ // Hack to force-insert a space after `]` in certain case.
+ // See discussion of the `hex-literal` crate in #114571.
+ if delim == Delimiter::Bracket {
+ spacing.close = Spacing::Alone;
+ }
if result_stack.is_empty() {
// No results left to compute! We are back at the top-level.
return Ok(TokenStream::new(result));
}
// Step back into the parent Delimited.
- let tree = TokenTree::Delimited(span, delim, TokenStream::new(result));
+ let tree = TokenTree::Delimited(span, spacing, delim, TokenStream::new(result));
result = result_stack.pop().unwrap();
result.push(tree);
}
@@ -166,7 +183,7 @@ pub(super) fn transcribe<'a>(
// and the matches in `interp` have the same shape. Otherwise, either the caller or the
// macro writer has made a mistake.
seq @ mbe::TokenTree::Sequence(_, delimited) => {
- match lockstep_iter_size(&seq, interp, &repeats) {
+ match lockstep_iter_size(seq, interp, &repeats) {
LockstepIterSize::Unconstrained => {
return Err(cx.create_err(NoSyntaxVarsExprRepeat { span: seq.span() }));
}
@@ -240,7 +257,7 @@ pub(super) fn transcribe<'a>(
// with modified syntax context. (I believe this supports nested macros).
marker.visit_span(&mut sp);
marker.visit_ident(&mut original_ident);
- result.push(TokenTree::token_alone(token::Dollar, sp));
+ result.push(TokenTree::token_joint_hidden(token::Dollar, sp));
result.push(TokenTree::Token(
Token::from_ast_ident(original_ident),
Spacing::Alone,
@@ -250,7 +267,7 @@ pub(super) fn transcribe<'a>(
// Replace meta-variable expressions with the result of their expansion.
mbe::TokenTree::MetaVarExpr(sp, expr) => {
- transcribe_metavar_expr(cx, expr, interp, &mut marker, &repeats, &mut result, &sp)?;
+ transcribe_metavar_expr(cx, expr, interp, &mut marker, &repeats, &mut result, sp)?;
}
// If we are entering a new delimiter, we push its contents to the `stack` to be
@@ -258,13 +275,14 @@ pub(super) fn transcribe<'a>(
// We will produce all of the results of the inside of the `Delimited` and then we will
// jump back out of the Delimited, pop the result_stack and add the new results back to
// the previous results (from outside the Delimited).
- mbe::TokenTree::Delimited(mut span, delimited) => {
+ mbe::TokenTree::Delimited(mut span, spacing, delimited) => {
mut_visit::visit_delim_span(&mut span, &mut marker);
stack.push(Frame::Delimited {
tts: &delimited.tts,
delim: delimited.delim,
idx: 0,
span,
+ spacing: *spacing,
});
result_stack.push(mem::take(&mut result));
}
@@ -374,7 +392,7 @@ fn lockstep_iter_size(
) -> LockstepIterSize {
use mbe::TokenTree;
match tree {
- TokenTree::Delimited(_, delimited) => {
+ TokenTree::Delimited(.., delimited) => {
delimited.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
size.with(lockstep_iter_size(tt, interpolations, repeats))
})
@@ -422,7 +440,7 @@ fn lockstep_iter_size(
/// declared inside a single repetition and the index `1` implies two nested repetitions.
fn count_repetitions<'a>(
cx: &ExtCtxt<'a>,
- depth_opt: Option<usize>,
+ depth_user: usize,
mut matched: &NamedMatch,
repeats: &[(usize, usize)],
sp: &DelimSpan,
@@ -431,37 +449,45 @@ fn count_repetitions<'a>(
// (or at the top-level of `matched` if no depth is given).
fn count<'a>(
cx: &ExtCtxt<'a>,
- declared_lhs_depth: usize,
- depth_opt: Option<usize>,
+ depth_curr: usize,
+ depth_max: usize,
matched: &NamedMatch,
sp: &DelimSpan,
) -> PResult<'a, usize> {
match matched {
- MatchedTokenTree(_) | MatchedNonterminal(_) => {
- if declared_lhs_depth == 0 {
- return Err(cx.create_err(CountRepetitionMisplaced { span: sp.entire() }));
- }
- match depth_opt {
- None => Ok(1),
- Some(_) => Err(out_of_bounds_err(cx, declared_lhs_depth, sp.entire(), "count")),
- }
- }
+ MatchedTokenTree(_) | MatchedNonterminal(_) => Ok(1),
MatchedSeq(named_matches) => {
- let new_declared_lhs_depth = declared_lhs_depth + 1;
- match depth_opt {
- None => named_matches
- .iter()
- .map(|elem| count(cx, new_declared_lhs_depth, None, elem, sp))
- .sum(),
- Some(0) => Ok(named_matches.len()),
- Some(depth) => named_matches
+ if depth_curr == depth_max {
+ Ok(named_matches.len())
+ } else {
+ named_matches
.iter()
- .map(|elem| count(cx, new_declared_lhs_depth, Some(depth - 1), elem, sp))
- .sum(),
+ .map(|elem| count(cx, depth_curr + 1, depth_max, elem, sp))
+ .sum()
}
}
}
}
+
+ /// Maximum depth
+ fn depth(counter: usize, matched: &NamedMatch) -> usize {
+ match matched {
+ MatchedTokenTree(_) | MatchedNonterminal(_) => counter,
+ MatchedSeq(named_matches) => {
+ let rslt = counter + 1;
+ if let Some(elem) = named_matches.first() { depth(rslt, elem) } else { rslt }
+ }
+ }
+ }
+
+ let depth_max = depth(0, matched)
+ .checked_sub(1)
+ .and_then(|el| el.checked_sub(repeats.len()))
+ .unwrap_or_default();
+ if depth_user > depth_max {
+ return Err(out_of_bounds_err(cx, depth_max + 1, sp.entire(), "count"));
+ }
+
// `repeats` records all of the nested levels at which we are currently
// matching meta-variables. The meta-var-expr `count($x)` only counts
// matches that occur in this "subtree" of the `NamedMatch` where we
@@ -473,7 +499,12 @@ fn count_repetitions<'a>(
matched = &ads[idx];
}
}
- count(cx, 0, depth_opt, matched, sp)
+
+ if let MatchedTokenTree(_) | MatchedNonterminal(_) = matched {
+ return Err(cx.create_err(CountRepetitionMisplaced { span: sp.entire() }));
+ }
+
+ count(cx, depth_user, depth_max, matched, sp)
}
/// Returns a `NamedMatch` item declared on the LHS given an arbitrary [Ident]
@@ -505,7 +536,7 @@ fn out_of_bounds_err<'a>(
)
} else {
format!(
- "depth parameter on meta-variable expression `{ty}` \
+ "depth parameter of meta-variable expression `{ty}` \
must be less than {max}"
)
};
@@ -527,9 +558,9 @@ fn transcribe_metavar_expr<'a>(
span
};
match *expr {
- MetaVarExpr::Count(original_ident, depth_opt) => {
+ MetaVarExpr::Count(original_ident, depth) => {
let matched = matched_from_ident(cx, original_ident, interp)?;
- let count = count_repetitions(cx, depth_opt, matched, &repeats, sp)?;
+ let count = count_repetitions(cx, depth, matched, repeats, sp)?;
let tt = TokenTree::token_alone(
TokenKind::lit(token::Integer, sym::integer(count), None),
visited_span(),
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index df6bdc695..a0dec89d6 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -57,7 +57,7 @@ pub(crate) fn parse_external_mod(
// We bail on the first error, but that error does not cause a fatal error... (1)
let result: Result<_, ModError<'_>> = try {
// Extract the file path and the new ownership.
- let mp = mod_file_path(sess, ident, &attrs, &module.dir_path, dir_ownership)?;
+ let mp = mod_file_path(sess, ident, attrs, &module.dir_path, dir_ownership)?;
dir_ownership = mp.dir_ownership;
// Ensure file paths are acyclic.
@@ -119,7 +119,7 @@ pub(crate) fn mod_dir_path(
Inline::No => {
// FIXME: This is a subset of `parse_external_mod` without actual parsing,
// check whether the logic for unloaded, loaded and inline modules can be unified.
- let file_path = mod_file_path(sess, ident, &attrs, &module.dir_path, dir_ownership)
+ let file_path = mod_file_path(sess, ident, attrs, &module.dir_path, dir_ownership)
.map(|mp| {
dir_ownership = mp.dir_ownership;
mp.file_path
diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs
index bdc20882a..7a888250c 100644
--- a/compiler/rustc_expand/src/parse/tests.rs
+++ b/compiler/rustc_expand/src/parse/tests.rs
@@ -4,7 +4,7 @@ use crate::tests::{
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token};
-use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
+use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
use rustc_ast::visit;
use rustc_ast::{self as ast, PatKind};
use rustc_ast_pretty::pprust::item_to_string;
@@ -77,14 +77,14 @@ fn string_to_tts_macro() {
TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }, _),
TokenTree::Token(Token { kind: token::Not, .. }, _),
TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }, _),
- TokenTree::Delimited(_, macro_delim, macro_tts),
+ TokenTree::Delimited(.., macro_delim, macro_tts),
] if name_macro_rules == &kw::MacroRules && name_zip.as_str() == "zip" => {
let tts = &macro_tts.trees().collect::<Vec<_>>();
match &tts[..] {
[
- TokenTree::Delimited(_, first_delim, first_tts),
+ TokenTree::Delimited(.., first_delim, first_tts),
TokenTree::Token(Token { kind: token::FatArrow, .. }, _),
- TokenTree::Delimited(_, second_delim, second_tts),
+ TokenTree::Delimited(.., second_delim, second_tts),
] if macro_delim == &Delimiter::Parenthesis => {
let tts = &first_tts.trees().collect::<Vec<_>>();
match &tts[..] {
@@ -116,27 +116,36 @@ fn string_to_tts_macro() {
#[test]
fn string_to_tts_1() {
create_default_session_globals_then(|| {
- let tts = string_to_stream("fn a (b : i32) { b; }".to_string());
+ let tts = string_to_stream("fn a(b: i32) { b; }".to_string());
let expected = TokenStream::new(vec![
TokenTree::token_alone(token::Ident(kw::Fn, false), sp(0, 2)),
- TokenTree::token_alone(token::Ident(Symbol::intern("a"), false), sp(3, 4)),
+ TokenTree::token_joint_hidden(token::Ident(Symbol::intern("a"), false), sp(3, 4)),
TokenTree::Delimited(
- DelimSpan::from_pair(sp(5, 6), sp(13, 14)),
+ DelimSpan::from_pair(sp(4, 5), sp(11, 12)),
+ // `JointHidden` because the `(` is followed immediately by
+ // `b`, `Alone` because the `)` is followed by whitespace.
+ DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
Delimiter::Parenthesis,
TokenStream::new(vec![
- TokenTree::token_alone(token::Ident(Symbol::intern("b"), false), sp(6, 7)),
- TokenTree::token_alone(token::Colon, sp(8, 9)),
- TokenTree::token_alone(token::Ident(sym::i32, false), sp(10, 13)),
+ TokenTree::token_joint(token::Ident(Symbol::intern("b"), false), sp(5, 6)),
+ TokenTree::token_alone(token::Colon, sp(6, 7)),
+ // `JointHidden` because the `i32` is immediately followed by the `)`.
+ TokenTree::token_joint_hidden(token::Ident(sym::i32, false), sp(8, 11)),
])
.into(),
),
TokenTree::Delimited(
- DelimSpan::from_pair(sp(15, 16), sp(20, 21)),
+ DelimSpan::from_pair(sp(13, 14), sp(18, 19)),
+ // First `Alone` because the `{` is followed by whitespace,
+ // second `Alone` because the `}` is followed immediately by
+ // EOF.
+ DelimSpacing::new(Spacing::Alone, Spacing::Alone),
Delimiter::Brace,
TokenStream::new(vec![
- TokenTree::token_joint(token::Ident(Symbol::intern("b"), false), sp(17, 18)),
- TokenTree::token_alone(token::Semi, sp(18, 19)),
+ TokenTree::token_joint(token::Ident(Symbol::intern("b"), false), sp(15, 16)),
+ // `Alone` because the `;` is followed by whitespace.
+ TokenTree::token_alone(token::Semi, sp(16, 17)),
])
.into(),
),
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 1292a8552..2c4187031 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -119,7 +119,7 @@ pub fn placeholder(
}]),
AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm {
attrs: Default::default(),
- body: expr_placeholder(),
+ body: Some(expr_placeholder()),
guard: None,
id,
pat: pat(),
@@ -174,7 +174,7 @@ pub fn placeholder(
}]),
AstFragmentKind::Variants => AstFragment::Variants(smallvec![ast::Variant {
attrs: Default::default(),
- data: ast::VariantData::Struct(Default::default(), false),
+ data: ast::VariantData::Struct { fields: Default::default(), recovered: false },
disr_expr: None,
id,
ident,
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index c617cd76e..429bfa614 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -126,7 +126,7 @@ impl MultiItemModifier for DeriveProcMacro {
Annotatable::Stmt(stmt) => token::NtStmt(stmt),
_ => unreachable!(),
};
- TokenStream::token_alone(token::Interpolated(Lrc::new(nt)), DUMMY_SP)
+ TokenStream::token_alone(token::Interpolated(Lrc::new((nt, span))), DUMMY_SP)
} else {
item.to_tokens()
};
@@ -156,7 +156,7 @@ impl MultiItemModifier for DeriveProcMacro {
}
};
- let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count();
+ let error_count_before = ecx.sess.dcx().err_count();
let mut parser =
rustc_parse::stream_to_parser(&ecx.sess.parse_sess, stream, Some("proc-macro derive"));
let mut items = vec![];
@@ -179,7 +179,7 @@ impl MultiItemModifier for DeriveProcMacro {
}
// fail if there have been errors emitted
- if ecx.sess.parse_sess.span_diagnostic.err_count() > error_count_before {
+ if ecx.sess.dcx().err_count() > error_count_before {
ecx.sess.emit_err(errors::ProcMacroDeriveTokens { span });
}
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index aa4c7a531..c412b064c 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -5,7 +5,7 @@ use pm::bridge::{
use pm::{Delimiter, Level};
use rustc_ast as ast;
use rustc_ast::token;
-use rustc_ast::tokenstream::{self, Spacing::*, TokenStream};
+use rustc_ast::tokenstream::{self, DelimSpacing, Spacing, TokenStream};
use rustc_ast::util::literal::escape_byte_str_symbol;
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
@@ -98,7 +98,7 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
while let Some(tree) = cursor.next() {
let (Token { kind, span }, joint) = match tree.clone() {
- tokenstream::TokenTree::Delimited(span, delim, tts) => {
+ tokenstream::TokenTree::Delimited(span, _, delim, tts) => {
let delimiter = pm::Delimiter::from_internal(delim);
trees.push(TokenTree::Group(Group {
delimiter,
@@ -111,7 +111,22 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
}));
continue;
}
- tokenstream::TokenTree::Token(token, spacing) => (token, spacing == Joint),
+ tokenstream::TokenTree::Token(token, spacing) => {
+ // Do not be tempted to check here that the `spacing`
+ // values are "correct" w.r.t. the token stream (e.g. that
+ // `Spacing::Joint` is actually followed by a `Punct` token
+ // tree). Because the problem in #76399 was introduced that
+ // way.
+ //
+ // This is where the `Hidden` in `JointHidden` applies,
+ // because the jointness is effectively hidden from proc
+ // macros.
+ let joint = match spacing {
+ Spacing::Alone | Spacing::JointHidden => false,
+ Spacing::Joint => true,
+ };
+ (token, joint)
+ }
};
// Split the operator into one or more `Punct`s, one per character.
@@ -133,7 +148,8 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
} else {
span
};
- TokenTree::Punct(Punct { ch, joint: if is_final { joint } else { true }, span })
+ let joint = if is_final { joint } else { true };
+ TokenTree::Punct(Punct { ch, joint, span })
}));
};
@@ -226,18 +242,23 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
}));
}
- Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => trees
- .push(TokenTree::Ident(Ident { sym: ident.name, is_raw, span: ident.span })),
+ Interpolated(ref nt) if let NtIdent(ident, is_raw) = &nt.0 => {
+ trees.push(TokenTree::Ident(Ident {
+ sym: ident.name,
+ is_raw: *is_raw,
+ span: ident.span,
+ }))
+ }
Interpolated(nt) => {
- let stream = TokenStream::from_nonterminal_ast(&nt);
+ let stream = TokenStream::from_nonterminal_ast(&nt.0);
// A hack used to pass AST fragments to attribute and derive
// macros as a single nonterminal token instead of a token
// stream. Such token needs to be "unwrapped" and not
// represented as a delimited group.
// FIXME: It needs to be removed, but there are some
// compatibility issues (see #73345).
- if crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.sess()) {
+ if crate::base::nt_pretty_printing_compatibility_hack(&nt.0, rustc.sess()) {
trees.extend(Self::from_internal((stream, rustc)));
} else {
trees.push(TokenTree::Group(Group {
@@ -263,6 +284,11 @@ impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>>
fn to_internal(self) -> SmallVec<[tokenstream::TokenTree; 2]> {
use rustc_ast::token::*;
+ // The code below is conservative, using `token_alone`/`Spacing::Alone`
+ // in most places. When the resulting code is pretty-printed by
+ // `print_tts` it ends up with spaces between most tokens, which is
+ // safe but ugly. It's hard in general to do better when working at the
+ // token level.
let (tree, rustc) = self;
match tree {
TokenTree::Punct(Punct { ch, joint, span }) => {
@@ -291,6 +317,11 @@ impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>>
b'\'' => SingleQuote,
_ => unreachable!(),
};
+ // We never produce `token::Spacing::JointHidden` here, which
+ // means the pretty-printing of code produced by proc macros is
+ // ugly, with lots of whitespace between tokens. This is
+ // unavoidable because `proc_macro::Spacing` only applies to
+ // `Punct` token trees.
smallvec![if joint {
tokenstream::TokenTree::token_joint(kind, span)
} else {
@@ -300,6 +331,7 @@ impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>>
TokenTree::Group(Group { delimiter, stream, span: DelimSpan { open, close, .. } }) => {
smallvec![tokenstream::TokenTree::Delimited(
tokenstream::DelimSpan { open, close },
+ DelimSpacing::new(Spacing::Alone, Spacing::Alone),
delimiter.to_internal(),
stream.unwrap_or_default(),
)]
@@ -317,7 +349,7 @@ impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>>
let minus = BinOp(BinOpToken::Minus);
let symbol = Symbol::intern(&symbol.as_str()[1..]);
let integer = TokenKind::lit(token::Integer, symbol, suffix);
- let a = tokenstream::TokenTree::token_alone(minus, span);
+ let a = tokenstream::TokenTree::token_joint_hidden(minus, span);
let b = tokenstream::TokenTree::token_alone(integer, span);
smallvec![a, b]
}
@@ -330,7 +362,7 @@ impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>>
let minus = BinOp(BinOpToken::Minus);
let symbol = Symbol::intern(&symbol.as_str()[1..]);
let float = TokenKind::lit(token::Float, symbol, suffix);
- let a = tokenstream::TokenTree::token_alone(minus, span);
+ let a = tokenstream::TokenTree::token_joint_hidden(minus, span);
let b = tokenstream::TokenTree::token_alone(float, span);
smallvec![a, b]
}
@@ -394,6 +426,10 @@ impl server::Types for Rustc<'_, '_> {
}
impl server::FreeFunctions for Rustc<'_, '_> {
+ fn injected_env_var(&mut self, var: &str) -> Option<String> {
+ self.ecx.sess.opts.logical_env.get(var).cloned()
+ }
+
fn track_env_var(&mut self, var: &str, value: Option<&str>) {
self.sess()
.env_depinfo
@@ -470,7 +506,7 @@ impl server::FreeFunctions for Rustc<'_, '_> {
None,
);
}
- self.sess().span_diagnostic.emit_diagnostic(&mut diag);
+ self.sess().dcx.emit_diagnostic(diag);
}
}
@@ -541,7 +577,10 @@ impl server::TokenStream for Rustc<'_, '_> {
Ok(Self::TokenStream::from_iter([
// FIXME: The span of the `-` token is lost when
// parsing, so we cannot faithfully recover it here.
- tokenstream::TokenTree::token_alone(token::BinOp(token::Minus), e.span),
+ tokenstream::TokenTree::token_joint_hidden(
+ token::BinOp(token::Minus),
+ e.span,
+ ),
tokenstream::TokenTree::token_alone(token::Literal(*token_lit), e.span),
]))
}
@@ -779,6 +818,6 @@ impl server::Server for Rustc<'_, '_> {
}
fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
- f(&symbol.as_str())
+ f(symbol.as_str())
}
}
diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs
index 9f52669e1..0b8598418 100644
--- a/compiler/rustc_expand/src/tests.rs
+++ b/compiler/rustc_expand/src/tests.rs
@@ -8,7 +8,7 @@ use rustc_span::{BytePos, Span};
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::{Handler, MultiSpan, PResult};
+use rustc_errors::{DiagCtxt, MultiSpan, PResult};
use termcolor::WriteColor;
use std::io;
@@ -23,7 +23,7 @@ fn string_to_parser(ps: &ParseSess, source_str: String) -> Parser<'_> {
new_parser_from_source_str(ps, PathBuf::from("bogofile").into(), source_str)
}
-fn create_test_handler() -> (Handler, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
+fn create_test_handler() -> (DiagCtxt, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
let output = Arc::new(Mutex::new(Vec::new()));
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let fallback_bundle = rustc_errors::fallback_fluent_bundle(
@@ -33,8 +33,8 @@ fn create_test_handler() -> (Handler, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), fallback_bundle)
.sm(Some(source_map.clone()))
.diagnostic_width(Some(140));
- let handler = Handler::with_emitter(Box::new(emitter));
- (handler, source_map, output)
+ let dcx = DiagCtxt::with_emitter(Box::new(emitter));
+ (dcx, source_map, output)
}
/// Returns the result of parsing the given string via the given callback.
@@ -46,7 +46,7 @@ where
{
let mut p = string_to_parser(&ps, s);
let x = f(&mut p).unwrap();
- p.sess.span_diagnostic.abort_if_errors();
+ p.sess.dcx.abort_if_errors();
x
}
@@ -57,7 +57,7 @@ where
F: for<'a> FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
{
let (handler, source_map, output) = create_test_handler();
- let ps = ParseSess::with_span_handler(handler, source_map);
+ let ps = ParseSess::with_dcx(handler, source_map);
let mut p = string_to_parser(&ps, source_str.to_string());
let result = f(&mut p);
assert!(result.is_ok());
@@ -135,7 +135,7 @@ pub(crate) fn matches_codepattern(a: &str, b: &str) -> bool {
/// Advances the given peekable `Iterator` until it reaches a non-whitespace character.
fn scan_for_non_ws_or_end<I: Iterator<Item = char>>(iter: &mut Peekable<I>) {
- while iter.peek().copied().map(rustc_lexer::is_whitespace) == Some(true) {
+ while iter.peek().copied().is_some_and(rustc_lexer::is_whitespace) {
iter.next();
}
}