Skip to content

Commit eb3e0d4

Browse files
committed
Properly recover from parenthesized use-bounds (precise capturing)
1 parent 5771665 commit eb3e0d4

File tree

3 files changed

+48
-16
lines changed

3 files changed

+48
-16
lines changed

compiler/rustc_parse/src/parser/ty.rs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -849,8 +849,9 @@ impl<'a> Parser<'a> {
849849

850850
fn parse_precise_capturing_args(
851851
&mut self,
852-
) -> PResult<'a, (ThinVec<PreciseCapturingArg>, Span)> {
853-
let lo = self.token.span;
852+
lo: Span,
853+
parens: ast::Parens,
854+
) -> PResult<'a, GenericBound> {
854855
self.expect_lt()?;
855856
let (args, _, _) = self.parse_seq_to_before_tokens(
856857
&[exp!(Gt)],
@@ -876,7 +877,22 @@ impl<'a> Parser<'a> {
876877
},
877878
)?;
878879
self.expect_gt()?;
879-
Ok((args, lo.to(self.prev_token.span)))
880+
881+
if let ast::Parens::Yes = parens {
882+
self.expect(exp!(CloseParen))?;
883+
let hi = self.prev_token.span;
884+
let mut diag = self
885+
.dcx()
886+
.struct_span_err(lo.to(hi), "precise capturing lists may not be parenthesized");
887+
diag.multipart_suggestion(
888+
"remove the parentheses",
889+
vec![(lo, String::new()), (hi, String::new())],
890+
Applicability::MachineApplicable,
891+
);
892+
diag.emit();
893+
}
894+
895+
Ok(GenericBound::Use(args, lo.to(self.prev_token.span)))
880896
}
881897

882898
/// Is a `dyn B0 + ... + Bn` type allowed here?
@@ -987,24 +1003,18 @@ impl<'a> Parser<'a> {
9871003
/// BOUND = TY_BOUND | LT_BOUND
9881004
/// ```
9891005
fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
990-
let lo = self.token.span;
9911006
let leading_token = self.prev_token;
1007+
let lo = self.token.span;
1008+
9921009
let parens = if self.eat(exp!(OpenParen)) { ast::Parens::Yes } else { ast::Parens::No };
9931010

994-
let bound = if self.token.is_lifetime() {
995-
self.parse_generic_lt_bound(lo, parens)?
1011+
if self.token.is_lifetime() {
1012+
self.parse_generic_lt_bound(lo, parens)
9961013
} else if self.eat_keyword(exp!(Use)) {
997-
// parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of
998-
// lifetimes and ident params (including SelfUpper). These are validated later
999-
// for order, duplication, and whether they actually reference params.
1000-
let use_span = self.prev_token.span;
1001-
let (args, args_span) = self.parse_precise_capturing_args()?;
1002-
GenericBound::Use(args, use_span.to(args_span))
1014+
self.parse_precise_capturing_args(lo, parens)
10031015
} else {
1004-
self.parse_generic_ty_bound(lo, parens, &leading_token)?
1005-
};
1006-
1007-
Ok(bound)
1016+
self.parse_generic_ty_bound(lo, parens, &leading_token)
1017+
}
10081018
}
10091019

10101020
/// Parses a lifetime ("outlives") bound, e.g. `'a`, according to:
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Ensure that we forbid parenthesized use-bounds. In the future we might want
2+
// to lift this restriction but for now they bear no use whatsoever.
3+
4+
fn f() -> impl Sized + (use<>) {}
5+
//~^ ERROR precise capturing lists may not be parenthesized
6+
//~| HELP remove the parentheses
7+
8+
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: precise capturing lists may not be parenthesized
2+
--> $DIR/parenthesized.rs:4:24
3+
|
4+
LL | fn f() -> impl Sized + (use<>) {}
5+
| ^^^^^^^
6+
|
7+
help: remove the parentheses
8+
|
9+
LL - fn f() -> impl Sized + (use<>) {}
10+
LL + fn f() -> impl Sized + use<> {}
11+
|
12+
13+
error: aborting due to 1 previous error
14+

0 commit comments

Comments
 (0)