Skip to content

Commit ae77516

Browse files
Rollup merge of #155820 - Zalathar:range, r=Kivooeo
Avoid improper spans when `...` or `..=` is recovered from non-ASCII - Fixes #155799 Adjusting span endpoints by `BytePos(1)` is almost always bad news. In this case, the code assumed that it was skipping over a single ASCII character. But in the presence of parser recovery from other non-ASCII characters this resulted in an ICE due to bad string indexing when emitting suggestions.
2 parents b227d45 + 9ceed25 commit ae77516

4 files changed

Lines changed: 388 additions & 14 deletions

File tree

compiler/rustc_parse/src/errors.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,29 +1140,27 @@ pub(crate) struct InclusiveRangeMatchArrow {
11401140
#[primary_span]
11411141
pub arrow: Span,
11421142
#[label("this is parsed as an inclusive range `..=`")]
1143-
pub span: Span,
11441143
#[suggestion(
11451144
"add a space between the pattern and `=>`",
11461145
style = "verbose",
1147-
code = " ",
1146+
code = ".. =",
11481147
applicability = "machine-applicable"
11491148
)]
1150-
pub after_pat: Span,
1149+
pub span: Span,
11511150
}
11521151

11531152
#[derive(Diagnostic)]
11541153
#[diag("inclusive range with no end", code = E0586)]
11551154
#[note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")]
11561155
pub(crate) struct InclusiveRangeNoEnd {
11571156
#[primary_span]
1158-
pub span: Span,
11591157
#[suggestion(
11601158
"use `..` instead",
1161-
code = "",
1159+
code = "..",
11621160
applicability = "machine-applicable",
11631161
style = "verbose"
11641162
)]
1165-
pub suggestion: Span,
1163+
pub span: Span,
11661164
}
11671165

11681166
#[derive(Subdiagnostic)]

compiler/rustc_parse/src/parser/pat.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,7 +1225,7 @@ impl<'a> Parser<'a> {
12251225
pub(super) fn inclusive_range_with_incorrect_end(&mut self) -> ErrorGuaranteed {
12261226
let tok = &self.token;
12271227
let span = self.prev_token.span;
1228-
// If the user typed "..==" instead of "..=", we want to give them
1228+
// If the user typed "..==" or "...=" instead of "..=", we want to give them
12291229
// a specific error message telling them to use "..=".
12301230
// If they typed "..=>", suggest they use ".. =>".
12311231
// Otherwise, we assume that they meant to type a half open exclusive
@@ -1243,14 +1243,10 @@ impl<'a> Parser<'a> {
12431243

12441244
self.dcx().emit_err(InclusiveRangeExtraEquals { span: span_with_eq })
12451245
}
1246-
token::Gt if no_space => {
1247-
let after_pat = span.with_hi(span.hi() - BytePos(1)).shrink_to_hi();
1248-
self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat })
1246+
token::Gt if self.prev_token.kind == token::DotDotEq && no_space => {
1247+
self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span })
12491248
}
1250-
_ => self.dcx().emit_err(InclusiveRangeNoEnd {
1251-
span,
1252-
suggestion: span.with_lo(span.hi() - BytePos(1)),
1253-
}),
1249+
_ => self.dcx().emit_err(InclusiveRangeNoEnd { span }),
12541250
}
12551251
}
12561252

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#![crate_type = "rlib"]
2+
3+
// Suggestions for range patterns should not perform span manipulations that
4+
// assume the range token is ASCII, because it could have been recovered from
5+
// similar-looking Unicode characters.
6+
//
7+
// Regression test for <https://github.com/rust-lang/rust/issues/155799>.
8+
9+
// These dots are U+00B7 MIDDLE DOT, not an ASCII period.
10+
fn dot_dot_dot() { ··· }
11+
//~^ ERROR unknown start of token
12+
//~| ERROR unknown start of token
13+
//~| ERROR unknown start of token
14+
//~| ERROR unexpected token: `...`
15+
//~| ERROR inclusive range with no end
16+
17+
fn dot_dot_dot_eq() { ···= }
18+
//~^ ERROR unknown start of token
19+
//~| ERROR unknown start of token
20+
//~| ERROR unknown start of token
21+
//~| ERROR unexpected token: `...`
22+
//~| ERROR unexpected `=` after inclusive range
23+
24+
fn dot_dot_dot_gt() { ···> }
25+
//~^ ERROR unknown start of token
26+
//~| ERROR unknown start of token
27+
//~| ERROR unknown start of token
28+
//~| ERROR unexpected token: `...`
29+
//~| ERROR inclusive range with no end
30+
//~| ERROR expected one of `;` or `}`, found `>`
31+
32+
fn dot_dot_eq() { ··= }
33+
//~^ ERROR unknown start of token
34+
//~| ERROR unknown start of token
35+
//~| ERROR inclusive range with no end
36+
37+
fn dot_dot_eq_eq() { ··== }
38+
//~^ ERROR unknown start of token
39+
//~| ERROR unknown start of token
40+
//~| ERROR unexpected `=` after inclusive range
41+
42+
fn dot_dot_eq_gt() { ··=> }
43+
//~^ ERROR unknown start of token
44+
//~| ERROR unknown start of token
45+
//~| ERROR unexpected `>` after inclusive range
46+
//~| ERROR expected one of `;` or `}`, found `>`

0 commit comments

Comments
 (0)