1 //! Utilities for rendering escape sequence errors as diagnostics.
6 use rustc_errors::{Applicability, Handler};
7 use rustc_lexer::unescape::{EscapeError, Mode};
8 use rustc_span::{BytePos, Span};
10 pub(crate) fn emit_unescape_error(
12 // interior part of the literal, without quotes
14 // full span of the literal, including quotes
15 span_with_quotes: Span,
17 // range of the error inside `lit`
22 "emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}",
30 let Range { start, end } = range;
31 let (start, end) = (start as u32, end as u32);
32 let lo = span_with_quotes.lo() + BytePos(start + 1);
33 let hi = lo + BytePos(end - start);
34 span_with_quotes.with_lo(lo).with_hi(hi)
37 let c = lit[range.clone()].chars().rev().next().unwrap();
38 let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32));
42 EscapeError::LoneSurrogateUnicodeEscape => {
44 .struct_span_err(span, "invalid unicode character escape")
45 .help("unicode escape must not be a surrogate")
48 EscapeError::OutOfRangeUnicodeEscape => {
50 .struct_span_err(span, "invalid unicode character escape")
51 .help("unicode escape must be at most 10FFFF")
54 EscapeError::MoreThanOneChar => {
55 let msg = if mode.is_bytes() {
56 "if you meant to write a byte string literal, use double quotes"
58 "if you meant to write a `str` literal, use double quotes"
64 "character literal may only contain one codepoint",
69 format!("\"{}\"", lit),
70 Applicability::MachineApplicable,
74 EscapeError::EscapeOnlyChar => {
75 let (c, _span) = last_char();
77 let mut msg = if mode.is_bytes() {
78 "byte constant must be escaped: "
80 "character constant must be escaped: "
83 push_escaped_char(&mut msg, c);
85 handler.span_err(span, msg.as_str())
87 EscapeError::BareCarriageReturn => {
88 let msg = if mode.in_double_quotes() {
89 "bare CR not allowed in string, use \\r instead"
91 "character constant must be escaped: \\r"
93 handler.span_err(span, msg);
95 EscapeError::BareCarriageReturnInRawString => {
96 assert!(mode.in_double_quotes());
97 let msg = "bare CR not allowed in raw string";
98 handler.span_err(span, msg);
100 EscapeError::InvalidEscape => {
101 let (c, span) = last_char();
104 if mode.is_bytes() { "unknown byte escape" } else { "unknown character escape" };
105 let mut msg = label.to_string();
107 push_escaped_char(&mut msg, c);
109 let mut diag = handler.struct_span_err(span, msg.as_str());
110 diag.span_label(span, label);
111 if c == '{' || c == '}' && !mode.is_bytes() {
113 "if used in a formatting string, \
114 curly braces are escaped with `{{` and `}}`",
116 } else if c == '\r' {
118 "this is an isolated carriage return; \
119 consider checking your editor and version control settings",
124 EscapeError::TooShortHexEscape => {
125 handler.span_err(span, "numeric character escape is too short")
127 EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => {
128 let (c, span) = last_char();
130 let mut msg = if error == EscapeError::InvalidCharInHexEscape {
131 "invalid character in numeric character escape: "
133 "invalid character in unicode escape: "
136 push_escaped_char(&mut msg, c);
138 handler.span_err(span, msg.as_str())
140 EscapeError::NonAsciiCharInByte => {
141 assert!(mode.is_bytes());
142 let (_c, span) = last_char();
145 "byte constant must be ASCII. \
146 Use a \\xHH escape for a non-ASCII byte",
149 EscapeError::NonAsciiCharInByteString => {
150 assert!(mode.is_bytes());
151 let (_c, span) = last_char();
152 handler.span_err(span, "raw byte string must be ASCII")
154 EscapeError::OutOfRangeHexEscape => handler.span_err(
156 "this form of character escape may only be used \
157 with characters in the range [\\x00-\\x7f]",
159 EscapeError::LeadingUnderscoreUnicodeEscape => {
160 let (_c, span) = last_char();
161 handler.span_err(span, "invalid start of unicode escape")
163 EscapeError::OverlongUnicodeEscape => {
164 handler.span_err(span, "overlong unicode escape (must have at most 6 hex digits)")
166 EscapeError::UnclosedUnicodeEscape => {
167 handler.span_err(span, "unterminated unicode escape (needed a `}`)")
169 EscapeError::NoBraceInUnicodeEscape => {
170 let msg = "incorrect unicode escape sequence";
171 let mut diag = handler.struct_span_err(span, msg);
173 let mut suggestion = "\\u{".to_owned();
174 let mut suggestion_len = 0;
175 let (c, char_span) = last_char();
176 let chars = once(c).chain(lit[range.end..].chars());
177 for c in chars.take(6).take_while(|c| c.is_digit(16)) {
179 suggestion_len += c.len_utf8();
182 if suggestion_len > 0 {
183 suggestion.push('}');
184 let lo = char_span.lo();
185 let hi = lo + BytePos(suggestion_len as u32);
186 diag.span_suggestion(
187 span.with_lo(lo).with_hi(hi),
188 "format of unicode escape sequences uses braces",
190 Applicability::MaybeIncorrect,
193 diag.span_label(span, msg);
194 diag.help("format of unicode escape sequences is `\\u{...}`");
199 EscapeError::UnicodeEscapeInByte => handler.span_err(
201 "unicode escape sequences cannot be used \
202 as a byte or in a byte string",
204 EscapeError::EmptyUnicodeEscape => {
205 handler.span_err(span, "empty unicode escape (must have at least 1 hex digit)")
207 EscapeError::ZeroChars => handler.span_err(span, "empty character literal"),
208 EscapeError::LoneSlash => handler.span_err(span, "invalid trailing slash in literal"),
212 /// Pushes a character to a message string for error reporting
213 pub(crate) fn push_escaped_char(msg: &mut String, c: char) {
215 '\u{20}'..='\u{7e}' => {
216 // Don't escape \, ' or " for user-facing messages
220 msg.extend(c.escape_default());