1 //! Utilities for rendering escape sequence errors as diagnostics.
6 use rustc_lexer::unescape::{EscapeError, Mode};
7 use rustc_span::{BytePos, Span};
9 use syntax::errors::{Applicability, Handler};
11 pub(crate) fn emit_unescape_error(
13 // interior part of the literal, without quotes
15 // full span of the literal, including quotes
16 span_with_quotes: Span,
18 // range of the error inside `lit`
23 "emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}",
31 let Range { start, end } = range;
32 let (start, end) = (start as u32, end as u32);
33 let lo = span_with_quotes.lo() + BytePos(start + 1);
34 let hi = lo + BytePos(end - start);
35 span_with_quotes.with_lo(lo).with_hi(hi)
38 let c = lit[range.clone()].chars().rev().next().unwrap();
39 let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32));
43 EscapeError::LoneSurrogateUnicodeEscape => {
45 .struct_span_err(span, "invalid unicode character escape")
46 .help("unicode escape must not be a surrogate")
49 EscapeError::OutOfRangeUnicodeEscape => {
51 .struct_span_err(span, "invalid unicode character escape")
52 .help("unicode escape must be at most 10FFFF")
55 EscapeError::MoreThanOneChar => {
56 let msg = if mode.is_bytes() {
57 "if you meant to write a byte string literal, use double quotes"
59 "if you meant to write a `str` literal, use double quotes"
65 "character literal may only contain one codepoint",
70 format!("\"{}\"", lit),
71 Applicability::MachineApplicable,
75 EscapeError::EscapeOnlyChar => {
76 let (c, _span) = last_char();
78 let mut msg = if mode.is_bytes() {
79 "byte constant must be escaped: "
81 "character constant must be escaped: "
84 push_escaped_char(&mut msg, c);
86 handler.span_err(span, msg.as_str())
88 EscapeError::BareCarriageReturn => {
89 let msg = if mode.in_double_quotes() {
90 "bare CR not allowed in string, use \\r instead"
92 "character constant must be escaped: \\r"
94 handler.span_err(span, msg);
96 EscapeError::BareCarriageReturnInRawString => {
97 assert!(mode.in_double_quotes());
98 let msg = "bare CR not allowed in raw string";
99 handler.span_err(span, msg);
101 EscapeError::InvalidEscape => {
102 let (c, span) = last_char();
105 if mode.is_bytes() { "unknown byte escape" } else { "unknown character escape" };
106 let mut msg = label.to_string();
108 push_escaped_char(&mut msg, c);
110 let mut diag = handler.struct_span_err(span, msg.as_str());
111 diag.span_label(span, label);
112 if c == '{' || c == '}' && !mode.is_bytes() {
114 "if used in a formatting string, \
115 curly braces are escaped with `{{` and `}}`",
117 } else if c == '\r' {
119 "this is an isolated carriage return; \
120 consider checking your editor and version control settings",
125 EscapeError::TooShortHexEscape => {
126 handler.span_err(span, "numeric character escape is too short")
128 EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => {
129 let (c, span) = last_char();
131 let mut msg = if error == EscapeError::InvalidCharInHexEscape {
132 "invalid character in numeric character escape: "
134 "invalid character in unicode escape: "
137 push_escaped_char(&mut msg, c);
139 handler.span_err(span, msg.as_str())
141 EscapeError::NonAsciiCharInByte => {
142 assert!(mode.is_bytes());
143 let (_c, span) = last_char();
146 "byte constant must be ASCII. \
147 Use a \\xHH escape for a non-ASCII byte",
150 EscapeError::NonAsciiCharInByteString => {
151 assert!(mode.is_bytes());
152 let (_c, span) = last_char();
153 handler.span_err(span, "raw byte string must be ASCII")
155 EscapeError::OutOfRangeHexEscape => handler.span_err(
157 "this form of character escape may only be used \
158 with characters in the range [\\x00-\\x7f]",
160 EscapeError::LeadingUnderscoreUnicodeEscape => {
161 let (_c, span) = last_char();
162 handler.span_err(span, "invalid start of unicode escape")
164 EscapeError::OverlongUnicodeEscape => {
165 handler.span_err(span, "overlong unicode escape (must have at most 6 hex digits)")
167 EscapeError::UnclosedUnicodeEscape => {
168 handler.span_err(span, "unterminated unicode escape (needed a `}`)")
170 EscapeError::NoBraceInUnicodeEscape => {
171 let msg = "incorrect unicode escape sequence";
172 let mut diag = handler.struct_span_err(span, msg);
174 let mut suggestion = "\\u{".to_owned();
175 let mut suggestion_len = 0;
176 let (c, char_span) = last_char();
177 let chars = once(c).chain(lit[range.end..].chars());
178 for c in chars.take(6).take_while(|c| c.is_digit(16)) {
180 suggestion_len += c.len_utf8();
183 if suggestion_len > 0 {
184 suggestion.push('}');
185 let lo = char_span.lo();
186 let hi = lo + BytePos(suggestion_len as u32);
187 diag.span_suggestion(
188 span.with_lo(lo).with_hi(hi),
189 "format of unicode escape sequences uses braces",
191 Applicability::MaybeIncorrect,
194 diag.span_label(span, msg);
195 diag.help("format of unicode escape sequences is `\\u{...}`");
200 EscapeError::UnicodeEscapeInByte => handler.span_err(
202 "unicode escape sequences cannot be used \
203 as a byte or in a byte string",
205 EscapeError::EmptyUnicodeEscape => {
206 handler.span_err(span, "empty unicode escape (must have at least 1 hex digit)")
208 EscapeError::ZeroChars => handler.span_err(span, "empty character literal"),
209 EscapeError::LoneSlash => handler.span_err(span, "invalid trailing slash in literal"),
213 /// Pushes a character to a message string for error reporting
214 pub(crate) fn push_escaped_char(msg: &mut String, c: char) {
216 '\u{20}'..='\u{7e}' => {
217 // Don't escape \, ' or " for user-facing messages
221 msg.extend(c.escape_default());