parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
+
+parse_unexpected_token_after_dot = unexpected token: `{$actual}`
+
+parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier
+
+parse_cr_doc_comment = bare CR not allowed in {$block ->
+ [true] block doc-comment
+ *[false] doc-comment
+}
+
+parse_no_digits_literal = no valid digits found for number
+
+parse_invalid_digit_literal = invalid digit for a base {$base} literal
+
+parse_empty_exponent_float = expected at least one digit in exponent
+
+parse_float_literal_unsupported_base = {$base} float literal is not supported
+
+parse_more_than_one_char = character literal may only contain one codepoint
+ .followed_by = this `{$chr}` is followed by the combining {$len ->
+ [one] mark
+ *[other] marks
+ } `{$escaped_marks}`
+ .non_printing = there are non-printing characters, the full sequence is `{$escaped}`
+ .consider_normalized = consider using the normalized form `{$ch}` of this character
+ .remove_non = consider removing the non-printing characters
+ .use_double_quotes = if you meant to write a {$is_byte ->
+ [true] byte string
+ *[false] `str`
+ } literal, use double quotes
+
+parse_no_brace_unicode_escape = incorrect unicode escape sequence
+ .label = {parse_no_brace_unicode_escape}
+ .use_braces = format of unicode escape sequences uses braces
+ .format_of_unicode = format of unicode escape sequences is `\u{"{...}"}`
+
+parse_invalid_unicode_escape = invalid unicode character escape
+ .label = invalid escape
+ .help = unicode escape must {$surrogate ->
+ [true] not be a surrogate
+ *[false] be at most 10FFFF
+ }
+
+parse_escape_only_char = {$byte ->
+ [true] byte
+ *[false] character
+ } constant must be escaped: `{$escaped_msg}`
+ .escape = escape the character
+
+parse_bare_cr = {$double_quotes ->
+ [true] bare CR not allowed in string, use `\r` instead
+ *[false] character constant must be escaped: `\r`
+ }
+ .escape = escape the character
+
+parse_bare_cr_in_raw_string = bare CR not allowed in raw string
+
+parse_too_short_hex_escape = numeric character escape is too short
+
+parse_invalid_char_in_escape = {parse_invalid_char_in_escape_msg}: `{$ch}`
+ .label = {parse_invalid_char_in_escape_msg}
+
+parse_invalid_char_in_escape_msg = invalid character in {$is_hex ->
+ [true] numeric character
+ *[false] unicode
+ } escape
+
+parse_out_of_range_hex_escape = out of range hex escape
+ .label = must be a character in the range [\x00-\x7f]
+
+parse_leading_underscore_unicode_escape = {parse_leading_underscore_unicode_escape_label}: `_`
+parse_leading_underscore_unicode_escape_label = invalid start of unicode escape
+
+parse_overlong_unicode_escape = overlong unicode escape
+ .label = must have at most 6 hex digits
+
+parse_unclosed_unicode_escape = unterminated unicode escape
+ .label = missing a closing `{"}"}`
+ .terminate = terminate the unicode escape
+
+parse_unicode_escape_in_byte = unicode escape in byte string
+ .label = {parse_unicode_escape_in_byte}
+ .help = unicode escape sequences cannot be used as a byte or in a byte string
+
+parse_empty_unicode_escape = empty unicode escape
+ .label = this escape must have at least 1 hex digit
+
+parse_zero_chars = empty character literal
+ .label = {parse_zero_chars}
+
+parse_lone_slash = invalid trailing slash in literal
+ .label = {parse_lone_slash}
+
+parse_unskipped_whitespace = non-ASCII whitespace symbol '{$ch}' is not skipped
+ .label = {parse_unskipped_whitespace}
+
+parse_multiple_skipped_lines = multiple lines skipped by escaped newline
+ .label = skipping everything up to and including this point
+
+parse_unknown_prefix = prefix `{$prefix}` is unknown
+ .label = unknown prefix
+ .note = prefixed identifiers and literals are reserved since Rust 2021
+ .suggestion_br = use `br` for a raw byte string
+ .suggestion_whitespace = consider inserting whitespace here
+
+parse_too_many_hashes = too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found {$num}
+
+parse_unknown_start_of_token = unknown start of token: {$escaped}
+ .sugg_quotes = Unicode characters '“' (Left Double Quotation Mark) and '”' (Right Double Quotation Mark) look like '{$ascii_str}' ({$ascii_name}), but are not
+ .sugg_other = Unicode character '{$ch}' ({$u_name}) looks like '{$ascii_str}' ({$ascii_name}), but it is not
+ .help_null = source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
+ .note_repeats = character appears {$repeats ->
+ [one] once more
+ *[other] {$repeats} more times
+ }
pub span: Span,
}
+#[derive(Diagnostic)]
+#[diag(parse_unexpected_token_after_dot)]
+pub struct UnexpectedTokenAfterDot<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub actual: Cow<'a, str>,
+}
+
#[derive(Diagnostic)]
#[diag(parse_visibility_not_followed_by_item)]
#[help]
},
}
+#[derive(Diagnostic)]
+#[diag(parse_cannot_be_raw_ident)]
+pub struct CannotBeRawIdent {
+ #[primary_span]
+ pub span: Span,
+ pub ident: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_cr_doc_comment)]
+pub struct CrDocComment {
+ #[primary_span]
+ pub span: Span,
+ pub block: bool,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_no_digits_literal, code = "E0768")]
+pub struct NoDigitsLiteral {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_invalid_digit_literal)]
+pub struct InvalidDigitLiteral {
+ #[primary_span]
+ pub span: Span,
+ pub base: u32,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_empty_exponent_float)]
+pub struct EmptyExponentFloat {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_float_literal_unsupported_base)]
+pub struct FloatLiteralUnsupportedBase {
+ #[primary_span]
+ pub span: Span,
+ pub base: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_unknown_prefix)]
+#[note]
+pub struct UnknownPrefix<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub prefix: &'a str,
+ #[subdiagnostic]
+ pub sugg: Option<UnknownPrefixSugg>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum UnknownPrefixSugg {
+ #[suggestion(suggestion_br, code = "br", applicability = "maybe-incorrect", style = "verbose")]
+ UseBr(#[primary_span] Span),
+ #[suggestion(
+ suggestion_whitespace,
+ code = " ",
+ applicability = "maybe-incorrect",
+ style = "verbose"
+ )]
+ Whitespace(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_too_many_hashes)]
+pub struct TooManyHashes {
+ #[primary_span]
+ pub span: Span,
+ pub num: u32,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_unknown_start_of_token)]
+pub struct UnknownTokenStart {
+ #[primary_span]
+ pub span: Span,
+ pub escaped: String,
+ #[subdiagnostic]
+ pub sugg: Option<TokenSubstitution>,
+ #[subdiagnostic]
+ pub null: Option<UnknownTokenNull>,
+ #[subdiagnostic]
+ pub repeat: Option<UnknownTokenRepeat>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum TokenSubstitution {
+ #[suggestion(sugg_quotes, code = "{suggestion}", applicability = "maybe-incorrect")]
+ DirectedQuotes {
+ #[primary_span]
+ span: Span,
+ suggestion: String,
+ ascii_str: &'static str,
+ ascii_name: &'static str,
+ },
+ #[suggestion(sugg_other, code = "{suggestion}", applicability = "maybe-incorrect")]
+ Other {
+ #[primary_span]
+ span: Span,
+ suggestion: String,
+ ch: String,
+ u_name: &'static str,
+ ascii_str: &'static str,
+ ascii_name: &'static str,
+ },
+}
+
+#[derive(Subdiagnostic)]
+#[note(note_repeats)]
+pub struct UnknownTokenRepeat {
+ pub repeats: usize,
+}
+
+#[derive(Subdiagnostic)]
+#[help(help_null)]
+pub struct UnknownTokenNull;
+
+#[derive(Diagnostic)]
+pub enum UnescapeError {
+ #[diag(parse_invalid_unicode_escape)]
+ #[help]
+ InvalidUnicodeEscape {
+ #[primary_span]
+ #[label]
+ span: Span,
+ surrogate: bool,
+ },
+ #[diag(parse_escape_only_char)]
+ EscapeOnlyChar {
+ #[primary_span]
+ span: Span,
+ #[suggestion(escape, applicability = "machine-applicable", code = "{escaped_sugg}")]
+ char_span: Span,
+ escaped_sugg: String,
+ escaped_msg: String,
+ byte: bool,
+ },
+ #[diag(parse_bare_cr)]
+ BareCr {
+ #[primary_span]
+ #[suggestion(escape, applicability = "machine-applicable", code = "\\r")]
+ span: Span,
+ double_quotes: bool,
+ },
+ #[diag(parse_bare_cr_in_raw_string)]
+ BareCrRawString(#[primary_span] Span),
+ #[diag(parse_too_short_hex_escape)]
+ TooShortHexEscape(#[primary_span] Span),
+ #[diag(parse_invalid_char_in_escape)]
+ InvalidCharInEscape {
+ #[primary_span]
+ #[label]
+ span: Span,
+ is_hex: bool,
+ ch: String,
+ },
+ #[diag(parse_out_of_range_hex_escape)]
+ OutOfRangeHexEscape(
+ #[primary_span]
+ #[label]
+ Span,
+ ),
+ #[diag(parse_leading_underscore_unicode_escape)]
+ LeadingUnderscoreUnicodeEscape {
+ #[primary_span]
+ #[label(parse_leading_underscore_unicode_escape_label)]
+ span: Span,
+ ch: String,
+ },
+ #[diag(parse_overlong_unicode_escape)]
+ OverlongUnicodeEscape(
+ #[primary_span]
+ #[label]
+ Span,
+ ),
+ #[diag(parse_unclosed_unicode_escape)]
+ UnclosedUnicodeEscape(
+ #[primary_span]
+ #[label]
+ Span,
+ #[suggestion(terminate, code = "}}", applicability = "maybe-incorrect", style = "verbose")]
+ Span,
+ ),
+ #[diag(parse_no_brace_unicode_escape)]
+ NoBraceInUnicodeEscape {
+ #[primary_span]
+ span: Span,
+ #[label]
+ label: Option<Span>,
+ #[subdiagnostic]
+ sub: NoBraceUnicodeSub,
+ },
+ #[diag(parse_unicode_escape_in_byte)]
+ #[help]
+ UnicodeEscapeInByte(
+ #[primary_span]
+ #[label]
+ Span,
+ ),
+ #[diag(parse_empty_unicode_escape)]
+ EmptyUnicodeEscape(
+ #[primary_span]
+ #[label]
+ Span,
+ ),
+ #[diag(parse_zero_chars)]
+ ZeroChars(
+ #[primary_span]
+ #[label]
+ Span,
+ ),
+ #[diag(parse_lone_slash)]
+ LoneSlash(
+ #[primary_span]
+ #[label]
+ Span,
+ ),
+ #[diag(parse_unskipped_whitespace)]
+ UnskippedWhitespace {
+ #[primary_span]
+ span: Span,
+ #[label]
+ char_span: Span,
+ ch: String,
+ },
+ #[diag(parse_multiple_skipped_lines)]
+ MultipleSkippedLinesWarning(
+ #[primary_span]
+ #[label]
+ Span,
+ ),
+ #[diag(parse_more_than_one_char)]
+ MoreThanOneChar {
+ #[primary_span]
+ span: Span,
+ #[subdiagnostic]
+ note: Option<MoreThanOneCharNote>,
+ #[subdiagnostic]
+ suggestion: MoreThanOneCharSugg,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub enum MoreThanOneCharSugg {
+ #[suggestion(consider_normalized, code = "{normalized}", applicability = "machine-applicable")]
+ NormalizedForm {
+ #[primary_span]
+ span: Span,
+ ch: String,
+ normalized: String,
+ },
+ #[suggestion(remove_non, code = "{ch}", applicability = "maybe-incorrect")]
+ RemoveNonPrinting {
+ #[primary_span]
+ span: Span,
+ ch: String,
+ },
+ #[suggestion(use_double_quotes, code = "{sugg}", applicability = "machine-applicable")]
+ Quotes {
+ #[primary_span]
+ span: Span,
+ is_byte: bool,
+ sugg: String,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub enum MoreThanOneCharNote {
+ #[note(followed_by)]
+ AllCombining {
+ #[primary_span]
+ span: Span,
+ chr: String,
+ len: usize,
+ escaped_marks: String,
+ },
+ #[note(non_printing)]
+ NonPrinting {
+ #[primary_span]
+ span: Span,
+ escaped: String,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub enum NoBraceUnicodeSub {
+ #[suggestion(use_braces, code = "{suggestion}", applicability = "maybe-incorrect")]
+ Suggestion {
+ #[primary_span]
+ span: Span,
+ suggestion: String,
+ },
+ #[help(format_of_unicode)]
+ Help,
+}
+
#[derive(Subdiagnostic)]
pub(crate) enum TopLevelOrPatternNotAllowedSugg {
#[suggestion(
+use crate::errors;
use crate::lexer::unicode_chars::UNICODE_ARRAY;
use rustc_ast::ast::{self, AttrStyle};
use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::util::unicode::contains_text_flow_control_chars;
-use rustc_errors::{
- error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult, StashKey,
-};
+use rustc_errors::{error_code, Applicability, DiagnosticBuilder, PResult, StashKey};
use rustc_lexer::unescape::{self, Mode};
use rustc_lexer::Cursor;
use rustc_lexer::{Base, DocStyle, RawStrError};
let span = self.mk_sp(start, self.pos);
self.sess.symbol_gallery.insert(sym, span);
if !sym.can_be_raw() {
- self.err_span(span, &format!("`{}` cannot be a raw identifier", sym));
+ self.sess.emit_err(errors::CannotBeRawIdent { span, ident: sym });
}
self.sess.raw_identifier_spans.borrow_mut().push(span);
token::Ident(sym, true)
self.nbsp_is_whitespace = true;
}
let repeats = it.take_while(|c1| *c1 == c).count();
- let mut err =
- self.struct_err_span_char(start, self.pos + Pos::from_usize(repeats * c.len_utf8()), "unknown start of token", c);
// FIXME: the lexer could be used to turn the ASCII version of unicode
// homoglyphs, instead of keeping a table in `check_for_substitution`into the
// token. Ideally, this should be inside `rustc_lexer`. However, we should
// first remove compound tokens like `<<` from `rustc_lexer`, and then add
// fancier error recovery to it, as there will be less overall work to do this
// way.
- let token = unicode_chars::check_for_substitution(self, start, c, &mut err, repeats+1);
- if c == '\x00' {
- err.help("source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used");
- }
- if repeats > 0 {
- if repeats == 1 {
- err.note(format!("character appears once more"));
- } else {
- err.note(format!("character appears {repeats} more times"));
- }
- swallow_next_invalid = repeats;
- }
- err.emit();
+ let (token, sugg) = unicode_chars::check_for_substitution(self, start, c, repeats+1);
+ self.sess.emit_err(errors::UnknownTokenStart {
+ span: self.mk_sp(start, self.pos + Pos::from_usize(repeats * c.len_utf8())),
+ escaped: escaped_char(c),
+ sugg,
+ null: if c == '\x00' {Some(errors::UnknownTokenNull)} else {None},
+ repeat: if repeats > 0 {
+ swallow_next_invalid = repeats;
+ Some(errors::UnknownTokenRepeat { repeats })
+ } else {None}
+ });
+
if let Some(token) = token {
token
} else {
}
}
- /// Report a fatal lexical error with a given span.
- fn fatal_span(&self, sp: Span, m: &str) -> ! {
- self.sess.span_diagnostic.span_fatal(sp, m)
- }
-
- /// Report a lexical error with a given span.
- fn err_span(&self, sp: Span, m: &str) {
- self.sess.span_diagnostic.struct_span_err(sp, m).emit();
- }
-
- /// Report a fatal error spanning [`from_pos`, `to_pos`).
- fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> ! {
- self.fatal_span(self.mk_sp(from_pos, to_pos), m)
- }
-
- /// Report a lexical error spanning [`from_pos`, `to_pos`).
- fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) {
- self.err_span(self.mk_sp(from_pos, to_pos), m)
- }
-
fn struct_fatal_span_char(
&self,
from_pos: BytePos,
.struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
}
- fn struct_err_span_char(
- &self,
- from_pos: BytePos,
- to_pos: BytePos,
- m: &str,
- c: char,
- ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
- self.sess
- .span_diagnostic
- .struct_span_err(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
- }
-
/// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly
/// complain about it.
fn lint_unicode_text_flow(&self, start: BytePos) {
) -> TokenKind {
if content.contains('\r') {
for (idx, _) in content.char_indices().filter(|&(_, c)| c == '\r') {
- self.err_span_(
+ let span = self.mk_sp(
content_start + BytePos(idx as u32),
content_start + BytePos(idx as u32 + 1),
- match comment_kind {
- CommentKind::Line => "bare CR not allowed in doc-comment",
- CommentKind::Block => "bare CR not allowed in block doc-comment",
- },
);
+ let block = matches!(comment_kind, CommentKind::Block);
+ self.sess.emit_err(errors::CrDocComment { span, block });
}
}
}
rustc_lexer::LiteralKind::Int { base, empty_int } => {
if empty_int {
- self.sess
- .span_diagnostic
- .struct_span_err_with_code(
- self.mk_sp(start, end),
- "no valid digits found for number",
- error_code!(E0768),
- )
- .emit();
+ let span = self.mk_sp(start, end);
+ self.sess.emit_err(errors::NoDigitsLiteral { span });
(token::Integer, sym::integer(0))
} else {
if matches!(base, Base::Binary | Base::Octal) {
let base = base as u32;
let s = self.str_from_to(start + BytePos(2), end);
for (idx, c) in s.char_indices() {
+ let span = self.mk_sp(
+ start + BytePos::from_usize(2 + idx),
+ start + BytePos::from_usize(2 + idx + c.len_utf8()),
+ );
if c != '_' && c.to_digit(base).is_none() {
- self.err_span_(
- start + BytePos::from_usize(2 + idx),
- start + BytePos::from_usize(2 + idx + c.len_utf8()),
- &format!("invalid digit for a base {} literal", base),
- );
+ self.sess.emit_err(errors::InvalidDigitLiteral { span, base });
}
}
}
}
rustc_lexer::LiteralKind::Float { base, empty_exponent } => {
if empty_exponent {
- self.err_span_(start, self.pos, "expected at least one digit in exponent");
+ let span = self.mk_sp(start, self.pos);
+ self.sess.emit_err(errors::EmptyExponentFloat { span });
}
- match base {
- Base::Hexadecimal => {
- self.err_span_(start, end, "hexadecimal float literal is not supported")
- }
- Base::Octal => {
- self.err_span_(start, end, "octal float literal is not supported")
- }
- Base::Binary => {
- self.err_span_(start, end, "binary float literal is not supported")
- }
- _ => {}
+ let base = match base {
+ Base::Hexadecimal => Some("hexadecimal"),
+ Base::Octal => Some("octal"),
+ Base::Binary => Some("binary"),
+ _ => None,
+ };
+ if let Some(base) = base {
+ let span = self.mk_sp(start, end);
+ self.sess.emit_err(errors::FloatLiteralUnsupportedBase { span, base });
}
(token::Float, self.symbol_from_to(start, end))
}
// identifier tokens.
fn report_unknown_prefix(&self, start: BytePos) {
let prefix_span = self.mk_sp(start, self.pos);
- let prefix_str = self.str_from_to(start, self.pos);
- let msg = format!("prefix `{}` is unknown", prefix_str);
+ let prefix = self.str_from_to(start, self.pos);
let expn_data = prefix_span.ctxt().outer_expn_data();
if expn_data.edition >= Edition::Edition2021 {
// In Rust 2021, this is a hard error.
- let mut err = self.sess.span_diagnostic.struct_span_err(prefix_span, &msg);
- err.span_label(prefix_span, "unknown prefix");
- if prefix_str == "rb" {
- err.span_suggestion_verbose(
- prefix_span,
- "use `br` for a raw byte string",
- "br",
- Applicability::MaybeIncorrect,
- );
+ let sugg = if prefix == "rb" {
+ Some(errors::UnknownPrefixSugg::UseBr(prefix_span))
} else if expn_data.is_root() {
- err.span_suggestion_verbose(
- prefix_span.shrink_to_hi(),
- "consider inserting whitespace here",
- " ",
- Applicability::MaybeIncorrect,
- );
- }
- err.note("prefixed identifiers and literals are reserved since Rust 2021");
- err.emit();
+ Some(errors::UnknownPrefixSugg::Whitespace(prefix_span.shrink_to_hi()))
+ } else {
+ None
+ };
+ self.sess.emit_err(errors::UnknownPrefix { span: prefix_span, prefix, sugg });
} else {
// Before Rust 2021, only emit a lint for migration.
self.sess.buffer_lint_with_diagnostic(
&RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
prefix_span,
ast::CRATE_NODE_ID,
- &msg,
+ &format!("prefix `{prefix}` is unknown"),
BuiltinLintDiagnostics::ReservedPrefix(prefix_span),
);
}
}
- fn report_too_many_hashes(&self, start: BytePos, found: u32) -> ! {
- self.fatal_span_(
- start,
- self.pos,
- &format!(
- "too many `#` symbols: raw strings may be delimited \
- by up to 255 `#` symbols, but found {}",
- found
- ),
- )
+ fn report_too_many_hashes(&self, start: BytePos, num: u32) -> ! {
+ self.sess.emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num });
}
fn cook_quoted(
use std::iter::once;
use std::ops::Range;
-use rustc_errors::{pluralize, Applicability, Handler};
+use rustc_errors::{Applicability, Handler};
use rustc_lexer::unescape::{EscapeError, Mode};
use rustc_span::{BytePos, Span};
+use crate::errors::{MoreThanOneCharNote, MoreThanOneCharSugg, NoBraceUnicodeSub, UnescapeError};
+
pub(crate) fn emit_unescape_error(
handler: &Handler,
// interior part of the literal, without quotes
};
match error {
EscapeError::LoneSurrogateUnicodeEscape => {
- handler
- .struct_span_err(span, "invalid unicode character escape")
- .span_label(span, "invalid escape")
- .help("unicode escape must not be a surrogate")
- .emit();
+ handler.emit_err(UnescapeError::InvalidUnicodeEscape { span, surrogate: true });
}
EscapeError::OutOfRangeUnicodeEscape => {
- handler
- .struct_span_err(span, "invalid unicode character escape")
- .span_label(span, "invalid escape")
- .help("unicode escape must be at most 10FFFF")
- .emit();
+ handler.emit_err(UnescapeError::InvalidUnicodeEscape { span, surrogate: false });
}
EscapeError::MoreThanOneChar => {
use unicode_normalization::{char::is_combining_mark, UnicodeNormalization};
+ let mut sugg = None;
+ let mut note = None;
- let mut has_help = false;
- let mut handler = handler.struct_span_err(
- span_with_quotes,
- "character literal may only contain one codepoint",
- );
-
- if lit.chars().skip(1).all(|c| is_combining_mark(c)) {
- let escaped_marks =
- lit.chars().skip(1).map(|c| c.escape_default().to_string()).collect::<Vec<_>>();
- handler.span_note(
- span,
- &format!(
- "this `{}` is followed by the combining mark{} `{}`",
- lit.chars().next().unwrap(),
- pluralize!(escaped_marks.len()),
- escaped_marks.join(""),
- ),
- );
+ let lit_chars = lit.chars().collect::<Vec<_>>();
+ let (first, rest) = lit_chars.split_first().unwrap();
+ if rest.iter().copied().all(is_combining_mark) {
let normalized = lit.nfc().to_string();
if normalized.chars().count() == 1 {
- has_help = true;
- handler.span_suggestion(
- span,
- &format!(
- "consider using the normalized form `{}` of this character",
- normalized.chars().next().unwrap().escape_default()
- ),
- normalized,
- Applicability::MachineApplicable,
- );
+ let ch = normalized.chars().next().unwrap().escape_default().to_string();
+ sugg = Some(MoreThanOneCharSugg::NormalizedForm { span, ch, normalized });
}
+ let escaped_marks =
+ rest.iter().map(|c| c.escape_default().to_string()).collect::<Vec<_>>();
+ note = Some(MoreThanOneCharNote::AllCombining {
+ span,
+ chr: format!("{first}"),
+ len: escaped_marks.len(),
+ escaped_marks: escaped_marks.join(""),
+ });
} else {
let printable: Vec<char> = lit
.chars()
})
.collect();
- if let [ch] = printable.as_slice() {
- has_help = true;
-
- handler.span_note(
+ if let &[ch] = printable.as_slice() {
+ sugg =
+ Some(MoreThanOneCharSugg::RemoveNonPrinting { span, ch: ch.to_string() });
+ note = Some(MoreThanOneCharNote::NonPrinting {
span,
- &format!(
- "there are non-printing characters, the full sequence is `{}`",
- lit.escape_default(),
- ),
- );
-
- handler.span_suggestion(
- span,
- "consider removing the non-printing characters",
- ch,
- Applicability::MaybeIncorrect,
- );
+ escaped: lit.escape_default().to_string(),
+ });
}
- }
-
- if !has_help {
- let (prefix, msg) = if mode.is_byte() {
- ("b", "if you meant to write a byte string literal, use double quotes")
- } else {
- ("", "if you meant to write a `str` literal, use double quotes")
- };
+ };
+ let sugg = sugg.unwrap_or_else(|| {
+ let is_byte = mode.is_byte();
+ let prefix = if is_byte { "b" } else { "" };
let mut escaped = String::with_capacity(lit.len());
let mut chrs = lit.chars().peekable();
while let Some(first) = chrs.next() {
(c, _) => escaped.push(c),
};
}
- handler.span_suggestion(
- span_with_quotes,
- msg,
- format!("{prefix}\"{escaped}\""),
- Applicability::MachineApplicable,
- );
- }
-
- handler.emit();
+ let sugg = format!("{prefix}\"{escaped}\"");
+ MoreThanOneCharSugg::Quotes { span: span_with_quotes, is_byte, sugg }
+ });
+ handler.emit_err(UnescapeError::MoreThanOneChar {
+ span: span_with_quotes,
+ note,
+ suggestion: sugg,
+ });
}
EscapeError::EscapeOnlyChar => {
let (c, char_span) = last_char();
-
- let msg = if mode.is_byte() {
- "byte constant must be escaped"
- } else {
- "character constant must be escaped"
- };
- handler
- .struct_span_err(span, &format!("{}: `{}`", msg, escaped_char(c)))
- .span_suggestion(
- char_span,
- "escape the character",
- c.escape_default(),
- Applicability::MachineApplicable,
- )
- .emit();
+ handler.emit_err(UnescapeError::EscapeOnlyChar {
+ span,
+ char_span,
+ escaped_sugg: c.escape_default().to_string(),
+ escaped_msg: escaped_char(c),
+ byte: mode.is_byte(),
+ });
}
EscapeError::BareCarriageReturn => {
- let msg = if mode.in_double_quotes() {
- "bare CR not allowed in string, use `\\r` instead"
- } else {
- "character constant must be escaped: `\\r`"
- };
- handler
- .struct_span_err(span, msg)
- .span_suggestion(
- span,
- "escape the character",
- "\\r",
- Applicability::MachineApplicable,
- )
- .emit();
+ let double_quotes = mode.in_double_quotes();
+ handler.emit_err(UnescapeError::BareCr { span, double_quotes });
}
EscapeError::BareCarriageReturnInRawString => {
assert!(mode.in_double_quotes());
- let msg = "bare CR not allowed in raw string";
- handler.span_err(span, msg);
+ handler.emit_err(UnescapeError::BareCrRawString(span));
}
EscapeError::InvalidEscape => {
let (c, span) = last_char();
diag.emit();
}
EscapeError::TooShortHexEscape => {
- handler.span_err(span, "numeric character escape is too short");
+ handler.emit_err(UnescapeError::TooShortHexEscape(span));
}
EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => {
let (c, span) = last_char();
-
- let msg = if error == EscapeError::InvalidCharInHexEscape {
- "invalid character in numeric character escape"
- } else {
- "invalid character in unicode escape"
- };
- let c = escaped_char(c);
-
- handler
- .struct_span_err(span, &format!("{}: `{}`", msg, c))
- .span_label(span, msg)
- .emit();
+ let is_hex = error == EscapeError::InvalidCharInHexEscape;
+ let ch = escaped_char(c);
+ handler.emit_err(UnescapeError::InvalidCharInEscape { span, is_hex, ch });
}
EscapeError::NonAsciiCharInByte => {
let (c, span) = last_char();
err.emit();
}
EscapeError::OutOfRangeHexEscape => {
- handler
- .struct_span_err(span, "out of range hex escape")
- .span_label(span, "must be a character in the range [\\x00-\\x7f]")
- .emit();
+ handler.emit_err(UnescapeError::OutOfRangeHexEscape(span));
}
EscapeError::LeadingUnderscoreUnicodeEscape => {
let (c, span) = last_char();
- let msg = "invalid start of unicode escape";
- handler
- .struct_span_err(span, &format!("{}: `{}`", msg, c))
- .span_label(span, msg)
- .emit();
+ handler.emit_err(UnescapeError::LeadingUnderscoreUnicodeEscape {
+ span,
+ ch: escaped_char(c),
+ });
}
EscapeError::OverlongUnicodeEscape => {
- handler
- .struct_span_err(span, "overlong unicode escape")
- .span_label(span, "must have at most 6 hex digits")
- .emit();
+ handler.emit_err(UnescapeError::OverlongUnicodeEscape(span));
}
EscapeError::UnclosedUnicodeEscape => {
- handler
- .struct_span_err(span, "unterminated unicode escape")
- .span_label(span, "missing a closing `}`")
- .span_suggestion_verbose(
- span.shrink_to_hi(),
- "terminate the unicode escape",
- "}",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ handler.emit_err(UnescapeError::UnclosedUnicodeEscape(span, span.shrink_to_hi()));
}
EscapeError::NoBraceInUnicodeEscape => {
- let msg = "incorrect unicode escape sequence";
- let mut diag = handler.struct_span_err(span, msg);
-
let mut suggestion = "\\u{".to_owned();
let mut suggestion_len = 0;
let (c, char_span) = last_char();
suggestion_len += c.len_utf8();
}
- if suggestion_len > 0 {
+ let (label, sub) = if suggestion_len > 0 {
suggestion.push('}');
let hi = char_span.lo() + BytePos(suggestion_len as u32);
- diag.span_suggestion(
- span.with_hi(hi),
- "format of unicode escape sequences uses braces",
- suggestion,
- Applicability::MaybeIncorrect,
- );
+ (None, NoBraceUnicodeSub::Suggestion { span: span.with_hi(hi), suggestion })
} else {
- diag.span_label(span, msg);
- diag.help("format of unicode escape sequences is `\\u{...}`");
- }
-
- diag.emit();
+ (Some(span), NoBraceUnicodeSub::Help)
+ };
+ handler.emit_err(UnescapeError::NoBraceInUnicodeEscape { span, label, sub });
}
EscapeError::UnicodeEscapeInByte => {
- let msg = "unicode escape in byte string";
- handler
- .struct_span_err(span, msg)
- .span_label(span, msg)
- .help("unicode escape sequences cannot be used as a byte or in a byte string")
- .emit();
+ handler.emit_err(UnescapeError::UnicodeEscapeInByte(span));
}
EscapeError::EmptyUnicodeEscape => {
- handler
- .struct_span_err(span, "empty unicode escape")
- .span_label(span, "this escape must have at least 1 hex digit")
- .emit();
+ handler.emit_err(UnescapeError::EmptyUnicodeEscape(span));
}
EscapeError::ZeroChars => {
- let msg = "empty character literal";
- handler.struct_span_err(span, msg).span_label(span, msg).emit();
+ handler.emit_err(UnescapeError::ZeroChars(span));
}
EscapeError::LoneSlash => {
- let msg = "invalid trailing slash in literal";
- handler.struct_span_err(span, msg).span_label(span, msg).emit();
+ handler.emit_err(UnescapeError::LoneSlash(span));
}
EscapeError::UnskippedWhitespaceWarning => {
let (c, char_span) = last_char();
- let msg =
- format!("non-ASCII whitespace symbol '{}' is not skipped", c.escape_unicode());
- handler.struct_span_warn(span, &msg).span_label(char_span, &msg).emit();
+ handler.emit_warning(UnescapeError::UnskippedWhitespace {
+ span,
+ ch: escaped_char(c),
+ char_span,
+ });
}
EscapeError::MultipleSkippedLinesWarning => {
- let msg = "multiple lines skipped by escaped newline";
- let bottom_msg = "skipping everything up to and including this point";
- handler.struct_span_warn(span, msg).span_label(span, bottom_msg).emit();
+ handler.emit_warning(UnescapeError::MultipleSkippedLinesWarning(span));
}
}
}
//! <https://www.unicode.org/Public/security/10.0.0/confusables.txt>
use super::StringReader;
-use crate::token::{self, Delimiter};
-use rustc_errors::{Applicability, Diagnostic};
+use crate::{
+ errors::TokenSubstitution,
+ token::{self, Delimiter},
+};
use rustc_span::{symbol::kw, BytePos, Pos, Span};
#[rustfmt::skip] // for line breaks
reader: &StringReader<'a>,
pos: BytePos,
ch: char,
- err: &mut Diagnostic,
count: usize,
-) -> Option<token::TokenKind> {
- let &(_, u_name, ascii_str) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch)?;
+) -> (Option<token::TokenKind>, Option<TokenSubstitution>) {
+ let Some(&(_, u_name, ascii_str)) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch) else {
+ return (None, None);
+ };
let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8() * count));
let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else {
let msg = format!("substitution character not found for '{}'", ch);
reader.sess.span_diagnostic.span_bug_no_panic(span, &msg);
- return None;
+ return (None, None);
};
// special help suggestion for "directed" double quotes
- if let Some(s) = peek_delimited(&reader.src[reader.src_index(pos)..], '“', '”') {
- let msg = format!(
- "Unicode characters '“' (Left Double Quotation Mark) and \
- '”' (Right Double Quotation Mark) look like '{}' ({}), but are not",
- ascii_str, ascii_name
- );
- err.span_suggestion(
- Span::with_root_ctxt(
- pos,
- pos + Pos::from_usize('“'.len_utf8() + s.len() + '”'.len_utf8()),
- ),
- &msg,
- format!("\"{}\"", s),
- Applicability::MaybeIncorrect,
+ let sugg = if let Some(s) = peek_delimited(&reader.src[reader.src_index(pos)..], '“', '”') {
+ let span = Span::with_root_ctxt(
+ pos,
+ pos + Pos::from_usize('“'.len_utf8() + s.len() + '”'.len_utf8()),
);
+ Some(TokenSubstitution::DirectedQuotes {
+ span,
+ suggestion: format!("\"{s}\""),
+ ascii_str,
+ ascii_name,
+ })
} else {
- let msg = format!(
- "Unicode character '{}' ({}) looks like '{}' ({}), but it is not",
- ch, u_name, ascii_str, ascii_name
- );
- err.span_suggestion(
+ let suggestion = ascii_str.to_string().repeat(count);
+ Some(TokenSubstitution::Other {
span,
- &msg,
- ascii_str.to_string().repeat(count),
- Applicability::MaybeIncorrect,
- );
- }
- token.clone()
+ suggestion,
+ ch: ch.to_string(),
+ u_name,
+ ascii_str,
+ ascii_name,
+ })
+ };
+ (token.clone(), sugg)
}
/// Extract string if found at current position with given delimiters
AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken,
};
+
use crate::errors;
use crate::maybe_recover_from_interpolated_ty_qpath;
use core::mem;
fn error_unexpected_after_dot(&self) {
// FIXME Could factor this out into non_fatal_unexpected or something.
let actual = pprust::token_to_string(&self.token);
- self.struct_span_err(self.token.span, &format!("unexpected token: `{actual}`")).emit();
+ self.sess.emit_err(errors::UnexpectedTokenAfterDot { span: self.token.span, actual });
}
// We need an identifier or integer, but the next token is a float.
-use crate::errors::{
- AmbiguousMissingKwForItemSub, AssociatedStaticItemNotAllowed, AsyncFnIn2015,
- BoundsNotAllowedOnTraitAliases, ConstGlobalCannotBeMutable, ConstLetMutuallyExclusive,
- DefaultNotFollowedByItem, DocCommentDoesNotDocumentAnything, EnumStructMutuallyExclusive,
- ExpectedTraitInTraitImplFoundType, ExternCrateNameWithDashes, ExternCrateNameWithDashesSugg,
- ExternItemCannotBeConst, HelpUseLatestEdition, MissingConstType, MissingForInTraitImpl,
- MissingKeywordForItemDefinition, MissingTraitInTraitImpl, SelfArgumentPointer,
- TraitAliasCannotBeAuto, TraitAliasCannotBeUnsafe, UnexpectedTokenAfterStructName,
- UseEmptyBlockNotSemi, VisibilityNotFollowedByItem,
-};
+use crate::errors;
use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
-use crate::errors::FnTypoWithImpl;
use rustc_ast::ast::*;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, TokenKind};
// At this point, we have failed to parse an item.
if !matches!(vis.kind, VisibilityKind::Inherited) {
- self.sess.emit_err(VisibilityNotFollowedByItem { span: vis.span, vis });
+ self.sess.emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis });
}
if let Defaultness::Default(span) = def {
- self.sess.emit_err(DefaultNotFollowedByItem { span });
+ self.sess.emit_err(errors::DefaultNotFollowedByItem { span });
}
if !attrs_allowed {
let err = if self.check(&token::OpenDelim(Delimiter::Brace)) {
// possible public struct definition where `struct` was forgotten
- Some(MissingKeywordForItemDefinition::Struct { span: sp, ident })
+ Some(errors::MissingKeywordForItemDefinition::Struct { span: sp, ident })
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
// possible public function or tuple struct definition where `fn`/`struct` was
// forgotten
self.consume_block(Delimiter::Parenthesis, ConsumeClosingDelim::Yes);
- let err = if self.check(&token::RArrow)
- || self.check(&token::OpenDelim(Delimiter::Brace))
- {
- self.eat_to_tokens(&[&token::OpenDelim(Delimiter::Brace)]);
- self.bump(); // `{`
- self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
- if is_method {
- MissingKeywordForItemDefinition::Method { span: sp, ident }
- } else {
- MissingKeywordForItemDefinition::Function { span: sp, ident }
- }
- } else if self.check(&token::Semi) {
- MissingKeywordForItemDefinition::Struct { span: sp, ident }
- } else {
- MissingKeywordForItemDefinition::Ambiguous {
- span: sp,
- subdiag: if found_generics {
- None
- } else if let Ok(snippet) = self.span_to_snippet(ident_sp) {
- Some(AmbiguousMissingKwForItemSub::SuggestMacro { span: full_sp, snippet })
+ let err =
+ if self.check(&token::RArrow) || self.check(&token::OpenDelim(Delimiter::Brace)) {
+ self.eat_to_tokens(&[&token::OpenDelim(Delimiter::Brace)]);
+ self.bump(); // `{`
+ self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
+ if is_method {
+ errors::MissingKeywordForItemDefinition::Method { span: sp, ident }
} else {
- Some(AmbiguousMissingKwForItemSub::HelpMacro)
- },
- }
- };
+ errors::MissingKeywordForItemDefinition::Function { span: sp, ident }
+ }
+ } else if self.check(&token::Semi) {
+ errors::MissingKeywordForItemDefinition::Struct { span: sp, ident }
+ } else {
+ errors::MissingKeywordForItemDefinition::Ambiguous {
+ span: sp,
+ subdiag: if found_generics {
+ None
+ } else if let Ok(snippet) = self.span_to_snippet(ident_sp) {
+ Some(errors::AmbiguousMissingKwForItemSub::SuggestMacro {
+ span: full_sp,
+ snippet,
+ })
+ } else {
+ Some(errors::AmbiguousMissingKwForItemSub::HelpMacro)
+ },
+ }
+ };
Some(err)
} else if found_generics {
- Some(MissingKeywordForItemDefinition::Ambiguous { span: sp, subdiag: None })
+ Some(errors::MissingKeywordForItemDefinition::Ambiguous { span: sp, subdiag: None })
} else {
None
};
let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt)
{
let span = self.prev_token.span.between(self.token.span);
- self.sess
- .emit_err(MissingTraitInTraitImpl { span, for_span: span.to(self.token.span) });
+ self.sess.emit_err(errors::MissingTraitInTraitImpl {
+ span,
+ for_span: span.to(self.token.span),
+ });
P(Ty {
kind: TyKind::Path(None, err_path(span)),
Some(ty_second) => {
// impl Trait for Type
if !has_for {
- self.sess.emit_err(MissingForInTraitImpl { span: missing_for_span });
+ self.sess.emit_err(errors::MissingForInTraitImpl { span: missing_for_span });
}
let ty_first = ty_first.into_inner();
// This notably includes paths passed through `ty` macro fragments (#46438).
TyKind::Path(None, path) => path,
_ => {
- self.sess
- .emit_err(ExpectedTraitInTraitImplFoundType { span: ty_first.span });
+ self.sess.emit_err(errors::ExpectedTraitInTraitImplFoundType {
+ span: ty_first.span,
+ });
err_path(ty_first.span)
}
};
// Recover `impl Ty;` instead of `impl Ty {}`
if self.token == TokenKind::Semi {
- self.sess.emit_err(UseEmptyBlockNotSemi { span: self.token.span });
+ self.sess.emit_err(errors::UseEmptyBlockNotSemi { span: self.token.span });
self.bump();
return Ok(vec![]);
}
// It's a trait alias.
if had_colon {
let span = span_at_colon.to(span_before_eq);
- self.sess.emit_err(BoundsNotAllowedOnTraitAliases { span });
+ self.sess.emit_err(errors::BoundsNotAllowedOnTraitAliases { span });
}
let bounds = self.parse_generic_bounds(None)?;
let whole_span = lo.to(self.prev_token.span);
if is_auto == IsAuto::Yes {
- self.sess.emit_err(TraitAliasCannotBeAuto { span: whole_span });
+ self.sess.emit_err(errors::TraitAliasCannotBeAuto { span: whole_span });
}
if let Unsafe::Yes(_) = unsafety {
- self.sess.emit_err(TraitAliasCannotBeUnsafe { span: whole_span });
+ self.sess.emit_err(errors::TraitAliasCannotBeUnsafe { span: whole_span });
}
self.sess.gated_spans.gate(sym::trait_alias, whole_span);
Ok(kind) => kind,
Err(kind) => match kind {
ItemKind::Static(a, _, b) => {
- self.sess.emit_err(AssociatedStaticItemNotAllowed { span });
+ self.sess.emit_err(errors::AssociatedStaticItemNotAllowed { span });
AssocItemKind::Const(Defaultness::Final, a, b)
}
_ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"),
write!(fixed_name, "_{}", part.name).unwrap();
}
- self.sess.emit_err(ExternCrateNameWithDashes {
+ self.sess.emit_err(errors::ExternCrateNameWithDashes {
span: fixed_name_sp,
- sugg: ExternCrateNameWithDashesSugg { dashes },
+ sugg: errors::ExternCrateNameWithDashesSugg { dashes },
});
Ok(Ident::from_str_and_span(&fixed_name, fixed_name_sp))
Ok(kind) => kind,
Err(kind) => match kind {
ItemKind::Const(_, a, b) => {
- self.sess.emit_err(ExternItemCannotBeConst {
+ self.sess.emit_err(errors::ExternItemCannotBeConst {
ident_span: ident.span,
const_span: span.with_hi(ident.span.lo()),
});
fn recover_const_mut(&mut self, const_span: Span) {
if self.eat_keyword(kw::Mut) {
let span = self.prev_token.span;
- self.sess.emit_err(ConstGlobalCannotBeMutable { ident_span: span, const_span });
+ self.sess.emit_err(errors::ConstGlobalCannotBeMutable { ident_span: span, const_span });
} else if self.eat_keyword(kw::Let) {
let span = self.prev_token.span;
- self.sess.emit_err(ConstLetMutuallyExclusive { span: const_span.to(span) });
+ self.sess.emit_err(errors::ConstLetMutuallyExclusive { span: const_span.to(span) });
}
}
let span = self.prev_token.span.shrink_to_hi();
let err: DiagnosticBuilder<'_, ErrorGuaranteed> =
- MissingConstType { span, colon, kind }.into_diagnostic(&self.sess.span_diagnostic);
+ errors::MissingConstType { span, colon, kind }
+ .into_diagnostic(&self.sess.span_diagnostic);
err.stash(span, StashKey::ItemNoType);
// The user intended that the type be inferred,
fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> {
if self.token.is_keyword(kw::Struct) {
let span = self.prev_token.span.to(self.token.span);
- let err = EnumStructMutuallyExclusive { span };
+ let err = errors::EnumStructMutuallyExclusive { span };
if self.look_ahead(1, |t| t.is_ident()) {
self.bump();
self.sess.emit_err(err);
// Possibly recover `enum Foo;` instead of `enum Foo {}`
let (variants, _) = if self.token == TokenKind::Semi {
- self.sess.emit_err(UseEmptyBlockNotSemi { span: self.token.span });
+ self.sess.emit_err(errors::UseEmptyBlockNotSemi { span: self.token.span });
self.bump();
(vec![], false)
} else {
self.expect_semi()?;
body
} else {
- let err = UnexpectedTokenAfterStructName::new(self.token.span, self.token.clone());
+ let err =
+ errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token.clone());
return Err(err.into_diagnostic(&self.sess.span_diagnostic));
};
token::CloseDelim(Delimiter::Brace) => {}
token::DocComment(..) => {
let previous_span = self.prev_token.span;
- let mut err = DocCommentDoesNotDocumentAnything {
+ let mut err = errors::DocCommentDoesNotDocumentAnything {
span: self.token.span,
missing_comma: None,
};
// If we see `for Ty ...` then user probably meant `impl` item.
if self.token.is_keyword(kw::For) {
old_err.cancel();
- return Err(self.sess.create_err(FnTypoWithImpl { fn_span }));
+ return Err(self.sess.create_err(errors::FnTypoWithImpl { fn_span }));
} else {
return Err(old_err);
}
if let Async::Yes { span, .. } = asyncness {
if span.is_rust_2015() {
- self.sess.emit_err(AsyncFnIn2015 { span, help: HelpUseLatestEdition::new() });
+ self.sess.emit_err(errors::AsyncFnIn2015 {
+ span,
+ help: errors::HelpUseLatestEdition::new(),
+ });
}
}
};
// Recover for the grammar `*self`, `*const self`, and `*mut self`.
let recover_self_ptr = |this: &mut Self| {
- self.sess.emit_err(SelfArgumentPointer { span: this.token.span });
+ self.sess.emit_err(errors::SelfArgumentPointer { span: this.token.span });
Ok((SelfKind::Value(Mutability::Not), expect_self_ident(this), this.prev_token.span))
};
--- /dev/null
+// ignore-tidy-linelength
+
+fn main() {
+ let s: &str = r################################################################################################################################################################################################################################################################"very raw"################################################################################################################################################################################################################################################################;
+ //~^ ERROR too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found 256
+}
--- /dev/null
+error: too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found 256
+ --> $DIR/too-many-hash.rs:4:19
+ |
+LL | ... = r################################################################################################################################################################################################################################################################"very raw"##############################################################################################################################################################################################################################################################...
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+