Skip to content

Commit a03fbfe

Browse files
committed
Warn when an escaped newline skips multiple lines
1 parent d488de8 commit a03fbfe

File tree

3 files changed

+19
-0
lines changed

3 files changed

+19
-0
lines changed

compiler/rustc_lexer/src/unescape.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,17 @@ pub enum EscapeError {
6060
/// After a line ending with '\', the next line contains whitespace
6161
/// characters that are not skipped.
6262
UnskippedWhitespaceWarning,
63+
64+
/// After a line ending with '\', multiple lines are skipped.
65+
MultipleSkippedLinesWarning,
6366
}
6467

6568
impl EscapeError {
6669
/// Returns true for actual errors, as opposed to warnings.
6770
pub fn is_fatal(&self) -> bool {
6871
match self {
6972
EscapeError::UnskippedWhitespaceWarning => false,
73+
EscapeError::MultipleSkippedLinesWarning => false,
7074
_ => true,
7175
}
7276
}
@@ -320,6 +324,11 @@ where
320324
.bytes()
321325
.position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
322326
.unwrap_or(str.len());
327+
if str[1..first_non_space].contains('\n') {
328+
// The +1 accounts for the escaping slash.
329+
let end = start + first_non_space + 1;
330+
callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
331+
}
323332
let tail = &str[first_non_space..];
324333
if let Some(c) = tail.chars().nth(0) {
325334
// For error reporting, we would like the span to contain the character that was not

compiler/rustc_lexer/src/unescape/tests.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ fn test_unescape_str_warn() {
106106
assert_eq!(unescaped, expected);
107107
}
108108

109+
// Check we can handle escaped newlines at the end of a file.
110+
check("\\\n", &[]);
111+
check("\\\n ", &[]);
112+
109113
check(
110114
"\\\n \u{a0} x",
111115
&[
@@ -115,6 +119,7 @@ fn test_unescape_str_warn() {
115119
(6..7, Ok('x')),
116120
],
117121
);
122+
check("\\\n \n x", &[(0..7, Err(EscapeError::MultipleSkippedLinesWarning)), (7..8, Ok('x'))]);
118123
}
119124

120125
#[test]

compiler/rustc_parse/src/lexer/unescape_error_reporting.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,11 @@ pub(crate) fn emit_unescape_error(
280280
format!("non-ASCII whitespace symbol '{}' is not skipped", c.escape_unicode());
281281
handler.struct_span_warn(span, &msg).span_label(char_span, &msg).emit();
282282
}
283+
EscapeError::MultipleSkippedLinesWarning => {
284+
let msg = "multiple lines skipped by escaped newline";
285+
let bottom_msg = "skipping everything up to and including this point";
286+
handler.struct_span_warn(span, msg).span_label(span, bottom_msg).emit();
287+
}
283288
}
284289
}
285290

0 commit comments

Comments
 (0)