Skip to content

Parsing issues around qualifiers and modifiers #146122

@fmease

Description

@fmease

Fn vs. trait qualifiers

We fail to parse

const unsafe trait Trait {} //~ ERROR expected one of `extern` or `fn`, found keyword `trait`

and

const unsafe auto trait Trait {} //~ ERROR expected one of `extern` or `fn`, found `auto`

even though check_trait_front_matter would return true here in theory. That's because in parse_item_kind we check_fn_front_matter first which returns true once there are >=2 "fn" qualifiers (†) which most notably includes the sequence const unsafe. Two basic solutions:

  • (†): check_fn_front_matter already contains certain exceptions like unsafe extern {, async gen { and async gen move {; we could extend this with !self.is_trait_front_matter() but that's kind of awful because we would basically check the sequence const unsafe three times over. Moreover, we gonna wanna have both is_* (&self) and check_* (&mut self) variants but that means bad duplication.
  • We could move the check_trait_front_matter check above/before the fn one since it's more strict. However, I wonder if this breaks some soft invariants: check_trait_front_matter is also used elsewhere to determine whether a fn item follows. With this change, it would have "false positives". Likely not a problem in practice though.

Fn ptr ty qualifiers vs. trait bound modifiers in bare trait object tys

What's more, we also use check_fn_front_matter inside parse_ty_common for fn ptr tys but later reject const and async qualifiers in parse_fn_front_matter. Now, since that happens before we check can_begin_bound we incorrectly reject bare trait object tys that start with >=2 trait bound modifiers if they coincide with "fn" qualifiers (thanks to check_fn_front_matter yet again), i.e., async const bare trait object tys:

#![feature(const_trait_impl, async_trait_bounds)]

#[cfg(false)]
type X = (const Trait, async Trait, dyn const async Trait); // OK!

#[cfg(false)]
type Y = const async Trait;
//~^ ERROR an `fn` pointer type cannot be `const`
//~| ERROR an `fn` pointer type cannot be `async`
//~| ERROR expected one of `extern`, `fn`, `gen`, `safe`, or `unsafe`, found `Trait`

Array/slice ty vs. conditional constness inside bare trait object tys

For consistency, the following should get parsed as a bare trait object ty with a conditionally-const trait bound. However, we commit to parsing an array/slice ty before that:

#[cfg(false)] type X = dyn [const] Trait; // OK!

#[cfg(false)] type Y = [const] Trait; //~ ERROR expected identifier, found `]`

Metadata

Metadata

Assignees

Labels

A-parserArea: The lexing & parsing of Rust source code to an ASTC-bugCategory: This is a bug.F-const_trait_impl`#![feature(const_trait_impl)]`PG-const-traitsProject group: Const traitsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions