Rollup merge of #64910 - Centril:params-cleanup, r=petrochenkov

syntax: cleanup param, method, and misc parsing

Do some misc cleanup of the parser:
- Method and parameter parsing is refactored.
- A parser for `const | mut` is introduced that https://github.com/rust-lang/rust/pull/64588 can reuse.
- Some other misc parsing.

Next up in a different PR:
- ~Implementing https://github.com/rust-lang/rust/issues/64252.~ -- maybe some other time...
- Heavily restructuring up `item.rs` which is a mess (hopefully, no promises ^^).

r? @petrochenkov
This commit is contained in:
Mazdak Farrokhzad 2019-10-01 23:56:21 +02:00 committed by GitHub
commit db9689333a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 518 additions and 586 deletions

View file

@ -1180,7 +1180,7 @@ impl<'a> Parser<'a> {
}
}
crate fn expected_semi_or_open_brace(&mut self) -> PResult<'a, ast::TraitItem> {
crate fn expected_semi_or_open_brace<T>(&mut self) -> PResult<'a, T> {
let token_str = self.this_token_descr();
let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str));
err.span_label(self.token.span, "expected `;` or `{`");

View file

@ -511,13 +511,15 @@ impl<'a> Parser<'a> {
is_present
}
/// If the next token is the given keyword, returns `true` without eating it.
/// An expectation is also added for diagnostics purposes.
fn check_keyword(&mut self, kw: Symbol) -> bool {
self.expected_tokens.push(TokenType::Keyword(kw));
self.token.is_keyword(kw)
}
/// If the next token is the given keyword, eats it and returns
/// `true`. Otherwise, returns `false`.
/// If the next token is the given keyword, eats it and returns `true`.
/// Otherwise, returns `false`. An expectation is also added for diagnostics purposes.
pub fn eat_keyword(&mut self, kw: Symbol) -> bool {
if self.check_keyword(kw) {
self.bump();
@ -547,40 +549,38 @@ impl<'a> Parser<'a> {
}
}
crate fn check_ident(&mut self) -> bool {
if self.token.is_ident() {
fn check_or_expected(&mut self, ok: bool, typ: TokenType) -> bool {
if ok {
true
} else {
self.expected_tokens.push(TokenType::Ident);
self.expected_tokens.push(typ);
false
}
}
crate fn check_ident(&mut self) -> bool {
self.check_or_expected(self.token.is_ident(), TokenType::Ident)
}
fn check_path(&mut self) -> bool {
if self.token.is_path_start() {
true
} else {
self.expected_tokens.push(TokenType::Path);
false
}
self.check_or_expected(self.token.is_path_start(), TokenType::Path)
}
fn check_type(&mut self) -> bool {
if self.token.can_begin_type() {
true
} else {
self.expected_tokens.push(TokenType::Type);
false
}
self.check_or_expected(self.token.can_begin_type(), TokenType::Type)
}
fn check_const_arg(&mut self) -> bool {
if self.token.can_begin_const_arg() {
true
} else {
self.expected_tokens.push(TokenType::Const);
false
}
self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const)
}
/// Checks to see if the next token is either `+` or `+=`.
/// Otherwise returns `false`.
fn check_plus(&mut self) -> bool {
self.check_or_expected(
self.token.is_like_plus(),
TokenType::Token(token::BinOp(token::Plus)),
)
}
/// Expects and consumes a `+`. if `+=` is seen, replaces it with a `=`
@ -604,18 +604,6 @@ impl<'a> Parser<'a> {
}
}
/// Checks to see if the next token is either `+` or `+=`.
/// Otherwise returns `false`.
fn check_plus(&mut self) -> bool {
if self.token.is_like_plus() {
true
}
else {
self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus)));
false
}
}
/// Expects and consumes an `&`. If `&&` is seen, replaces it with a single
/// `&` and continues. If an `&` is not seen, signals an error.
fn expect_and(&mut self) -> PResult<'a, ()> {
@ -910,15 +898,15 @@ impl<'a> Parser<'a> {
self.expected_tokens.clear();
}
pub fn look_ahead<R, F>(&self, dist: usize, f: F) -> R where
F: FnOnce(&Token) -> R,
{
/// Look-ahead `dist` tokens of `self.token` and get access to that token there.
/// When `dist == 0` then the current token is looked at.
pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R {
if dist == 0 {
return f(&self.token);
return looker(&self.token);
}
let frame = &self.token_cursor.frame;
f(&match frame.tree_cursor.look_ahead(dist - 1) {
looker(&match frame.tree_cursor.look_ahead(dist - 1) {
Some(tree) => match tree {
TokenTree::Token(token) => token,
TokenTree::Delimited(dspan, delim, _) =>
@ -954,109 +942,6 @@ impl<'a> Parser<'a> {
}
}
fn is_named_argument(&self) -> bool {
let offset = match self.token.kind {
token::Interpolated(ref nt) => match **nt {
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
_ => 0,
}
token::BinOp(token::And) | token::AndAnd => 1,
_ if self.token.is_keyword(kw::Mut) => 1,
_ => 0,
};
self.look_ahead(offset, |t| t.is_ident()) &&
self.look_ahead(offset + 1, |t| t == &token::Colon)
}
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
/// error.
/// This version of parse param doesn't necessarily require identifier names.
fn parse_param_general(
&mut self,
is_self_allowed: bool,
is_trait_item: bool,
allow_c_variadic: bool,
is_name_required: impl Fn(&token::Token) -> bool,
) -> PResult<'a, Param> {
let lo = self.token.span;
let attrs = self.parse_outer_attributes()?;
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
if let Some(mut param) = self.parse_self_param()? {
param.attrs = attrs.into();
return if is_self_allowed {
Ok(param)
} else {
self.recover_bad_self_param(param, is_trait_item)
};
}
let is_name_required = is_name_required(&self.token);
let (pat, ty) = if is_name_required || self.is_named_argument() {
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
let pat = self.parse_fn_param_pat()?;
if let Err(mut err) = self.expect(&token::Colon) {
if let Some(ident) = self.parameter_without_type(
&mut err,
pat,
is_name_required,
is_trait_item,
) {
err.emit();
return Ok(dummy_arg(ident));
} else {
return Err(err);
}
}
self.eat_incorrect_doc_comment_for_param_type();
(pat, self.parse_ty_common(true, true, allow_c_variadic)?)
} else {
debug!("parse_param_general ident_to_pat");
let parser_snapshot_before_ty = self.clone();
self.eat_incorrect_doc_comment_for_param_type();
let mut ty = self.parse_ty_common(true, true, allow_c_variadic);
if ty.is_ok() && self.token != token::Comma &&
self.token != token::CloseDelim(token::Paren) {
// This wasn't actually a type, but a pattern looking like a type,
// so we are going to rollback and re-parse for recovery.
ty = self.unexpected();
}
match ty {
Ok(ty) => {
let ident = Ident::new(kw::Invalid, self.prev_span);
let bm = BindingMode::ByValue(Mutability::Immutable);
let pat = self.mk_pat_ident(ty.span, bm, ident);
(pat, ty)
}
Err(mut err) => {
// If this is a C-variadic argument and we hit an error, return the
// error.
if self.token == token::DotDotDot {
return Err(err);
}
// Recover from attempting to parse the argument as a type without pattern.
err.cancel();
mem::replace(self, parser_snapshot_before_ty);
self.recover_arg_parse()?
}
}
};
let span = lo.to(self.token.span);
Ok(Param {
attrs: attrs.into(),
id: ast::DUMMY_NODE_ID,
is_placeholder: false,
pat,
span,
ty,
})
}
/// Parses mutability (`mut` or nothing).
fn parse_mutability(&mut self) -> Mutability {
if self.eat_keyword(kw::Mut) {
@ -1066,6 +951,17 @@ impl<'a> Parser<'a> {
}
}
/// Possibly parses mutability (`const` or `mut`).
fn parse_const_or_mut(&mut self) -> Option<Mutability> {
if self.eat_keyword(kw::Mut) {
Some(Mutability::Mutable)
} else if self.eat_keyword(kw::Const) {
Some(Mutability::Immutable)
} else {
None
}
}
fn parse_field_name(&mut self) -> PResult<'a, Ident> {
if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) =
self.token.kind {
@ -1100,9 +996,10 @@ impl<'a> Parser<'a> {
Ok((delim, tts.into()))
}
fn parse_or_use_outer_attributes(&mut self,
already_parsed_attrs: Option<ThinVec<Attribute>>)
-> PResult<'a, ThinVec<Attribute>> {
fn parse_or_use_outer_attributes(
&mut self,
already_parsed_attrs: Option<ThinVec<Attribute>>,
) -> PResult<'a, ThinVec<Attribute>> {
if let Some(attrs) = already_parsed_attrs {
Ok(attrs)
} else {
@ -1189,53 +1086,52 @@ impl<'a> Parser<'a> {
/// Evaluates the closure with restrictions in place.
///
/// Afters the closure is evaluated, restrictions are reset.
fn with_res<F, T>(&mut self, r: Restrictions, f: F) -> T
where F: FnOnce(&mut Self) -> T
{
fn with_res<T>(&mut self, res: Restrictions, f: impl FnOnce(&mut Self) -> T) -> T {
let old = self.restrictions;
self.restrictions = r;
let r = f(self);
self.restrictions = res;
let res = f(self);
self.restrictions = old;
return r;
res
}
fn parse_fn_params(&mut self, named_params: bool, allow_c_variadic: bool)
-> PResult<'a, Vec<Param>> {
fn parse_fn_params(
&mut self,
named_params: bool,
allow_c_variadic: bool,
) -> PResult<'a, Vec<Param>> {
let sp = self.token.span;
let do_not_enforce_named_params_for_c_variadic = |token: &token::Token| {
match token.kind {
token::DotDotDot => false,
_ => named_params,
}
};
let mut c_variadic = false;
let (params, _): (Vec<Option<Param>>, _) = self.parse_paren_comma_seq(|p| {
let do_not_enforce_named_arguments_for_c_variadic =
|token: &token::Token| -> bool {
if token == &token::DotDotDot {
false
} else {
named_params
}
};
let (params, _) = self.parse_paren_comma_seq(|p| {
match p.parse_param_general(
false,
false,
allow_c_variadic,
do_not_enforce_named_arguments_for_c_variadic
do_not_enforce_named_params_for_c_variadic,
) {
Ok(param) => {
Ok(param) => Ok(
if let TyKind::CVarArgs = param.ty.kind {
c_variadic = true;
if p.token != token::CloseDelim(token::Paren) {
let span = p.token.span;
p.span_err(span,
"`...` must be the last argument of a C-variadic function");
p.span_err(
p.token.span,
"`...` must be the last argument of a C-variadic function",
);
// FIXME(eddyb) this should probably still push `CVarArgs`.
// Maybe AST validation/HIR lowering should emit the above error?
Ok(None)
None
} else {
Ok(Some(param))
Some(param)
}
} else {
Ok(Some(param))
Some(param)
}
},
),
Err(mut e) => {
e.emit();
let lo = p.prev_span;
@ -1251,124 +1147,15 @@ impl<'a> Parser<'a> {
let params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
if c_variadic && params.len() <= 1 {
self.span_err(sp,
"C-variadic function must be declared with at least one named argument");
self.span_err(
sp,
"C-variadic function must be declared with at least one named argument",
);
}
Ok(params)
}
/// Returns the parsed optional self parameter and whether a self shortcut was used.
///
/// See `parse_self_param_with_attrs` to collect attributes.
fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
let expect_ident = |this: &mut Self| match this.token.kind {
// Preserve hygienic context.
token::Ident(name, _) =>
{ let span = this.token.span; this.bump(); Ident::new(name, span) }
_ => unreachable!()
};
let isolated_self = |this: &mut Self, n| {
this.look_ahead(n, |t| t.is_keyword(kw::SelfLower)) &&
this.look_ahead(n + 1, |t| t != &token::ModSep)
};
// Parse optional `self` parameter of a method.
// Only a limited set of initial token sequences is considered `self` parameters; anything
// else is parsed as a normal function parameter list, so some lookahead is required.
let eself_lo = self.token.span;
let (eself, eself_ident, eself_hi) = match self.token.kind {
token::BinOp(token::And) => {
// `&self`
// `&mut self`
// `&'lt self`
// `&'lt mut self`
// `&not_self`
(if isolated_self(self, 1) {
self.bump();
SelfKind::Region(None, Mutability::Immutable)
} else if self.is_keyword_ahead(1, &[kw::Mut]) &&
isolated_self(self, 2) {
self.bump();
self.bump();
SelfKind::Region(None, Mutability::Mutable)
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
isolated_self(self, 2) {
self.bump();
let lt = self.expect_lifetime();
SelfKind::Region(Some(lt), Mutability::Immutable)
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
self.is_keyword_ahead(2, &[kw::Mut]) &&
isolated_self(self, 3) {
self.bump();
let lt = self.expect_lifetime();
self.bump();
SelfKind::Region(Some(lt), Mutability::Mutable)
} else {
return Ok(None);
}, expect_ident(self), self.prev_span)
}
token::BinOp(token::Star) => {
// `*self`
// `*const self`
// `*mut self`
// `*not_self`
// Emit special error for `self` cases.
let msg = "cannot pass `self` by raw pointer";
(if isolated_self(self, 1) {
self.bump();
self.struct_span_err(self.token.span, msg)
.span_label(self.token.span, msg)
.emit();
SelfKind::Value(Mutability::Immutable)
} else if self.look_ahead(1, |t| t.is_mutability()) &&
isolated_self(self, 2) {
self.bump();
self.bump();
self.struct_span_err(self.token.span, msg)
.span_label(self.token.span, msg)
.emit();
SelfKind::Value(Mutability::Immutable)
} else {
return Ok(None);
}, expect_ident(self), self.prev_span)
}
token::Ident(..) => {
if isolated_self(self, 0) {
// `self`
// `self: TYPE`
let eself_ident = expect_ident(self);
let eself_hi = self.prev_span;
(if self.eat(&token::Colon) {
let ty = self.parse_ty()?;
SelfKind::Explicit(ty, Mutability::Immutable)
} else {
SelfKind::Value(Mutability::Immutable)
}, eself_ident, eself_hi)
} else if self.token.is_keyword(kw::Mut) &&
isolated_self(self, 1) {
// `mut self`
// `mut self: TYPE`
self.bump();
let eself_ident = expect_ident(self);
let eself_hi = self.prev_span;
(if self.eat(&token::Colon) {
let ty = self.parse_ty()?;
SelfKind::Explicit(ty, Mutability::Mutable)
} else {
SelfKind::Value(Mutability::Mutable)
}, eself_ident, eself_hi)
} else {
return Ok(None);
}
}
_ => return Ok(None),
};
let eself = source_map::respan(eself_lo.to(eself_hi), eself);
Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident)))
}
/// Parses the parameter list and result type of a function that may have a `self` parameter.
fn parse_fn_decl_with_self(
&mut self,
@ -1392,6 +1179,216 @@ impl<'a> Parser<'a> {
}))
}
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
/// error.
/// This version of parse param doesn't necessarily require identifier names.
fn parse_param_general(
&mut self,
is_self_allowed: bool,
is_trait_item: bool,
allow_c_variadic: bool,
is_name_required: impl Fn(&token::Token) -> bool,
) -> PResult<'a, Param> {
let lo = self.token.span;
let attrs = self.parse_outer_attributes()?;
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
if let Some(mut param) = self.parse_self_param()? {
param.attrs = attrs.into();
return if is_self_allowed {
Ok(param)
} else {
self.recover_bad_self_param(param, is_trait_item)
};
}
let is_name_required = is_name_required(&self.token);
let (pat, ty) = if is_name_required || self.is_named_param() {
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
let pat = self.parse_fn_param_pat()?;
if let Err(mut err) = self.expect(&token::Colon) {
if let Some(ident) = self.parameter_without_type(
&mut err,
pat,
is_name_required,
is_trait_item,
) {
err.emit();
return Ok(dummy_arg(ident));
} else {
return Err(err);
}
}
self.eat_incorrect_doc_comment_for_param_type();
(pat, self.parse_ty_common(true, true, allow_c_variadic)?)
} else {
debug!("parse_param_general ident_to_pat");
let parser_snapshot_before_ty = self.clone();
self.eat_incorrect_doc_comment_for_param_type();
let mut ty = self.parse_ty_common(true, true, allow_c_variadic);
if ty.is_ok() && self.token != token::Comma &&
self.token != token::CloseDelim(token::Paren) {
// This wasn't actually a type, but a pattern looking like a type,
// so we are going to rollback and re-parse for recovery.
ty = self.unexpected();
}
match ty {
Ok(ty) => {
let ident = Ident::new(kw::Invalid, self.prev_span);
let bm = BindingMode::ByValue(Mutability::Immutable);
let pat = self.mk_pat_ident(ty.span, bm, ident);
(pat, ty)
}
// If this is a C-variadic argument and we hit an error, return the error.
Err(err) if self.token == token::DotDotDot => return Err(err),
// Recover from attempting to parse the argument as a type without pattern.
Err(mut err) => {
err.cancel();
mem::replace(self, parser_snapshot_before_ty);
self.recover_arg_parse()?
}
}
};
let span = lo.to(self.token.span);
Ok(Param {
attrs: attrs.into(),
id: ast::DUMMY_NODE_ID,
is_placeholder: false,
pat,
span,
ty,
})
}
/// Returns the parsed optional self parameter and whether a self shortcut was used.
///
/// See `parse_self_param_with_attrs` to collect attributes.
fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
// Extract an identifier *after* having confirmed that the token is one.
let expect_self_ident = |this: &mut Self| {
match this.token.kind {
// Preserve hygienic context.
token::Ident(name, _) => {
let span = this.token.span;
this.bump();
Ident::new(name, span)
}
_ => unreachable!(),
}
};
// Is `self` `n` tokens ahead?
let is_isolated_self = |this: &Self, n| {
this.is_keyword_ahead(n, &[kw::SelfLower])
&& this.look_ahead(n + 1, |t| t != &token::ModSep)
};
// Is `mut self` `n` tokens ahead?
let is_isolated_mut_self = |this: &Self, n| {
this.is_keyword_ahead(n, &[kw::Mut])
&& is_isolated_self(this, n + 1)
};
// Parse `self` or `self: TYPE`. We already know the current token is `self`.
let parse_self_possibly_typed = |this: &mut Self, m| {
let eself_ident = expect_self_ident(this);
let eself_hi = this.prev_span;
let eself = if this.eat(&token::Colon) {
SelfKind::Explicit(this.parse_ty()?, m)
} else {
SelfKind::Value(m)
};
Ok((eself, eself_ident, eself_hi))
};
// Recover for the grammar `*self`, `*const self`, and `*mut self`.
let recover_self_ptr = |this: &mut Self| {
let msg = "cannot pass `self` by raw pointer";
let span = this.token.span;
this.struct_span_err(span, msg)
.span_label(span, msg)
.emit();
Ok((SelfKind::Value(Mutability::Immutable), expect_self_ident(this), this.prev_span))
};
// Parse optional `self` parameter of a method.
// Only a limited set of initial token sequences is considered `self` parameters; anything
// else is parsed as a normal function parameter list, so some lookahead is required.
let eself_lo = self.token.span;
let (eself, eself_ident, eself_hi) = match self.token.kind {
token::BinOp(token::And) => {
let eself = if is_isolated_self(self, 1) {
// `&self`
self.bump();
SelfKind::Region(None, Mutability::Immutable)
} else if is_isolated_mut_self(self, 1) {
// `&mut self`
self.bump();
self.bump();
SelfKind::Region(None, Mutability::Mutable)
} else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) {
// `&'lt self`
self.bump();
let lt = self.expect_lifetime();
SelfKind::Region(Some(lt), Mutability::Immutable)
} else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_mut_self(self, 2) {
// `&'lt mut self`
self.bump();
let lt = self.expect_lifetime();
self.bump();
SelfKind::Region(Some(lt), Mutability::Mutable)
} else {
// `&not_self`
return Ok(None);
};
(eself, expect_self_ident(self), self.prev_span)
}
// `*self`
token::BinOp(token::Star) if is_isolated_self(self, 1) => {
self.bump();
recover_self_ptr(self)?
}
// `*mut self` and `*const self`
token::BinOp(token::Star) if
self.look_ahead(1, |t| t.is_mutability())
&& is_isolated_self(self, 2) =>
{
self.bump();
self.bump();
recover_self_ptr(self)?
}
// `self` and `self: TYPE`
token::Ident(..) if is_isolated_self(self, 0) => {
parse_self_possibly_typed(self, Mutability::Immutable)?
}
// `mut self` and `mut self: TYPE`
token::Ident(..) if is_isolated_mut_self(self, 0) => {
self.bump();
parse_self_possibly_typed(self, Mutability::Mutable)?
}
_ => return Ok(None),
};
let eself = source_map::respan(eself_lo.to(eself_hi), eself);
Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident)))
}
fn is_named_param(&self) -> bool {
let offset = match self.token.kind {
token::Interpolated(ref nt) => match **nt {
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
_ => 0,
}
token::BinOp(token::And) | token::AndAnd => 1,
_ if self.token.is_keyword(kw::Mut) => 1,
_ => 0,
};
self.look_ahead(offset, |t| t.is_ident()) &&
self.look_ahead(offset + 1, |t| t == &token::Colon)
}
fn is_crate_vis(&self) -> bool {
self.token.is_keyword(kw::Crate) && self.look_ahead(1, |t| t != &token::ModSep)
}
@ -1423,100 +1420,107 @@ impl<'a> Parser<'a> {
// `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`.
// Because of this, we only `bump` the `(` if we're assured it is appropriate to do so
// by the following tokens.
if self.is_keyword_ahead(1, &[kw::Crate]) &&
self.look_ahead(2, |t| t != &token::ModSep) // account for `pub(crate::foo)`
if self.is_keyword_ahead(1, &[kw::Crate])
&& self.look_ahead(2, |t| t != &token::ModSep) // account for `pub(crate::foo)`
{
// `pub(crate)`
// Parse `pub(crate)`.
self.bump(); // `(`
self.bump(); // `crate`
self.expect(&token::CloseDelim(token::Paren))?; // `)`
let vis = respan(
lo.to(self.prev_span),
VisibilityKind::Crate(CrateSugar::PubCrate),
);
return Ok(vis)
let vis = VisibilityKind::Crate(CrateSugar::PubCrate);
return Ok(respan(lo.to(self.prev_span), vis));
} else if self.is_keyword_ahead(1, &[kw::In]) {
// `pub(in path)`
// Parse `pub(in path)`.
self.bump(); // `(`
self.bump(); // `in`
let path = self.parse_path(PathStyle::Mod)?; // `path`
self.expect(&token::CloseDelim(token::Paren))?; // `)`
let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted {
let vis = VisibilityKind::Restricted {
path: P(path),
id: ast::DUMMY_NODE_ID,
});
return Ok(vis)
} else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) &&
self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower])
};
return Ok(respan(lo.to(self.prev_span), vis));
} else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren))
&& self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower])
{
// `pub(self)` or `pub(super)`
// Parse `pub(self)` or `pub(super)`.
self.bump(); // `(`
let path = self.parse_path(PathStyle::Mod)?; // `super`/`self`
self.expect(&token::CloseDelim(token::Paren))?; // `)`
let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted {
let vis = VisibilityKind::Restricted {
path: P(path),
id: ast::DUMMY_NODE_ID,
});
return Ok(vis)
} else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct
// `pub(something) fn ...` or `struct X { pub(something) y: Z }`
self.bump(); // `(`
let msg = "incorrect visibility restriction";
let suggestion = r##"some possible visibility restrictions are:
`pub(crate)`: visible only on the current crate
`pub(super)`: visible only in the current module's parent
`pub(in path::to::module)`: visible only on the specified path"##;
let path = self.parse_path(PathStyle::Mod)?;
let sp = path.span;
let help_msg = format!("make this visible only to module `{}` with `in`", path);
self.expect(&token::CloseDelim(token::Paren))?; // `)`
struct_span_err!(self.sess.span_diagnostic, sp, E0704, "{}", msg)
.help(suggestion)
.span_suggestion(
sp,
&help_msg,
format!("in {}", path),
Applicability::MachineApplicable,
)
.emit(); // Emit diagnostic, but continue with public visibility.
};
return Ok(respan(lo.to(self.prev_span), vis));
} else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct.
self.recover_incorrect_vis_restriction()?;
// Emit diagnostic, but continue with public visibility.
}
}
Ok(respan(lo, VisibilityKind::Public))
}
/// Recovery for e.g. `pub(something) fn ...` or `struct X { pub(something) y: Z }`
fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> {
self.bump(); // `(`
let path = self.parse_path(PathStyle::Mod)?;
self.expect(&token::CloseDelim(token::Paren))?; // `)`
let msg = "incorrect visibility restriction";
let suggestion = r##"some possible visibility restrictions are:
`pub(crate)`: visible only on the current crate
`pub(super)`: visible only in the current module's parent
`pub(in path::to::module)`: visible only on the specified path"##;
struct_span_err!(self.sess.span_diagnostic, path.span, E0704, "{}", msg)
.help(suggestion)
.span_suggestion(
path.span,
&format!("make this visible only to module `{}` with `in`", path),
format!("in {}", path),
Applicability::MachineApplicable,
)
.emit();
Ok(())
}
/// Parses a string as an ABI spec on an extern type or module. Consumes
/// the `extern` keyword, if one is found.
fn parse_opt_abi(&mut self) -> PResult<'a, Option<Abi>> {
match self.token.kind {
token::Literal(token::Lit { kind: token::Str, symbol, suffix }) |
token::Literal(token::Lit { kind: token::StrRaw(..), symbol, suffix }) => {
let sp = self.token.span;
self.expect_no_suffix(sp, "an ABI spec", suffix);
self.expect_no_suffix(self.token.span, "an ABI spec", suffix);
self.bump();
match abi::lookup(&symbol.as_str()) {
Some(abi) => Ok(Some(abi)),
None => {
let prev_span = self.prev_span;
struct_span_err!(
self.sess.span_diagnostic,
prev_span,
E0703,
"invalid ABI: found `{}`",
symbol
)
.span_label(prev_span, "invalid ABI")
.help(&format!("valid ABIs: {}", abi::all_names().join(", ")))
.emit();
self.error_on_invalid_abi(symbol);
Ok(None)
}
}
}
_ => Ok(None),
}
}
/// Emit an error where `symbol` is an invalid ABI.
fn error_on_invalid_abi(&self, symbol: Symbol) {
let prev_span = self.prev_span;
struct_span_err!(
self.sess.span_diagnostic,
prev_span,
E0703,
"invalid ABI: found `{}`",
symbol
)
.span_label(prev_span, "invalid ABI")
.help(&format!("valid ABIs: {}", abi::all_names().join(", ")))
.emit();
}
/// We are parsing `async fn`. If we are on Rust 2015, emit an error.
fn ban_async_in_2015(&self, async_span: Span) {
if async_span.rust_2015() {
@ -1530,9 +1534,10 @@ impl<'a> Parser<'a> {
}
}
fn collect_tokens<F, R>(&mut self, f: F) -> PResult<'a, (R, TokenStream)>
where F: FnOnce(&mut Self) -> PResult<'a, R>
{
fn collect_tokens<R>(
&mut self,
f: impl FnOnce(&mut Self) -> PResult<'a, R>,
) -> PResult<'a, (R, TokenStream)> {
// Record all tokens we parse when parsing this item.
let mut tokens = Vec::new();
let prev_collecting = match self.token_cursor.frame.last_token {

View file

@ -7,7 +7,7 @@ use crate::ast::{
Item, ItemKind, ImplItem, TraitItem, TraitItemKind,
UseTree, UseTreeKind, PathSegment,
IsAuto, Constness, IsAsync, Unsafety, Defaultness,
Visibility, VisibilityKind, Mutability, FnDecl, FnHeader,
Visibility, VisibilityKind, Mutability, FnDecl, FnHeader, MethodSig, Block,
ForeignItem, ForeignItemKind,
Ty, TyKind, Generics, GenericBounds, TraitRef,
EnumDef, VariantData, StructField, AnonConst,
@ -18,7 +18,7 @@ use crate::parse::token;
use crate::parse::parser::maybe_append;
use crate::parse::diagnostics::Error;
use crate::tokenstream::{TokenTree, TokenStream};
use crate::source_map::{respan, Span, Spanned};
use crate::source_map::{respan, Span};
use crate::symbol::{kw, sym};
use std::mem;
@ -122,19 +122,13 @@ impl<'a> Parser<'a> {
if self.eat_keyword(kw::Fn) {
// EXTERN FUNCTION ITEM
let fn_span = self.prev_span;
let abi = opt_abi.unwrap_or(Abi::C);
let (ident, item_, extra_attrs) =
self.parse_item_fn(Unsafety::Normal,
respan(fn_span, IsAsync::NotAsync),
respan(fn_span, Constness::NotConst),
abi)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
let header = FnHeader {
unsafety: Unsafety::Normal,
asyncness: respan(fn_span, IsAsync::NotAsync),
constness: respan(fn_span, Constness::NotConst),
abi: opt_abi.unwrap_or(Abi::C),
};
return self.parse_item_fn(lo, visibility, attrs, header);
} else if self.check(&token::OpenDelim(token::Brace)) {
return Ok(Some(
self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs, extern_sp)?,
@ -149,13 +143,9 @@ impl<'a> Parser<'a> {
// STATIC ITEM
let m = self.parse_mutability();
let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
let span = lo.to(self.prev_span);
let attrs = maybe_append(attrs, extra_attrs);
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
}
if self.eat_keyword(kw::Const) {
let const_span = self.prev_span;
@ -165,18 +155,13 @@ impl<'a> Parser<'a> {
// CONST FUNCTION ITEM
let unsafety = self.parse_unsafety();
self.bump();
let (ident, item_, extra_attrs) =
self.parse_item_fn(unsafety,
respan(const_span, IsAsync::NotAsync),
respan(const_span, Constness::Const),
Abi::Rust)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
let header = FnHeader {
unsafety,
asyncness: respan(const_span, IsAsync::NotAsync),
constness: respan(const_span, Constness::Const),
abi: Abi::Rust,
};
return self.parse_item_fn(lo, visibility, attrs, header);
}
// CONST ITEM
@ -193,13 +178,9 @@ impl<'a> Parser<'a> {
.emit();
}
let (ident, item_, extra_attrs) = self.parse_item_const(None)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
let span = lo.to(self.prev_span);
let attrs = maybe_append(attrs, extra_attrs);
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
}
// Parses `async unsafe? fn`.
@ -213,22 +194,18 @@ impl<'a> Parser<'a> {
let unsafety = self.parse_unsafety(); // `unsafe`?
self.expect_keyword(kw::Fn)?; // `fn`
let fn_span = self.prev_span;
let (ident, item_, extra_attrs) =
self.parse_item_fn(unsafety,
respan(async_span, IsAsync::Async {
closure_id: DUMMY_NODE_ID,
return_impl_trait_id: DUMMY_NODE_ID,
}),
respan(fn_span, Constness::NotConst),
Abi::Rust)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
let asyncness = respan(async_span, IsAsync::Async {
closure_id: DUMMY_NODE_ID,
return_impl_trait_id: DUMMY_NODE_ID,
});
self.ban_async_in_2015(async_span);
return Ok(Some(item));
let header = FnHeader {
unsafety,
asyncness,
constness: respan(fn_span, Constness::NotConst),
abi: Abi::Rust,
};
return self.parse_item_fn(lo, visibility, attrs, header);
}
}
if self.check_keyword(kw::Unsafe) &&
@ -243,15 +220,10 @@ impl<'a> Parser<'a> {
self.expect_keyword(kw::Trait)?;
IsAuto::Yes
};
let (ident, item_, extra_attrs) =
self.parse_item_trait(is_auto, Unsafety::Unsafe)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
let (ident, item_, extra_attrs) = self.parse_item_trait(is_auto, Unsafety::Unsafe)?;
let span = lo.to(self.prev_span);
let attrs = maybe_append(attrs, extra_attrs);
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
}
if self.check_keyword(kw::Impl) ||
self.check_keyword(kw::Unsafe) &&
@ -262,27 +234,22 @@ impl<'a> Parser<'a> {
let defaultness = self.parse_defaultness();
let unsafety = self.parse_unsafety();
self.expect_keyword(kw::Impl)?;
let (ident, item, extra_attrs) = self.parse_item_impl(unsafety, defaultness)?;
let (ident, item_, extra_attrs) = self.parse_item_impl(unsafety, defaultness)?;
let span = lo.to(self.prev_span);
return Ok(Some(self.mk_item(span, ident, item, visibility,
maybe_append(attrs, extra_attrs))));
let attrs = maybe_append(attrs, extra_attrs);
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
}
if self.check_keyword(kw::Fn) {
// FUNCTION ITEM
self.bump();
let fn_span = self.prev_span;
let (ident, item_, extra_attrs) =
self.parse_item_fn(Unsafety::Normal,
respan(fn_span, IsAsync::NotAsync),
respan(fn_span, Constness::NotConst),
Abi::Rust)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
let header = FnHeader {
unsafety: Unsafety::Normal,
asyncness: respan(fn_span, IsAsync::NotAsync),
constness: respan(fn_span, Constness::NotConst),
abi: Abi::Rust,
};
return self.parse_item_fn(lo, visibility, attrs, header);
}
if self.check_keyword(kw::Unsafe)
&& self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) {
@ -297,30 +264,20 @@ impl<'a> Parser<'a> {
};
self.expect_keyword(kw::Fn)?;
let fn_span = self.prev_span;
let (ident, item_, extra_attrs) =
self.parse_item_fn(Unsafety::Unsafe,
respan(fn_span, IsAsync::NotAsync),
respan(fn_span, Constness::NotConst),
abi)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
let header = FnHeader {
unsafety: Unsafety::Unsafe,
asyncness: respan(fn_span, IsAsync::NotAsync),
constness: respan(fn_span, Constness::NotConst),
abi,
};
return self.parse_item_fn(lo, visibility, attrs, header);
}
if self.eat_keyword(kw::Mod) {
// MODULE ITEM
let (ident, item_, extra_attrs) =
self.parse_item_mod(&attrs[..])?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
let (ident, item_, extra_attrs) = self.parse_item_mod(&attrs[..])?;
let span = lo.to(self.prev_span);
let attrs = maybe_append(attrs, extra_attrs);
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
}
if let Some(type_) = self.eat_type() {
let (ident, alias, generics) = type_?;
@ -329,24 +286,15 @@ impl<'a> Parser<'a> {
AliasKind::Weak(ty) => ItemKind::TyAlias(ty, generics),
AliasKind::OpaqueTy(bounds) => ItemKind::OpaqueTy(bounds, generics),
};
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
attrs);
return Ok(Some(item));
let span = lo.to(self.prev_span);
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
}
if self.eat_keyword(kw::Enum) {
// ENUM ITEM
let (ident, item_, extra_attrs) = self.parse_item_enum()?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
let span = lo.to(self.prev_span);
let attrs = maybe_append(attrs, extra_attrs);
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
}
if self.check_keyword(kw::Trait)
|| (self.check_keyword(kw::Auto)
@ -360,38 +308,25 @@ impl<'a> Parser<'a> {
IsAuto::Yes
};
// TRAIT ITEM
let (ident, item_, extra_attrs) =
self.parse_item_trait(is_auto, Unsafety::Normal)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
let (ident, item_, extra_attrs) = self.parse_item_trait(is_auto, Unsafety::Normal)?;
let span = lo.to(self.prev_span);
let attrs = maybe_append(attrs, extra_attrs);
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
}
if self.eat_keyword(kw::Struct) {
// STRUCT ITEM
let (ident, item_, extra_attrs) = self.parse_item_struct()?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
let span = lo.to(self.prev_span);
let attrs = maybe_append(attrs, extra_attrs);
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
}
if self.is_union_item() {
// UNION ITEM
self.bump();
let (ident, item_, extra_attrs) = self.parse_item_union()?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
let span = lo.to(self.prev_span);
let attrs = maybe_append(attrs, extra_attrs);
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
}
if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility, lo)? {
return Ok(Some(macro_def));
@ -848,29 +783,37 @@ impl<'a> Parser<'a> {
}
/// Parses a method or a macro invocation in a trait impl.
fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool)
-> PResult<'a, (Ident, Vec<Attribute>, Generics, ast::ImplItemKind)> {
fn parse_impl_method(
&mut self,
vis: &Visibility,
at_end: &mut bool
) -> PResult<'a, (Ident, Vec<Attribute>, Generics, ast::ImplItemKind)> {
// FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction!
if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? {
// method macro
Ok((Ident::invalid(), vec![], Generics::default(),
ast::ImplItemKind::Macro(mac)))
Ok((Ident::invalid(), vec![], Generics::default(), ast::ImplItemKind::Macro(mac)))
} else {
let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
let decl = self.parse_fn_decl_with_self(|_| true)?;
generics.where_clause = self.parse_where_clause()?;
let (ident, sig, generics) = self.parse_method_sig(|_| true)?;
*at_end = true;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
let header = ast::FnHeader { abi, unsafety, constness, asyncness };
Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(
ast::MethodSig { header, decl },
body
)))
Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(sig, body)))
}
}
/// Parse the "signature", including the identifier, parameters, and generics
/// of a method. The body is not parsed as that differs between `trait`s and `impl`s.
fn parse_method_sig(
&mut self,
is_name_required: impl Copy + Fn(&token::Token) -> bool,
) -> PResult<'a, (Ident, MethodSig, Generics)> {
let header = self.parse_fn_front_matter()?;
let (ident, mut generics) = self.parse_fn_header()?;
let decl = self.parse_fn_decl_with_self(is_name_required)?;
let sig = MethodSig { header, decl };
generics.where_clause = self.parse_where_clause()?;
Ok((ident, sig, generics))
}
/// Parses all the "front matter" for a `fn` declaration, up to
/// and including the `fn` keyword:
///
@ -879,14 +822,7 @@ impl<'a> Parser<'a> {
/// - `const unsafe fn`
/// - `extern fn`
/// - etc.
fn parse_fn_front_matter(&mut self)
-> PResult<'a, (
Spanned<Constness>,
Unsafety,
Spanned<IsAsync>,
Abi
)>
{
fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
let is_const_fn = self.eat_keyword(kw::Const);
let const_span = self.prev_span;
let asyncness = self.parse_asyncness();
@ -911,7 +847,7 @@ impl<'a> Parser<'a> {
// account for this.
if !self.expect_one_of(&[], &[])? { unreachable!() }
}
Ok((constness, unsafety, asyncness, abi))
Ok(FnHeader { constness, unsafety, asyncness, abi })
}
/// Parses `trait Foo { ... }` or `trait Foo = Bar;`.
@ -1025,59 +961,12 @@ impl<'a> Parser<'a> {
// trait item macro.
(Ident::invalid(), ast::TraitItemKind::Macro(mac), Generics::default())
} else {
let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
// This is somewhat dubious; We don't want to allow
// argument names to be left off if there is a definition...
//
// We don't allow argument names to be left off in edition 2018.
let decl = self.parse_fn_decl_with_self(|t| t.span.rust_2018())?;
generics.where_clause = self.parse_where_clause()?;
let sig = ast::MethodSig {
header: FnHeader {
unsafety,
constness,
abi,
asyncness,
},
decl,
};
let body = match self.token.kind {
token::Semi => {
self.bump();
*at_end = true;
debug!("parse_trait_methods(): parsing required method");
None
}
token::OpenDelim(token::Brace) => {
debug!("parse_trait_methods(): parsing provided method");
*at_end = true;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(inner_attrs.iter().cloned());
Some(body)
}
token::Interpolated(ref nt) => {
match **nt {
token::NtBlock(..) => {
*at_end = true;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(inner_attrs.iter().cloned());
Some(body)
}
_ => {
return self.expected_semi_or_open_brace();
}
}
}
_ => {
return self.expected_semi_or_open_brace();
}
};
let (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?;
let body = self.parse_trait_method_body(at_end, &mut attrs)?;
(ident, ast::TraitItemKind::Method(sig, body), generics)
};
@ -1092,6 +981,43 @@ impl<'a> Parser<'a> {
})
}
/// Parse the "body" of a method in a trait item definition.
/// This can either be `;` when there's no body,
/// or e.g. a block when the method is a provided one.
fn parse_trait_method_body(
&mut self,
at_end: &mut bool,
attrs: &mut Vec<Attribute>,
) -> PResult<'a, Option<P<Block>>> {
Ok(match self.token.kind {
token::Semi => {
debug!("parse_trait_method_body(): parsing required method");
self.bump();
*at_end = true;
None
}
token::OpenDelim(token::Brace) => {
debug!("parse_trait_method_body(): parsing provided method");
*at_end = true;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(inner_attrs.iter().cloned());
Some(body)
}
token::Interpolated(ref nt) => {
match **nt {
token::NtBlock(..) => {
*at_end = true;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(inner_attrs.iter().cloned());
Some(body)
}
_ => return self.expected_semi_or_open_brace(),
}
}
_ => return self.expected_semi_or_open_brace(),
})
}
/// Parses the following grammar:
///
/// TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
@ -1261,18 +1187,29 @@ impl<'a> Parser<'a> {
/// Parses an item-position function declaration.
fn parse_item_fn(
&mut self,
unsafety: Unsafety,
asyncness: Spanned<IsAsync>,
constness: Spanned<Constness>,
abi: Abi
) -> PResult<'a, ItemInfo> {
lo: Span,
vis: Visibility,
attrs: Vec<Attribute>,
header: FnHeader,
) -> PResult<'a, Option<P<Item>>> {
let allow_c_variadic = header.abi == Abi::C && header.unsafety == Unsafety::Unsafe;
let (ident, decl, generics) = self.parse_fn_sig(allow_c_variadic)?;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
let span = lo.to(self.prev_span);
let kind = ItemKind::Fn(decl, header, generics, body);
let attrs = maybe_append(attrs, Some(inner_attrs));
Ok(Some(self.mk_item(span, ident, kind, vis, attrs)))
}
/// Parse the "signature", including the identifier, parameters, and generics of a function.
fn parse_fn_sig(
&mut self,
allow_c_variadic: bool,
) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
let (ident, mut generics) = self.parse_fn_header()?;
let allow_c_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe;
let decl = self.parse_fn_decl(allow_c_variadic)?;
generics.where_clause = self.parse_where_clause()?;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
let header = FnHeader { unsafety, asyncness, constness, abi };
Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs)))
Ok((ident, decl, generics))
}
/// Parses the name and optional generic types of a function header.
@ -1282,14 +1219,11 @@ impl<'a> Parser<'a> {
Ok((id, generics))
}
/// Parses the argument list and result type of a function declaration.
/// Parses the parameter list and result type of a function declaration.
fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P<FnDecl>> {
let args = self.parse_fn_params(true, allow_c_variadic)?;
let ret_ty = self.parse_ret_ty(true)?;
Ok(P(FnDecl {
inputs: args,
output: ret_ty,
inputs: self.parse_fn_params(true, allow_c_variadic)?,
output: self.parse_ret_ty(true)?,
}))
}
@ -1397,18 +1331,15 @@ impl<'a> Parser<'a> {
extern_sp: Span,
) -> PResult<'a, ForeignItem> {
self.expect_keyword(kw::Fn)?;
let (ident, mut generics) = self.parse_fn_header()?;
let decl = self.parse_fn_decl(true)?;
generics.where_clause = self.parse_where_clause()?;
let hi = self.token.span;
let (ident, decl, generics) = self.parse_fn_sig(true)?;
let span = lo.to(self.token.span);
self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
Ok(ast::ForeignItem {
ident,
attrs,
kind: ForeignItemKind::Fn(decl, generics),
id: DUMMY_NODE_ID,
span: lo.to(hi),
span,
vis,
})
}

View file

@ -231,11 +231,7 @@ impl<'a> Parser<'a> {
}
fn parse_ptr(&mut self) -> PResult<'a, MutTy> {
let mutbl = if self.eat_keyword(kw::Mut) {
Mutability::Mutable
} else if self.eat_keyword(kw::Const) {
Mutability::Immutable
} else {
let mutbl = self.parse_const_or_mut().unwrap_or_else(|| {
let span = self.prev_span;
let msg = "expected mut or const in raw pointer type";
self.struct_span_err(span, msg)
@ -243,7 +239,7 @@ impl<'a> Parser<'a> {
.help("use `*mut T` or `*const T` as appropriate")
.emit();
Mutability::Immutable
};
});
let t = self.parse_ty_no_plus()?;
Ok(MutTy { ty: t, mutbl })
}

View file

@ -10,18 +10,18 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
LL | fn baz() { async fn foo() {} }
| ^^^^^
error[E0670]: `async fn` is not permitted in the 2015 edition
--> $DIR/edition-deny-async-fns-2015.rs:8:5
|
LL | async fn bar() {}
| ^^^^^
error[E0670]: `async fn` is not permitted in the 2015 edition
--> $DIR/edition-deny-async-fns-2015.rs:7:1
|
LL | async fn async_baz() {
| ^^^^^
error[E0670]: `async fn` is not permitted in the 2015 edition
--> $DIR/edition-deny-async-fns-2015.rs:8:5
|
LL | async fn bar() {}
| ^^^^^
error[E0670]: `async fn` is not permitted in the 2015 edition
--> $DIR/edition-deny-async-fns-2015.rs:14:5
|