1 //! Utilities for rendering escape sequence errors as diagnostics.
6 use rustc_lexer::unescape::{EscapeError, Mode};
7 use syntax_pos::{Span, BytePos};
9 use crate::errors::{Handler, Applicability};
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`
22 log::debug!("emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}",
23 lit, span_with_quotes, mode, range, error);
25 let Range { start, end } = range;
26 let (start, end) = (start as u32, end as u32);
27 let lo = span_with_quotes.lo() + BytePos(start + 1);
28 let hi = lo + BytePos(end - start);
34 let c = lit[range.clone()].chars().rev().next().unwrap();
35 let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32));
39 EscapeError::LoneSurrogateUnicodeEscape => {
40 handler.struct_span_err(span, "invalid unicode character escape")
41 .help("unicode escape must not be a surrogate")
44 EscapeError::OutOfRangeUnicodeEscape => {
45 handler.struct_span_err(span, "invalid unicode character escape")
46 .help("unicode escape must be at most 10FFFF")
49 EscapeError::MoreThanOneChar => {
50 let msg = if mode.is_bytes() {
51 "if you meant to write a byte string literal, use double quotes"
53 "if you meant to write a `str` literal, use double quotes"
59 "character literal may only contain one codepoint",
64 format!("\"{}\"", lit),
65 Applicability::MachineApplicable,
68 EscapeError::EscapeOnlyChar => {
69 let (c, _span) = last_char();
71 let mut msg = if mode.is_bytes() {
72 "byte constant must be escaped: "
74 "character constant must be escaped: "
76 push_escaped_char(&mut msg, c);
78 handler.span_err(span, msg.as_str())
80 EscapeError::BareCarriageReturn => {
81 let msg = if mode.in_double_quotes() {
82 "bare CR not allowed in string, use \\r instead"
84 "character constant must be escaped: \\r"
86 handler.span_err(span, msg);
88 EscapeError::BareCarriageReturnInRawString => {
89 assert!(mode.in_double_quotes());
90 let msg = "bare CR not allowed in raw string";
91 handler.span_err(span, msg);
93 EscapeError::InvalidEscape => {
94 let (c, span) = last_char();
96 let label = if mode.is_bytes() {
99 "unknown character escape"
101 let mut msg = label.to_string();
103 push_escaped_char(&mut msg, c);
105 let mut diag = handler.struct_span_err(span, msg.as_str());
106 diag.span_label(span, label);
107 if c == '{' || c == '}' && !mode.is_bytes() {
108 diag.help("if used in a formatting string, \
109 curly braces are escaped with `{{` and `}}`");
110 } else if c == '\r' {
111 diag.help("this is an isolated carriage return; \
112 consider checking your editor and version control settings");
116 EscapeError::TooShortHexEscape => {
117 handler.span_err(span, "numeric character escape is too short")
119 EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => {
120 let (c, span) = last_char();
122 let mut msg = if error == EscapeError::InvalidCharInHexEscape {
123 "invalid character in numeric character escape: "
125 "invalid character in unicode escape: "
127 push_escaped_char(&mut msg, c);
129 handler.span_err(span, msg.as_str())
131 EscapeError::NonAsciiCharInByte => {
132 assert!(mode.is_bytes());
133 let (_c, span) = last_char();
134 handler.span_err(span, "byte constant must be ASCII. \
135 Use a \\xHH escape for a non-ASCII byte")
137 EscapeError::NonAsciiCharInByteString => {
138 assert!(mode.is_bytes());
139 let (_c, span) = last_char();
140 handler.span_err(span, "raw byte string must be ASCII")
142 EscapeError::OutOfRangeHexEscape => {
143 handler.span_err(span, "this form of character escape may only be used \
144 with characters in the range [\\x00-\\x7f]")
146 EscapeError::LeadingUnderscoreUnicodeEscape => {
147 let (_c, span) = last_char();
148 handler.span_err(span, "invalid start of unicode escape")
150 EscapeError::OverlongUnicodeEscape => {
151 handler.span_err(span, "overlong unicode escape (must have at most 6 hex digits)")
153 EscapeError::UnclosedUnicodeEscape => {
154 handler.span_err(span, "unterminated unicode escape (needed a `}`)")
156 EscapeError::NoBraceInUnicodeEscape => {
157 let msg = "incorrect unicode escape sequence";
158 let mut diag = handler.struct_span_err(span, msg);
160 let mut suggestion = "\\u{".to_owned();
161 let mut suggestion_len = 0;
162 let (c, char_span) = last_char();
163 let chars = once(c).chain(lit[range.end..].chars());
164 for c in chars.take(6).take_while(|c| c.is_digit(16)) {
166 suggestion_len += c.len_utf8();
169 if suggestion_len > 0 {
170 suggestion.push('}');
171 let lo = char_span.lo();
172 let hi = lo + BytePos(suggestion_len as u32);
173 diag.span_suggestion(
174 span.with_lo(lo).with_hi(hi),
175 "format of unicode escape sequences uses braces",
177 Applicability::MaybeIncorrect,
180 diag.span_label(span, msg);
182 "format of unicode escape sequences is `\\u{...}`",
188 EscapeError::UnicodeEscapeInByte => {
189 handler.span_err(span, "unicode escape sequences cannot be used \
190 as a byte or in a byte string")
192 EscapeError::EmptyUnicodeEscape => {
193 handler.span_err(span, "empty unicode escape (must have at least 1 hex digit)")
195 EscapeError::ZeroChars => {
196 handler.span_err(span, "empty character literal")
198 EscapeError::LoneSlash => {
199 handler.span_err(span, "invalid trailing slash in literal")
204 /// Pushes a character to a message string for error reporting
205 pub(crate) fn push_escaped_char(msg: &mut String, c: char) {
207 '\u{20}'..='\u{7e}' => {
208 // Don't escape \, ' or " for user-facing messages
212 msg.extend(c.escape_default());