Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions compiler/rustc_parse/src/parser/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,45 +444,46 @@ impl<'a> Parser<'a> {
/// 2. tuple type
/// 3. bare trait object type where the first trait bound is parenthesized
fn parse_paren_start_ty(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
let mut trailing_plus = false;
let (ts, trailing) = self.parse_paren_comma_seq(|p| {
let mut inside_has_trailing_plus = false;
let (ts, trailing_comma) = self.parse_paren_comma_seq(|p| {
let ty = p.parse_ty()?;
trailing_plus = p.prev_token == TokenKind::Plus;
inside_has_trailing_plus = p.prev_token == TokenKind::Plus;
Ok(ty)
})?;

if ts.len() == 1 && matches!(trailing, Trailing::No) {
if ts.len() == 1 && matches!(trailing_comma, Trailing::No) {
let ty = ts.into_iter().next().unwrap();

// Let's check if we actually have a bare trait object type where the first trait bound
// is parenthesized. That's the case if the parentheses are followed by a `+` and if
// what's contained between the parentheses resembles a *BareTraitBound*.
//
// For context, looking at bounds in general (see *Bound*), only trait bounds are
// allowed to be wrapped in parentheses, not however lifetime and use bounds.
let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus();
// allowed to be wrapped in parentheses, not however outlives and use bounds.
let outside_has_eligible_trailing_plus =
allow_plus == AllowPlus::Yes && self.token.is_like_plus();
match ty.kind {
// `"(" TypePath ")" "+"`
TyKind::Path(None, path) if maybe_bounds => self
TyKind::Path(None, path) if outside_has_eligible_trailing_plus => self
.finish_parsing_bare_trait_object_ty(
ThinVec::new(),
path,
lo,
true,
ast::Parens::Yes,
),
// `"(" BareTraitBound\TypePath | UseBound ")" "+"`
// `"(" BareTraitBound\TypePath ")" "+"`
//
// * FIXME: As alluded to above, only trait bounds are meant to allow parens.
// Arguably, it's an accident that we're permitting *UseBound*s and thus types
// like `(use<>)+`. Might need a T-lang FCP to change this.
// * We're checking `!trailing_plus` to prevent us from accepting code like
// `(T+)+` or `('a+)+`.
// * While we could be looking at `('a)+` which we don't want to accept, we
// know that the `parse_ty` above has already emitted an error since the
// lifetime isn't immediately followed by a `+`.
// We actually accept outlives bounds here, too, purely to reduce diagnostic output
// for ill-formed code like `('a)+`: We know for a fact that the `parse_ty` above
// has already emitted an error for the inner `'a` as it's not followed by `+`.
// This way we indirectly suppress unhelpful follow-up diagnostics like E0178
// ("bad `+` in type") and E0224 ("no trait bound in trait object type").
TyKind::TraitObject(mut bounds, TraitObjectSyntax::None)
if maybe_bounds && bounds.len() == 1 && !trailing_plus =>
if outside_has_eligible_trailing_plus
&& !inside_has_trailing_plus
&& let [ast::GenericBound::Trait(_) | ast::GenericBound::Outlives(_)] =
bounds.as_slice() =>
{
self.eat_plus();
bounds.append(&mut self.parse_generic_bounds()?);
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/impl-trait/precise-capturing/parenthesized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,14 @@ fn f() -> impl Sized + (use<>) {}
//~^ ERROR precise capturing lists may not be parenthesized
//~| HELP remove the parentheses

#[cfg(false)]
type O = Trait + (use<>);
//~^ ERROR precise capturing lists may not be parenthesized
//~| HELP remove the parentheses

// We once used to accidentally accept this.
#[cfg(false)]
type O = (use<>) + Trait;
//~^ ERROR expected a path on the left-hand side of `+`

fn main() {}
21 changes: 20 additions & 1 deletion tests/ui/impl-trait/precise-capturing/parenthesized.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,24 @@ LL - fn f() -> impl Sized + (use<>) {}
LL + fn f() -> impl Sized + use<> {}
|

error: aborting due to 1 previous error
error: precise capturing lists may not be parenthesized
--> $DIR/parenthesized.rs:9:18
|
LL | type O = Trait + (use<>);
| ^^^^^^^
|
help: remove the parentheses
|
LL - type O = Trait + (use<>);
LL + type O = Trait + use<>;
|

error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/parenthesized.rs:15:10
|
LL | type O = (use<>) + Trait;
| ^^^^^^^ expected a path

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0178`.
Loading