Rollup merge of #70074 - Centril:unpanictry, r=petrochenkov
Expand: nix all fatal errors Basically, we go after all `.span_fatal` / `FatalError.raise()` and similar things and remove them one by one until there are no fatal errors left. r? @petrochenkov
This commit is contained in:
commit
3d8b9614d3
@ -3,7 +3,6 @@
|
||||
use rustc_ast::ast::{self, AttrItem, AttrStyle};
|
||||
use rustc_ast::attr::mk_attr;
|
||||
use rustc_ast::token;
|
||||
use rustc_expand::panictry;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::FileName;
|
||||
|
||||
@ -16,7 +15,13 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -
|
||||
);
|
||||
|
||||
let start_span = parser.token.span;
|
||||
let AttrItem { path, args } = panictry!(parser.parse_attr_item());
|
||||
let AttrItem { path, args } = match parser.parse_attr_item() {
|
||||
Ok(ai) => ai,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let end_span = parser.token.span;
|
||||
if parser.token != token::Eof {
|
||||
parse_sess.span_diagnostic.span_err(start_span.to(end_span), "invalid crate attribute");
|
||||
|
@ -5,7 +5,6 @@ use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_expand::module::DirectoryOwnership;
|
||||
use rustc_expand::panictry;
|
||||
use rustc_parse::{self, new_parser_from_file, parser::Parser};
|
||||
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
|
||||
use rustc_span::symbol::Symbol;
|
||||
@ -126,7 +125,7 @@ pub fn expand_include<'cx>(
|
||||
}
|
||||
impl<'a> base::MacResult for ExpandResult<'a> {
|
||||
fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
|
||||
let r = panictry!(self.p.parse_expr());
|
||||
let r = base::parse_expr(&mut self.p)?;
|
||||
if self.p.token != token::Eof {
|
||||
self.p.sess.buffer_lint(
|
||||
&INCOMPLETE_INCLUDE,
|
||||
@ -141,18 +140,17 @@ pub fn expand_include<'cx>(
|
||||
fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
|
||||
let mut ret = SmallVec::new();
|
||||
while self.p.token != token::Eof {
|
||||
match panictry!(self.p.parse_item()) {
|
||||
Some(item) => ret.push(item),
|
||||
None => {
|
||||
match self.p.parse_item() {
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
break;
|
||||
}
|
||||
Ok(Some(item)) => ret.push(item),
|
||||
Ok(None) => {
|
||||
let token = pprust::token_to_string(&self.p.token);
|
||||
self.p
|
||||
.sess
|
||||
.span_diagnostic
|
||||
.span_fatal(
|
||||
self.p.token.span,
|
||||
&format!("expected item, found `{}`", token),
|
||||
)
|
||||
.raise();
|
||||
let msg = format!("expected item, found `{}`", token);
|
||||
self.p.struct_span_err(self.p.token.span, &msg).emit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,16 +74,16 @@ pub fn expand_test_or_bench(
|
||||
return vec![];
|
||||
}
|
||||
|
||||
let item = if let Annotatable::Item(i) = item {
|
||||
i
|
||||
} else {
|
||||
cx.parse_sess
|
||||
.span_diagnostic
|
||||
.span_fatal(
|
||||
item.span(),
|
||||
let item = match item {
|
||||
Annotatable::Item(i) => i,
|
||||
other => {
|
||||
cx.struct_span_err(
|
||||
other.span(),
|
||||
"`#[test]` attribute is only allowed on non associated functions",
|
||||
)
|
||||
.raise();
|
||||
.emit();
|
||||
return vec![other];
|
||||
}
|
||||
};
|
||||
|
||||
if let ast::ItemKind::MacCall(_) = item.kind {
|
||||
|
@ -345,14 +345,14 @@ fn is_test_case(i: &ast::Item) -> bool {
|
||||
|
||||
fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
|
||||
let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
|
||||
test_attr.meta_item_list().map(|meta_list| {
|
||||
if meta_list.len() != 1 {
|
||||
sd.span_fatal(test_attr.span, "`#![test_runner(..)]` accepts exactly 1 argument")
|
||||
.raise()
|
||||
}
|
||||
match meta_list[0].meta_item() {
|
||||
Some(meta_item) if meta_item.is_word() => meta_item.path.clone(),
|
||||
_ => sd.span_fatal(test_attr.span, "`test_runner` argument must be a path").raise(),
|
||||
}
|
||||
})
|
||||
let meta_list = test_attr.meta_item_list()?;
|
||||
let span = test_attr.span;
|
||||
match &*meta_list {
|
||||
[single] => match single.meta_item() {
|
||||
Some(meta_item) if meta_item.is_word() => return Some(meta_item.path.clone()),
|
||||
_ => sd.struct_span_err(span, "`test_runner` argument must be a path").emit(),
|
||||
},
|
||||
_ => sd.struct_span_err(span, "`#![test_runner(..)]` accepts exactly 1 argument").emit(),
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use rustc_ast::visit::{AssocCtxt, Visitor};
|
||||
use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::{self, Lrc};
|
||||
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
|
||||
use rustc_errors::{DiagnosticBuilder, ErrorReported};
|
||||
use rustc_parse::{self, parser, MACRO_ARGUMENTS};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::edition::Edition;
|
||||
@ -296,16 +296,26 @@ where
|
||||
}
|
||||
|
||||
pub trait ProcMacro {
|
||||
fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt<'_>, span: Span, ts: TokenStream) -> TokenStream;
|
||||
fn expand<'cx>(
|
||||
&self,
|
||||
ecx: &'cx mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
ts: TokenStream,
|
||||
) -> Result<TokenStream, ErrorReported>;
|
||||
}
|
||||
|
||||
impl<F> ProcMacro for F
|
||||
where
|
||||
F: Fn(TokenStream) -> TokenStream,
|
||||
{
|
||||
fn expand<'cx>(&self, _ecx: &'cx mut ExtCtxt<'_>, _span: Span, ts: TokenStream) -> TokenStream {
|
||||
fn expand<'cx>(
|
||||
&self,
|
||||
_ecx: &'cx mut ExtCtxt<'_>,
|
||||
_span: Span,
|
||||
ts: TokenStream,
|
||||
) -> Result<TokenStream, ErrorReported> {
|
||||
// FIXME setup implicit context in TLS before calling self.
|
||||
(*self)(ts)
|
||||
Ok((*self)(ts))
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,7 +326,7 @@ pub trait AttrProcMacro {
|
||||
span: Span,
|
||||
annotation: TokenStream,
|
||||
annotated: TokenStream,
|
||||
) -> TokenStream;
|
||||
) -> Result<TokenStream, ErrorReported>;
|
||||
}
|
||||
|
||||
impl<F> AttrProcMacro for F
|
||||
@ -329,9 +339,9 @@ where
|
||||
_span: Span,
|
||||
annotation: TokenStream,
|
||||
annotated: TokenStream,
|
||||
) -> TokenStream {
|
||||
) -> Result<TokenStream, ErrorReported> {
|
||||
// FIXME setup implicit context in TLS before calling self.
|
||||
(*self)(annotation, annotated)
|
||||
Ok((*self)(annotation, annotated))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1004,31 +1014,9 @@ impl<'a> ExtCtxt<'a> {
|
||||
self.current_expansion.id.expansion_cause()
|
||||
}
|
||||
|
||||
pub fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
self.parse_sess.span_diagnostic.struct_span_warn(sp, msg)
|
||||
}
|
||||
pub fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
self.parse_sess.span_diagnostic.struct_span_err(sp, msg)
|
||||
}
|
||||
pub fn struct_span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
self.parse_sess.span_diagnostic.struct_span_fatal(sp, msg)
|
||||
}
|
||||
|
||||
/// Emit `msg` attached to `sp`, and stop compilation immediately.
|
||||
///
|
||||
/// `span_err` should be strongly preferred where-ever possible:
|
||||
/// this should *only* be used when:
|
||||
///
|
||||
/// - continuing has a high risk of flow-on errors (e.g., errors in
|
||||
/// declaring a macro would cause all uses of that macro to
|
||||
/// complain about "undefined macro"), or
|
||||
/// - there is literally nothing else that can be done (however,
|
||||
/// in most cases one can construct a dummy expression/item to
|
||||
/// substitute; we never hit resolve/type-checking so the dummy
|
||||
/// value doesn't have to match anything)
|
||||
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
|
||||
self.parse_sess.span_diagnostic.span_fatal(sp, msg).raise();
|
||||
}
|
||||
|
||||
/// Emit `msg` attached to `sp`, without immediately stopping
|
||||
/// compilation.
|
||||
@ -1038,9 +1026,6 @@ impl<'a> ExtCtxt<'a> {
|
||||
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
self.parse_sess.span_diagnostic.span_err(sp, msg);
|
||||
}
|
||||
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
|
||||
self.parse_sess.span_diagnostic.span_err_with_code(sp, msg, code);
|
||||
}
|
||||
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
self.parse_sess.span_diagnostic.span_warn(sp, msg);
|
||||
}
|
||||
@ -1168,6 +1153,18 @@ pub fn check_zero_tts(cx: &ExtCtxt<'_>, sp: Span, tts: TokenStream, name: &str)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse an expression. On error, emit it, advancing to `Eof`, and return `None`.
|
||||
pub fn parse_expr(p: &mut parser::Parser<'_>) -> Option<P<ast::Expr>> {
|
||||
match p.parse_expr() {
|
||||
Ok(e) => return Some(e),
|
||||
Err(mut err) => err.emit(),
|
||||
}
|
||||
while p.token != token::Eof {
|
||||
p.bump();
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Interpreting `tts` as a comma-separated sequence of expressions,
|
||||
/// expect exactly one string literal, or emit an error and return `None`.
|
||||
pub fn get_single_str_from_tts(
|
||||
@ -1181,7 +1178,7 @@ pub fn get_single_str_from_tts(
|
||||
cx.span_err(sp, &format!("{} takes 1 argument", name));
|
||||
return None;
|
||||
}
|
||||
let ret = panictry!(p.parse_expr());
|
||||
let ret = parse_expr(&mut p)?;
|
||||
let _ = p.eat(&token::Comma);
|
||||
|
||||
if p.token != token::Eof {
|
||||
@ -1190,8 +1187,8 @@ pub fn get_single_str_from_tts(
|
||||
expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s.to_string())
|
||||
}
|
||||
|
||||
/// Extracts comma-separated expressions from `tts`. If there is a
|
||||
/// parsing error, emit a non-fatal error and return `None`.
|
||||
/// Extracts comma-separated expressions from `tts`.
|
||||
/// On error, emit it, and return `None`.
|
||||
pub fn get_exprs_from_tts(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
@ -1200,7 +1197,7 @@ pub fn get_exprs_from_tts(
|
||||
let mut p = cx.new_parser_from_tts(tts);
|
||||
let mut es = Vec::new();
|
||||
while p.token != token::Eof {
|
||||
let expr = panictry!(p.parse_expr());
|
||||
let expr = parse_expr(&mut p)?;
|
||||
|
||||
// Perform eager expansion on the expression.
|
||||
// We want to be able to handle e.g., `concat!("foo", "bar")`.
|
||||
|
@ -204,7 +204,7 @@ ast_fragments! {
|
||||
}
|
||||
|
||||
impl AstFragmentKind {
|
||||
fn dummy(self, span: Span) -> AstFragment {
|
||||
crate fn dummy(self, span: Span) -> AstFragment {
|
||||
self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment")
|
||||
}
|
||||
|
||||
@ -682,7 +682,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
InvocationKind::Bang { mac, .. } => match ext {
|
||||
SyntaxExtensionKind::Bang(expander) => {
|
||||
self.gate_proc_macro_expansion_kind(span, fragment_kind);
|
||||
let tok_result = expander.expand(self.cx, span, mac.args.inner_tokens());
|
||||
let tok_result = match expander.expand(self.cx, span, mac.args.inner_tokens()) {
|
||||
Err(_) => return ExpandResult::Ready(fragment_kind.dummy(span)),
|
||||
Ok(ts) => ts,
|
||||
};
|
||||
self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span)
|
||||
}
|
||||
SyntaxExtensionKind::LegacyBang(expander) => {
|
||||
@ -709,8 +712,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
if let MacArgs::Eq(..) = attr_item.args {
|
||||
self.cx.span_err(span, "key-value macro attributes are not supported");
|
||||
}
|
||||
let tok_result =
|
||||
expander.expand(self.cx, span, attr_item.args.inner_tokens(), tokens);
|
||||
let inner_tokens = attr_item.args.inner_tokens();
|
||||
let tok_result = match expander.expand(self.cx, span, inner_tokens, tokens) {
|
||||
Err(_) => return ExpandResult::Ready(fragment_kind.dummy(span)),
|
||||
Ok(ts) => ts,
|
||||
};
|
||||
self.parse_ast_fragment(tok_result, fragment_kind, &attr_item.path, span)
|
||||
}
|
||||
SyntaxExtensionKind::LegacyAttr(expander) => {
|
||||
@ -1139,6 +1145,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
||||
// macros are expanded before any lint passes so this warning has to be hardcoded
|
||||
if attr.has_name(sym::derive) {
|
||||
self.cx
|
||||
.parse_sess()
|
||||
.span_diagnostic
|
||||
.struct_span_warn(attr.span, "`#[derive]` does nothing on macro invocations")
|
||||
.note("this may become a hard error in a future release")
|
||||
.emit();
|
||||
|
@ -9,25 +9,6 @@
|
||||
|
||||
extern crate proc_macro as pm;
|
||||
|
||||
// A variant of 'try!' that panics on an Err. This is used as a crutch on the
|
||||
// way towards a non-panic!-prone parser. It should be used for fatal parsing
|
||||
// errors; eventually we plan to convert all code using panictry to just use
|
||||
// normal try.
|
||||
#[macro_export]
|
||||
macro_rules! panictry {
|
||||
($e:expr) => {{
|
||||
use rustc_errors::FatalError;
|
||||
use std::result::Result::{Err, Ok};
|
||||
match $e {
|
||||
Ok(e) => e,
|
||||
Err(mut e) => {
|
||||
e.emit();
|
||||
FatalError.raise()
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
mod placeholders;
|
||||
mod proc_macro_server;
|
||||
|
||||
|
@ -84,7 +84,7 @@ use rustc_parse::parser::{FollowedByType, Parser, PathStyle};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent, Symbol};
|
||||
|
||||
use rustc_errors::{FatalError, PResult};
|
||||
use rustc_errors::PResult;
|
||||
use rustc_span::Span;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
@ -271,6 +271,7 @@ crate enum ParseResult<T> {
|
||||
Failure(Token, &'static str),
|
||||
/// Fatal error (malformed macro?). Abort compilation.
|
||||
Error(rustc_span::Span, String),
|
||||
ErrorReported,
|
||||
}
|
||||
|
||||
/// A `ParseResult` where the `Success` variant contains a mapping of
|
||||
@ -652,6 +653,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
|
||||
Success(_) => {}
|
||||
Failure(token, msg) => return Failure(token, msg),
|
||||
Error(sp, msg) => return Error(sp, msg),
|
||||
ErrorReported => return ErrorReported,
|
||||
}
|
||||
|
||||
// inner parse loop handled all cur_items, so it's empty
|
||||
@ -735,10 +737,11 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
|
||||
let mut item = bb_items.pop().unwrap();
|
||||
if let TokenTree::MetaVarDecl(span, _, ident) = item.top_elts.get_tt(item.idx) {
|
||||
let match_cur = item.match_cur;
|
||||
item.push_match(
|
||||
match_cur,
|
||||
MatchedNonterminal(Lrc::new(parse_nt(parser.to_mut(), span, ident.name))),
|
||||
);
|
||||
let nt = match parse_nt(parser.to_mut(), span, ident.name) {
|
||||
Err(()) => return ErrorReported,
|
||||
Ok(nt) => nt,
|
||||
};
|
||||
item.push_match(match_cur, MatchedNonterminal(Lrc::new(nt)));
|
||||
item.idx += 1;
|
||||
item.match_cur += 1;
|
||||
} else {
|
||||
@ -849,20 +852,16 @@ fn may_begin_with(token: &Token, name: Name) -> bool {
|
||||
/// # Returns
|
||||
///
|
||||
/// The parsed non-terminal.
|
||||
fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Nonterminal {
|
||||
fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Result<Nonterminal, ()> {
|
||||
// FIXME(Centril): Consider moving this to `parser.rs` to make
|
||||
// the visibilities of the methods used below `pub(super)` at most.
|
||||
|
||||
if name == sym::tt {
|
||||
return token::NtTT(p.parse_token_tree());
|
||||
}
|
||||
match parse_nt_inner(p, sp, name) {
|
||||
Ok(nt) => nt,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
return Ok(token::NtTT(p.parse_token_tree()));
|
||||
}
|
||||
parse_nt_inner(p, sp, name).map_err(|mut err| {
|
||||
err.span_label(sp, format!("while parsing argument for this `{}` macro fragment", name))
|
||||
.emit()
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_nt_inner<'a>(p: &mut Parser<'a>, sp: Span, name: Symbol) -> PResult<'a, Nonterminal> {
|
||||
|
@ -4,7 +4,7 @@ use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstF
|
||||
use crate::mbe;
|
||||
use crate::mbe::macro_check;
|
||||
use crate::mbe::macro_parser::parse_tt;
|
||||
use crate::mbe::macro_parser::{Error, Failure, Success};
|
||||
use crate::mbe::macro_parser::{Error, ErrorReported, Failure, Success};
|
||||
use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq};
|
||||
use crate::mbe::transcribe::transcribe;
|
||||
|
||||
@ -15,7 +15,7 @@ use rustc_ast_pretty::pprust;
|
||||
use rustc_attr::{self as attr, TransparencyError};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder, FatalError};
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_feature::Features;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_session::parse::ParseSess;
|
||||
@ -83,41 +83,56 @@ fn suggest_slice_pat(e: &mut DiagnosticBuilder<'_>, site_span: Span, parser: &Pa
|
||||
);
|
||||
}
|
||||
|
||||
fn emit_frag_parse_err(
|
||||
mut e: DiagnosticBuilder<'_>,
|
||||
parser: &Parser<'_>,
|
||||
site_span: Span,
|
||||
macro_ident: ast::Ident,
|
||||
arm_span: Span,
|
||||
kind: AstFragmentKind,
|
||||
) {
|
||||
if parser.token == token::Eof && e.message().ends_with(", found `<eof>`") {
|
||||
if !e.span.is_dummy() {
|
||||
// early end of macro arm (#52866)
|
||||
e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
|
||||
}
|
||||
let msg = &e.message[0];
|
||||
e.message[0] = (
|
||||
format!(
|
||||
"macro expansion ends with an incomplete expression: {}",
|
||||
msg.0.replace(", found `<eof>`", ""),
|
||||
),
|
||||
msg.1,
|
||||
);
|
||||
}
|
||||
if e.span.is_dummy() {
|
||||
// Get around lack of span in error (#30128)
|
||||
e.replace_span_with(site_span);
|
||||
if !parser.sess.source_map().is_imported(arm_span) {
|
||||
e.span_label(arm_span, "in this macro arm");
|
||||
}
|
||||
} else if parser.sess.source_map().is_imported(parser.token.span) {
|
||||
e.span_label(site_span, "in this macro invocation");
|
||||
}
|
||||
match kind {
|
||||
AstFragmentKind::Pat if macro_ident.name == sym::vec => {
|
||||
suggest_slice_pat(&mut e, site_span, parser);
|
||||
}
|
||||
_ => annotate_err_with_kind(&mut e, kind, site_span),
|
||||
};
|
||||
e.emit();
|
||||
}
|
||||
|
||||
impl<'a> ParserAnyMacro<'a> {
|
||||
crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
|
||||
let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
|
||||
let fragment = panictry!(parse_ast_fragment(parser, kind).map_err(|mut e| {
|
||||
if parser.token == token::Eof && e.message().ends_with(", found `<eof>`") {
|
||||
if !e.span.is_dummy() {
|
||||
// early end of macro arm (#52866)
|
||||
e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
|
||||
}
|
||||
let msg = &e.message[0];
|
||||
e.message[0] = (
|
||||
format!(
|
||||
"macro expansion ends with an incomplete expression: {}",
|
||||
msg.0.replace(", found `<eof>`", ""),
|
||||
),
|
||||
msg.1,
|
||||
);
|
||||
let fragment = match parse_ast_fragment(parser, kind) {
|
||||
Ok(f) => f,
|
||||
Err(err) => {
|
||||
emit_frag_parse_err(err, parser, site_span, macro_ident, arm_span, kind);
|
||||
return kind.dummy(site_span);
|
||||
}
|
||||
if e.span.is_dummy() {
|
||||
// Get around lack of span in error (#30128)
|
||||
e.replace_span_with(site_span);
|
||||
if !parser.sess.source_map().is_imported(arm_span) {
|
||||
e.span_label(arm_span, "in this macro arm");
|
||||
}
|
||||
} else if parser.sess.source_map().is_imported(parser.token.span) {
|
||||
e.span_label(site_span, "in this macro invocation");
|
||||
}
|
||||
match kind {
|
||||
AstFragmentKind::Pat if macro_ident.name == sym::vec => {
|
||||
suggest_slice_pat(&mut e, site_span, parser);
|
||||
}
|
||||
_ => annotate_err_with_kind(&mut e, kind, site_span),
|
||||
};
|
||||
e
|
||||
}));
|
||||
};
|
||||
|
||||
// We allow semicolons at the end of expressions -- e.g., the semicolon in
|
||||
// `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`,
|
||||
@ -165,6 +180,14 @@ impl TTMacroExpander for MacroRulesMacroExpander {
|
||||
}
|
||||
}
|
||||
|
||||
fn macro_rules_dummy_expander<'cx>(
|
||||
_: &'cx mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
_: TokenStream,
|
||||
) -> Box<dyn MacResult + 'cx> {
|
||||
DummyResult::any(span)
|
||||
}
|
||||
|
||||
fn trace_macros_note(cx_expansions: &mut FxHashMap<Span, Vec<String>>, sp: Span, message: String) {
|
||||
let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp);
|
||||
cx_expansions.entry(sp).or_default().push(message);
|
||||
@ -240,7 +263,13 @@ fn generic_extension<'cx>(
|
||||
|
||||
let rhs_spans = rhs.iter().map(|t| t.span()).collect::<Vec<_>>();
|
||||
// rhs has holes ( `$id` and `$(...)` that need filled)
|
||||
let mut tts = transcribe(cx, &named_matches, rhs, transparency);
|
||||
let mut tts = match transcribe(cx, &named_matches, rhs, transparency) {
|
||||
Ok(tts) => tts,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
return DummyResult::any(arm_span);
|
||||
}
|
||||
};
|
||||
|
||||
// Replace all the tokens for the corresponding positions in the macro, to maintain
|
||||
// proper positions in error reporting, while maintaining the macro_backtrace.
|
||||
@ -278,7 +307,12 @@ fn generic_extension<'cx>(
|
||||
Some((ref best_token, _)) if best_token.span.lo() >= token.span.lo() => {}
|
||||
_ => best_failure = Some((token, msg)),
|
||||
},
|
||||
Error(err_sp, ref msg) => cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..]),
|
||||
Error(err_sp, ref msg) => {
|
||||
let span = err_sp.substitute_dummy(sp);
|
||||
cx.struct_span_err(span, &msg).emit();
|
||||
return DummyResult::any(span);
|
||||
}
|
||||
ErrorReported => return DummyResult::any(sp),
|
||||
}
|
||||
|
||||
// The matcher was not `Success(..)`ful.
|
||||
@ -337,6 +371,18 @@ pub fn compile_declarative_macro(
|
||||
def: &ast::Item,
|
||||
edition: Edition,
|
||||
) -> SyntaxExtension {
|
||||
let mk_syn_ext = |expander| {
|
||||
SyntaxExtension::new(
|
||||
sess,
|
||||
SyntaxExtensionKind::LegacyBang(expander),
|
||||
def.span,
|
||||
Vec::new(),
|
||||
edition,
|
||||
def.ident.name,
|
||||
&def.attrs,
|
||||
)
|
||||
};
|
||||
|
||||
let diag = &sess.span_diagnostic;
|
||||
let lhs_nm = ast::Ident::new(sym::lhs, def.span);
|
||||
let rhs_nm = ast::Ident::new(sym::rhs, def.span);
|
||||
@ -391,13 +437,15 @@ pub fn compile_declarative_macro(
|
||||
Failure(token, msg) => {
|
||||
let s = parse_failure_msg(&token);
|
||||
let sp = token.span.substitute_dummy(def.span);
|
||||
let mut err = sess.span_diagnostic.struct_span_fatal(sp, &s);
|
||||
err.span_label(sp, msg);
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
sess.span_diagnostic.struct_span_err(sp, &s).span_label(sp, msg).emit();
|
||||
return mk_syn_ext(Box::new(macro_rules_dummy_expander));
|
||||
}
|
||||
Error(sp, s) => {
|
||||
sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &s).raise();
|
||||
Error(sp, msg) => {
|
||||
sess.span_diagnostic.struct_span_err(sp.substitute_dummy(def.span), &msg).emit();
|
||||
return mk_syn_ext(Box::new(macro_rules_dummy_expander));
|
||||
}
|
||||
ErrorReported => {
|
||||
return mk_syn_ext(Box::new(macro_rules_dummy_expander));
|
||||
}
|
||||
};
|
||||
|
||||
@ -460,24 +508,14 @@ pub fn compile_declarative_macro(
|
||||
None => {}
|
||||
}
|
||||
|
||||
let expander: Box<_> = Box::new(MacroRulesMacroExpander {
|
||||
mk_syn_ext(Box::new(MacroRulesMacroExpander {
|
||||
name: def.ident,
|
||||
span: def.span,
|
||||
transparency,
|
||||
lhses,
|
||||
rhses,
|
||||
valid,
|
||||
});
|
||||
|
||||
SyntaxExtension::new(
|
||||
sess,
|
||||
SyntaxExtensionKind::LegacyBang(expander),
|
||||
def.span,
|
||||
Vec::new(),
|
||||
edition,
|
||||
def.ident.name,
|
||||
&def.attrs,
|
||||
)
|
||||
}))
|
||||
}
|
||||
|
||||
fn check_lhs_nt_follows(
|
||||
|
@ -8,7 +8,7 @@ use rustc_ast::token::{self, NtTT, Token};
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::pluralize;
|
||||
use rustc_errors::{pluralize, PResult};
|
||||
use rustc_span::hygiene::{ExpnId, Transparency};
|
||||
use rustc_span::symbol::MacroRulesNormalizedIdent;
|
||||
use rustc_span::Span;
|
||||
@ -80,15 +80,15 @@ impl Iterator for Frame {
|
||||
/// `transcribe` would return a `TokenStream` containing `println!("{}", stringify!(bar));`.
|
||||
///
|
||||
/// Along the way, we do some additional error checking.
|
||||
pub(super) fn transcribe(
|
||||
cx: &ExtCtxt<'_>,
|
||||
pub(super) fn transcribe<'a>(
|
||||
cx: &ExtCtxt<'a>,
|
||||
interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
|
||||
src: Vec<mbe::TokenTree>,
|
||||
transparency: Transparency,
|
||||
) -> TokenStream {
|
||||
) -> PResult<'a, TokenStream> {
|
||||
// Nothing for us to transcribe...
|
||||
if src.is_empty() {
|
||||
return TokenStream::default();
|
||||
return Ok(TokenStream::default());
|
||||
}
|
||||
|
||||
// We descend into the RHS (`src`), expanding things as we go. This stack contains the things
|
||||
@ -152,7 +152,7 @@ pub(super) fn transcribe(
|
||||
Frame::Delimited { forest, span, .. } => {
|
||||
if result_stack.is_empty() {
|
||||
// No results left to compute! We are back at the top-level.
|
||||
return TokenStream::new(result);
|
||||
return Ok(TokenStream::new(result));
|
||||
}
|
||||
|
||||
// Step back into the parent Delimited.
|
||||
@ -173,11 +173,11 @@ pub(super) fn transcribe(
|
||||
seq @ mbe::TokenTree::Sequence(..) => {
|
||||
match lockstep_iter_size(&seq, interp, &repeats) {
|
||||
LockstepIterSize::Unconstrained => {
|
||||
cx.span_fatal(
|
||||
return Err(cx.struct_span_err(
|
||||
seq.span(), /* blame macro writer */
|
||||
"attempted to repeat an expression containing no syntax variables \
|
||||
matched as repeating at this depth",
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
LockstepIterSize::Contradiction(ref msg) => {
|
||||
@ -185,7 +185,7 @@ pub(super) fn transcribe(
|
||||
// happens when two meta-variables are used in the same repetition in a
|
||||
// sequence, but they come from different sequence matchers and repeat
|
||||
// different amounts.
|
||||
cx.span_fatal(seq.span(), &msg[..]);
|
||||
return Err(cx.struct_span_err(seq.span(), &msg[..]));
|
||||
}
|
||||
|
||||
LockstepIterSize::Constraint(len, _) => {
|
||||
@ -203,7 +203,10 @@ pub(super) fn transcribe(
|
||||
// FIXME: this really ought to be caught at macro definition
|
||||
// time... It happens when the Kleene operator in the matcher and
|
||||
// the body for the same meta-variable do not match.
|
||||
cx.span_fatal(sp.entire(), "this must repeat at least once");
|
||||
return Err(cx.struct_span_err(
|
||||
sp.entire(),
|
||||
"this must repeat at least once",
|
||||
));
|
||||
}
|
||||
} else {
|
||||
// 0 is the initial counter (we have done 0 repretitions so far). `len`
|
||||
@ -242,10 +245,10 @@ pub(super) fn transcribe(
|
||||
}
|
||||
} else {
|
||||
// We were unable to descend far enough. This is an error.
|
||||
cx.span_fatal(
|
||||
return Err(cx.struct_span_err(
|
||||
sp, /* blame the macro writer */
|
||||
&format!("variable '{}' is still repeating at this depth", ident),
|
||||
);
|
||||
));
|
||||
}
|
||||
} else {
|
||||
// If we aren't able to match the meta-var, we push it back into the result but
|
||||
|
@ -5,7 +5,7 @@ use rustc_ast::ast::{self, ItemKind, MetaItemKind, NestedMetaItem};
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::{self, TokenStream};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Applicability, FatalError};
|
||||
use rustc_errors::{Applicability, ErrorReported};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
@ -21,21 +21,16 @@ impl base::ProcMacro for BangProcMacro {
|
||||
ecx: &'cx mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
input: TokenStream,
|
||||
) -> TokenStream {
|
||||
) -> Result<TokenStream, ErrorReported> {
|
||||
let server = proc_macro_server::Rustc::new(ecx);
|
||||
match self.client.run(&EXEC_STRATEGY, server, input) {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
let msg = "proc macro panicked";
|
||||
let mut err = ecx.struct_span_fatal(span, msg);
|
||||
if let Some(s) = e.as_str() {
|
||||
err.help(&format!("message: {}", s));
|
||||
}
|
||||
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
self.client.run(&EXEC_STRATEGY, server, input).map_err(|e| {
|
||||
let mut err = ecx.struct_span_err(span, "proc macro panicked");
|
||||
if let Some(s) = e.as_str() {
|
||||
err.help(&format!("message: {}", s));
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
ErrorReported
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,21 +45,16 @@ impl base::AttrProcMacro for AttrProcMacro {
|
||||
span: Span,
|
||||
annotation: TokenStream,
|
||||
annotated: TokenStream,
|
||||
) -> TokenStream {
|
||||
) -> Result<TokenStream, ErrorReported> {
|
||||
let server = proc_macro_server::Rustc::new(ecx);
|
||||
match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
let msg = "custom attribute panicked";
|
||||
let mut err = ecx.struct_span_fatal(span, msg);
|
||||
if let Some(s) = e.as_str() {
|
||||
err.help(&format!("message: {}", s));
|
||||
}
|
||||
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
self.client.run(&EXEC_STRATEGY, server, annotation, annotated).map_err(|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.emit();
|
||||
ErrorReported
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,8 +86,7 @@ impl MultiItemModifier for ProcMacroDerive {
|
||||
| Annotatable::Expr(_) => {
|
||||
ecx.span_err(
|
||||
span,
|
||||
"proc-macro derives may only be \
|
||||
applied to a struct, enum, or union",
|
||||
"proc-macro derives may only be applied to a struct, enum, or union",
|
||||
);
|
||||
return ExpandResult::Ready(Vec::new());
|
||||
}
|
||||
@ -107,8 +96,7 @@ impl MultiItemModifier for ProcMacroDerive {
|
||||
_ => {
|
||||
ecx.span_err(
|
||||
span,
|
||||
"proc-macro derives may only be \
|
||||
applied to a struct, enum, or union",
|
||||
"proc-macro derives may only be applied to a struct, enum, or union",
|
||||
);
|
||||
return ExpandResult::Ready(Vec::new());
|
||||
}
|
||||
@ -121,20 +109,16 @@ impl MultiItemModifier for ProcMacroDerive {
|
||||
let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
let msg = "proc-macro derive panicked";
|
||||
let mut err = ecx.struct_span_fatal(span, msg);
|
||||
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.emit();
|
||||
FatalError.raise();
|
||||
return ExpandResult::Ready(vec![]);
|
||||
}
|
||||
};
|
||||
|
||||
let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
|
||||
let msg = "proc-macro derive produced unparseable tokens";
|
||||
|
||||
let mut parser =
|
||||
rustc_parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
|
||||
let mut items = vec![];
|
||||
@ -144,18 +128,15 @@ impl MultiItemModifier for ProcMacroDerive {
|
||||
Ok(None) => break,
|
||||
Ok(Some(item)) => items.push(Annotatable::Item(item)),
|
||||
Err(mut err) => {
|
||||
// FIXME: handle this better
|
||||
err.cancel();
|
||||
ecx.struct_span_fatal(span, msg).emit();
|
||||
FatalError.raise();
|
||||
err.emit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fail if there have been errors emitted
|
||||
if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
|
||||
ecx.struct_span_fatal(span, msg).emit();
|
||||
FatalError.raise();
|
||||
ecx.struct_span_err(span, "proc-macro derive produced unparseable tokens").emit();
|
||||
}
|
||||
|
||||
ExpandResult::Ready(items)
|
||||
|
@ -1,9 +1,17 @@
|
||||
// edition:2018
|
||||
// aux-build:edition-kw-macro-2015.rs
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
fn main() {}
|
||||
|
||||
#[macro_use]
|
||||
extern crate edition_kw_macro_2015;
|
||||
|
||||
mod module {
|
||||
pub fn r#async() {}
|
||||
}
|
||||
|
||||
pub fn check_async() {
|
||||
let mut async = 1; //~ ERROR expected identifier, found keyword `async`
|
||||
let mut r#async = 1; // OK
|
||||
@ -17,4 +25,6 @@ pub fn check_async() {
|
||||
if passes_ident!(r#async) == 1 {} // OK
|
||||
module::async(); //~ ERROR expected identifier, found keyword `async`
|
||||
module::r#async(); // OK
|
||||
|
||||
let _recovery_witness: () = 0; //~ ERROR mismatched types
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: expected identifier, found keyword `async`
|
||||
--> $DIR/edition-keywords-2018-2015-parsing.rs:8:13
|
||||
--> $DIR/edition-keywords-2018-2015-parsing.rs:16:13
|
||||
|
|
||||
LL | let mut async = 1;
|
||||
| ^^^^^ expected identifier, found keyword
|
||||
@ -10,7 +10,7 @@ LL | let mut r#async = 1;
|
||||
| ^^^^^^^
|
||||
|
||||
error: expected identifier, found keyword `async`
|
||||
--> $DIR/edition-keywords-2018-2015-parsing.rs:18:13
|
||||
--> $DIR/edition-keywords-2018-2015-parsing.rs:26:13
|
||||
|
|
||||
LL | module::async();
|
||||
| ^^^^^ expected identifier, found keyword
|
||||
@ -21,13 +21,13 @@ LL | module::r#async();
|
||||
| ^^^^^^^
|
||||
|
||||
error: no rules expected the token `r#async`
|
||||
--> $DIR/edition-keywords-2018-2015-parsing.rs:12:31
|
||||
--> $DIR/edition-keywords-2018-2015-parsing.rs:20:31
|
||||
|
|
||||
LL | r#async = consumes_async!(r#async);
|
||||
| ^^^^^^^ no rules expected this token in macro call
|
||||
|
||||
error: no rules expected the token `async`
|
||||
--> $DIR/edition-keywords-2018-2015-parsing.rs:13:35
|
||||
--> $DIR/edition-keywords-2018-2015-parsing.rs:21:35
|
||||
|
|
||||
LL | r#async = consumes_async_raw!(async);
|
||||
| ^^^^^ no rules expected this token in macro call
|
||||
@ -38,10 +38,19 @@ error: macro expansion ends with an incomplete expression: expected one of `move
|
||||
LL | ($i: ident) => ($i)
|
||||
| ^ expected one of `move`, `|`, or `||`
|
||||
|
|
||||
::: $DIR/edition-keywords-2018-2015-parsing.rs:16:8
|
||||
::: $DIR/edition-keywords-2018-2015-parsing.rs:24:8
|
||||
|
|
||||
LL | if passes_ident!(async) == 1 {}
|
||||
| -------------------- in this macro invocation
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/edition-keywords-2018-2015-parsing.rs:29:33
|
||||
|
|
||||
LL | let _recovery_witness: () = 0;
|
||||
| -- ^ expected `()`, found integer
|
||||
| |
|
||||
| expected due to this
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -1,9 +1,17 @@
|
||||
// edition:2018
|
||||
// aux-build:edition-kw-macro-2018.rs
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
fn main() {}
|
||||
|
||||
#[macro_use]
|
||||
extern crate edition_kw_macro_2018;
|
||||
|
||||
mod module {
|
||||
pub fn r#async() {}
|
||||
}
|
||||
|
||||
pub fn check_async() {
|
||||
let mut async = 1; //~ ERROR expected identifier, found keyword `async`
|
||||
let mut r#async = 1; // OK
|
||||
@ -17,4 +25,6 @@ pub fn check_async() {
|
||||
if passes_ident!(r#async) == 1 {} // OK
|
||||
module::async(); //~ ERROR expected identifier, found keyword `async`
|
||||
module::r#async(); // OK
|
||||
|
||||
let _recovery_witness: () = 0; //~ ERROR mismatched types
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: expected identifier, found keyword `async`
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:8:13
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:16:13
|
||||
|
|
||||
LL | let mut async = 1;
|
||||
| ^^^^^ expected identifier, found keyword
|
||||
@ -10,7 +10,7 @@ LL | let mut r#async = 1;
|
||||
| ^^^^^^^
|
||||
|
||||
error: expected identifier, found keyword `async`
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:18:13
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:26:13
|
||||
|
|
||||
LL | module::async();
|
||||
| ^^^^^ expected identifier, found keyword
|
||||
@ -21,13 +21,13 @@ LL | module::r#async();
|
||||
| ^^^^^^^
|
||||
|
||||
error: no rules expected the token `r#async`
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:12:31
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:20:31
|
||||
|
|
||||
LL | r#async = consumes_async!(r#async);
|
||||
| ^^^^^^^ no rules expected this token in macro call
|
||||
|
||||
error: no rules expected the token `async`
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:13:35
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:21:35
|
||||
|
|
||||
LL | r#async = consumes_async_raw!(async);
|
||||
| ^^^^^ no rules expected this token in macro call
|
||||
@ -38,10 +38,19 @@ error: macro expansion ends with an incomplete expression: expected one of `move
|
||||
LL | ($i: ident) => ($i)
|
||||
| ^ expected one of `move`, `|`, or `||`
|
||||
|
|
||||
::: $DIR/edition-keywords-2018-2018-parsing.rs:16:8
|
||||
::: $DIR/edition-keywords-2018-2018-parsing.rs:24:8
|
||||
|
|
||||
LL | if passes_ident!(async) == 1 {}
|
||||
| -------------------- in this macro invocation
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:29:33
|
||||
|
|
||||
LL | let _recovery_witness: () = 0;
|
||||
| -- ^ expected `()`, found integer
|
||||
| |
|
||||
| expected due to this
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -1,9 +1,10 @@
|
||||
// Regression test for issue #61033.
|
||||
|
||||
macro_rules! test1 {
|
||||
($x:ident, $($tt:tt)*) => { $($tt)+ } //~ERROR this must repeat at least once
|
||||
($x:ident, $($tt:tt)*) => { $($tt)+ } //~ ERROR this must repeat at least once
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test1!(x,);
|
||||
let _recovery_witness: () = 0; //~ ERROR mismatched types
|
||||
}
|
||||
|
@ -4,5 +4,14 @@ error: this must repeat at least once
|
||||
LL | ($x:ident, $($tt:tt)*) => { $($tt)+ }
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-61033-1.rs:9:33
|
||||
|
|
||||
LL | let _recovery_witness: () = 0;
|
||||
| -- ^ expected `()`, found integer
|
||||
| |
|
||||
| expected due to this
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -5,7 +5,9 @@ macro_rules! test2 {
|
||||
$(* $id1:ident)*
|
||||
$(+ $id2:ident)*
|
||||
) => {
|
||||
$( //~ERROR meta-variable `id1` repeats 2 times
|
||||
$(
|
||||
//~^ ERROR meta-variable `id1` repeats 2 times
|
||||
//~| ERROR meta-variable `id1` repeats 2 times
|
||||
$id1 + $id2 // $id1 and $id2 may repeat different numbers of times
|
||||
)*
|
||||
}
|
||||
@ -16,4 +18,8 @@ fn main() {
|
||||
* a * b
|
||||
+ a + b + c
|
||||
}
|
||||
test2! {
|
||||
* a * b
|
||||
+ a + b + c + d
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,22 @@ error: meta-variable `id1` repeats 2 times, but `id2` repeats 3 times
|
||||
|
|
||||
LL | $(
|
||||
| __________^
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | $id1 + $id2 // $id1 and $id2 may repeat different numbers of times
|
||||
LL | | )*
|
||||
| |_________^
|
||||
|
||||
error: aborting due to previous error
|
||||
error: meta-variable `id1` repeats 2 times, but `id2` repeats 4 times
|
||||
--> $DIR/issue-61033-2.rs:8:10
|
||||
|
|
||||
LL | $(
|
||||
| __________^
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | $id1 + $id2 // $id1 and $id2 may repeat different numbers of times
|
||||
LL | | )*
|
||||
| |_________^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
fn main() {}
|
||||
|
||||
macro_rules! ambiguity {
|
||||
($($i:ident)* $j:ident) => {};
|
||||
}
|
||||
|
||||
ambiguity!(error); //~ ERROR local ambiguity
|
||||
ambiguity!(error); //~ ERROR local ambiguity
|
@ -0,0 +1,14 @@
|
||||
error: local ambiguity: multiple parsing options: built-in NTs ident ('i') or ident ('j').
|
||||
--> $DIR/local-ambiguity-multiple-parsing-options.rs:7:12
|
||||
|
|
||||
LL | ambiguity!(error);
|
||||
| ^^^^^
|
||||
|
||||
error: local ambiguity: multiple parsing options: built-in NTs ident ('i') or ident ('j').
|
||||
--> $DIR/local-ambiguity-multiple-parsing-options.rs:8:12
|
||||
|
|
||||
LL | ambiguity!(error);
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -4,6 +4,8 @@ macro_rules! m {
|
||||
//~| ERROR macro expansion ignores token `typeof`
|
||||
//~| ERROR macro expansion ignores token `;`
|
||||
//~| ERROR macro expansion ignores token `;`
|
||||
//~| ERROR cannot find type `i` in this scope
|
||||
//~| ERROR cannot find value `i` in this scope
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -42,5 +42,29 @@ LL | m!();
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error[E0412]: cannot find type `i` in this scope
|
||||
--> $DIR/macro-context.rs:3:13
|
||||
|
|
||||
LL | () => ( i ; typeof );
|
||||
| ^ help: a builtin type with a similar name exists: `i8`
|
||||
...
|
||||
LL | let a: m!();
|
||||
| ---- in this macro invocation
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0425]: cannot find value `i` in this scope
|
||||
--> $DIR/macro-context.rs:3:13
|
||||
|
|
||||
LL | () => ( i ; typeof );
|
||||
| ^ help: a local variable with a similar name exists: `a`
|
||||
...
|
||||
LL | let i = m!();
|
||||
| ---- in this macro invocation
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0412, E0425.
|
||||
For more information about an error, try `rustc --explain E0412`.
|
||||
|
@ -1,4 +1,11 @@
|
||||
macro_rules! test { ($a, $b) => (()); } //~ ERROR missing fragment
|
||||
macro_rules! test {
|
||||
($a, $b) => {
|
||||
//~^ ERROR missing fragment
|
||||
//~| ERROR missing fragment
|
||||
//~| WARN this was previously accepted
|
||||
()
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test!()
|
||||
|
@ -1,8 +1,18 @@
|
||||
error: missing fragment specifier
|
||||
--> $DIR/macro-match-nonterminal.rs:1:24
|
||||
--> $DIR/macro-match-nonterminal.rs:2:8
|
||||
|
|
||||
LL | macro_rules! test { ($a, $b) => (()); }
|
||||
| ^
|
||||
LL | ($a, $b) => {
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
error: missing fragment specifier
|
||||
--> $DIR/macro-match-nonterminal.rs:2:10
|
||||
|
|
||||
LL | ($a, $b) => {
|
||||
| ^^
|
||||
|
|
||||
= note: `#[deny(missing_fragment_specifier)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// compile-flags: -Z trace-macros
|
||||
|
||||
#![recursion_limit="4"]
|
||||
#![recursion_limit = "4"]
|
||||
|
||||
macro_rules! my_faulty_macro {
|
||||
() => {
|
||||
@ -24,9 +24,7 @@ macro_rules! my_recursive_macro {
|
||||
}
|
||||
|
||||
macro_rules! my_macro {
|
||||
() => {
|
||||
|
||||
};
|
||||
() => {};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@ -39,7 +37,7 @@ fn main() {
|
||||
}
|
||||
|
||||
#[my_macro]
|
||||
fn use_bang_macro_as_attr(){}
|
||||
fn use_bang_macro_as_attr() {}
|
||||
|
||||
#[derive(Debug)]
|
||||
fn use_derive_macro_as_attr(){}
|
||||
#[derive(Debug)] //~ ERROR `derive` may only be applied to structs
|
||||
fn use_derive_macro_as_attr() {}
|
||||
|
@ -13,7 +13,7 @@ LL | my_faulty_macro!();
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
note: trace_macro
|
||||
--> $DIR/trace_faulty_macros.rs:33:5
|
||||
--> $DIR/trace_faulty_macros.rs:31:5
|
||||
|
|
||||
LL | my_faulty_macro!();
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
@ -35,7 +35,7 @@ LL | my_recursive_macro!();
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
note: trace_macro
|
||||
--> $DIR/trace_faulty_macros.rs:34:5
|
||||
--> $DIR/trace_faulty_macros.rs:32:5
|
||||
|
|
||||
LL | my_recursive_macro!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -60,5 +60,22 @@ LL | let a = pat_macro!();
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: `derive` may only be applied to structs, enums and unions
|
||||
--> $DIR/trace_faulty_macros.rs:42:1
|
||||
|
|
||||
LL | #[derive(Debug)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
note: trace_macro
|
||||
--> $DIR/trace_faulty_macros.rs:36:13
|
||||
|
|
||||
LL | let a = pat_macro!();
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: expanding `pat_macro! { }`
|
||||
= note: to `pat_macro ! (A { a : a, b : 0, c : _, .. }) ;`
|
||||
= note: expanding `pat_macro! { A { a : a, b : 0, c : _, .. } }`
|
||||
= note: to `A { a: a, b: 0, c: _, .. }`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
// FIXME: missing sysroot spans (#53081)
|
||||
// ignore-i586-unknown-linux-gnu
|
||||
// ignore-i586-unknown-linux-musl
|
||||
// ignore-i686-unknown-linux-musl
|
||||
|
||||
// Regression test for #62894, shouldn't crash.
|
||||
// error-pattern: this file contains an unclosed delimiter
|
||||
// error-pattern: expected one of `(`, `[`, or `{`, found keyword `fn`
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: this file contains an unclosed delimiter
|
||||
--> $DIR/issue-62894.rs:7:14
|
||||
--> $DIR/issue-62894.rs:12:14
|
||||
|
|
||||
LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq!
|
||||
| - - - unclosed delimiter
|
||||
@ -11,7 +11,7 @@ LL | fn main() {}
|
||||
| ^
|
||||
|
||||
error: this file contains an unclosed delimiter
|
||||
--> $DIR/issue-62894.rs:7:14
|
||||
--> $DIR/issue-62894.rs:12:14
|
||||
|
|
||||
LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq!
|
||||
| - - - unclosed delimiter
|
||||
@ -23,7 +23,7 @@ LL | fn main() {}
|
||||
| ^
|
||||
|
||||
error: this file contains an unclosed delimiter
|
||||
--> $DIR/issue-62894.rs:7:14
|
||||
--> $DIR/issue-62894.rs:12:14
|
||||
|
|
||||
LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq!
|
||||
| - - - unclosed delimiter
|
||||
@ -35,13 +35,18 @@ LL | fn main() {}
|
||||
| ^
|
||||
|
||||
error: expected one of `(`, `[`, or `{`, found keyword `fn`
|
||||
--> $DIR/issue-62894.rs:7:1
|
||||
--> $DIR/issue-62894.rs:12:1
|
||||
|
|
||||
LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq!
|
||||
| - expected one of `(`, `[`, or `{`
|
||||
LL |
|
||||
LL | fn main() {}
|
||||
| ^^ unexpected token
|
||||
|
|
||||
::: $SRC_DIR/libcore/macros/mod.rs:LL:COL
|
||||
|
|
||||
LL | ($left:expr, $right:expr) => ({
|
||||
| ---------- while parsing argument for this `expr` macro fragment
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
@ -6,3 +6,5 @@ macro_rules! foo {
|
||||
}
|
||||
|
||||
foo!();
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,9 +1,12 @@
|
||||
macro_rules! mac {
|
||||
( $($v:tt)* ) => (
|
||||
$v //~ ERROR still repeating at this depth
|
||||
)
|
||||
( $($v:tt)* ) => {
|
||||
$v
|
||||
//~^ ERROR still repeating at this depth
|
||||
//~| ERROR still repeating at this depth
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mac!(0);
|
||||
mac!(1);
|
||||
}
|
||||
|
@ -4,5 +4,11 @@ error: variable 'v' is still repeating at this depth
|
||||
LL | $v
|
||||
| ^^
|
||||
|
||||
error: aborting due to previous error
|
||||
error: variable 'v' is still repeating at this depth
|
||||
--> $DIR/macro-repeat.rs:3:9
|
||||
|
|
||||
LL | $v
|
||||
| ^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
10
src/test/ui/parser/nt-parsing-has-recovery.rs
Normal file
10
src/test/ui/parser/nt-parsing-has-recovery.rs
Normal file
@ -0,0 +1,10 @@
|
||||
macro_rules! foo {
|
||||
($e:expr) => {}
|
||||
}
|
||||
|
||||
foo!(1 + @); //~ ERROR expected expression, found `@`
|
||||
foo!(1 + @); //~ ERROR expected expression, found `@`
|
||||
|
||||
fn main() {
|
||||
let _recovery_witness: () = 0; //~ ERROR mismatched types
|
||||
}
|
29
src/test/ui/parser/nt-parsing-has-recovery.stderr
Normal file
29
src/test/ui/parser/nt-parsing-has-recovery.stderr
Normal file
@ -0,0 +1,29 @@
|
||||
error: expected expression, found `@`
|
||||
--> $DIR/nt-parsing-has-recovery.rs:5:10
|
||||
|
|
||||
LL | ($e:expr) => {}
|
||||
| ------- while parsing argument for this `expr` macro fragment
|
||||
...
|
||||
LL | foo!(1 + @);
|
||||
| ^ expected expression
|
||||
|
||||
error: expected expression, found `@`
|
||||
--> $DIR/nt-parsing-has-recovery.rs:6:10
|
||||
|
|
||||
LL | ($e:expr) => {}
|
||||
| ------- while parsing argument for this `expr` macro fragment
|
||||
...
|
||||
LL | foo!(1 + @);
|
||||
| ^ expected expression
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/nt-parsing-has-recovery.rs:9:33
|
||||
|
|
||||
LL | let _recovery_witness: () = 0;
|
||||
| -- ^ expected `()`, found integer
|
||||
| |
|
||||
| expected due to this
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -3,11 +3,9 @@
|
||||
#[macro_use]
|
||||
extern crate derive_bad;
|
||||
|
||||
#[derive(
|
||||
A
|
||||
)]
|
||||
//~^^ ERROR proc-macro derive produced unparseable tokens
|
||||
#[derive(A)]
|
||||
//~^ ERROR proc-macro derive produced unparseable tokens
|
||||
//~| ERROR expected `:`, found `}`
|
||||
struct A;
|
||||
struct A; //~ ERROR the name `A` is defined multiple times
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,16 +1,28 @@
|
||||
error: expected `:`, found `}`
|
||||
--> $DIR/derive-bad.rs:7:5
|
||||
--> $DIR/derive-bad.rs:6:10
|
||||
|
|
||||
LL | A
|
||||
| ^ expected `:`
|
||||
LL | #[derive(A)]
|
||||
| ^ expected `:`
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: proc-macro derive produced unparseable tokens
|
||||
--> $DIR/derive-bad.rs:7:5
|
||||
--> $DIR/derive-bad.rs:6:10
|
||||
|
|
||||
LL | A
|
||||
| ^
|
||||
LL | #[derive(A)]
|
||||
| ^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0428]: the name `A` is defined multiple times
|
||||
--> $DIR/derive-bad.rs:9:1
|
||||
|
|
||||
LL | #[derive(A)]
|
||||
| - previous definition of the type `A` here
|
||||
...
|
||||
LL | struct A;
|
||||
| ^^^^^^^^^ `A` redefined here
|
||||
|
|
||||
= note: `A` must be defined only once in the type namespace of this module
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0428`.
|
||||
|
@ -14,3 +14,5 @@
|
||||
extern crate invalid_punct_ident;
|
||||
|
||||
invalid_punct!(); //~ ERROR proc macro panicked
|
||||
|
||||
fn main() {}
|
||||
|
@ -14,3 +14,5 @@
|
||||
extern crate invalid_punct_ident;
|
||||
|
||||
invalid_ident!(); //~ ERROR proc macro panicked
|
||||
|
||||
fn main() {}
|
||||
|
@ -14,3 +14,5 @@
|
||||
extern crate invalid_punct_ident;
|
||||
|
||||
invalid_raw_ident!(); //~ ERROR proc macro panicked
|
||||
|
||||
fn main() {}
|
||||
|
@ -3,5 +3,10 @@
|
||||
#[macro_use]
|
||||
extern crate invalid_punct_ident;
|
||||
|
||||
lexer_failure!(); //~ ERROR proc macro panicked
|
||||
//~| ERROR unexpected closing delimiter: `)`
|
||||
lexer_failure!();
|
||||
//~^ ERROR proc macro panicked
|
||||
//~| ERROR unexpected closing delimiter: `)`
|
||||
|
||||
fn main() {
|
||||
let _recovery_witness: () = 0; //~ ERROR mismatched types
|
||||
}
|
||||
|
@ -12,5 +12,14 @@ error: proc macro panicked
|
||||
LL | lexer_failure!();
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/invalid-punct-ident-4.rs:11:33
|
||||
|
|
||||
LL | let _recovery_witness: () = 0;
|
||||
| -- ^ expected `()`, found integer
|
||||
| |
|
||||
| expected due to this
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -5,6 +5,7 @@ extern crate test_macros;
|
||||
|
||||
#[derive(Identity, Panic)] //~ ERROR proc-macro derive panicked
|
||||
struct Baz {
|
||||
//~^ ERROR the name `Baz` is defined multiple times
|
||||
a: i32,
|
||||
b: i32,
|
||||
}
|
||||
|
@ -6,5 +6,17 @@ LL | #[derive(Identity, Panic)]
|
||||
|
|
||||
= help: message: panic-derive
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0428]: the name `Baz` is defined multiple times
|
||||
--> $DIR/issue-36935.rs:7:1
|
||||
|
|
||||
LL | struct Baz {
|
||||
| ^^^^^^^^^^
|
||||
| |
|
||||
| `Baz` redefined here
|
||||
| previous definition of the type `Baz` here
|
||||
|
|
||||
= note: `Baz` must be defined only once in the type namespace of this module
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0428`.
|
||||
|
@ -11,3 +11,5 @@
|
||||
extern crate transitive_dep_two;
|
||||
|
||||
transitive_dep_two::parse_error!(); //~ ERROR expected one of
|
||||
|
||||
fn main() {}
|
||||
|
@ -6,7 +6,13 @@ struct A {}
|
||||
|
||||
impl A {
|
||||
#[test]
|
||||
fn new() -> A { //~ ERROR `#[test]` attribute is only allowed on non associated functions
|
||||
fn new() -> A {
|
||||
//~^ ERROR `#[test]` attribute is only allowed on non associated functions
|
||||
A {}
|
||||
}
|
||||
#[test]
|
||||
fn recovery_witness() -> A {
|
||||
//~^ ERROR `#[test]` attribute is only allowed on non associated functions
|
||||
A {}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,19 @@ error: `#[test]` attribute is only allowed on non associated functions
|
||||
--> $DIR/test-attr-non-associated-functions.rs:9:5
|
||||
|
|
||||
LL | / fn new() -> A {
|
||||
LL | |
|
||||
LL | | A {}
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
||||
error: aborting due to previous error
|
||||
error: `#[test]` attribute is only allowed on non associated functions
|
||||
--> $DIR/test-attr-non-associated-functions.rs:14:5
|
||||
|
|
||||
LL | / fn recovery_witness() -> A {
|
||||
LL | |
|
||||
LL | | A {}
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
fn main() {
|
||||
let _ = Option:Some(vec![0, 1]); //~ ERROR expected type, found
|
||||
//~^ ERROR expected value, found enum `Option`
|
||||
//~| ERROR expected type, found variant `Some`
|
||||
}
|
||||
|
||||
// This case isn't currently being handled gracefully due to the macro invocation.
|
||||
|
@ -13,5 +13,35 @@ LL | let _ = Option:Some(vec![0, 1]);
|
||||
= note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0423]: expected value, found enum `Option`
|
||||
--> $DIR/issue-47666.rs:2:13
|
||||
|
|
||||
LL | let _ = Option:Some(vec![0, 1]);
|
||||
| ^^^^^^
|
||||
|
|
||||
help: try using one of the enum's variants
|
||||
|
|
||||
LL | let _ = std::option::Option::None:Some(vec![0, 1]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let _ = std::option::Option::Some:Some(vec![0, 1]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0573]: expected type, found variant `Some`
|
||||
--> $DIR/issue-47666.rs:2:20
|
||||
|
|
||||
LL | let _ = Option:Some(vec![0, 1]);
|
||||
| ^^^^^^^^^^^^^^^^ not a type
|
||||
|
|
||||
help: try using the variant's enum
|
||||
|
|
||||
LL | let _ = Option:std::option::Option;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
help: maybe you meant to write a path separator here
|
||||
|
|
||||
LL | let _ = Option::Some(vec![0, 1]);
|
||||
| ^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0423, E0573.
|
||||
For more information about an error, try `rustc --explain E0423`.
|
||||
|
Loading…
Reference in New Issue
Block a user