Skip to content

Commit 1bef90f

Browse files
Rollup merge of #86010 - FabianWolff:ICE-parser, r=varkor
Fix two ICEs in the parser This pull request fixes #84104 and fixes #84148. The latter is caused by an invalid `assert_ne!()` in the parser, which I have simply removed because the error is then caught in another part of the parser. #84104 is somewhat more subtle and has to do with a suggestion to remove extraneous `<` characters; for instance: ```rust fn main() { foo::<Ty<<<i32>(); } ``` currently leads to ``` error: unmatched angle brackets --> unmatched-langle.rs:2:10 | 2 | foo::<Ty<<<i32>(); | ^^^ help: remove extra angle brackets ``` which is obviously wrong and stems from the fact that the code for issuing the above suggestion does not consider the possibility that there might be other tokens in between the opening angle brackets. In #84104, this has led to a span being generated that ends in the middle of a multi-byte character (because the code issuing the suggestion thought that it was only skipping over `<`, which are single-byte), causing an ICE.
2 parents a3c76f6 + 6a6a605 commit 1bef90f

12 files changed

+182
-38
lines changed

compiler/rustc_parse/src/parser/path.rs

+47-37
Original file line numberDiff line numberDiff line change
@@ -352,49 +352,59 @@ impl<'a> Parser<'a> {
352352
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
353353
match self.parse_angle_args() {
354354
Ok(args) => Ok(args),
355-
Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
356-
// Cancel error from being unable to find `>`. We know the error
357-
// must have been this due to a non-zero unmatched angle bracket
358-
// count.
359-
e.cancel();
360-
355+
Err(mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
361356
// Swap `self` with our backup of the parser state before attempting to parse
362357
// generic arguments.
363358
let snapshot = mem::replace(self, snapshot.unwrap());
364359

365-
debug!(
366-
"parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
367-
snapshot.count={:?}",
368-
snapshot.unmatched_angle_bracket_count,
369-
);
370-
371360
// Eat the unmatched angle brackets.
372-
for _ in 0..snapshot.unmatched_angle_bracket_count {
373-
self.eat_lt();
374-
}
375-
376-
// Make a span over ${unmatched angle bracket count} characters.
377-
let span = lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
378-
self.struct_span_err(
379-
span,
380-
&format!(
381-
"unmatched angle bracket{}",
382-
pluralize!(snapshot.unmatched_angle_bracket_count)
383-
),
384-
)
385-
.span_suggestion(
386-
span,
387-
&format!(
388-
"remove extra angle bracket{}",
389-
pluralize!(snapshot.unmatched_angle_bracket_count)
390-
),
391-
String::new(),
392-
Applicability::MachineApplicable,
393-
)
394-
.emit();
361+
let all_angle_brackets = (0..snapshot.unmatched_angle_bracket_count)
362+
.fold(true, |a, _| a && self.eat_lt());
363+
364+
if !all_angle_brackets {
365+
// If there are other tokens in between the extraneous `<`s, we cannot simply
366+
// suggest to remove them. This check also prevents us from accidentally ending
367+
// up in the middle of a multibyte character (issue #84104).
368+
let _ = mem::replace(self, snapshot);
369+
Err(e)
370+
} else {
371+
// Cancel error from being unable to find `>`. We know the error
372+
// must have been this due to a non-zero unmatched angle bracket
373+
// count.
374+
e.cancel();
375+
376+
debug!(
377+
"parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
378+
snapshot.count={:?}",
379+
snapshot.unmatched_angle_bracket_count,
380+
);
381+
382+
// Make a span over ${unmatched angle bracket count} characters.
383+
// This is safe because `all_angle_brackets` ensures that there are only `<`s,
384+
// i.e. no multibyte characters, in this range.
385+
let span =
386+
lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
387+
self.struct_span_err(
388+
span,
389+
&format!(
390+
"unmatched angle bracket{}",
391+
pluralize!(snapshot.unmatched_angle_bracket_count)
392+
),
393+
)
394+
.span_suggestion(
395+
span,
396+
&format!(
397+
"remove extra angle bracket{}",
398+
pluralize!(snapshot.unmatched_angle_bracket_count)
399+
),
400+
String::new(),
401+
Applicability::MachineApplicable,
402+
)
403+
.emit();
395404

396-
// Try again without unmatched angle bracket characters.
397-
self.parse_angle_args()
405+
// Try again without unmatched angle bracket characters.
406+
self.parse_angle_args()
407+
}
398408
}
399409
Err(e) => Err(e),
400410
}

compiler/rustc_parse/src/parser/ty.rs

-1
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,6 @@ impl<'a> Parser<'a> {
334334
mut bounds: GenericBounds,
335335
plus: bool,
336336
) -> PResult<'a, TyKind> {
337-
assert_ne!(self.token, token::Question);
338337
if plus {
339338
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
340339
bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?);

src/test/ui/parser/issue-84104.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// error-pattern: this file contains an unclosed delimiter
2+
// error-pattern: expected one of
3+
#[i=i::<ښܖ<

src/test/ui/parser/issue-84104.stderr

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: this file contains an unclosed delimiter
2+
--> $DIR/issue-84104.rs:3:13
3+
|
4+
LL | #[i=i::<ښܖ<
5+
| - ^
6+
| |
7+
| unclosed delimiter
8+
9+
error: expected one of `>`, a const expression, lifetime, or type, found `]`
10+
--> $DIR/issue-84104.rs:3:13
11+
|
12+
LL | #[i=i::<ښܖ<
13+
| ^ expected one of `>`, a const expression, lifetime, or type
14+
15+
error: aborting due to 2 previous errors
16+

src/test/ui/parser/issue-84148-1.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn f(t:for<>t?)
2+
//~^ ERROR: expected parameter name
3+
//~| ERROR: expected one of
4+
//~| ERROR: expected one of
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error: expected parameter name, found `?`
2+
--> $DIR/issue-84148-1.rs:1:14
3+
|
4+
LL | fn f(t:for<>t?)
5+
| ^ expected parameter name
6+
7+
error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
8+
--> $DIR/issue-84148-1.rs:1:14
9+
|
10+
LL | fn f(t:for<>t?)
11+
| ^
12+
| |
13+
| expected one of `(`, `)`, `+`, `,`, `::`, or `<`
14+
| help: missing `,`
15+
16+
error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
17+
--> $DIR/issue-84148-1.rs:1:15
18+
|
19+
LL | fn f(t:for<>t?)
20+
| ^ expected one of `->`, `;`, `where`, or `{`
21+
22+
error: aborting due to 3 previous errors
23+

src/test/ui/parser/issue-84148-2.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// error-pattern: this file contains an unclosed delimiter
2+
// error-pattern: expected parameter name
3+
// error-pattern: expected one of
4+
fn f(t:for<>t?
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error: this file contains an unclosed delimiter
2+
--> $DIR/issue-84148-2.rs:4:16
3+
|
4+
LL | fn f(t:for<>t?
5+
| - ^
6+
| |
7+
| unclosed delimiter
8+
9+
error: expected parameter name, found `?`
10+
--> $DIR/issue-84148-2.rs:4:14
11+
|
12+
LL | fn f(t:for<>t?
13+
| ^ expected parameter name
14+
15+
error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
16+
--> $DIR/issue-84148-2.rs:4:14
17+
|
18+
LL | fn f(t:for<>t?
19+
| ^
20+
| |
21+
| expected one of `(`, `)`, `+`, `,`, `::`, or `<`
22+
| help: missing `,`
23+
24+
error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
25+
--> $DIR/issue-84148-2.rs:4:16
26+
|
27+
LL | fn f(t:for<>t?
28+
| ^ expected one of `->`, `;`, `where`, or `{`
29+
30+
error: aborting due to 4 previous errors
31+
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Check that a suggestion is issued if there are too many `<`s in a
2+
// generic argument list, and that the parser recovers properly.
3+
4+
fn main() {
5+
foo::<<<<Ty<i32>>();
6+
//~^ ERROR: unmatched angle brackets
7+
//~| ERROR: cannot find function `foo` in this scope [E0425]
8+
//~| ERROR: cannot find type `Ty` in this scope [E0412]
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: unmatched angle brackets
2+
--> $DIR/unmatched-langle-1.rs:5:10
3+
|
4+
LL | foo::<<<<Ty<i32>>();
5+
| ^^^ help: remove extra angle brackets
6+
7+
error[E0425]: cannot find function `foo` in this scope
8+
--> $DIR/unmatched-langle-1.rs:5:5
9+
|
10+
LL | foo::<<<<Ty<i32>>();
11+
| ^^^ not found in this scope
12+
13+
error[E0412]: cannot find type `Ty` in this scope
14+
--> $DIR/unmatched-langle-1.rs:5:14
15+
|
16+
LL | foo::<<<<Ty<i32>>();
17+
| ^^ not found in this scope
18+
19+
error: aborting due to 3 previous errors
20+
21+
Some errors have detailed explanations: E0412, E0425.
22+
For more information about an error, try `rustc --explain E0412`.
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// When there are too many opening `<`s, the compiler would previously
2+
// suggest nonsense if the `<`s were interspersed with other tokens:
3+
//
4+
// error: unmatched angle brackets
5+
// --> unmatched-langle.rs:2:10
6+
// |
7+
// 2 | foo::<Ty<<<i32>();
8+
// | ^^^ help: remove extra angle brackets
9+
//
10+
// This test makes sure that this is no longer happening.
11+
12+
fn main() {
13+
foo::<Ty<<<i32>();
14+
//~^ ERROR: expected `::`, found `(`
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: expected `::`, found `(`
2+
--> $DIR/unmatched-langle-2.rs:13:20
3+
|
4+
LL | foo::<Ty<<<i32>();
5+
| ^ expected `::`
6+
7+
error: aborting due to previous error
8+

0 commit comments

Comments
 (0)