summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_parse
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:03:36 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:03:36 +0000
commit17d40c6057c88f4c432b0d7bac88e1b84cb7e67f (patch)
tree3f66c4a5918660bb8a758ab6cda5ff8ee4f6cdcd /compiler/rustc_parse
parentAdding upstream version 1.64.0+dfsg1. (diff)
downloadrustc-upstream/1.65.0+dfsg1.tar.xz
rustc-upstream/1.65.0+dfsg1.zip
Adding upstream version 1.65.0+dfsg1.upstream/1.65.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs2
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs8
-rw-r--r--compiler/rustc_parse/src/lib.rs6
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs31
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs78
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs476
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs837
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs15
-rw-r--r--compiler/rustc_parse/src/parser/item.rs192
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs45
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs24
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs59
-rw-r--r--compiler/rustc_parse/src/parser/path.rs22
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs70
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs39
-rw-r--r--compiler/rustc_parse_format/src/lib.rs87
-rw-r--r--compiler/rustc_parse_format/src/tests.rs43
17 files changed, 1225 insertions, 809 deletions
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 848e142e5..63819a2f9 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -14,8 +14,6 @@ use rustc_session::parse::ParseSess;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{edition::Edition, BytePos, Pos, Span};
-use tracing::debug;
-
mod tokentrees;
mod unescape_error_reporting;
mod unicode_chars;
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 273827864..77c4fadab 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -20,13 +20,9 @@ pub(crate) fn emit_unescape_error(
range: Range<usize>,
error: EscapeError,
) {
- tracing::debug!(
+ debug!(
"emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}",
- lit,
- span_with_quotes,
- mode,
- range,
- error
+ lit, span_with_quotes, mode, range, error
);
let last_char = || {
let c = lit[range.clone()].chars().rev().next().unwrap();
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 8c087c65c..a37327f42 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -4,7 +4,7 @@
#![feature(box_patterns)]
#![feature(if_let_guard)]
#![feature(let_chains)]
-#![feature(let_else)]
+#![cfg_attr(bootstrap, feature(let_else))]
#![feature(never_type)]
#![feature(rustc_attrs)]
#![recursion_limit = "256"]
@@ -63,7 +63,7 @@ pub fn parse_crate_from_file<'a>(input: &Path, sess: &'a ParseSess) -> PResult<'
pub fn parse_crate_attrs_from_file<'a>(
input: &Path,
sess: &'a ParseSess,
-) -> PResult<'a, Vec<ast::Attribute>> {
+) -> PResult<'a, ast::AttrVec> {
let mut parser = new_parser_from_file(sess, input, None);
parser.parse_inner_attributes()
}
@@ -80,7 +80,7 @@ pub fn parse_crate_attrs_from_source_str(
name: FileName,
source: String,
sess: &ParseSess,
-) -> PResult<'_, Vec<ast::Attribute>> {
+) -> PResult<'_, ast::AttrVec> {
new_parser_from_source_str(sess, name, source).parse_inner_attributes()
}
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index acdbddf40..5fd69b15e 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -7,8 +7,6 @@ use rustc_errors::{error_code, Diagnostic, PResult};
use rustc_span::{sym, BytePos, Span};
use std::convert::TryInto;
-use tracing::debug;
-
// Public for rustfmt usage
#[derive(Debug)]
pub enum InnerAttrPolicy<'a> {
@@ -34,7 +32,7 @@ enum OuterAttributeType {
impl<'a> Parser<'a> {
/// Parses attributes that appear before an item.
pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> {
- let mut outer_attrs: Vec<ast::Attribute> = Vec::new();
+ let mut outer_attrs = ast::AttrVec::new();
let mut just_parsed_doc_comment = false;
let start_pos = self.token_cursor.num_next_calls;
loop {
@@ -89,6 +87,7 @@ impl<'a> Parser<'a> {
// Always make an outer attribute - this allows us to recover from a misplaced
// inner attribute.
Some(attr::mk_doc_comment(
+ &self.sess.attr_id_generator,
comment_kind,
ast::AttrStyle::Outer,
data,
@@ -106,7 +105,7 @@ impl<'a> Parser<'a> {
break;
}
}
- Ok(AttrWrapper::new(outer_attrs.into(), start_pos))
+ Ok(AttrWrapper::new(outer_attrs, start_pos))
}
/// Matches `attribute = # ! [ meta_item ]`.
@@ -140,7 +139,13 @@ impl<'a> Parser<'a> {
this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
}
- Ok(attr::mk_attr_from_item(item, None, style, attr_sp))
+ Ok(attr::mk_attr_from_item(
+ &self.sess.attr_id_generator,
+ item,
+ None,
+ style,
+ attr_sp,
+ ))
} else {
let token_str = pprust::token_to_string(&this.token);
let msg = &format!("expected `#`, found `{token_str}`");
@@ -283,8 +288,8 @@ impl<'a> Parser<'a> {
/// terminated by a semicolon.
///
/// Matches `inner_attrs*`.
- pub(crate) fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
- let mut attrs: Vec<ast::Attribute> = vec![];
+ pub(crate) fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> {
+ let mut attrs = ast::AttrVec::new();
loop {
let start_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap();
// Only try to parse if it is an inner attribute (has `!`).
@@ -293,7 +298,13 @@ impl<'a> Parser<'a> {
} else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
if attr_style == ast::AttrStyle::Inner {
self.bump();
- Some(attr::mk_doc_comment(comment_kind, attr_style, data, self.prev_token.span))
+ Some(attr::mk_doc_comment(
+ &self.sess.attr_id_generator,
+ comment_kind,
+ attr_style,
+ data,
+ self.prev_token.span,
+ ))
} else {
None
}
@@ -303,9 +314,9 @@ impl<'a> Parser<'a> {
if let Some(attr) = attr {
let end_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap();
// If we are currently capturing tokens, mark the location of this inner attribute.
- // If capturing ends up creating a `LazyTokenStream`, we will include
+ // If capturing ends up creating a `LazyAttrTokenStream`, we will include
// this replace range with it, removing the inner attribute from the final
- // `AttrAnnotatedTokenStream`. Inner attributes are stored in the parsed AST note.
+ // `AttrTokenStream`. Inner attributes are stored in the parsed AST note.
// During macro expansion, they are selectively inserted back into the
// token stream (the first inner attribute is removed each time we invoke the
// corresponding macro).
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 6c750ff42..5fdafd187 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -1,7 +1,7 @@
use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor, TrailingToken};
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttributesData, CreateTokenStream};
-use rustc_ast::tokenstream::{AttrAnnotatedTokenTree, DelimSpan, LazyTokenStream, Spacing};
+use rustc_ast::tokenstream::{AttrTokenStream, AttributesData, ToAttrTokenStream};
+use rustc_ast::tokenstream::{AttrTokenTree, DelimSpan, LazyAttrTokenStream, Spacing};
use rustc_ast::{self as ast};
use rustc_ast::{AttrVec, Attribute, HasAttrs, HasTokens};
use rustc_errors::PResult;
@@ -15,11 +15,11 @@ use std::ops::Range;
/// for the attribute target. This allows us to perform cfg-expansion on
/// a token stream before we invoke a derive proc-macro.
///
-/// This wrapper prevents direct access to the underlying `Vec<ast::Attribute>`.
+/// This wrapper prevents direct access to the underlying `ast::AttrVec>`.
/// Parsing code can only get access to the underlying attributes
/// by passing an `AttrWrapper` to `collect_tokens_trailing_tokens`.
/// This makes it difficult to accidentally construct an AST node
-/// (which stores a `Vec<ast::Attribute>`) without first collecting tokens.
+/// (which stores an `ast::AttrVec`) without first collecting tokens.
///
/// This struct has its own module, to ensure that the parser code
/// cannot directly access the `attrs` field
@@ -49,9 +49,10 @@ impl AttrWrapper {
self.attrs
}
+ // Prepend `self.attrs` to `attrs`.
// FIXME: require passing an NT to prevent misuse of this method
- pub(crate) fn prepend_to_nt_inner(self, attrs: &mut Vec<Attribute>) {
- let mut self_attrs: Vec<_> = self.attrs.into();
+ pub(crate) fn prepend_to_nt_inner(self, attrs: &mut AttrVec) {
+ let mut self_attrs = self.attrs;
std::mem::swap(attrs, &mut self_attrs);
attrs.extend(self_attrs);
}
@@ -87,7 +88,7 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool {
// This also makes `Parser` very cheap to clone, since
// there is no intermediate collection buffer to clone.
#[derive(Clone)]
-struct LazyTokenStreamImpl {
+struct LazyAttrTokenStreamImpl {
start_token: (Token, Spacing),
cursor_snapshot: TokenCursor,
num_calls: usize,
@@ -96,10 +97,10 @@ struct LazyTokenStreamImpl {
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(LazyTokenStreamImpl, 144);
+rustc_data_structures::static_assert_size!(LazyAttrTokenStreamImpl, 144);
-impl CreateTokenStream for LazyTokenStreamImpl {
- fn create_token_stream(&self) -> AttrAnnotatedTokenStream {
+impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
+ fn to_attr_token_stream(&self) -> AttrTokenStream {
// The token produced by the final call to `{,inlined_}next` was not
// actually consumed by the callback. The combination of chaining the
// initial token and using `take` produces the desired result - we
@@ -116,7 +117,7 @@ impl CreateTokenStream for LazyTokenStreamImpl {
if !self.replace_ranges.is_empty() {
let mut tokens: Vec<_> = tokens.collect();
- let mut replace_ranges = self.replace_ranges.clone();
+ let mut replace_ranges = self.replace_ranges.to_vec();
replace_ranges.sort_by_key(|(range, _)| range.start);
#[cfg(debug_assertions)]
@@ -146,7 +147,7 @@ impl CreateTokenStream for LazyTokenStreamImpl {
// start position, we ensure that any replace range which encloses
// another replace range will capture the *replaced* tokens for the inner
// range, not the original tokens.
- for (range, new_tokens) in replace_ranges.iter().rev() {
+ for (range, new_tokens) in replace_ranges.into_iter().rev() {
assert!(!range.is_empty(), "Cannot replace an empty range: {:?}", range);
// Replace ranges are only allowed to decrease the number of tokens.
assert!(
@@ -165,7 +166,7 @@ impl CreateTokenStream for LazyTokenStreamImpl {
tokens.splice(
(range.start as usize)..(range.end as usize),
- new_tokens.clone().into_iter().chain(filler),
+ new_tokens.into_iter().chain(filler),
);
}
make_token_stream(tokens.into_iter(), self.break_last_token)
@@ -178,7 +179,7 @@ impl CreateTokenStream for LazyTokenStreamImpl {
impl<'a> Parser<'a> {
/// Records all tokens consumed by the provided callback,
/// including the current token. These tokens are collected
- /// into a `LazyTokenStream`, and returned along with the result
+ /// into a `LazyAttrTokenStream`, and returned along with the result
/// of the callback.
///
/// Note: If your callback consumes an opening delimiter
@@ -196,7 +197,7 @@ impl<'a> Parser<'a> {
&mut self,
attrs: AttrWrapper,
force_collect: ForceCollect,
- f: impl FnOnce(&mut Self, Vec<ast::Attribute>) -> PResult<'a, (R, TrailingToken)>,
+ f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, (R, TrailingToken)>,
) -> PResult<'a, R> {
// We only bail out when nothing could possibly observe the collected tokens:
// 1. We cannot be force collecting tokens (since force-collecting requires tokens
@@ -212,7 +213,7 @@ impl<'a> Parser<'a> {
// or `#[cfg_attr]` attributes.
&& !self.capture_cfg
{
- return Ok(f(self, attrs.attrs.into())?.0);
+ return Ok(f(self, attrs.attrs)?.0);
}
let start_token = (self.token.clone(), self.token_spacing);
@@ -222,7 +223,7 @@ impl<'a> Parser<'a> {
let prev_capturing = std::mem::replace(&mut self.capture_state.capturing, Capturing::Yes);
let replace_ranges_start = self.capture_state.replace_ranges.len();
- let ret = f(self, attrs.attrs.into());
+ let ret = f(self, attrs.attrs);
self.capture_state.capturing = prev_capturing;
@@ -296,8 +297,8 @@ impl<'a> Parser<'a> {
// If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens),
// then extend the range of captured tokens to include it, since the parser
- // was not actually bumped past it. When the `LazyTokenStream` gets converted
- // into an `AttrAnnotatedTokenStream`, we will create the proper token.
+ // was not actually bumped past it. When the `LazyAttrTokenStream` gets converted
+ // into an `AttrTokenStream`, we will create the proper token.
if self.token_cursor.break_last_token {
assert_eq!(
trailing,
@@ -315,20 +316,20 @@ impl<'a> Parser<'a> {
Box::new([])
} else {
// Grab any replace ranges that occur *inside* the current AST node.
- // We will perform the actual replacement when we convert the `LazyTokenStream`
- // to an `AttrAnnotatedTokenStream`
+ // We will perform the actual replacement when we convert the `LazyAttrTokenStream`
+ // to an `AttrTokenStream`.
let start_calls: u32 = cursor_snapshot_next_calls.try_into().unwrap();
self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end]
.iter()
.cloned()
- .chain(inner_attr_replace_ranges.clone().into_iter())
+ .chain(inner_attr_replace_ranges.iter().cloned())
.map(|(range, tokens)| {
((range.start - start_calls)..(range.end - start_calls), tokens)
})
.collect()
};
- let tokens = LazyTokenStream::new(LazyTokenStreamImpl {
+ let tokens = LazyAttrTokenStream::new(LazyAttrTokenStreamImpl {
start_token,
num_calls,
cursor_snapshot,
@@ -352,9 +353,9 @@ impl<'a> Parser<'a> {
// on the captured token stream.
if self.capture_cfg
&& matches!(self.capture_state.capturing, Capturing::Yes)
- && has_cfg_or_cfg_attr(&final_attrs)
+ && has_cfg_or_cfg_attr(final_attrs)
{
- let attr_data = AttributesData { attrs: final_attrs.to_vec().into(), tokens };
+ let attr_data = AttributesData { attrs: final_attrs.iter().cloned().collect(), tokens };
// Replace the entire AST node that we just parsed, including attributes,
// with a `FlatToken::AttrTarget`. If this AST node is inside an item
@@ -391,12 +392,12 @@ impl<'a> Parser<'a> {
fn make_token_stream(
mut iter: impl Iterator<Item = (FlatToken, Spacing)>,
break_last_token: bool,
-) -> AttrAnnotatedTokenStream {
+) -> AttrTokenStream {
#[derive(Debug)]
struct FrameData {
// This is `None` for the first frame, `Some` for all others.
open_delim_sp: Option<(Delimiter, Span)>,
- inner: Vec<(AttrAnnotatedTokenTree, Spacing)>,
+ inner: Vec<AttrTokenTree>,
}
let mut stack = vec![FrameData { open_delim_sp: None, inner: vec![] }];
let mut token_and_spacing = iter.next();
@@ -417,48 +418,47 @@ fn make_token_stream(
open_delim, span
);
let dspan = DelimSpan::from_pair(open_sp, span);
- let stream = AttrAnnotatedTokenStream::new(frame_data.inner);
- let delimited = AttrAnnotatedTokenTree::Delimited(dspan, delim, stream);
+ let stream = AttrTokenStream::new(frame_data.inner);
+ let delimited = AttrTokenTree::Delimited(dspan, delim, stream);
stack
.last_mut()
.unwrap_or_else(|| {
panic!("Bottom token frame is missing for token: {:?}", token)
})
.inner
- .push((delimited, Spacing::Alone));
+ .push(delimited);
}
FlatToken::Token(token) => stack
.last_mut()
.expect("Bottom token frame is missing!")
.inner
- .push((AttrAnnotatedTokenTree::Token(token), spacing)),
+ .push(AttrTokenTree::Token(token, spacing)),
FlatToken::AttrTarget(data) => stack
.last_mut()
.expect("Bottom token frame is missing!")
.inner
- .push((AttrAnnotatedTokenTree::Attributes(data), spacing)),
+ .push(AttrTokenTree::Attributes(data)),
FlatToken::Empty => {}
}
token_and_spacing = iter.next();
}
let mut final_buf = stack.pop().expect("Missing final buf!");
if break_last_token {
- let (last_token, spacing) = final_buf.inner.pop().unwrap();
- if let AttrAnnotatedTokenTree::Token(last_token) = last_token {
+ let last_token = final_buf.inner.pop().unwrap();
+ if let AttrTokenTree::Token(last_token, spacing) = last_token {
let unglued_first = last_token.kind.break_two_token_op().unwrap().0;
// An 'unglued' token is always two ASCII characters
let mut first_span = last_token.span.shrink_to_lo();
first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1));
- final_buf.inner.push((
- AttrAnnotatedTokenTree::Token(Token::new(unglued_first, first_span)),
- spacing,
- ));
+ final_buf
+ .inner
+ .push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing));
} else {
panic!("Unexpected last token {:?}", last_token)
}
}
assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack);
- AttrAnnotatedTokenStream::new(final_buf.inner)
+ AttrTokenStream::new(final_buf.inner)
}
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index a2155ac1d..be524db78 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -10,26 +10,25 @@ use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind};
use rustc_ast::util::parser::AssocOp;
use rustc_ast::{
- AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
- BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Mutability, Param, Pat,
- PatKind, Path, PathSegment, QSelf, Ty, TyKind,
+ AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingAnnotation, Block,
+ BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind,
+ Path, PathSegment, QSelf, Ty, TyKind,
};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{
fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
};
-use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed};
+use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed};
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
use rustc_span::source_map::Spanned;
-use rustc_span::symbol::{kw, Ident};
+use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{Span, SpanSnippetError, DUMMY_SP};
use std::ops::{Deref, DerefMut};
use std::mem::take;
use crate::parser;
-use tracing::{debug, trace};
const TURBOFISH_SUGGESTION_STR: &str =
"use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments";
@@ -38,7 +37,7 @@ const TURBOFISH_SUGGESTION_STR: &str =
pub(super) fn dummy_arg(ident: Ident) -> Param {
let pat = P(Pat {
id: ast::DUMMY_NODE_ID,
- kind: PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None),
+ kind: PatKind::Ident(BindingAnnotation::NONE, ident, None),
span: ident.span,
tokens: None,
});
@@ -228,13 +227,13 @@ struct MultiSugg {
}
impl MultiSugg {
- fn emit<G: EmissionGuarantee>(self, err: &mut DiagnosticBuilder<'_, G>) {
+ fn emit(self, err: &mut Diagnostic) {
err.multipart_suggestion(&self.msg, self.patches, self.applicability);
}
/// Overrides individual messages and applicabilities.
- fn emit_many<G: EmissionGuarantee>(
- err: &mut DiagnosticBuilder<'_, G>,
+ fn emit_many(
+ err: &mut Diagnostic,
msg: &str,
applicability: Applicability,
suggestions: impl Iterator<Item = Self>,
@@ -244,7 +243,7 @@ impl MultiSugg {
}
#[derive(SessionDiagnostic)]
-#[error(parser::maybe_report_ambiguous_plus)]
+#[diag(parser::maybe_report_ambiguous_plus)]
struct AmbiguousPlus {
pub sum_ty: String,
#[primary_span]
@@ -253,7 +252,7 @@ struct AmbiguousPlus {
}
#[derive(SessionDiagnostic)]
-#[error(parser::maybe_recover_from_bad_type_plus, code = "E0178")]
+#[diag(parser::maybe_recover_from_bad_type_plus, code = "E0178")]
struct BadTypePlus {
pub ty: String,
#[primary_span]
@@ -287,7 +286,7 @@ pub enum BadTypePlusSub {
}
#[derive(SessionDiagnostic)]
-#[error(parser::maybe_recover_from_bad_qpath_stage_2)]
+#[diag(parser::maybe_recover_from_bad_qpath_stage_2)]
struct BadQPathStage2 {
#[primary_span]
#[suggestion(applicability = "maybe-incorrect")]
@@ -296,7 +295,7 @@ struct BadQPathStage2 {
}
#[derive(SessionDiagnostic)]
-#[error(parser::incorrect_semicolon)]
+#[diag(parser::incorrect_semicolon)]
struct IncorrectSemicolon<'a> {
#[primary_span]
#[suggestion_short(applicability = "machine-applicable")]
@@ -307,7 +306,7 @@ struct IncorrectSemicolon<'a> {
}
#[derive(SessionDiagnostic)]
-#[error(parser::incorrect_use_of_await)]
+#[diag(parser::incorrect_use_of_await)]
struct IncorrectUseOfAwait {
#[primary_span]
#[suggestion(parser::parentheses_suggestion, applicability = "machine-applicable")]
@@ -315,7 +314,7 @@ struct IncorrectUseOfAwait {
}
#[derive(SessionDiagnostic)]
-#[error(parser::incorrect_use_of_await)]
+#[diag(parser::incorrect_use_of_await)]
struct IncorrectAwait {
#[primary_span]
span: Span,
@@ -326,7 +325,7 @@ struct IncorrectAwait {
}
#[derive(SessionDiagnostic)]
-#[error(parser::in_in_typo)]
+#[diag(parser::in_in_typo)]
struct InInTypo {
#[primary_span]
span: Span,
@@ -334,6 +333,394 @@ struct InInTypo {
sugg_span: Span,
}
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_variable_declaration)]
+pub struct InvalidVariableDeclaration {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sub: InvalidVariableDeclarationSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum InvalidVariableDeclarationSub {
+ #[suggestion(
+ parser::switch_mut_let_order,
+ applicability = "maybe-incorrect",
+ code = "let mut"
+ )]
+ SwitchMutLetOrder(#[primary_span] Span),
+ #[suggestion(
+ parser::missing_let_before_mut,
+ applicability = "machine-applicable",
+ code = "let mut"
+ )]
+ MissingLet(#[primary_span] Span),
+ #[suggestion(parser::use_let_not_auto, applicability = "machine-applicable", code = "let")]
+ UseLetNotAuto(#[primary_span] Span),
+ #[suggestion(parser::use_let_not_var, applicability = "machine-applicable", code = "let")]
+ UseLetNotVar(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_comparison_operator)]
+pub(crate) struct InvalidComparisonOperator {
+ #[primary_span]
+ pub span: Span,
+ pub invalid: String,
+ #[subdiagnostic]
+ pub sub: InvalidComparisonOperatorSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum InvalidComparisonOperatorSub {
+ #[suggestion_short(
+ parser::use_instead,
+ applicability = "machine-applicable",
+ code = "{correct}"
+ )]
+ Correctable {
+ #[primary_span]
+ span: Span,
+ invalid: String,
+ correct: String,
+ },
+ #[label(parser::spaceship_operator_invalid)]
+ Spaceship(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_logical_operator)]
+#[note]
+pub(crate) struct InvalidLogicalOperator {
+ #[primary_span]
+ pub span: Span,
+ pub incorrect: String,
+ #[subdiagnostic]
+ pub sub: InvalidLogicalOperatorSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum InvalidLogicalOperatorSub {
+ #[suggestion_short(
+ parser::use_amp_amp_for_conjunction,
+ applicability = "machine-applicable",
+ code = "&&"
+ )]
+ Conjunction(#[primary_span] Span),
+ #[suggestion_short(
+ parser::use_pipe_pipe_for_disjunction,
+ applicability = "machine-applicable",
+ code = "||"
+ )]
+ Disjunction(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::tilde_is_not_unary_operator)]
+pub(crate) struct TildeAsUnaryOperator(
+ #[primary_span]
+ #[suggestion_short(applicability = "machine-applicable", code = "!")]
+ pub Span,
+);
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::unexpected_token_after_not)]
+pub(crate) struct NotAsNegationOperator {
+ #[primary_span]
+ pub negated: Span,
+ pub negated_desc: String,
+ #[suggestion_short(applicability = "machine-applicable", code = "!")]
+ pub not: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::malformed_loop_label)]
+pub(crate) struct MalformedLoopLabel {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = "{correct_label}")]
+ pub span: Span,
+ pub correct_label: Ident,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::lifetime_in_borrow_expression)]
+pub(crate) struct LifetimeInBorrowExpression {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(applicability = "machine-applicable", code = "")]
+ #[label]
+ pub lifetime_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::field_expression_with_generic)]
+pub(crate) struct FieldExpressionWithGeneric(#[primary_span] pub Span);
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::macro_invocation_with_qualified_path)]
+pub(crate) struct MacroInvocationWithQualifiedPath(#[primary_span] pub Span);
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::unexpected_token_after_label)]
+pub(crate) struct UnexpectedTokenAfterLabel(
+ #[primary_span]
+ #[label(parser::unexpected_token_after_label)]
+ pub Span,
+);
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::require_colon_after_labeled_expression)]
+#[note]
+pub(crate) struct RequireColonAfterLabeledExpression {
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub label: Span,
+ #[suggestion_short(applicability = "machine-applicable", code = ": ")]
+ pub label_end: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::do_catch_syntax_removed)]
+#[note]
+pub(crate) struct DoCatchSyntaxRemoved {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = "try")]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::float_literal_requires_integer_part)]
+pub(crate) struct FloatLiteralRequiresIntegerPart {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = "{correct}")]
+ pub span: Span,
+ pub correct: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_int_literal_width)]
+#[help]
+pub(crate) struct InvalidIntLiteralWidth {
+ #[primary_span]
+ pub span: Span,
+ pub width: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_num_literal_base_prefix)]
+#[note]
+pub(crate) struct InvalidNumLiteralBasePrefix {
+ #[primary_span]
+ #[suggestion(applicability = "maybe-incorrect", code = "{fixed}")]
+ pub span: Span,
+ pub fixed: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_num_literal_suffix)]
+#[help]
+pub(crate) struct InvalidNumLiteralSuffix {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub suffix: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_float_literal_width)]
+#[help]
+pub(crate) struct InvalidFloatLiteralWidth {
+ #[primary_span]
+ pub span: Span,
+ pub width: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_float_literal_suffix)]
+#[help]
+pub(crate) struct InvalidFloatLiteralSuffix {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub suffix: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::int_literal_too_large)]
+pub(crate) struct IntLiteralTooLarge {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::missing_semicolon_before_array)]
+pub(crate) struct MissingSemicolonBeforeArray {
+ #[primary_span]
+ pub open_delim: Span,
+ #[suggestion_verbose(applicability = "maybe-incorrect", code = ";")]
+ pub semicolon: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_block_macro_segment)]
+pub(crate) struct InvalidBlockMacroSegment {
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub context: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::if_expression_missing_then_block)]
+pub(crate) struct IfExpressionMissingThenBlock {
+ #[primary_span]
+ pub if_span: Span,
+ #[subdiagnostic]
+ pub sub: IfExpressionMissingThenBlockSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum IfExpressionMissingThenBlockSub {
+ #[help(parser::condition_possibly_unfinished)]
+ UnfinishedCondition(#[primary_span] Span),
+ #[help(parser::add_then_block)]
+ AddThenBlock(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::if_expression_missing_condition)]
+pub(crate) struct IfExpressionMissingCondition {
+ #[primary_span]
+ #[label(parser::condition_label)]
+ pub if_span: Span,
+ #[label(parser::block_label)]
+ pub block_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::expected_expression_found_let)]
+pub(crate) struct ExpectedExpressionFoundLet {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::expected_else_block)]
+pub(crate) struct ExpectedElseBlock {
+ #[primary_span]
+ pub first_tok_span: Span,
+ pub first_tok: String,
+ #[label]
+ pub else_span: Span,
+ #[suggestion(applicability = "maybe-incorrect", code = "if ")]
+ pub condition_start: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::outer_attribute_not_allowed_on_if_else)]
+pub(crate) struct OuterAttributeNotAllowedOnIfElse {
+ #[primary_span]
+ pub last: Span,
+
+ #[label(parser::branch_label)]
+ pub branch_span: Span,
+
+ #[label(parser::ctx_label)]
+ pub ctx_span: Span,
+ pub ctx: String,
+
+ #[suggestion(applicability = "machine-applicable", code = "")]
+ pub attributes: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::missing_in_in_for_loop)]
+pub(crate) struct MissingInInForLoop {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sub: MissingInInForLoopSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum MissingInInForLoopSub {
+ // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect
+ #[suggestion_short(parser::use_in_not_of, applicability = "maybe-incorrect", code = "in")]
+ InNotOf(#[primary_span] Span),
+ #[suggestion_short(parser::add_in, applicability = "maybe-incorrect", code = " in ")]
+ AddIn(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::missing_comma_after_match_arm)]
+pub(crate) struct MissingCommaAfterMatchArm {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = ",")]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::catch_after_try)]
+#[help]
+pub(crate) struct CatchAfterTry {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::comma_after_base_struct)]
+#[note]
+pub(crate) struct CommaAfterBaseStruct {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion_short(applicability = "machine-applicable", code = "")]
+ pub comma: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::eq_field_init)]
+pub(crate) struct EqFieldInit {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(applicability = "machine-applicable", code = ":")]
+ pub eq: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::dotdotdot)]
+pub(crate) struct DotDotDot {
+ #[primary_span]
+ #[suggestion(parser::suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")]
+ #[suggestion(parser::suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::left_arrow_operator)]
+pub(crate) struct LeftArrowOperator {
+ #[primary_span]
+ #[suggestion(applicability = "maybe-incorrect", code = "< -")]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::remove_let)]
+pub(crate) struct RemoveLet {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = "")]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::use_eq_instead)]
+pub(crate) struct UseEqInstead {
+ #[primary_span]
+ #[suggestion_short(applicability = "machine-applicable", code = "=")]
+ pub span: Span,
+}
+
// SnapshotParser is used to create a snapshot of the parser
// without causing duplicate errors being emitted when the `Parser`
// is dropped.
@@ -387,7 +774,7 @@ impl<'a> Parser<'a> {
/// This is to avoid losing unclosed delims errors `create_snapshot_for_diagnostic` clears.
pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
*self = snapshot.parser;
- self.unclosed_delims.extend(snapshot.unclosed_delims.clone());
+ self.unclosed_delims.extend(snapshot.unclosed_delims);
}
pub fn unclosed_delims(&self) -> &[UnmatchedBrace] {
@@ -555,10 +942,12 @@ impl<'a> Parser<'a> {
return Ok(true);
} else if self.look_ahead(0, |t| {
t == &token::CloseDelim(Delimiter::Brace)
- || (t.can_begin_expr() && t != &token::Semi && t != &token::Pound)
+ || ((t.can_begin_expr() || t.can_begin_item())
+ && t != &token::Semi
+ && t != &token::Pound)
// Avoid triggering with too many trailing `#` in raw string.
|| (sm.is_multiline(
- self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo())
+ self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()),
) && t == &token::Pound)
}) && !expected.contains(&TokenType::Token(token::Comma))
{
@@ -576,6 +965,14 @@ impl<'a> Parser<'a> {
}
}
+ if self.token.kind == TokenKind::EqEq
+ && self.prev_token.is_ident()
+ && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq)))
+ {
+ // Likely typo: `=` → `==` in let expr or enum item
+ return Err(self.sess.create_err(UseEqInstead { span: self.token.span }));
+ }
+
let expect = tokens_to_string(&expected);
let actual = super::token_descr(&self.token);
let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
@@ -590,7 +987,7 @@ impl<'a> Parser<'a> {
)
} else if expected.is_empty() {
(
- format!("unexpected token: {}", actual),
+ format!("unexpected token: {actual}"),
(self.prev_token.span, "unexpected token after this".to_string()),
)
} else {
@@ -603,16 +1000,29 @@ impl<'a> Parser<'a> {
let mut err = self.struct_span_err(self.token.span, &msg_exp);
if let TokenKind::Ident(symbol, _) = &self.prev_token.kind {
- if symbol.as_str() == "public" {
+ if ["def", "fun", "func", "function"].contains(&symbol.as_str()) {
err.span_suggestion_short(
self.prev_token.span,
- "write `pub` instead of `public` to make the item public",
- "pub",
+ &format!("write `fn` instead of `{symbol}` to declare a function"),
+ "fn",
appl,
);
}
}
+ // `pub` may be used for an item or `pub(crate)`
+ if self.prev_token.is_ident_named(sym::public)
+ && (self.token.can_begin_item()
+ || self.token.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
+ {
+ err.span_suggestion_short(
+ self.prev_token.span,
+ "write `pub` instead of `public` to make the item public",
+ "pub",
+ appl,
+ );
+ }
+
// Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens
// there are unclosed angle brackets
if self.unmatched_angle_bracket_count > 0
@@ -734,7 +1144,7 @@ impl<'a> Parser<'a> {
let mut snapshot = self.create_snapshot_for_diagnostic();
let path =
Path { segments: vec![], span: self.prev_token.span.shrink_to_lo(), tokens: None };
- let struct_expr = snapshot.parse_struct_expr(None, path, AttrVec::new(), false);
+ let struct_expr = snapshot.parse_struct_expr(None, path, false);
let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No);
return Some(match (struct_expr, block_tail) {
(Ok(expr), Err(mut err)) => {
@@ -1188,8 +1598,7 @@ impl<'a> Parser<'a> {
outer_op.node,
);
- let mk_err_expr =
- |this: &Self, span| Ok(Some(this.mk_expr(span, ExprKind::Err, AttrVec::new())));
+ let mk_err_expr = |this: &Self, span| Ok(Some(this.mk_expr(span, ExprKind::Err)));
match inner_op.kind {
ExprKind::Binary(op, ref l1, ref r1) if op.node.is_comparison() => {
@@ -1497,7 +1906,7 @@ impl<'a> Parser<'a> {
MultiSugg {
msg: format!("use `{}= 1` instead", kind.op.chr()),
patches: vec![
- (pre_span, format!("{{ let {} = ", tmp_var)),
+ (pre_span, format!("{{ let {tmp_var} = ")),
(post_span, format!("; {} {}= 1; {} }}", base_src, kind.op.chr(), tmp_var)),
],
applicability: Applicability::HasPlaceholders,
@@ -1647,7 +2056,6 @@ impl<'a> Parser<'a> {
&mut self,
lo: Span,
await_sp: Span,
- attrs: AttrVec,
) -> PResult<'a, P<Expr>> {
let (hi, expr, is_question) = if self.token == token::Not {
// Handle `await!(<expr>)`.
@@ -1662,7 +2070,7 @@ impl<'a> Parser<'a> {
ExprKind::Try(_) => ExprKind::Err,
_ => ExprKind::Await(expr),
};
- let expr = self.mk_expr(lo.to(sp), kind, attrs);
+ let expr = self.mk_expr(lo.to(sp), kind);
self.maybe_recover_from_bad_qpath(expr)
}
@@ -1680,7 +2088,7 @@ impl<'a> Parser<'a> {
// Handle `await { <expr> }`.
// This needs to be handled separately from the next arm to avoid
// interpreting `await { <expr> }?` as `<expr>?.await`.
- self.parse_block_expr(None, self.token.span, BlockCheckMode::Default, AttrVec::new())
+ self.parse_block_expr(None, self.token.span, BlockCheckMode::Default)
} else {
self.parse_expr()
}
@@ -1823,7 +2231,7 @@ impl<'a> Parser<'a> {
err.emit();
// Recover from parse error, callers expect the closing delim to be consumed.
self.consume_block(delim, ConsumeClosingDelim::Yes);
- self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err, AttrVec::new())
+ self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err)
}
}
}
@@ -2334,7 +2742,7 @@ impl<'a> Parser<'a> {
fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option<GenericArg> {
let snapshot = self.create_snapshot_for_diagnostic();
- let param = match self.parse_const_param(vec![]) {
+ let param = match self.parse_const_param(AttrVec::new()) {
Ok(param) => param,
Err(err) => {
err.cancel();
@@ -2577,7 +2985,7 @@ impl<'a> Parser<'a> {
}
_ => {}
},
- PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => {
+ PatKind::Ident(BindingAnnotation::NONE, ident, None) => {
match &first_pat.kind {
PatKind::Ident(_, old_ident, _) => {
let path = PatKind::Path(
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 0719a0ef0..725768c1f 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1,4 +1,14 @@
-use super::diagnostics::SnapshotParser;
+use super::diagnostics::{
+ CatchAfterTry, CommaAfterBaseStruct, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
+ ExpectedElseBlock, ExpectedExpressionFoundLet, FieldExpressionWithGeneric,
+ FloatLiteralRequiresIntegerPart, IfExpressionMissingCondition, IfExpressionMissingThenBlock,
+ IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator,
+ InvalidComparisonOperatorSub, InvalidLogicalOperator, InvalidLogicalOperatorSub,
+ LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath,
+ MalformedLoopLabel, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray,
+ NotAsNegationOperator, OuterAttributeNotAllowedOnIfElse, RequireColonAfterLabeledExpression,
+ SnapshotParser, TildeAsUnaryOperator, UnexpectedTokenAfterLabel,
+};
use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{
@@ -6,6 +16,11 @@ use super::{
SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken,
};
use crate::maybe_recover_from_interpolated_ty_qpath;
+use crate::parser::diagnostics::{
+ IntLiteralTooLarge, InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth,
+ InvalidIntLiteralWidth, InvalidNumLiteralBasePrefix, InvalidNumLiteralSuffix,
+ MissingCommaAfterMatchArm,
+};
use core::mem;
use rustc_ast::ptr::P;
@@ -20,10 +35,10 @@ use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty
use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
use rustc_ast::{ClosureBinder, StmtKind};
use rustc_ast_pretty::pprust;
-use rustc_data_structures::thin_vec::ThinVec;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult};
+use rustc_errors::{Applicability, Diagnostic, PResult};
use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_session::SessionDiagnostic;
use rustc_span::source_map::{self, Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, Pos};
@@ -45,20 +60,12 @@ macro_rules! maybe_whole_expr {
token::NtPath(path) => {
let path = (**path).clone();
$p.bump();
- return Ok($p.mk_expr(
- $p.prev_token.span,
- ExprKind::Path(None, path),
- AttrVec::new(),
- ));
+ return Ok($p.mk_expr($p.prev_token.span, ExprKind::Path(None, path)));
}
token::NtBlock(block) => {
let block = block.clone();
$p.bump();
- return Ok($p.mk_expr(
- $p.prev_token.span,
- ExprKind::Block(block, None),
- AttrVec::new(),
- ));
+ return Ok($p.mk_expr($p.prev_token.span, ExprKind::Block(block, None)));
}
_ => {}
};
@@ -120,7 +127,7 @@ impl<'a> Parser<'a> {
// Special-case handling of `foo(_, _, _)`
err.emit();
self.bump();
- Ok(self.mk_expr(self.prev_token.span, ExprKind::Err, AttrVec::new()))
+ Ok(self.mk_expr(self.prev_token.span, ExprKind::Err))
}
_ => Err(err),
},
@@ -225,15 +232,18 @@ impl<'a> Parser<'a> {
AssocOp::Equal => "==",
AssocOp::NotEqual => "!=",
_ => unreachable!(),
- };
- self.struct_span_err(sp, &format!("invalid comparison operator `{sugg}=`"))
- .span_suggestion_short(
- sp,
- &format!("`{s}=` is not a valid comparison operator, use `{s}`", s = sugg),
- sugg,
- Applicability::MachineApplicable,
- )
- .emit();
+ }
+ .into();
+ let invalid = format!("{}=", &sugg);
+ self.sess.emit_err(InvalidComparisonOperator {
+ span: sp,
+ invalid: invalid.clone(),
+ sub: InvalidComparisonOperatorSub::Correctable {
+ span: sp,
+ invalid,
+ correct: sugg,
+ },
+ });
self.bump();
}
@@ -243,14 +253,15 @@ impl<'a> Parser<'a> {
&& self.prev_token.span.hi() == self.token.span.lo()
{
let sp = op.span.to(self.token.span);
- self.struct_span_err(sp, "invalid comparison operator `<>`")
- .span_suggestion_short(
- sp,
- "`<>` is not a valid comparison operator, use `!=`",
- "!=",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(InvalidComparisonOperator {
+ span: sp,
+ invalid: "<>".into(),
+ sub: InvalidComparisonOperatorSub::Correctable {
+ span: sp,
+ invalid: "<>".into(),
+ correct: "!=".into(),
+ },
+ });
self.bump();
}
@@ -260,12 +271,11 @@ impl<'a> Parser<'a> {
&& self.prev_token.span.hi() == self.token.span.lo()
{
let sp = op.span.to(self.token.span);
- self.struct_span_err(sp, "invalid comparison operator `<=>`")
- .span_label(
- sp,
- "`<=>` is not a valid comparison operator, use `std::cmp::Ordering`",
- )
- .emit();
+ self.sess.emit_err(InvalidComparisonOperator {
+ span: sp,
+ invalid: "<=>".into(),
+ sub: InvalidComparisonOperatorSub::Spaceship(sp),
+ });
self.bump();
}
@@ -329,11 +339,9 @@ impl<'a> Parser<'a> {
| AssocOp::GreaterEqual => {
let ast_op = op.to_ast_binop().unwrap();
let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs);
- self.mk_expr(span, binary, AttrVec::new())
- }
- AssocOp::Assign => {
- self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span), AttrVec::new())
+ self.mk_expr(span, binary)
}
+ AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span)),
AssocOp::AssignOp(k) => {
let aop = match k {
token::Plus => BinOpKind::Add,
@@ -348,7 +356,7 @@ impl<'a> Parser<'a> {
token::Shr => BinOpKind::Shr,
};
let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs);
- self.mk_expr(span, aopexpr, AttrVec::new())
+ self.mk_expr(span, aopexpr)
}
AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotEq => {
self.span_bug(span, "AssocOp should have been handled by special case")
@@ -441,11 +449,19 @@ impl<'a> Parser<'a> {
}
(Some(op), _) => (op, self.token.span),
(None, Some((Ident { name: sym::and, span }, false))) => {
- self.error_bad_logical_op("and", "&&", "conjunction");
+ self.sess.emit_err(InvalidLogicalOperator {
+ span: self.token.span,
+ incorrect: "and".into(),
+ sub: InvalidLogicalOperatorSub::Conjunction(self.token.span),
+ });
(AssocOp::LAnd, span)
}
(None, Some((Ident { name: sym::or, span }, false))) => {
- self.error_bad_logical_op("or", "||", "disjunction");
+ self.sess.emit_err(InvalidLogicalOperator {
+ span: self.token.span,
+ incorrect: "or".into(),
+ sub: InvalidLogicalOperatorSub::Disjunction(self.token.span),
+ });
(AssocOp::LOr, span)
}
_ => return None,
@@ -453,19 +469,6 @@ impl<'a> Parser<'a> {
Some(source_map::respan(span, op))
}
- /// Error on `and` and `or` suggesting `&&` and `||` respectively.
- fn error_bad_logical_op(&self, bad: &str, good: &str, english: &str) {
- self.struct_span_err(self.token.span, &format!("`{bad}` is not a logical operator"))
- .span_suggestion_short(
- self.token.span,
- &format!("use `{good}` to perform logical {english}"),
- good,
- Applicability::MachineApplicable,
- )
- .note("unlike in e.g., python and PHP, `&&` and `||` are used for logical operators")
- .emit();
- }
-
/// Checks if this expression is a successfully parsed statement.
fn expr_is_complete(&self, e: &Expr) -> bool {
self.restrictions.contains(Restrictions::STMT_EXPR)
@@ -491,7 +494,7 @@ impl<'a> Parser<'a> {
let limits =
if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed };
let range = self.mk_range(Some(lhs), rhs, limits);
- Ok(self.mk_expr(span, range, AttrVec::new()))
+ Ok(self.mk_expr(span, range))
}
fn is_at_start_of_range_notation_rhs(&self) -> bool {
@@ -540,7 +543,7 @@ impl<'a> Parser<'a> {
(lo, None)
};
let range = this.mk_range(None, opt_end, limits);
- Ok(this.mk_expr(span, range, attrs.into()))
+ Ok(this.mk_expr_with_attrs(span, range, attrs))
})
}
@@ -553,7 +556,7 @@ impl<'a> Parser<'a> {
($this:ident, $attrs:expr, |this, _| $body:expr) => {
$this.collect_tokens_for_expr($attrs, |$this, attrs| {
let (hi, ex) = $body?;
- Ok($this.mk_expr(lo.to(hi), ex, attrs.into()))
+ Ok($this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
})
};
}
@@ -630,14 +633,7 @@ impl<'a> Parser<'a> {
// Recover on `!` suggesting for bitwise negation instead.
fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
- self.struct_span_err(lo, "`~` cannot be used as a unary operator")
- .span_suggestion_short(
- lo,
- "use `!` to perform bitwise not",
- "!",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(TildeAsUnaryOperator(lo));
self.parse_unary_expr(lo, UnOp::Not)
}
@@ -663,20 +659,14 @@ impl<'a> Parser<'a> {
/// Recover on `not expr` in favor of `!expr`.
fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
// Emit the error...
- let not_token = self.look_ahead(1, |t| t.clone());
- self.struct_span_err(
- not_token.span,
- &format!("unexpected {} after identifier", super::token_descr(&not_token)),
- )
- .span_suggestion_short(
+ let negated_token = self.look_ahead(1, |t| t.clone());
+ self.sess.emit_err(NotAsNegationOperator {
+ negated: negated_token.span,
+ negated_desc: super::token_descr(&negated_token),
// Span the `not` plus trailing whitespace to avoid
// trailing whitespace after the `!` in our suggestion
- self.sess.source_map().span_until_non_whitespace(lo.to(not_token.span)),
- "use `!` to perform logical negation",
- "!",
- Applicability::MachineApplicable,
- )
- .emit();
+ not: self.sess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),
+ });
// ...and recover!
self.parse_unary_expr(lo, UnOp::Not)
@@ -705,11 +695,7 @@ impl<'a> Parser<'a> {
expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
) -> PResult<'a, P<Expr>> {
let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| {
- this.mk_expr(
- this.mk_expr_sp(&lhs, lhs_span, rhs.span),
- expr_kind(lhs, rhs),
- AttrVec::new(),
- )
+ this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, rhs.span), expr_kind(lhs, rhs))
};
// Save the state of the parser before parsing type normally, in case there is a
@@ -737,17 +723,13 @@ impl<'a> Parser<'a> {
segments[0].ident.span,
),
};
- match self.parse_labeled_expr(label, AttrVec::new(), false) {
+ match self.parse_labeled_expr(label, false) {
Ok(expr) => {
type_err.cancel();
- self.struct_span_err(label.ident.span, "malformed loop label")
- .span_suggestion(
- label.ident.span,
- "use the correct loop label format",
- label.ident,
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(MalformedLoopLabel {
+ span: label.ident.span,
+ correct_label: label.ident,
+ });
return Ok(expr);
}
Err(err) => {
@@ -859,7 +841,7 @@ impl<'a> Parser<'a> {
);
let mut err = self.struct_span_err(span, &msg);
- let suggest_parens = |err: &mut DiagnosticBuilder<'_, _>| {
+ let suggest_parens = |err: &mut Diagnostic| {
let suggestions = vec![
(span.shrink_to_lo(), "(".to_string()),
(span.shrink_to_hi(), ")".to_string()),
@@ -925,15 +907,7 @@ impl<'a> Parser<'a> {
}
fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
- self.struct_span_err(span, "borrow expressions cannot be annotated with lifetimes")
- .span_label(lt_span, "annotated with lifetime here")
- .span_suggestion(
- lt_span,
- "remove the lifetime annotation",
- "",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(LifetimeInBorrowExpression { span, lifetime_span: lt_span });
}
/// Parse `mut?` or `raw [ const | mut ]`.
@@ -965,18 +939,23 @@ impl<'a> Parser<'a> {
&mut self,
e0: P<Expr>,
lo: Span,
- mut attrs: Vec<ast::Attribute>,
+ mut attrs: ast::AttrVec,
) -> PResult<'a, P<Expr>> {
// Stitch the list of outer attributes onto the return value.
// A little bit ugly, but the best way given the current code
// structure
- self.parse_dot_or_call_expr_with_(e0, lo).map(|expr| {
- expr.map(|mut expr| {
- attrs.extend::<Vec<_>>(expr.attrs.into());
- expr.attrs = attrs.into();
- expr
+ let res = self.parse_dot_or_call_expr_with_(e0, lo);
+ if attrs.is_empty() {
+ res
+ } else {
+ res.map(|expr| {
+ expr.map(|mut expr| {
+ attrs.extend(expr.attrs);
+ expr.attrs = attrs;
+ expr
+ })
})
- })
+ }
}
fn parse_dot_or_call_expr_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
@@ -990,7 +969,7 @@ impl<'a> Parser<'a> {
};
if has_question {
// `expr?`
- e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e), AttrVec::new());
+ e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
continue;
}
let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, false) {
@@ -1168,7 +1147,7 @@ impl<'a> Parser<'a> {
let span = self.prev_token.span;
let field = ExprKind::Field(base, Ident::new(field, span));
self.expect_no_suffix(span, "a tuple index", suffix);
- self.mk_expr(lo.to(span), field, AttrVec::new())
+ self.mk_expr(lo.to(span), field)
}
/// Parse a function call expression, `expr(...)`.
@@ -1182,9 +1161,9 @@ impl<'a> Parser<'a> {
};
let open_paren = self.token.span;
- let mut seq = self.parse_paren_expr_seq().map(|args| {
- self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args), AttrVec::new())
- });
+ let mut seq = self
+ .parse_paren_expr_seq()
+ .map(|args| self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args)));
if let Some(expr) =
self.maybe_recover_struct_lit_bad_delims(lo, open_paren, &mut seq, snapshot)
{
@@ -1258,10 +1237,13 @@ impl<'a> Parser<'a> {
/// Parse an indexing expression `expr[...]`.
fn parse_index_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
+ let prev_span = self.prev_token.span;
+ let open_delim_span = self.token.span;
self.bump(); // `[`
let index = self.parse_expr()?;
+ self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?;
self.expect(&token::CloseDelim(Delimiter::Bracket))?;
- Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index), AttrVec::new()))
+ Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index)))
}
/// Assuming we have just parsed `.`, continue parsing into an expression.
@@ -1282,19 +1264,15 @@ impl<'a> Parser<'a> {
let fn_span = fn_span_lo.to(self.prev_token.span);
let span = lo.to(self.prev_token.span);
- Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args, fn_span), AttrVec::new()))
+ Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args, fn_span)))
} else {
// Field access `expr.f`
if let Some(args) = segment.args {
- self.struct_span_err(
- args.span(),
- "field expressions cannot have generic arguments",
- )
- .emit();
+ self.sess.emit_err(FieldExpressionWithGeneric(args.span()));
}
let span = lo.to(self.prev_token.span);
- Ok(self.mk_expr(span, ExprKind::Field(self_arg, segment.ident), AttrVec::new()))
+ Ok(self.mk_expr(span, ExprKind::Field(self_arg, segment.ident)))
}
}
@@ -1309,10 +1287,6 @@ impl<'a> Parser<'a> {
// Outer attributes are already parsed and will be
// added to the return value after the fact.
- //
- // Therefore, prevent sub-parser from parsing
- // attributes by giving them an empty "already-parsed" list.
- let attrs = AttrVec::new();
// Note: when adding new syntax here, don't forget to adjust `TokenKind::can_begin_expr()`.
let lo = self.token.span;
@@ -1320,13 +1294,13 @@ impl<'a> Parser<'a> {
// This match arm is a special-case of the `_` match arm below and
// could be removed without changing functionality, but it's faster
// to have it here, especially for programs with large constants.
- self.parse_lit_expr(attrs)
+ self.parse_lit_expr()
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
- self.parse_tuple_parens_expr(attrs)
+ self.parse_tuple_parens_expr()
} else if self.check(&token::OpenDelim(Delimiter::Brace)) {
- self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs)
+ self.parse_block_expr(None, lo, BlockCheckMode::Default)
} else if self.check(&token::BinOp(token::Or)) || self.check(&token::OrOr) {
- self.parse_closure_expr(attrs).map_err(|mut err| {
+ self.parse_closure_expr().map_err(|mut err| {
// If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`
// then suggest parens around the lhs.
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&lo) {
@@ -1335,65 +1309,66 @@ impl<'a> Parser<'a> {
err
})
} else if self.check(&token::OpenDelim(Delimiter::Bracket)) {
- self.parse_array_or_repeat_expr(attrs, Delimiter::Bracket)
+ self.parse_array_or_repeat_expr(Delimiter::Bracket)
} else if self.check_path() {
- self.parse_path_start_expr(attrs)
+ self.parse_path_start_expr()
} else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
- self.parse_closure_expr(attrs)
+ self.parse_closure_expr()
} else if self.eat_keyword(kw::If) {
- self.parse_if_expr(attrs)
+ self.parse_if_expr()
} else if self.check_keyword(kw::For) {
if self.choose_generics_over_qpath(1) {
- self.parse_closure_expr(attrs)
+ self.parse_closure_expr()
} else {
assert!(self.eat_keyword(kw::For));
- self.parse_for_expr(None, self.prev_token.span, attrs)
+ self.parse_for_expr(None, self.prev_token.span)
}
} else if self.eat_keyword(kw::While) {
- self.parse_while_expr(None, self.prev_token.span, attrs)
+ self.parse_while_expr(None, self.prev_token.span)
} else if let Some(label) = self.eat_label() {
- self.parse_labeled_expr(label, attrs, true)
+ self.parse_labeled_expr(label, true)
} else if self.eat_keyword(kw::Loop) {
let sp = self.prev_token.span;
- self.parse_loop_expr(None, self.prev_token.span, attrs).map_err(|mut err| {
+ self.parse_loop_expr(None, self.prev_token.span).map_err(|mut err| {
err.span_label(sp, "while parsing this `loop` expression");
err
})
} else if self.eat_keyword(kw::Continue) {
let kind = ExprKind::Continue(self.eat_label());
- Ok(self.mk_expr(lo.to(self.prev_token.span), kind, attrs))
+ Ok(self.mk_expr(lo.to(self.prev_token.span), kind))
} else if self.eat_keyword(kw::Match) {
let match_sp = self.prev_token.span;
- self.parse_match_expr(attrs).map_err(|mut err| {
+ self.parse_match_expr().map_err(|mut err| {
err.span_label(match_sp, "while parsing this `match` expression");
err
})
} else if self.eat_keyword(kw::Unsafe) {
let sp = self.prev_token.span;
- self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided), attrs)
- .map_err(|mut err| {
+ self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err(
+ |mut err| {
err.span_label(sp, "while parsing this `unsafe` expression");
err
- })
+ },
+ )
} else if self.check_inline_const(0) {
self.parse_const_block(lo.to(self.token.span), false)
} else if self.is_do_catch_block() {
- self.recover_do_catch(attrs)
+ self.recover_do_catch()
} else if self.is_try_block() {
self.expect_keyword(kw::Try)?;
- self.parse_try_block(lo, attrs)
+ self.parse_try_block(lo)
} else if self.eat_keyword(kw::Return) {
- self.parse_return_expr(attrs)
+ self.parse_return_expr()
} else if self.eat_keyword(kw::Break) {
- self.parse_break_expr(attrs)
+ self.parse_break_expr()
} else if self.eat_keyword(kw::Yield) {
- self.parse_yield_expr(attrs)
+ self.parse_yield_expr()
} else if self.is_do_yeet() {
- self.parse_yeet_expr(attrs)
+ self.parse_yeet_expr()
} else if self.check_keyword(kw::Let) {
- self.parse_let_expr(attrs)
+ self.parse_let_expr()
} else if self.eat_keyword(kw::Underscore) {
- Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore, attrs))
+ Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore))
} else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) {
// Don't complain about bare semicolons after unclosed braces
// recovery in order to keep the error count down. Fixing the
@@ -1412,32 +1387,32 @@ impl<'a> Parser<'a> {
if self.check_keyword(kw::Async) {
if self.is_async_block() {
// Check for `async {` and `async move {`.
- self.parse_async_block(attrs)
+ self.parse_async_block()
} else {
- self.parse_closure_expr(attrs)
+ self.parse_closure_expr()
}
} else if self.eat_keyword(kw::Await) {
- self.recover_incorrect_await_syntax(lo, self.prev_token.span, attrs)
+ self.recover_incorrect_await_syntax(lo, self.prev_token.span)
} else {
- self.parse_lit_expr(attrs)
+ self.parse_lit_expr()
}
} else {
- self.parse_lit_expr(attrs)
+ self.parse_lit_expr()
}
}
- fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_lit_expr(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
match self.parse_opt_lit() {
Some(literal) => {
- let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs);
+ let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal));
self.maybe_recover_from_bad_qpath(expr)
}
None => self.try_macro_suggestion(),
}
}
- fn parse_tuple_parens_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_tuple_parens_expr(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
let (es, trailing_comma) = match self.parse_seq_to_end(
@@ -1457,15 +1432,11 @@ impl<'a> Parser<'a> {
// `(e,)` is a tuple with only one field, `e`.
ExprKind::Tup(es)
};
- let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
+ let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
self.maybe_recover_from_bad_qpath(expr)
}
- fn parse_array_or_repeat_expr(
- &mut self,
- attrs: AttrVec,
- close_delim: Delimiter,
- ) -> PResult<'a, P<Expr>> {
+ fn parse_array_or_repeat_expr(&mut self, close_delim: Delimiter) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
self.bump(); // `[` or other open delim
@@ -1494,45 +1465,42 @@ impl<'a> Parser<'a> {
ExprKind::Array(vec![first_expr])
}
};
- let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
+ let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
self.maybe_recover_from_bad_qpath(expr)
}
- fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_path_start_expr(&mut self) -> PResult<'a, P<Expr>> {
let (qself, path) = if self.eat_lt() {
let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
(Some(qself), path)
} else {
(None, self.parse_path(PathStyle::Expr)?)
};
- let lo = path.span;
// `!`, as an operator, is prefix, so we know this isn't that.
- let (hi, kind) = if self.eat(&token::Not) {
+ let (span, kind) = if self.eat(&token::Not) {
// MACRO INVOCATION expression
if qself.is_some() {
- self.struct_span_err(path.span, "macros cannot use qualified paths").emit();
+ self.sess.emit_err(MacroInvocationWithQualifiedPath(path.span));
}
- let mac = MacCall {
+ let lo = path.span;
+ let mac = P(MacCall {
path,
args: self.parse_mac_args()?,
prior_type_ascription: self.last_type_ascription,
- };
- (self.prev_token.span, ExprKind::MacCall(mac))
- } else if self.check(&token::OpenDelim(Delimiter::Brace)) {
- if let Some(expr) = self.maybe_parse_struct_expr(qself.as_ref(), &path, &attrs) {
+ });
+ (lo.to(self.prev_token.span), ExprKind::MacCall(mac))
+ } else if self.check(&token::OpenDelim(Delimiter::Brace)) &&
+ let Some(expr) = self.maybe_parse_struct_expr(qself.as_ref(), &path) {
if qself.is_some() {
self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
}
return expr;
- } else {
- (path.span, ExprKind::Path(qself, path))
- }
} else {
(path.span, ExprKind::Path(qself, path))
};
- let expr = self.mk_expr(lo.to(hi), kind, attrs);
+ let expr = self.mk_expr(span, kind);
self.maybe_recover_from_bad_qpath(expr)
}
@@ -1540,31 +1508,30 @@ impl<'a> Parser<'a> {
fn parse_labeled_expr(
&mut self,
label: Label,
- attrs: AttrVec,
mut consume_colon: bool,
) -> PResult<'a, P<Expr>> {
let lo = label.ident.span;
let label = Some(label);
let ate_colon = self.eat(&token::Colon);
let expr = if self.eat_keyword(kw::While) {
- self.parse_while_expr(label, lo, attrs)
+ self.parse_while_expr(label, lo)
} else if self.eat_keyword(kw::For) {
- self.parse_for_expr(label, lo, attrs)
+ self.parse_for_expr(label, lo)
} else if self.eat_keyword(kw::Loop) {
- self.parse_loop_expr(label, lo, attrs)
+ self.parse_loop_expr(label, lo)
} else if self.check_noexpect(&token::OpenDelim(Delimiter::Brace))
|| self.token.is_whole_block()
{
- self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs)
+ self.parse_block_expr(label, lo, BlockCheckMode::Default)
} else if !ate_colon
&& (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
{
// We're probably inside of a `Path<'a>` that needs a turbofish
- let msg = "expected `while`, `for`, `loop` or `{` after a label";
- self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
+ self.sess.emit_err(UnexpectedTokenAfterLabel(self.token.span));
consume_colon = false;
Ok(self.mk_expr_err(lo))
} else {
+ // FIXME: use UnexpectedTokenAfterLabel, needs multipart suggestions
let msg = "expected `while`, `for`, `loop` or `{` after a label";
let mut err = self.struct_span_err(self.token.span, msg);
@@ -1618,10 +1585,10 @@ impl<'a> Parser<'a> {
Applicability::MachineApplicable,
);
- // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to supress future errors about `break 'label`.
+ // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`.
let stmt = self.mk_stmt(span, StmtKind::Expr(expr));
let blk = self.mk_block(vec![stmt], BlockCheckMode::Default, span);
- self.mk_expr(span, ExprKind::Block(blk, label), ThinVec::new())
+ self.mk_expr(span, ExprKind::Block(blk, label))
});
err.emit();
@@ -1629,44 +1596,27 @@ impl<'a> Parser<'a> {
}?;
if !ate_colon && consume_colon {
- self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
+ self.sess.emit_err(RequireColonAfterLabeledExpression {
+ span: expr.span,
+ label: lo,
+ label_end: lo.shrink_to_hi(),
+ });
}
Ok(expr)
}
- fn error_labeled_expr_must_be_followed_by_colon(&self, lo: Span, span: Span) {
- self.struct_span_err(span, "labeled expression must be followed by `:`")
- .span_label(lo, "the label")
- .span_suggestion_short(
- lo.shrink_to_hi(),
- "add `:` after the label",
- ": ",
- Applicability::MachineApplicable,
- )
- .note("labels are used before loops and blocks, allowing e.g., `break 'label` to them")
- .emit();
- }
-
/// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
- fn recover_do_catch(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn recover_do_catch(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
self.bump(); // `do`
self.bump(); // `catch`
- let span_dc = lo.to(self.prev_token.span);
- self.struct_span_err(span_dc, "found removed `do catch` syntax")
- .span_suggestion(
- span_dc,
- "replace with the new syntax",
- "try",
- Applicability::MachineApplicable,
- )
- .note("following RFC #2388, the new non-placeholder syntax is `try`")
- .emit();
+ let span = lo.to(self.prev_token.span);
+ self.sess.emit_err(DoCatchSyntaxRemoved { span });
- self.parse_try_block(lo, attrs)
+ self.parse_try_block(lo)
}
/// Parse an expression if the token can begin one.
@@ -1675,15 +1625,15 @@ impl<'a> Parser<'a> {
}
/// Parse `"return" expr?`.
- fn parse_return_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_return_expr(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.prev_token.span;
let kind = ExprKind::Ret(self.parse_expr_opt()?);
- let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
+ let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
self.maybe_recover_from_bad_qpath(expr)
}
/// Parse `"do" "yeet" expr?`.
- fn parse_yeet_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_yeet_expr(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
self.bump(); // `do`
@@ -1693,7 +1643,7 @@ impl<'a> Parser<'a> {
let span = lo.to(self.prev_token.span);
self.sess.gated_spans.gate(sym::yeet_expr, span);
- let expr = self.mk_expr(span, kind, attrs);
+ let expr = self.mk_expr(span, kind);
self.maybe_recover_from_bad_qpath(expr)
}
@@ -1705,13 +1655,13 @@ impl<'a> Parser<'a> {
/// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value
/// expression only gets a warning for compatibility reasons; and a labeled break
/// with a labeled loop does not even get a warning because there is no ambiguity.
- fn parse_break_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_break_expr(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.prev_token.span;
let mut label = self.eat_label();
let kind = if label.is_some() && self.token == token::Colon {
// The value expression can be a labeled loop, see issue #86948, e.g.:
// `loop { break 'label: loop { break 'label 42; }; }`
- let lexpr = self.parse_labeled_expr(label.take().unwrap(), AttrVec::new(), true)?;
+ let lexpr = self.parse_labeled_expr(label.take().unwrap(), true)?;
self.struct_span_err(
lexpr.span,
"parentheses are required around this expression to avoid confusion with a labeled break expression",
@@ -1753,17 +1703,17 @@ impl<'a> Parser<'a> {
} else {
None
};
- let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind), attrs);
+ let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind));
self.maybe_recover_from_bad_qpath(expr)
}
/// Parse `"yield" expr?`.
- fn parse_yield_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_yield_expr(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.prev_token.span;
let kind = ExprKind::Yield(self.parse_expr_opt()?);
let span = lo.to(self.prev_token.span);
self.sess.gated_spans.gate(sym::generators, span);
- let expr = self.mk_expr(span, kind, attrs);
+ let expr = self.mk_expr(span, kind);
self.maybe_recover_from_bad_qpath(expr)
}
@@ -1775,8 +1725,8 @@ impl<'a> Parser<'a> {
Some(lit) => match lit.kind {
ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit {
style,
- symbol: lit.token.symbol,
- suffix: lit.token.suffix,
+ symbol: lit.token_lit.symbol,
+ suffix: lit.token_lit.suffix,
span: lit.span,
symbol_unescaped,
}),
@@ -1853,20 +1803,16 @@ impl<'a> Parser<'a> {
let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None);
let symbol = Symbol::intern(&suffixless_lit.to_string());
let lit = token::Lit::new(token::Err, symbol, lit.suffix);
- Some(Lit::from_lit_token(lit, span).unwrap_or_else(|_| unreachable!()))
+ Some(Lit::from_token_lit(lit, span).unwrap_or_else(|_| unreachable!()))
}
}
}
fn error_float_lits_must_have_int_part(&self, token: &Token) {
- self.struct_span_err(token.span, "float literals must have an integer part")
- .span_suggestion(
- token.span,
- "must have an integer part",
- pprust::token_to_string(token),
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(FloatLiteralRequiresIntegerPart {
+ span: token.span,
+ correct: pprust::token_to_string(token).into_owned(),
+ });
}
fn report_lit_error(&self, err: LitError, lit: token::Lit, span: Span) {
@@ -1908,28 +1854,11 @@ impl<'a> Parser<'a> {
let suf = suf.as_str();
if looks_like_width_suffix(&['i', 'u'], &suf) {
// If it looks like a width, try to be helpful.
- let msg = format!("invalid width `{}` for integer literal", &suf[1..]);
- self.struct_span_err(span, &msg)
- .help("valid widths are 8, 16, 32, 64 and 128")
- .emit();
+ self.sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() });
} else if let Some(fixed) = fix_base_capitalisation(suf) {
- let msg = "invalid base prefix for number literal";
-
- self.struct_span_err(span, msg)
- .note("base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase")
- .span_suggestion(
- span,
- "try making the prefix lowercase",
- fixed,
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(InvalidNumLiteralBasePrefix { span, fixed });
} else {
- let msg = format!("invalid suffix `{suf}` for number literal");
- self.struct_span_err(span, &msg)
- .span_label(span, format!("invalid suffix `{suf}`"))
- .help("the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)")
- .emit();
+ self.sess.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() });
}
}
LitError::InvalidFloatSuffix => {
@@ -1937,14 +1866,10 @@ impl<'a> Parser<'a> {
let suf = suf.as_str();
if looks_like_width_suffix(&['f'], suf) {
// If it looks like a width, try to be helpful.
- let msg = format!("invalid width `{}` for float literal", &suf[1..]);
- self.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit();
+ self.sess
+ .emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() });
} else {
- let msg = format!("invalid suffix `{suf}` for float literal");
- self.struct_span_err(span, &msg)
- .span_label(span, format!("invalid suffix `{suf}`"))
- .help("valid suffixes are `f32` and `f64`")
- .emit();
+ self.sess.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() });
}
}
LitError::NonDecimalFloat(base) => {
@@ -1959,7 +1884,7 @@ impl<'a> Parser<'a> {
.emit();
}
LitError::IntTooLarge => {
- self.struct_span_err(span, "integer literal is too large").emit();
+ self.sess.emit_err(IntLiteralTooLarge { span });
}
}
}
@@ -2007,14 +1932,10 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
let minus_present = self.eat(&token::BinOp(token::Minus));
let lit = self.parse_lit()?;
- let expr = self.mk_expr(lit.span, ExprKind::Lit(lit), AttrVec::new());
+ let expr = self.mk_expr(lit.span, ExprKind::Lit(lit));
if minus_present {
- Ok(self.mk_expr(
- lo.to(self.prev_token.span),
- self.mk_unary(UnOp::Neg, expr),
- AttrVec::new(),
- ))
+ Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_unary(UnOp::Neg, expr)))
} else {
Ok(expr)
}
@@ -2029,13 +1950,9 @@ impl<'a> Parser<'a> {
/// Emits a suggestion if it looks like the user meant an array but
/// accidentally used braces, causing the code to be interpreted as a block
/// expression.
- fn maybe_suggest_brackets_instead_of_braces(
- &mut self,
- lo: Span,
- attrs: AttrVec,
- ) -> Option<P<Expr>> {
+ fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option<P<Expr>> {
let mut snapshot = self.create_snapshot_for_diagnostic();
- match snapshot.parse_array_or_repeat_expr(attrs, Delimiter::Brace) {
+ match snapshot.parse_array_or_repeat_expr(Delimiter::Brace) {
Ok(arr) => {
let hi = snapshot.prev_token.span;
self.struct_span_err(arr.span, "this is a block expression, not an array")
@@ -2056,43 +1973,76 @@ impl<'a> Parser<'a> {
}
}
+ fn suggest_missing_semicolon_before_array(
+ &self,
+ prev_span: Span,
+ open_delim_span: Span,
+ ) -> PResult<'a, ()> {
+ if self.token.kind == token::Comma {
+ if !self.sess.source_map().is_multiline(prev_span.until(self.token.span)) {
+ return Ok(());
+ }
+ let mut snapshot = self.create_snapshot_for_diagnostic();
+ snapshot.bump();
+ match snapshot.parse_seq_to_before_end(
+ &token::CloseDelim(Delimiter::Bracket),
+ SeqSep::trailing_allowed(token::Comma),
+ |p| p.parse_expr(),
+ ) {
+ Ok(_)
+ // When the close delim is `)`, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
+ // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`.
+ // This is because the `token.kind` of the close delim is treated as the same as
+ // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
+ // Therefore, `token.kind` should not be compared here.
+ if snapshot
+ .span_to_snippet(snapshot.token.span)
+ .map_or(false, |snippet| snippet == "]") =>
+ {
+ return Err(MissingSemicolonBeforeArray {
+ open_delim: open_delim_span,
+ semicolon: prev_span.shrink_to_hi(),
+ }.into_diagnostic(&self.sess.span_diagnostic));
+ }
+ Ok(_) => (),
+ Err(err) => err.cancel(),
+ }
+ }
+ Ok(())
+ }
+
/// Parses a block or unsafe block.
pub(super) fn parse_block_expr(
&mut self,
opt_label: Option<Label>,
lo: Span,
blk_mode: BlockCheckMode,
- mut attrs: AttrVec,
) -> PResult<'a, P<Expr>> {
if self.is_array_like_block() {
- if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo, attrs.clone()) {
+ if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo) {
return Ok(arr);
}
}
- if let Some(label) = opt_label {
- self.sess.gated_spans.gate(sym::label_break_value, label.ident.span);
- }
-
if self.token.is_whole_block() {
- self.struct_span_err(self.token.span, "cannot use a `block` macro fragment here")
- .span_label(lo.to(self.token.span), "the `block` fragment is within this context")
- .emit();
+ self.sess.emit_err(InvalidBlockMacroSegment {
+ span: self.token.span,
+ context: lo.to(self.token.span),
+ });
}
- let (inner_attrs, blk) = self.parse_block_common(lo, blk_mode)?;
- attrs.extend(inner_attrs);
- Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs))
+ let (attrs, blk) = self.parse_block_common(lo, blk_mode)?;
+ Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs))
}
/// Parse a block which takes no attributes and has no label
fn parse_simple_block(&mut self) -> PResult<'a, P<Expr>> {
let blk = self.parse_block()?;
- Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()))
+ Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None)))
}
/// Parses a closure expression (e.g., `move |args| expr`).
- fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_closure_expr(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
let binder = if self.check_keyword(kw::For) {
@@ -2127,7 +2077,7 @@ impl<'a> Parser<'a> {
_ => {
// If an explicit return type is given, require a block to appear (RFC 968).
let body_lo = self.token.span;
- self.parse_block_expr(None, body_lo, BlockCheckMode::Default, AttrVec::new())?
+ self.parse_block_expr(None, body_lo, BlockCheckMode::Default)?
}
};
@@ -2158,7 +2108,6 @@ impl<'a> Parser<'a> {
body,
lo.to(decl_hi),
),
- attrs,
);
// Disable recovery for closure body
@@ -2221,10 +2170,10 @@ impl<'a> Parser<'a> {
Ok((
Param {
- attrs: attrs.into(),
+ attrs,
ty,
pat,
- span: lo.to(this.token.span),
+ span: lo.to(this.prev_token.span),
id: DUMMY_NODE_ID,
is_placeholder: false,
},
@@ -2234,19 +2183,13 @@ impl<'a> Parser<'a> {
}
/// Parses an `if` expression (`if` token already eaten).
- fn parse_if_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_if_expr(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.prev_token.span;
let cond = self.parse_cond_expr()?;
-
- self.parse_if_after_cond(attrs, lo, cond)
+ self.parse_if_after_cond(lo, cond)
}
- fn parse_if_after_cond(
- &mut self,
- attrs: AttrVec,
- lo: Span,
- mut cond: P<Expr>,
- ) -> PResult<'a, P<Expr>> {
+ fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<Expr>> {
let cond_span = cond.span;
// Tries to interpret `cond` as either a missing expression if it's a block,
// or as an unfinished expression if it's a binop and the RHS is a block.
@@ -2255,11 +2198,19 @@ impl<'a> Parser<'a> {
let block = match &mut cond.kind {
ExprKind::Binary(Spanned { span: binop_span, .. }, _, right)
if let ExprKind::Block(_, None) = right.kind => {
- this.error_missing_if_then_block(lo, cond_span.shrink_to_lo().to(*binop_span), true).emit();
+ self.sess.emit_err(IfExpressionMissingThenBlock {
+ if_span: lo,
+ sub: IfExpressionMissingThenBlockSub::UnfinishedCondition(
+ cond_span.shrink_to_lo().to(*binop_span)
+ ),
+ });
std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi()))
},
ExprKind::Block(_, None) => {
- this.error_missing_if_cond(lo, cond_span).emit();
+ self.sess.emit_err(IfExpressionMissingCondition {
+ if_span: self.sess.source_map().next_point(lo),
+ block_span: self.sess.source_map().start_point(cond_span),
+ });
std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi()))
}
_ => {
@@ -2277,7 +2228,10 @@ impl<'a> Parser<'a> {
if let Some(block) = recover_block_from_condition(self) {
block
} else {
- self.error_missing_if_then_block(lo, cond_span, false).emit();
+ self.sess.emit_err(IfExpressionMissingThenBlock {
+ if_span: lo,
+ sub: IfExpressionMissingThenBlockSub::AddThenBlock(cond_span.shrink_to_hi()),
+ });
self.mk_block_err(cond_span.shrink_to_hi())
}
} else {
@@ -2302,45 +2256,13 @@ impl<'a> Parser<'a> {
block
};
let els = if self.eat_keyword(kw::Else) { Some(self.parse_else_expr()?) } else { None };
- Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els), attrs))
- }
-
- fn error_missing_if_then_block(
- &self,
- if_span: Span,
- cond_span: Span,
- is_unfinished: bool,
- ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
- let mut err = self.struct_span_err(
- if_span,
- "this `if` expression is missing a block after the condition",
- );
- if is_unfinished {
- err.span_help(cond_span, "this binary operation is possibly unfinished");
- } else {
- err.span_help(cond_span.shrink_to_hi(), "add a block here");
- }
- err
- }
-
- fn error_missing_if_cond(
- &self,
- lo: Span,
- span: Span,
- ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
- let next_span = self.sess.source_map().next_point(lo);
- let mut err = self.struct_span_err(next_span, "missing condition for `if` expression");
- err.span_label(next_span, "expected condition here");
- err.span_label(
- self.sess.source_map().start_point(span),
- "if this block is the condition of the `if` expression, then it must be followed by another block"
- );
- err
+ Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
}
/// Parses the condition of a `if` or `while` expression.
fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> {
- let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)?;
+ let cond =
+ self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)?;
if let ExprKind::Let(..) = cond.kind {
// Remove the last feature gating of a `let` expression since it's stable.
@@ -2351,7 +2273,7 @@ impl<'a> Parser<'a> {
}
/// Parses a `let $pat = $expr` pseudo-expression.
- fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_let_expr(&mut self) -> PResult<'a, P<Expr>> {
// This is a *approximate* heuristic that detects if `let` chains are
// being parsed in the right position. It's approximate because it
// doesn't deny all invalid `let` expressions, just completely wrong usages.
@@ -2360,8 +2282,7 @@ impl<'a> Parser<'a> {
TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _)
);
if !self.restrictions.contains(Restrictions::ALLOW_LET) || not_in_chain {
- self.struct_span_err(self.token.span, "expected expression, found `let` statement")
- .emit();
+ self.sess.emit_err(ExpectedExpressionFoundLet { span: self.token.span });
}
self.bump(); // Eat `let` token
@@ -2378,7 +2299,7 @@ impl<'a> Parser<'a> {
})?;
let span = lo.to(expr.span);
self.sess.gated_spans.gate(sym::let_chains, span);
- Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span), attrs))
+ Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span)))
}
/// Parses an `else { ... }` expression (`else` token already eaten).
@@ -2386,7 +2307,7 @@ impl<'a> Parser<'a> {
let else_span = self.prev_token.span; // `else`
let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
let expr = if self.eat_keyword(kw::If) {
- self.parse_if_expr(AttrVec::new())?
+ self.parse_if_expr()?
} else if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) {
self.parse_simple_block()?
} else {
@@ -2400,16 +2321,13 @@ impl<'a> Parser<'a> {
if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
&& classify::expr_requires_semi_to_be_stmt(&cond) =>
{
- self.struct_span_err(first_tok_span, format!("expected `{{`, found {first_tok}"))
- .span_label(else_span, "expected an `if` or a block after this `else`")
- .span_suggestion(
- cond.span.shrink_to_lo(),
- "add an `if` if this is the condition of a chained `else if` statement",
- "if ",
- Applicability::MaybeIncorrect,
- )
- .emit();
- self.parse_if_after_cond(AttrVec::new(), cond.span.shrink_to_lo(), cond)?
+ self.sess.emit_err(ExpectedElseBlock {
+ first_tok_span,
+ first_tok,
+ else_span,
+ condition_start: cond.span.shrink_to_lo(),
+ });
+ self.parse_if_after_cond(cond.span.shrink_to_lo(), cond)?
}
Err(e) => {
e.cancel();
@@ -2433,25 +2351,22 @@ impl<'a> Parser<'a> {
branch_span: Span,
attrs: &[ast::Attribute],
) {
- let (span, last) = match attrs {
+ let (attributes, last) = match attrs {
[] => return,
[x0 @ xn] | [x0, .., xn] => (x0.span.to(xn.span), xn.span),
};
let ctx = if is_ctx_else { "else" } else { "if" };
- self.struct_span_err(last, "outer attributes are not allowed on `if` and `else` branches")
- .span_label(branch_span, "the attributes are attached to this branch")
- .span_label(ctx_span, format!("the branch belongs to this `{ctx}`"))
- .span_suggestion(span, "remove the attributes", "", Applicability::MachineApplicable)
- .emit();
+ self.sess.emit_err(OuterAttributeNotAllowedOnIfElse {
+ last,
+ branch_span,
+ ctx_span,
+ ctx: ctx.to_string(),
+ attributes,
+ });
}
/// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
- fn parse_for_expr(
- &mut self,
- opt_label: Option<Label>,
- lo: Span,
- mut attrs: AttrVec,
- ) -> PResult<'a, P<Expr>> {
+ fn parse_for_expr(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
// Record whether we are about to parse `for (`.
// This is used below for recovery in case of `for ( $stuff ) $block`
// in which case we will suggest `for $stuff $block`.
@@ -2474,63 +2389,51 @@ impl<'a> Parser<'a> {
let pat = self.recover_parens_around_for_head(pat, begin_paren);
- let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
- attrs.extend(iattrs);
+ let (attrs, loop_block) = self.parse_inner_attrs_and_block()?;
let kind = ExprKind::ForLoop(pat, expr, loop_block, opt_label);
- Ok(self.mk_expr(lo.to(self.prev_token.span), kind, attrs))
+ Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
}
fn error_missing_in_for_loop(&mut self) {
- let (span, msg, sugg) = if self.token.is_ident_named(sym::of) {
+ let (span, sub): (_, fn(_) -> _) = if self.token.is_ident_named(sym::of) {
// Possibly using JS syntax (#75311).
let span = self.token.span;
self.bump();
- (span, "try using `in` here instead", "in")
+ (span, MissingInInForLoopSub::InNotOf)
} else {
- (self.prev_token.span.between(self.token.span), "try adding `in` here", " in ")
+ (self.prev_token.span.between(self.token.span), MissingInInForLoopSub::AddIn)
};
- self.struct_span_err(span, "missing `in` in `for` loop")
- .span_suggestion_short(
- span,
- msg,
- sugg,
- // Has been misleading, at least in the past (closed Issue #48492).
- Applicability::MaybeIncorrect,
- )
- .emit();
+
+ self.sess.emit_err(MissingInInForLoop { span, sub: sub(span) });
}
/// Parses a `while` or `while let` expression (`while` token already eaten).
- fn parse_while_expr(
- &mut self,
- opt_label: Option<Label>,
- lo: Span,
- mut attrs: AttrVec,
- ) -> PResult<'a, P<Expr>> {
+ fn parse_while_expr(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
let cond = self.parse_cond_expr().map_err(|mut err| {
err.span_label(lo, "while parsing the condition of this `while` expression");
err
})?;
- let (iattrs, body) = self.parse_inner_attrs_and_block().map_err(|mut err| {
+ let (attrs, body) = self.parse_inner_attrs_and_block().map_err(|mut err| {
err.span_label(lo, "while parsing the body of this `while` expression");
err.span_label(cond.span, "this `while` condition successfully parsed");
err
})?;
- attrs.extend(iattrs);
- Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::While(cond, body, opt_label), attrs))
+ Ok(self.mk_expr_with_attrs(
+ lo.to(self.prev_token.span),
+ ExprKind::While(cond, body, opt_label),
+ attrs,
+ ))
}
/// Parses `loop { ... }` (`loop` token already eaten).
- fn parse_loop_expr(
- &mut self,
- opt_label: Option<Label>,
- lo: Span,
- mut attrs: AttrVec,
- ) -> PResult<'a, P<Expr>> {
- let (iattrs, body) = self.parse_inner_attrs_and_block()?;
- attrs.extend(iattrs);
- Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::Loop(body, opt_label), attrs))
+ fn parse_loop_expr(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
+ let (attrs, body) = self.parse_inner_attrs_and_block()?;
+ Ok(self.mk_expr_with_attrs(
+ lo.to(self.prev_token.span),
+ ExprKind::Loop(body, opt_label),
+ attrs,
+ ))
}
pub(crate) fn eat_label(&mut self) -> Option<Label> {
@@ -2541,7 +2444,7 @@ impl<'a> Parser<'a> {
}
/// Parses a `match ... { ... }` expression (`match` token already eaten).
- fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_match_expr(&mut self) -> PResult<'a, P<Expr>> {
let match_span = self.prev_token.span;
let lo = self.prev_token.span;
let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
@@ -2561,7 +2464,7 @@ impl<'a> Parser<'a> {
return Err(e);
}
}
- attrs.extend(self.parse_inner_attributes()?);
+ let attrs = self.parse_inner_attributes()?;
let mut arms: Vec<Arm> = Vec::new();
while self.token != token::CloseDelim(Delimiter::Brace) {
@@ -2575,13 +2478,17 @@ impl<'a> Parser<'a> {
if self.token == token::CloseDelim(Delimiter::Brace) {
self.bump();
}
- return Ok(self.mk_expr(span, ExprKind::Match(scrutinee, arms), attrs));
+ return Ok(self.mk_expr_with_attrs(
+ span,
+ ExprKind::Match(scrutinee, arms),
+ attrs,
+ ));
}
}
}
let hi = self.token.span;
self.bump();
- Ok(self.mk_expr(lo.to(hi), ExprKind::Match(scrutinee, arms), attrs))
+ Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms), attrs))
}
/// Attempt to recover from match arm body with statements and no surrounding braces.
@@ -2681,7 +2588,7 @@ impl<'a> Parser<'a> {
}
pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
- // Used to check the `let_chains` and `if_let_guard` features mostly by scaning
+ // Used to check the `let_chains` and `if_let_guard` features mostly by scanning
// `&&` tokens.
fn check_let_expr(expr: &Expr) -> (bool, bool) {
match expr.kind {
@@ -2756,7 +2663,7 @@ impl<'a> Parser<'a> {
let span = body.span;
return Ok((
ast::Arm {
- attrs: attrs.into(),
+ attrs,
pat,
guard,
body,
@@ -2811,17 +2718,9 @@ impl<'a> Parser<'a> {
.is_ok();
if pattern_follows && snapshot.check(&TokenKind::FatArrow) {
err.cancel();
- this.struct_span_err(
- hi.shrink_to_hi(),
- "expected `,` following `match` arm",
- )
- .span_suggestion(
- hi.shrink_to_hi(),
- "missing a comma here to end this `match` arm",
- ",",
- Applicability::MachineApplicable,
- )
- .emit();
+ this.sess.emit_err(MissingCommaAfterMatchArm {
+ span: hi.shrink_to_hi(),
+ });
return Ok(true);
}
}
@@ -2834,7 +2733,7 @@ impl<'a> Parser<'a> {
Ok((
ast::Arm {
- attrs: attrs.into(),
+ attrs,
pat,
guard,
body: expr,
@@ -2848,21 +2747,15 @@ impl<'a> Parser<'a> {
}
/// Parses a `try {...}` expression (`try` token already eaten).
- fn parse_try_block(&mut self, span_lo: Span, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
- let (iattrs, body) = self.parse_inner_attrs_and_block()?;
- attrs.extend(iattrs);
+ fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
+ let (attrs, body) = self.parse_inner_attrs_and_block()?;
if self.eat_keyword(kw::Catch) {
- let mut error = self.struct_span_err(
- self.prev_token.span,
- "keyword `catch` cannot follow a `try` block",
- );
- error.help("try using `match` on the result of the `try` block instead");
- error.emit();
- Err(error)
+ Err(CatchAfterTry { span: self.prev_token.span }
+ .into_diagnostic(&self.sess.span_diagnostic))
} else {
let span = span_lo.to(body.span);
self.sess.gated_spans.gate(sym::try_blocks, span);
- Ok(self.mk_expr(span, ExprKind::TryBlock(body), attrs))
+ Ok(self.mk_expr_with_attrs(span, ExprKind::TryBlock(body), attrs))
}
}
@@ -2884,14 +2777,13 @@ impl<'a> Parser<'a> {
}
/// Parses an `async move? {...}` expression.
- fn parse_async_block(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_async_block(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
self.expect_keyword(kw::Async)?;
let capture_clause = self.parse_capture_clause()?;
- let (iattrs, body) = self.parse_inner_attrs_and_block()?;
- attrs.extend(iattrs);
+ let (attrs, body) = self.parse_inner_attrs_and_block()?;
let kind = ExprKind::Async(capture_clause, DUMMY_NODE_ID, body);
- Ok(self.mk_expr(lo.to(self.prev_token.span), kind, attrs))
+ Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
}
fn is_async_block(&self) -> bool {
@@ -2925,14 +2817,13 @@ impl<'a> Parser<'a> {
&mut self,
qself: Option<&ast::QSelf>,
path: &ast::Path,
- attrs: &AttrVec,
) -> Option<PResult<'a, P<Expr>>> {
let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
if struct_allowed || self.is_certainly_not_a_block() {
if let Err(err) = self.expect(&token::OpenDelim(Delimiter::Brace)) {
return Some(Err(err));
}
- let expr = self.parse_struct_expr(qself.cloned(), path.clone(), attrs.clone(), true);
+ let expr = self.parse_struct_expr(qself.cloned(), path.clone(), true);
if let (Ok(expr), false) = (&expr, struct_allowed) {
// This is a struct literal, but we don't can't accept them here.
self.error_struct_lit_not_allowed_here(path.span, expr.span);
@@ -3069,7 +2960,6 @@ impl<'a> Parser<'a> {
&mut self,
qself: Option<ast::QSelf>,
pth: ast::Path,
- attrs: AttrVec,
recover: bool,
) -> PResult<'a, P<Expr>> {
let lo = pth.span;
@@ -3082,7 +2972,7 @@ impl<'a> Parser<'a> {
} else {
ExprKind::Struct(P(ast::StructExpr { qself, path: pth, fields, rest: base }))
};
- Ok(self.mk_expr(span, expr, attrs))
+ Ok(self.mk_expr(span, expr))
}
/// Use in case of error after field-looking code: `S { foo: () with a }`.
@@ -3110,18 +3000,10 @@ impl<'a> Parser<'a> {
if self.token != token::Comma {
return;
}
- self.struct_span_err(
- span.to(self.prev_token.span),
- "cannot use a comma after the base struct",
- )
- .span_suggestion_short(
- self.token.span,
- "remove this comma",
- "",
- Applicability::MachineApplicable,
- )
- .note("the base struct must always be the last field")
- .emit();
+ self.sess.emit_err(CommaAfterBaseStruct {
+ span: span.to(self.prev_token.span),
+ comma: self.token.span,
+ });
self.recover_stmt();
}
@@ -3137,7 +3019,7 @@ impl<'a> Parser<'a> {
// Mimic `x: x` for the `x` field shorthand.
let ident = this.parse_ident_common(false)?;
let path = ast::Path::from_ident(ident);
- (ident, this.mk_expr(ident.span, ExprKind::Path(None, path), AttrVec::new()))
+ (ident, this.mk_expr(ident.span, ExprKind::Path(None, path)))
} else {
let ident = this.parse_field_name()?;
this.error_on_eq_field_init(ident);
@@ -3151,7 +3033,7 @@ impl<'a> Parser<'a> {
span: lo.to(expr.span),
expr,
is_shorthand,
- attrs: attrs.into(),
+ attrs,
id: DUMMY_NODE_ID,
is_placeholder: false,
},
@@ -3167,43 +3049,18 @@ impl<'a> Parser<'a> {
return;
}
- self.struct_span_err(self.token.span, "expected `:`, found `=`")
- .span_suggestion(
- field_name.span.shrink_to_hi().to(self.token.span),
- "replace equals symbol with a colon",
- ":",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(EqFieldInit {
+ span: self.token.span,
+ eq: field_name.span.shrink_to_hi().to(self.token.span),
+ });
}
fn err_dotdotdot_syntax(&self, span: Span) {
- self.struct_span_err(span, "unexpected token: `...`")
- .span_suggestion(
- span,
- "use `..` for an exclusive range",
- "..",
- Applicability::MaybeIncorrect,
- )
- .span_suggestion(
- span,
- "or `..=` for an inclusive range",
- "..=",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(DotDotDot { span });
}
fn err_larrow_operator(&self, span: Span) {
- self.struct_span_err(span, "unexpected token: `<-`")
- .span_suggestion(
- span,
- "if you meant to write a comparison against a negative value, add a \
- space in between `<` and `-`",
- "< -",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(LeftArrowOperator { span });
}
fn mk_assign_op(&self, binop: BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ExprKind {
@@ -3242,17 +3099,21 @@ impl<'a> Parser<'a> {
fn mk_await_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> {
let span = lo.to(self.prev_token.span);
- let await_expr = self.mk_expr(span, ExprKind::Await(self_arg), AttrVec::new());
+ let await_expr = self.mk_expr(span, ExprKind::Await(self_arg));
self.recover_from_await_method_call();
await_expr
}
- pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P<Expr> {
+ pub(crate) fn mk_expr_with_attrs(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P<Expr> {
P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
}
+ pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind) -> P<Expr> {
+ P(Expr { kind, span, attrs: AttrVec::new(), id: DUMMY_NODE_ID, tokens: None })
+ }
+
pub(super) fn mk_expr_err(&self, span: Span) -> P<Expr> {
- self.mk_expr(span, ExprKind::Err, AttrVec::new())
+ self.mk_expr(span, ExprKind::Err)
}
/// Create expression span ensuring the span of the parent node
@@ -3268,7 +3129,7 @@ impl<'a> Parser<'a> {
fn collect_tokens_for_expr(
&mut self,
attrs: AttrWrapper,
- f: impl FnOnce(&mut Self, Vec<ast::Attribute>) -> PResult<'a, P<Expr>>,
+ f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, P<Expr>>,
) -> PResult<'a, P<Expr>> {
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
let res = f(this, attrs)?;
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 1acfd93d8..4d0a8b05e 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -1,9 +1,7 @@
use super::{ForceCollect, Parser, TrailingToken};
use rustc_ast::token;
-use rustc_ast::{
- self as ast, Attribute, GenericBounds, GenericParam, GenericParamKind, WhereClause,
-};
+use rustc_ast::{self as ast, AttrVec, GenericBounds, GenericParam, GenericParamKind, WhereClause};
use rustc_errors::{Applicability, PResult};
use rustc_span::symbol::kw;
@@ -26,7 +24,7 @@ impl<'a> Parser<'a> {
}
/// Matches `typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?`.
- fn parse_ty_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, GenericParam> {
+ fn parse_ty_param(&mut self, preceding_attrs: AttrVec) -> PResult<'a, GenericParam> {
let ident = self.parse_ident()?;
// Parse optional colon and param bounds.
@@ -43,7 +41,7 @@ impl<'a> Parser<'a> {
Ok(GenericParam {
ident,
id: ast::DUMMY_NODE_ID,
- attrs: preceding_attrs.into(),
+ attrs: preceding_attrs,
bounds,
kind: GenericParamKind::Type { default },
is_placeholder: false,
@@ -53,7 +51,7 @@ impl<'a> Parser<'a> {
pub(crate) fn parse_const_param(
&mut self,
- preceding_attrs: Vec<Attribute>,
+ preceding_attrs: AttrVec,
) -> PResult<'a, GenericParam> {
let const_span = self.token.span;
@@ -68,7 +66,7 @@ impl<'a> Parser<'a> {
Ok(GenericParam {
ident,
id: ast::DUMMY_NODE_ID,
- attrs: preceding_attrs.into(),
+ attrs: preceding_attrs,
bounds: Vec::new(),
kind: GenericParamKind::Const { ty, kw_span: const_span, default },
is_placeholder: false,
@@ -109,7 +107,7 @@ impl<'a> Parser<'a> {
Some(ast::GenericParam {
ident: lifetime.ident,
id: lifetime.id,
- attrs: attrs.into(),
+ attrs,
bounds,
kind: ast::GenericParamKind::Lifetime,
is_placeholder: false,
@@ -314,7 +312,6 @@ impl<'a> Parser<'a> {
span: lo.to(self.prev_token.span),
lhs_ty: ty,
rhs_ty,
- id: ast::DUMMY_NODE_ID,
}))
} else {
self.maybe_recover_bounds_doubled_colon(&ty)?;
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 567072925..e55b5ce71 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -8,7 +8,7 @@ use rustc_ast::token::{self, Delimiter, TokenKind};
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID};
use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind};
-use rustc_ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind};
+use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind};
use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, VariantData};
use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
use rustc_ast::{MacArgs, MacCall, MacDelimiter};
@@ -22,7 +22,6 @@ use rustc_span::DUMMY_SP;
use std::convert::TryFrom;
use std::mem;
-use tracing::debug;
impl<'a> Parser<'a> {
/// Parses a source module as a crate. This is the main entry point for the parser.
@@ -32,7 +31,7 @@ impl<'a> Parser<'a> {
}
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
- fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
+ fn parse_item_mod(&mut self, attrs: &mut AttrVec) -> PResult<'a, ItemInfo> {
let unsafety = self.parse_unsafety();
self.expect_keyword(kw::Mod)?;
let id = self.parse_ident()?;
@@ -40,9 +39,9 @@ impl<'a> Parser<'a> {
ModKind::Unloaded
} else {
self.expect(&token::OpenDelim(Delimiter::Brace))?;
- let (mut inner_attrs, items, inner_span) =
+ let (inner_attrs, items, inner_span) =
self.parse_mod(&token::CloseDelim(Delimiter::Brace))?;
- attrs.append(&mut inner_attrs);
+ attrs.extend(inner_attrs);
ModKind::Loaded(items, Inline::Yes, inner_span)
};
Ok((id, ItemKind::Mod(unsafety, mod_kind)))
@@ -52,7 +51,7 @@ impl<'a> Parser<'a> {
pub fn parse_mod(
&mut self,
term: &TokenKind,
- ) -> PResult<'a, (Vec<Attribute>, Vec<P<Item>>, ModSpans)> {
+ ) -> PResult<'a, (AttrVec, Vec<P<Item>>, ModSpans)> {
let lo = self.token.span;
let attrs = self.parse_inner_attributes()?;
@@ -68,7 +67,12 @@ impl<'a> Parser<'a> {
if !self.maybe_consume_incorrect_semicolon(&items) {
let msg = &format!("expected item, found {token_str}");
let mut err = self.struct_span_err(self.token.span, msg);
- err.span_label(self.token.span, "expected item");
+ let label = if self.is_kw_followed_by_ident(kw::Let) {
+ "consider using `const` or `static` instead of `let` for global variables"
+ } else {
+ "expected item"
+ };
+ err.span_label(self.token.span, label);
return Err(err);
}
}
@@ -129,7 +133,7 @@ impl<'a> Parser<'a> {
fn parse_item_common_(
&mut self,
- mut attrs: Vec<Attribute>,
+ mut attrs: AttrVec,
mac_allowed: bool,
attrs_allowed: bool,
fn_parse_mode: FnParseMode,
@@ -193,7 +197,7 @@ impl<'a> Parser<'a> {
/// Parses one of the items allowed by the flags.
fn parse_item_kind(
&mut self,
- attrs: &mut Vec<Attribute>,
+ attrs: &mut AttrVec,
macros_allowed: bool,
lo: Span,
vis: &Visibility,
@@ -271,7 +275,10 @@ impl<'a> Parser<'a> {
// MACRO_RULES ITEM
self.parse_item_macro_rules(vis, has_bang)?
} else if self.isnt_macro_invocation()
- && (self.token.is_ident_named(sym::import) || self.token.is_ident_named(sym::using))
+ && (self.token.is_ident_named(sym::import)
+ || self.token.is_ident_named(sym::using)
+ || self.token.is_ident_named(sym::include)
+ || self.token.is_ident_named(sym::require))
{
return self.recover_import_as_use();
} else if self.isnt_macro_invocation() && vis.kind.is_pub() {
@@ -279,7 +286,7 @@ impl<'a> Parser<'a> {
return Ok(None);
} else if macros_allowed && self.check_path() {
// MACRO INVOCATION ITEM
- (Ident::empty(), ItemKind::MacCall(self.parse_item_macro(vis)?))
+ (Ident::empty(), ItemKind::MacCall(P(self.parse_item_macro(vis)?)))
} else {
return Ok(None);
};
@@ -526,7 +533,7 @@ impl<'a> Parser<'a> {
/// ```
fn parse_item_impl(
&mut self,
- attrs: &mut Vec<Attribute>,
+ attrs: &mut AttrVec,
defaultness: Defaultness,
) -> PResult<'a, ItemInfo> {
let unsafety = self.parse_unsafety();
@@ -653,12 +660,12 @@ impl<'a> Parser<'a> {
fn parse_item_list<T>(
&mut self,
- attrs: &mut Vec<Attribute>,
+ attrs: &mut AttrVec,
mut parse_item: impl FnMut(&mut Parser<'a>) -> PResult<'a, Option<Option<T>>>,
) -> PResult<'a, Vec<T>> {
let open_brace_span = self.token.span;
self.expect(&token::OpenDelim(Delimiter::Brace))?;
- attrs.append(&mut self.parse_inner_attributes()?);
+ attrs.extend(self.parse_inner_attributes()?);
let mut items = Vec::new();
while !self.eat(&token::CloseDelim(Delimiter::Brace)) {
@@ -667,14 +674,55 @@ impl<'a> Parser<'a> {
}
match parse_item(self) {
Ok(None) => {
+ let is_unnecessary_semicolon = !items.is_empty()
+ // When the close delim is `)` in a case like the following, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
+ // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`.
+ // This is because the `token.kind` of the close delim is treated as the same as
+ // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
+ // Therefore, `token.kind` should not be compared here.
+ //
+ // issue-60075.rs
+ // ```
+ // trait T {
+ // fn qux() -> Option<usize> {
+ // let _ = if true {
+ // });
+ // ^ this close delim
+ // Some(4)
+ // }
+ // ```
+ && self
+ .span_to_snippet(self.prev_token.span)
+ .map_or(false, |snippet| snippet == "}")
+ && self.token.kind == token::Semi;
+ let semicolon_span = self.token.span;
// We have to bail or we'll potentially never make progress.
let non_item_span = self.token.span;
+ let is_let = self.token.is_keyword(kw::Let);
+
+ let mut err = self.struct_span_err(non_item_span, "non-item in item list");
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
- self.struct_span_err(non_item_span, "non-item in item list")
- .span_label(open_brace_span, "item list starts here")
- .span_label(non_item_span, "non-item starts here")
- .span_label(self.prev_token.span, "item list ends here")
- .emit();
+ if is_let {
+ err.span_suggestion(
+ non_item_span,
+ "consider using `const` instead of `let` for associated const",
+ "const",
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.span_label(open_brace_span, "item list starts here")
+ .span_label(non_item_span, "non-item starts here")
+ .span_label(self.prev_token.span, "item list ends here");
+ }
+ if is_unnecessary_semicolon {
+ err.span_suggestion(
+ semicolon_span,
+ "consider removing this semicolon",
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ err.emit();
break;
}
Ok(Some(item)) => items.extend(item),
@@ -737,7 +785,7 @@ impl<'a> Parser<'a> {
}
/// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`.
- fn parse_item_trait(&mut self, attrs: &mut Vec<Attribute>, lo: Span) -> PResult<'a, ItemInfo> {
+ fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemInfo> {
let unsafety = self.parse_unsafety();
// Parse optional `auto` prefix.
let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No };
@@ -1023,7 +1071,7 @@ impl<'a> Parser<'a> {
/// ```
fn parse_item_foreign_mod(
&mut self,
- attrs: &mut Vec<Attribute>,
+ attrs: &mut AttrVec,
mut unsafety: Unsafe,
) -> PResult<'a, ItemInfo> {
let abi = self.parse_abi(); // ABI?
@@ -1124,6 +1172,16 @@ impl<'a> Parser<'a> {
Applicability::MaybeIncorrect,
)
.emit();
+ } else if self.eat_keyword(kw::Let) {
+ let span = self.prev_token.span;
+ self.struct_span_err(const_span.to(span), "`const` and `let` are mutually exclusive")
+ .span_suggestion(
+ const_span.to(span),
+ "remove `let`",
+ "const",
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
}
}
@@ -1131,7 +1189,7 @@ impl<'a> Parser<'a> {
fn recover_const_impl(
&mut self,
const_span: Span,
- attrs: &mut Vec<Attribute>,
+ attrs: &mut AttrVec,
defaultness: Defaultness,
) -> PResult<'a, ItemInfo> {
let impl_span = self.token.span;
@@ -1179,10 +1237,11 @@ impl<'a> Parser<'a> {
// Parse the type of a `const` or `static mut?` item.
// That is, the `":" $ty` fragment.
- let ty = if self.eat(&token::Colon) {
- self.parse_ty()?
- } else {
- self.recover_missing_const_type(id, m)
+ let ty = match (self.eat(&token::Colon), self.check(&token::Eq) | self.check(&token::Semi))
+ {
+ // If there wasn't a `:` or the colon was followed by a `=` or `;` recover a missing type.
+ (true, false) => self.parse_ty()?,
+ (colon, _) => self.recover_missing_const_type(colon, m),
};
let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
@@ -1190,9 +1249,9 @@ impl<'a> Parser<'a> {
Ok((id, ty, expr))
}
- /// We were supposed to parse `:` but the `:` was missing.
+ /// We were supposed to parse `":" $ty` but the `:` or the type was missing.
/// This means that the type is missing.
- fn recover_missing_const_type(&mut self, id: Ident, m: Option<Mutability>) -> P<Ty> {
+ fn recover_missing_const_type(&mut self, colon_present: bool, m: Option<Mutability>) -> P<Ty> {
// Construct the error and stash it away with the hope
// that typeck will later enrich the error with a type.
let kind = match m {
@@ -1200,18 +1259,25 @@ impl<'a> Parser<'a> {
Some(Mutability::Not) => "static",
None => "const",
};
- let mut err = self.struct_span_err(id.span, &format!("missing type for `{kind}` item"));
+
+ let colon = match colon_present {
+ true => "",
+ false => ":",
+ };
+
+ let span = self.prev_token.span.shrink_to_hi();
+ let mut err = self.struct_span_err(span, &format!("missing type for `{kind}` item"));
err.span_suggestion(
- id.span,
+ span,
"provide a type for the item",
- format!("{id}: <type>"),
+ format!("{colon} <type>"),
Applicability::HasPlaceholders,
);
- err.stash(id.span, StashKey::ItemNoType);
+ err.stash(span, StashKey::ItemNoType);
// The user intended that the type be inferred,
// so treat this as if the user wrote e.g. `const A: _ = expr;`.
- P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID, tokens: None })
+ P(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID, tokens: None })
}
/// Parses an enum declaration.
@@ -1281,7 +1347,7 @@ impl<'a> Parser<'a> {
ident,
vis,
id: DUMMY_NODE_ID,
- attrs: variant_attrs.into(),
+ attrs: variant_attrs,
data: struct_def,
disr_expr,
span: vlo.to(this.prev_token.span),
@@ -1438,7 +1504,7 @@ impl<'a> Parser<'a> {
ident: None,
id: DUMMY_NODE_ID,
ty,
- attrs: attrs.into(),
+ attrs,
is_placeholder: false,
},
TrailingToken::MaybeComma,
@@ -1464,13 +1530,24 @@ impl<'a> Parser<'a> {
adt_ty: &str,
lo: Span,
vis: Visibility,
- attrs: Vec<Attribute>,
+ attrs: AttrVec,
) -> PResult<'a, FieldDef> {
let mut seen_comma: bool = false;
let a_var = self.parse_name_and_ty(adt_ty, lo, vis, attrs)?;
if self.token == token::Comma {
seen_comma = true;
}
+ if self.eat(&token::Semi) {
+ let sp = self.prev_token.span;
+ let mut err = self.struct_span_err(sp, format!("{adt_ty} fields are separated by `,`"));
+ err.span_suggestion_short(
+ sp,
+ "replace `;` with `,`",
+ ",",
+ Applicability::MachineApplicable,
+ );
+ return Err(err);
+ }
match self.token.kind {
token::Comma => {
self.bump();
@@ -1528,8 +1605,12 @@ impl<'a> Parser<'a> {
}
}
- if self.token.is_ident() {
- // This is likely another field; emit the diagnostic and keep going
+ if self.token.is_ident()
+ || (self.token.kind == TokenKind::Pound
+ && (self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Bracket))))
+ {
+ // This is likely another field, TokenKind::Pound is used for `#[..]` attribute for next field,
+ // emit the diagnostic and keep going
err.span_suggestion(
sp,
"try adding a comma",
@@ -1590,7 +1671,7 @@ impl<'a> Parser<'a> {
adt_ty: &str,
lo: Span,
vis: Visibility,
- attrs: Vec<Attribute>,
+ attrs: AttrVec,
) -> PResult<'a, FieldDef> {
let name = self.parse_field_ident(adt_ty, lo)?;
self.expect_field_ty_separator()?;
@@ -1624,7 +1705,7 @@ impl<'a> Parser<'a> {
vis,
id: DUMMY_NODE_ID,
ty,
- attrs: attrs.into(),
+ attrs,
is_placeholder: false,
})
}
@@ -1643,7 +1724,7 @@ impl<'a> Parser<'a> {
// We use `parse_fn` to get a span for the function
let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
if let Err(mut db) =
- self.parse_fn(&mut Vec::new(), fn_parse_mode, lo, &inherited_vis)
+ self.parse_fn(&mut AttrVec::new(), fn_parse_mode, lo, &inherited_vis)
{
db.delay_as_bug();
}
@@ -1919,7 +2000,7 @@ impl<'a> Parser<'a> {
/// Parse a function starting from the front matter (`const ...`) to the body `{ ... }` or `;`.
fn parse_fn(
&mut self,
- attrs: &mut Vec<Attribute>,
+ attrs: &mut AttrVec,
fn_parse_mode: FnParseMode,
sig_lo: Span,
vis: &Visibility,
@@ -1942,7 +2023,7 @@ impl<'a> Parser<'a> {
/// or e.g. a block when the function is a provided one.
fn parse_fn_body(
&mut self,
- attrs: &mut Vec<Attribute>,
+ attrs: &mut AttrVec,
ident: &Ident,
sig_hi: &mut Span,
req_body: bool,
@@ -1957,7 +2038,7 @@ impl<'a> Parser<'a> {
// Include the trailing semicolon in the span of the signature
self.expect_semi()?;
*sig_hi = self.prev_token.span;
- (Vec::new(), None)
+ (AttrVec::new(), None)
} else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() {
self.parse_inner_attrs_and_block().map(|(attrs, body)| (attrs, Some(body)))?
} else if self.token.kind == token::Eq {
@@ -1974,7 +2055,7 @@ impl<'a> Parser<'a> {
Applicability::MachineApplicable,
)
.emit();
- (Vec::new(), Some(self.mk_block_err(span)))
+ (AttrVec::new(), Some(self.mk_block_err(span)))
} else {
let expected = if req_body {
&[token::OpenDelim(Delimiter::Brace)][..]
@@ -1991,7 +2072,7 @@ impl<'a> Parser<'a> {
return Err(err);
}
}
- (Vec::new(), None)
+ (AttrVec::new(), None)
};
attrs.extend(inner_attrs);
Ok(body)
@@ -2220,7 +2301,7 @@ impl<'a> Parser<'a> {
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
if let Some(mut param) = this.parse_self_param()? {
- param.attrs = attrs.into();
+ param.attrs = attrs;
let res = if first_param { Ok(param) } else { this.recover_bad_self_param(param) };
return Ok((res?, TrailingToken::None));
}
@@ -2249,7 +2330,7 @@ impl<'a> Parser<'a> {
(pat, this.parse_ty_for_param()?)
} else {
debug!("parse_param_general ident_to_pat");
- let parser_snapshot_before_ty = this.clone();
+ let parser_snapshot_before_ty = this.create_snapshot_for_diagnostic();
this.eat_incorrect_doc_comment_for_param_type();
let mut ty = this.parse_ty_for_param();
if ty.is_ok()
@@ -2263,7 +2344,7 @@ impl<'a> Parser<'a> {
match ty {
Ok(ty) => {
let ident = Ident::new(kw::Empty, this.prev_token.span);
- let bm = BindingMode::ByValue(Mutability::Not);
+ let bm = BindingAnnotation::NONE;
let pat = this.mk_pat_ident(ty.span, bm, ident);
(pat, ty)
}
@@ -2272,23 +2353,16 @@ impl<'a> Parser<'a> {
// Recover from attempting to parse the argument as a type without pattern.
Err(err) => {
err.cancel();
- *this = parser_snapshot_before_ty;
+ this.restore_snapshot(parser_snapshot_before_ty);
this.recover_arg_parse()?
}
}
};
- let span = lo.until(this.token.span);
+ let span = lo.to(this.prev_token.span);
Ok((
- Param {
- attrs: attrs.into(),
- id: ast::DUMMY_NODE_ID,
- is_placeholder: false,
- pat,
- span,
- ty,
- },
+ Param { attrs, id: ast::DUMMY_NODE_ID, is_placeholder: false, pat, span, ty },
TrailingToken::None,
))
})
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 0c523ad22..4cb198561 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -37,7 +37,6 @@ use rustc_errors::{
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{Span, DUMMY_SP};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use tracing::debug;
use std::ops::Range;
use std::{cmp, mem, slice};
@@ -171,7 +170,7 @@ pub struct ClosureSpans {
/// attribute, we parse a nested AST node that has `#[cfg]` or `#[cfg_attr]`
/// In this case, we use a `ReplaceRange` to replace the entire inner AST node
/// with `FlatToken::AttrTarget`, allowing us to perform eager cfg-expansion
-/// on an `AttrAnnotatedTokenStream`
+/// on an `AttrTokenStream`.
///
/// 2. When we parse an inner attribute while collecting tokens. We
/// remove inner attributes from the token stream entirely, and
@@ -184,7 +183,7 @@ pub type ReplaceRange = (Range<u32>, Vec<(FlatToken, Spacing)>);
/// Controls how we capture tokens. Capturing can be expensive,
/// so we try to avoid performing capturing in cases where
-/// we will never need an `AttrAnnotatedTokenStream`
+/// we will never need an `AttrTokenStream`.
#[derive(Copy, Clone)]
pub enum Capturing {
/// We aren't performing any capturing - this is the default mode.
@@ -238,7 +237,7 @@ struct TokenCursor {
// the trailing `>>` token. The `break_last_token`
// field is used to track this token - it gets
// appended to the captured stream when
- // we evaluate a `LazyTokenStream`
+ // we evaluate a `LazyAttrTokenStream`.
break_last_token: bool,
}
@@ -281,7 +280,7 @@ impl TokenCursor {
if delim != Delimiter::Invisible {
return (Token::new(token::OpenDelim(delim), sp.open), Spacing::Alone);
}
- // No open delimeter to return; continue on to the next iteration.
+ // No open delimiter to return; continue on to the next iteration.
}
};
} else if let Some(frame) = self.stack.pop() {
@@ -1116,10 +1115,14 @@ impl<'a> Parser<'a> {
let (attrs, blk) = self.parse_inner_attrs_and_block()?;
let anon_const = AnonConst {
id: DUMMY_NODE_ID,
- value: self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()),
+ value: self.mk_expr(blk.span, ExprKind::Block(blk, None)),
};
let blk_span = anon_const.value.span;
- Ok(self.mk_expr(span.to(blk_span), ExprKind::ConstBlock(anon_const), AttrVec::from(attrs)))
+ Ok(self.mk_expr_with_attrs(
+ span.to(blk_span),
+ ExprKind::ConstBlock(anon_const),
+ AttrVec::from(attrs),
+ ))
}
/// Parses mutability (`mut` or nothing).
@@ -1295,7 +1298,11 @@ impl<'a> Parser<'a> {
self.bump(); // `in`
let path = self.parse_path(PathStyle::Mod)?; // `path`
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
- let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID };
+ let vis = VisibilityKind::Restricted {
+ path: P(path),
+ id: ast::DUMMY_NODE_ID,
+ shorthand: false,
+ };
return Ok(Visibility {
span: lo.to(self.prev_token.span),
kind: vis,
@@ -1308,7 +1315,11 @@ impl<'a> Parser<'a> {
self.bump(); // `(`
let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self`
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
- let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID };
+ let vis = VisibilityKind::Restricted {
+ path: P(path),
+ id: ast::DUMMY_NODE_ID,
+ shorthand: true,
+ };
return Ok(Visibility {
span: lo.to(self.prev_token.span),
kind: vis,
@@ -1371,7 +1382,7 @@ impl<'a> Parser<'a> {
match self.parse_str_lit() {
Ok(str_lit) => Some(str_lit),
Err(Some(lit)) => match lit.kind {
- ast::LitKind::Err(_) => None,
+ ast::LitKind::Err => None,
_ => {
self.struct_span_err(lit.span, "non-string ABI literal")
.span_suggestion(
@@ -1453,11 +1464,11 @@ pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, sess: &Pa
}
}
-/// A helper struct used when building an `AttrAnnotatedTokenStream` from
-/// a `LazyTokenStream`. Both delimiter and non-delimited tokens
+/// A helper struct used when building an `AttrTokenStream` from
+/// a `LazyAttrTokenStream`. Both delimiter and non-delimited tokens
/// are stored as `FlatToken::Token`. A vector of `FlatToken`s
-/// is then 'parsed' to build up an `AttrAnnotatedTokenStream` with nested
-/// `AttrAnnotatedTokenTree::Delimited` tokens
+/// is then 'parsed' to build up an `AttrTokenStream` with nested
+/// `AttrTokenTree::Delimited` tokens.
#[derive(Debug, Clone)]
pub enum FlatToken {
/// A token - this holds both delimiter (e.g. '{' and '}')
@@ -1465,11 +1476,11 @@ pub enum FlatToken {
Token(Token),
/// Holds the `AttributesData` for an AST node. The
/// `AttributesData` is inserted directly into the
- /// constructed `AttrAnnotatedTokenStream` as
- /// an `AttrAnnotatedTokenTree::Attributes`
+ /// constructed `AttrTokenStream` as
+ /// an `AttrTokenTree::Attributes`.
AttrTarget(AttributesData),
/// A special 'empty' token that is ignored during the conversion
- /// to an `AttrAnnotatedTokenStream`. This is used to simplify the
+ /// to an `AttrTokenStream`. This is used to simplify the
/// handling of replace ranges.
Empty,
}
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index e215b6872..103dd8012 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -66,18 +66,18 @@ impl<'a> Parser<'a> {
},
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
match token.kind {
- token::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
- token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern
- token::OpenDelim(Delimiter::Bracket) | // slice pattern
- token::BinOp(token::And) | // reference
- token::BinOp(token::Minus) | // negative literal
- token::AndAnd | // double reference
- token::Literal(..) | // literal
- token::DotDot | // range pattern (future compat)
- token::DotDotDot | // range pattern (future compat)
- token::ModSep | // path
- token::Lt | // path (UFCS constant)
- token::BinOp(token::Shl) => true, // path (double UFCS)
+ token::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
+ token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern
+ token::OpenDelim(Delimiter::Bracket) | // slice pattern
+ token::BinOp(token::And) | // reference
+ token::BinOp(token::Minus) | // negative literal
+ token::AndAnd | // double reference
+ token::Literal(..) | // literal
+ token::DotDot | // range pattern (future compat)
+ token::DotDotDot | // range pattern (future compat)
+ token::ModSep | // path
+ token::Lt | // path (UFCS constant)
+ token::BinOp(token::Shl) => true, // path (double UFCS)
// leading vert `|` or-pattern
token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr {..}),
token::Interpolated(ref nt) => may_be_ident(nt),
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index ba77a3958..120a3c267 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1,10 +1,11 @@
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
+use crate::parser::diagnostics::RemoveLet;
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter};
use rustc_ast::{
- self as ast, AttrVec, Attribute, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat,
+ self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat,
PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
};
use rustc_ast_pretty::pprust;
@@ -320,7 +321,13 @@ impl<'a> Parser<'a> {
maybe_recover_from_interpolated_ty_qpath!(self, true);
maybe_whole!(self, NtPat, |x| x);
- let lo = self.token.span;
+ let mut lo = self.token.span;
+
+ if self.token.is_keyword(kw::Let) && self.look_ahead(1, |tok| tok.can_begin_pattern()) {
+ self.bump();
+ self.sess.emit_err(RemoveLet { span: lo });
+ lo = self.token.span;
+ }
let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
self.parse_pat_deref(expected)?
@@ -353,7 +360,7 @@ impl<'a> Parser<'a> {
} else if self.eat_keyword(kw::Ref) {
// Parse ref ident @ pat / ref mut ident @ pat
let mutbl = self.parse_mutability();
- self.parse_pat_ident(BindingMode::ByRef(mutbl))?
+ self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl))?
} else if self.eat_keyword(kw::Box) {
self.parse_pat_box()?
} else if self.check_inline_const(0) {
@@ -369,7 +376,7 @@ impl<'a> Parser<'a> {
// Parse `ident @ pat`
// This can give false positives and parse nullary enums,
// they are dealt with later in resolve.
- self.parse_pat_ident(BindingMode::ByValue(Mutability::Not))?
+ self.parse_pat_ident(BindingAnnotation::NONE)?
} else if self.is_start_of_pat_with_path() {
// Parse pattern starting with a path
let (qself, path) = if self.eat_lt() {
@@ -385,7 +392,7 @@ impl<'a> Parser<'a> {
if qself.is_none() && self.check(&token::Not) {
self.parse_pat_mac_invoc(path)?
} else if let Some(form) = self.parse_range_end() {
- let begin = self.mk_expr(span, ExprKind::Path(qself, path), AttrVec::new());
+ let begin = self.mk_expr(span, ExprKind::Path(qself, path));
self.parse_pat_range_begin_with(begin, form)?
} else if self.check(&token::OpenDelim(Delimiter::Brace)) {
self.parse_pat_struct(qself, path)?
@@ -578,7 +585,8 @@ impl<'a> Parser<'a> {
let mut pat = self.parse_pat_no_top_alt(Some("identifier"))?;
// If we don't have `mut $ident (@ pat)?`, error.
- if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind {
+ if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind
+ {
// Don't recurse into the subpattern.
// `mut` on the outer binding doesn't affect the inner bindings.
*m = Mutability::Mut;
@@ -604,7 +612,7 @@ impl<'a> Parser<'a> {
)
.emit();
- self.parse_pat_ident(BindingMode::ByRef(Mutability::Mut))
+ self.parse_pat_ident(BindingAnnotation::REF_MUT)
}
/// Turn all by-value immutable bindings in a pattern into mutable bindings.
@@ -613,7 +621,8 @@ impl<'a> Parser<'a> {
struct AddMut(bool);
impl MutVisitor for AddMut {
fn visit_pat(&mut self, pat: &mut P<Pat>) {
- if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind
+ if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) =
+ &mut pat.kind
{
self.0 = true;
*m = Mutability::Mut;
@@ -665,7 +674,7 @@ impl<'a> Parser<'a> {
fn parse_pat_mac_invoc(&mut self, path: Path) -> PResult<'a, PatKind> {
self.bump();
let args = self.parse_mac_args()?;
- let mac = MacCall { path, args, prior_type_ascription: self.last_type_ascription };
+ let mac = P(MacCall { path, args, prior_type_ascription: self.last_type_ascription });
Ok(PatKind::MacCall(mac))
}
@@ -807,7 +816,7 @@ impl<'a> Parser<'a> {
(None, self.parse_path(PathStyle::Expr)?)
};
let hi = self.prev_token.span;
- Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), AttrVec::new()))
+ Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path)))
} else {
self.parse_literal_maybe_minus()
}
@@ -838,7 +847,7 @@ impl<'a> Parser<'a> {
/// Parses `ident` or `ident @ pat`.
/// Used by the copy foo and ref foo patterns to give a good
/// error message when parsing mistakes like `ref foo(a, b)`.
- fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind> {
+ fn parse_pat_ident(&mut self, binding_annotation: BindingAnnotation) -> PResult<'a, PatKind> {
let ident = self.parse_ident()?;
let sub = if self.eat(&token::At) {
Some(self.parse_pat_no_top_alt(Some("binding pattern"))?)
@@ -856,7 +865,7 @@ impl<'a> Parser<'a> {
.struct_span_err(self.prev_token.span, "expected identifier, found enum pattern"));
}
- Ok(PatKind::Ident(binding_mode, ident, sub))
+ Ok(PatKind::Ident(binding_annotation, ident, sub))
}
/// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
@@ -936,11 +945,7 @@ impl<'a> Parser<'a> {
None
};
- Ok(PatKind::Ident(
- BindingMode::ByValue(Mutability::Not),
- Ident::new(kw::Box, box_span),
- sub,
- ))
+ Ok(PatKind::Ident(BindingAnnotation::NONE, Ident::new(kw::Box, box_span), sub))
} else {
let pat = self.parse_pat_with_range_pat(false, None)?;
self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span));
@@ -1093,7 +1098,7 @@ impl<'a> Parser<'a> {
.emit();
}
- fn parse_pat_field(&mut self, lo: Span, attrs: Vec<Attribute>) -> PResult<'a, PatField> {
+ fn parse_pat_field(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, PatField> {
// Check if a colon exists one ahead. This means we're parsing a fieldname.
let hi;
let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
@@ -1117,14 +1122,12 @@ impl<'a> Parser<'a> {
let fieldname = self.parse_field_name()?;
hi = self.prev_token.span;
- let bind_type = match (is_ref, is_mut) {
- (true, true) => BindingMode::ByRef(Mutability::Mut),
- (true, false) => BindingMode::ByRef(Mutability::Not),
- (false, true) => BindingMode::ByValue(Mutability::Mut),
- (false, false) => BindingMode::ByValue(Mutability::Not),
+ let mutability = match is_mut {
+ false => Mutability::Not,
+ true => Mutability::Mut,
};
-
- let fieldpat = self.mk_pat_ident(boxed_span.to(hi), bind_type, fieldname);
+ let ann = BindingAnnotation(ByRef::from(is_ref), mutability);
+ let fieldpat = self.mk_pat_ident(boxed_span.to(hi), ann, fieldname);
let subpat =
if is_box { self.mk_pat(lo.to(hi), PatKind::Box(fieldpat)) } else { fieldpat };
(subpat, fieldname, true)
@@ -1134,15 +1137,15 @@ impl<'a> Parser<'a> {
ident: fieldname,
pat: subpat,
is_shorthand,
- attrs: attrs.into(),
+ attrs,
id: ast::DUMMY_NODE_ID,
span: lo.to(hi),
is_placeholder: false,
})
}
- pub(super) fn mk_pat_ident(&self, span: Span, bm: BindingMode, ident: Ident) -> P<Pat> {
- self.mk_pat(span, PatKind::Ident(bm, ident, None))
+ pub(super) fn mk_pat_ident(&self, span: Span, ann: BindingAnnotation, ident: Ident) -> P<Pat> {
+ self.mk_pat(span, PatKind::Ident(ann, ident, None))
}
pub(super) fn mk_pat(&self, span: Span, kind: PatKind) -> P<Pat> {
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 5cf1758c3..fdc1af27f 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -13,7 +13,6 @@ use rustc_span::source_map::{BytePos, Span};
use rustc_span::symbol::{kw, sym, Ident};
use std::mem;
-use tracing::debug;
/// Specifies how to parse a path.
#[derive(Copy, Clone, PartialEq)]
@@ -527,7 +526,7 @@ impl<'a> Parser<'a> {
Ok(ident_gen_args) => ident_gen_args,
Err(()) => return Ok(Some(AngleBracketedArg::Arg(arg))),
};
- if binder.is_some() {
+ if binder {
// FIXME(compiler-errors): this could be improved by suggesting lifting
// this up to the trait, at least before this becomes real syntax.
// e.g. `Trait<for<'a> Assoc = Ty>` -> `for<'a> Trait<Assoc = Ty>`
@@ -652,12 +651,7 @@ impl<'a> Parser<'a> {
pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> {
// Parse const argument.
let value = if let token::OpenDelim(Delimiter::Brace) = self.token.kind {
- self.parse_block_expr(
- None,
- self.token.span,
- BlockCheckMode::Default,
- ast::AttrVec::new(),
- )?
+ self.parse_block_expr(None, self.token.span, BlockCheckMode::Default)?
} else {
self.handle_unambiguous_unbraced_const_arg()?
};
@@ -725,28 +719,24 @@ impl<'a> Parser<'a> {
/// Given a arg inside of generics, we try to destructure it as if it were the LHS in
/// `LHS = ...`, i.e. an associated type binding.
- /// This returns (optionally, if they are present) any `for<'a, 'b>` binder args, the
+ /// This returns a bool indicating if there are any `for<'a, 'b>` binder args, the
/// identifier, and any GAT arguments.
fn get_ident_from_generic_arg(
&self,
gen_arg: &GenericArg,
- ) -> Result<(Option<Vec<ast::GenericParam>>, Ident, Option<GenericArgs>), ()> {
+ ) -> Result<(bool, Ident, Option<GenericArgs>), ()> {
if let GenericArg::Type(ty) = gen_arg {
if let ast::TyKind::Path(qself, path) = &ty.kind
&& qself.is_none()
&& let [seg] = path.segments.as_slice()
{
- return Ok((None, seg.ident, seg.args.as_deref().cloned()));
+ return Ok((false, seg.ident, seg.args.as_deref().cloned()));
} else if let ast::TyKind::TraitObject(bounds, ast::TraitObjectSyntax::None) = &ty.kind
&& let [ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)] =
bounds.as_slice()
&& let [seg] = trait_ref.trait_ref.path.segments.as_slice()
{
- return Ok((
- Some(trait_ref.bound_generic_params.clone()),
- seg.ident,
- seg.args.as_deref().cloned(),
- ));
+ return Ok((true, seg.ident, seg.args.as_deref().cloned()));
}
}
Err(())
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 51bd9d2d3..3d957406b 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -1,5 +1,7 @@
use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN;
-use super::diagnostics::{AttemptLocalParseRecovery, Error};
+use super::diagnostics::{
+ AttemptLocalParseRecovery, Error, InvalidVariableDeclaration, InvalidVariableDeclarationSub,
+};
use super::expr::LhsExpr;
use super::pat::RecoverComma;
use super::path::PathStyle;
@@ -34,7 +36,7 @@ impl<'a> Parser<'a> {
}))
}
- /// If `force_capture` is true, forces collection of tokens regardless of whether
+ /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of whether
/// or not we have attributes
pub(crate) fn parse_stmt_without_recovery(
&mut self,
@@ -55,18 +57,25 @@ impl<'a> Parser<'a> {
return Ok(Some(stmt.into_inner()));
}
+ if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) {
+ self.bump();
+ let mut_let_span = lo.to(self.token.span);
+ self.sess.emit_err(InvalidVariableDeclaration {
+ span: mut_let_span,
+ sub: InvalidVariableDeclarationSub::SwitchMutLetOrder(mut_let_span),
+ });
+ }
+
Ok(Some(if self.token.is_keyword(kw::Let) {
self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
} else if self.is_kw_followed_by_ident(kw::Mut) {
- self.recover_stmt_local(lo, attrs, "missing keyword", "let mut")?
+ self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::MissingLet)?
} else if self.is_kw_followed_by_ident(kw::Auto) {
self.bump(); // `auto`
- let msg = "write `let` instead of `auto` to introduce a new variable";
- self.recover_stmt_local(lo, attrs, msg, "let")?
+ self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotAuto)?
} else if self.is_kw_followed_by_ident(sym::var) {
self.bump(); // `var`
- let msg = "write `let` instead of `var` to introduce a new variable";
- self.recover_stmt_local(lo, attrs, msg, "let")?
+ self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotVar)?
} else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
// We have avoided contextual keywords like `union`, items with `crate` visibility,
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
@@ -121,7 +130,7 @@ impl<'a> Parser<'a> {
let path = this.parse_path(PathStyle::Expr)?;
if this.eat(&token::Not) {
- let stmt_mac = this.parse_stmt_mac(lo, attrs.into(), path)?;
+ let stmt_mac = this.parse_stmt_mac(lo, attrs, path)?;
if this.token == token::Semi {
return Ok((stmt_mac, TrailingToken::Semi));
} else {
@@ -130,10 +139,10 @@ impl<'a> Parser<'a> {
}
let expr = if this.eat(&token::OpenDelim(Delimiter::Brace)) {
- this.parse_struct_expr(None, path, AttrVec::new(), true)?
+ this.parse_struct_expr(None, path, true)?
} else {
let hi = this.prev_token.span;
- this.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
+ this.mk_expr(lo.to(hi), ExprKind::Path(None, path))
};
let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
@@ -168,7 +177,7 @@ impl<'a> Parser<'a> {
None => unreachable!(),
};
- let mac = MacCall { path, args, prior_type_ascription: self.last_type_ascription };
+ let mac = P(MacCall { path, args, prior_type_ascription: self.last_type_ascription });
let kind = if (style == MacStmtStyle::Braces
&& self.token != token::Dot
@@ -179,9 +188,9 @@ impl<'a> Parser<'a> {
StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None }))
} else {
// Since none of the above applied, this is an expression statement macro.
- let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new());
+ let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
let e = self.maybe_recover_from_bad_qpath(e)?;
- let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
+ let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
StmtKind::Expr(e)
};
@@ -204,13 +213,10 @@ impl<'a> Parser<'a> {
&mut self,
lo: Span,
attrs: AttrWrapper,
- msg: &str,
- sugg: &str,
+ subdiagnostic: fn(Span) -> InvalidVariableDeclarationSub,
) -> PResult<'a, Stmt> {
let stmt = self.recover_local_after_let(lo, attrs)?;
- self.struct_span_err(lo, "invalid variable declaration")
- .span_suggestion(lo, msg, sugg, Applicability::MachineApplicable)
- .emit();
+ self.sess.emit_err(InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
Ok(stmt)
}
@@ -223,7 +229,7 @@ impl<'a> Parser<'a> {
) -> PResult<'a, Stmt> {
self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
this.expect_keyword(kw::Let)?;
- let local = this.parse_local(attrs.into())?;
+ let local = this.parse_local(attrs)?;
let trailing = if capture_semi && this.token.kind == token::Semi {
TrailingToken::Semi
} else {
@@ -235,7 +241,7 @@ impl<'a> Parser<'a> {
fn recover_local_after_let(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> {
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
- let local = this.parse_local(attrs.into())?;
+ let local = this.parse_local(attrs)?;
// FIXME - maybe capture semicolon in recovery?
Ok((
this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)),
@@ -247,6 +253,22 @@ impl<'a> Parser<'a> {
/// Parses a local variable declaration.
fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
let lo = self.prev_token.span;
+
+ if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) {
+ self.struct_span_err(
+ lo.to(self.token.span),
+ "`const` and `let` are mutually exclusive",
+ )
+ .span_suggestion(
+ lo.to(self.token.span),
+ "remove `let`",
+ "const",
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ self.bump();
+ }
+
let (pat, colon) = self.parse_pat_before_ty(None, RecoverComma::Yes, "`let` bindings")?;
let (err, ty) = if colon {
@@ -487,9 +509,7 @@ impl<'a> Parser<'a> {
}
/// Parses a block. Inner attributes are allowed.
- pub(super) fn parse_inner_attrs_and_block(
- &mut self,
- ) -> PResult<'a, (Vec<Attribute>, P<Block>)> {
+ pub(super) fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (AttrVec, P<Block>)> {
self.parse_block_common(self.token.span, BlockCheckMode::Default)
}
@@ -498,8 +518,8 @@ impl<'a> Parser<'a> {
&mut self,
lo: Span,
blk_mode: BlockCheckMode,
- ) -> PResult<'a, (Vec<Attribute>, P<Block>)> {
- maybe_whole!(self, NtBlock, |x| (Vec::new(), x));
+ ) -> PResult<'a, (AttrVec, P<Block>)> {
+ maybe_whole!(self, NtBlock, |x| (AttrVec::new(), x));
self.maybe_recover_unexpected_block_label();
if !self.eat(&token::OpenDelim(Delimiter::Brace)) {
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 31b40a83e..b47f0c097 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -567,7 +567,8 @@ impl<'a> Parser<'a> {
self.check_keyword(kw::Dyn)
&& (!self.token.uninterpolated_span().rust_2015()
|| self.look_ahead(1, |t| {
- t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t)
+ (t.can_begin_bound() || t.kind == TokenKind::BinOp(token::Star))
+ && !can_continue_type_after_non_fn_ident(t)
}))
}
@@ -576,10 +577,18 @@ impl<'a> Parser<'a> {
/// Note that this does *not* parse bare trait objects.
fn parse_dyn_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
self.bump(); // `dyn`
+
+ // parse dyn* types
+ let syntax = if self.eat(&TokenKind::BinOp(token::Star)) {
+ TraitObjectSyntax::DynStar
+ } else {
+ TraitObjectSyntax::Dyn
+ };
+
// Always parse bounds greedily for better error recovery.
let bounds = self.parse_generic_bounds(None)?;
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
- Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn))
+ Ok(TyKind::TraitObject(bounds, syntax))
}
/// Parses a type starting with a path.
@@ -598,11 +607,11 @@ impl<'a> Parser<'a> {
let path = self.parse_path_inner(PathStyle::Type, ty_generics)?;
if self.eat(&token::Not) {
// Macro invocation in type position
- Ok(TyKind::MacCall(MacCall {
+ Ok(TyKind::MacCall(P(MacCall {
path,
args: self.parse_mac_args()?,
prior_type_ascription: self.last_type_ascription,
- }))
+ })))
} else if allow_plus == AllowPlus::Yes && self.check_plus() {
// `Trait1 + Trait2 + 'a`
self.parse_remaining_bounds_path(Vec::new(), path, lo, true)
@@ -640,7 +649,13 @@ impl<'a> Parser<'a> {
let mut bounds = Vec::new();
let mut negative_bounds = Vec::new();
- while self.can_begin_bound() || self.token.is_keyword(kw::Dyn) {
+ while self.can_begin_bound()
+ // Continue even if we find a keyword.
+ // This is necessary for error recover on, for example, `impl fn()`.
+ //
+ // The only keyword that can go after generic bounds is `where`, so stop if it's it.
+ || (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where))
+ {
if self.token.is_keyword(kw::Dyn) {
// Account for `&dyn Trait + dyn Other`.
self.struct_span_err(self.token.span, "invalid `dyn` keyword")
@@ -804,6 +819,20 @@ impl<'a> Parser<'a> {
let span = tilde.to(self.prev_token.span);
self.sess.gated_spans.gate(sym::const_trait_impl, span);
Some(span)
+ } else if self.eat_keyword(kw::Const) {
+ let span = self.prev_token.span;
+ self.sess.gated_spans.gate(sym::const_trait_impl, span);
+
+ self.struct_span_err(span, "const bounds must start with `~`")
+ .span_suggestion(
+ span.shrink_to_lo(),
+ "add `~`",
+ "~",
+ Applicability::MachineApplicable,
+ )
+ .emit();
+
+ Some(span)
} else {
None
};
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 4890fade5..a9e502016 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -9,6 +9,8 @@
html_playground_url = "https://play.rust-lang.org/",
test(attr(deny(warnings)))
)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
// We want to be able to build this crate with a stable compiler, so no
// `#![feature]` attributes should be added.
@@ -165,6 +167,8 @@ pub enum Count<'a> {
CountIsName(&'a str, InnerSpan),
/// The count is specified by the argument at the given index.
CountIsParam(usize),
+ /// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index.
+ CountIsStar(usize),
/// The count is implied and cannot be explicitly specified.
CountImplied,
}
@@ -262,9 +266,7 @@ impl<'a> Iterator for Parser<'a> {
}
} else {
if self.is_literal {
- let start = self.to_span_index(self.cur_line_start);
- let end = self.to_span_index(self.input.len());
- let span = start.to(end);
+ let span = self.span(self.cur_line_start, self.input.len());
if self.line_spans.last() != Some(&span) {
self.line_spans.push(span);
}
@@ -382,6 +384,12 @@ impl<'a> Parser<'a> {
InnerOffset(raw + pos + 1)
}
+ fn span(&self, start_pos: usize, end_pos: usize) -> InnerSpan {
+ let start = self.to_span_index(start_pos);
+ let end = self.to_span_index(end_pos);
+ start.to(end)
+ }
+
/// Forces consumption of the specified character. If the character is not
/// found, an error is emitted.
fn must_consume(&mut self, c: char) -> Option<usize> {
@@ -470,9 +478,7 @@ impl<'a> Parser<'a> {
return &self.input[start..pos];
}
'\n' if self.is_literal => {
- let start = self.to_span_index(self.cur_line_start);
- let end = self.to_span_index(pos);
- self.line_spans.push(start.to(end));
+ self.line_spans.push(self.span(self.cur_line_start, pos));
self.cur_line_start = pos + 1;
self.cur.next();
}
@@ -535,6 +541,10 @@ impl<'a> Parser<'a> {
}
}
+ fn current_pos(&mut self) -> usize {
+ if let Some(&(pos, _)) = self.cur.peek() { pos } else { self.input.len() }
+ }
+
/// Parses a format specifier at the current position, returning all of the
/// relevant information in the `FormatSpec` struct.
fn format(&mut self) -> FormatSpec<'a> {
@@ -588,39 +598,37 @@ impl<'a> Parser<'a> {
// no '0' flag and '0$' as the width instead.
if let Some(end) = self.consume_pos('$') {
spec.width = CountIsParam(0);
-
- if let Some((pos, _)) = self.cur.peek().cloned() {
- spec.width_span = Some(self.to_span_index(pos - 2).to(self.to_span_index(pos)));
- }
+ spec.width_span = Some(self.span(end - 1, end + 1));
havewidth = true;
- spec.width_span = Some(self.to_span_index(end - 1).to(self.to_span_index(end + 1)));
} else {
spec.flags |= 1 << (FlagSignAwareZeroPad as u32);
}
}
+
if !havewidth {
- let width_span_start = if let Some((pos, _)) = self.cur.peek() { *pos } else { 0 };
- let (w, sp) = self.count(width_span_start);
- spec.width = w;
- spec.width_span = sp;
+ let start = self.current_pos();
+ spec.width = self.count(start);
+ if spec.width != CountImplied {
+ let end = self.current_pos();
+ spec.width_span = Some(self.span(start, end));
+ }
}
if let Some(start) = self.consume_pos('.') {
- if let Some(end) = self.consume_pos('*') {
+ if self.consume('*') {
// Resolve `CountIsNextParam`.
// We can do this immediately as `position` is resolved later.
let i = self.curarg;
self.curarg += 1;
- spec.precision = CountIsParam(i);
- spec.precision_span =
- Some(self.to_span_index(start).to(self.to_span_index(end + 1)));
+ spec.precision = CountIsStar(i);
} else {
- let (p, sp) = self.count(start);
- spec.precision = p;
- spec.precision_span = sp;
+ spec.precision = self.count(start + 1);
}
+ let end = self.current_pos();
+ spec.precision_span = Some(self.span(start, end));
}
- let ty_span_start = self.cur.peek().map(|(pos, _)| *pos);
+
+ let ty_span_start = self.current_pos();
// Optional radix followed by the actual format specifier
if self.consume('x') {
if self.consume('?') {
@@ -640,11 +648,9 @@ impl<'a> Parser<'a> {
spec.ty = "?";
} else {
spec.ty = self.word();
- let ty_span_end = self.cur.peek().map(|(pos, _)| *pos);
if !spec.ty.is_empty() {
- spec.ty_span = ty_span_start
- .and_then(|s| ty_span_end.map(|e| (s, e)))
- .map(|(start, end)| self.to_span_index(start).to(self.to_span_index(end)));
+ let ty_span_end = self.current_pos();
+ spec.ty_span = Some(self.span(ty_span_start, ty_span_end));
}
}
spec
@@ -668,13 +674,11 @@ impl<'a> Parser<'a> {
return spec;
}
- let ty_span_start = self.cur.peek().map(|(pos, _)| *pos);
+ let ty_span_start = self.current_pos();
spec.ty = self.word();
- let ty_span_end = self.cur.peek().map(|(pos, _)| *pos);
if !spec.ty.is_empty() {
- spec.ty_span = ty_span_start
- .and_then(|s| ty_span_end.map(|e| (s, e)))
- .map(|(start, end)| self.to_span_index(start).to(self.to_span_index(end)));
+ let ty_span_end = self.current_pos();
+ spec.ty_span = Some(self.span(ty_span_start, ty_span_end));
}
spec
@@ -683,26 +687,21 @@ impl<'a> Parser<'a> {
/// Parses a `Count` parameter at the current position. This does not check
/// for 'CountIsNextParam' because that is only used in precision, not
/// width.
- fn count(&mut self, start: usize) -> (Count<'a>, Option<InnerSpan>) {
+ fn count(&mut self, start: usize) -> Count<'a> {
if let Some(i) = self.integer() {
- if let Some(end) = self.consume_pos('$') {
- let span = self.to_span_index(start).to(self.to_span_index(end + 1));
- (CountIsParam(i), Some(span))
- } else {
- (CountIs(i), None)
- }
+ if self.consume('$') { CountIsParam(i) } else { CountIs(i) }
} else {
let tmp = self.cur.clone();
let word = self.word();
if word.is_empty() {
self.cur = tmp;
- (CountImplied, None)
+ CountImplied
} else if let Some(end) = self.consume_pos('$') {
- let span = self.to_span_index(start + 1).to(self.to_span_index(end));
- (CountIsName(word, span), None)
+ let name_span = self.span(start, end);
+ CountIsName(word, name_span)
} else {
self.cur = tmp;
- (CountImplied, None)
+ CountImplied
}
}
}
@@ -735,7 +734,7 @@ impl<'a> Parser<'a> {
"invalid argument name `_`",
"invalid argument name",
"argument name cannot be a single underscore",
- self.to_span_index(start).to(self.to_span_index(end)),
+ self.span(start, end),
);
}
word
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index 578530696..2f8c229c6 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -1,5 +1,6 @@
use super::*;
+#[track_caller]
fn same(fmt: &'static str, p: &[Piece<'static>]) {
let parser = Parser::new(fmt, None, None, false, ParseMode::Format);
assert_eq!(parser.collect::<Vec<Piece<'static>>>(), p);
@@ -190,9 +191,9 @@ fn format_counts() {
align: AlignUnknown,
flags: 0,
precision: CountImplied,
- width: CountIs(10),
precision_span: None,
- width_span: None,
+ width: CountIs(10),
+ width_span: Some(InnerSpan { start: 3, end: 5 }),
ty: "x",
ty_span: None,
},
@@ -208,9 +209,9 @@ fn format_counts() {
align: AlignUnknown,
flags: 0,
precision: CountIs(10),
+ precision_span: Some(InnerSpan { start: 6, end: 9 }),
width: CountIsParam(10),
- precision_span: None,
- width_span: Some(InnerSpan::new(3, 6)),
+ width_span: Some(InnerSpan { start: 3, end: 6 }),
ty: "x",
ty_span: None,
},
@@ -226,9 +227,9 @@ fn format_counts() {
align: AlignUnknown,
flags: 0,
precision: CountIs(10),
+ precision_span: Some(InnerSpan { start: 6, end: 9 }),
width: CountIsParam(0),
- precision_span: None,
- width_span: Some(InnerSpan::new(4, 6)),
+ width_span: Some(InnerSpan { start: 4, end: 6 }),
ty: "x",
ty_span: None,
},
@@ -243,9 +244,9 @@ fn format_counts() {
fill: None,
align: AlignUnknown,
flags: 0,
- precision: CountIsParam(0),
+ precision: CountIsStar(0),
+ precision_span: Some(InnerSpan { start: 3, end: 5 }),
width: CountImplied,
- precision_span: Some(InnerSpan::new(3, 5)),
width_span: None,
ty: "x",
ty_span: None,
@@ -279,15 +280,33 @@ fn format_counts() {
fill: None,
align: AlignUnknown,
flags: 0,
- precision: CountIsName("b", InnerSpan::new(6, 7)),
- width: CountIsName("a", InnerSpan::new(4, 4)),
- precision_span: None,
- width_span: None,
+ precision: CountIsName("b", InnerSpan { start: 6, end: 7 }),
+ precision_span: Some(InnerSpan { start: 5, end: 8 }),
+ width: CountIsName("a", InnerSpan { start: 3, end: 4 }),
+ width_span: Some(InnerSpan { start: 3, end: 5 }),
ty: "?",
ty_span: None,
},
})],
);
+ same(
+ "{:.4}",
+ &[NextArgument(Argument {
+ position: ArgumentImplicitlyIs(0),
+ position_span: InnerSpan { start: 2, end: 2 },
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountIs(4),
+ precision_span: Some(InnerSpan { start: 3, end: 5 }),
+ width: CountImplied,
+ width_span: None,
+ ty: "",
+ ty_span: None,
+ },
+ })],
+ )
}
#[test]
fn format_flags() {