Rollup merge of #68788 - Centril:unified-fn-bodies, r=petrochenkov

Towards unified `fn` grammar

Part of https://github.com/rust-lang/rust/pull/68728.

- Syntactically, `fn` items in `extern { ... }` blocks can now have bodies (`fn foo() { ... }` as opposed to `fn foo();`). As above, we use semantic restrictions instead.

- Syntactically, `fn` items in free contexts (directly in a file or a module) can now be without bodies (`fn foo();` as opposed to `fn foo() { ... }`. As above, we use semantic restrictions instead, including for non-ident parameter patterns.

- We move towards unifying the `fn` front matter; this is fully realized in https://github.com/rust-lang/rust/pull/68728.

r? @petrochenkov
This commit is contained in:
Dylan DPC 2020-02-06 15:37:41 +01:00 committed by GitHub
commit 424304a14f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 1051 additions and 667 deletions

View File

@ -14,7 +14,7 @@ use rustc_target::spec::abi;
use syntax::ast::*;
use syntax::attr;
use syntax::node_id::NodeMap;
use syntax::visit::{self, Visitor};
use syntax::visit::{self, AssocCtxt, Visitor};
use log::debug;
use smallvec::{smallvec, SmallVec};
@ -81,25 +81,23 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
}
}
fn visit_trait_item(&mut self, item: &'a AssocItem) {
self.lctx.with_hir_id_owner(item.id, |lctx| {
let hir_item = lctx.lower_trait_item(item);
let id = hir::TraitItemId { hir_id: hir_item.hir_id };
lctx.trait_items.insert(id, hir_item);
lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id);
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
AssocCtxt::Trait => {
let hir_item = lctx.lower_trait_item(item);
let id = hir::TraitItemId { hir_id: hir_item.hir_id };
lctx.trait_items.insert(id, hir_item);
lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id);
}
AssocCtxt::Impl => {
let hir_item = lctx.lower_impl_item(item);
let id = hir::ImplItemId { hir_id: hir_item.hir_id };
lctx.impl_items.insert(id, hir_item);
lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id);
}
});
visit::walk_trait_item(self, item);
}
fn visit_impl_item(&mut self, item: &'a AssocItem) {
self.lctx.with_hir_id_owner(item.id, |lctx| {
let hir_item = lctx.lower_impl_item(item);
let id = hir::ImplItemId { hir_id: hir_item.hir_id };
lctx.impl_items.insert(id, hir_item);
lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id);
});
visit::walk_impl_item(self, item);
visit::walk_assoc_item(self, item, ctxt);
}
}
@ -299,20 +297,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `impl Future<Output = T>` here because lower_body
// only cares about the input argument patterns in the function
// declaration (decl), not the return types.
let asyncness = header.asyncness.node;
let body_id =
this.lower_maybe_async_body(span, &decl, header.asyncness.node, Some(body));
this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
let (generics, decl) = this.add_in_band_defs(
generics,
fn_def_id,
AnonymousLifetimeMode::PassThrough,
|this, idty| {
this.lower_fn_decl(
&decl,
Some((fn_def_id, idty)),
true,
header.asyncness.node.opt_return_id(),
)
let ret_id = asyncness.opt_return_id();
this.lower_fn_decl(&decl, Some((fn_def_id, idty)), true, ret_id)
},
);
let sig = hir::FnSig { decl, header: this.lower_fn_header(header) };
@ -658,7 +653,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
ident: i.ident,
attrs: self.lower_attrs(&i.attrs),
kind: match i.kind {
ForeignItemKind::Fn(ref fdec, ref generics) => {
ForeignItemKind::Fn(ref sig, ref generics, _) => {
let fdec = &sig.decl;
let (generics, (fn_dec, fn_args)) = self.add_in_band_defs(
generics,
def_id,

View File

@ -32,6 +32,7 @@
#![feature(array_value_iter)]
#![feature(crate_visibility_modifier)]
#![recursion_limit = "256"]
use rustc::arena::Arena;
use rustc::dep_graph::DepGraph;
@ -63,7 +64,7 @@ use syntax::attr;
use syntax::node_id::NodeMap;
use syntax::token::{self, Nonterminal, Token};
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::visit::{self, Visitor};
use syntax::visit::{self, AssocCtxt, Visitor};
use syntax::walk_list;
use log::{debug, trace};
@ -485,25 +486,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
});
}
fn visit_trait_item(&mut self, item: &'tcx AssocItem) {
fn visit_assoc_item(&mut self, item: &'tcx AssocItem, ctxt: AssocCtxt) {
self.lctx.allocate_hir_id_counter(item.id);
match item.kind {
AssocItemKind::Fn(_, None) => {
// Ignore patterns in trait methods without bodies
self.with_hir_id_owner(None, |this| visit::walk_trait_item(this, item));
}
_ => self.with_hir_id_owner(Some(item.id), |this| {
visit::walk_trait_item(this, item);
}),
}
}
fn visit_impl_item(&mut self, item: &'tcx AssocItem) {
self.lctx.allocate_hir_id_counter(item.id);
self.with_hir_id_owner(Some(item.id), |this| {
visit::walk_impl_item(this, item);
});
let owner = match (&item.kind, ctxt) {
// Ignore patterns in trait methods without bodies.
(AssocItemKind::Fn(_, None), AssocCtxt::Trait) => None,
_ => Some(item.id),
};
self.with_hir_id_owner(owner, |this| visit::walk_assoc_item(this, item, ctxt));
}
fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) {

View File

@ -8,7 +8,7 @@
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{struct_span_err, Applicability, FatalError};
use rustc_errors::{error_code, struct_span_err, Applicability, FatalError};
use rustc_parse::validate_attr;
use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
use rustc_session::lint::LintBuffer;
@ -20,7 +20,7 @@ use std::mem;
use syntax::ast::*;
use syntax::attr;
use syntax::expand::is_proc_macro_attr;
use syntax::visit::{self, Visitor};
use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use syntax::walk_list;
/// Is `self` allowed semantically as the first parameter in an `FnDecl`?
@ -49,6 +49,13 @@ impl BoundContext {
struct AstValidator<'a> {
session: &'a Session,
/// The span of the `extern` in an `extern { ... }` block, if any.
extern_mod: Option<&'a Item>,
/// Are we inside a trait impl?
in_trait_impl: bool,
has_proc_macro_decls: bool,
/// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
@ -74,6 +81,12 @@ struct AstValidator<'a> {
}
impl<'a> AstValidator<'a> {
fn with_in_trait_impl(&mut self, is_in: bool, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.in_trait_impl, is_in);
f(self);
self.in_trait_impl = old;
}
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.is_impl_trait_banned, true);
f(self);
@ -389,13 +402,9 @@ impl<'a> AstValidator<'a> {
}
}
fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
if body.is_some() {
return;
}
fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
self.err_handler()
.struct_span_err(sp, &format!("associated {} in `impl` without body", ctx))
.struct_span_err(sp, msg)
.span_suggestion(
self.session.source_map().end_point(sp),
&format!("provide a definition for the {}", ctx),
@ -405,6 +414,13 @@ impl<'a> AstValidator<'a> {
.emit();
}
fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
if body.is_none() {
let msg = format!("associated {} in `impl` without body", ctx);
self.error_item_without_body(sp, ctx, &msg, sugg);
}
}
fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
let span = match bounds {
[] => return,
@ -416,8 +432,71 @@ impl<'a> AstValidator<'a> {
.emit();
}
fn check_c_varadic_type(&self, decl: &FnDecl) {
for Param { ty, span, .. } in &decl.inputs {
/// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
let body = match body {
None => return,
Some(body) => body,
};
self.err_handler()
.struct_span_err(ident.span, "incorrect function inside `extern` block")
.span_label(ident.span, "cannot have a body")
.span_suggestion(
body.span,
"remove the invalid body",
";".to_string(),
Applicability::MaybeIncorrect,
)
.help(
"you might have meant to write a function accessible through FFI, \
which can be done by writing `extern fn` outside of the `extern` block",
)
.span_label(
self.current_extern_span(),
"`extern` blocks define existing foreign functions and functions \
inside of them cannot have a body",
)
.note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html")
.emit();
}
fn current_extern_span(&self) -> Span {
self.session.source_map().def_span(self.extern_mod.unwrap().span)
}
/// An `fn` in `extern { ... }` cannot have qualfiers, e.g. `async fn`.
fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
if header.has_qualifiers() {
self.err_handler()
.struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
.span_label(self.current_extern_span(), "in this `extern` block")
.span_suggestion(
span.until(ident.span.shrink_to_lo()),
"remove the qualifiers",
"fn ".to_string(),
Applicability::MaybeIncorrect,
)
.emit();
}
}
/// Reject C-varadic type unless the function is foreign,
/// or free and `unsafe extern "C"` semantically.
fn check_c_varadic_type(&self, fk: FnKind<'a>) {
match (fk.ctxt(), fk.header()) {
(Some(FnCtxt::Foreign), _) => return,
(Some(FnCtxt::Free), Some(header)) => match header.ext {
Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
if header.unsafety == Unsafety::Unsafe =>
{
return;
}
_ => {}
},
_ => {}
};
for Param { ty, span, .. } in &fk.decl().inputs {
if let TyKind::CVarArgs = ty.kind {
self.err_handler()
.struct_span_err(
@ -428,6 +507,24 @@ impl<'a> AstValidator<'a> {
}
}
}
/// We currently do not permit const generics in `const fn`,
/// as this is tantamount to allowing compile-time dependent typing.
///
/// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor.
/// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck.
fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) {
if sig.header.constness.node == Constness::Const {
// Look for const generics and error if we find any.
for param in &generics.params {
if let GenericParamKind::Const { .. } = param.kind {
self.err_handler()
.struct_span_err(span, "const parameters are not permitted in `const fn`")
.emit();
}
}
}
}
}
enum GenericPosition {
@ -532,9 +629,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_expr(&mut self, expr: &'a Expr) {
match &expr.kind {
ExprKind::Closure(_, _, _, fn_decl, _, _) => {
self.check_fn_decl(fn_decl, SelfSemantic::No);
}
ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
struct_span_err!(
self.session,
@ -647,31 +741,32 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
generics: _,
of_trait: Some(_),
ref self_ty,
ref items,
items: _,
} => {
self.invalid_visibility(&item.vis, None);
if let TyKind::Err = self_ty.kind {
self.err_handler()
.struct_span_err(item.span, "`impl Trait for .. {}` is an obsolete syntax")
.help("use `auto trait Trait {}` instead")
.emit();
}
if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative {
struct_span_err!(
self.session,
item.span,
E0198,
"negative impls cannot be unsafe"
)
.emit();
}
for impl_item in items {
self.invalid_visibility(&impl_item.vis, None);
if let AssocItemKind::Fn(ref sig, _) = impl_item.kind {
self.check_trait_fn_not_const(sig.header.constness);
self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node);
self.with_in_trait_impl(true, |this| {
this.invalid_visibility(&item.vis, None);
if let TyKind::Err = self_ty.kind {
this.err_handler()
.struct_span_err(
item.span,
"`impl Trait for .. {}` is an obsolete syntax",
)
.help("use `auto trait Trait {}` instead")
.emit();
}
}
if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative {
struct_span_err!(
this.session,
item.span,
E0198,
"negative impls cannot be unsafe"
)
.emit();
}
visit::walk_item(this, item);
});
return; // Avoid visiting again.
}
ItemKind::Impl {
unsafety,
@ -712,40 +807,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
.emit();
}
}
ItemKind::Fn(ref sig, ref generics, _) => {
self.visit_fn_header(&sig.header);
self.check_fn_decl(&sig.decl, SelfSemantic::No);
// We currently do not permit const generics in `const fn`, as
// this is tantamount to allowing compile-time dependent typing.
if sig.header.constness.node == Constness::Const {
// Look for const generics and error if we find any.
for param in &generics.params {
match param.kind {
GenericParamKind::Const { .. } => {
self.err_handler()
.struct_span_err(
item.span,
"const parameters are not permitted in `const fn`",
)
.emit();
}
_ => {}
}
}
}
// Reject C-varadic type unless the function is `unsafe extern "C"` semantically.
match sig.header.ext {
Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. })
| Extern::Implicit
if sig.header.unsafety == Unsafety::Unsafe => {}
_ => self.check_c_varadic_type(&sig.decl),
ItemKind::Fn(ref sig, ref generics, ref body) => {
self.check_const_fn_const_generic(item.span, sig, generics);
if body.is_none() {
let msg = "free function without a body";
self.error_item_without_body(item.span, "function", msg, " { <body> }");
}
}
ItemKind::ForeignMod(..) => {
ItemKind::ForeignMod(_) => {
let old_item = mem::replace(&mut self.extern_mod, Some(item));
self.invalid_visibility(
&item.vis,
Some("place qualifiers on individual foreign items instead"),
);
visit::walk_item(self, item);
self.extern_mod = old_item;
return; // Avoid visiting again.
}
ItemKind::Enum(ref def, _) => {
for variant in &def.variants {
@ -796,7 +874,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.with_bound_context(BoundContext::TraitBounds, |this| {
walk_list!(this, visit_param_bound, bounds);
});
walk_list!(self, visit_trait_item, trait_items);
walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
walk_list!(self, visit_attribute, &item.attrs);
return;
}
@ -820,19 +898,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
match fi.kind {
ForeignItemKind::Fn(ref decl, _) => {
self.check_fn_decl(decl, SelfSemantic::No);
Self::check_decl_no_pat(decl, |span, _| {
struct_span_err!(
self.session,
span,
E0130,
"patterns aren't allowed in foreign function declarations"
)
.span_label(span, "pattern not allowed in foreign function")
.emit();
});
match &fi.kind {
ForeignItemKind::Fn(sig, _, body) => {
self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
}
ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {}
}
@ -1011,67 +1080,84 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
})
}
fn visit_impl_item(&mut self, ii: &'a AssocItem) {
match &ii.kind {
AssocItemKind::Const(_, body) => {
self.check_impl_item_provided(ii.span, body, "constant", " = <expr>;");
}
AssocItemKind::Fn(_, body) => {
self.check_impl_item_provided(ii.span, body, "function", " { <body> }");
}
AssocItemKind::TyAlias(bounds, body) => {
self.check_impl_item_provided(ii.span, body, "type", " = <type>;");
self.check_impl_assoc_type_no_bounds(bounds);
}
_ => {}
}
visit::walk_impl_item(self, ii);
}
fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
// Only associated `fn`s can have `self` parameters.
let self_semantic = match fk.ctxt() {
Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
_ => SelfSemantic::No,
};
self.check_fn_decl(fk.decl(), self_semantic);
fn visit_trait_item(&mut self, ti: &'a AssocItem) {
self.invalid_visibility(&ti.vis, None);
self.check_defaultness(ti.span, ti.defaultness);
self.check_c_varadic_type(fk);
if let AssocItemKind::Fn(sig, block) = &ti.kind {
self.check_trait_fn_not_async(ti.span, sig.header.asyncness.node);
self.check_trait_fn_not_const(sig.header.constness);
if block.is_none() {
Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
if mut_ident {
self.lint_buffer.buffer_lint(
PATTERNS_IN_FNS_WITHOUT_BODY,
ti.id,
span,
"patterns aren't allowed in methods without bodies",
);
} else {
struct_span_err!(
self.session,
span,
E0642,
"patterns aren't allowed in methods without bodies"
)
// Functions without bodies cannot have patterns.
if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
let (code, msg, label) = match ctxt {
FnCtxt::Foreign => (
error_code!(E0130),
"patterns aren't allowed in foreign function declarations",
"pattern not allowed in foreign function",
),
_ => (
error_code!(E0642),
"patterns aren't allowed in functions without bodies",
"pattern not allowed in function without body",
),
};
if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
} else {
self.err_handler()
.struct_span_err(span, msg)
.span_label(span, label)
.code(code)
.emit();
}
});
}
});
}
visit::walk_fn(self, fk, span);
}
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
if ctxt == AssocCtxt::Trait {
self.check_defaultness(item.span, item.defaultness);
}
if ctxt == AssocCtxt::Impl {
match &item.kind {
AssocItemKind::Const(_, body) => {
self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
}
AssocItemKind::Fn(_, body) => {
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
}
AssocItemKind::TyAlias(bounds, body) => {
self.check_impl_item_provided(item.span, body, "type", " = <type>;");
self.check_impl_assoc_type_no_bounds(bounds);
}
_ => {}
}
}
visit::walk_trait_item(self, ti);
}
fn visit_assoc_item(&mut self, item: &'a AssocItem) {
if let AssocItemKind::Fn(sig, _) = &item.kind {
self.check_fn_decl(&sig.decl, SelfSemantic::Yes);
self.check_c_varadic_type(&sig.decl);
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
self.invalid_visibility(&item.vis, None);
if let AssocItemKind::Fn(sig, _) = &item.kind {
self.check_trait_fn_not_const(sig.header.constness);
self.check_trait_fn_not_async(item.span, sig.header.asyncness.node);
}
}
visit::walk_assoc_item(self, item);
self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
}
}
pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
let mut validator = AstValidator {
session,
extern_mod: None,
in_trait_impl: false,
has_proc_macro_decls: false,
outer_impl_trait: None,
bound_context: None,

View File

@ -8,7 +8,7 @@ use rustc_span::Span;
use syntax::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId};
use syntax::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
use syntax::attr;
use syntax::visit::{self, FnKind, Visitor};
use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use log::debug;
@ -492,25 +492,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
visit::walk_pat(self, pattern)
}
fn visit_fn(
&mut self,
fn_kind: FnKind<'a>,
fn_decl: &'a ast::FnDecl,
span: Span,
_node_id: NodeId,
) {
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
if let Some(header) = fn_kind.header() {
// Stability of const fn methods are covered in
// `visit_trait_item` and `visit_impl_item` below; this is
// because default methods don't pass through this point.
// Stability of const fn methods are covered in `visit_assoc_item` below.
self.check_extern(header.ext);
}
if fn_decl.c_variadic() {
if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() {
gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
}
visit::walk_fn(self, fn_kind, fn_decl, span)
visit::walk_fn(self, fn_kind, span)
}
fn visit_generic_param(&mut self, param: &'a GenericParam) {
@ -539,56 +531,35 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
visit::walk_assoc_ty_constraint(self, constraint)
}
fn visit_trait_item(&mut self, ti: &'a ast::AssocItem) {
match ti.kind {
ast::AssocItemKind::Fn(ref sig, ref block) => {
if block.is_none() {
self.check_extern(sig.header.ext);
}
if sig.header.constness.node == ast::Constness::Const {
gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
}
}
ast::AssocItemKind::TyAlias(_, ref default) => {
if let Some(_) = default {
gate_feature_post!(
&self,
associated_type_defaults,
ti.span,
"associated type defaults are unstable"
);
}
}
_ => {}
}
visit::walk_trait_item(self, ti)
}
fn visit_assoc_item(&mut self, ii: &'a ast::AssocItem) {
if ii.defaultness == ast::Defaultness::Default {
gate_feature_post!(&self, specialization, ii.span, "specialization is unstable");
fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
if i.defaultness == ast::Defaultness::Default {
gate_feature_post!(&self, specialization, i.span, "specialization is unstable");
}
match ii.kind {
match i.kind {
ast::AssocItemKind::Fn(ref sig, _) => {
if sig.decl.c_variadic() {
gate_feature_post!(
&self,
c_variadic,
ii.span,
"C-variadic functions are unstable"
);
let constness = sig.header.constness.node;
if let (ast::Constness::Const, AssocCtxt::Trait) = (constness, ctxt) {
gate_feature_post!(&self, const_fn, i.span, "const fn is unstable");
}
}
ast::AssocItemKind::TyAlias(_, ref ty) => {
if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
gate_feature_post!(
&self,
associated_type_defaults,
i.span,
"associated type defaults are unstable"
);
}
if let Some(ty) = ty {
self.check_impl_trait(ty);
}
self.check_gat(&ii.generics, ii.span);
self.check_gat(&i.generics, i.span);
}
_ => {}
}
visit::walk_assoc_item(self, ii)
visit::walk_assoc_item(self, i, ctxt)
}
fn visit_vis(&mut self, vis: &'a ast::Visibility) {

View File

@ -67,13 +67,13 @@ impl<'ast> Visitor<'ast> for NodeCounter {
self.count += 1;
walk_generics(self, g)
}
fn visit_fn(&mut self, fk: FnKind<'_>, fd: &FnDecl, s: Span, _: NodeId) {
fn visit_fn(&mut self, fk: FnKind<'_>, s: Span, _: NodeId) {
self.count += 1;
walk_fn(self, fk, fd, s)
walk_fn(self, fk, s)
}
fn visit_assoc_item(&mut self, ti: &AssocItem) {
fn visit_assoc_item(&mut self, ti: &AssocItem, ctxt: AssocCtxt) {
self.count += 1;
walk_assoc_item(self, ti)
walk_assoc_item(self, ti, ctxt);
}
fn visit_trait_ref(&mut self, t: &TraitRef) {
self.count += 1;

View File

@ -1020,18 +1020,8 @@ impl<'a> State<'a> {
self.maybe_print_comment(item.span.lo());
self.print_outer_attributes(&item.attrs);
match item.kind {
ast::ForeignItemKind::Fn(ref decl, ref generics) => {
self.head("");
self.print_fn(
decl,
ast::FnHeader::default(),
Some(item.ident),
generics,
&item.vis,
);
self.end(); // end head-ibox
self.s.word(";");
self.end(); // end the outer fn box
ast::ForeignItemKind::Fn(ref sig, ref gen, ref body) => {
self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs);
}
ast::ForeignItemKind::Static(ref t, m) => {
self.head(visibility_qualified(&item.vis, "static"));
@ -1154,11 +1144,8 @@ impl<'a> State<'a> {
self.s.word(";");
self.end(); // end the outer cbox
}
ast::ItemKind::Fn(ref sig, ref param_names, ref body) => {
self.head("");
self.print_fn(&sig.decl, sig.header, Some(item.ident), param_names, &item.vis);
self.s.word(" ");
self.print_block_with_attrs(body, &item.attrs);
ast::ItemKind::Fn(ref sig, ref gen, ref body) => {
self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs);
}
ast::ItemKind::Mod(ref _mod) => {
self.head(visibility_qualified(&item.vis, "mod"));
@ -1483,16 +1470,8 @@ impl<'a> State<'a> {
self.print_associated_const(item.ident, ty, expr.as_deref(), &item.vis);
}
ast::AssocItemKind::Fn(sig, body) => {
if body.is_some() {
self.head("");
}
self.print_fn(&sig.decl, sig.header, Some(item.ident), &item.generics, &item.vis);
if let Some(body) = body {
self.nbsp();
self.print_block_with_attrs(body, &item.attrs);
} else {
self.s.word(";");
}
let body = body.as_deref();
self.print_fn_full(sig, item.ident, &item.generics, &item.vis, body, &item.attrs);
}
ast::AssocItemKind::TyAlias(bounds, ty) => {
self.print_associated_type(item.ident, bounds, ty.as_deref());
@ -2412,6 +2391,27 @@ impl<'a> State<'a> {
}
}
fn print_fn_full(
&mut self,
sig: &ast::FnSig,
name: ast::Ident,
generics: &ast::Generics,
vis: &ast::Visibility,
body: Option<&ast::Block>,
attrs: &[ast::Attribute],
) {
if body.is_some() {
self.head("");
}
self.print_fn(&sig.decl, sig.header, Some(name), generics, vis);
if let Some(body) = body {
self.nbsp();
self.print_block_with_attrs(body, attrs);
} else {
self.s.word(";");
}
}
crate fn print_fn(
&mut self,
decl: &ast::FnDecl,
@ -2698,13 +2698,9 @@ impl<'a> State<'a> {
where_clause: ast::WhereClause { predicates: Vec::new(), span: rustc_span::DUMMY_SP },
span: rustc_span::DUMMY_SP,
};
self.print_fn(
decl,
ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() },
name,
&generics,
&dummy_spanned(ast::VisibilityKind::Inherited),
);
let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
let vis = dummy_spanned(ast::VisibilityKind::Inherited);
self.print_fn(decl, header, name, &generics, &vis);
self.end();
}

View File

@ -66,7 +66,7 @@ impl AllocFnFactory<'_, '_> {
let decl = self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty));
let header = FnHeader { unsafety: Unsafety::Unsafe, ..FnHeader::default() };
let sig = FnSig { decl, header };
let kind = ItemKind::Fn(sig, Generics::default(), self.cx.block_expr(output_expr));
let kind = ItemKind::Fn(sig, Generics::default(), Some(self.cx.block_expr(output_expr)));
let item = self.cx.item(
self.span,
self.cx.ident_of(&self.kind.fn_name(method.name), self.span),

View File

@ -307,7 +307,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
let decl = ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty));
let sig = ast::FnSig { decl, header: ast::FnHeader::default() };
let main = ast::ItemKind::Fn(sig, ast::Generics::default(), main_body);
let main = ast::ItemKind::Fn(sig, ast::Generics::default(), Some(main_body));
// Honor the reexport_test_harness_main attribute
let main_id = match cx.reexport_test_harness_main {

View File

@ -17,7 +17,7 @@ use syntax::mut_visit::{self, MutVisitor};
use syntax::ptr::P;
use syntax::token;
use syntax::tokenstream::{self, TokenStream};
use syntax::visit::Visitor;
use syntax::visit::{AssocCtxt, Visitor};
use std::default::Default;
use std::iter;
@ -103,8 +103,8 @@ impl Annotatable {
pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
match self {
Annotatable::Item(item) => visitor.visit_item(item),
Annotatable::TraitItem(trait_item) => visitor.visit_trait_item(trait_item),
Annotatable::ImplItem(impl_item) => visitor.visit_impl_item(impl_item),
Annotatable::TraitItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Trait),
Annotatable::ImplItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Impl),
Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item),
Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt),
Annotatable::Expr(expr) => visitor.visit_expr(expr),

View File

@ -25,7 +25,7 @@ use syntax::ptr::P;
use syntax::token;
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::util::map_in_place::MapInPlace;
use syntax::visit::{self, Visitor};
use syntax::visit::{self, AssocCtxt, Visitor};
use smallvec::{smallvec, SmallVec};
use std::io::ErrorKind;
@ -39,7 +39,7 @@ macro_rules! ast_fragments {
$($Kind:ident($AstTy:ty) {
$kind_name:expr;
$(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)?
$(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident;)?
$(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)?
fn $make_ast:ident;
})*
) => {
@ -127,7 +127,7 @@ macro_rules! ast_fragments {
AstFragment::OptExpr(None) => {}
$($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)*
$($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] {
visitor.$visit_ast_elt(ast_elt);
visitor.$visit_ast_elt(ast_elt, $($args)*);
})?)*
}
}
@ -147,52 +147,58 @@ ast_fragments! {
Pat(P<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; }
Ty(P<ast::Ty>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; }
Stmts(SmallVec<[ast::Stmt; 1]>) {
"statement"; many fn flat_map_stmt; fn visit_stmt; fn make_stmts;
"statement"; many fn flat_map_stmt; fn visit_stmt(); fn make_stmts;
}
Items(SmallVec<[P<ast::Item>; 1]>) {
"item"; many fn flat_map_item; fn visit_item; fn make_items;
"item"; many fn flat_map_item; fn visit_item(); fn make_items;
}
TraitItems(SmallVec<[P<ast::AssocItem>; 1]>) {
"trait item"; many fn flat_map_trait_item; fn visit_trait_item; fn make_trait_items;
"trait item";
many fn flat_map_trait_item;
fn visit_assoc_item(AssocCtxt::Trait);
fn make_trait_items;
}
ImplItems(SmallVec<[P<ast::AssocItem>; 1]>) {
"impl item"; many fn flat_map_impl_item; fn visit_impl_item; fn make_impl_items;
"impl item";
many fn flat_map_impl_item;
fn visit_assoc_item(AssocCtxt::Impl);
fn make_impl_items;
}
ForeignItems(SmallVec<[P<ast::ForeignItem>; 1]>) {
"foreign item";
many fn flat_map_foreign_item;
fn visit_foreign_item;
fn visit_foreign_item();
fn make_foreign_items;
}
Arms(SmallVec<[ast::Arm; 1]>) {
"match arm"; many fn flat_map_arm; fn visit_arm; fn make_arms;
"match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms;
}
Fields(SmallVec<[ast::Field; 1]>) {
"field expression"; many fn flat_map_field; fn visit_field; fn make_fields;
"field expression"; many fn flat_map_field; fn visit_field(); fn make_fields;
}
FieldPats(SmallVec<[ast::FieldPat; 1]>) {
"field pattern";
many fn flat_map_field_pattern;
fn visit_field_pattern;
fn visit_field_pattern();
fn make_field_patterns;
}
GenericParams(SmallVec<[ast::GenericParam; 1]>) {
"generic parameter";
many fn flat_map_generic_param;
fn visit_generic_param;
fn visit_generic_param();
fn make_generic_params;
}
Params(SmallVec<[ast::Param; 1]>) {
"function parameter"; many fn flat_map_param; fn visit_param; fn make_params;
"function parameter"; many fn flat_map_param; fn visit_param(); fn make_params;
}
StructFields(SmallVec<[ast::StructField; 1]>) {
"field";
many fn flat_map_struct_field;
fn visit_struct_field;
fn visit_struct_field();
fn make_struct_fields;
}
Variants(SmallVec<[ast::Variant; 1]>) {
"variant"; many fn flat_map_variant; fn visit_variant; fn make_variants;
"variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants;
}
}
@ -861,7 +867,7 @@ pub fn parse_ast_fragment<'a>(
AstFragmentKind::ForeignItems => {
let mut items = SmallVec::new();
while this.token != token::Eof {
items.push(this.parse_foreign_item(DUMMY_SP)?);
items.push(this.parse_foreign_item()?);
}
AstFragment::ForeignItems(items)
}

View File

@ -43,7 +43,7 @@ use rustc_span::{BytePos, Span};
use syntax::ast::{self, Expr};
use syntax::attr::{self, HasAttrs};
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::visit::FnKind;
use syntax::visit::{FnCtxt, FnKind};
use crate::nonstandard_style::{method_context, MethodLateContext};
@ -259,34 +259,22 @@ impl EarlyLintPass for UnsafeCode {
}
}
fn check_fn(
&mut self,
cx: &EarlyContext<'_>,
fk: FnKind<'_>,
_: &ast::FnDecl,
span: Span,
_: ast::NodeId,
) {
match fk {
FnKind::ItemFn(_, ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, ..) => {
self.report_unsafe(cx, span, "declaration of an `unsafe` function")
}
FnKind::Method(_, sig, ..) => {
if sig.header.unsafety == ast::Unsafety::Unsafe {
self.report_unsafe(cx, span, "implementation of an `unsafe` method")
}
}
_ => (),
}
}
fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &ast::AssocItem) {
if let ast::AssocItemKind::Fn(ref sig, None) = item.kind {
if sig.header.unsafety == ast::Unsafety::Unsafe {
self.report_unsafe(cx, item.span, "declaration of an `unsafe` method")
}
fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) {
if let FnKind::Fn(
ctxt,
_,
ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, .. },
_,
body,
) = fk
{
let msg = match ctxt {
FnCtxt::Foreign => return,
FnCtxt::Free => "declaration of an `unsafe` function",
FnCtxt::Assoc(_) if body.is_none() => "declaration of an `unsafe` method",
FnCtxt::Assoc(_) => "implementation of an `unsafe` method",
};
self.report_unsafe(cx, span, msg);
}
}
}

View File

@ -116,17 +116,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
ast_visit::walk_stmt(self, s);
}
fn visit_fn(
&mut self,
fk: ast_visit::FnKind<'a>,
decl: &'a ast::FnDecl,
span: Span,
id: ast::NodeId,
) {
run_early_pass!(self, check_fn, fk, decl, span, id);
fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, span: Span, id: ast::NodeId) {
run_early_pass!(self, check_fn, fk, span, id);
self.check_id(id);
ast_visit::walk_fn(self, fk, decl, span);
run_early_pass!(self, check_fn_post, fk, decl, span, id);
ast_visit::walk_fn(self, fk, span);
run_early_pass!(self, check_fn_post, fk, span, id);
}
fn visit_variant_data(&mut self, s: &'a ast::VariantData) {
@ -213,19 +207,18 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
ast_visit::walk_poly_trait_ref(self, t, m);
}
fn visit_trait_item(&mut self, trait_item: &'a ast::AssocItem) {
self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
run_early_pass!(cx, check_trait_item, trait_item);
ast_visit::walk_trait_item(cx, trait_item);
run_early_pass!(cx, check_trait_item_post, trait_item);
});
}
fn visit_impl_item(&mut self, impl_item: &'a ast::AssocItem) {
self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| {
run_early_pass!(cx, check_impl_item, impl_item);
ast_visit::walk_impl_item(cx, impl_item);
run_early_pass!(cx, check_impl_item_post, impl_item);
fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
self.with_lint_attrs(item.id, &item.attrs, |cx| match ctxt {
ast_visit::AssocCtxt::Trait => {
run_early_pass!(cx, check_trait_item, item);
ast_visit::walk_assoc_item(cx, item, ctxt);
run_early_pass!(cx, check_trait_item_post, item);
}
ast_visit::AssocCtxt::Impl => {
run_early_pass!(cx, check_impl_item, item);
ast_visit::walk_assoc_item(cx, item, ctxt);
run_early_pass!(cx, check_impl_item_post, item);
}
});
}

View File

@ -179,10 +179,9 @@ macro_rules! early_lint_methods {
fn check_where_predicate(a: &ast::WherePredicate);
fn check_poly_trait_ref(a: &ast::PolyTraitRef,
b: &ast::TraitBoundModifier);
fn check_fn(a: syntax::visit::FnKind<'_>, b: &ast::FnDecl, c: Span, d_: ast::NodeId);
fn check_fn(a: syntax::visit::FnKind<'_>, c: Span, d_: ast::NodeId);
fn check_fn_post(
a: syntax::visit::FnKind<'_>,
b: &ast::FnDecl,
c: Span,
d: ast::NodeId
);

View File

@ -1,3 +1,4 @@
use super::ty::AllowPlus;
use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType};
use rustc_ast_pretty::pprust;
@ -693,11 +694,11 @@ impl<'a> Parser<'a> {
pub(super) fn maybe_report_ambiguous_plus(
&mut self,
allow_plus: bool,
allow_plus: AllowPlus,
impl_dyn_multi: bool,
ty: &Ty,
) {
if !allow_plus && impl_dyn_multi {
if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi {
let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
self.struct_span_err(ty.span, "ambiguous `+` in a type")
.span_suggestion(
@ -712,11 +713,11 @@ impl<'a> Parser<'a> {
pub(super) fn maybe_recover_from_bad_type_plus(
&mut self,
allow_plus: bool,
allow_plus: AllowPlus,
ty: &Ty,
) -> PResult<'a, ()> {
// Do not add `+` to expected tokens.
if !allow_plus || !self.token.is_like_plus() {
if matches!(allow_plus, AllowPlus::No) || !self.token.is_like_plus() {
return Ok(());
}
@ -937,47 +938,6 @@ impl<'a> Parser<'a> {
self.expect(&token::Semi).map(drop) // Error unconditionally
}
pub(super) fn parse_semi_or_incorrect_foreign_fn_body(
&mut self,
ident: &Ident,
extern_sp: Span,
) -> PResult<'a, ()> {
if self.token != token::Semi {
// This might be an incorrect fn definition (#62109).
let parser_snapshot = self.clone();
match self.parse_inner_attrs_and_block() {
Ok((_, body)) => {
self.struct_span_err(ident.span, "incorrect `fn` inside `extern` block")
.span_label(ident.span, "can't have a body")
.span_label(body.span, "this body is invalid here")
.span_label(
extern_sp,
"`extern` blocks define existing foreign functions and `fn`s \
inside of them cannot have a body",
)
.help(
"you might have meant to write a function accessible through ffi, \
which can be done by writing `extern fn` outside of the \
`extern` block",
)
.note(
"for more information, visit \
https://doc.rust-lang.org/std/keyword.extern.html",
)
.emit();
}
Err(mut err) => {
err.cancel();
mem::replace(self, parser_snapshot);
self.expect_semi()?;
}
}
} else {
self.bump();
}
Ok(())
}
/// Consumes alternative await syntaxes like `await!(<expr>)`, `await <expr>`,
/// `await? <expr>`, `await(<expr>)`, and `await { <expr> }`.
pub(super) fn recover_incorrect_await_syntax(

View File

@ -1,4 +1,5 @@
use super::pat::{GateOr, PARAM_EXPECTED};
use super::ty::{AllowPlus, RecoverQPath};
use super::{BlockMode, Parser, PathStyle, PrevTokenKind, Restrictions, TokenType};
use super::{SemiColonMode, SeqSep, TokenExpectType};
use crate::maybe_recover_from_interpolated_ty_qpath;
@ -1399,7 +1400,7 @@ impl<'a> Parser<'a> {
self.expect_or()?;
args
};
let output = self.parse_ret_ty(true, true)?;
let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes)?;
Ok(P(FnDecl { inputs, output }))
}

View File

@ -1,4 +1,5 @@
use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
use super::ty::{AllowPlus, RecoverQPath};
use super::{FollowedByType, Parser, PathStyle};
use crate::maybe_whole;
@ -96,7 +97,6 @@ impl<'a> Parser<'a> {
}
if self.eat_keyword(kw::Extern) {
let extern_sp = self.prev_span;
if self.eat_keyword(kw::Crate) {
return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?));
}
@ -114,7 +114,7 @@ impl<'a> Parser<'a> {
};
return self.parse_item_fn(lo, vis, attrs, header);
} else if self.check(&token::OpenDelim(token::Brace)) {
return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs, extern_sp)?));
return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs)?));
}
self.unexpected()?;
@ -1045,7 +1045,6 @@ impl<'a> Parser<'a> {
abi: Option<StrLit>,
visibility: Visibility,
mut attrs: Vec<Attribute>,
extern_sp: Span,
) -> PResult<'a, P<Item>> {
self.expect(&token::OpenDelim(token::Brace))?;
@ -1053,7 +1052,7 @@ impl<'a> Parser<'a> {
let mut foreign_items = vec![];
while !self.eat(&token::CloseDelim(token::Brace)) {
foreign_items.push(self.parse_foreign_item(extern_sp)?);
foreign_items.push(self.parse_foreign_item()?);
}
let prev_span = self.prev_span;
@ -1063,51 +1062,42 @@ impl<'a> Parser<'a> {
}
/// Parses a foreign item.
pub fn parse_foreign_item(&mut self, extern_sp: Span) -> PResult<'a, P<ForeignItem>> {
pub fn parse_foreign_item(&mut self) -> PResult<'a, P<ForeignItem>> {
maybe_whole!(self, NtForeignItem, |ni| ni);
let attrs = self.parse_outer_attributes()?;
let lo = self.token.span;
let visibility = self.parse_visibility(FollowedByType::No)?;
// FOREIGN STATIC ITEM
// Treat `const` as `static` for error recovery, but don't add it to expected tokens.
if self.check_keyword(kw::Static) || self.token.is_keyword(kw::Const) {
if self.token.is_keyword(kw::Const) {
let mut err =
self.struct_span_err(self.token.span, "extern items cannot be `const`");
// FOREIGN TYPE ITEM
if self.check_keyword(kw::Type) {
return self.parse_item_foreign_type(visibility, lo, attrs);
}
// The user wrote 'const fn'
if self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe]) {
err.emit();
// Consume `const`
self.bump();
// Consume `unsafe` if present, since `extern` blocks
// don't allow it. This will leave behind a plain 'fn'
self.eat_keyword(kw::Unsafe);
// Treat 'const fn` as a plain `fn` for error recovery purposes.
// We've already emitted an error, so compilation is guaranteed
// to fail
return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?);
}
err.span_suggestion(
self.token.span,
// FOREIGN STATIC ITEM
if self.is_static_global() {
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.bump(); // `const`
self.struct_span_err(self.prev_span, "extern items cannot be `const`")
.span_suggestion(
self.prev_span,
"try using a static value",
"static".to_owned(),
Applicability::MachineApplicable,
);
err.emit();
}
self.bump(); // `static` or `const`
return Ok(self.parse_item_foreign_static(visibility, lo, attrs)?);
)
.emit();
return self.parse_item_foreign_static(visibility, lo, attrs);
}
// FOREIGN FUNCTION ITEM
if self.check_keyword(kw::Fn) {
return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?);
}
// FOREIGN TYPE ITEM
if self.check_keyword(kw::Type) {
return Ok(self.parse_item_foreign_type(visibility, lo, attrs)?);
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)? {
@ -1726,14 +1716,14 @@ impl<'a> Parser<'a> {
&mut self,
lo: Span,
vis: Visibility,
attrs: Vec<Attribute>,
mut attrs: Vec<Attribute>,
header: FnHeader,
) -> PResult<'a, Option<P<Item>>> {
let cfg = ParamCfg { is_name_required: |_| true };
let (ident, decl, generics) = self.parse_fn_sig(&cfg)?;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
let body = self.parse_fn_body(&mut false, &mut attrs)?;
let kind = ItemKind::Fn(FnSig { decl, header }, generics, body);
self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs)))
self.mk_item_with_info(attrs, lo, vis, (ident, kind, None))
}
/// Parses a function declaration from a foreign module.
@ -1741,15 +1731,14 @@ impl<'a> Parser<'a> {
&mut self,
vis: ast::Visibility,
lo: Span,
attrs: Vec<Attribute>,
extern_sp: Span,
mut attrs: Vec<Attribute>,
) -> PResult<'a, P<ForeignItem>> {
let cfg = ParamCfg { is_name_required: |_| true };
self.expect_keyword(kw::Fn)?;
let header = self.parse_fn_front_matter()?;
let (ident, decl, generics) = self.parse_fn_sig(&cfg)?;
let span = lo.to(self.token.span);
self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
let kind = ForeignItemKind::Fn(decl, generics);
let body = self.parse_fn_body(&mut false, &mut attrs)?;
let kind = ForeignItemKind::Fn(FnSig { header, decl }, generics, body);
let span = lo.to(self.prev_span);
Ok(P(ast::ForeignItem { ident, attrs, kind, id: DUMMY_NODE_ID, span, vis, tokens: None }))
}
@ -1760,45 +1749,40 @@ impl<'a> Parser<'a> {
is_name_required: fn(&token::Token) -> bool,
) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
let header = self.parse_fn_front_matter()?;
let (ident, decl, generics) = self.parse_fn_sig(&ParamCfg { is_name_required })?;
let sig = FnSig { header, decl };
let body = self.parse_assoc_fn_body(at_end, attrs)?;
Ok((ident, AssocItemKind::Fn(sig, body), generics))
let (ident, decl, generics) = self.parse_fn_sig(&&ParamCfg { is_name_required })?;
let body = self.parse_fn_body(at_end, attrs)?;
Ok((ident, AssocItemKind::Fn(FnSig { header, decl }, body), generics))
}
/// Parse the "body" of a method in an associated item definition.
/// Parse the "body" of a function.
/// This can either be `;` when there's no body,
/// or e.g. a block when the method is a provided one.
fn parse_assoc_fn_body(
/// or e.g. a block when the function is a provided one.
fn parse_fn_body(
&mut self,
at_end: &mut bool,
attrs: &mut Vec<Attribute>,
) -> PResult<'a, Option<P<Block>>> {
Ok(match self.token.kind {
let (inner_attrs, body) = match self.token.kind {
token::Semi => {
debug!("parse_assoc_fn_body(): parsing required method");
self.bump();
*at_end = true;
None
(Vec::new(), None)
}
token::OpenDelim(token::Brace) => {
debug!("parse_assoc_fn_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)
let (attrs, body) = self.parse_inner_attrs_and_block()?;
(attrs, 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)
let (attrs, body) = self.parse_inner_attrs_and_block()?;
(attrs, Some(body))
}
_ => return self.expected_semi_or_open_brace(),
},
_ => return self.expected_semi_or_open_brace(),
})
};
attrs.extend(inner_attrs);
*at_end = true;
Ok(body)
}
/// Parses all the "front matter" for a `fn` declaration, up to
@ -1839,7 +1823,7 @@ impl<'a> Parser<'a> {
fn parse_fn_sig(&mut self, cfg: &ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
let decl = self.parse_fn_decl(cfg, true)?;
let decl = self.parse_fn_decl(cfg, AllowPlus::Yes)?;
generics.where_clause = self.parse_where_clause()?;
Ok((ident, decl, generics))
}
@ -1848,11 +1832,11 @@ impl<'a> Parser<'a> {
pub(super) fn parse_fn_decl(
&mut self,
cfg: &ParamCfg,
ret_allow_plus: bool,
ret_allow_plus: AllowPlus,
) -> PResult<'a, P<FnDecl>> {
Ok(P(FnDecl {
inputs: self.parse_fn_params(cfg)?,
output: self.parse_ret_ty(ret_allow_plus, true)?,
output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?,
}))
}

View File

@ -1,3 +1,4 @@
use super::ty::{AllowPlus, RecoverQPath};
use super::{Parser, TokenType};
use crate::maybe_whole;
use rustc_errors::{pluralize, Applicability, PResult};
@ -224,7 +225,7 @@ impl<'a> Parser<'a> {
// `(T, U) -> R`
let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
let span = ident.span.to(self.prev_span);
let output = self.parse_ret_ty(false, false)?;
let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No)?;
ParenthesizedArgs { inputs, output, span }.into()
};

View File

@ -199,7 +199,7 @@ impl<'a> Parser<'a> {
}
}
fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
pub(super) 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())
}

View File

@ -36,6 +36,25 @@ impl BoundModifiers {
}
}
#[derive(Copy, Clone, PartialEq)]
pub(super) enum AllowPlus {
Yes,
No,
}
#[derive(PartialEq)]
pub(super) enum RecoverQPath {
Yes,
No,
}
// Is `...` (`CVarArgs`) legal at this level of type parsing?
#[derive(PartialEq)]
enum AllowCVariadic {
Yes,
No,
}
/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
/// `IDENT<<u8 as Trait>::AssocTy>`.
///
@ -48,14 +67,14 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool {
impl<'a> Parser<'a> {
/// Parses a type.
pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
self.parse_ty_common(true, true, false)
self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::No)
}
/// Parse a type suitable for a function or function pointer parameter.
/// The difference from `parse_ty` is that this version allows `...`
/// (`CVarArgs`) at the top level of the the type.
pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> {
self.parse_ty_common(true, true, true)
self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::Yes)
}
/// Parses a type in restricted contexts where `+` is not permitted.
@ -65,18 +84,19 @@ impl<'a> Parser<'a> {
/// Example 2: `value1 as TYPE + value2`
/// `+` is prohibited to avoid interactions with expression grammar.
pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
self.parse_ty_common(false, true, false)
self.parse_ty_common(AllowPlus::No, RecoverQPath::Yes, AllowCVariadic::No)
}
/// Parses an optional return type `[ -> TY ]` in a function declaration.
pub(super) fn parse_ret_ty(
&mut self,
allow_plus: bool,
allow_qpath_recovery: bool,
allow_plus: AllowPlus,
recover_qpath: RecoverQPath,
) -> PResult<'a, FunctionRetTy> {
Ok(if self.eat(&token::RArrow) {
// FIXME(Centril): Can we unconditionally `allow_plus`?
FunctionRetTy::Ty(self.parse_ty_common(allow_plus, allow_qpath_recovery, false)?)
let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?;
FunctionRetTy::Ty(ty)
} else {
FunctionRetTy::Default(self.token.span.shrink_to_lo())
})
@ -84,11 +104,11 @@ impl<'a> Parser<'a> {
fn parse_ty_common(
&mut self,
allow_plus: bool,
allow_qpath_recovery: bool,
// Is `...` (`CVarArgs`) legal in the immediate top level call?
allow_c_variadic: bool,
allow_plus: AllowPlus,
recover_qpath: RecoverQPath,
allow_c_variadic: AllowCVariadic,
) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
maybe_whole!(self, NtTy, |x| x);
@ -124,7 +144,7 @@ impl<'a> Parser<'a> {
self.parse_ty_bare_fn(lifetime_defs)?
} else {
let path = self.parse_path(PathStyle::Type)?;
let parse_plus = allow_plus && self.check_plus();
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)?
}
} else if self.eat_keyword(kw::Impl) {
@ -144,7 +164,7 @@ impl<'a> Parser<'a> {
} else if self.token.is_path_start() {
self.parse_path_start_ty(lo, allow_plus)?
} else if self.eat(&token::DotDotDot) {
if allow_c_variadic {
if allow_c_variadic == AllowCVariadic::Yes {
TyKind::CVarArgs
} else {
// FIXME(Centril): Should we just allow `...` syntactically
@ -172,7 +192,7 @@ impl<'a> Parser<'a> {
/// Parses either:
/// - `(TYPE)`, a parenthesized type.
/// - `(TYPE,)`, a tuple with a single field of type TYPE.
fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: bool) -> PResult<'a, TyKind> {
fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
let mut trailing_plus = false;
let (ts, trailing) = self.parse_paren_comma_seq(|p| {
let ty = p.parse_ty()?;
@ -182,7 +202,7 @@ impl<'a> Parser<'a> {
if ts.len() == 1 && !trailing {
let ty = ts.into_iter().nth(0).unwrap().into_inner();
let maybe_bounds = allow_plus && self.token.is_like_plus();
let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus();
match ty.kind {
// `(TY_BOUND_NOPAREN) + BOUND + ...`.
TyKind::Path(None, path) if maybe_bounds => {
@ -288,7 +308,8 @@ impl<'a> Parser<'a> {
let unsafety = self.parse_unsafety();
let ext = self.parse_extern()?;
self.expect_keyword(kw::Fn)?;
let decl = self.parse_fn_decl(&ParamCfg { is_name_required: |_| false }, false)?;
let cfg = ParamCfg { is_name_required: |_| false };
let decl = self.parse_fn_decl(&cfg, AllowPlus::No)?;
Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params, decl })))
}
@ -326,7 +347,7 @@ impl<'a> Parser<'a> {
/// 1. a type macro, `mac!(...)`,
/// 2. a bare trait object, `B0 + ... + Bn`,
/// 3. or a path, `path::to::MyType`.
fn parse_path_start_ty(&mut self, lo: Span, allow_plus: bool) -> PResult<'a, TyKind> {
fn parse_path_start_ty(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
// Simple path
let path = self.parse_path(PathStyle::Type)?;
if self.eat(&token::Not) {
@ -336,7 +357,7 @@ impl<'a> Parser<'a> {
args: self.parse_mac_args()?,
prior_type_ascription: self.last_type_ascription,
}))
} else if allow_plus && self.check_plus() {
} else if allow_plus == AllowPlus::Yes && self.check_plus() {
// `Trait1 + Trait2 + 'a`
self.parse_remaining_bounds(Vec::new(), path, lo, true)
} else {
@ -359,7 +380,7 @@ impl<'a> Parser<'a> {
&mut self,
colon_span: Option<Span>,
) -> PResult<'a, GenericBounds> {
self.parse_generic_bounds_common(true, colon_span)
self.parse_generic_bounds_common(AllowPlus::Yes, colon_span)
}
/// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`.
@ -367,7 +388,7 @@ impl<'a> Parser<'a> {
/// See `parse_generic_bound` for the `BOUND` grammar.
fn parse_generic_bounds_common(
&mut self,
allow_plus: bool,
allow_plus: AllowPlus,
colon_span: Option<Span>,
) -> PResult<'a, GenericBounds> {
let mut bounds = Vec::new();
@ -377,7 +398,7 @@ impl<'a> Parser<'a> {
Ok(bound) => bounds.push(bound),
Err(neg_sp) => negative_bounds.push(neg_sp),
}
if !allow_plus || !self.eat_plus() {
if allow_plus == AllowPlus::No || !self.eat_plus() {
break;
}
}

View File

@ -302,19 +302,18 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
ast_visit::walk_ty(self, t)
}
fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, fd: &'v ast::FnDecl, s: Span, _: NodeId) {
self.record("FnDecl", Id::None, fd);
ast_visit::walk_fn(self, fk, fd, s)
fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, s: Span, _: NodeId) {
self.record("FnDecl", Id::None, fk.decl());
ast_visit::walk_fn(self, fk, s)
}
fn visit_trait_item(&mut self, ti: &'v ast::AssocItem) {
self.record("TraitItem", Id::None, ti);
ast_visit::walk_trait_item(self, ti)
}
fn visit_impl_item(&mut self, ii: &'v ast::AssocItem) {
self.record("ImplItem", Id::None, ii);
ast_visit::walk_impl_item(self, ii)
fn visit_assoc_item(&mut self, item: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
let label = match ctxt {
ast_visit::AssocCtxt::Trait => "TraitItem",
ast_visit::AssocCtxt::Impl => "ImplItem",
};
self.record(label, Id::None, item);
ast_visit::walk_assoc_item(self, item, ctxt);
}
fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound) {

View File

@ -36,7 +36,7 @@ use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, Nod
use syntax::ast::{AssocItem, AssocItemKind, MetaItemKind, StmtKind};
use syntax::ast::{Ident, Name};
use syntax::token::{self, Token};
use syntax::visit::{self, Visitor};
use syntax::visit::{self, AssocCtxt, Visitor};
use log::debug;
use std::cell::Cell;
@ -1234,7 +1234,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
self.parent_scope.legacy = orig_current_legacy_scope;
}
fn visit_trait_item(&mut self, item: &'b AssocItem) {
fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) {
let parent = self.parent_scope.module;
if let AssocItemKind::Macro(_) = item.kind {
@ -1242,6 +1242,12 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
return;
}
if let AssocCtxt::Impl = ctxt {
self.resolve_visibility(&item.vis);
visit::walk_assoc_item(self, item, ctxt);
return;
}
// Add the item to the trait info.
let item_def_id = self.r.definitions.local_def_id(item.id);
let (res, ns) = match item.kind {
@ -1260,16 +1266,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
let expansion = self.parent_scope.expansion;
self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion));
visit::walk_trait_item(self, item);
}
fn visit_impl_item(&mut self, item: &'b ast::AssocItem) {
if let ast::AssocItemKind::Macro(..) = item.kind {
self.visit_invoc(item.id);
} else {
self.resolve_visibility(&item.vis);
visit::walk_impl_item(self, item);
}
visit::walk_assoc_item(self, item, ctxt);
}
fn visit_token(&mut self, t: Token) {

View File

@ -125,7 +125,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
&sig.header,
generics,
&sig.decl,
Some(body),
body.as_deref(),
);
}
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => {
@ -213,39 +213,26 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
visit::walk_generic_param(self, param);
}
fn visit_trait_item(&mut self, ti: &'a AssocItem) {
let def_data = match ti.kind {
AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(ti.ident.name),
AssocItemKind::TyAlias(..) => DefPathData::TypeNs(ti.ident.name),
AssocItemKind::Macro(..) => return self.visit_macro_invoc(ti.id),
};
let def = self.create_def(ti.id, def_data, ti.span);
self.with_parent(def, |this| visit::walk_trait_item(this, ti));
}
fn visit_impl_item(&mut self, ii: &'a AssocItem) {
let def_data = match ii.kind {
AssocItemKind::Fn(FnSig { ref header, ref decl }, ref body)
if header.asyncness.node.is_async() =>
{
fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) {
let def_data = match &i.kind {
AssocItemKind::Fn(FnSig { header, decl }, body) if header.asyncness.node.is_async() => {
return self.visit_async_fn(
ii.id,
ii.ident.name,
ii.span,
i.id,
i.ident.name,
i.span,
header,
&ii.generics,
&i.generics,
decl,
body.as_deref(),
);
}
AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(ii.ident.name),
AssocItemKind::TyAlias(..) => DefPathData::TypeNs(ii.ident.name),
AssocItemKind::Macro(..) => return self.visit_macro_invoc(ii.id),
AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(i.ident.name),
AssocItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name),
AssocItemKind::Macro(..) => return self.visit_macro_invoc(i.id),
};
let def = self.create_def(ii.id, def_data, ii.span);
self.with_parent(def, |this| visit::walk_impl_item(this, ii));
let def = self.create_def(i.id, def_data, i.span);
self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt));
}
fn visit_pat(&mut self, pat: &'a Pat) {

View File

@ -24,7 +24,7 @@ use smallvec::{smallvec, SmallVec};
use syntax::ast::*;
use syntax::ptr::P;
use syntax::util::lev_distance::find_best_match_for_name;
use syntax::visit::{self, FnKind, Visitor};
use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use syntax::{unwrap_or, walk_list};
use log::debug;
@ -437,7 +437,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
}
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
match foreign_item.kind {
ForeignItemKind::Fn(_, ref generics) => {
ForeignItemKind::Fn(_, ref generics, _) => {
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_foreign_item(this, foreign_item);
});
@ -452,13 +452,15 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
}
}
}
fn visit_fn(&mut self, fn_kind: FnKind<'ast>, declaration: &'ast FnDecl, sp: Span, _: NodeId) {
fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
let rib_kind = match fn_kind {
FnKind::Fn(FnCtxt::Foreign, ..) => return visit::walk_fn(self, fn_kind, sp),
FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
FnKind::Fn(FnCtxt::Assoc(_), ..) | FnKind::Closure(..) => NormalRibKind,
};
let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some(sp));
debug!("(resolving function) entering function");
let rib_kind = match fn_kind {
FnKind::ItemFn(..) => FnItemRibKind,
FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind,
};
let declaration = fn_kind.decl();
// Create a value rib for the function.
self.with_rib(ValueNS, rib_kind, |this| {
@ -471,8 +473,8 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
// Resolve the function body, potentially inside the body of an async closure
match fn_kind {
FnKind::ItemFn(.., body) | FnKind::Method(.., body) => this.visit_block(body),
FnKind::Closure(body) => this.visit_expr(body),
FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
FnKind::Closure(_, body) => this.visit_expr(body),
};
debug!("(resolving function) leaving function");
@ -843,12 +845,16 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
});
}
}
AssocItemKind::Fn(_, _) => {
visit::walk_trait_item(this, trait_item)
}
AssocItemKind::TyAlias(..) => {
visit::walk_trait_item(this, trait_item)
}
AssocItemKind::Fn(_, _) => visit::walk_assoc_item(
this,
trait_item,
AssocCtxt::Trait,
),
AssocItemKind::TyAlias(..) => visit::walk_assoc_item(
this,
trait_item,
AssocCtxt::Trait,
),
AssocItemKind::Macro(_) => {
panic!("unexpanded macro in resolve!")
}
@ -1128,7 +1134,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
);
this.with_constant_rib(|this| {
visit::walk_impl_item(this, impl_item)
visit::walk_assoc_item(
this,
impl_item,
AssocCtxt::Impl,
)
});
}
AssocItemKind::Fn(..) => {
@ -1139,7 +1149,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
impl_item.span,
|n, s| MethodNotMemberOfTrait(n, s));
visit::walk_impl_item(this, impl_item);
visit::walk_assoc_item(
this,
impl_item,
AssocCtxt::Impl,
)
}
AssocItemKind::TyAlias(_, _) => {
// If this is a trait impl, ensure the type
@ -1149,7 +1163,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
impl_item.span,
|n, s| TypeNotMemberOfTrait(n, s));
visit::walk_impl_item(this, impl_item);
visit::walk_assoc_item(
this,
impl_item,
AssocCtxt::Impl,
)
}
AssocItemKind::Macro(_) =>
panic!("unexpanded macro in resolve!"),

View File

@ -358,7 +358,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
decl: &'l ast::FnDecl,
header: &'l ast::FnHeader,
ty_params: &'l ast::Generics,
body: &'l ast::Block,
body: Option<&'l ast::Block>,
) {
let hir_id = self.tcx.hir().node_to_hir_id(item.id);
self.nest_tables(item.id, |v| {
@ -392,7 +392,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
}
}
v.visit_block(&body);
walk_list!(v, visit_block, body);
});
}
@ -1291,7 +1291,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
}
}
Fn(ref sig, ref ty_params, ref body) => {
self.process_fn(item, &sig.decl, &sig.header, ty_params, &body)
self.process_fn(item, &sig.decl, &sig.header, ty_params, body.as_deref())
}
Static(ref typ, _, ref expr) => self.process_static_or_const_item(item, typ, expr),
Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr),
@ -1515,7 +1515,8 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
let access = access_from!(self.save_ctxt, item, hir_id);
match item.kind {
ast::ForeignItemKind::Fn(ref decl, ref generics) => {
ast::ForeignItemKind::Fn(ref sig, ref generics, _) => {
let decl = &sig.decl;
if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
down_cast_data!(fn_data, DefData, item.span);

View File

@ -133,7 +133,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(item.id))
);
match item.kind {
ast::ForeignItemKind::Fn(ref decl, ref generics) => {
ast::ForeignItemKind::Fn(ref sig, ref generics, _) => {
filter!(self.span_utils, item.ident.span);
Some(Data::DefData(Def {
@ -142,7 +142,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
span: self.span_from_span(item.ident.span),
name: item.ident.to_string(),
qualname,
value: make_signature(decl, generics),
value: make_signature(&sig.decl, generics),
parent: None,
children: vec![],
decl_id: None,

View File

@ -723,7 +723,8 @@ impl Sig for ast::ForeignItem {
fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
let id = Some(self.id);
match self.kind {
ast::ForeignItemKind::Fn(ref decl, ref generics) => {
ast::ForeignItemKind::Fn(ref sig, ref generics, _) => {
let decl = &sig.decl;
let mut text = String::new();
text.push_str("fn ");

View File

@ -2533,6 +2533,17 @@ pub struct FnHeader {
pub ext: Extern,
}
impl FnHeader {
/// Does this function header have any qualifiers or is it empty?
pub fn has_qualifiers(&self) -> bool {
let Self { unsafety, asyncness, constness, ext } = self;
matches!(unsafety, Unsafety::Unsafe)
|| asyncness.node.is_async()
|| matches!(constness.node, Constness::Const)
|| !matches!(ext, Extern::None)
}
}
impl Default for FnHeader {
fn default() -> FnHeader {
FnHeader {
@ -2565,7 +2576,7 @@ pub enum ItemKind {
/// A function declaration (`fn`).
///
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
Fn(FnSig, Generics, P<Block>),
Fn(FnSig, Generics, Option<P<Block>>),
/// A module declaration (`mod`).
///
/// E.g., `mod foo;` or `mod foo { .. }`.
@ -2667,7 +2678,7 @@ pub type ForeignItem = Item<ForeignItemKind>;
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub enum ForeignItemKind {
/// A foreign function.
Fn(P<FnDecl>, Generics),
Fn(FnSig, Generics, Option<P<Block>>),
/// A foreign static item (`static ext: u8`).
Static(P<Ty>, Mutability),
/// A foreign type.

View File

@ -901,7 +901,7 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
ItemKind::Fn(sig, generics, body) => {
visit_fn_sig(sig, vis);
vis.visit_generics(generics);
vis.visit_block(body);
visit_opt(body, |body| vis.visit_block(body));
}
ItemKind::Mod(m) => vis.visit_mod(m),
ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
@ -1044,9 +1044,10 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
visitor.visit_ident(ident);
visit_attrs(attrs, visitor);
match kind {
ForeignItemKind::Fn(fdec, generics) => {
visitor.visit_fn_decl(fdec);
ForeignItemKind::Fn(sig, generics, body) => {
visit_fn_sig(sig, visitor);
visitor.visit_generics(generics);
visit_opt(body, |body| visitor.visit_block(body));
}
ForeignItemKind::Static(t, _m) => visitor.visit_ty(t),
ForeignItemKind::Ty => {}

View File

@ -19,24 +19,47 @@ use crate::tokenstream::{TokenStream, TokenTree};
use rustc_span::Span;
#[derive(Copy, Clone, PartialEq)]
pub enum AssocCtxt {
Trait,
Impl,
}
#[derive(Copy, Clone, PartialEq)]
pub enum FnCtxt {
Free,
Foreign,
Assoc(AssocCtxt),
}
#[derive(Copy, Clone)]
pub enum FnKind<'a> {
/// E.g., `fn foo()` or `extern "Abi" fn foo()`.
ItemFn(Ident, &'a FnHeader, &'a Visibility, &'a Block),
/// E.g., `fn foo(&self)`.
Method(Ident, &'a FnSig, &'a Visibility, &'a Block),
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>),
/// E.g., `|x, y| body`.
Closure(&'a Expr),
Closure(&'a FnDecl, &'a Expr),
}
impl<'a> FnKind<'a> {
pub fn header(&self) -> Option<&'a FnHeader> {
match *self {
FnKind::ItemFn(_, header, _, _) => Some(header),
FnKind::Method(_, sig, _, _) => Some(&sig.header),
FnKind::Closure(_) => None,
FnKind::Fn(_, _, sig, _, _) => Some(&sig.header),
FnKind::Closure(_, _) => None,
}
}
pub fn decl(&self) -> &'a FnDecl {
match self {
FnKind::Fn(_, _, sig, _, _) => &sig.decl,
FnKind::Closure(decl, _) => decl,
}
}
pub fn ctxt(&self) -> Option<FnCtxt> {
match self {
FnKind::Fn(ctxt, ..) => Some(*ctxt),
FnKind::Closure(..) => None,
}
}
}
@ -106,17 +129,11 @@ pub trait Visitor<'ast>: Sized {
fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
walk_where_predicate(self, p)
}
fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl, s: Span, _: NodeId) {
walk_fn(self, fk, fd, s)
fn visit_fn(&mut self, fk: FnKind<'ast>, s: Span, _: NodeId) {
walk_fn(self, fk, s)
}
fn visit_trait_item(&mut self, i: &'ast AssocItem) {
walk_trait_item(self, i)
}
fn visit_impl_item(&mut self, i: &'ast AssocItem) {
walk_impl_item(self, i)
}
fn visit_assoc_item(&mut self, i: &'ast AssocItem) {
walk_assoc_item(self, i)
fn visit_assoc_item(&mut self, i: &'ast AssocItem, ctxt: AssocCtxt) {
walk_assoc_item(self, i, ctxt)
}
fn visit_trait_ref(&mut self, t: &'ast TraitRef) {
walk_trait_ref(self, t)
@ -287,13 +304,8 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
}
ItemKind::Fn(ref sig, ref generics, ref body) => {
visitor.visit_generics(generics);
visitor.visit_fn_header(&sig.header);
visitor.visit_fn(
FnKind::ItemFn(item.ident, &sig.header, &item.vis, body),
&sig.decl,
item.span,
item.id,
)
let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
visitor.visit_fn(kind, item.span, item.id)
}
ItemKind::Mod(ref module) => visitor.visit_mod(module, item.span, &item.attrs, item.id),
ItemKind::ForeignMod(ref foreign_module) => {
@ -321,17 +333,17 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
visitor.visit_generics(generics);
walk_list!(visitor, visit_trait_ref, of_trait);
visitor.visit_ty(self_ty);
walk_list!(visitor, visit_impl_item, items);
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Impl);
}
ItemKind::Struct(ref struct_definition, ref generics)
| ItemKind::Union(ref struct_definition, ref generics) => {
visitor.visit_generics(generics);
visitor.visit_variant_data(struct_definition);
}
ItemKind::Trait(.., ref generics, ref bounds, ref methods) => {
ItemKind::Trait(.., ref generics, ref bounds, ref items) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_trait_item, methods);
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
}
ItemKind::TraitAlias(ref generics, ref bounds) => {
visitor.visit_generics(generics);
@ -512,21 +524,22 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
}
}
pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a ForeignItem) {
visitor.visit_vis(&foreign_item.vis);
visitor.visit_ident(foreign_item.ident);
pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignItem) {
visitor.visit_vis(&item.vis);
visitor.visit_ident(item.ident);
match foreign_item.kind {
ForeignItemKind::Fn(ref function_declaration, ref generics) => {
walk_fn_decl(visitor, function_declaration);
visitor.visit_generics(generics)
match item.kind {
ForeignItemKind::Fn(ref sig, ref generics, ref body) => {
visitor.visit_generics(generics);
let kind = FnKind::Fn(FnCtxt::Foreign, item.ident, sig, &item.vis, body.as_deref());
visitor.visit_fn(kind, item.span, item.id);
}
ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
ForeignItemKind::Ty => (),
ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac),
}
walk_list!(visitor, visit_attribute, &foreign_item.attrs);
walk_list!(visitor, visit_attribute, &item.attrs);
}
pub fn walk_global_asm<'a, V: Visitor<'a>>(_: &mut V, _: &'a GlobalAsm) {
@ -594,37 +607,21 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &
visitor.visit_fn_ret_ty(&function_declaration.output);
}
pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl, _span: Span)
where
V: Visitor<'a>,
{
pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Span) {
match kind {
FnKind::ItemFn(_, header, _, body) => {
visitor.visit_fn_header(header);
walk_fn_decl(visitor, declaration);
visitor.visit_block(body);
}
FnKind::Method(_, sig, _, body) => {
FnKind::Fn(_, _, sig, _, body) => {
visitor.visit_fn_header(&sig.header);
walk_fn_decl(visitor, declaration);
visitor.visit_block(body);
walk_fn_decl(visitor, &sig.decl);
walk_list!(visitor, visit_block, body);
}
FnKind::Closure(body) => {
walk_fn_decl(visitor, declaration);
FnKind::Closure(decl, body) => {
walk_fn_decl(visitor, decl);
visitor.visit_expr(body);
}
}
}
pub fn walk_impl_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) {
visitor.visit_assoc_item(item);
}
pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) {
visitor.visit_assoc_item(item);
}
pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) {
pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, ctxt: AssocCtxt) {
visitor.visit_vis(&item.vis);
visitor.visit_ident(item.ident);
walk_list!(visitor, visit_attribute, &item.attrs);
@ -634,17 +631,9 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem)
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}
AssocItemKind::Fn(ref sig, None) => {
visitor.visit_fn_header(&sig.header);
walk_fn_decl(visitor, &sig.decl);
}
AssocItemKind::Fn(ref sig, Some(ref body)) => {
visitor.visit_fn(
FnKind::Method(item.ident, sig, &item.vis, body),
&sig.decl,
item.span,
item.id,
);
AssocItemKind::Fn(ref sig, ref body) => {
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
visitor.visit_fn(kind, item.span, item.id);
}
AssocItemKind::TyAlias(ref bounds, ref ty) => {
walk_list!(visitor, visit_param_bound, bounds);
@ -765,8 +754,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
visitor.visit_expr(subexpression);
walk_list!(visitor, visit_arm, arms);
}
ExprKind::Closure(_, _, _, ref function_declaration, ref body, _decl_span) => visitor
.visit_fn(FnKind::Closure(body), function_declaration, expression.span, expression.id),
ExprKind::Closure(_, _, _, ref decl, ref body, _decl_span) => {
visitor.visit_fn(FnKind::Closure(decl, body), expression.span, expression.id)
}
ExprKind::Block(ref block, ref opt_label) => {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_block(block);

View File

@ -1,5 +1,5 @@
extern "C" {
fn foo() -> i32 { //~ ERROR incorrect `fn` inside `extern` block
fn foo() -> i32 { //~ ERROR incorrect function inside `extern` block
return 0;
}
}

View File

@ -1,17 +1,17 @@
error: incorrect `fn` inside `extern` block
error: incorrect function inside `extern` block
--> $DIR/extern-ffi-fn-with-body.rs:2:8
|
LL | extern "C" {
| ------ `extern` blocks define existing foreign functions and `fn`s inside of them cannot have a body
| ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body
LL | fn foo() -> i32 {
| ________^^^__________-
| | |
| | can't have a body
| | cannot have a body
LL | | return 0;
LL | | }
| |_____- this body is invalid here
| |_____- help: remove the invalid body: `;`
|
= help: you might have meant to write a function accessible through ffi, which can be done by writing `extern fn` outside of the `extern` block
= help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
error: aborting due to previous error

View File

@ -1,5 +1,4 @@
fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0`
//~| ERROR expected one of `)`, `,`, `->`, `where`, or `{`, found `]`
// FIXME(jseyfried): avoid emitting the second error (preexisting)
//~| ERROR expected `;` or `{`, found `]`
fn main() {}

View File

@ -4,11 +4,11 @@ error: expected type, found `0`
LL | fn foo(a: [0; 1]) {}
| ^ expected type
error: expected one of `)`, `,`, `->`, `where`, or `{`, found `]`
error: expected `;` or `{`, found `]`
--> $DIR/issue-39616.rs:1:16
|
LL | fn foo(a: [0; 1]) {}
| ^ expected one of `)`, `,`, `->`, `where`, or `{`
| ^ expected `;` or `{`
error: aborting due to 2 previous errors

View File

@ -1,8 +1,8 @@
error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found keyword `let`
error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `static`, `type`, or `unsafe`, found keyword `let`
--> $DIR/issue-54441.rs:3:9
|
LL | let
| ^^^ expected one of `crate`, `fn`, `pub`, `static`, or `type`
| ^^^ expected one of 9 possible tokens
...
LL | m!();
| ----- in this macro invocation

View File

@ -1,9 +1,9 @@
#![deny(patterns_in_fns_without_body)]
trait Tr {
fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in methods without bodies
fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in functions without bodies
//~^ WARN was previously accepted
fn f2(&arg: u8); //~ ERROR patterns aren't allowed in methods without bodies
fn f2(&arg: u8); //~ ERROR patterns aren't allowed in functions without bodies
fn g1(arg: u8); // OK
fn g2(_: u8); // OK
#[allow(anonymous_parameters)]

View File

@ -1,10 +1,10 @@
error[E0642]: patterns aren't allowed in methods without bodies
error[E0642]: patterns aren't allowed in functions without bodies
--> $DIR/no-patterns-in-args-2.rs:6:11
|
LL | fn f2(&arg: u8);
| ^^^^
| ^^^^ pattern not allowed in function without body
error: patterns aren't allowed in methods without bodies
error: patterns aren't allowed in functions without bodies
--> $DIR/no-patterns-in-args-2.rs:4:11
|
LL | fn f1(mut arg: u8);

View File

@ -6,10 +6,10 @@ macro_rules! m {
type A = fn($pat: u8);
extern {
extern "C" {
fn foreign_fn($pat: u8);
}
}
};
}
mod good_pat {
@ -20,7 +20,7 @@ mod bad_pat {
m!((bad, pat));
//~^ ERROR patterns aren't allowed in function pointer types
//~| ERROR patterns aren't allowed in foreign function declarations
//~| ERROR patterns aren't allowed in methods without bodies
//~| ERROR patterns aren't allowed in functions without bodies
}
fn main() {}

View File

@ -1,8 +1,8 @@
error[E0642]: patterns aren't allowed in methods without bodies
error[E0642]: patterns aren't allowed in functions without bodies
--> $DIR/no-patterns-in-args-macro.rs:20:8
|
LL | m!((bad, pat));
| ^^^^^^^^^^
| ^^^^^^^^^^ pattern not allowed in function without body
error[E0561]: patterns aren't allowed in function pointer types
--> $DIR/no-patterns-in-args-macro.rs:20:8

View File

@ -1,4 +1,4 @@
// error-pattern:expected one of `(`, `fn`, `static`, or `type`
// error-pattern: expected one of `(`, `async`, `const`, `extern`, `fn`
extern {
pub pub fn foo();
}

View File

@ -1,8 +1,8 @@
error: expected one of `(`, `fn`, `static`, or `type`, found keyword `pub`
error: expected one of `(`, `async`, `const`, `extern`, `fn`, `static`, `type`, or `unsafe`, found keyword `pub`
--> $DIR/duplicate-visibility.rs:3:9
|
LL | pub pub fn foo();
| ^^^ expected one of `(`, `fn`, `static`, or `type`
| ^^^ expected one of 8 possible tokens
error: aborting due to previous error

View File

@ -0,0 +1,27 @@
// Tests the different rules for `fn` forms requiring the presence or lack of a body.
fn main() {
fn f1(); //~ ERROR free function without a body
fn f2() {} // OK.
trait X {
fn f1(); // OK.
fn f2() {} // OK.
}
struct Y;
impl X for Y {
fn f1(); //~ ERROR associated function in `impl` without body
fn f2() {} // OK.
}
impl Y {
fn f3(); //~ ERROR associated function in `impl` without body
fn f4() {} // OK.
}
extern {
fn f5(); // OK.
fn f6() {} //~ ERROR incorrect function inside `extern` block
}
}

View File

@ -0,0 +1,40 @@
error: free function without a body
--> $DIR/fn-body-optional-semantic-fail.rs:4:5
|
LL | fn f1();
| ^^^^^^^-
| |
| help: provide a definition for the function: `{ <body> }`
error: associated function in `impl` without body
--> $DIR/fn-body-optional-semantic-fail.rs:14:9
|
LL | fn f1();
| ^^^^^^^-
| |
| help: provide a definition for the function: `{ <body> }`
error: associated function in `impl` without body
--> $DIR/fn-body-optional-semantic-fail.rs:19:9
|
LL | fn f3();
| ^^^^^^^-
| |
| help: provide a definition for the function: `{ <body> }`
error: incorrect function inside `extern` block
--> $DIR/fn-body-optional-semantic-fail.rs:25:12
|
LL | extern {
| ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body
LL | fn f5(); // OK.
LL | fn f6() {}
| ^^ -- help: remove the invalid body: `;`
| |
| cannot have a body
|
= help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
error: aborting due to 4 previous errors

View File

@ -0,0 +1,31 @@
// Ensures that all `fn` forms having or lacking a body are syntactically valid.
// check-pass
fn main() {}
#[cfg(FALSE)]
fn syntax() {
fn f();
fn f() {}
trait X {
fn f();
fn f() {}
}
impl X for Y {
fn f();
fn f() {}
}
impl Y {
fn f();
fn f() {}
}
extern {
fn f();
fn f() {}
}
}

View File

@ -0,0 +1,57 @@
// Ensures that all `fn` forms can have all the function qualifiers syntactically.
// edition:2018
#![feature(const_extern_fn)]
#![feature(const_fn)]
fn main() {
async fn ff1() {} // OK.
unsafe fn ff2() {} // OK.
const fn ff3() {} // OK.
extern "C" fn ff4() {} // OK.
const /* async */ unsafe extern "C" fn ff5() {} // OK.
//^ FIXME(Centril): `async` should be legal syntactically, ensure it's illegal semantically.
trait X {
async fn ft1(); //~ ERROR trait fns cannot be declared `async`
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();
//~^ ERROR trait fns cannot be declared `async`
//^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically.
}
struct Y;
impl X for Y {
async fn ft1() {} //~ ERROR trait fns cannot be declared `async`
//~^ ERROR method `ft1` has an incompatible type for trait
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() {}
//~^ ERROR trait fns cannot be declared `async`
//~| ERROR method `ft5` has an incompatible type for trait
//^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically.
}
impl Y {
async fn fi1() {} // OK.
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.
}
extern {
async fn fe1(); //~ ERROR functions in `extern` blocks cannot have qualifiers
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.
}
}

View File

@ -0,0 +1,136 @@
error[E0706]: trait fns cannot be declared `async`
--> $DIR/fn-header-semantic-fail.rs:17:9
|
LL | async fn ft1();
| ^^^^^^^^^^^^^^^
|
= note: `async` trait functions are not currently supported
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
error[E0379]: trait fns cannot be declared const
--> $DIR/fn-header-semantic-fail.rs:19:9
|
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
|
LL | /* const */ async unsafe extern "C" fn ft5();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `async` trait functions are not currently supported
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
error[E0706]: trait fns cannot be declared `async`
--> $DIR/fn-header-semantic-fail.rs:28:9
|
LL | async fn ft1() {}
| ^^^^^^^^^^^^^^^^^
|
= note: `async` trait functions are not currently supported
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
error[E0379]: trait fns cannot be declared const
--> $DIR/fn-header-semantic-fail.rs:31:9
|
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
|
LL | /* const */ async unsafe extern "C" fn ft5() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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
|
LL | extern {
| ------ in this `extern` block
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
|
LL | extern {
| ------ in this `extern` block
LL | async fn fe1();
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
|
LL | extern {
| ------ in this `extern` block
...
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
|
LL | extern {
| ------ in this `extern` block
...
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
|
LL | extern {
| ------ in this `extern` block
...
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
|
LL | async fn ft1();
| - type in trait
...
LL | async fn ft1() {}
| ^
| |
| the `Output` of this `async fn`'s found opaque type
| expected `()`, found opaque type
|
= note: expected fn pointer `fn()`
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
|
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
|
= 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
Some errors have detailed explanations: E0053, E0379, E0706.
For more information about an error, try `rustc --explain E0053`.

View File

@ -0,0 +1,55 @@
// Ensures that all `fn` forms can have all the function qualifiers syntactically.
// check-pass
// edition:2018
#![feature(const_extern_fn)]
//^ FIXME(Centril): move check to ast_validation.
fn main() {}
#[cfg(FALSE)]
fn syntax() {
async fn f();
unsafe fn f();
const fn f();
extern "C" fn f();
const /* async */ unsafe extern "C" fn f();
//^ FIXME(Centril): `async` should be legal syntactically.
trait X {
async fn f();
unsafe fn f();
const fn f();
extern "C" fn f();
/* const */ async unsafe extern "C" fn f();
//^ FIXME(Centril): `const` should be legal syntactically.
}
impl X for Y {
async fn f();
unsafe fn f();
const fn f();
extern "C" fn f();
/* const */ async unsafe extern "C" fn f();
//^ FIXME(Centril): `const` should be legal syntactically.
}
impl Y {
async fn f();
unsafe fn f();
const fn f();
extern "C" fn f();
/* const */ async unsafe extern "C" fn f();
//^ FIXME(Centril): `const` should be legal syntactically.
}
extern {
async fn f();
unsafe fn f();
const fn f();
extern "C" fn f();
/* const */ async unsafe extern "C" fn f();
//^ FIXME(Centril): `const` should be legal syntactically.
}
}

View File

@ -3,6 +3,6 @@
// expected one of ..., `>`, ... found `>`
fn foo() -> Vec<usize>> {
//~^ ERROR expected one of `!`, `+`, `::`, `where`, or `{`, found `>`
//~^ ERROR expected `;` or `{`, found `>`
Vec::new()
}

View File

@ -1,8 +1,8 @@
error: expected one of `!`, `+`, `::`, `where`, or `{`, found `>`
error: expected `;` or `{`, found `>`
--> $DIR/issue-24780.rs:5:23
|
LL | fn foo() -> Vec<usize>> {
| ^ expected one of `!`, `+`, `::`, `where`, or `{`
| ^ expected `;` or `{`
error: aborting due to previous error

View File

@ -1,3 +1,3 @@
// error-pattern: aborting due to 6 previous errors
// error-pattern: aborting due to 7 previous errors
fn i(n{...,f #

View File

@ -43,5 +43,11 @@ error: expected one of `:` or `|`, found `)`
LL | fn i(n{...,f #
| ^ expected one of `:` or `|`
error: aborting due to 6 previous errors
error: expected `;` or `{`, found `<eof>`
--> $DIR/issue-63135.rs:3:16
|
LL | fn i(n{...,f #
| ^ expected `;` or `{`
error: aborting due to 7 previous errors

View File

@ -0,0 +1,21 @@
// Make sure we don't propagate restrictions on trait impl items to items inside them.
// check-pass
// edition:2018
fn main() {}
trait X {
fn foo();
}
impl X for () {
fn foo() {
struct S;
impl S {
pub const X: u8 = 0;
pub const fn bar() {}
async fn qux() {}
}
}
}

View File

@ -1,3 +1,3 @@
// ignore-tidy-trailing-newlines
// error-pattern: aborting due to 3 previous errors
// error-pattern: aborting due to 4 previous errors
fn main((ؼ

View File

@ -22,5 +22,11 @@ error: expected one of `:` or `|`, found `)`
LL | fn main((ؼ
| ^ expected one of `:` or `|`
error: aborting due to 3 previous errors
error: expected `;` or `{`, found `<eof>`
--> $DIR/missing_right_paren.rs:3:11
|
LL | fn main((ؼ
| ^ expected `;` or `{`
error: aborting due to 4 previous errors

View File

@ -1,8 +1,8 @@
extern {
const fn foo();
//~^ ERROR extern items cannot be `const`
//~^ ERROR functions in `extern` blocks cannot have qualifiers
const unsafe fn bar();
//~^ ERROR extern items cannot be `const`
//~^ ERROR functions in `extern` blocks cannot have qualifiers
}
fn main() {}

View File

@ -1,14 +1,23 @@
error: extern items cannot be `const`
--> $DIR/no-const-fn-in-extern-block.rs:2:5
error: functions in `extern` blocks cannot have qualifiers
--> $DIR/no-const-fn-in-extern-block.rs:2:14
|
LL | extern {
| ------ in this `extern` block
LL | const fn foo();
| ^^^^^
| ---------^^^
| |
| help: remove the qualifiers: `fn`
error: extern items cannot be `const`
--> $DIR/no-const-fn-in-extern-block.rs:4:5
error: functions in `extern` blocks cannot have qualifiers
--> $DIR/no-const-fn-in-extern-block.rs:4:21
|
LL | extern {
| ------ in this `extern` block
...
LL | const unsafe fn bar();
| ^^^^^
| ----------------^^^
| |
| help: remove the qualifiers: `fn`
error: aborting due to 2 previous errors

View File

@ -1,8 +1,8 @@
error: expected one of `->`, `where`, or `{`, found `:`
error: expected `;` or `{`, found `:`
--> $DIR/not-a-pred.rs:3:26
|
LL | fn f(a: isize, b: isize) : lt(a, b) { }
| ^ expected one of `->`, `where`, or `{`
| ^ expected `;` or `{`
error: aborting due to previous error