Skip to content

Commit 19eb307

Browse files
committed
Handle incorrect and ambiguous use of pin sugar better
1 parent c0746b9 commit 19eb307

File tree

6 files changed

+60
-25
lines changed

6 files changed

+60
-25
lines changed

compiler/rustc_parse/src/parser/ty.rs

+19-23
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,10 @@ impl<'a> Parser<'a> {
530530
fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
531531
let and_span = self.prev_token.span;
532532
let mut opt_lifetime = self.check_lifetime().then(|| self.expect_lifetime());
533-
let (pinned, mut mutbl) = self.parse_pin_and_mut();
533+
let (pinned, mut mutbl) = match self.parse_pin_and_mut() {
534+
Some(pin_mut) => pin_mut,
535+
None => (Pinnedness::Not, self.parse_mutability()),
536+
};
534537
if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() {
535538
// A lifetime is invalid here: it would be part of a bare trait bound, which requires
536539
// it to be followed by a plus, but we disallow plus in the pointee type.
@@ -572,31 +575,24 @@ impl<'a> Parser<'a> {
572575
/// Parses `pin` and `mut` annotations on references.
573576
///
574577
/// It must be either `pin const` or `pin mut`.
575-
pub(crate) fn parse_pin_and_mut(&mut self) -> (Pinnedness, Mutability) {
576-
let pinned = if self.eat(&TokenKind::Ident(sym::pin, IdentIsRaw::No)) {
577-
Pinnedness::Pinned
578-
} else {
579-
Pinnedness::Not
580-
};
581-
582-
if pinned == Pinnedness::Pinned {
583-
self.psess.gated_spans.gate(sym::pin_ergonomics, self.prev_token.span);
584-
}
585-
586-
match pinned {
587-
Pinnedness::Pinned => {
588-
if self.eat_keyword(kw::Const) {
589-
(pinned, Mutability::Not)
590-
} else if self.eat_keyword(kw::Mut) {
591-
(pinned, Mutability::Mut)
578+
pub(crate) fn parse_pin_and_mut(&mut self) -> Option<(Pinnedness, Mutability)> {
579+
if self.token.is_ident_named(sym::pin) {
580+
let result = self.look_ahead(1, |token| {
581+
if token.is_keyword(kw::Const) {
582+
Some((Pinnedness::Pinned, Mutability::Not))
583+
} else if token.is_keyword(kw::Mut) {
584+
Some((Pinnedness::Pinned, Mutability::Mut))
592585
} else {
593-
// FIXME: Emit an error here
594-
595-
// self.dcx().emit_err();
596-
(pinned, Mutability::Not)
586+
None
597587
}
588+
});
589+
if result.is_some() {
590+
self.bump();
591+
self.bump();
598592
}
599-
Pinnedness::Not => (pinned, self.parse_mutability()),
593+
result
594+
} else {
595+
None
600596
}
601597
}
602598

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//@ check-pass
2+
#![feature(pin_ergonomics)]
3+
#![allow(dead_code, incomplete_features)]
4+
5+
// Handle the case where there's ambiguity between pin as a contextual keyword and pin as a path.
6+
7+
struct Foo;
8+
9+
mod pin {
10+
pub struct Foo;
11+
}
12+
13+
fn main() {
14+
let _x: &pin ::Foo = &pin::Foo;
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![feature(pin_ergonomics)]
2+
#![allow(incomplete_features)]
3+
4+
// Makes sure we don't accidentally accept `&pin Foo` without the `const` keyword.
5+
6+
fn main() {
7+
let _x: &pin i32 = todo!(); //~ ERROR found `i32`
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: expected one of `!`, `(`, `::`, `;`, `<`, or `=`, found `i32`
2+
--> $DIR/pin-sugar-no-const.rs:7:18
3+
|
4+
LL | let _x: &pin i32 = todo!();
5+
| - ^^^ expected one of `!`, `(`, `::`, `;`, `<`, or `=`
6+
| |
7+
| while parsing the type for `_x`
8+
|
9+
help: there is a keyword `in` with a similar name
10+
|
11+
LL | let _x: &in i32 = todo!();
12+
| ~~
13+
14+
error: aborting due to 1 previous error
15+

tests/ui/feature-gates/feature-gate-pin_ergonomics.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ use std::pin::Pin;
44

55
struct Foo;
66

7-
fn foo(_: Pin<&mut Foo>) {
8-
}
7+
fn foo(_: &pin mut Foo) {}
98

109
fn bar(mut x: Pin<&mut Foo>) {
1110
foo(x);
1211
foo(x); //~ ERROR use of moved value: `x`
1312
}
1413

14+
fn baz(_: &pin Foo) {}
15+
1516
fn main() {}

0 commit comments

Comments
 (0)