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:
bors 2020-02-06 15:43:00 +00:00
commit 442ae7f040
75 changed files with 1207 additions and 758 deletions

View file

@ -310,6 +310,11 @@ rustc_queries! {
/// Maps from a trait item to the trait item "descriptor". /// Maps from a trait item to the trait item "descriptor".
query associated_item(_: DefId) -> ty::AssocItem {} 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_trait_ref(_: DefId) -> Option<ty::TraitRef<'tcx>> {}
query impl_polarity(_: DefId) -> ty::ImplPolarity {} query impl_polarity(_: DefId) -> ty::ImplPolarity {}

View file

@ -2743,19 +2743,6 @@ impl<'tcx> TyCtxt<'tcx> {
variant.fields.iter().position(|field| self.hygienic_eq(ident, field.ident, variant.def_id)) 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 /// Returns `true` if the impls are the same polarity and the trait either
/// has no items or is annotated #[marker] and prevents item overrides. /// has no items or is annotated #[marker] and prevents item overrides.
pub fn impls_are_allowed_to_overlap( 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> { pub struct AssocItemsIterator<'tcx> {
tcx: TyCtxt<'tcx>, pub items: &'tcx [AssocItem],
def_ids: &'tcx [DefId],
next_index: usize,
} }
impl Iterator for AssocItemsIterator<'_> { impl<'tcx> Iterator for AssocItemsIterator<'tcx> {
type Item = AssocItem; type Item = AssocItem;
#[inline]
fn next(&mut self) -> Option<AssocItem> { fn next(&mut self) -> Option<AssocItem> {
let def_id = self.def_ids.get(self.next_index)?; if let Some((first, rest)) = self.items.split_first() {
self.next_index += 1; self.items = rest;
Some(self.tcx.associated_item(*def_id)) Some(*first)
} else {
None
}
} }
} }

View file

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

View file

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

View file

@ -8,7 +8,7 @@
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap; 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_parse::validate_attr;
use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY; use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
use rustc_session::lint::LintBuffer; use rustc_session::lint::LintBuffer;
@ -20,7 +20,7 @@ use std::mem;
use syntax::ast::*; use syntax::ast::*;
use syntax::attr; use syntax::attr;
use syntax::expand::is_proc_macro_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; use syntax::walk_list;
/// Is `self` allowed semantically as the first parameter in an `FnDecl`? /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
@ -49,6 +49,13 @@ impl BoundContext {
struct AstValidator<'a> { struct AstValidator<'a> {
session: &'a Session, 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, has_proc_macro_decls: bool,
/// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`. /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
@ -74,6 +81,12 @@ struct AstValidator<'a> {
} }
impl<'a> 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)) { fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.is_impl_trait_banned, true); let old = mem::replace(&mut self.is_impl_trait_banned, true);
f(self); 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) { fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
if body.is_some() {
return;
}
self.err_handler() self.err_handler()
.struct_span_err(sp, &format!("associated {} in `impl` without body", ctx)) .struct_span_err(sp, msg)
.span_suggestion( .span_suggestion(
self.session.source_map().end_point(sp), self.session.source_map().end_point(sp),
&format!("provide a definition for the {}", ctx), &format!("provide a definition for the {}", ctx),
@ -405,6 +414,13 @@ impl<'a> AstValidator<'a> {
.emit(); .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]) { fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
let span = match bounds { let span = match bounds {
[] => return, [] => return,
@ -416,8 +432,71 @@ impl<'a> AstValidator<'a> {
.emit(); .emit();
} }
fn check_c_varadic_type(&self, decl: &FnDecl) { /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
for Param { ty, span, .. } in &decl.inputs { 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 { if let TyKind::CVarArgs = ty.kind {
self.err_handler() self.err_handler()
.struct_span_err( .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 { enum GenericPosition {
@ -532,9 +629,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_expr(&mut self, expr: &'a Expr) { fn visit_expr(&mut self, expr: &'a Expr) {
match &expr.kind { 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 => { ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
struct_span_err!( struct_span_err!(
self.session, self.session,
@ -647,31 +741,32 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
generics: _, generics: _,
of_trait: Some(_), of_trait: Some(_),
ref self_ty, ref self_ty,
ref items, items: _,
} => { } => {
self.invalid_visibility(&item.vis, None); self.with_in_trait_impl(true, |this| {
if let TyKind::Err = self_ty.kind { this.invalid_visibility(&item.vis, None);
self.err_handler() if let TyKind::Err = self_ty.kind {
.struct_span_err(item.span, "`impl Trait for .. {}` is an obsolete syntax") this.err_handler()
.help("use `auto trait Trait {}` instead") .struct_span_err(
.emit(); item.span,
} "`impl Trait for .. {}` is an obsolete syntax",
if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative { )
struct_span_err!( .help("use `auto trait Trait {}` instead")
self.session, .emit();
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);
} }
} 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 { ItemKind::Impl {
unsafety, unsafety,
@ -712,40 +807,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
.emit(); .emit();
} }
} }
ItemKind::Fn(ref sig, ref generics, _) => { ItemKind::Fn(ref sig, ref generics, ref body) => {
self.visit_fn_header(&sig.header); self.check_const_fn_const_generic(item.span, sig, generics);
self.check_fn_decl(&sig.decl, SelfSemantic::No);
// We currently do not permit const generics in `const fn`, as if body.is_none() {
// this is tantamount to allowing compile-time dependent typing. let msg = "free function without a body";
if sig.header.constness.node == Constness::Const { self.error_item_without_body(item.span, "function", msg, " { <body> }");
// 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::ForeignMod(..) => { ItemKind::ForeignMod(_) => {
let old_item = mem::replace(&mut self.extern_mod, Some(item));
self.invalid_visibility( self.invalid_visibility(
&item.vis, &item.vis,
Some("place qualifiers on individual foreign items instead"), 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, _) => { ItemKind::Enum(ref def, _) => {
for variant in &def.variants { for variant in &def.variants {
@ -796,7 +874,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.with_bound_context(BoundContext::TraitBounds, |this| { self.with_bound_context(BoundContext::TraitBounds, |this| {
walk_list!(this, visit_param_bound, bounds); 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); walk_list!(self, visit_attribute, &item.attrs);
return; return;
} }
@ -820,19 +898,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
} }
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
match fi.kind { match &fi.kind {
ForeignItemKind::Fn(ref decl, _) => { ForeignItemKind::Fn(sig, _, body) => {
self.check_fn_decl(decl, SelfSemantic::No); self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
Self::check_decl_no_pat(decl, |span, _| { self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
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();
});
} }
ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {} 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) { fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
match &ii.kind { // Only associated `fn`s can have `self` parameters.
AssocItemKind::Const(_, body) => { let self_semantic = match fk.ctxt() {
self.check_impl_item_provided(ii.span, body, "constant", " = <expr>;"); Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
} _ => SelfSemantic::No,
AssocItemKind::Fn(_, body) => { };
self.check_impl_item_provided(ii.span, body, "function", " { <body> }"); self.check_fn_decl(fk.decl(), self_semantic);
}
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_trait_item(&mut self, ti: &'a AssocItem) { self.check_c_varadic_type(fk);
self.invalid_visibility(&ti.vis, None);
self.check_defaultness(ti.span, ti.defaultness);
if let AssocItemKind::Fn(sig, block) = &ti.kind { // Functions without bodies cannot have patterns.
self.check_trait_fn_not_async(ti.span, sig.header.asyncness.node); if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
self.check_trait_fn_not_const(sig.header.constness); Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
if block.is_none() { let (code, msg, label) = match ctxt {
Self::check_decl_no_pat(&sig.decl, |span, mut_ident| { FnCtxt::Foreign => (
if mut_ident { error_code!(E0130),
self.lint_buffer.buffer_lint( "patterns aren't allowed in foreign function declarations",
PATTERNS_IN_FNS_WITHOUT_BODY, "pattern not allowed in foreign function",
ti.id, ),
span, _ => (
"patterns aren't allowed in methods without bodies", error_code!(E0642),
); "patterns aren't allowed in functions without bodies",
} else { "pattern not allowed in function without body",
struct_span_err!( ),
self.session, };
span, if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
E0642, self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
"patterns aren't allowed in methods without bodies" } else {
) self.err_handler()
.struct_span_err(span, msg)
.span_label(span, label)
.code(code)
.emit(); .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); if ctxt == AssocCtxt::Trait || self.in_trait_impl {
} self.invalid_visibility(&item.vis, None);
if let AssocItemKind::Fn(sig, _) = &item.kind {
fn visit_assoc_item(&mut self, item: &'a AssocItem) { self.check_trait_fn_not_const(sig.header.constness);
if let AssocItemKind::Fn(sig, _) = &item.kind { self.check_trait_fn_not_async(item.span, sig.header.asyncness.node);
self.check_fn_decl(&sig.decl, SelfSemantic::Yes); }
self.check_c_varadic_type(&sig.decl);
} }
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 { pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
let mut validator = AstValidator { let mut validator = AstValidator {
session, session,
extern_mod: None,
in_trait_impl: false,
has_proc_macro_decls: false, has_proc_macro_decls: false,
outer_impl_trait: None, outer_impl_trait: None,
bound_context: None, bound_context: None,

View file

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

View file

@ -67,13 +67,13 @@ impl<'ast> Visitor<'ast> for NodeCounter {
self.count += 1; self.count += 1;
walk_generics(self, g) 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; 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; self.count += 1;
walk_assoc_item(self, ti) walk_assoc_item(self, ti, ctxt);
} }
fn visit_trait_ref(&mut self, t: &TraitRef) { fn visit_trait_ref(&mut self, t: &TraitRef) {
self.count += 1; self.count += 1;

View file

@ -1020,18 +1020,8 @@ impl<'a> State<'a> {
self.maybe_print_comment(item.span.lo()); self.maybe_print_comment(item.span.lo());
self.print_outer_attributes(&item.attrs); self.print_outer_attributes(&item.attrs);
match item.kind { match item.kind {
ast::ForeignItemKind::Fn(ref decl, ref generics) => { ast::ForeignItemKind::Fn(ref sig, ref gen, ref body) => {
self.head(""); self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs);
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::Static(ref t, m) => { ast::ForeignItemKind::Static(ref t, m) => {
self.head(visibility_qualified(&item.vis, "static")); self.head(visibility_qualified(&item.vis, "static"));
@ -1154,11 +1144,8 @@ impl<'a> State<'a> {
self.s.word(";"); self.s.word(";");
self.end(); // end the outer cbox self.end(); // end the outer cbox
} }
ast::ItemKind::Fn(ref sig, ref param_names, ref body) => { ast::ItemKind::Fn(ref sig, ref gen, ref body) => {
self.head(""); self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs);
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::Mod(ref _mod) => { ast::ItemKind::Mod(ref _mod) => {
self.head(visibility_qualified(&item.vis, "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); self.print_associated_const(item.ident, ty, expr.as_deref(), &item.vis);
} }
ast::AssocItemKind::Fn(sig, body) => { ast::AssocItemKind::Fn(sig, body) => {
if body.is_some() { let body = body.as_deref();
self.head(""); self.print_fn_full(sig, item.ident, &item.generics, &item.vis, body, &item.attrs);
}
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(";");
}
} }
ast::AssocItemKind::TyAlias(bounds, ty) => { ast::AssocItemKind::TyAlias(bounds, ty) => {
self.print_associated_type(item.ident, bounds, ty.as_deref()); 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( crate fn print_fn(
&mut self, &mut self,
decl: &ast::FnDecl, decl: &ast::FnDecl,
@ -2698,13 +2698,9 @@ impl<'a> State<'a> {
where_clause: ast::WhereClause { predicates: Vec::new(), span: rustc_span::DUMMY_SP }, where_clause: ast::WhereClause { predicates: Vec::new(), span: rustc_span::DUMMY_SP },
span: rustc_span::DUMMY_SP, span: rustc_span::DUMMY_SP,
}; };
self.print_fn( let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
decl, let vis = dummy_spanned(ast::VisibilityKind::Inherited);
ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() }, self.print_fn(decl, header, name, &generics, &vis);
name,
&generics,
&dummy_spanned(ast::VisibilityKind::Inherited),
);
self.end(); self.end();
} }

View file

@ -396,26 +396,31 @@ where
issue_num = match &*issue.unwrap().as_str() { issue_num = match &*issue.unwrap().as_str() {
"none" => None, "none" => None,
issue => { 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() { match issue.parse() {
Ok(num) => { Ok(num) if num == 0 => {
// FIXME(rossmacarthur): disallow 0 emit_diag(
// Disallowing this requires updates to "`issue` must not be \"0\", \
// some submodules use \"none\" instead",
NonZeroU32::new(num) );
continue 'outer;
} }
Ok(num) => NonZeroU32::new(num),
Err(err) => { Err(err) => {
struct_span_err!( emit_diag(&err.to_string());
diagnostic,
mi.span,
E0545,
"`issue` must be a numeric string \
or \"none\"",
)
.span_label(
mi.name_value_literal().unwrap().span,
&err.to_string(),
)
.emit();
continue 'outer; continue 'outer;
} }
} }

View file

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

View file

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

View file

@ -74,7 +74,7 @@
use crate::fx::{FxHashMap, FxHashSet}; use crate::fx::{FxHashMap, FxHashSet};
use std::cell::{Cell, RefCell}; use std::cell::Cell;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash; use std::hash;
@ -146,7 +146,7 @@ pub struct ObligationForest<O: ForestObligation> {
active_cache: FxHashMap<O::Predicate, usize>, active_cache: FxHashMap<O::Predicate, usize>,
/// A vector reused in compress(), to avoid allocating new vectors. /// A vector reused in compress(), to avoid allocating new vectors.
node_rewrites: RefCell<Vec<usize>>, node_rewrites: Vec<usize>,
obligation_tree_id_generator: ObligationTreeIdGenerator, obligation_tree_id_generator: ObligationTreeIdGenerator,
@ -285,7 +285,7 @@ impl<O: ForestObligation> ObligationForest<O> {
nodes: vec![], nodes: vec![],
done_cache: Default::default(), done_cache: Default::default(),
active_cache: Default::default(), active_cache: Default::default(),
node_rewrites: RefCell::new(vec![]), node_rewrites: vec![],
obligation_tree_id_generator: (0..).map(ObligationTreeId), obligation_tree_id_generator: (0..).map(ObligationTreeId),
error_cache: Default::default(), error_cache: Default::default(),
} }
@ -590,7 +590,7 @@ impl<O: ForestObligation> ObligationForest<O> {
#[inline(never)] #[inline(never)]
fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> { fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
let orig_nodes_len = self.nodes.len(); 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()); debug_assert!(node_rewrites.is_empty());
node_rewrites.extend(0..orig_nodes_len); node_rewrites.extend(0..orig_nodes_len);
let mut dead_nodes = 0; let mut dead_nodes = 0;
@ -651,7 +651,7 @@ impl<O: ForestObligation> ObligationForest<O> {
} }
node_rewrites.truncate(0); 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 } if do_completed == DoCompleted::Yes { Some(removed_done_obligations) } else { None }
} }

View file

@ -1,9 +1,6 @@
This is because of a type mismatch between the associated type of some A type mismatched an associated type of a trait.
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 a basic example: Erroneous code example:
```compile_fail,E0271 ```compile_fail,E0271
trait Trait { type AssociatedType; } trait Trait { type AssociatedType; }
@ -17,6 +14,11 @@ impl Trait for i8 { type AssociatedType = &'static str; }
foo(3_i8); 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: Here is that same example again, with some explanatory comments:
```compile_fail,E0271 ```compile_fail,E0271

View file

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

View file

@ -25,7 +25,7 @@ use syntax::ptr::P;
use syntax::token; use syntax::token;
use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::util::map_in_place::MapInPlace; use syntax::util::map_in_place::MapInPlace;
use syntax::visit::{self, Visitor}; use syntax::visit::{self, AssocCtxt, Visitor};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use std::io::ErrorKind; use std::io::ErrorKind;
@ -39,7 +39,7 @@ macro_rules! ast_fragments {
$($Kind:ident($AstTy:ty) { $($Kind:ident($AstTy:ty) {
$kind_name:expr; $kind_name:expr;
$(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)? $(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; fn $make_ast:ident;
})* })*
) => { ) => {
@ -127,7 +127,7 @@ macro_rules! ast_fragments {
AstFragment::OptExpr(None) => {} AstFragment::OptExpr(None) => {}
$($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)* $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)*
$($(AstFragment::$Kind(ref ast) => for ast_elt in &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; } 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; } Ty(P<ast::Ty>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; }
Stmts(SmallVec<[ast::Stmt; 1]>) { 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]>) { 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]>) { 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]>) { 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]>) { ForeignItems(SmallVec<[P<ast::ForeignItem>; 1]>) {
"foreign item"; "foreign item";
many fn flat_map_foreign_item; many fn flat_map_foreign_item;
fn visit_foreign_item; fn visit_foreign_item();
fn make_foreign_items; fn make_foreign_items;
} }
Arms(SmallVec<[ast::Arm; 1]>) { 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]>) { 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]>) { FieldPats(SmallVec<[ast::FieldPat; 1]>) {
"field pattern"; "field pattern";
many fn flat_map_field_pattern; many fn flat_map_field_pattern;
fn visit_field_pattern; fn visit_field_pattern();
fn make_field_patterns; fn make_field_patterns;
} }
GenericParams(SmallVec<[ast::GenericParam; 1]>) { GenericParams(SmallVec<[ast::GenericParam; 1]>) {
"generic parameter"; "generic parameter";
many fn flat_map_generic_param; many fn flat_map_generic_param;
fn visit_generic_param; fn visit_generic_param();
fn make_generic_params; fn make_generic_params;
} }
Params(SmallVec<[ast::Param; 1]>) { 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]>) { StructFields(SmallVec<[ast::StructField; 1]>) {
"field"; "field";
many fn flat_map_struct_field; many fn flat_map_struct_field;
fn visit_struct_field; fn visit_struct_field();
fn make_struct_fields; fn make_struct_fields;
} }
Variants(SmallVec<[ast::Variant; 1]>) { 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 => { AstFragmentKind::ForeignItems => {
let mut items = SmallVec::new(); let mut items = SmallVec::new();
while this.token != token::Eof { while this.token != token::Eof {
items.push(this.parse_foreign_item(DUMMY_SP)?); items.push(this.parse_foreign_item()?);
} }
AstFragment::ForeignItems(items) AstFragment::ForeignItems(items)
} }

View file

@ -43,7 +43,7 @@ use rustc_span::{BytePos, Span};
use syntax::ast::{self, Expr}; use syntax::ast::{self, Expr};
use syntax::attr::{self, HasAttrs}; use syntax::attr::{self, HasAttrs};
use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::visit::FnKind; use syntax::visit::{FnCtxt, FnKind};
use crate::nonstandard_style::{method_context, MethodLateContext}; use crate::nonstandard_style::{method_context, MethodLateContext};
@ -259,34 +259,22 @@ impl EarlyLintPass for UnsafeCode {
} }
} }
fn check_fn( fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) {
&mut self, if let FnKind::Fn(
cx: &EarlyContext<'_>, ctxt,
fk: FnKind<'_>, _,
_: &ast::FnDecl, ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, .. },
span: Span, _,
_: ast::NodeId, body,
) { ) = fk
match fk { {
FnKind::ItemFn(_, ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, ..) => { let msg = match ctxt {
self.report_unsafe(cx, span, "declaration of an `unsafe` function") FnCtxt::Foreign => return,
} FnCtxt::Free => "declaration of an `unsafe` function",
FnCtxt::Assoc(_) if body.is_none() => "declaration of an `unsafe` method",
FnKind::Method(_, sig, ..) => { FnCtxt::Assoc(_) => "implementation of an `unsafe` method",
if sig.header.unsafety == ast::Unsafety::Unsafe { };
self.report_unsafe(cx, span, "implementation of an `unsafe` method") self.report_unsafe(cx, span, msg);
}
}
_ => (),
}
}
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")
}
} }
} }
} }
@ -567,7 +555,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
declare_lint! { declare_lint! {
MISSING_DEBUG_IMPLEMENTATIONS, MISSING_DEBUG_IMPLEMENTATIONS,
Allow, Allow,
"detects missing implementations of fmt::Debug" "detects missing implementations of Debug"
} }
#[derive(Default)] #[derive(Default)]
@ -611,9 +599,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations {
cx.span_lint( cx.span_lint(
MISSING_DEBUG_IMPLEMENTATIONS, MISSING_DEBUG_IMPLEMENTATIONS,
item.span, item.span,
"type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` \ &format!(
or a manual implementation", "type does not implement `{}`; consider adding `#[derive(Debug)]` \
) or a manual implementation",
cx.tcx.def_path_str(debug)
),
);
} }
} }
} }

View file

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

View file

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

View file

@ -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! { declare_lint! {

View file

@ -1,3 +1,4 @@
use super::ty::AllowPlus;
use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType}; use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
@ -693,11 +694,11 @@ impl<'a> Parser<'a> {
pub(super) fn maybe_report_ambiguous_plus( pub(super) fn maybe_report_ambiguous_plus(
&mut self, &mut self,
allow_plus: bool, allow_plus: AllowPlus,
impl_dyn_multi: bool, impl_dyn_multi: bool,
ty: &Ty, 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)); let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
self.struct_span_err(ty.span, "ambiguous `+` in a type") self.struct_span_err(ty.span, "ambiguous `+` in a type")
.span_suggestion( .span_suggestion(
@ -712,11 +713,11 @@ impl<'a> Parser<'a> {
pub(super) fn maybe_recover_from_bad_type_plus( pub(super) fn maybe_recover_from_bad_type_plus(
&mut self, &mut self,
allow_plus: bool, allow_plus: AllowPlus,
ty: &Ty, ty: &Ty,
) -> PResult<'a, ()> { ) -> PResult<'a, ()> {
// Do not add `+` to expected tokens. // 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(()); return Ok(());
} }
@ -937,47 +938,6 @@ impl<'a> Parser<'a> {
self.expect(&token::Semi).map(drop) // Error unconditionally 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>`, /// Consumes alternative await syntaxes like `await!(<expr>)`, `await <expr>`,
/// `await? <expr>`, `await(<expr>)`, and `await { <expr> }`. /// `await? <expr>`, `await(<expr>)`, and `await { <expr> }`.
pub(super) fn recover_incorrect_await_syntax( pub(super) fn recover_incorrect_await_syntax(

View file

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

View file

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

View file

@ -21,7 +21,7 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError
use rustc_session::parse::ParseSess; use rustc_session::parse::ParseSess;
use rustc_span::source_map::respan; use rustc_span::source_map::respan;
use rustc_span::symbol::{kw, sym, Symbol}; 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::{self, AttrStyle, AttrVec, CrateSugar, Extern, Ident, Unsafety, DUMMY_NODE_ID};
use syntax::ast::{IsAsync, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind}; use syntax::ast::{IsAsync, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind};
use syntax::ptr::P; use syntax::ptr::P;
@ -615,8 +615,8 @@ impl<'a> Parser<'a> {
true true
} }
token::BinOpEq(token::Plus) => { token::BinOpEq(token::Plus) => {
let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); let start_point = self.sess.source_map().start_point(self.token.span);
self.bump_with(token::Eq, span); self.bump_with(token::Eq, self.token.span.with_lo(start_point.hi()));
true true
} }
_ => false, _ => false,
@ -633,8 +633,9 @@ impl<'a> Parser<'a> {
Ok(()) Ok(())
} }
token::AndAnd => { token::AndAnd => {
let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); let start_point = self.sess.source_map().start_point(self.token.span);
Ok(self.bump_with(token::BinOp(token::And), span)) Ok(self
.bump_with(token::BinOp(token::And), self.token.span.with_lo(start_point.hi())))
} }
_ => self.unexpected(), _ => self.unexpected(),
} }
@ -650,8 +651,9 @@ impl<'a> Parser<'a> {
Ok(()) Ok(())
} }
token::OrOr => { token::OrOr => {
let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); let start_point = self.sess.source_map().start_point(self.token.span);
Ok(self.bump_with(token::BinOp(token::Or), span)) Ok(self
.bump_with(token::BinOp(token::Or), self.token.span.with_lo(start_point.hi())))
} }
_ => self.unexpected(), _ => self.unexpected(),
} }
@ -671,13 +673,16 @@ impl<'a> Parser<'a> {
true true
} }
token::BinOp(token::Shl) => { token::BinOp(token::Shl) => {
let span = self.sess.source_map().next_point(self.token.span); let start_point = self.sess.source_map().start_point(self.token.span);
self.bump_with(token::Lt, span); self.bump_with(token::Lt, self.token.span.with_lo(start_point.hi()));
true true
} }
token::LArrow => { token::LArrow => {
let span = self.sess.source_map().next_point(self.token.span); let start_point = self.sess.source_map().start_point(self.token.span);
self.bump_with(token::BinOp(token::Minus), span); self.bump_with(
token::BinOp(token::Minus),
self.token.span.with_lo(start_point.hi()),
);
true true
} }
_ => false, _ => false,
@ -707,16 +712,16 @@ impl<'a> Parser<'a> {
Some(()) Some(())
} }
token::BinOp(token::Shr) => { token::BinOp(token::Shr) => {
let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); let start_point = self.sess.source_map().start_point(self.token.span);
Some(self.bump_with(token::Gt, span)) Some(self.bump_with(token::Gt, self.token.span.with_lo(start_point.hi())))
} }
token::BinOpEq(token::Shr) => { token::BinOpEq(token::Shr) => {
let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); let start_point = self.sess.source_map().start_point(self.token.span);
Some(self.bump_with(token::Ge, span)) Some(self.bump_with(token::Ge, self.token.span.with_lo(start_point.hi())))
} }
token::Ge => { token::Ge => {
let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); let start_point = self.sess.source_map().start_point(self.token.span);
Some(self.bump_with(token::Eq, span)) Some(self.bump_with(token::Eq, self.token.span.with_lo(start_point.hi())))
} }
_ => None, _ => None,
}; };

View file

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

View file

@ -199,7 +199,7 @@ impl<'a> Parser<'a> {
} }
} }
fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool { pub(super) fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -358,7 +358,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
decl: &'l ast::FnDecl, decl: &'l ast::FnDecl,
header: &'l ast::FnHeader, header: &'l ast::FnHeader,
ty_params: &'l ast::Generics, 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); let hir_id = self.tcx.hir().node_to_hir_id(item.id);
self.nest_tables(item.id, |v| { 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) => { 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), 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), 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); let access = access_from!(self.save_ctxt, item, hir_id);
match item.kind { 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) { if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
down_cast_data!(fn_data, DefData, item.span); down_cast_data!(fn_data, DefData, item.span);

View file

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

View file

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

View file

@ -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 { fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span {
tcx.hir().span_if_local(def_id).unwrap() tcx.hir().span_if_local(def_id).unwrap()
} }
@ -356,6 +364,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
asyncness, asyncness,
associated_item, associated_item,
associated_item_def_ids, associated_item_def_ids,
associated_items,
adt_sized_constraint, adt_sized_constraint,
def_span, def_span,
param_env, param_env,

View file

@ -2533,6 +2533,17 @@ pub struct FnHeader {
pub ext: Extern, 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 { impl Default for FnHeader {
fn default() -> FnHeader { fn default() -> FnHeader {
FnHeader { FnHeader {
@ -2565,7 +2576,7 @@ pub enum ItemKind {
/// A function declaration (`fn`). /// A function declaration (`fn`).
/// ///
/// E.g., `fn foo(bar: usize) -> usize { .. }`. /// E.g., `fn foo(bar: usize) -> usize { .. }`.
Fn(FnSig, Generics, P<Block>), Fn(FnSig, Generics, Option<P<Block>>),
/// A module declaration (`mod`). /// A module declaration (`mod`).
/// ///
/// E.g., `mod foo;` or `mod foo { .. }`. /// E.g., `mod foo;` or `mod foo { .. }`.
@ -2667,7 +2678,7 @@ pub type ForeignItem = Item<ForeignItemKind>;
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub enum ForeignItemKind { pub enum ForeignItemKind {
/// A foreign function. /// A foreign function.
Fn(P<FnDecl>, Generics), Fn(FnSig, Generics, Option<P<Block>>),
/// A foreign static item (`static ext: u8`). /// A foreign static item (`static ext: u8`).
Static(P<Ty>, Mutability), Static(P<Ty>, Mutability),
/// A foreign type. /// A foreign type.

View file

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

View file

@ -19,24 +19,47 @@ use crate::tokenstream::{TokenStream, TokenTree};
use rustc_span::Span; 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)] #[derive(Copy, Clone)]
pub enum FnKind<'a> { pub enum FnKind<'a> {
/// E.g., `fn foo()` or `extern "Abi" fn foo()`. /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
ItemFn(Ident, &'a FnHeader, &'a Visibility, &'a Block), Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>),
/// E.g., `fn foo(&self)`.
Method(Ident, &'a FnSig, &'a Visibility, &'a Block),
/// E.g., `|x, y| body`. /// E.g., `|x, y| body`.
Closure(&'a Expr), Closure(&'a FnDecl, &'a Expr),
} }
impl<'a> FnKind<'a> { impl<'a> FnKind<'a> {
pub fn header(&self) -> Option<&'a FnHeader> { pub fn header(&self) -> Option<&'a FnHeader> {
match *self { match *self {
FnKind::ItemFn(_, header, _, _) => Some(header), FnKind::Fn(_, _, sig, _, _) => Some(&sig.header),
FnKind::Method(_, sig, _, _) => Some(&sig.header), FnKind::Closure(_, _) => None,
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) { fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
walk_where_predicate(self, p) walk_where_predicate(self, p)
} }
fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl, s: Span, _: NodeId) { fn visit_fn(&mut self, fk: FnKind<'ast>, s: Span, _: NodeId) {
walk_fn(self, fk, fd, s) walk_fn(self, fk, s)
} }
fn visit_trait_item(&mut self, i: &'ast AssocItem) { fn visit_assoc_item(&mut self, i: &'ast AssocItem, ctxt: AssocCtxt) {
walk_trait_item(self, i) walk_assoc_item(self, i, ctxt)
}
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_trait_ref(&mut self, t: &'ast TraitRef) { fn visit_trait_ref(&mut self, t: &'ast TraitRef) {
walk_trait_ref(self, t) 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) => { ItemKind::Fn(ref sig, ref generics, ref body) => {
visitor.visit_generics(generics); visitor.visit_generics(generics);
visitor.visit_fn_header(&sig.header); let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
visitor.visit_fn( visitor.visit_fn(kind, item.span, item.id)
FnKind::ItemFn(item.ident, &sig.header, &item.vis, body),
&sig.decl,
item.span,
item.id,
)
} }
ItemKind::Mod(ref module) => visitor.visit_mod(module, item.span, &item.attrs, item.id), ItemKind::Mod(ref module) => visitor.visit_mod(module, item.span, &item.attrs, item.id),
ItemKind::ForeignMod(ref foreign_module) => { 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); visitor.visit_generics(generics);
walk_list!(visitor, visit_trait_ref, of_trait); walk_list!(visitor, visit_trait_ref, of_trait);
visitor.visit_ty(self_ty); 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::Struct(ref struct_definition, ref generics)
| ItemKind::Union(ref struct_definition, ref generics) => { | ItemKind::Union(ref struct_definition, ref generics) => {
visitor.visit_generics(generics); visitor.visit_generics(generics);
visitor.visit_variant_data(struct_definition); 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); visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds); 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) => { ItemKind::TraitAlias(ref generics, ref bounds) => {
visitor.visit_generics(generics); 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) { pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignItem) {
visitor.visit_vis(&foreign_item.vis); visitor.visit_vis(&item.vis);
visitor.visit_ident(foreign_item.ident); visitor.visit_ident(item.ident);
match foreign_item.kind { match item.kind {
ForeignItemKind::Fn(ref function_declaration, ref generics) => { ForeignItemKind::Fn(ref sig, ref generics, ref body) => {
walk_fn_decl(visitor, function_declaration); visitor.visit_generics(generics);
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::Static(ref typ, _) => visitor.visit_ty(typ),
ForeignItemKind::Ty => (), ForeignItemKind::Ty => (),
ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac), 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) { 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); 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) pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Span) {
where
V: Visitor<'a>,
{
match kind { match kind {
FnKind::ItemFn(_, header, _, body) => { FnKind::Fn(_, _, sig, _, body) => {
visitor.visit_fn_header(header);
walk_fn_decl(visitor, declaration);
visitor.visit_block(body);
}
FnKind::Method(_, sig, _, body) => {
visitor.visit_fn_header(&sig.header); visitor.visit_fn_header(&sig.header);
walk_fn_decl(visitor, declaration); walk_fn_decl(visitor, &sig.decl);
visitor.visit_block(body); walk_list!(visitor, visit_block, body);
} }
FnKind::Closure(body) => { FnKind::Closure(decl, body) => {
walk_fn_decl(visitor, declaration); walk_fn_decl(visitor, decl);
visitor.visit_expr(body); visitor.visit_expr(body);
} }
} }
} }
pub fn walk_impl_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_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) {
visitor.visit_vis(&item.vis); visitor.visit_vis(&item.vis);
visitor.visit_ident(item.ident); visitor.visit_ident(item.ident);
walk_list!(visitor, visit_attribute, &item.attrs); 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); visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr); walk_list!(visitor, visit_expr, expr);
} }
AssocItemKind::Fn(ref sig, None) => { AssocItemKind::Fn(ref sig, ref body) => {
visitor.visit_fn_header(&sig.header); let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
walk_fn_decl(visitor, &sig.decl); visitor.visit_fn(kind, item.span, item.id);
}
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::TyAlias(ref bounds, ref ty) => { AssocItemKind::TyAlias(ref bounds, ref ty) => {
walk_list!(visitor, visit_param_bound, bounds); 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); visitor.visit_expr(subexpression);
walk_list!(visitor, visit_arm, arms); walk_list!(visitor, visit_arm, arms);
} }
ExprKind::Closure(_, _, _, ref function_declaration, ref body, _decl_span) => visitor ExprKind::Closure(_, _, _, ref decl, ref body, _decl_span) => {
.visit_fn(FnKind::Closure(body), function_declaration, expression.span, expression.id), visitor.visit_fn(FnKind::Closure(decl, body), expression.span, expression.id)
}
ExprKind::Block(ref block, ref opt_label) => { ExprKind::Block(ref block, ref opt_label) => {
walk_list!(visitor, visit_label, opt_label); walk_list!(visitor, visit_label, opt_label);
visitor.visit_block(block); visitor.visit_block(block);

View file

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

View file

@ -1,17 +1,17 @@
error: incorrect `fn` inside `extern` block error: incorrect function inside `extern` block
--> $DIR/extern-ffi-fn-with-body.rs:2:8 --> $DIR/extern-ffi-fn-with-body.rs:2:8
| |
LL | extern "C" { 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 { LL | fn foo() -> i32 {
| ________^^^__________- | ________^^^__________-
| | | | | |
| | can't have a body | | cannot have a body
LL | | return 0; LL | | return 0;
LL | | } 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 = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
error: aborting due to previous error error: aborting due to previous error

View file

@ -4,10 +4,10 @@
#![stable(feature = "stable_test_feature", since = "1.0.0")] #![stable(feature = "stable_test_feature", since = "1.0.0")]
#[unstable(feature = "unstable_test_feature", issue = "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")] #[unstable(feature = "unstable_test_feature", issue = "none")]
fn unstable_issue_none() {} fn unstable_issue_none() {}
#[unstable(feature = "unstable_test_feature", issue = "something")] #[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"

View file

@ -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 --> $DIR/unstable-attribute-allow-issue-0.rs:12:47
| |
LL | #[unstable(feature = "unstable_test_feature", issue = "something")] 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 | invalid digit found in string
error: aborting due to previous error error: aborting due to 2 previous errors

View file

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

View file

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

View file

@ -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() { fn main() {
foo(); foo();
bar((true)); //~ ERROR unnecessary parentheses around function argument bar((true)); //~ ERROR unnecessary parentheses around function argument

View file

@ -34,26 +34,38 @@ error: unnecessary parentheses around block return value
LL | (5) LL | (5)
| ^^^ help: remove these parentheses | ^^^ 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 error: unnecessary parentheses around function argument
--> $DIR/lint-unnecessary-parens.rs:43:9 --> $DIR/lint-unnecessary-parens.rs:46:9
| |
LL | bar((true)); LL | bar((true));
| ^^^^^^ help: remove these parentheses | ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around `if` condition error: unnecessary parentheses around `if` condition
--> $DIR/lint-unnecessary-parens.rs:45:8 --> $DIR/lint-unnecessary-parens.rs:48:8
| |
LL | if (true) {} LL | if (true) {}
| ^^^^^^ help: remove these parentheses | ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around `while` condition error: unnecessary parentheses around `while` condition
--> $DIR/lint-unnecessary-parens.rs:46:11 --> $DIR/lint-unnecessary-parens.rs:49:11
| |
LL | while (true) {} LL | while (true) {}
| ^^^^^^ help: remove these parentheses | ^^^^^^ help: remove these parentheses
warning: denote infinite loops with `loop { ... }` warning: denote infinite loops with `loop { ... }`
--> $DIR/lint-unnecessary-parens.rs:46:5 --> $DIR/lint-unnecessary-parens.rs:49:5
| |
LL | while (true) {} LL | while (true) {}
| ^^^^^^^^^^^^ help: use `loop` | ^^^^^^^^^^^^ help: use `loop`
@ -61,46 +73,46 @@ LL | while (true) {}
= note: `#[warn(while_true)]` on by default = note: `#[warn(while_true)]` on by default
error: unnecessary parentheses around `match` head expression error: unnecessary parentheses around `match` head expression
--> $DIR/lint-unnecessary-parens.rs:48:11 --> $DIR/lint-unnecessary-parens.rs:51:11
| |
LL | match (true) { LL | match (true) {
| ^^^^^^ help: remove these parentheses | ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around `let` head expression 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) {} LL | if let 1 = (1) {}
| ^^^ help: remove these parentheses | ^^^ help: remove these parentheses
error: unnecessary parentheses around `let` head expression 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) {} LL | while let 1 = (2) {}
| ^^^ help: remove these parentheses | ^^^ help: remove these parentheses
error: unnecessary parentheses around method argument 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)); LL | X { y: false }.foo((true));
| ^^^^^^ help: remove these parentheses | ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around assigned value 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); LL | let mut _a = (0);
| ^^^ help: remove these parentheses | ^^^ help: remove these parentheses
error: unnecessary parentheses around assigned value error: unnecessary parentheses around assigned value
--> $DIR/lint-unnecessary-parens.rs:69:10 --> $DIR/lint-unnecessary-parens.rs:72:10
| |
LL | _a = (0); LL | _a = (0);
| ^^^ help: remove these parentheses | ^^^ help: remove these parentheses
error: unnecessary parentheses around assigned value error: unnecessary parentheses around assigned value
--> $DIR/lint-unnecessary-parens.rs:70:11 --> $DIR/lint-unnecessary-parens.rs:73:11
| |
LL | _a += (1); LL | _a += (1);
| ^^^ help: remove these parentheses | ^^^ help: remove these parentheses
error: aborting due to 15 previous errors error: aborting due to 17 previous errors

View file

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

View file

@ -4,7 +4,7 @@
use std::fmt; 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)] #[derive(Debug)]
pub enum B {} 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)] #[derive(Debug)]
pub struct Bar; pub struct Bar;

View file

@ -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 --> $DIR/missing_debug_impls.rs:7:1
| |
LL | pub enum A {} LL | pub enum A {}
@ -10,7 +10,7 @@ note: the lint level is defined here
LL | #![deny(missing_debug_implementations)] 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 --> $DIR/missing_debug_impls.rs:20:1
| |
LL | pub struct Foo; LL | pub struct Foo;

View file

@ -1,9 +1,9 @@
#![deny(patterns_in_fns_without_body)] #![deny(patterns_in_fns_without_body)]
trait Tr { 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 //~^ 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 g1(arg: u8); // OK
fn g2(_: u8); // OK fn g2(_: u8); // OK
#[allow(anonymous_parameters)] #[allow(anonymous_parameters)]

View file

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

View file

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

View file

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

View file

@ -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));
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,136 @@
error[E0706]: trait fns cannot be declared `async`
--> $DIR/fn-header-semantic-fail.rs:17:9
|
LL | async fn ft1();
| ^^^^^^^^^^^^^^^
|
= note: `async` trait functions are not currently supported
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
error[E0379]: trait fns cannot be declared const
--> $DIR/fn-header-semantic-fail.rs:19:9
|
LL | const fn ft3();
| ^^^^^ trait fns cannot be const
error[E0706]: trait fns cannot be declared `async`
--> $DIR/fn-header-semantic-fail.rs:21:21
|
LL | /* const */ async unsafe extern "C" fn ft5();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `async` trait functions are not currently supported
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
error[E0706]: trait fns cannot be declared `async`
--> $DIR/fn-header-semantic-fail.rs:28:9
|
LL | async fn ft1() {}
| ^^^^^^^^^^^^^^^^^
|
= note: `async` trait functions are not currently supported
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
error[E0379]: trait fns cannot be declared const
--> $DIR/fn-header-semantic-fail.rs:31:9
|
LL | const fn ft3() {}
| ^^^^^ trait fns cannot be const
error[E0706]: trait fns cannot be declared `async`
--> $DIR/fn-header-semantic-fail.rs:33:21
|
LL | /* const */ async unsafe extern "C" fn ft5() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `async` trait functions are not currently supported
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
error: functions in `extern` blocks cannot have qualifiers
--> $DIR/fn-header-semantic-fail.rs:49:18
|
LL | extern {
| ------ in this `extern` block
LL | async fn fe1();
| ---------^^^
| |
| help: remove the qualifiers: `fn`
error: functions in `extern` blocks cannot have qualifiers
--> $DIR/fn-header-semantic-fail.rs:50:19
|
LL | extern {
| ------ in this `extern` block
LL | async fn fe1();
LL | unsafe fn fe2();
| ----------^^^
| |
| help: remove the qualifiers: `fn`
error: functions in `extern` blocks cannot have qualifiers
--> $DIR/fn-header-semantic-fail.rs:51:18
|
LL | extern {
| ------ in this `extern` block
...
LL | const fn fe3();
| ---------^^^
| |
| help: remove the qualifiers: `fn`
error: functions in `extern` blocks cannot have qualifiers
--> $DIR/fn-header-semantic-fail.rs:52:23
|
LL | extern {
| ------ in this `extern` block
...
LL | extern "C" fn fe4();
| --------------^^^
| |
| help: remove the qualifiers: `fn`
error: functions in `extern` blocks cannot have qualifiers
--> $DIR/fn-header-semantic-fail.rs:53:48
|
LL | extern {
| ------ in this `extern` block
...
LL | /* const */ async unsafe extern "C" fn fe5();
| ---------------------------^^^
| |
| help: remove the qualifiers: `fn`
error[E0053]: method `ft1` has an incompatible type for trait
--> $DIR/fn-header-semantic-fail.rs:28:24
|
LL | async fn ft1();
| - type in trait
...
LL | async fn ft1() {}
| ^
| |
| the `Output` of this `async fn`'s found opaque type
| expected `()`, found opaque type
|
= note: expected fn pointer `fn()`
found fn pointer `fn() -> impl std::future::Future`
error[E0053]: method `ft5` has an incompatible type for trait
--> $DIR/fn-header-semantic-fail.rs:33:54
|
LL | /* const */ async unsafe extern "C" fn ft5();
| - type in trait
...
LL | /* const */ async unsafe extern "C" fn ft5() {}
| ^
| |
| the `Output` of this `async fn`'s found opaque type
| expected `()`, found opaque type
|
= note: expected fn pointer `unsafe extern "C" fn()`
found fn pointer `unsafe extern "C" fn() -> impl std::future::Future`
error: aborting due to 13 previous errors
Some errors have detailed explanations: E0053, E0379, E0706.
For more information about an error, try `rustc --explain E0053`.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,7 +10,8 @@ fn f1() { }
#[stable(feature = "a", sinse = "1.0.0")] //~ ERROR unknown meta item 'sinse' #[stable(feature = "a", sinse = "1.0.0")] //~ ERROR unknown meta item 'sinse'
fn f2() { } 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 f3() { }
fn main() { } fn main() { }

View file

@ -10,7 +10,7 @@ error[E0541]: unknown meta item 'sinse'
LL | #[stable(feature = "a", sinse = "1.0.0")] LL | #[stable(feature = "a", sinse = "1.0.0")]
| ^^^^^^^^^^^^^^^ expected one of `since`, `note` | ^^^^^^^^^^^^^^^ 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 --> $DIR/stability-attribute-sanity-2.rs:13:27
| |
LL | #[unstable(feature = "a", issue = "no")] LL | #[unstable(feature = "a", issue = "no")]

View file

@ -1,5 +1,6 @@
// run-pass // run-pass
#![allow(unused_parens)]
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
#![allow(dead_code)] #![allow(dead_code)]
// exec-env:RUST_MIN_STACK=16000000 // exec-env:RUST_MIN_STACK=16000000