Skip to content

Commit

Permalink
Rollup merge of rust-lang#87671 - jesyspa:issue-87319-multiple-newlin…
Browse files Browse the repository at this point in the history
…es, r=estebank

Warn when an escaped newline skips multiple lines

Resolves rust-lang#87319
  • Loading branch information
JohnTitor committed Aug 11, 2021
2 parents 8ac3d7b + 07aacf5 commit 6bd5910
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 8 deletions.
17 changes: 13 additions & 4 deletions compiler/rustc_lexer/src/unescape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,17 @@ pub enum EscapeError {
/// After a line ending with '\', the next line contains whitespace
/// characters that are not skipped.
UnskippedWhitespaceWarning,

/// After a line ending with '\', multiple lines are skipped.
MultipleSkippedLinesWarning,
}

impl EscapeError {
/// Returns true for actual errors, as opposed to warnings.
pub fn is_fatal(&self) -> bool {
match self {
EscapeError::UnskippedWhitespaceWarning => false,
EscapeError::MultipleSkippedLinesWarning => false,
_ => true,
}
}
Expand Down Expand Up @@ -315,12 +319,17 @@ where
where
F: FnMut(Range<usize>, Result<char, EscapeError>),
{
let str = chars.as_str();
let first_non_space = str
let tail = chars.as_str();
let first_non_space = tail
.bytes()
.position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
.unwrap_or(str.len());
let tail = &str[first_non_space..];
.unwrap_or(tail.len());
if tail[1..first_non_space].contains('\n') {
// The +1 accounts for the escaping slash.
let end = start + first_non_space + 1;
callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
}
let tail = &tail[first_non_space..];
if let Some(c) = tail.chars().nth(0) {
// For error reporting, we would like the span to contain the character that was not
// skipped. The +1 is necessary to account for the leading \ that started the escape.
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_lexer/src/unescape/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ fn test_unescape_str_warn() {
assert_eq!(unescaped, expected);
}

// Check we can handle escaped newlines at the end of a file.
check("\\\n", &[]);
check("\\\n ", &[]);

check(
"\\\n \u{a0} x",
&[
Expand All @@ -115,6 +119,7 @@ fn test_unescape_str_warn() {
(6..7, Ok('x')),
],
);
check("\\\n \n x", &[(0..7, Err(EscapeError::MultipleSkippedLinesWarning)), (7..8, Ok('x'))]);
}

#[test]
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,11 @@ pub(crate) fn emit_unescape_error(
format!("non-ASCII whitespace symbol '{}' is not skipped", c.escape_unicode());
handler.struct_span_warn(span, &msg).span_label(char_span, &msg).emit();
}
EscapeError::MultipleSkippedLinesWarning => {
let msg = "multiple lines skipped by escaped newline";
let bottom_msg = "skipping everything up to and including this point";
handler.struct_span_warn(span, msg).span_label(span, bottom_msg).emit();
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/fmt/format-string-error-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ fn main() {
a");
//~^ ERROR invalid format string
format!("{ \
\
b");
//~^ ERROR invalid format string
format!(r#"{ \
Expand Down Expand Up @@ -38,12 +38,12 @@ fn main() {
{ \
\
b \
\
");
//~^^^ ERROR invalid format string
format!(r#"
raw { \
\
c"#);
//~^^^ ERROR invalid format string
format!(r#"
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/fmt/format-string-error-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ error: invalid format string: expected `'}'`, found `'b'`
|
LL | format!("{ \
| - because of this opening brace
LL |
LL | \
LL | b");
| ^ expected `}` in format string
|
Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/str/str-escape.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// check-pass
fn main() {
let s = "\
";
//~^^^ WARNING multiple lines skipped by escaped newline
let s = "foo\
  bar
";
//~^^^ WARNING non-ASCII whitespace symbol '\u{a0}' is not skipped
}
21 changes: 21 additions & 0 deletions src/test/ui/str/str-escape.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
warning: multiple lines skipped by escaped newline
--> $DIR/str-escape.rs:3:14
|
LL | let s = "\
| ______________^
LL | |
LL | | ";
| |_____________^ skipping everything up to and including this point

warning: non-ASCII whitespace symbol '\u{a0}' is not skipped
--> $DIR/str-escape.rs:7:17
|
LL | let s = "foo\
| _________________^
LL | |   bar
| | ^ non-ASCII whitespace symbol '\u{a0}' is not skipped
| |___|
|

warning: 2 warnings emitted

0 comments on commit 6bd5910

Please sign in to comment.