Rollup merge of #137140 - Noratrieb:const-move, r=jieyouxu,compiler-errors
Fix const items not being allowed to be called `r#move` or `r#static` Because of an ambiguity with const closures, the parser needs to ensure that for a const item, the `const` keyword isn't followed by a `move` or `static` keyword, as that would indicate a const closure: ```rust fn main() { const move // ... } ``` This check did not take raw identifiers into account, therefore being unable to distinguish between `const move` and `const r#move`. The latter is obviously not a const closure, so it should be allowed as a const item. This fixes the check in the parser to only treat `const ...` as a const closure if it's followed by the *proper keyword*, and not a raw identifier. Additionally, this adds a large test that tests for all raw identifiers in all kinds of positions, including `const`, to prevent issues like this one from occurring again. fixes #137128
This commit is contained in:
commit
f0710999a9
3 changed files with 163 additions and 3 deletions
|
@ -754,9 +754,9 @@ impl<'a> Parser<'a> {
|
|||
self.is_keyword_ahead(0, &[kw::Const])
|
||||
&& self.look_ahead(1, |t| match &t.kind {
|
||||
// async closures do not work with const closures, so we do not parse that here.
|
||||
token::Ident(kw::Move | kw::Static, _) | token::OrOr | token::BinOp(token::Or) => {
|
||||
true
|
||||
}
|
||||
token::Ident(kw::Move | kw::Static, IdentIsRaw::No)
|
||||
| token::OrOr
|
||||
| token::BinOp(token::Or) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -104,6 +104,8 @@ symbols! {
|
|||
Gen: "gen", // >= 2024 Edition only
|
||||
Try: "try", // >= 2018 Edition only
|
||||
|
||||
// NOTE: When adding new keywords, consider adding them to the ui/parser/raw/raw-idents.rs test.
|
||||
|
||||
// "Lifetime keywords": regular keywords with a leading `'`.
|
||||
// Matching predicates: `is_any_keyword`
|
||||
UnderscoreLifetime: "'_",
|
||||
|
|
158
tests/ui/parser/raw/raw-idents.rs
Normal file
158
tests/ui/parser/raw/raw-idents.rs
Normal file
|
@ -0,0 +1,158 @@
|
|||
//@ check-pass
|
||||
//@ revisions:e2015 e2018 e2021 e2024
|
||||
//@[e2015] edition:2015
|
||||
//@[e2018] edition:2018
|
||||
//@[e2021] edition:2021
|
||||
//@[e2024] edition:2024
|
||||
|
||||
// Ensure that all (usable as identifier) keywords work as raw identifiers in all positions.
|
||||
// This was motivated by issue #137128, where `r#move`/`r#static`` did not work as `const` names
|
||||
// due to a parser check not acounting for raw identifiers.
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![allow(dead_code, nonstandard_style)]
|
||||
|
||||
// NOTE: It is vital to only use a `tt` fragment to avoid confusing
|
||||
// the parser with nonterminals that can mask bugs.
|
||||
|
||||
macro_rules! tests {
|
||||
($kw:tt) => {
|
||||
mod $kw {
|
||||
mod const_item {
|
||||
const $kw: () = ();
|
||||
}
|
||||
mod static_item {
|
||||
static $kw: () = ();
|
||||
}
|
||||
mod fn_item {
|
||||
fn $kw() {}
|
||||
}
|
||||
mod mod_and_use_item {
|
||||
mod $kw {
|
||||
use super::$kw;
|
||||
}
|
||||
}
|
||||
mod ty_alias_item {
|
||||
type $kw = ();
|
||||
}
|
||||
mod struct_item {
|
||||
struct $kw { $kw: () }
|
||||
}
|
||||
mod enum_item {
|
||||
enum $kw { $kw }
|
||||
}
|
||||
mod union_item {
|
||||
union $kw { $kw: () }
|
||||
}
|
||||
mod trait_item {
|
||||
trait $kw {
|
||||
fn $kw() {}
|
||||
}
|
||||
}
|
||||
mod generics_and_impl {
|
||||
struct A<$kw>($kw);
|
||||
enum B<$kw> { A($kw) }
|
||||
trait Tr<$kw> {
|
||||
type $kw;
|
||||
}
|
||||
|
||||
impl<$kw> Tr<$kw> for A<$kw> {
|
||||
type $kw = ();
|
||||
}
|
||||
impl<$kw> B<$kw> {}
|
||||
}
|
||||
mod extern_crate {
|
||||
#[cfg(any())]
|
||||
extern crate $kw;
|
||||
}
|
||||
mod body {
|
||||
fn expr() {
|
||||
let $kw = 0;
|
||||
let b = $kw;
|
||||
assert_eq!($kw, b);
|
||||
type $kw = ();
|
||||
let $kw: $kw = ();
|
||||
let _ = $kw as $kw;
|
||||
}
|
||||
fn pat_const() {
|
||||
const $kw: u8 = 0;
|
||||
|
||||
// Ensure that $kw actually matches the constant.
|
||||
#[forbid(unreachable_patterns)]
|
||||
match 1 {
|
||||
$kw => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
fn pat_binding() {
|
||||
match 1 {
|
||||
$kw => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
tests!(r#break);
|
||||
tests!(r#const);
|
||||
tests!(r#continue);
|
||||
tests!(r#else);
|
||||
tests!(r#enum);
|
||||
tests!(r#extern);
|
||||
tests!(r#false);
|
||||
tests!(r#fn);
|
||||
tests!(r#for);
|
||||
tests!(r#if);
|
||||
tests!(r#impl);
|
||||
tests!(r#in);
|
||||
tests!(r#let);
|
||||
tests!(r#loop);
|
||||
tests!(r#match);
|
||||
tests!(r#mod);
|
||||
tests!(r#move);
|
||||
tests!(r#mut);
|
||||
tests!(r#pub);
|
||||
tests!(r#ref);
|
||||
tests!(r#return);
|
||||
tests!(r#static);
|
||||
tests!(r#struct);
|
||||
tests!(r#trait);
|
||||
tests!(r#true);
|
||||
tests!(r#type);
|
||||
tests!(r#unsafe);
|
||||
tests!(r#use);
|
||||
tests!(r#where);
|
||||
tests!(r#while);
|
||||
tests!(r#abstract);
|
||||
tests!(r#become);
|
||||
tests!(r#box);
|
||||
tests!(r#do);
|
||||
tests!(r#final);
|
||||
tests!(r#macro);
|
||||
tests!(r#override);
|
||||
tests!(r#priv);
|
||||
tests!(r#typeof);
|
||||
tests!(r#unsized);
|
||||
tests!(r#virtual);
|
||||
tests!(r#yield);
|
||||
tests!(r#async);
|
||||
tests!(r#await);
|
||||
tests!(r#dyn);
|
||||
tests!(r#gen);
|
||||
tests!(r#try);
|
||||
|
||||
// Weak keywords:
|
||||
tests!(auto);
|
||||
tests!(builtin);
|
||||
tests!(catch);
|
||||
tests!(default);
|
||||
tests!(macro_rules);
|
||||
tests!(raw);
|
||||
tests!(reuse);
|
||||
tests!(contract_ensures);
|
||||
tests!(contract_requires);
|
||||
tests!(safe);
|
||||
tests!(union);
|
||||
tests!(yeet);
|
Loading…
Add table
Add a link
Reference in a new issue