diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-12-14 04:09:37 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-12-14 04:09:37 +0100 |
| commit | 4efa98cf2d1659468d01e97a9c42c51b6f6ac44b (patch) | |
| tree | 3c20bbea156c26b8d7fa463118464540fa538ed3 | |
| parent | 155dede638190b17eda93eddea9bad3e1e4d4ee4 (diff) | |
| parent | f1d2a6a34b05bb0f8e3da284fcc484b360638846 (diff) | |
| download | rust-4efa98cf2d1659468d01e97a9c42c51b6f6ac44b.tar.gz rust-4efa98cf2d1659468d01e97a9c42c51b6f6ac44b.zip | |
Rollup merge of #134274 - fmease:amp-raw-is-a-normal-borrow, r=Noratrieb
Add check-pass test for `&raw`
`&raw` denotes a normal/non-raw borrow of the path `raw`, not the start of raw borrow since it's not followed by either `const` or `mut`. Ensure this (and variants) will never regress!
When I saw the open diagnostic issue https://github.com/rust-lang/rust/issues/133231 (better parse error (recovery) on `&raw <expr>`), it made me think that we have to make sure that we will never commit too early/overzealously(†) when encountering the sequence `&raw`, even during parse error recovery!
Modifying the parser to eagerly treat `&raw` as the start of a raw borrow expr only lead to a single UI test failing, namely [tests/ui/enum-discriminant/ptr_niche.rs](https://github.com/rust-lang/rust/blob/4847d6a9d07d4be9ba3196f6ad444af2d7bdde72/tests/ui/enum-discriminant/ptr_niche.rs). However, this is just coincidental — it didn't *intentionally* test this edge case of the grammar.
---
†: With "eager" I mean something like:
```patch
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 0904a42d8a4..68d690fd602 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
`@@` -873,11 +873,16 `@@` fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
/// Parse `mut?` or `raw [ const | mut ]`.
fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {
- if self.check_keyword(kw::Raw) && self.look_ahead(1, Token::is_mutability) {
+ if self.eat_keyword(kw::Raw) {
// `raw [ const | mut ]`.
- let found_raw = self.eat_keyword(kw::Raw);
- assert!(found_raw);
- let mutability = self.parse_const_or_mut().unwrap();
+ let mutability = self.parse_const_or_mut().unwrap_or_else(|| {
+ let span = self.prev_token.span;
+ self.dcx().emit_err(ExpectedMutOrConstInRawBorrowExpr {
+ span,
+ after_ampersand: span.shrink_to_hi(),
+ });
+ ast::Mutability::Not
+ });
(ast::BorrowKind::Raw, mutability)
} else {
// `mut?`
```
---
r? compiler
| -rw-r--r-- | tests/ui/raw-ref-op/amp-raw-without-mut-const-is-a-normal-borrow.rs | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/tests/ui/raw-ref-op/amp-raw-without-mut-const-is-a-normal-borrow.rs b/tests/ui/raw-ref-op/amp-raw-without-mut-const-is-a-normal-borrow.rs new file mode 100644 index 00000000000..9360146a0fc --- /dev/null +++ b/tests/ui/raw-ref-op/amp-raw-without-mut-const-is-a-normal-borrow.rs @@ -0,0 +1,30 @@ +//! The token sequence `&raw` *only* starts a raw borrow expr if it's immediately +//! followed by either `const` or `mut`. If that's not the case, the `&` denotes +//! the start of a normal borrow expr where `raw` is interpreted as a regular +//! identifier and thus denotes the start of a path expr. +//! +//! This test ensures that we never commit too early/overzealously in the parser +//! when encountering the sequence `&raw` (even during parse error recovery) so +//! as not to regress preexisting code. + +//@ check-pass + +fn main() { // the odd formatting in here is intentional + let raw = 0; + let _ = &raw; + + let raw = 0; + let local = 1; + let _: i32 = &raw *local; + + let raw = |_| (); + let local = [0]; + let () = &raw (local[0]); +} + +macro_rules! check { + ($e:expr) => { compile_error!("expr"); }; + (&raw $e:expr) => {}; +} + +check!(&raw local); |
