summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_expand/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:24 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:24 +0000
commit023939b627b7dc93b01471f7d41fb8553ddb4ffa (patch)
tree60fc59477c605c72b0a1051409062ddecc43f877 /compiler/rustc_expand/src
parentAdding debian version 1.72.1+dfsg1-1. (diff)
downloadrustc-023939b627b7dc93b01471f7d41fb8553ddb4ffa.tar.xz
rustc-023939b627b7dc93b01471f7d41fb8553ddb4ffa.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_expand/src')
-rw-r--r--compiler/rustc_expand/src/base.rs9
-rw-r--r--compiler/rustc_expand/src/build.rs11
-rw-r--r--compiler/rustc_expand/src/config.rs23
-rw-r--r--compiler/rustc_expand/src/expand.rs35
-rw-r--r--compiler/rustc_expand/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs5
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs16
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs56
-rw-r--r--compiler/rustc_expand/src/mbe/metavar_expr.rs23
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs44
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs15
-rw-r--r--compiler/rustc_expand/src/parse/tests.rs21
-rw-r--r--compiler/rustc_expand/src/placeholders.rs3
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs4
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs6
-rw-r--r--compiler/rustc_expand/src/tests.rs76
17 files changed, 208 insertions, 144 deletions
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 8a251ea29..c4d2a374f 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -18,6 +18,7 @@ use rustc_errors::{
Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic,
MultiSpan, PResult,
};
+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};
@@ -767,6 +768,7 @@ impl SyntaxExtension {
/// and other properties converted from attributes.
pub fn new(
sess: &Session,
+ features: &Features,
kind: SyntaxExtensionKind,
span: Span,
helper_attrs: Vec<Symbol>,
@@ -816,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, attrs).map(|(d, _)| d),
+ deprecation: attr::find_deprecation(&sess, features, attrs).map(|(d, _)| d),
helper_attrs,
edition,
builtin_name,
@@ -957,6 +959,7 @@ pub trait LintStoreExpand {
fn pre_expansion_lint(
&self,
sess: &Session,
+ features: &Features,
registered_tools: &RegisteredTools,
node_id: NodeId,
attrs: &[Attribute],
@@ -1147,7 +1150,7 @@ impl<'a> ExtCtxt<'a> {
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<DiagnosticMessage>) -> ! {
+ 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 trace_macros_diag(&mut self) {
@@ -1366,7 +1369,7 @@ pub fn parse_macro_name_and_helper_attrs(
return None;
}
let Some(trait_attr) = list[0].meta_item() else {
- diag.emit_err(errors::NotAMetaItem {span: list[0].span()});
+ diag.emit_err(errors::NotAMetaItem { span: list[0].span() });
return None;
};
let trait_ident = match trait_attr.ident() {
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 264f30fb1..7de469944 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -643,7 +643,16 @@ impl<'a> ExtCtxt<'a> {
span,
name,
AttrVec::new(),
- ast::ItemKind::Const(ast::ConstItem { defaultness, ty, expr: Some(expr) }.into()),
+ ast::ItemKind::Const(
+ ast::ConstItem {
+ defaultness,
+ // FIXME(generic_const_items): Pass the generics as a parameter.
+ generics: ast::Generics::default(),
+ ty,
+ expr: Some(expr),
+ }
+ .into(),
+ ),
)
}
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 3e43eae00..8658cea13 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -313,9 +313,10 @@ impl<'a> StripUnconfigured<'a> {
/// the attribute is incorrect.
pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> {
let Some((cfg_predicate, expanded_attrs)) =
- rustc_parse::parse_cfg_attr(attr, &self.sess.parse_sess) else {
- return vec![];
- };
+ rustc_parse::parse_cfg_attr(attr, &self.sess.parse_sess)
+ else {
+ return vec![];
+ };
// Lint on zero attributes in source.
if expanded_attrs.is_empty() {
@@ -364,17 +365,21 @@ impl<'a> StripUnconfigured<'a> {
// Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
// for `attr` when we expand it to `#[attr]`
- let mut orig_trees = orig_tokens.into_trees();
- let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _) = orig_trees.next().unwrap() else {
- panic!("Bad tokens for attribute {:?}", attr);
+ let mut orig_trees = orig_tokens.trees();
+ let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _) =
+ orig_trees.next().unwrap().clone()
+ else {
+ panic!("Bad tokens for attribute {attr:?}");
};
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() else {
- panic!("Bad tokens for attribute {:?}", 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));
}
@@ -385,7 +390,7 @@ impl<'a> StripUnconfigured<'a> {
Delimiter::Bracket,
item.tokens
.as_ref()
- .unwrap_or_else(|| panic!("Missing tokens for {:?}", item))
+ .unwrap_or_else(|| panic!("Missing tokens for {item:?}"))
.to_attr_token_stream(),
);
trees.push(bracket_group);
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 9850723a8..34d16bf00 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -651,7 +651,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
ExpandResult::Ready(match invoc.kind {
InvocationKind::Bang { mac, .. } => match ext {
SyntaxExtensionKind::Bang(expander) => {
- let Ok(tok_result) = expander.expand(self.cx, span, mac.args.tokens.clone()) else {
+ let Ok(tok_result) = expander.expand(self.cx, span, mac.args.tokens.clone())
+ else {
return ExpandResult::Ready(fragment_kind.dummy(span));
};
self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span)
@@ -704,7 +705,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
self.cx.emit_err(UnsupportedKeyValue { span });
}
let inner_tokens = attr_item.args.inner_tokens();
- let Ok(tok_result) = expander.expand(self.cx, span, inner_tokens, tokens) else {
+ let Ok(tok_result) = expander.expand(self.cx, span, inner_tokens, tokens)
+ else {
return ExpandResult::Ready(fragment_kind.dummy(span));
};
self.parse_ast_fragment(tok_result, fragment_kind, &attr_item.path, span)
@@ -794,14 +796,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
| Annotatable::FieldDef(..)
| Annotatable::Variant(..) => panic!("unexpected annotatable"),
};
- if self.cx.ecfg.proc_macro_hygiene() {
+ if self.cx.ecfg.features.proc_macro_hygiene {
return;
}
feature_err(
&self.cx.sess.parse_sess,
sym::proc_macro_hygiene,
span,
- format!("custom attributes cannot be applied to {}", kind),
+ format!("custom attributes cannot be applied to {kind}"),
)
.emit();
}
@@ -832,7 +834,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
}
- if !self.cx.ecfg.proc_macro_hygiene() {
+ if !self.cx.ecfg.features.proc_macro_hygiene {
annotatable
.visit_with(&mut GateProcMacroInput { parse_sess: &self.cx.sess.parse_sess });
}
@@ -1087,9 +1089,7 @@ impl InvocationCollectorNode for P<ast::Item> {
// Work around borrow checker not seeing through `P`'s deref.
let (ident, span, mut attrs) = (node.ident, node.span, mem::take(&mut node.attrs));
- let ItemKind::Mod(_, mod_kind) = &mut node.kind else {
- unreachable!()
- };
+ let ItemKind::Mod(_, mod_kind) = &mut node.kind else { unreachable!() };
let ecx = &mut collector.cx;
let (file_path, dir_path, dir_ownership) = match mod_kind {
@@ -1122,6 +1122,7 @@ impl InvocationCollectorNode for P<ast::Item> {
if let Some(lint_store) = ecx.lint_store {
lint_store.pre_expansion_lint(
ecx.sess,
+ ecx.ecfg.features,
ecx.resolver.registered_tools(),
ecx.current_expansion.lint_node_id,
&attrs,
@@ -1580,7 +1581,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
fn cfg(&self) -> StripUnconfigured<'_> {
StripUnconfigured {
sess: &self.cx.sess,
- features: self.cx.ecfg.features,
+ features: Some(self.cx.ecfg.features),
config_tokens: false,
lint_node_id: self.cx.current_expansion.lint_node_id,
}
@@ -1676,7 +1677,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
// Detect use of feature-gated or invalid attributes on macro invocations
// since they will not be detected after macro expansion.
fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
- let features = self.cx.ecfg.features.unwrap();
+ let features = self.cx.ecfg.features;
let mut attrs = attrs.iter().peekable();
let mut span: Option<Span> = None;
while let Some(attr) = attrs.next() {
@@ -1707,7 +1708,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
&UNUSED_ATTRIBUTES,
attr.span,
self.cx.current_expansion.lint_node_id,
- format!("unused attribute `{}`", attr_name),
+ format!("unused attribute `{attr_name}`"),
BuiltinLintDiagnostics::UnusedBuiltinAttribute {
attr_name,
macro_name: pprust::path_to_string(&call.path),
@@ -1976,7 +1977,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
pub struct ExpansionConfig<'feat> {
pub crate_name: String,
- pub features: Option<&'feat Features>,
+ pub features: &'feat Features,
pub recursion_limit: Limit,
pub trace_mac: bool,
/// If false, strip `#[test]` nodes
@@ -1987,11 +1988,11 @@ pub struct ExpansionConfig<'feat> {
pub proc_macro_backtrace: bool,
}
-impl<'feat> ExpansionConfig<'feat> {
- pub fn default(crate_name: String) -> ExpansionConfig<'static> {
+impl ExpansionConfig<'_> {
+ pub fn default(crate_name: String, features: &Features) -> ExpansionConfig<'_> {
ExpansionConfig {
crate_name,
- features: None,
+ features,
recursion_limit: Limit::new(1024),
trace_mac: false,
should_test: false,
@@ -1999,8 +2000,4 @@ impl<'feat> ExpansionConfig<'feat> {
proc_macro_backtrace: false,
}
}
-
- fn proc_macro_hygiene(&self) -> bool {
- self.features.is_some_and(|features| features.proc_macro_hygiene)
- }
}
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 83a5043b0..c4a9b2ace 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -11,6 +11,7 @@
#![feature(try_blocks)]
#![recursion_limit = "256"]
#![deny(rustc::untranslatable_diagnostic)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
#[macro_use]
extern crate rustc_macros;
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 3593bed2d..e06037564 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -42,7 +42,8 @@ pub(super) fn failed_to_match_macro<'cx>(
return result;
}
- let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure else {
+ let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure
+ else {
return DummyResult::any(sp);
};
@@ -256,7 +257,7 @@ pub(super) fn emit_frag_parse_err(
e.span_suggestion_verbose(
site_span,
"surround the macro invocation with `{}` to interpret the expansion as a statement",
- format!("{{ {}; }}", snippet),
+ format!("{{ {snippet}; }}"),
Applicability::MaybeIncorrect,
);
}
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index 34f998274..95f5bb2d2 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -593,7 +593,7 @@ fn check_ops_is_prefix(
return;
}
}
- buffer_lint(sess, span.into(), node_id, format!("unknown macro variable `{}`", name));
+ buffer_lint(sess, span.into(), node_id, format!("unknown macro variable `{name}`"));
}
/// Returns whether `binder_ops` is a prefix of `occurrence_ops`.
@@ -626,7 +626,7 @@ fn ops_is_prefix(
if i >= occurrence_ops.len() {
let mut span = MultiSpan::from_span(span);
span.push_span_label(binder.span, "expected repetition");
- let message = format!("variable '{}' is still repeating at this depth", name);
+ let message = format!("variable '{name}' is still repeating at this depth");
buffer_lint(sess, span, node_id, message);
return;
}
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index f0e67cfd5..7e85beaad 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -81,7 +81,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use rustc_errors::ErrorGuaranteed;
use rustc_lint_defs::pluralize;
-use rustc_parse::parser::{NtOrTt, Parser};
+use rustc_parse::parser::{ParseNtResult, Parser};
use rustc_span::symbol::Ident;
use rustc_span::symbol::MacroRulesNormalizedIdent;
use rustc_span::Span;
@@ -156,7 +156,7 @@ impl Display for MatcherLoc {
MatcherLoc::MetaVarDecl { bind, kind, .. } => {
write!(f, "meta-variable `${bind}")?;
if let Some(kind) = kind {
- write!(f, ":{}", kind)?;
+ write!(f, ":{kind}")?;
}
write!(f, "`")?;
Ok(())
@@ -692,8 +692,8 @@ impl TtParser {
Ok(nt) => nt,
};
let m = match nt {
- NtOrTt::Nt(nt) => MatchedNonterminal(Lrc::new(nt)),
- NtOrTt::Tt(tt) => MatchedTokenTree(tt),
+ ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new(nt)),
+ ParseNtResult::Tt(tt) => MatchedTokenTree(tt),
};
mp.push_match(next_metavar, seq_depth, m);
mp.idx += 1;
@@ -723,7 +723,7 @@ impl TtParser {
.iter()
.map(|mp| match &matcher[mp.idx] {
MatcherLoc::MetaVarDecl { bind, kind: Some(kind), .. } => {
- format!("{} ('{}')", kind, bind)
+ format!("{kind} ('{bind}')")
}
_ => unreachable!(),
})
@@ -736,8 +736,8 @@ impl TtParser {
"local ambiguity when calling macro `{}`: multiple parsing options: {}",
self.macro_name,
match self.next_mps.len() {
- 0 => format!("built-in NTs {}.", nts),
- n => format!("built-in NTs {} or {n} other option{s}.", nts, s = pluralize!(n)),
+ 0 => format!("built-in NTs {nts}."),
+ n => format!("built-in NTs {nts} or {n} other option{s}.", s = pluralize!(n)),
}
),
)
@@ -757,7 +757,7 @@ impl TtParser {
match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) {
Vacant(spot) => spot.insert(res.next().unwrap()),
Occupied(..) => {
- return Error(span, format!("duplicated bind name: {}", bind));
+ return Error(span, format!("duplicated bind name: {bind}"));
}
};
} else {
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 42cc0a6b1..a5959d68f 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -16,6 +16,7 @@ use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, TransparencyError};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::{Applicability, ErrorGuaranteed};
+use rustc_feature::Features;
use rustc_lint_defs::builtin::{
RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
};
@@ -249,7 +250,7 @@ fn expand_macro<'cx>(
trace_macros_note(&mut cx.expansions, sp, msg);
}
- let p = Parser::new(sess, tts, false, None);
+ let p = Parser::new(sess, tts, None);
if is_local {
cx.resolver.record_macro_rule_usage(node_id, i);
@@ -257,7 +258,7 @@ fn expand_macro<'cx>(
// Let the context choose how to interpret the result.
// Weird, but useful for X-macros.
- return Box::new(ParserAnyMacro {
+ Box::new(ParserAnyMacro {
parser: p,
// Pass along the original expansion site and the name of the macro
@@ -269,18 +270,17 @@ fn expand_macro<'cx>(
is_trailing_mac: cx.current_expansion.is_trailing_mac,
arm_span,
is_local,
- });
+ })
}
Err(CanRetry::No(_)) => {
debug!("Will not retry matching as an error was emitted already");
- return DummyResult::any(sp);
+ DummyResult::any(sp)
}
Err(CanRetry::Yes) => {
- // Retry and emit a better error below.
+ // Retry and emit a better error.
+ diagnostics::failed_to_match_macro(cx, sp, def_span, name, arg, lhses)
}
}
-
- diagnostics::failed_to_match_macro(cx, sp, def_span, name, arg, lhses)
}
pub(super) enum CanRetry {
@@ -376,6 +376,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
/// Converts a macro item into a syntax extension.
pub fn compile_declarative_macro(
sess: &Session,
+ features: &Features,
def: &ast::Item,
edition: Edition,
) -> (SyntaxExtension, Vec<(usize, Span)>) {
@@ -383,6 +384,7 @@ pub fn compile_declarative_macro(
let mk_syn_ext = |expander| {
SyntaxExtension::new(
sess,
+ features,
SyntaxExtensionKind::LegacyBang(expander),
def.span,
Vec::new(),
@@ -447,7 +449,7 @@ pub fn compile_declarative_macro(
let create_parser = || {
let body = macro_def.body.tokens.clone();
- Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS)
+ Parser::new(&sess.parse_sess, body, rustc_parse::MACRO_ARGUMENTS)
};
let parser = create_parser();
@@ -457,8 +459,8 @@ pub fn compile_declarative_macro(
match tt_parser.parse_tt(&mut Cow::Owned(parser), &argument_gram, &mut NoopTracker) {
Success(m) => m,
Failure(()) => {
- // The fast `NoopTracker` doesn't have any info on failure, so we need to retry it with another one
- // that gives us the information we need.
+ // The fast `NoopTracker` doesn't have any info on failure, so we need to retry it
+ // with another one that gives us the information we need.
// For this we need to reclone the macro body as the previous parser consumed it.
let retry_parser = create_parser();
@@ -500,11 +502,11 @@ pub fn compile_declarative_macro(
.map(|m| {
if let MatchedTokenTree(tt) = m {
let tt = mbe::quoted::parse(
- TokenStream::new(vec![tt.clone()]),
+ &TokenStream::new(vec![tt.clone()]),
true,
&sess.parse_sess,
def.id,
- sess.features_untracked(),
+ features,
edition,
)
.pop()
@@ -524,11 +526,11 @@ pub fn compile_declarative_macro(
.map(|m| {
if let MatchedTokenTree(tt) = m {
return mbe::quoted::parse(
- TokenStream::new(vec![tt.clone()]),
+ &TokenStream::new(vec![tt.clone()]),
false,
&sess.parse_sess,
def.id,
- sess.features_untracked(),
+ features,
edition,
)
.pop()
@@ -554,7 +556,7 @@ 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));
+ diag.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");
@@ -1197,10 +1199,10 @@ fn check_matcher_core<'tt>(
may_be = may_be
),
);
- err.span_label(sp, format!("not allowed after `{}` fragments", kind));
+ err.span_label(sp, format!("not allowed after `{kind}` fragments"));
if kind == NonterminalKind::PatWithOr
- && sess.edition.rust_2021()
+ && sess.edition.at_least_rust_2021()
&& next_token.is_token(&BinOp(token::BinOpToken::Or))
{
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
@@ -1221,8 +1223,7 @@ fn check_matcher_core<'tt>(
&[] => {}
&[t] => {
err.note(format!(
- "only {} is allowed after `{}` fragments",
- t, kind,
+ "only {t} is allowed after `{kind}` fragments",
));
}
ts => {
@@ -1327,7 +1328,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
_ => IsInFollow::No(TOKENS),
}
}
- NonterminalKind::PatWithOr { .. } => {
+ NonterminalKind::PatWithOr => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"];
match tok {
TokenTree::Token(token) => match token.kind {
@@ -1407,9 +1408,9 @@ 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::MetaVar(_, name) => format!("${}", name),
- mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind),
- mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name),
+ mbe::TokenTree::MetaVar(_, name) => format!("${name}"),
+ mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${name}:{kind}"),
+ mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${name}:"),
_ => panic!(
"{}",
"unexpected mbe::TokenTree::{Sequence or Delimited} \
@@ -1418,6 +1419,11 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
}
}
-pub(super) fn parser_from_cx(sess: &ParseSess, tts: TokenStream, recovery: Recovery) -> Parser<'_> {
- Parser::new(sess, tts, true, rustc_parse::MACRO_ARGUMENTS).recovery(recovery)
+pub(super) fn parser_from_cx(
+ sess: &ParseSess,
+ mut tts: TokenStream,
+ recovery: Recovery,
+) -> Parser<'_> {
+ tts.desugar_doc_comments();
+ Parser::new(sess, tts, rustc_parse::MACRO_ARGUMENTS).recovery(recovery)
}
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index 6e9196150..7c37aadc6 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -93,7 +93,17 @@ fn parse_count<'sess>(
span: Span,
) -> PResult<'sess, MetaVarExpr> {
let ident = parse_ident(iter, sess, span)?;
- let depth = if try_eat_comma(iter) { Some(parse_depth(iter, sess, span)?) } else { None };
+ let depth = if try_eat_comma(iter) {
+ if iter.look_ahead(0).is_none() {
+ return Err(sess.span_diagnostic.struct_span_err(
+ span,
+ "`count` followed by a comma must have an associated index indicating its depth",
+ ));
+ }
+ Some(parse_depth(iter, sess, span)?)
+ } else {
+ None
+ };
Ok(MetaVarExpr::Count(ident, depth))
}
@@ -104,13 +114,10 @@ fn parse_depth<'sess>(
span: Span,
) -> PResult<'sess, usize> {
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.struct_span_err(
- span,
- "meta-variable expression depth must be a literal"
- ));
+ let TokenTree::Token(token::Token { kind: token::TokenKind::Literal(lit), .. }, _) = tt else {
+ return Err(sess
+ .span_diagnostic
+ .struct_span_err(span, "meta-variable expression depth must be a literal"));
};
if let Ok(lit_kind) = LitKind::from_token_lit(*lit)
&& let LitKind::Int(n_u128, LitIntType::Unsuffixed) = lit_kind
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 40bfa3715..6546199f5 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -36,7 +36,7 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
///
/// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`.
pub(super) fn parse(
- input: tokenstream::TokenStream,
+ input: &tokenstream::TokenStream,
parsing_patterns: bool,
sess: &ParseSess,
node_id: NodeId,
@@ -48,7 +48,7 @@ pub(super) fn parse(
// For each token tree in `input`, parse the token into a `self::TokenTree`, consuming
// additional trees if need be.
- let mut trees = input.into_trees();
+ let mut trees = input.trees();
while let Some(tree) = trees.next() {
// Given the parsed tree, if there is a metavar and we are expecting matchers, actually
// parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
@@ -56,7 +56,7 @@ pub(super) fn parse(
match tree {
TokenTree::MetaVar(start_sp, ident) if parsing_patterns => {
let span = match trees.next() {
- Some(tokenstream::TokenTree::Token(Token { kind: token::Colon, span }, _)) => {
+ Some(&tokenstream::TokenTree::Token(Token { kind: token::Colon, span }, _)) => {
match trees.next() {
Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
Some((frag, _)) => {
@@ -96,10 +96,10 @@ pub(super) fn parse(
}
_ => token.span,
},
- tree => tree.as_ref().map_or(span, tokenstream::TokenTree::span),
+ tree => tree.map_or(span, tokenstream::TokenTree::span),
}
}
- tree => tree.as_ref().map_or(start_sp, tokenstream::TokenTree::span),
+ tree => tree.map_or(start_sp, tokenstream::TokenTree::span),
};
result.push(TokenTree::MetaVarDecl(span, ident, None));
@@ -134,9 +134,9 @@ fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &ParseSess,
/// - `parsing_patterns`: same as [parse].
/// - `sess`: the parsing session. Any errors will be emitted to this session.
/// - `features`: language features so we can do feature gating.
-fn parse_tree(
- tree: tokenstream::TokenTree,
- outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
+fn parse_tree<'a>(
+ tree: &'a tokenstream::TokenTree,
+ outer_trees: &mut impl Iterator<Item = &'a tokenstream::TokenTree>,
parsing_patterns: bool,
sess: &ParseSess,
node_id: NodeId,
@@ -146,13 +146,13 @@ fn parse_tree(
// Depending on what `tree` is, we could be parsing different parts of a macro
match tree {
// `tree` is a `$` token. Look at the next token in `trees`
- tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }, _) => {
+ &tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }, _) => {
// FIXME: Handle `Invisible`-delimited groups in a more systematic way
// during parsing.
let mut next = outer_trees.next();
- let mut trees: Box<dyn Iterator<Item = tokenstream::TokenTree>>;
+ let mut trees: Box<dyn Iterator<Item = &tokenstream::TokenTree>>;
if let Some(tokenstream::TokenTree::Delimited(_, Delimiter::Invisible, tts)) = next {
- trees = Box::new(tts.into_trees());
+ trees = Box::new(tts.trees());
next = trees.next();
} else {
trees = Box::new(outer_trees);
@@ -160,7 +160,7 @@ fn parse_tree(
match next {
// `tree` is followed by a delimited set of token trees.
- Some(tokenstream::TokenTree::Delimited(delim_span, delim, 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(
@@ -194,7 +194,7 @@ fn parse_tree(
Delimiter::Parenthesis => {}
_ => {
let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
- let msg = format!("expected `(` or `{{`, found `{}`", tok);
+ let msg = format!("expected `(` or `{{`, found `{tok}`");
sess.span_diagnostic.span_err(delim_span.entire(), msg);
}
}
@@ -228,7 +228,7 @@ fn parse_tree(
}
// `tree` is followed by another `$`. This is an escaped `$`.
- Some(tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }, _)) => {
+ Some(&tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }, _)) => {
if parsing_patterns {
span_dollar_dollar_or_metavar_in_the_lhs_err(
sess,
@@ -256,11 +256,11 @@ fn parse_tree(
}
// `tree` is an arbitrary token. Keep it.
- tokenstream::TokenTree::Token(token, _) => TokenTree::Token(token),
+ tokenstream::TokenTree::Token(token, _) => TokenTree::Token(token.clone()),
// `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, tts) => TokenTree::Delimited(
+ &tokenstream::TokenTree::Delimited(span, delim, ref tts) => TokenTree::Delimited(
span,
Delimited {
delim,
@@ -286,16 +286,16 @@ fn kleene_op(token: &Token) -> Option<KleeneOp> {
/// - Ok(Ok((op, span))) if the next token tree is a KleeneOp
/// - Ok(Err(tok, span)) if the next token tree is a token but not a KleeneOp
/// - Err(span) if the next token tree is not a token
-fn parse_kleene_op(
- input: &mut impl Iterator<Item = tokenstream::TokenTree>,
+fn parse_kleene_op<'a>(
+ input: &mut impl Iterator<Item = &'a tokenstream::TokenTree>,
span: Span,
) -> Result<Result<(KleeneOp, Span), Token>, Span> {
match input.next() {
Some(tokenstream::TokenTree::Token(token, _)) => match kleene_op(&token) {
Some(op) => Ok(Ok((op, token.span))),
- None => Ok(Err(token)),
+ None => Ok(Err(token.clone())),
},
- tree => Err(tree.as_ref().map_or(span, tokenstream::TokenTree::span)),
+ tree => Err(tree.map_or(span, tokenstream::TokenTree::span)),
}
}
@@ -311,8 +311,8 @@ fn parse_kleene_op(
/// session `sess`. If the next one (or possibly two) tokens in `input` correspond to a Kleene
/// operator and separator, then a tuple with `(separator, KleeneOp)` is returned. Otherwise, an
/// error with the appropriate span is emitted to `sess` and a dummy value is returned.
-fn parse_sep_and_kleene_op(
- input: &mut impl Iterator<Item = tokenstream::TokenTree>,
+fn parse_sep_and_kleene_op<'a>(
+ input: &mut impl Iterator<Item = &'a tokenstream::TokenTree>,
span: Span,
sess: &ParseSess,
) -> (Option<Token>, KleeneToken) {
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index d523d3eac..15e7ab3fe 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -182,9 +182,7 @@ pub(super) fn transcribe<'a>(
LockstepIterSize::Constraint(len, _) => {
// We do this to avoid an extra clone above. We know that this is a
// sequence already.
- let mbe::TokenTree::Sequence(sp, seq) = seq else {
- unreachable!()
- };
+ let mbe::TokenTree::Sequence(sp, seq) = seq else { unreachable!() };
// Is the repetition empty?
if len == 0 {
@@ -222,16 +220,15 @@ pub(super) fn transcribe<'a>(
MatchedTokenTree(tt) => {
// `tt`s are emitted into the output stream directly as "raw tokens",
// without wrapping them into groups.
- let token = tt.clone();
- result.push(token);
+ result.push(tt.clone());
}
MatchedNonterminal(nt) => {
// Other variables are emitted into the output stream as groups with
// `Delimiter::Invisible` to maintain parsing priorities.
// `Interpolated` is currently used for such groups in rustc parser.
marker.visit_span(&mut sp);
- let token = TokenTree::token_alone(token::Interpolated(nt.clone()), sp);
- result.push(token);
+ result
+ .push(TokenTree::token_alone(token::Interpolated(nt.clone()), sp));
}
MatchedSeq(..) => {
// We were unable to descend far enough. This is an error.
@@ -399,7 +396,9 @@ fn lockstep_iter_size(
}
TokenTree::MetaVarExpr(_, expr) => {
let default_rslt = LockstepIterSize::Unconstrained;
- let Some(ident) = expr.ident() else { return default_rslt; };
+ let Some(ident) = expr.ident() else {
+ return default_rslt;
+ };
let name = MacroRulesNormalizedIdent::new(ident);
match lookup_cur_matched(name, interpolations, repeats) {
Some(MatchedSeq(ads)) => {
diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs
index 8b37728b6..bdc20882a 100644
--- a/compiler/rustc_expand/src/parse/tests.rs
+++ b/compiler/rustc_expand/src/parse/tests.rs
@@ -1,4 +1,6 @@
-use crate::tests::{matches_codepattern, string_to_stream, with_error_checking_parse};
+use crate::tests::{
+ matches_codepattern, string_to_stream, with_error_checking_parse, with_expected_parse_error,
+};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token};
@@ -51,11 +53,15 @@ fn string_to_item(source_str: String) -> Option<P<ast::Item>> {
with_error_checking_parse(source_str, &sess(), |p| p.parse_item(ForceCollect::No))
}
-#[should_panic]
#[test]
fn bad_path_expr_1() {
+ // This should trigger error: expected identifier, found keyword `return`
create_default_session_globals_then(|| {
- string_to_expr("::abc::def::return".to_string());
+ with_expected_parse_error(
+ "::abc::def::return",
+ "expected identifier, found keyword `return`",
+ |p| p.parse_expr(),
+ );
})
}
@@ -63,9 +69,8 @@ fn bad_path_expr_1() {
#[test]
fn string_to_tts_macro() {
create_default_session_globals_then(|| {
- let tts: Vec<_> =
- string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).into_trees().collect();
- let tts: &[TokenTree] = &tts[..];
+ let stream = string_to_stream("macro_rules! zip (($a)=>($a))".to_string());
+ let tts = &stream.trees().collect::<Vec<_>>()[..];
match tts {
[
@@ -294,9 +299,7 @@ fn ttdelim_span() {
.unwrap();
let ast::ExprKind::MacCall(mac) = &expr.kind else { panic!("not a macro") };
- let tts: Vec<_> = mac.args.tokens.clone().into_trees().collect();
-
- let span = tts.iter().rev().next().unwrap().span();
+ let span = mac.args.tokens.trees().last().unwrap().span();
match sess.source_map().span_to_snippet(span) {
Ok(s) => assert_eq!(&s[..], "{ body }"),
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index e9af688ee..82cac2292 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -2,6 +2,7 @@ use crate::expand::{AstFragment, AstFragmentKind};
use rustc_ast as ast;
use rustc_ast::mut_visit::*;
use rustc_ast::ptr::P;
+use rustc_ast::token::Delimiter;
use rustc_data_structures::fx::FxHashMap;
use rustc_span::source_map::DUMMY_SP;
use rustc_span::symbol::Ident;
@@ -18,7 +19,7 @@ pub fn placeholder(
path: ast::Path { span: DUMMY_SP, segments: ThinVec::new(), tokens: None },
args: P(ast::DelimArgs {
dspan: ast::tokenstream::DelimSpan::dummy(),
- delim: ast::MacDelimiter::Parenthesis,
+ delim: Delimiter::Parenthesis,
tokens: ast::tokenstream::TokenStream::new(Vec::new()),
}),
})
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 41b24407f..c617cd76e 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -95,7 +95,7 @@ impl base::AttrProcMacro for AttrProcMacro {
|e| {
let mut err = ecx.struct_span_err(span, "custom attribute panicked");
if let Some(s) = e.as_str() {
- err.help(format!("message: {}", s));
+ err.help(format!("message: {s}"));
}
err.emit()
},
@@ -148,7 +148,7 @@ impl MultiItemModifier for DeriveProcMacro {
Err(e) => {
let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
if let Some(s) = e.as_str() {
- err.help(format!("message: {}", s));
+ err.help(format!("message: {s}"));
}
err.emit();
return ExpandResult::Ready(vec![]);
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index ecd231511..2dc9b51a3 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -94,10 +94,10 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
// Estimate the capacity as `stream.len()` rounded up to the next power
// of two to limit the number of required reallocations.
let mut trees = Vec::with_capacity(stream.len().next_power_of_two());
- let mut cursor = stream.into_trees();
+ let mut cursor = stream.trees();
while let Some(tree) = cursor.next() {
- let (Token { kind, span }, joint) = match tree {
+ let (Token { kind, span }, joint) = match tree.clone() {
tokenstream::TokenTree::Delimited(span, delim, tts) => {
let delimiter = pm::Delimiter::from_internal(delim);
trees.push(TokenTree::Group(Group {
@@ -622,7 +622,7 @@ impl server::SourceFile for Rustc<'_, '_> {
impl server::Span for Rustc<'_, '_> {
fn debug(&mut self, span: Self::Span) -> String {
if self.ecx.ecfg.span_debug {
- format!("{:?}", span)
+ format!("{span:?}")
} else {
format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0)
}
diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs
index 8a5e09475..8e3219c13 100644
--- a/compiler/rustc_expand/src/tests.rs
+++ b/compiler/rustc_expand/src/tests.rs
@@ -8,7 +8,8 @@ use rustc_span::{BytePos, Span};
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::{Handler, MultiSpan, PResult, TerminalUrl};
+use rustc_errors::{Handler, MultiSpan, PResult};
+use termcolor::WriteColor;
use std::io;
use std::io::prelude::*;
@@ -22,6 +23,23 @@ 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>>>) {
+ 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(
+ vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
+ false,
+ );
+ 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)
+}
+
+/// Returns the result of parsing the given string via the given callback.
+///
+/// If there are any errors, this will panic.
pub(crate) fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T
where
F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
@@ -32,6 +50,26 @@ where
x
}
+/// Verifies that parsing the given string using the given callback will
+/// generate an error that contains the given text.
+pub(crate) fn with_expected_parse_error<T, F>(source_str: &str, expected_output: &str, f: F)
+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 mut p = string_to_parser(&ps, source_str.to_string());
+ let result = f(&mut p);
+ assert!(result.is_ok());
+
+ let bytes = output.lock().unwrap();
+ let actual_output = str::from_utf8(&bytes).unwrap();
+ println!("expected output:\n------\n{}------", expected_output);
+ println!("actual output:\n------\n{}------", actual_output);
+
+ assert!(actual_output.contains(expected_output))
+}
+
/// Maps a string to tts, using a made-up filename.
pub(crate) fn string_to_stream(source_str: String) -> TokenStream {
let ps = ParseSess::new(
@@ -118,6 +156,20 @@ pub(crate) struct Shared<T: Write> {
pub data: Arc<Mutex<T>>,
}
+impl<T: Write> WriteColor for Shared<T> {
+ fn supports_color(&self) -> bool {
+ false
+ }
+
+ fn set_color(&mut self, _spec: &termcolor::ColorSpec) -> io::Result<()> {
+ Ok(())
+ }
+
+ fn reset(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
impl<T: Write> Write for Shared<T> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.data.lock().unwrap().write(buf)
@@ -130,13 +182,7 @@ impl<T: Write> Write for Shared<T> {
fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
create_default_session_if_not_set_then(|_| {
- let output = Arc::new(Mutex::new(Vec::new()));
-
- let fallback_bundle = rustc_errors::fallback_fluent_bundle(
- vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
- false,
- );
- let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+ let (handler, source_map, output) = create_test_handler();
source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned());
let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
@@ -148,20 +194,6 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
println!("text: {:?}", source_map.span_to_snippet(span));
}
- let emitter = EmitterWriter::new(
- Box::new(Shared { data: output.clone() }),
- Some(source_map.clone()),
- None,
- fallback_bundle,
- false,
- false,
- false,
- None,
- false,
- false,
- TerminalUrl::No,
- );
- let handler = Handler::with_emitter(true, None, Box::new(emitter));
#[allow(rustc::untranslatable_diagnostic)]
handler.span_err(msp, "foo");