1 //! Utilities for rendering escape sequence errors as diagnostics.
6 use syntax_pos::{Span, BytePos};
8 use crate::errors::{Handler, Applicability};
10 use super::unescape::{EscapeError, Mode};
12 pub(crate) fn emit_unescape_error(
14 // interior part of the literal, without quotes
16 // full span of the literal, including quotes
17 span_with_quotes: Span,
19 // range of the error inside `lit`
23 log::debug!("emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}",
24 lit, span_with_quotes, mode, range, error);
26 let Range { start, end } = range;
27 let (start, end) = (start as u32, end as u32);
28 let lo = span_with_quotes.lo() + BytePos(start + 1);
29 let hi = lo + BytePos(end - start);
35 let c = lit[range.clone()].chars().rev().next().unwrap();
36 let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32));
40 EscapeError::LoneSurrogateUnicodeEscape => {
41 handler.struct_span_err(span, "invalid unicode character escape")
42 .help("unicode escape must not be a surrogate")
45 EscapeError::OutOfRangeUnicodeEscape => {
46 handler.struct_span_err(span, "invalid unicode character escape")
47 .help("unicode escape must be at most 10FFFF")
50 EscapeError::MoreThanOneChar => {
54 "character literal may only contain one codepoint",
58 "if you meant to write a `str` literal, use double quotes",
59 format!("\"{}\"", lit),
60 Applicability::MachineApplicable,
63 EscapeError::EscapeOnlyChar => {
64 let (c, _span) = last_char();
66 let mut msg = if mode.is_bytes() {
67 "byte constant must be escaped: "
69 "character constant must be escaped: "
71 push_escaped_char(&mut msg, c);
73 handler.span_err(span, msg.as_str())
75 EscapeError::BareCarriageReturn => {
76 let msg = if mode.in_double_quotes() {
77 "bare CR not allowed in string, use \\r instead"
79 "character constant must be escaped: \\r"
81 handler.span_err(span, msg);
83 EscapeError::InvalidEscape => {
84 let (c, span) = last_char();
86 let label = if mode.is_bytes() {
89 "unknown character escape"
91 let mut msg = label.to_string();
93 push_escaped_char(&mut msg, c);
95 let mut diag = handler.struct_span_err(span, msg.as_str());
96 diag.span_label(span, label);
97 if c == '{' || c == '}' && !mode.is_bytes() {
98 diag.help("if used in a formatting string, \
99 curly braces are escaped with `{{` and `}}`");
100 } else if c == '\r' {
101 diag.help("this is an isolated carriage return; \
102 consider checking your editor and version control settings");
106 EscapeError::TooShortHexEscape => {
107 handler.span_err(span, "numeric character escape is too short")
109 EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => {
110 let (c, span) = last_char();
112 let mut msg = if error == EscapeError::InvalidCharInHexEscape {
113 "invalid character in numeric character escape: "
115 "invalid character in unicode escape: "
117 push_escaped_char(&mut msg, c);
119 handler.span_err(span, msg.as_str())
121 EscapeError::NonAsciiCharInByte => {
122 assert!(mode.is_bytes());
123 let (_c, span) = last_char();
124 handler.span_err(span, "byte constant must be ASCII. \
125 Use a \\xHH escape for a non-ASCII byte")
127 EscapeError::OutOfRangeHexEscape => {
128 handler.span_err(span, "this form of character escape may only be used \
129 with characters in the range [\\x00-\\x7f]")
131 EscapeError::LeadingUnderscoreUnicodeEscape => {
132 let (_c, span) = last_char();
133 handler.span_err(span, "invalid start of unicode escape")
135 EscapeError::OverlongUnicodeEscape => {
136 handler.span_err(span, "overlong unicode escape (must have at most 6 hex digits)")
138 EscapeError::UnclosedUnicodeEscape => {
139 handler.span_err(span, "unterminated unicode escape (needed a `}`)")
141 EscapeError::NoBraceInUnicodeEscape => {
142 let msg = "incorrect unicode escape sequence";
143 let mut diag = handler.struct_span_err(span, msg);
145 let mut suggestion = "\\u{".to_owned();
146 let mut suggestion_len = 0;
147 let (c, char_span) = last_char();
148 let chars = once(c).chain(lit[range.end..].chars());
149 for c in chars.take(6).take_while(|c| c.is_digit(16)) {
151 suggestion_len += c.len_utf8();
154 if suggestion_len > 0 {
155 suggestion.push('}');
156 let lo = char_span.lo();
157 let hi = lo + BytePos(suggestion_len as u32);
158 diag.span_suggestion(
159 span.with_lo(lo).with_hi(hi),
160 "format of unicode escape sequences uses braces",
162 Applicability::MaybeIncorrect,
165 diag.span_label(span, msg);
167 "format of unicode escape sequences is `\\u{...}`",
173 EscapeError::UnicodeEscapeInByte => {
174 handler.span_err(span, "unicode escape sequences cannot be used \
175 as a byte or in a byte string")
177 EscapeError::EmptyUnicodeEscape => {
178 handler.span_err(span, "empty unicode escape (must have at least 1 hex digit)")
180 EscapeError::ZeroChars => {
181 handler.span_err(span, "empty character literal")
183 EscapeError::LoneSlash => {
184 panic!("lexer accepted unterminated literal with trailing slash")
189 /// Pushes a character to a message string for error reporting
190 pub(crate) fn push_escaped_char(msg: &mut String, c: char) {
192 '\u{20}'..='\u{7e}' => {
193 // Don't escape \, ' or " for user-facing messages
197 msg.extend(c.escape_default());