diff options
Diffstat (limited to 'compiler/rustc_parse')
| -rw-r--r-- | compiler/rustc_parse/src/lexer/mod.rs | 63 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/lexer/unescape_error_reporting.rs | 22 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 1 |
3 files changed, 75 insertions, 11 deletions
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index b1c0dedd3c7..51e90489002 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,3 +1,5 @@ +use std::ops::Range; + use crate::errors; use crate::lexer::unicode_chars::UNICODE_ARRAY; use crate::make_unclosed_delims_error; @@ -6,7 +8,7 @@ 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, Diagnostic, DiagnosticBuilder, StashKey}; -use rustc_lexer::unescape::{self, Mode}; +use rustc_lexer::unescape::{self, EscapeError, Mode}; use rustc_lexer::Cursor; use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_session::lint::builtin::{ @@ -204,6 +206,9 @@ impl<'a> StringReader<'a> { rustc_lexer::TokenKind::Literal { kind, suffix_start } => { let suffix_start = start + BytePos(suffix_start); let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind); + if let token::LitKind::CStr | token::LitKind::CStrRaw(_) = kind { + self.sess.gated_spans.gate(sym::c_str_literals, self.mk_sp(start, self.pos)); + } let suffix = if suffix_start < self.pos { let string = self.str_from(suffix_start); if string == "_" { @@ -415,6 +420,16 @@ impl<'a> StringReader<'a> { } self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" " } + rustc_lexer::LiteralKind::CStr { terminated } => { + if !terminated { + self.sess.span_diagnostic.span_fatal_with_code( + self.mk_sp(start + BytePos(1), end), + "unterminated C string", + error_code!(E0767), + ) + } + self.cook_c_string(token::CStr, Mode::CStr, start, end, 2, 1) // c" " + } rustc_lexer::LiteralKind::RawStr { n_hashes } => { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); @@ -433,6 +448,15 @@ impl<'a> StringReader<'a> { self.report_raw_str_error(start, 2); } } + rustc_lexer::LiteralKind::RawCStr { n_hashes } => { + if let Some(n_hashes) = n_hashes { + let n = u32::from(n_hashes); + let kind = token::CStrRaw(n_hashes); + self.cook_c_string(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) // cr##" "## + } else { + self.report_raw_str_error(start, 2); + } + } rustc_lexer::LiteralKind::Int { base, empty_int } => { if empty_int { let span = self.mk_sp(start, end); @@ -648,7 +672,7 @@ impl<'a> StringReader<'a> { self.sess.emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num }); } - fn cook_quoted( + fn cook_common( &self, kind: token::LitKind, mode: Mode, @@ -656,12 +680,13 @@ impl<'a> StringReader<'a> { end: BytePos, prefix_len: u32, postfix_len: u32, + unescape: fn(&str, Mode, &mut dyn FnMut(Range<usize>, Result<(), EscapeError>)), ) -> (token::LitKind, Symbol) { let mut has_fatal_err = false; let content_start = start + BytePos(prefix_len); let content_end = end - BytePos(postfix_len); let lit_content = self.str_from_to(content_start, content_end); - unescape::unescape_literal(lit_content, mode, &mut |range, result| { + unescape(lit_content, mode, &mut |range, result| { // Here we only check for errors. The actual unescaping is done later. if let Err(err) = result { let span_with_quotes = self.mk_sp(start, end); @@ -692,6 +717,38 @@ impl<'a> StringReader<'a> { (token::Err, self.symbol_from_to(start, end)) } } + + fn cook_quoted( + &self, + kind: token::LitKind, + mode: Mode, + start: BytePos, + end: BytePos, + prefix_len: u32, + postfix_len: u32, + ) -> (token::LitKind, Symbol) { + self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { + unescape::unescape_literal(src, mode, &mut |span, result| { + callback(span, result.map(drop)) + }) + }) + } + + fn cook_c_string( + &self, + kind: token::LitKind, + mode: Mode, + start: BytePos, + end: BytePos, + prefix_len: u32, + postfix_len: u32, + ) -> (token::LitKind, Symbol) { + self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { + unescape::unescape_c_string(src, mode, &mut |span, result| { + callback(span, result.map(drop)) + }) + }) + } } pub fn nfc_normalize(string: &str) -> Symbol { diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index d8bcf816fb2..eb9625f923a 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -78,8 +78,7 @@ pub(crate) fn emit_unescape_error( } }; let sugg = sugg.unwrap_or_else(|| { - let is_byte = mode.is_byte(); - let prefix = if is_byte { "b" } else { "" }; + let prefix = mode.prefix_noraw(); let mut escaped = String::with_capacity(lit.len()); let mut chrs = lit.chars().peekable(); while let Some(first) = chrs.next() { @@ -97,7 +96,11 @@ pub(crate) fn emit_unescape_error( }; } let sugg = format!("{prefix}\"{escaped}\""); - MoreThanOneCharSugg::Quotes { span: span_with_quotes, is_byte, sugg } + MoreThanOneCharSugg::Quotes { + span: span_with_quotes, + is_byte: mode == Mode::Byte, + sugg, + } }); handler.emit_err(UnescapeError::MoreThanOneChar { span: span_with_quotes, @@ -112,7 +115,7 @@ pub(crate) fn emit_unescape_error( char_span, escaped_sugg: c.escape_default().to_string(), escaped_msg: escaped_char(c), - byte: mode.is_byte(), + byte: mode == Mode::Byte, }); } EscapeError::BareCarriageReturn => { @@ -126,12 +129,15 @@ pub(crate) fn emit_unescape_error( EscapeError::InvalidEscape => { let (c, span) = last_char(); - let label = - if mode.is_byte() { "unknown byte escape" } else { "unknown character escape" }; + let label = if mode == Mode::Byte || mode == Mode::ByteStr { + "unknown byte escape" + } else { + "unknown character escape" + }; let ec = escaped_char(c); let mut diag = handler.struct_span_err(span, format!("{}: `{}`", label, ec)); diag.span_label(span, label); - if c == '{' || c == '}' && !mode.is_byte() { + if c == '{' || c == '}' && matches!(mode, Mode::Str | Mode::RawStr) { diag.help( "if used in a formatting string, curly braces are escaped with `{{` and `}}`", ); @@ -141,7 +147,7 @@ pub(crate) fn emit_unescape_error( version control settings", ); } else { - if !mode.is_byte() { + if mode == Mode::Str || mode == Mode::Char { diag.span_suggestion( span_with_quotes, "if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal", diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index f58f8919e5c..61396ee0d4a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1870,6 +1870,7 @@ impl<'a> Parser<'a> { let recovered = self.recover_after_dot(); let token = recovered.as_ref().unwrap_or(&self.token); let span = token.span; + token::Lit::from_token(token).map(|token_lit| { self.bump(); (token_lit, span) |
