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::BareCarriageReturnInRawString => {
84 assert!(mode.in_double_quotes());
85 let msg = "bare CR not allowed in raw string";
86 handler.span_err(span, msg);
88 EscapeError::InvalidEscape => {
89 let (c, span) = last_char();
91 let label = if mode.is_bytes() {
94 "unknown character escape"
96 let mut msg = label.to_string();
98 push_escaped_char(&mut msg, c);
100 let mut diag = handler.struct_span_err(span, msg.as_str());
101 diag.span_label(span, label);
102 if c == '{' || c == '}' && !mode.is_bytes() {
103 diag.help("if used in a formatting string, \
104 curly braces are escaped with `{{` and `}}`");
105 } else if c == '\r' {
106 diag.help("this is an isolated carriage return; \
107 consider checking your editor and version control settings");
111 EscapeError::TooShortHexEscape => {
112 handler.span_err(span, "numeric character escape is too short")
114 EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => {
115 let (c, span) = last_char();
117 let mut msg = if error == EscapeError::InvalidCharInHexEscape {
118 "invalid character in numeric character escape: "
120 "invalid character in unicode escape: "
122 push_escaped_char(&mut msg, c);
124 handler.span_err(span, msg.as_str())
126 EscapeError::NonAsciiCharInByte => {
127 assert!(mode.is_bytes());
128 let (_c, span) = last_char();
129 handler.span_err(span, "byte constant must be ASCII. \
130 Use a \\xHH escape for a non-ASCII byte")
132 EscapeError::NonAsciiCharInByteString => {
133 assert!(mode.is_bytes());
134 let (_c, span) = last_char();
135 handler.span_err(span, "raw byte string must be ASCII")
137 EscapeError::OutOfRangeHexEscape => {
138 handler.span_err(span, "this form of character escape may only be used \
139 with characters in the range [\\x00-\\x7f]")
141 EscapeError::LeadingUnderscoreUnicodeEscape => {
142 let (_c, span) = last_char();
143 handler.span_err(span, "invalid start of unicode escape")
145 EscapeError::OverlongUnicodeEscape => {
146 handler.span_err(span, "overlong unicode escape (must have at most 6 hex digits)")
148 EscapeError::UnclosedUnicodeEscape => {
149 handler.span_err(span, "unterminated unicode escape (needed a `}`)")
151 EscapeError::NoBraceInUnicodeEscape => {
152 let msg = "incorrect unicode escape sequence";
153 let mut diag = handler.struct_span_err(span, msg);
155 let mut suggestion = "\\u{".to_owned();
156 let mut suggestion_len = 0;
157 let (c, char_span) = last_char();
158 let chars = once(c).chain(lit[range.end..].chars());
159 for c in chars.take(6).take_while(|c| c.is_digit(16)) {
161 suggestion_len += c.len_utf8();
164 if suggestion_len > 0 {
165 suggestion.push('}');
166 let lo = char_span.lo();
167 let hi = lo + BytePos(suggestion_len as u32);
168 diag.span_suggestion(
169 span.with_lo(lo).with_hi(hi),
170 "format of unicode escape sequences uses braces",
172 Applicability::MaybeIncorrect,
175 diag.span_label(span, msg);
177 "format of unicode escape sequences is `\\u{...}`",
183 EscapeError::UnicodeEscapeInByte => {
184 handler.span_err(span, "unicode escape sequences cannot be used \
185 as a byte or in a byte string")
187 EscapeError::EmptyUnicodeEscape => {
188 handler.span_err(span, "empty unicode escape (must have at least 1 hex digit)")
190 EscapeError::ZeroChars => {
191 handler.span_err(span, "empty character literal")
193 EscapeError::LoneSlash => {
194 panic!("lexer accepted unterminated literal with trailing slash")
199 /// Pushes a character to a message string for error reporting
200 pub(crate) fn push_escaped_char(msg: &mut String, c: char) {
202 '\u{20}'..='\u{7e}' => {
203 // Don't escape \, ' or " for user-facing messages
207 msg.extend(c.escape_default());