mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
Auto merge of #68893 - Dylan-DPC:rollup-3f2421a, r=Dylan-DPC
Rollup of 9 pull requests Successful merges: - #68691 (Remove `RefCell` usage from `ObligationForest`.) - #68751 (Implement `unused_parens` for `const` and `static` items) - #68788 (Towards unified `fn` grammar) - #68837 (Make associated item collection a query) - #68842 (or_patterns: add regression test for #68785) - #68844 (use def_path_str for missing_debug_impls message) - #68845 (stop using BytePos for computing spans in librustc_parse/parser/mod.rs) - #68869 (clean up E0271 explanation) - #68880 (Forbid using `0` as issue number) Failed merges: r? @ghost
This commit is contained in:
commit
442ae7f040
@ -310,6 +310,11 @@ rustc_queries! {
|
||||
/// Maps from a trait item to the trait item "descriptor".
|
||||
query associated_item(_: DefId) -> ty::AssocItem {}
|
||||
|
||||
/// Collects the associated items defined on a trait or impl.
|
||||
query associated_items(key: DefId) -> ty::AssocItemsIterator<'tcx> {
|
||||
desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
query impl_trait_ref(_: DefId) -> Option<ty::TraitRef<'tcx>> {}
|
||||
query impl_polarity(_: DefId) -> ty::ImplPolarity {}
|
||||
|
||||
|
@ -2743,19 +2743,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
variant.fields.iter().position(|field| self.hygienic_eq(ident, field.ident, variant.def_id))
|
||||
}
|
||||
|
||||
pub fn associated_items(self, def_id: DefId) -> AssocItemsIterator<'tcx> {
|
||||
// Ideally, we would use `-> impl Iterator` here, but it falls
|
||||
// afoul of the conservative "capture [restrictions]" we put
|
||||
// in place, so we use a hand-written iterator.
|
||||
//
|
||||
// [restrictions]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999
|
||||
AssocItemsIterator {
|
||||
tcx: self,
|
||||
def_ids: self.associated_item_def_ids(def_id),
|
||||
next_index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the impls are the same polarity and the trait either
|
||||
/// has no items or is annotated #[marker] and prevents item overrides.
|
||||
pub fn impls_are_allowed_to_overlap(
|
||||
@ -2987,20 +2974,22 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Copy, Clone, HashStable)]
|
||||
pub struct AssocItemsIterator<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_ids: &'tcx [DefId],
|
||||
next_index: usize,
|
||||
pub items: &'tcx [AssocItem],
|
||||
}
|
||||
|
||||
impl Iterator for AssocItemsIterator<'_> {
|
||||
impl<'tcx> Iterator for AssocItemsIterator<'tcx> {
|
||||
type Item = AssocItem;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<AssocItem> {
|
||||
let def_id = self.def_ids.get(self.next_index)?;
|
||||
self.next_index += 1;
|
||||
Some(self.tcx.associated_item(*def_id))
|
||||
if let Some((first, rest)) = self.items.split_first() {
|
||||
self.items = rest;
|
||||
Some(*first)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -396,26 +396,31 @@ where
|
||||
issue_num = match &*issue.unwrap().as_str() {
|
||||
"none" => None,
|
||||
issue => {
|
||||
let emit_diag = |msg: &str| {
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
mi.span,
|
||||
E0545,
|
||||
"`issue` must be a non-zero numeric string \
|
||||
or \"none\"",
|
||||
)
|
||||
.span_label(
|
||||
mi.name_value_literal().unwrap().span,
|
||||
msg,
|
||||
)
|
||||
.emit();
|
||||
};
|
||||
match issue.parse() {
|
||||
Ok(num) => {
|
||||
// FIXME(rossmacarthur): disallow 0
|
||||
// Disallowing this requires updates to
|
||||
// some submodules
|
||||
NonZeroU32::new(num)
|
||||
Ok(num) if num == 0 => {
|
||||
emit_diag(
|
||||
"`issue` must not be \"0\", \
|
||||
use \"none\" instead",
|
||||
);
|
||||
continue 'outer;
|
||||
}
|
||||
Ok(num) => NonZeroU32::new(num),
|
||||
Err(err) => {
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
mi.span,
|
||||
E0545,
|
||||
"`issue` must be a numeric string \
|
||||
or \"none\"",
|
||||
)
|
||||
.span_label(
|
||||
mi.name_value_literal().unwrap().span,
|
||||
&err.to_string(),
|
||||
)
|
||||
.emit();
|
||||
emit_diag(&err.to_string());
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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 {
|
||||
|
@ -74,7 +74,7 @@
|
||||
|
||||
use crate::fx::{FxHashMap, FxHashSet};
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cell::Cell;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::fmt::Debug;
|
||||
use std::hash;
|
||||
@ -146,7 +146,7 @@ pub struct ObligationForest<O: ForestObligation> {
|
||||
active_cache: FxHashMap<O::Predicate, usize>,
|
||||
|
||||
/// A vector reused in compress(), to avoid allocating new vectors.
|
||||
node_rewrites: RefCell<Vec<usize>>,
|
||||
node_rewrites: Vec<usize>,
|
||||
|
||||
obligation_tree_id_generator: ObligationTreeIdGenerator,
|
||||
|
||||
@ -285,7 +285,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
nodes: vec![],
|
||||
done_cache: Default::default(),
|
||||
active_cache: Default::default(),
|
||||
node_rewrites: RefCell::new(vec![]),
|
||||
node_rewrites: vec![],
|
||||
obligation_tree_id_generator: (0..).map(ObligationTreeId),
|
||||
error_cache: Default::default(),
|
||||
}
|
||||
@ -590,7 +590,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
#[inline(never)]
|
||||
fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
|
||||
let orig_nodes_len = self.nodes.len();
|
||||
let mut node_rewrites: Vec<_> = self.node_rewrites.replace(vec![]);
|
||||
let mut node_rewrites: Vec<_> = std::mem::take(&mut self.node_rewrites);
|
||||
debug_assert!(node_rewrites.is_empty());
|
||||
node_rewrites.extend(0..orig_nodes_len);
|
||||
let mut dead_nodes = 0;
|
||||
@ -651,7 +651,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
}
|
||||
|
||||
node_rewrites.truncate(0);
|
||||
self.node_rewrites.replace(node_rewrites);
|
||||
self.node_rewrites = node_rewrites;
|
||||
|
||||
if do_completed == DoCompleted::Yes { Some(removed_done_obligations) } else { None }
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
This is because of a type mismatch between the associated type of some
|
||||
trait (e.g., `T::Bar`, where `T` implements `trait Quux { type Bar; }`)
|
||||
and another type `U` that is required to be equal to `T::Bar`, but is not.
|
||||
Examples follow.
|
||||
A type mismatched an associated type of a trait.
|
||||
|
||||
Here is a basic example:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0271
|
||||
trait Trait { type AssociatedType; }
|
||||
@ -17,6 +14,11 @@ impl Trait for i8 { type AssociatedType = &'static str; }
|
||||
foo(3_i8);
|
||||
```
|
||||
|
||||
This is because of a type mismatch between the associated type of some
|
||||
trait (e.g., `T::Bar`, where `T` implements `trait Quux { type Bar; }`)
|
||||
and another type `U` that is required to be equal to `T::Bar`, but is not.
|
||||
Examples follow.
|
||||
|
||||
Here is that same example again, with some explanatory comments:
|
||||
|
||||
```compile_fail,E0271
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -567,7 +555,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
|
||||
declare_lint! {
|
||||
MISSING_DEBUG_IMPLEMENTATIONS,
|
||||
Allow,
|
||||
"detects missing implementations of fmt::Debug"
|
||||
"detects missing implementations of Debug"
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@ -611,9 +599,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations {
|
||||
cx.span_lint(
|
||||
MISSING_DEBUG_IMPLEMENTATIONS,
|
||||
item.span,
|
||||
"type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` \
|
||||
or a manual implementation",
|
||||
)
|
||||
&format!(
|
||||
"type does not implement `{}`; consider adding `#[derive(Debug)]` \
|
||||
or a manual implementation",
|
||||
cx.tcx.def_path_str(debug)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
);
|
||||
|
@ -587,6 +587,14 @@ impl EarlyLintPass for UnusedParens {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
||||
use ast::ItemKind::*;
|
||||
|
||||
if let Const(.., ref expr) | Static(.., ref expr) = item.kind {
|
||||
self.check_unused_parens_expr(cx, expr, "assigned value", false, None, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
|
@ -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(
|
||||
|
@ -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 }))
|
||||
}
|
||||
|
@ -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)?,
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::source_map::respan;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
|
||||
use rustc_span::{FileName, Span, DUMMY_SP};
|
||||
use syntax::ast::{self, AttrStyle, AttrVec, CrateSugar, Extern, Ident, Unsafety, DUMMY_NODE_ID};
|
||||
use syntax::ast::{IsAsync, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind};
|
||||
use syntax::ptr::P;
|
||||
@ -615,8 +615,8 @@ impl<'a> Parser<'a> {
|
||||
true
|
||||
}
|
||||
token::BinOpEq(token::Plus) => {
|
||||
let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
|
||||
self.bump_with(token::Eq, span);
|
||||
let start_point = self.sess.source_map().start_point(self.token.span);
|
||||
self.bump_with(token::Eq, self.token.span.with_lo(start_point.hi()));
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
@ -633,8 +633,9 @@ impl<'a> Parser<'a> {
|
||||
Ok(())
|
||||
}
|
||||
token::AndAnd => {
|
||||
let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
|
||||
Ok(self.bump_with(token::BinOp(token::And), span))
|
||||
let start_point = self.sess.source_map().start_point(self.token.span);
|
||||
Ok(self
|
||||
.bump_with(token::BinOp(token::And), self.token.span.with_lo(start_point.hi())))
|
||||
}
|
||||
_ => self.unexpected(),
|
||||
}
|
||||
@ -650,8 +651,9 @@ impl<'a> Parser<'a> {
|
||||
Ok(())
|
||||
}
|
||||
token::OrOr => {
|
||||
let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
|
||||
Ok(self.bump_with(token::BinOp(token::Or), span))
|
||||
let start_point = self.sess.source_map().start_point(self.token.span);
|
||||
Ok(self
|
||||
.bump_with(token::BinOp(token::Or), self.token.span.with_lo(start_point.hi())))
|
||||
}
|
||||
_ => self.unexpected(),
|
||||
}
|
||||
@ -671,13 +673,16 @@ impl<'a> Parser<'a> {
|
||||
true
|
||||
}
|
||||
token::BinOp(token::Shl) => {
|
||||
let span = self.sess.source_map().next_point(self.token.span);
|
||||
self.bump_with(token::Lt, span);
|
||||
let start_point = self.sess.source_map().start_point(self.token.span);
|
||||
self.bump_with(token::Lt, self.token.span.with_lo(start_point.hi()));
|
||||
true
|
||||
}
|
||||
token::LArrow => {
|
||||
let span = self.sess.source_map().next_point(self.token.span);
|
||||
self.bump_with(token::BinOp(token::Minus), span);
|
||||
let start_point = self.sess.source_map().start_point(self.token.span);
|
||||
self.bump_with(
|
||||
token::BinOp(token::Minus),
|
||||
self.token.span.with_lo(start_point.hi()),
|
||||
);
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
@ -707,16 +712,16 @@ impl<'a> Parser<'a> {
|
||||
Some(())
|
||||
}
|
||||
token::BinOp(token::Shr) => {
|
||||
let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
|
||||
Some(self.bump_with(token::Gt, span))
|
||||
let start_point = self.sess.source_map().start_point(self.token.span);
|
||||
Some(self.bump_with(token::Gt, self.token.span.with_lo(start_point.hi())))
|
||||
}
|
||||
token::BinOpEq(token::Shr) => {
|
||||
let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
|
||||
Some(self.bump_with(token::Ge, span))
|
||||
let start_point = self.sess.source_map().start_point(self.token.span);
|
||||
Some(self.bump_with(token::Ge, self.token.span.with_lo(start_point.hi())))
|
||||
}
|
||||
token::Ge => {
|
||||
let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
|
||||
Some(self.bump_with(token::Eq, span))
|
||||
let start_point = self.sess.source_map().start_point(self.token.span);
|
||||
Some(self.bump_with(token::Eq, self.token.span.with_lo(start_point.hi())))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
@ -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()
|
||||
};
|
||||
|
||||
|
@ -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())
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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!"),
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 ");
|
||||
|
||||
|
@ -206,6 +206,14 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
|
||||
}
|
||||
}
|
||||
|
||||
fn associated_items<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AssocItemsIterator<'tcx> {
|
||||
ty::AssocItemsIterator {
|
||||
items: tcx.arena.alloc_from_iter(
|
||||
tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span {
|
||||
tcx.hir().span_if_local(def_id).unwrap()
|
||||
}
|
||||
@ -356,6 +364,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
||||
asyncness,
|
||||
associated_item,
|
||||
associated_item_def_ids,
|
||||
associated_items,
|
||||
adt_sized_constraint,
|
||||
def_span,
|
||||
param_env,
|
||||
|
@ -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.
|
||||
|
@ -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 => {}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -4,10 +4,10 @@
|
||||
#![stable(feature = "stable_test_feature", since = "1.0.0")]
|
||||
|
||||
#[unstable(feature = "unstable_test_feature", issue = "0")]
|
||||
fn unstable_issue_0() {}
|
||||
fn unstable_issue_0() {} //~^ ERROR `issue` must be a non-zero numeric string or "none"
|
||||
|
||||
#[unstable(feature = "unstable_test_feature", issue = "none")]
|
||||
fn unstable_issue_none() {}
|
||||
|
||||
#[unstable(feature = "unstable_test_feature", issue = "something")]
|
||||
fn unstable_issue_not_allowed() {} //~^ ERROR `issue` must be a numeric string or "none"
|
||||
fn unstable_issue_not_allowed() {} //~^ ERROR `issue` must be a non-zero numeric string or "none"
|
||||
|
@ -1,4 +1,12 @@
|
||||
error[E0545]: `issue` must be a numeric string or "none"
|
||||
error[E0545]: `issue` must be a non-zero numeric string or "none"
|
||||
--> $DIR/unstable-attribute-allow-issue-0.rs:6:47
|
||||
|
|
||||
LL | #[unstable(feature = "unstable_test_feature", issue = "0")]
|
||||
| ^^^^^^^^---
|
||||
| |
|
||||
| `issue` must not be "0", use "none" instead
|
||||
|
||||
error[E0545]: `issue` must be a non-zero numeric string or "none"
|
||||
--> $DIR/unstable-attribute-allow-issue-0.rs:12:47
|
||||
|
|
||||
LL | #[unstable(feature = "unstable_test_feature", issue = "something")]
|
||||
@ -6,5 +14,5 @@ LL | #[unstable(feature = "unstable_test_feature", issue = "something")]
|
||||
| |
|
||||
| invalid digit found in string
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
||||
|
@ -38,6 +38,9 @@ macro_rules! baz {
|
||||
}
|
||||
}
|
||||
|
||||
const CONST_ITEM: usize = (10); //~ ERROR unnecessary parentheses around assigned value
|
||||
static STATIC_ITEM: usize = (10); //~ ERROR unnecessary parentheses around assigned value
|
||||
|
||||
fn main() {
|
||||
foo();
|
||||
bar((true)); //~ ERROR unnecessary parentheses around function argument
|
||||
|
@ -34,26 +34,38 @@ error: unnecessary parentheses around block return value
|
||||
LL | (5)
|
||||
| ^^^ help: remove these parentheses
|
||||
|
||||
error: unnecessary parentheses around assigned value
|
||||
--> $DIR/lint-unnecessary-parens.rs:41:27
|
||||
|
|
||||
LL | const CONST_ITEM: usize = (10);
|
||||
| ^^^^ help: remove these parentheses
|
||||
|
||||
error: unnecessary parentheses around assigned value
|
||||
--> $DIR/lint-unnecessary-parens.rs:42:29
|
||||
|
|
||||
LL | static STATIC_ITEM: usize = (10);
|
||||
| ^^^^ help: remove these parentheses
|
||||
|
||||
error: unnecessary parentheses around function argument
|
||||
--> $DIR/lint-unnecessary-parens.rs:43:9
|
||||
--> $DIR/lint-unnecessary-parens.rs:46:9
|
||||
|
|
||||
LL | bar((true));
|
||||
| ^^^^^^ help: remove these parentheses
|
||||
|
||||
error: unnecessary parentheses around `if` condition
|
||||
--> $DIR/lint-unnecessary-parens.rs:45:8
|
||||
--> $DIR/lint-unnecessary-parens.rs:48:8
|
||||
|
|
||||
LL | if (true) {}
|
||||
| ^^^^^^ help: remove these parentheses
|
||||
|
||||
error: unnecessary parentheses around `while` condition
|
||||
--> $DIR/lint-unnecessary-parens.rs:46:11
|
||||
--> $DIR/lint-unnecessary-parens.rs:49:11
|
||||
|
|
||||
LL | while (true) {}
|
||||
| ^^^^^^ help: remove these parentheses
|
||||
|
||||
warning: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/lint-unnecessary-parens.rs:46:5
|
||||
--> $DIR/lint-unnecessary-parens.rs:49:5
|
||||
|
|
||||
LL | while (true) {}
|
||||
| ^^^^^^^^^^^^ help: use `loop`
|
||||
@ -61,46 +73,46 @@ LL | while (true) {}
|
||||
= note: `#[warn(while_true)]` on by default
|
||||
|
||||
error: unnecessary parentheses around `match` head expression
|
||||
--> $DIR/lint-unnecessary-parens.rs:48:11
|
||||
--> $DIR/lint-unnecessary-parens.rs:51:11
|
||||
|
|
||||
LL | match (true) {
|
||||
| ^^^^^^ help: remove these parentheses
|
||||
|
||||
error: unnecessary parentheses around `let` head expression
|
||||
--> $DIR/lint-unnecessary-parens.rs:51:16
|
||||
--> $DIR/lint-unnecessary-parens.rs:54:16
|
||||
|
|
||||
LL | if let 1 = (1) {}
|
||||
| ^^^ help: remove these parentheses
|
||||
|
||||
error: unnecessary parentheses around `let` head expression
|
||||
--> $DIR/lint-unnecessary-parens.rs:52:19
|
||||
--> $DIR/lint-unnecessary-parens.rs:55:19
|
||||
|
|
||||
LL | while let 1 = (2) {}
|
||||
| ^^^ help: remove these parentheses
|
||||
|
||||
error: unnecessary parentheses around method argument
|
||||
--> $DIR/lint-unnecessary-parens.rs:66:24
|
||||
--> $DIR/lint-unnecessary-parens.rs:69:24
|
||||
|
|
||||
LL | X { y: false }.foo((true));
|
||||
| ^^^^^^ help: remove these parentheses
|
||||
|
||||
error: unnecessary parentheses around assigned value
|
||||
--> $DIR/lint-unnecessary-parens.rs:68:18
|
||||
--> $DIR/lint-unnecessary-parens.rs:71:18
|
||||
|
|
||||
LL | let mut _a = (0);
|
||||
| ^^^ help: remove these parentheses
|
||||
|
||||
error: unnecessary parentheses around assigned value
|
||||
--> $DIR/lint-unnecessary-parens.rs:69:10
|
||||
--> $DIR/lint-unnecessary-parens.rs:72:10
|
||||
|
|
||||
LL | _a = (0);
|
||||
| ^^^ help: remove these parentheses
|
||||
|
||||
error: unnecessary parentheses around assigned value
|
||||
--> $DIR/lint-unnecessary-parens.rs:70:11
|
||||
--> $DIR/lint-unnecessary-parens.rs:73:11
|
||||
|
|
||||
LL | _a += (1);
|
||||
| ^^^ help: remove these parentheses
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
error: aborting due to 17 previous errors
|
||||
|
||||
|
@ -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
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use std::fmt;
|
||||
|
||||
pub enum A {} //~ ERROR type does not implement `fmt::Debug`
|
||||
pub enum A {} //~ ERROR type does not implement `std::fmt::Debug`
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum B {}
|
||||
@ -17,7 +17,7 @@ impl fmt::Debug for C {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Foo; //~ ERROR type does not implement `fmt::Debug`
|
||||
pub struct Foo; //~ ERROR type does not implement `std::fmt::Debug`
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Bar;
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation
|
||||
error: type does not implement `std::fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation
|
||||
--> $DIR/missing_debug_impls.rs:7:1
|
||||
|
|
||||
LL | pub enum A {}
|
||||
@ -10,7 +10,7 @@ note: the lint level is defined here
|
||||
LL | #![deny(missing_debug_implementations)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation
|
||||
error: type does not implement `std::fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation
|
||||
--> $DIR/missing_debug_impls.rs:20:1
|
||||
|
|
||||
LL | pub struct Foo;
|
||||
|
@ -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)]
|
||||
|
@ -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);
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
@ -0,0 +1,14 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(or_patterns)]
|
||||
|
||||
enum MyEnum {
|
||||
FirstCase(u8),
|
||||
OtherCase(u16),
|
||||
}
|
||||
|
||||
fn my_fn(x @ (MyEnum::FirstCase(_) | MyEnum::OtherCase(_)): MyEnum) {}
|
||||
|
||||
fn main() {
|
||||
my_fn(MyEnum::FirstCase(0));
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
27
src/test/ui/parser/fn-body-optional-semantic-fail.rs
Normal file
27
src/test/ui/parser/fn-body-optional-semantic-fail.rs
Normal 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
|
||||
}
|
||||
}
|
40
src/test/ui/parser/fn-body-optional-semantic-fail.stderr
Normal file
40
src/test/ui/parser/fn-body-optional-semantic-fail.stderr
Normal 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
|
||||
|
31
src/test/ui/parser/fn-body-optional-syntactic-pass.rs
Normal file
31
src/test/ui/parser/fn-body-optional-syntactic-pass.rs
Normal 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() {}
|
||||
}
|
||||
}
|
57
src/test/ui/parser/fn-header-semantic-fail.rs
Normal file
57
src/test/ui/parser/fn-header-semantic-fail.rs
Normal 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.
|
||||
}
|
||||
}
|
136
src/test/ui/parser/fn-header-semantic-fail.stderr
Normal file
136
src/test/ui/parser/fn-header-semantic-fail.stderr
Normal 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`.
|
55
src/test/ui/parser/fn-header-syntactic-pass.rs
Normal file
55
src/test/ui/parser/fn-header-syntactic-pass.rs
Normal 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.
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
// error-pattern: aborting due to 6 previous errors
|
||||
// error-pattern: aborting due to 7 previous errors
|
||||
|
||||
fn i(n{...,f #
|
||||
|
@ -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
|
||||
|
||||
|
Binary file not shown.
21
src/test/ui/parser/issue-68788-in-trait-item-propagation.rs
Normal file
21
src/test/ui/parser/issue-68788-in-trait-item-propagation.rs
Normal 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() {}
|
||||
}
|
||||
}
|
||||
}
|
@ -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((ؼ
|
@ -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
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -10,7 +10,8 @@ fn f1() { }
|
||||
#[stable(feature = "a", sinse = "1.0.0")] //~ ERROR unknown meta item 'sinse'
|
||||
fn f2() { }
|
||||
|
||||
#[unstable(feature = "a", issue = "no")] //~ ERROR `issue` must be a numeric string or "none"
|
||||
#[unstable(feature = "a", issue = "no")]
|
||||
//~^ ERROR `issue` must be a non-zero numeric string or "none"
|
||||
fn f3() { }
|
||||
|
||||
fn main() { }
|
||||
|
@ -10,7 +10,7 @@ error[E0541]: unknown meta item 'sinse'
|
||||
LL | #[stable(feature = "a", sinse = "1.0.0")]
|
||||
| ^^^^^^^^^^^^^^^ expected one of `since`, `note`
|
||||
|
||||
error[E0545]: `issue` must be a numeric string or "none"
|
||||
error[E0545]: `issue` must be a non-zero numeric string or "none"
|
||||
--> $DIR/stability-attribute-sanity-2.rs:13:27
|
||||
|
|
||||
LL | #[unstable(feature = "a", issue = "no")]
|
||||
|
@ -1,5 +1,6 @@
|
||||
// run-pass
|
||||
|
||||
#![allow(unused_parens)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(dead_code)]
|
||||
// exec-env:RUST_MIN_STACK=16000000
|
||||
|
Loading…
Reference in New Issue
Block a user