mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 06:22:00 +00:00
parser_fn_front_matter: allow const .. extern
This commit is contained in:
parent
c30f068dc8
commit
36a17e4067
@ -798,12 +798,12 @@ impl<'a> Parser<'a> {
|
||||
let defaultness = self.parse_defaultness();
|
||||
let (name, kind, generics) = if self.eat_keyword(kw::Type) {
|
||||
self.parse_assoc_ty()?
|
||||
} else if self.is_const_item() {
|
||||
self.parse_assoc_const()?
|
||||
} else if self.is_fn_front_matter() {
|
||||
self.parse_assoc_fn(at_end, &mut attrs, is_name_required)?
|
||||
} else if let Some(mac) = self.parse_assoc_macro_invoc("associated", Some(&vis), at_end)? {
|
||||
(Ident::invalid(), AssocItemKind::Macro(mac), Generics::default())
|
||||
} else {
|
||||
self.parse_assoc_fn(at_end, &mut attrs, is_name_required)?
|
||||
self.parse_assoc_const()?
|
||||
};
|
||||
|
||||
Ok(AssocItem {
|
||||
@ -819,12 +819,6 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns `true` if we are looking at `const ID`
|
||||
/// (returns `false` for things like `const fn`, etc.).
|
||||
fn is_const_item(&self) -> bool {
|
||||
self.token.is_keyword(kw::Const) && !self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe])
|
||||
}
|
||||
|
||||
/// This parses the grammar:
|
||||
///
|
||||
/// AssocConst = "const" Ident ":" Ty "=" Expr ";"
|
||||
@ -1034,21 +1028,20 @@ impl<'a> Parser<'a> {
|
||||
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
let lo = self.token.span;
|
||||
let visibility = self.parse_visibility(FollowedByType::No)?;
|
||||
let vis = self.parse_visibility(FollowedByType::No)?;
|
||||
|
||||
// FOREIGN TYPE ITEM
|
||||
if self.check_keyword(kw::Type) {
|
||||
return self.parse_item_foreign_type(visibility, lo, attrs);
|
||||
}
|
||||
|
||||
// FOREIGN STATIC ITEM
|
||||
if self.is_static_global() {
|
||||
// FOREIGN TYPE ITEM
|
||||
self.parse_item_foreign_type(vis, lo, attrs)
|
||||
} else if self.is_fn_front_matter() {
|
||||
// FOREIGN FUNCTION ITEM
|
||||
self.parse_item_foreign_fn(vis, lo, attrs)
|
||||
} else if self.is_static_global() {
|
||||
// FOREIGN STATIC ITEM
|
||||
self.bump(); // `static`
|
||||
return self.parse_item_foreign_static(visibility, lo, attrs);
|
||||
}
|
||||
|
||||
// Treat `const` as `static` for error recovery, but don't add it to expected tokens.
|
||||
if self.is_kw_followed_by_ident(kw::Const) {
|
||||
self.parse_item_foreign_static(vis, lo, attrs)
|
||||
} else if self.token.is_keyword(kw::Const) {
|
||||
// Treat `const` as `static` for error recovery, but don't add it to expected tokens.
|
||||
self.bump(); // `const`
|
||||
self.struct_span_err(self.prev_span, "extern items cannot be `const`")
|
||||
.span_suggestion(
|
||||
@ -1058,32 +1051,17 @@ impl<'a> Parser<'a> {
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
return self.parse_item_foreign_static(visibility, lo, attrs);
|
||||
}
|
||||
|
||||
// FOREIGN FUNCTION ITEM
|
||||
const MAY_INTRODUCE_FN: &[Symbol] = &[kw::Const, kw::Async, kw::Unsafe, kw::Extern, kw::Fn];
|
||||
if MAY_INTRODUCE_FN.iter().any(|&kw| self.check_keyword(kw)) {
|
||||
return self.parse_item_foreign_fn(visibility, lo, attrs);
|
||||
}
|
||||
|
||||
match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? {
|
||||
Some(mac) => Ok(P(ForeignItem {
|
||||
ident: Ident::invalid(),
|
||||
span: lo.to(self.prev_span),
|
||||
id: DUMMY_NODE_ID,
|
||||
attrs,
|
||||
vis: visibility,
|
||||
kind: ForeignItemKind::Macro(mac),
|
||||
tokens: None,
|
||||
})),
|
||||
None => {
|
||||
if !attrs.is_empty() {
|
||||
self.expected_item_err(&attrs)?;
|
||||
}
|
||||
|
||||
self.unexpected()
|
||||
self.parse_item_foreign_static(vis, lo, attrs)
|
||||
} else if let Some(mac) = self.parse_assoc_macro_invoc("extern", Some(&vis), &mut false)? {
|
||||
let kind = ForeignItemKind::Macro(mac);
|
||||
let span = lo.to(self.prev_span);
|
||||
let ident = Ident::invalid();
|
||||
Ok(P(ForeignItem { ident, span, id: DUMMY_NODE_ID, attrs, vis, kind, tokens: None }))
|
||||
} else {
|
||||
if !attrs.is_empty() {
|
||||
self.expected_item_err(&attrs)?;
|
||||
}
|
||||
self.unexpected()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1752,6 +1730,29 @@ impl<'a> Parser<'a> {
|
||||
Ok(body)
|
||||
}
|
||||
|
||||
/// Is the current token unambiguously the start of an `FnHeader`?
|
||||
fn is_fn_front_matter(&mut self) -> bool {
|
||||
// We use an over-approximation here.
|
||||
// `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
|
||||
// This works for `async fn` and similar as `async async` is an invalid
|
||||
// parse and `async fn` is never a valid parse on previous editions.
|
||||
const QUALIFIER: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern];
|
||||
|
||||
let check_qual_follow = |this: &mut Self, dist| {
|
||||
this.look_ahead(dist, |t| {
|
||||
// ...qualified and then `fn`, e.g. `const fn`.
|
||||
t.is_keyword(kw::Fn)
|
||||
// Two qualifiers. This is enough.
|
||||
|| QUALIFIER.iter().any(|&kw| t.is_keyword(kw))
|
||||
})
|
||||
};
|
||||
self.check_keyword(kw::Fn) // Definitely an `fn`.
|
||||
// `$qual fn` or `$qual $qual`:
|
||||
|| QUALIFIER.iter().any(|&kw| self.check_keyword(kw)) && check_qual_follow(self, 1)
|
||||
// `extern ABI fn` or `extern ABI $qual`; skip 1 for the ABI.
|
||||
|| self.check_keyword(kw::Extern) && check_qual_follow(self, 2)
|
||||
}
|
||||
|
||||
/// Parses all the "front matter" (or "qualifiers") for a `fn` declaration,
|
||||
/// up to and including the `fn` keyword. The formal grammar is:
|
||||
///
|
||||
@ -1763,16 +1764,13 @@ impl<'a> Parser<'a> {
|
||||
fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
|
||||
let constness = self.parse_constness();
|
||||
let asyncness = self.parse_asyncness();
|
||||
let unsafety = self.parse_unsafety();
|
||||
let ext = self.parse_extern()?;
|
||||
|
||||
if let Async::Yes { span, .. } = asyncness {
|
||||
self.ban_async_in_2015(span);
|
||||
}
|
||||
let unsafety = self.parse_unsafety();
|
||||
let (constness, unsafety, ext) = if let Const::Yes(_) = constness {
|
||||
(constness, unsafety, Extern::None)
|
||||
} else {
|
||||
let ext = self.parse_extern()?;
|
||||
(Const::No, unsafety, ext)
|
||||
};
|
||||
|
||||
if !self.eat_keyword(kw::Fn) {
|
||||
// It is possible for `expect_one_of` to recover given the contents of
|
||||
// `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
|
||||
@ -1781,6 +1779,7 @@ impl<'a> Parser<'a> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
Ok(FnHeader { constness, unsafety, asyncness, ext })
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
|
||||
fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
|
||||
self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,5 @@ trait T {
|
||||
});
|
||||
//~^ ERROR expected one of `async`
|
||||
//~| ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
|
||||
//~| ERROR expected identifier, found `;`
|
||||
Some(4)
|
||||
}
|
||||
|
@ -13,11 +13,5 @@ LL | let _ = if true {
|
||||
LL | });
|
||||
| ^ help: `}` may belong here
|
||||
|
||||
error: expected identifier, found `;`
|
||||
--> $DIR/issue-60075.rs:6:11
|
||||
|
|
||||
LL | });
|
||||
| ^ expected identifier
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -18,9 +18,9 @@ fn main() {
|
||||
unsafe fn ft2(); // OK.
|
||||
const fn ft3(); //~ ERROR trait fns cannot be declared const
|
||||
extern "C" fn ft4(); // OK.
|
||||
/* const */ async unsafe extern "C" fn ft5();
|
||||
const async unsafe extern "C" fn ft5();
|
||||
//~^ ERROR trait fns cannot be declared `async`
|
||||
//^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically.
|
||||
//~| ERROR trait fns cannot be declared const
|
||||
}
|
||||
|
||||
struct Y;
|
||||
@ -30,10 +30,10 @@ fn main() {
|
||||
unsafe fn ft2() {} // OK.
|
||||
const fn ft3() {} //~ ERROR trait fns cannot be declared const
|
||||
extern "C" fn ft4() {}
|
||||
/* const */ async unsafe extern "C" fn ft5() {}
|
||||
const async unsafe extern "C" fn ft5() {}
|
||||
//~^ ERROR trait fns cannot be declared `async`
|
||||
//~| ERROR trait fns cannot be declared const
|
||||
//~| ERROR method `ft5` has an incompatible type for trait
|
||||
//^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically.
|
||||
}
|
||||
|
||||
impl Y {
|
||||
@ -41,8 +41,7 @@ fn main() {
|
||||
unsafe fn fi2() {} // OK.
|
||||
const fn fi3() {} // OK.
|
||||
extern "C" fn fi4() {} // OK.
|
||||
/* const */ async unsafe extern "C" fn fi5() {} // OK.
|
||||
//^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically.
|
||||
const async unsafe extern "C" fn fi5() {} // OK.
|
||||
}
|
||||
|
||||
extern {
|
||||
@ -50,8 +49,6 @@ fn main() {
|
||||
unsafe fn fe2(); //~ ERROR functions in `extern` blocks cannot have qualifiers
|
||||
const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers
|
||||
extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot have qualifiers
|
||||
/* const */ async unsafe extern "C" fn fe5();
|
||||
//~^ ERROR functions in `extern` blocks cannot have qualifiers
|
||||
//^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically.
|
||||
const async unsafe extern "C" fn fe5(); //~ ERROR functions in `extern` blocks
|
||||
}
|
||||
}
|
||||
|
@ -15,13 +15,19 @@ error[E0379]: trait fns cannot be declared const
|
||||
LL | const fn ft3();
|
||||
| ^^^^^ trait fns cannot be const
|
||||
|
||||
error[E0706]: trait fns cannot be declared `async`
|
||||
--> $DIR/fn-header-semantic-fail.rs:21:21
|
||||
error[E0379]: trait fns cannot be declared const
|
||||
--> $DIR/fn-header-semantic-fail.rs:21:9
|
||||
|
|
||||
LL | /* const */ async unsafe extern "C" fn ft5();
|
||||
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| `async` because of this
|
||||
LL | const async unsafe extern "C" fn ft5();
|
||||
| ^^^^^ trait fns cannot be const
|
||||
|
||||
error[E0706]: trait fns cannot be declared `async`
|
||||
--> $DIR/fn-header-semantic-fail.rs:21:9
|
||||
|
|
||||
LL | const async unsafe extern "C" fn ft5();
|
||||
| ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| `async` because of this
|
||||
|
|
||||
= note: `async` trait functions are not currently supported
|
||||
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
||||
@ -43,19 +49,25 @@ error[E0379]: trait fns cannot be declared const
|
||||
LL | const fn ft3() {}
|
||||
| ^^^^^ trait fns cannot be const
|
||||
|
||||
error[E0706]: trait fns cannot be declared `async`
|
||||
--> $DIR/fn-header-semantic-fail.rs:33:21
|
||||
error[E0379]: trait fns cannot be declared const
|
||||
--> $DIR/fn-header-semantic-fail.rs:33:9
|
||||
|
|
||||
LL | /* const */ async unsafe extern "C" fn ft5() {}
|
||||
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| `async` because of this
|
||||
LL | const async unsafe extern "C" fn ft5() {}
|
||||
| ^^^^^ trait fns cannot be const
|
||||
|
||||
error[E0706]: trait fns cannot be declared `async`
|
||||
--> $DIR/fn-header-semantic-fail.rs:33:9
|
||||
|
|
||||
LL | const async unsafe extern "C" fn ft5() {}
|
||||
| ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| `async` because of this
|
||||
|
|
||||
= note: `async` trait functions are not currently supported
|
||||
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:49:18
|
||||
--> $DIR/fn-header-semantic-fail.rs:48:18
|
||||
|
|
||||
LL | extern {
|
||||
| ------ in this `extern` block
|
||||
@ -65,7 +77,7 @@ LL | async fn fe1();
|
||||
| help: remove the qualifiers: `fn`
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:50:19
|
||||
--> $DIR/fn-header-semantic-fail.rs:49:19
|
||||
|
|
||||
LL | extern {
|
||||
| ------ in this `extern` block
|
||||
@ -76,7 +88,7 @@ LL | unsafe fn fe2();
|
||||
| help: remove the qualifiers: `fn`
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:51:18
|
||||
--> $DIR/fn-header-semantic-fail.rs:50:18
|
||||
|
|
||||
LL | extern {
|
||||
| ------ in this `extern` block
|
||||
@ -87,7 +99,7 @@ LL | const fn fe3();
|
||||
| help: remove the qualifiers: `fn`
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:52:23
|
||||
--> $DIR/fn-header-semantic-fail.rs:51:23
|
||||
|
|
||||
LL | extern {
|
||||
| ------ in this `extern` block
|
||||
@ -98,15 +110,15 @@ LL | extern "C" fn fe4();
|
||||
| help: remove the qualifiers: `fn`
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:53:48
|
||||
--> $DIR/fn-header-semantic-fail.rs:52:42
|
||||
|
|
||||
LL | extern {
|
||||
| ------ in this `extern` block
|
||||
...
|
||||
LL | /* const */ async unsafe extern "C" fn fe5();
|
||||
| ---------------------------^^^
|
||||
| |
|
||||
| help: remove the qualifiers: `fn`
|
||||
LL | const async unsafe extern "C" fn fe5();
|
||||
| ---------------------------------^^^
|
||||
| |
|
||||
| help: remove the qualifiers: `fn`
|
||||
|
||||
error[E0053]: method `ft1` has an incompatible type for trait
|
||||
--> $DIR/fn-header-semantic-fail.rs:28:24
|
||||
@ -124,21 +136,21 @@ LL | async fn ft1() {}
|
||||
found fn pointer `fn() -> impl std::future::Future`
|
||||
|
||||
error[E0053]: method `ft5` has an incompatible type for trait
|
||||
--> $DIR/fn-header-semantic-fail.rs:33:54
|
||||
--> $DIR/fn-header-semantic-fail.rs:33:48
|
||||
|
|
||||
LL | /* const */ async unsafe extern "C" fn ft5();
|
||||
| - type in trait
|
||||
LL | const async unsafe extern "C" fn ft5();
|
||||
| - type in trait
|
||||
...
|
||||
LL | /* const */ async unsafe extern "C" fn ft5() {}
|
||||
| ^
|
||||
| |
|
||||
| the `Output` of this `async fn`'s found opaque type
|
||||
| expected `()`, found opaque type
|
||||
LL | const async unsafe extern "C" fn ft5() {}
|
||||
| ^
|
||||
| |
|
||||
| the `Output` of this `async fn`'s found opaque type
|
||||
| expected `()`, found opaque type
|
||||
|
|
||||
= note: expected fn pointer `unsafe extern "C" fn()`
|
||||
found fn pointer `unsafe extern "C" fn() -> impl std::future::Future`
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
error: aborting due to 15 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0053, E0379, E0706.
|
||||
For more information about an error, try `rustc --explain E0053`.
|
||||
|
@ -22,8 +22,7 @@ fn syntax() {
|
||||
unsafe fn f();
|
||||
const fn f();
|
||||
extern "C" fn f();
|
||||
/* const */ async unsafe extern "C" fn f();
|
||||
//^ FIXME(Centril): `const` should be legal syntactically.
|
||||
const async unsafe extern "C" fn f();
|
||||
}
|
||||
|
||||
impl X for Y {
|
||||
@ -31,8 +30,7 @@ fn syntax() {
|
||||
unsafe fn f();
|
||||
const fn f();
|
||||
extern "C" fn f();
|
||||
/* const */ async unsafe extern "C" fn f();
|
||||
//^ FIXME(Centril): `const` should be legal syntactically.
|
||||
const async unsafe extern "C" fn f();
|
||||
}
|
||||
|
||||
impl Y {
|
||||
@ -40,8 +38,7 @@ fn syntax() {
|
||||
unsafe fn f();
|
||||
const fn f();
|
||||
extern "C" fn f();
|
||||
/* const */ async unsafe extern "C" fn f();
|
||||
//^ FIXME(Centril): `const` should be legal syntactically.
|
||||
const async unsafe extern "C" fn f();
|
||||
}
|
||||
|
||||
extern {
|
||||
@ -49,7 +46,6 @@ fn syntax() {
|
||||
unsafe fn f();
|
||||
const fn f();
|
||||
extern "C" fn f();
|
||||
/* const */ async unsafe extern "C" fn f();
|
||||
//^ FIXME(Centril): `const` should be legal syntactically.
|
||||
const async unsafe extern "C" fn f();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user