summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_parse/src/lexer/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src/lexer/mod.rs')
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs77
1 files changed, 65 insertions, 12 deletions
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 9e856c9f2..c6e6b46e4 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::{
@@ -67,7 +69,7 @@ pub(crate) fn parse_token_trees<'a>(
match token_trees {
Ok(stream) if unmatched_delims.is_empty() => Ok(stream),
_ => {
- // Return error if there are unmatched delimiters or unclosng delimiters.
+ // Return error if there are unmatched delimiters or unclosed delimiters.
// We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch
// because the delimiter mismatch is more likely to be the root cause of error
@@ -204,16 +206,15 @@ 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 == "_" {
self.sess
.span_diagnostic
- .struct_span_err(
- self.mk_sp(suffix_start, self.pos),
- "underscore literal suffix is not allowed",
- )
- .emit();
+ .emit_err(errors::UnderscoreLiteralSuffix { span: self.mk_sp(suffix_start, self.pos) });
None
} else {
Some(Symbol::intern(string))
@@ -325,7 +326,7 @@ impl<'a> StringReader<'a> {
) -> DiagnosticBuilder<'a, !> {
self.sess
.span_diagnostic
- .struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
+ .struct_span_fatal(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
@@ -419,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);
@@ -437,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);
@@ -546,7 +566,7 @@ impl<'a> StringReader<'a> {
err.span_label(self.mk_sp(start, start), "unterminated raw string");
if n_hashes > 0 {
- err.note(&format!(
+ err.note(format!(
"this raw string should be terminated with `\"{}`",
"#".repeat(n_hashes as usize)
));
@@ -642,7 +662,7 @@ impl<'a> StringReader<'a> {
&RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
prefix_span,
ast::CRATE_NODE_ID,
- &format!("prefix `{prefix}` is unknown"),
+ format!("prefix `{prefix}` is unknown"),
BuiltinLintDiagnostics::ReservedPrefix(prefix_span),
);
}
@@ -652,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,
@@ -660,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);
@@ -696,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 {