diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs index c1facd34dfee5..b2973c642a21e 100644 --- a/src/librustc/traits/error_reporting/suggestions.rs +++ b/src/librustc/traits/error_reporting/suggestions.rs @@ -1646,8 +1646,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let current_limit = self.tcx.sess.recursion_limit.get(); let suggested_limit = current_limit * 2; err.help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + suggested_limit, self.tcx.crate_name, )); } } diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index e27f2bdb8d25f..dab950e23f618 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -14,7 +14,7 @@ use rustc_target::spec::abi; use syntax::ast::*; use syntax::attr; use syntax::node_id::NodeMap; -use syntax::visit::{self, Visitor}; +use syntax::visit::{self, AssocCtxt, Visitor}; use log::debug; use smallvec::{smallvec, SmallVec}; @@ -81,25 +81,23 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { } } - fn visit_trait_item(&mut self, item: &'a AssocItem) { - self.lctx.with_hir_id_owner(item.id, |lctx| { - let hir_item = lctx.lower_trait_item(item); - let id = hir::TraitItemId { hir_id: hir_item.hir_id }; - lctx.trait_items.insert(id, hir_item); - lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id); + fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { + self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt { + AssocCtxt::Trait => { + let hir_item = lctx.lower_trait_item(item); + let id = hir::TraitItemId { hir_id: hir_item.hir_id }; + lctx.trait_items.insert(id, hir_item); + lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id); + } + AssocCtxt::Impl => { + let hir_item = lctx.lower_impl_item(item); + let id = hir::ImplItemId { hir_id: hir_item.hir_id }; + lctx.impl_items.insert(id, hir_item); + lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id); + } }); - visit::walk_trait_item(self, item); - } - - fn visit_impl_item(&mut self, item: &'a AssocItem) { - self.lctx.with_hir_id_owner(item.id, |lctx| { - let hir_item = lctx.lower_impl_item(item); - let id = hir::ImplItemId { hir_id: hir_item.hir_id }; - lctx.impl_items.insert(id, hir_item); - lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id); - }); - visit::walk_impl_item(self, item); + visit::walk_assoc_item(self, item, ctxt); } } @@ -299,20 +297,17 @@ impl<'hir> LoweringContext<'_, 'hir> { // `impl Future` here because lower_body // only cares about the input argument patterns in the function // declaration (decl), not the return types. + let asyncness = header.asyncness.node; let body_id = - this.lower_maybe_async_body(span, &decl, header.asyncness.node, Some(body)); + this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref()); let (generics, decl) = this.add_in_band_defs( generics, fn_def_id, AnonymousLifetimeMode::PassThrough, |this, idty| { - this.lower_fn_decl( - &decl, - Some((fn_def_id, idty)), - true, - header.asyncness.node.opt_return_id(), - ) + let ret_id = asyncness.opt_return_id(); + this.lower_fn_decl(&decl, Some((fn_def_id, idty)), true, ret_id) }, ); let sig = hir::FnSig { decl, header: this.lower_fn_header(header) }; @@ -658,7 +653,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ident: i.ident, attrs: self.lower_attrs(&i.attrs), kind: match i.kind { - ForeignItemKind::Fn(ref fdec, ref generics) => { + ForeignItemKind::Fn(ref sig, ref generics, _) => { + let fdec = &sig.decl; let (generics, (fn_dec, fn_args)) = self.add_in_band_defs( generics, def_id, diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index c3e96a31e4001..5816a64fca52c 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -32,6 +32,7 @@ #![feature(array_value_iter)] #![feature(crate_visibility_modifier)] +#![recursion_limit = "256"] use rustc::arena::Arena; use rustc::dep_graph::DepGraph; @@ -63,7 +64,7 @@ use syntax::attr; use syntax::node_id::NodeMap; use syntax::token::{self, Nonterminal, Token}; use syntax::tokenstream::{TokenStream, TokenTree}; -use syntax::visit::{self, Visitor}; +use syntax::visit::{self, AssocCtxt, Visitor}; use syntax::walk_list; use log::{debug, trace}; @@ -485,25 +486,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }); } - fn visit_trait_item(&mut self, item: &'tcx AssocItem) { + fn visit_assoc_item(&mut self, item: &'tcx AssocItem, ctxt: AssocCtxt) { self.lctx.allocate_hir_id_counter(item.id); - - match item.kind { - AssocItemKind::Fn(_, None) => { - // Ignore patterns in trait methods without bodies - self.with_hir_id_owner(None, |this| visit::walk_trait_item(this, item)); - } - _ => self.with_hir_id_owner(Some(item.id), |this| { - visit::walk_trait_item(this, item); - }), - } - } - - fn visit_impl_item(&mut self, item: &'tcx AssocItem) { - self.lctx.allocate_hir_id_counter(item.id); - self.with_hir_id_owner(Some(item.id), |this| { - visit::walk_impl_item(this, item); - }); + let owner = match (&item.kind, ctxt) { + // Ignore patterns in trait methods without bodies. + (AssocItemKind::Fn(_, None), AssocCtxt::Trait) => None, + _ => Some(item.id), + }; + self.with_hir_id_owner(owner, |this| visit::walk_assoc_item(this, item, ctxt)); } fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) { diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index cb64e2e95bf7d..53911d147802d 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -8,7 +8,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_err, Applicability, FatalError}; +use rustc_errors::{error_code, struct_span_err, Applicability, FatalError}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY; use rustc_session::lint::LintBuffer; @@ -20,7 +20,7 @@ use std::mem; use syntax::ast::*; use syntax::attr; use syntax::expand::is_proc_macro_attr; -use syntax::visit::{self, Visitor}; +use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use syntax::walk_list; /// Is `self` allowed semantically as the first parameter in an `FnDecl`? @@ -49,6 +49,13 @@ impl BoundContext { struct AstValidator<'a> { session: &'a Session, + + /// The span of the `extern` in an `extern { ... }` block, if any. + extern_mod: Option<&'a Item>, + + /// Are we inside a trait impl? + in_trait_impl: bool, + has_proc_macro_decls: bool, /// Used to ban nested `impl Trait`, e.g., `impl Into`. @@ -389,13 +396,9 @@ impl<'a> AstValidator<'a> { } } - fn check_impl_item_provided(&self, sp: Span, body: &Option, ctx: &str, sugg: &str) { - if body.is_some() { - return; - } - + fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) { self.err_handler() - .struct_span_err(sp, &format!("associated {} in `impl` without body", ctx)) + .struct_span_err(sp, msg) .span_suggestion( self.session.source_map().end_point(sp), &format!("provide a definition for the {}", ctx), @@ -405,6 +408,13 @@ impl<'a> AstValidator<'a> { .emit(); } + fn check_impl_item_provided(&self, sp: Span, body: &Option, ctx: &str, sugg: &str) { + if body.is_none() { + let msg = format!("associated {} in `impl` without body", ctx); + self.error_item_without_body(sp, ctx, &msg, sugg); + } + } + fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) { let span = match bounds { [] => return, @@ -416,8 +426,71 @@ impl<'a> AstValidator<'a> { .emit(); } - fn check_c_varadic_type(&self, decl: &FnDecl) { - for Param { ty, span, .. } in &decl.inputs { + /// An `fn` in `extern { ... }` cannot have a body `{ ... }`. + fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) { + let body = match body { + None => return, + Some(body) => body, + }; + self.err_handler() + .struct_span_err(ident.span, "incorrect function inside `extern` block") + .span_label(ident.span, "cannot have a body") + .span_suggestion( + body.span, + "remove the invalid body", + ";".to_string(), + Applicability::MaybeIncorrect, + ) + .help( + "you might have meant to write a function accessible through FFI, \ + which can be done by writing `extern fn` outside of the `extern` block", + ) + .span_label( + self.current_extern_span(), + "`extern` blocks define existing foreign functions and functions \ + inside of them cannot have a body", + ) + .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html") + .emit(); + } + + fn current_extern_span(&self) -> Span { + self.session.source_map().def_span(self.extern_mod.unwrap().span) + } + + /// An `fn` in `extern { ... }` cannot have qualfiers, e.g. `async fn`. + fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) { + if header.has_qualifiers() { + self.err_handler() + .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers") + .span_label(self.current_extern_span(), "in this `extern` block") + .span_suggestion( + span.until(ident.span.shrink_to_lo()), + "remove the qualifiers", + "fn ".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + } + } + + /// Reject C-varadic type unless the function is foreign, + /// or free and `unsafe extern "C"` semantically. + fn check_c_varadic_type(&self, fk: FnKind<'a>) { + match (fk.ctxt(), fk.header()) { + (Some(FnCtxt::Foreign), _) => return, + (Some(FnCtxt::Free), Some(header)) => match header.ext { + Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit + if header.unsafety == Unsafety::Unsafe => + { + return; + } + _ => {} + }, + _ => {} + }; + + for Param { ty, span, .. } in &fk.decl().inputs { if let TyKind::CVarArgs = ty.kind { self.err_handler() .struct_span_err( @@ -428,6 +501,24 @@ impl<'a> AstValidator<'a> { } } } + + /// We currently do not permit const generics in `const fn`, + /// as this is tantamount to allowing compile-time dependent typing. + /// + /// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor. + /// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck. + fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) { + if sig.header.constness.node == Constness::Const { + // Look for const generics and error if we find any. + for param in &generics.params { + if let GenericParamKind::Const { .. } = param.kind { + self.err_handler() + .struct_span_err(span, "const parameters are not permitted in `const fn`") + .emit(); + } + } + } + } } enum GenericPosition { @@ -532,9 +623,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_expr(&mut self, expr: &'a Expr) { match &expr.kind { - ExprKind::Closure(_, _, _, fn_decl, _, _) => { - self.check_fn_decl(fn_decl, SelfSemantic::No); - } ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => { struct_span_err!( self.session, @@ -647,8 +735,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { generics: _, of_trait: Some(_), ref self_ty, - ref items, + items: _, } => { + let old_in_trait_impl = mem::replace(&mut self.in_trait_impl, true); + self.invalid_visibility(&item.vis, None); if let TyKind::Err = self_ty.kind { self.err_handler() @@ -665,13 +755,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ) .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); - } - } + + visit::walk_item(self, item); + + self.in_trait_impl = old_in_trait_impl; + return; // Avoid visiting again. } ItemKind::Impl { unsafety, @@ -712,40 +800,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .emit(); } } - ItemKind::Fn(ref sig, ref generics, _) => { - self.visit_fn_header(&sig.header); - self.check_fn_decl(&sig.decl, SelfSemantic::No); - // We currently do not permit const generics in `const fn`, as - // this is tantamount to allowing compile-time dependent typing. - if sig.header.constness.node == Constness::Const { - // Look for const generics and error if we find any. - for param in &generics.params { - match param.kind { - GenericParamKind::Const { .. } => { - self.err_handler() - .struct_span_err( - item.span, - "const parameters are not permitted in `const fn`", - ) - .emit(); - } - _ => {} - } - } - } - // Reject C-varadic type unless the function is `unsafe extern "C"` semantically. - match sig.header.ext { - Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) - | Extern::Implicit - if sig.header.unsafety == Unsafety::Unsafe => {} - _ => self.check_c_varadic_type(&sig.decl), + ItemKind::Fn(ref sig, ref generics, ref body) => { + self.check_const_fn_const_generic(item.span, sig, generics); + + if body.is_none() { + let msg = "free function without a body"; + self.error_item_without_body(item.span, "function", msg, " { }"); } } - ItemKind::ForeignMod(..) => { + ItemKind::ForeignMod(_) => { + let old_item = mem::replace(&mut self.extern_mod, Some(item)); self.invalid_visibility( &item.vis, Some("place qualifiers on individual foreign items instead"), ); + visit::walk_item(self, item); + self.extern_mod = old_item; + return; // Avoid visiting again. } ItemKind::Enum(ref def, _) => { for variant in &def.variants { @@ -796,7 +867,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.with_bound_context(BoundContext::TraitBounds, |this| { walk_list!(this, visit_param_bound, bounds); }); - walk_list!(self, visit_trait_item, trait_items); + walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait); walk_list!(self, visit_attribute, &item.attrs); return; } @@ -820,19 +891,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { - match fi.kind { - ForeignItemKind::Fn(ref decl, _) => { - self.check_fn_decl(decl, SelfSemantic::No); - Self::check_decl_no_pat(decl, |span, _| { - struct_span_err!( - self.session, - span, - E0130, - "patterns aren't allowed in foreign function declarations" - ) - .span_label(span, "pattern not allowed in foreign function") - .emit(); - }); + match &fi.kind { + ForeignItemKind::Fn(sig, _, body) => { + self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); + self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header); } ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {} } @@ -1011,67 +1073,84 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }) } - fn visit_impl_item(&mut self, ii: &'a AssocItem) { - match &ii.kind { - AssocItemKind::Const(_, body) => { - self.check_impl_item_provided(ii.span, body, "constant", " = ;"); - } - AssocItemKind::Fn(_, body) => { - self.check_impl_item_provided(ii.span, body, "function", " { }"); - } - AssocItemKind::TyAlias(bounds, body) => { - self.check_impl_item_provided(ii.span, body, "type", " = ;"); - self.check_impl_assoc_type_no_bounds(bounds); - } - _ => {} + fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) { + // Only associated `fn`s can have `self` parameters. + let self_semantic = match fk.ctxt() { + Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes, + _ => SelfSemantic::No, + }; + self.check_fn_decl(fk.decl(), self_semantic); + + self.check_c_varadic_type(fk); + + // Functions without bodies cannot have patterns. + if let FnKind::Fn(ctxt, _, sig, _, None) = fk { + Self::check_decl_no_pat(&sig.decl, |span, mut_ident| { + let (code, msg, label) = match ctxt { + FnCtxt::Foreign => ( + error_code!(E0130), + "patterns aren't allowed in foreign function declarations", + "pattern not allowed in foreign function", + ), + _ => ( + error_code!(E0642), + "patterns aren't allowed in functions without bodies", + "pattern not allowed in function without body", + ), + }; + if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { + self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg); + } else { + self.err_handler() + .struct_span_err(span, msg) + .span_label(span, label) + .code(code) + .emit(); + } + }); } - visit::walk_impl_item(self, ii); + + visit::walk_fn(self, fk, span); } - fn visit_trait_item(&mut self, ti: &'a AssocItem) { - self.invalid_visibility(&ti.vis, None); - self.check_defaultness(ti.span, ti.defaultness); - - if let AssocItemKind::Fn(sig, block) = &ti.kind { - self.check_trait_fn_not_async(ti.span, sig.header.asyncness.node); - self.check_trait_fn_not_const(sig.header.constness); - if block.is_none() { - Self::check_decl_no_pat(&sig.decl, |span, mut_ident| { - if mut_ident { - self.lint_buffer.buffer_lint( - PATTERNS_IN_FNS_WITHOUT_BODY, - ti.id, - span, - "patterns aren't allowed in methods without bodies", - ); - } else { - struct_span_err!( - self.session, - span, - E0642, - "patterns aren't allowed in methods without bodies" - ) - .emit(); - } - }); - } + fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { + if ctxt == AssocCtxt::Trait { + self.check_defaultness(item.span, item.defaultness); } - visit::walk_trait_item(self, ti); - } + if ctxt == AssocCtxt::Impl { + match &item.kind { + AssocItemKind::Const(_, body) => { + self.check_impl_item_provided(item.span, body, "constant", " = ;"); + } + AssocItemKind::Fn(_, body) => { + self.check_impl_item_provided(item.span, body, "function", " { }"); + } + AssocItemKind::TyAlias(bounds, body) => { + self.check_impl_item_provided(item.span, body, "type", " = ;"); + self.check_impl_assoc_type_no_bounds(bounds); + } + _ => {} + } + } - fn visit_assoc_item(&mut self, item: &'a AssocItem) { - if let AssocItemKind::Fn(sig, _) = &item.kind { - self.check_fn_decl(&sig.decl, SelfSemantic::Yes); - self.check_c_varadic_type(&sig.decl); + if ctxt == AssocCtxt::Trait || self.in_trait_impl { + self.invalid_visibility(&item.vis, None); + if let AssocItemKind::Fn(sig, _) = &item.kind { + self.check_trait_fn_not_const(sig.header.constness); + self.check_trait_fn_not_async(item.span, sig.header.asyncness.node); + } } - visit::walk_assoc_item(self, item); + + visit::walk_assoc_item(self, item, ctxt); } } pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool { let mut validator = AstValidator { session, + extern_mod: None, + in_trait_impl: false, has_proc_macro_decls: false, outer_impl_trait: None, bound_context: None, diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index 3b13ab354fdf9..a10ac94d8942b 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -8,7 +8,7 @@ use rustc_span::Span; use syntax::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId}; use syntax::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData}; use syntax::attr; -use syntax::visit::{self, FnKind, Visitor}; +use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use log::debug; @@ -492,25 +492,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_pat(self, pattern) } - fn visit_fn( - &mut self, - fn_kind: FnKind<'a>, - fn_decl: &'a ast::FnDecl, - span: Span, - _node_id: NodeId, - ) { + fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { if let Some(header) = fn_kind.header() { - // Stability of const fn methods are covered in - // `visit_trait_item` and `visit_impl_item` below; this is - // because default methods don't pass through this point. + // Stability of const fn methods are covered in `visit_assoc_item` below. self.check_extern(header.ext); } - if fn_decl.c_variadic() { + if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() { gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); } - visit::walk_fn(self, fn_kind, fn_decl, span) + visit::walk_fn(self, fn_kind, span) } fn visit_generic_param(&mut self, param: &'a GenericParam) { @@ -539,56 +531,35 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_assoc_ty_constraint(self, constraint) } - fn visit_trait_item(&mut self, ti: &'a ast::AssocItem) { - match ti.kind { - ast::AssocItemKind::Fn(ref sig, ref block) => { - if block.is_none() { - self.check_extern(sig.header.ext); - } - if sig.header.constness.node == ast::Constness::Const { - gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); + fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { + if i.defaultness == ast::Defaultness::Default { + gate_feature_post!(&self, specialization, i.span, "specialization is unstable"); + } + + match i.kind { + ast::AssocItemKind::Fn(ref sig, _) => { + let constness = sig.header.constness.node; + if let (ast::Constness::Const, AssocCtxt::Trait) = (constness, ctxt) { + gate_feature_post!(&self, const_fn, i.span, "const fn is unstable"); } } - ast::AssocItemKind::TyAlias(_, ref default) => { - if let Some(_) = default { + ast::AssocItemKind::TyAlias(_, ref ty) => { + if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) { gate_feature_post!( &self, associated_type_defaults, - ti.span, + i.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 { - ast::AssocItemKind::Fn(ref sig, _) => { - if sig.decl.c_variadic() { - gate_feature_post!( - &self, - c_variadic, - ii.span, - "C-variadic functions are unstable" - ); - } - } - ast::AssocItemKind::TyAlias(_, ref ty) => { if let Some(ty) = ty { self.check_impl_trait(ty); } - self.check_gat(&ii.generics, ii.span); + self.check_gat(&i.generics, i.span); } _ => {} } - visit::walk_assoc_item(self, ii) + visit::walk_assoc_item(self, i, ctxt) } fn visit_vis(&mut self, vis: &'a ast::Visibility) { diff --git a/src/librustc_ast_passes/node_count.rs b/src/librustc_ast_passes/node_count.rs index 9fe7238fcfc3e..ed1ccdf6a768a 100644 --- a/src/librustc_ast_passes/node_count.rs +++ b/src/librustc_ast_passes/node_count.rs @@ -67,13 +67,13 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_generics(self, g) } - fn visit_fn(&mut self, fk: FnKind<'_>, fd: &FnDecl, s: Span, _: NodeId) { + fn visit_fn(&mut self, fk: FnKind<'_>, s: Span, _: NodeId) { self.count += 1; - walk_fn(self, fk, fd, s) + walk_fn(self, fk, s) } - fn visit_assoc_item(&mut self, ti: &AssocItem) { + fn visit_assoc_item(&mut self, ti: &AssocItem, ctxt: AssocCtxt) { self.count += 1; - walk_assoc_item(self, ti) + walk_assoc_item(self, ti, ctxt); } fn visit_trait_ref(&mut self, t: &TraitRef) { self.count += 1; diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 3cc67a7c82117..d9077d1606f3a 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1020,18 +1020,8 @@ impl<'a> State<'a> { self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(&item.attrs); match item.kind { - ast::ForeignItemKind::Fn(ref decl, ref generics) => { - self.head(""); - self.print_fn( - decl, - ast::FnHeader::default(), - Some(item.ident), - generics, - &item.vis, - ); - self.end(); // end head-ibox - self.s.word(";"); - self.end(); // end the outer fn box + ast::ForeignItemKind::Fn(ref sig, ref gen, ref body) => { + self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs); } ast::ForeignItemKind::Static(ref t, m) => { self.head(visibility_qualified(&item.vis, "static")); @@ -1154,11 +1144,8 @@ impl<'a> State<'a> { self.s.word(";"); self.end(); // end the outer cbox } - ast::ItemKind::Fn(ref sig, ref param_names, ref body) => { - self.head(""); - self.print_fn(&sig.decl, sig.header, Some(item.ident), param_names, &item.vis); - self.s.word(" "); - self.print_block_with_attrs(body, &item.attrs); + ast::ItemKind::Fn(ref sig, ref gen, ref body) => { + self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs); } ast::ItemKind::Mod(ref _mod) => { self.head(visibility_qualified(&item.vis, "mod")); @@ -1483,16 +1470,8 @@ impl<'a> State<'a> { self.print_associated_const(item.ident, ty, expr.as_deref(), &item.vis); } ast::AssocItemKind::Fn(sig, body) => { - if body.is_some() { - self.head(""); - } - self.print_fn(&sig.decl, sig.header, Some(item.ident), &item.generics, &item.vis); - if let Some(body) = body { - self.nbsp(); - self.print_block_with_attrs(body, &item.attrs); - } else { - self.s.word(";"); - } + let body = body.as_deref(); + self.print_fn_full(sig, item.ident, &item.generics, &item.vis, body, &item.attrs); } ast::AssocItemKind::TyAlias(bounds, ty) => { self.print_associated_type(item.ident, bounds, ty.as_deref()); @@ -2412,6 +2391,27 @@ impl<'a> State<'a> { } } + fn print_fn_full( + &mut self, + sig: &ast::FnSig, + name: ast::Ident, + generics: &ast::Generics, + vis: &ast::Visibility, + body: Option<&ast::Block>, + attrs: &[ast::Attribute], + ) { + if body.is_some() { + self.head(""); + } + self.print_fn(&sig.decl, sig.header, Some(name), generics, vis); + if let Some(body) = body { + self.nbsp(); + self.print_block_with_attrs(body, attrs); + } else { + self.s.word(";"); + } + } + crate fn print_fn( &mut self, decl: &ast::FnDecl, @@ -2698,13 +2698,9 @@ impl<'a> State<'a> { where_clause: ast::WhereClause { predicates: Vec::new(), span: rustc_span::DUMMY_SP }, span: rustc_span::DUMMY_SP, }; - self.print_fn( - decl, - ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() }, - name, - &generics, - &dummy_spanned(ast::VisibilityKind::Inherited), - ); + let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() }; + let vis = dummy_spanned(ast::VisibilityKind::Inherited); + self.print_fn(decl, header, name, &generics, &vis); self.end(); } diff --git a/src/librustc_builtin_macros/global_allocator.rs b/src/librustc_builtin_macros/global_allocator.rs index 957d34b7d8983..ec0d55b38a73d 100644 --- a/src/librustc_builtin_macros/global_allocator.rs +++ b/src/librustc_builtin_macros/global_allocator.rs @@ -66,7 +66,7 @@ impl AllocFnFactory<'_, '_> { let decl = self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)); let header = FnHeader { unsafety: Unsafety::Unsafe, ..FnHeader::default() }; let sig = FnSig { decl, header }; - let kind = ItemKind::Fn(sig, Generics::default(), self.cx.block_expr(output_expr)); + let kind = ItemKind::Fn(sig, Generics::default(), Some(self.cx.block_expr(output_expr))); let item = self.cx.item( self.span, self.cx.ident_of(&self.kind.fn_name(method.name), self.span), diff --git a/src/librustc_builtin_macros/test_harness.rs b/src/librustc_builtin_macros/test_harness.rs index 6a73f121c99bf..70f1c0e4e2d7c 100644 --- a/src/librustc_builtin_macros/test_harness.rs +++ b/src/librustc_builtin_macros/test_harness.rs @@ -307,7 +307,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { let decl = ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)); let sig = ast::FnSig { decl, header: ast::FnHeader::default() }; - let main = ast::ItemKind::Fn(sig, ast::Generics::default(), main_body); + let main = ast::ItemKind::Fn(sig, ast::Generics::default(), Some(main_body)); // Honor the reexport_test_harness_main attribute let main_id = match cx.reexport_test_harness_main { diff --git a/src/librustc_error_codes/error_codes/E0264.md b/src/librustc_error_codes/error_codes/E0264.md index e1e7516cec2c7..708eac8837a7c 100644 --- a/src/librustc_error_codes/error_codes/E0264.md +++ b/src/librustc_error_codes/error_codes/E0264.md @@ -1,4 +1,6 @@ -An unknown external lang item was used. Erroneous code example: +An unknown external lang item was used. + +Erroneous code example: ```compile_fail,E0264 #![feature(lang_items)] diff --git a/src/librustc_error_codes/error_codes/E0267.md b/src/librustc_error_codes/error_codes/E0267.md index 066ebee0ffb74..951490df87403 100644 --- a/src/librustc_error_codes/error_codes/E0267.md +++ b/src/librustc_error_codes/error_codes/E0267.md @@ -1,5 +1,7 @@ -This error indicates the use of a loop keyword (`break` or `continue`) inside a -closure but outside of any loop. Erroneous code example: +A loop keyword (`break` or `continue`) was used inside a closure but outside of +any loop. + +Erroneous code example: ```compile_fail,E0267 let w = || { break; }; // error: `break` inside of a closure diff --git a/src/librustc_error_codes/error_codes/E0268.md b/src/librustc_error_codes/error_codes/E0268.md index 7f3ac1186018a..436aef79fe0b3 100644 --- a/src/librustc_error_codes/error_codes/E0268.md +++ b/src/librustc_error_codes/error_codes/E0268.md @@ -1,6 +1,6 @@ -This error indicates the use of a loop keyword (`break` or `continue`) outside -of a loop. Without a loop to break out of or continue in, no sensible action can -be taken. Erroneous code example: +A loop keyword (`break` or `continue`) was used outside of a loop. + +Erroneous code example: ```compile_fail,E0268 fn some_func() { @@ -8,6 +8,7 @@ fn some_func() { } ``` +Without a loop to break out of or continue in, no sensible action can be taken. Please verify that you are using `break` and `continue` only in loops. Example: ``` diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 536259e054718..e167089b93a35 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -17,7 +17,7 @@ use syntax::mut_visit::{self, MutVisitor}; use syntax::ptr::P; use syntax::token; use syntax::tokenstream::{self, TokenStream}; -use syntax::visit::Visitor; +use syntax::visit::{AssocCtxt, Visitor}; use std::default::Default; use std::iter; @@ -103,8 +103,8 @@ impl Annotatable { pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) { match self { Annotatable::Item(item) => visitor.visit_item(item), - Annotatable::TraitItem(trait_item) => visitor.visit_trait_item(trait_item), - Annotatable::ImplItem(impl_item) => visitor.visit_impl_item(impl_item), + Annotatable::TraitItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Trait), + Annotatable::ImplItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Impl), Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item), Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt), Annotatable::Expr(expr) => visitor.visit_expr(expr), diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 0b8cbd3a78333..90692fe1ec9dd 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -25,7 +25,7 @@ use syntax::ptr::P; use syntax::token; use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::util::map_in_place::MapInPlace; -use syntax::visit::{self, Visitor}; +use syntax::visit::{self, AssocCtxt, Visitor}; use smallvec::{smallvec, SmallVec}; use std::io::ErrorKind; @@ -39,7 +39,7 @@ macro_rules! ast_fragments { $($Kind:ident($AstTy:ty) { $kind_name:expr; $(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)? - $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident;)? + $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)? fn $make_ast:ident; })* ) => { @@ -127,7 +127,7 @@ macro_rules! ast_fragments { AstFragment::OptExpr(None) => {} $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)* $($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] { - visitor.$visit_ast_elt(ast_elt); + visitor.$visit_ast_elt(ast_elt, $($args)*); })?)* } } @@ -147,52 +147,58 @@ ast_fragments! { Pat(P) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; } Ty(P) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; } Stmts(SmallVec<[ast::Stmt; 1]>) { - "statement"; many fn flat_map_stmt; fn visit_stmt; fn make_stmts; + "statement"; many fn flat_map_stmt; fn visit_stmt(); fn make_stmts; } Items(SmallVec<[P; 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; 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; 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; 1]>) { "foreign item"; many fn flat_map_foreign_item; - fn visit_foreign_item; + fn visit_foreign_item(); fn make_foreign_items; } Arms(SmallVec<[ast::Arm; 1]>) { - "match arm"; many fn flat_map_arm; fn visit_arm; fn make_arms; + "match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms; } Fields(SmallVec<[ast::Field; 1]>) { - "field expression"; many fn flat_map_field; fn visit_field; fn make_fields; + "field expression"; many fn flat_map_field; fn visit_field(); fn make_fields; } FieldPats(SmallVec<[ast::FieldPat; 1]>) { "field pattern"; many fn flat_map_field_pattern; - fn visit_field_pattern; + fn visit_field_pattern(); fn make_field_patterns; } GenericParams(SmallVec<[ast::GenericParam; 1]>) { "generic parameter"; many fn flat_map_generic_param; - fn visit_generic_param; + fn visit_generic_param(); fn make_generic_params; } Params(SmallVec<[ast::Param; 1]>) { - "function parameter"; many fn flat_map_param; fn visit_param; fn make_params; + "function parameter"; many fn flat_map_param; fn visit_param(); fn make_params; } StructFields(SmallVec<[ast::StructField; 1]>) { "field"; many fn flat_map_struct_field; - fn visit_struct_field; + fn visit_struct_field(); fn make_struct_fields; } Variants(SmallVec<[ast::Variant; 1]>) { - "variant"; many fn flat_map_variant; fn visit_variant; fn make_variants; + "variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants; } } @@ -609,8 +615,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { &format!("recursion limit reached while expanding `{}`", expn_data.kind.descr()), ); err.help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + suggested_limit, self.cx.ecfg.crate_name, )); err.emit(); self.cx.trace_macros_diag(); @@ -861,7 +867,7 @@ pub fn parse_ast_fragment<'a>( AstFragmentKind::ForeignItems => { let mut items = SmallVec::new(); while this.token != token::Eof { - items.push(this.parse_foreign_item(DUMMY_SP)?); + items.push(this.parse_foreign_item()?); } AstFragment::ForeignItems(items) } diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 3ed0ad16eebf2..0c93a192667e5 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2260,10 +2260,10 @@ impl TraitRef<'_> { #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub struct PolyTraitRef<'hir> { - /// The `'a` in `<'a> Foo<&'a T>`. + /// The `'a` in `for<'a> Foo<&'a T>`. pub bound_generic_params: &'hir [GenericParam<'hir>], - /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`. + /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`. pub trait_ref: TraitRef<'hir>, pub span: Span, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 345665de63c3c..f024bb0e8b5c8 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -43,7 +43,7 @@ use rustc_span::{BytePos, Span}; use syntax::ast::{self, Expr}; use syntax::attr::{self, HasAttrs}; use syntax::tokenstream::{TokenStream, TokenTree}; -use syntax::visit::FnKind; +use syntax::visit::{FnCtxt, FnKind}; use crate::nonstandard_style::{method_context, MethodLateContext}; @@ -259,34 +259,22 @@ impl EarlyLintPass for UnsafeCode { } } - fn check_fn( - &mut self, - cx: &EarlyContext<'_>, - fk: FnKind<'_>, - _: &ast::FnDecl, - span: Span, - _: ast::NodeId, - ) { - match fk { - FnKind::ItemFn(_, ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, ..) => { - self.report_unsafe(cx, span, "declaration of an `unsafe` function") - } - - FnKind::Method(_, sig, ..) => { - if sig.header.unsafety == ast::Unsafety::Unsafe { - self.report_unsafe(cx, span, "implementation of an `unsafe` method") - } - } - - _ => (), - } - } - - fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &ast::AssocItem) { - if let ast::AssocItemKind::Fn(ref sig, None) = item.kind { - if sig.header.unsafety == ast::Unsafety::Unsafe { - self.report_unsafe(cx, item.span, "declaration of an `unsafe` method") - } + fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) { + if let FnKind::Fn( + ctxt, + _, + ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, .. }, + _, + body, + ) = fk + { + let msg = match ctxt { + FnCtxt::Foreign => return, + FnCtxt::Free => "declaration of an `unsafe` function", + FnCtxt::Assoc(_) if body.is_none() => "declaration of an `unsafe` method", + FnCtxt::Assoc(_) => "implementation of an `unsafe` method", + }; + self.report_unsafe(cx, span, msg); } } } diff --git a/src/librustc_lint/early.rs b/src/librustc_lint/early.rs index 490114b2d4d2a..542cbea0c954a 100644 --- a/src/librustc_lint/early.rs +++ b/src/librustc_lint/early.rs @@ -116,17 +116,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> ast_visit::walk_stmt(self, s); } - fn visit_fn( - &mut self, - fk: ast_visit::FnKind<'a>, - decl: &'a ast::FnDecl, - span: Span, - id: ast::NodeId, - ) { - run_early_pass!(self, check_fn, fk, decl, span, id); + fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, span: Span, id: ast::NodeId) { + run_early_pass!(self, check_fn, fk, span, id); self.check_id(id); - ast_visit::walk_fn(self, fk, decl, span); - run_early_pass!(self, check_fn_post, fk, decl, span, id); + ast_visit::walk_fn(self, fk, span); + run_early_pass!(self, check_fn_post, fk, span, id); } fn visit_variant_data(&mut self, s: &'a ast::VariantData) { @@ -213,19 +207,18 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> ast_visit::walk_poly_trait_ref(self, t, m); } - fn visit_trait_item(&mut self, trait_item: &'a ast::AssocItem) { - self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| { - run_early_pass!(cx, check_trait_item, trait_item); - ast_visit::walk_trait_item(cx, trait_item); - run_early_pass!(cx, check_trait_item_post, trait_item); - }); - } - - fn visit_impl_item(&mut self, impl_item: &'a ast::AssocItem) { - self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| { - run_early_pass!(cx, check_impl_item, impl_item); - ast_visit::walk_impl_item(cx, impl_item); - run_early_pass!(cx, check_impl_item_post, impl_item); + fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: ast_visit::AssocCtxt) { + self.with_lint_attrs(item.id, &item.attrs, |cx| match ctxt { + ast_visit::AssocCtxt::Trait => { + run_early_pass!(cx, check_trait_item, item); + ast_visit::walk_assoc_item(cx, item, ctxt); + run_early_pass!(cx, check_trait_item_post, item); + } + ast_visit::AssocCtxt::Impl => { + run_early_pass!(cx, check_impl_item, item); + ast_visit::walk_assoc_item(cx, item, ctxt); + run_early_pass!(cx, check_impl_item_post, item); + } }); } diff --git a/src/librustc_lint/passes.rs b/src/librustc_lint/passes.rs index 7e5d670767ad8..36de625cafac2 100644 --- a/src/librustc_lint/passes.rs +++ b/src/librustc_lint/passes.rs @@ -179,10 +179,9 @@ macro_rules! early_lint_methods { fn check_where_predicate(a: &ast::WherePredicate); fn check_poly_trait_ref(a: &ast::PolyTraitRef, b: &ast::TraitBoundModifier); - fn check_fn(a: syntax::visit::FnKind<'_>, b: &ast::FnDecl, c: Span, d_: ast::NodeId); + fn check_fn(a: syntax::visit::FnKind<'_>, c: Span, d_: ast::NodeId); fn check_fn_post( a: syntax::visit::FnKind<'_>, - b: &ast::FnDecl, c: Span, d: ast::NodeId ); diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index b1cab591fd97c..7c015c7a1d75d 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -1,3 +1,4 @@ +use super::ty::AllowPlus; use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType}; use rustc_ast_pretty::pprust; @@ -693,11 +694,11 @@ impl<'a> Parser<'a> { pub(super) fn maybe_report_ambiguous_plus( &mut self, - allow_plus: bool, + allow_plus: AllowPlus, impl_dyn_multi: bool, ty: &Ty, ) { - if !allow_plus && impl_dyn_multi { + if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi { let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); self.struct_span_err(ty.span, "ambiguous `+` in a type") .span_suggestion( @@ -712,11 +713,11 @@ impl<'a> Parser<'a> { pub(super) fn maybe_recover_from_bad_type_plus( &mut self, - allow_plus: bool, + allow_plus: AllowPlus, ty: &Ty, ) -> PResult<'a, ()> { // Do not add `+` to expected tokens. - if !allow_plus || !self.token.is_like_plus() { + if matches!(allow_plus, AllowPlus::No) || !self.token.is_like_plus() { return Ok(()); } @@ -937,47 +938,6 @@ impl<'a> Parser<'a> { self.expect(&token::Semi).map(drop) // Error unconditionally } - pub(super) fn parse_semi_or_incorrect_foreign_fn_body( - &mut self, - ident: &Ident, - extern_sp: Span, - ) -> PResult<'a, ()> { - if self.token != token::Semi { - // This might be an incorrect fn definition (#62109). - let parser_snapshot = self.clone(); - match self.parse_inner_attrs_and_block() { - Ok((_, body)) => { - self.struct_span_err(ident.span, "incorrect `fn` inside `extern` block") - .span_label(ident.span, "can't have a body") - .span_label(body.span, "this body is invalid here") - .span_label( - extern_sp, - "`extern` blocks define existing foreign functions and `fn`s \ - inside of them cannot have a body", - ) - .help( - "you might have meant to write a function accessible through ffi, \ - which can be done by writing `extern fn` outside of the \ - `extern` block", - ) - .note( - "for more information, visit \ - https://doc.rust-lang.org/std/keyword.extern.html", - ) - .emit(); - } - Err(mut err) => { - err.cancel(); - mem::replace(self, parser_snapshot); - self.expect_semi()?; - } - } - } else { - self.bump(); - } - Ok(()) - } - /// Consumes alternative await syntaxes like `await!()`, `await `, /// `await? `, `await()`, and `await { }`. pub(super) fn recover_incorrect_await_syntax( diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 0d12f8cf6c039..d98321416957d 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1,4 +1,5 @@ use super::pat::{GateOr, PARAM_EXPECTED}; +use super::ty::{AllowPlus, RecoverQPath}; use super::{BlockMode, Parser, PathStyle, PrevTokenKind, Restrictions, TokenType}; use super::{SemiColonMode, SeqSep, TokenExpectType}; use crate::maybe_recover_from_interpolated_ty_qpath; @@ -1399,7 +1400,7 @@ impl<'a> Parser<'a> { self.expect_or()?; args }; - let output = self.parse_ret_ty(true, true)?; + let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes)?; Ok(P(FnDecl { inputs, output })) } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index b7f299e56ae50..07d8bae4725bd 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1,4 +1,5 @@ use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error}; +use super::ty::{AllowPlus, RecoverQPath}; use super::{FollowedByType, Parser, PathStyle}; use crate::maybe_whole; @@ -96,7 +97,6 @@ impl<'a> Parser<'a> { } if self.eat_keyword(kw::Extern) { - let extern_sp = self.prev_span; if self.eat_keyword(kw::Crate) { return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?)); } @@ -114,7 +114,7 @@ impl<'a> Parser<'a> { }; return self.parse_item_fn(lo, vis, attrs, header); } else if self.check(&token::OpenDelim(token::Brace)) { - return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs, extern_sp)?)); + return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs)?)); } self.unexpected()?; @@ -1045,7 +1045,6 @@ impl<'a> Parser<'a> { abi: Option, visibility: Visibility, mut attrs: Vec, - extern_sp: Span, ) -> PResult<'a, P> { self.expect(&token::OpenDelim(token::Brace))?; @@ -1053,7 +1052,7 @@ impl<'a> Parser<'a> { let mut foreign_items = vec![]; while !self.eat(&token::CloseDelim(token::Brace)) { - foreign_items.push(self.parse_foreign_item(extern_sp)?); + foreign_items.push(self.parse_foreign_item()?); } let prev_span = self.prev_span; @@ -1063,51 +1062,42 @@ impl<'a> Parser<'a> { } /// Parses a foreign item. - pub fn parse_foreign_item(&mut self, extern_sp: Span) -> PResult<'a, P> { + pub fn parse_foreign_item(&mut self) -> PResult<'a, P> { maybe_whole!(self, NtForeignItem, |ni| ni); let attrs = self.parse_outer_attributes()?; let lo = self.token.span; let visibility = self.parse_visibility(FollowedByType::No)?; + // FOREIGN TYPE ITEM + if self.check_keyword(kw::Type) { + return self.parse_item_foreign_type(visibility, lo, attrs); + } + // FOREIGN STATIC ITEM - // Treat `const` as `static` for error recovery, but don't add it to expected tokens. - if self.check_keyword(kw::Static) || self.token.is_keyword(kw::Const) { - if self.token.is_keyword(kw::Const) { - let mut err = - self.struct_span_err(self.token.span, "extern items cannot be `const`"); + if self.is_static_global() { + self.bump(); // `static` + return self.parse_item_foreign_static(visibility, lo, attrs); + } - // The user wrote 'const fn' - if self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe]) { - err.emit(); - // Consume `const` - self.bump(); - // Consume `unsafe` if present, since `extern` blocks - // don't allow it. This will leave behind a plain 'fn' - self.eat_keyword(kw::Unsafe); - // Treat 'const fn` as a plain `fn` for error recovery purposes. - // We've already emitted an error, so compilation is guaranteed - // to fail - return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?); - } - err.span_suggestion( - self.token.span, + // Treat `const` as `static` for error recovery, but don't add it to expected tokens. + if self.is_kw_followed_by_ident(kw::Const) { + self.bump(); // `const` + self.struct_span_err(self.prev_span, "extern items cannot be `const`") + .span_suggestion( + self.prev_span, "try using a static value", "static".to_owned(), Applicability::MachineApplicable, - ); - err.emit(); - } - self.bump(); // `static` or `const` - return Ok(self.parse_item_foreign_static(visibility, lo, attrs)?); + ) + .emit(); + return self.parse_item_foreign_static(visibility, lo, attrs); } + // FOREIGN FUNCTION ITEM - if self.check_keyword(kw::Fn) { - return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?); - } - // FOREIGN TYPE ITEM - if self.check_keyword(kw::Type) { - return Ok(self.parse_item_foreign_type(visibility, lo, attrs)?); + const MAY_INTRODUCE_FN: &[Symbol] = &[kw::Const, kw::Async, kw::Unsafe, kw::Extern, kw::Fn]; + if MAY_INTRODUCE_FN.iter().any(|&kw| self.check_keyword(kw)) { + return self.parse_item_foreign_fn(visibility, lo, attrs); } match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? { @@ -1726,14 +1716,14 @@ impl<'a> Parser<'a> { &mut self, lo: Span, vis: Visibility, - attrs: Vec, + mut attrs: Vec, header: FnHeader, ) -> PResult<'a, Option>> { let cfg = ParamCfg { is_name_required: |_| true }; let (ident, decl, generics) = self.parse_fn_sig(&cfg)?; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + let body = self.parse_fn_body(&mut false, &mut attrs)?; let kind = ItemKind::Fn(FnSig { decl, header }, generics, body); - self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs))) + self.mk_item_with_info(attrs, lo, vis, (ident, kind, None)) } /// Parses a function declaration from a foreign module. @@ -1741,15 +1731,14 @@ impl<'a> Parser<'a> { &mut self, vis: ast::Visibility, lo: Span, - attrs: Vec, - extern_sp: Span, + mut attrs: Vec, ) -> PResult<'a, P> { let cfg = ParamCfg { is_name_required: |_| true }; - self.expect_keyword(kw::Fn)?; + let header = self.parse_fn_front_matter()?; let (ident, decl, generics) = self.parse_fn_sig(&cfg)?; - let span = lo.to(self.token.span); - self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?; - let kind = ForeignItemKind::Fn(decl, generics); + let body = self.parse_fn_body(&mut false, &mut attrs)?; + let kind = ForeignItemKind::Fn(FnSig { header, decl }, generics, body); + let span = lo.to(self.prev_span); Ok(P(ast::ForeignItem { ident, attrs, kind, id: DUMMY_NODE_ID, span, vis, tokens: None })) } @@ -1760,45 +1749,40 @@ impl<'a> Parser<'a> { is_name_required: fn(&token::Token) -> bool, ) -> PResult<'a, (Ident, AssocItemKind, Generics)> { let header = self.parse_fn_front_matter()?; - let (ident, decl, generics) = self.parse_fn_sig(&ParamCfg { is_name_required })?; - let sig = FnSig { header, decl }; - let body = self.parse_assoc_fn_body(at_end, attrs)?; - Ok((ident, AssocItemKind::Fn(sig, body), generics)) + let (ident, decl, generics) = self.parse_fn_sig(&&ParamCfg { is_name_required })?; + let body = self.parse_fn_body(at_end, attrs)?; + Ok((ident, AssocItemKind::Fn(FnSig { header, decl }, body), generics)) } - /// Parse the "body" of a method in an associated item definition. + /// Parse the "body" of a function. /// This can either be `;` when there's no body, - /// or e.g. a block when the method is a provided one. - fn parse_assoc_fn_body( + /// or e.g. a block when the function is a provided one. + fn parse_fn_body( &mut self, at_end: &mut bool, attrs: &mut Vec, ) -> PResult<'a, Option>> { - Ok(match self.token.kind { + let (inner_attrs, body) = match self.token.kind { token::Semi => { - debug!("parse_assoc_fn_body(): parsing required method"); self.bump(); - *at_end = true; - None + (Vec::new(), None) } token::OpenDelim(token::Brace) => { - debug!("parse_assoc_fn_body(): parsing provided method"); - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) + let (attrs, body) = self.parse_inner_attrs_and_block()?; + (attrs, Some(body)) } token::Interpolated(ref nt) => match **nt { token::NtBlock(..) => { - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) + let (attrs, body) = self.parse_inner_attrs_and_block()?; + (attrs, Some(body)) } _ => return self.expected_semi_or_open_brace(), }, _ => return self.expected_semi_or_open_brace(), - }) + }; + attrs.extend(inner_attrs); + *at_end = true; + Ok(body) } /// Parses all the "front matter" for a `fn` declaration, up to @@ -1839,7 +1823,7 @@ impl<'a> Parser<'a> { fn parse_fn_sig(&mut self, cfg: &ParamCfg) -> PResult<'a, (Ident, P, Generics)> { let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let decl = self.parse_fn_decl(cfg, true)?; + let decl = self.parse_fn_decl(cfg, AllowPlus::Yes)?; generics.where_clause = self.parse_where_clause()?; Ok((ident, decl, generics)) } @@ -1848,11 +1832,11 @@ impl<'a> Parser<'a> { pub(super) fn parse_fn_decl( &mut self, cfg: &ParamCfg, - ret_allow_plus: bool, + ret_allow_plus: AllowPlus, ) -> PResult<'a, P> { Ok(P(FnDecl { inputs: self.parse_fn_params(cfg)?, - output: self.parse_ret_ty(ret_allow_plus, true)?, + output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?, })) } diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index a09eb42dcfe6a..cb14ffb4bd028 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -1,3 +1,4 @@ +use super::ty::{AllowPlus, RecoverQPath}; use super::{Parser, TokenType}; use crate::maybe_whole; use rustc_errors::{pluralize, Applicability, PResult}; @@ -224,7 +225,7 @@ impl<'a> Parser<'a> { // `(T, U) -> R` let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; let span = ident.span.to(self.prev_span); - let output = self.parse_ret_ty(false, false)?; + let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No)?; ParenthesizedArgs { inputs, output, span }.into() }; diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index ae8f1e4db1b38..f3a69729399c1 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -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()) } diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index c9c2cbb98ca40..990661bf6b5b9 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -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`, /// `IDENT<::AssocTy>`. /// @@ -48,14 +67,14 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, P> { - self.parse_ty_common(true, true, false) + self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::No) } /// Parse a type suitable for a function or function pointer parameter. /// The difference from `parse_ty` is that this version allows `...` /// (`CVarArgs`) at the top level of the the type. pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P> { - self.parse_ty_common(true, true, true) + self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::Yes) } /// Parses a type in restricted contexts where `+` is not permitted. @@ -65,18 +84,19 @@ impl<'a> Parser<'a> { /// Example 2: `value1 as TYPE + value2` /// `+` is prohibited to avoid interactions with expression grammar. pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { - self.parse_ty_common(false, true, false) + self.parse_ty_common(AllowPlus::No, RecoverQPath::Yes, AllowCVariadic::No) } /// Parses an optional return type `[ -> TY ]` in a function declaration. pub(super) fn parse_ret_ty( &mut self, - allow_plus: bool, - allow_qpath_recovery: bool, + allow_plus: AllowPlus, + recover_qpath: RecoverQPath, ) -> PResult<'a, FunctionRetTy> { Ok(if self.eat(&token::RArrow) { // FIXME(Centril): Can we unconditionally `allow_plus`? - FunctionRetTy::Ty(self.parse_ty_common(allow_plus, allow_qpath_recovery, false)?) + let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?; + FunctionRetTy::Ty(ty) } else { FunctionRetTy::Default(self.token.span.shrink_to_lo()) }) @@ -84,11 +104,11 @@ impl<'a> Parser<'a> { fn parse_ty_common( &mut self, - allow_plus: bool, - allow_qpath_recovery: bool, - // Is `...` (`CVarArgs`) legal in the immediate top level call? - allow_c_variadic: bool, + allow_plus: AllowPlus, + recover_qpath: RecoverQPath, + allow_c_variadic: AllowCVariadic, ) -> PResult<'a, P> { + let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); maybe_whole!(self, NtTy, |x| x); @@ -124,7 +144,7 @@ impl<'a> Parser<'a> { self.parse_ty_bare_fn(lifetime_defs)? } else { let path = self.parse_path(PathStyle::Type)?; - let parse_plus = allow_plus && self.check_plus(); + let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? } } else if self.eat_keyword(kw::Impl) { @@ -144,7 +164,7 @@ impl<'a> Parser<'a> { } else if self.token.is_path_start() { self.parse_path_start_ty(lo, allow_plus)? } else if self.eat(&token::DotDotDot) { - if allow_c_variadic { + if allow_c_variadic == AllowCVariadic::Yes { TyKind::CVarArgs } else { // FIXME(Centril): Should we just allow `...` syntactically @@ -172,7 +192,7 @@ impl<'a> Parser<'a> { /// Parses either: /// - `(TYPE)`, a parenthesized type. /// - `(TYPE,)`, a tuple with a single field of type TYPE. - fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: bool) -> PResult<'a, TyKind> { + fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> { let mut trailing_plus = false; let (ts, trailing) = self.parse_paren_comma_seq(|p| { let ty = p.parse_ty()?; @@ -182,7 +202,7 @@ impl<'a> Parser<'a> { if ts.len() == 1 && !trailing { let ty = ts.into_iter().nth(0).unwrap().into_inner(); - let maybe_bounds = allow_plus && self.token.is_like_plus(); + let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus(); match ty.kind { // `(TY_BOUND_NOPAREN) + BOUND + ...`. TyKind::Path(None, path) if maybe_bounds => { @@ -288,7 +308,8 @@ impl<'a> Parser<'a> { let unsafety = self.parse_unsafety(); let ext = self.parse_extern()?; self.expect_keyword(kw::Fn)?; - let decl = self.parse_fn_decl(&ParamCfg { is_name_required: |_| false }, false)?; + let cfg = ParamCfg { is_name_required: |_| false }; + let decl = self.parse_fn_decl(&cfg, AllowPlus::No)?; Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params, decl }))) } @@ -326,7 +347,7 @@ impl<'a> Parser<'a> { /// 1. a type macro, `mac!(...)`, /// 2. a bare trait object, `B0 + ... + Bn`, /// 3. or a path, `path::to::MyType`. - fn parse_path_start_ty(&mut self, lo: Span, allow_plus: bool) -> PResult<'a, TyKind> { + fn parse_path_start_ty(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> { // Simple path let path = self.parse_path(PathStyle::Type)?; if self.eat(&token::Not) { @@ -336,7 +357,7 @@ impl<'a> Parser<'a> { args: self.parse_mac_args()?, prior_type_ascription: self.last_type_ascription, })) - } else if allow_plus && self.check_plus() { + } else if allow_plus == AllowPlus::Yes && self.check_plus() { // `Trait1 + Trait2 + 'a` self.parse_remaining_bounds(Vec::new(), path, lo, true) } else { @@ -359,7 +380,7 @@ impl<'a> Parser<'a> { &mut self, colon_span: Option, ) -> PResult<'a, GenericBounds> { - self.parse_generic_bounds_common(true, colon_span) + self.parse_generic_bounds_common(AllowPlus::Yes, colon_span) } /// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`. @@ -367,7 +388,7 @@ impl<'a> Parser<'a> { /// See `parse_generic_bound` for the `BOUND` grammar. fn parse_generic_bounds_common( &mut self, - allow_plus: bool, + allow_plus: AllowPlus, colon_span: Option, ) -> PResult<'a, GenericBounds> { let mut bounds = Vec::new(); @@ -377,7 +398,7 @@ impl<'a> Parser<'a> { Ok(bound) => bounds.push(bound), Err(neg_sp) => negative_bounds.push(neg_sp), } - if !allow_plus || !self.eat_plus() { + if allow_plus == AllowPlus::No || !self.eat_plus() { break; } } diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index b6ca2b3a595db..c6c201fa38ec1 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -302,19 +302,18 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { ast_visit::walk_ty(self, t) } - fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, fd: &'v ast::FnDecl, s: Span, _: NodeId) { - self.record("FnDecl", Id::None, fd); - ast_visit::walk_fn(self, fk, fd, s) - } - - fn visit_trait_item(&mut self, ti: &'v ast::AssocItem) { - self.record("TraitItem", Id::None, ti); - ast_visit::walk_trait_item(self, ti) - } - - fn visit_impl_item(&mut self, ii: &'v ast::AssocItem) { - self.record("ImplItem", Id::None, ii); - ast_visit::walk_impl_item(self, ii) + fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, s: Span, _: NodeId) { + self.record("FnDecl", Id::None, fk.decl()); + ast_visit::walk_fn(self, fk, s) + } + + fn visit_assoc_item(&mut self, item: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) { + let label = match ctxt { + ast_visit::AssocCtxt::Trait => "TraitItem", + ast_visit::AssocCtxt::Impl => "ImplItem", + }; + self.record(label, Id::None, item); + ast_visit::walk_assoc_item(self, item, ctxt); } fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound) { diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 7718139f6e924..b355a47c39470 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -822,8 +822,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { return false; } - let mut changed = false; + let mut any_changed = false; self.indices2(ln, succ_ln, |this, idx, succ_idx| { + // This is a special case, pulled out from the code below, where we + // don't have to do anything. It occurs about 60-70% of the time. + if this.rwu_table.packed_rwus[succ_idx] == INV_INV_FALSE { + return; + } + + let mut changed = false; let mut rwu = this.rwu_table.get(idx); let succ_rwu = this.rwu_table.get(succ_idx); if succ_rwu.reader.is_valid() && !rwu.reader.is_valid() { @@ -843,6 +850,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { if changed { this.rwu_table.assign_unpacked(idx, rwu); + any_changed = true; } }); @@ -851,9 +859,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ln, self.ln_str(succ_ln), first_merge, - changed + any_changed ); - return changed; + return any_changed; } // Indicates that a local variable was *defined*; we know that no diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index c77b588d7fbc3..d6ea737385cdd 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -36,7 +36,7 @@ use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, Nod use syntax::ast::{AssocItem, AssocItemKind, MetaItemKind, StmtKind}; use syntax::ast::{Ident, Name}; use syntax::token::{self, Token}; -use syntax::visit::{self, Visitor}; +use syntax::visit::{self, AssocCtxt, Visitor}; use log::debug; use std::cell::Cell; @@ -1234,7 +1234,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { self.parent_scope.legacy = orig_current_legacy_scope; } - fn visit_trait_item(&mut self, item: &'b AssocItem) { + fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) { let parent = self.parent_scope.module; if let AssocItemKind::Macro(_) = item.kind { @@ -1242,6 +1242,12 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { return; } + if let AssocCtxt::Impl = ctxt { + self.resolve_visibility(&item.vis); + visit::walk_assoc_item(self, item, ctxt); + return; + } + // Add the item to the trait info. let item_def_id = self.r.definitions.local_def_id(item.id); let (res, ns) = match item.kind { @@ -1260,16 +1266,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { let expansion = self.parent_scope.expansion; self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion)); - visit::walk_trait_item(self, item); - } - - fn visit_impl_item(&mut self, item: &'b ast::AssocItem) { - if let ast::AssocItemKind::Macro(..) = item.kind { - self.visit_invoc(item.id); - } else { - self.resolve_visibility(&item.vis); - visit::walk_impl_item(self, item); - } + visit::walk_assoc_item(self, item, ctxt); } fn visit_token(&mut self, t: Token) { diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs index 696ba0e994c7d..3a26197c1607a 100644 --- a/src/librustc_resolve/def_collector.rs +++ b/src/librustc_resolve/def_collector.rs @@ -125,7 +125,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { &sig.header, generics, &sig.decl, - Some(body), + body.as_deref(), ); } ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => { @@ -213,39 +213,26 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { visit::walk_generic_param(self, param); } - fn visit_trait_item(&mut self, ti: &'a AssocItem) { - let def_data = match ti.kind { - AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(ti.ident.name), - AssocItemKind::TyAlias(..) => DefPathData::TypeNs(ti.ident.name), - AssocItemKind::Macro(..) => return self.visit_macro_invoc(ti.id), - }; - - let def = self.create_def(ti.id, def_data, ti.span); - self.with_parent(def, |this| visit::walk_trait_item(this, ti)); - } - - fn visit_impl_item(&mut self, ii: &'a AssocItem) { - let def_data = match ii.kind { - AssocItemKind::Fn(FnSig { ref header, ref decl }, ref body) - if header.asyncness.node.is_async() => - { + fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) { + let def_data = match &i.kind { + AssocItemKind::Fn(FnSig { header, decl }, body) if header.asyncness.node.is_async() => { return self.visit_async_fn( - ii.id, - ii.ident.name, - ii.span, + i.id, + i.ident.name, + i.span, header, - &ii.generics, + &i.generics, decl, body.as_deref(), ); } - AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(ii.ident.name), - AssocItemKind::TyAlias(..) => DefPathData::TypeNs(ii.ident.name), - AssocItemKind::Macro(..) => return self.visit_macro_invoc(ii.id), + AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(i.ident.name), + AssocItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name), + AssocItemKind::Macro(..) => return self.visit_macro_invoc(i.id), }; - let def = self.create_def(ii.id, def_data, ii.span); - self.with_parent(def, |this| visit::walk_impl_item(this, ii)); + let def = self.create_def(i.id, def_data, i.span); + self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt)); } fn visit_pat(&mut self, pat: &'a Pat) { diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index a612ad9e783f4..075dca8f01d7b 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -20,6 +20,7 @@ use syntax::ast::{self, Ident, Path}; use syntax::util::lev_distance::find_best_match_for_name; use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; +use crate::lifetimes::{ElisionFailureInfo, LifetimeContext}; use crate::path_names_to_string; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind}; use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot}; @@ -48,6 +49,40 @@ crate struct ImportSuggestion { pub path: Path, } +crate enum MissingLifetimeSpot<'tcx> { + Generics(&'tcx hir::Generics<'tcx>), + HigherRanked { span: Span, span_type: ForLifetimeSpanType }, +} + +crate enum ForLifetimeSpanType { + BoundEmpty, + BoundTail, + TypeEmpty, + TypeTail, +} + +impl ForLifetimeSpanType { + crate fn descr(&self) -> &'static str { + match self { + Self::BoundEmpty | Self::BoundTail => "bound", + Self::TypeEmpty | Self::TypeTail => "type", + } + } + + crate fn suggestion(&self, sugg: &str) -> String { + match self { + Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg), + Self::BoundTail | Self::TypeTail => format!(", {}", sugg), + } + } +} + +impl<'tcx> Into> for &'tcx hir::Generics<'tcx> { + fn into(self) -> MissingLifetimeSpot<'tcx> { + MissingLifetimeSpot::Generics(self) + } +} + /// Adjust the impl span so that just the `impl` keyword is taken by removing /// everything after `<` (`"impl Iterator for A {}" -> "impl"`) and /// everything after the first whitespace (`"impl Iterator for A" -> "impl"`). @@ -1457,72 +1492,206 @@ crate fn show_candidates( } } -crate fn report_missing_lifetime_specifiers( - sess: &Session, - span: Span, - count: usize, -) -> DiagnosticBuilder<'_> { - struct_span_err!(sess, span, E0106, "missing lifetime specifier{}", pluralize!(count)) -} +impl<'tcx> LifetimeContext<'_, 'tcx> { + crate fn report_missing_lifetime_specifiers( + &self, + span: Span, + count: usize, + ) -> DiagnosticBuilder<'tcx> { + struct_span_err!( + self.tcx.sess, + span, + E0106, + "missing lifetime specifier{}", + pluralize!(count) + ) + } -crate fn add_missing_lifetime_specifiers_label( - err: &mut DiagnosticBuilder<'_>, - span: Span, - count: usize, - lifetime_names: &FxHashSet, - snippet: Option<&str>, - missing_named_lifetime_spots: &[&hir::Generics<'_>], -) { - if count > 1 { - err.span_label(span, format!("expected {} lifetime parameters", count)); - } else { - let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| { - err.span_suggestion( - span, - "consider using the named lifetime", - sugg, - Applicability::MaybeIncorrect, - ); - }; - let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg| { - err.span_label(span, "expected named lifetime parameter"); - - if let Some(generics) = missing_named_lifetime_spots.iter().last() { - let mut introduce_suggestion = vec![]; - introduce_suggestion.push(match &generics.params { - [] => (generics.span, "<'lifetime>".to_string()), - [param, ..] => (param.span.shrink_to_lo(), "'lifetime, ".to_string()), - }); - introduce_suggestion.push((span, sugg)); - err.multipart_suggestion( - "consider introducing a named lifetime parameter", - introduce_suggestion, - Applicability::MaybeIncorrect, - ); + crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) { + let mut err = struct_span_err!( + self.tcx.sess, + lifetime_ref.span, + E0261, + "use of undeclared lifetime name `{}`", + lifetime_ref + ); + err.span_label(lifetime_ref.span, "undeclared lifetime"); + for missing in &self.missing_named_lifetime_spots { + match missing { + MissingLifetimeSpot::Generics(generics) => { + let (span, sugg) = if let Some(param) = generics + .params + .iter() + .filter(|p| match p.kind { + hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } => false, + _ => true, + }) + .next() + { + (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)) + } else { + (generics.span, format!("<{}>", lifetime_ref)) + }; + err.span_suggestion( + span, + &format!("consider introducing lifetime `{}` here", lifetime_ref), + sugg, + Applicability::MaybeIncorrect, + ); + } + MissingLifetimeSpot::HigherRanked { span, span_type } => { + err.span_suggestion( + *span, + &format!( + "consider making the {} lifetime-generic with a new `{}` lifetime", + span_type.descr(), + lifetime_ref + ), + span_type.suggestion(&lifetime_ref.to_string()), + Applicability::MaybeIncorrect, + ); + err.note( + "for more information on higher-ranked polymorphism, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + } } - }; + } + err.emit(); + } - match (lifetime_names.len(), lifetime_names.iter().next(), snippet) { - (1, Some(name), Some("&")) => { - suggest_existing(err, format!("&{} ", name)); - } - (1, Some(name), Some("'_")) => { - suggest_existing(err, name.to_string()); - } - (1, Some(name), Some(snippet)) if !snippet.ends_with(">") => { - suggest_existing(err, format!("{}<{}>", snippet, name)); - } - (0, _, Some("&")) => { - suggest_new(err, "&'lifetime ".to_string()); - } - (0, _, Some("'_")) => { - suggest_new(err, "'lifetime".to_string()); - } - (0, _, Some(snippet)) if !snippet.ends_with(">") => { - suggest_new(err, format!("{}<'lifetime>", snippet)); + crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool { + if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res { + if [ + self.tcx.lang_items().fn_once_trait(), + self.tcx.lang_items().fn_trait(), + self.tcx.lang_items().fn_mut_trait(), + ] + .contains(&Some(did)) + { + let (span, span_type) = match &trait_ref.bound_generic_params { + [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty), + [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail), + }; + self.missing_named_lifetime_spots + .push(MissingLifetimeSpot::HigherRanked { span, span_type }); + return true; } - _ => { - err.span_label(span, "expected lifetime parameter"); + }; + false + } + + crate fn add_missing_lifetime_specifiers_label( + &self, + err: &mut DiagnosticBuilder<'_>, + span: Span, + count: usize, + lifetime_names: &FxHashSet, + params: &[ElisionFailureInfo], + ) { + if count > 1 { + err.span_label(span, format!("expected {} lifetime parameters", count)); + } else { + let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok(); + let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| { + err.span_suggestion( + span, + "consider using the named lifetime", + sugg, + Applicability::MaybeIncorrect, + ); + }; + let suggest_new = + |err: &mut DiagnosticBuilder<'_>, sugg: &str| { + err.span_label(span, "expected named lifetime parameter"); + + for missing in self.missing_named_lifetime_spots.iter().rev() { + let mut introduce_suggestion = vec![]; + let msg; + let should_break; + introduce_suggestion.push(match missing { + MissingLifetimeSpot::Generics(generics) => { + msg = "consider introducing a named lifetime parameter".to_string(); + should_break = true; + if let Some(param) = generics.params.iter().filter(|p| match p.kind { + hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } => false, + _ => true, + }).next() { + (param.span.shrink_to_lo(), "'a, ".to_string()) + } else { + (generics.span, "<'a>".to_string()) + } + } + MissingLifetimeSpot::HigherRanked { span, span_type } => { + msg = format!( + "consider making the {} lifetime-generic with a new `'a` lifetime", + span_type.descr(), + ); + should_break = false; + err.note( + "for more information on higher-ranked polymorphism, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + (*span, span_type.suggestion("'a")) + } + }); + for param in params { + if let Ok(snippet) = + self.tcx.sess.source_map().span_to_snippet(param.span) + { + if snippet.starts_with("&") && !snippet.starts_with("&'") { + introduce_suggestion + .push((param.span, format!("&'a {}", &snippet[1..]))); + } else if snippet.starts_with("&'_ ") { + introduce_suggestion + .push((param.span, format!("&'a {}", &snippet[4..]))); + } + } + } + introduce_suggestion.push((span, sugg.to_string())); + err.multipart_suggestion( + &msg, + introduce_suggestion, + Applicability::MaybeIncorrect, + ); + if should_break { + break; + } + } + }; + + match ( + lifetime_names.len(), + lifetime_names.iter().next(), + snippet.as_ref().map(|s| s.as_str()), + ) { + (1, Some(name), Some("&")) => { + suggest_existing(err, format!("&{} ", name)); + } + (1, Some(name), Some("'_")) => { + suggest_existing(err, name.to_string()); + } + (1, Some(name), Some(snippet)) if !snippet.ends_with(">") => { + suggest_existing(err, format!("{}<{}>", snippet, name)); + } + (0, _, Some("&")) => { + suggest_new(err, "&'a "); + } + (0, _, Some("'_")) => { + suggest_new(err, "'a"); + } + (0, _, Some(snippet)) if !snippet.ends_with(">") => { + suggest_new(err, &format!("{}<'a>", snippet)); + } + _ => { + err.span_label(span, "expected lifetime parameter"); + } } } } diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index f1622af130e77..01a0e568137b2 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -24,7 +24,7 @@ use smallvec::{smallvec, SmallVec}; use syntax::ast::*; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; -use syntax::visit::{self, FnKind, Visitor}; +use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use syntax::{unwrap_or, walk_list}; use log::debug; @@ -437,7 +437,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { match foreign_item.kind { - ForeignItemKind::Fn(_, ref generics) => { + ForeignItemKind::Fn(_, ref generics, _) => { self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { visit::walk_foreign_item(this, foreign_item); }); @@ -452,13 +452,15 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } } - fn visit_fn(&mut self, fn_kind: FnKind<'ast>, declaration: &'ast FnDecl, sp: Span, _: NodeId) { - let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some(sp)); - debug!("(resolving function) entering function"); + fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) { let rib_kind = match fn_kind { - FnKind::ItemFn(..) => FnItemRibKind, - FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind, + FnKind::Fn(FnCtxt::Foreign, ..) => return visit::walk_fn(self, fn_kind, sp), + FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind, + FnKind::Fn(FnCtxt::Assoc(_), ..) | FnKind::Closure(..) => NormalRibKind, }; + let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some(sp)); + debug!("(resolving function) entering function"); + let declaration = fn_kind.decl(); // Create a value rib for the function. self.with_rib(ValueNS, rib_kind, |this| { @@ -471,8 +473,8 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // Resolve the function body, potentially inside the body of an async closure match fn_kind { - FnKind::ItemFn(.., body) | FnKind::Method(.., body) => this.visit_block(body), - FnKind::Closure(body) => this.visit_expr(body), + FnKind::Fn(.., body) => walk_list!(this, visit_block, body), + FnKind::Closure(_, body) => this.visit_expr(body), }; debug!("(resolving function) leaving function"); @@ -843,12 +845,16 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }); } } - AssocItemKind::Fn(_, _) => { - visit::walk_trait_item(this, trait_item) - } - AssocItemKind::TyAlias(..) => { - visit::walk_trait_item(this, trait_item) - } + AssocItemKind::Fn(_, _) => visit::walk_assoc_item( + this, + trait_item, + AssocCtxt::Trait, + ), + AssocItemKind::TyAlias(..) => visit::walk_assoc_item( + this, + trait_item, + AssocCtxt::Trait, + ), AssocItemKind::Macro(_) => { panic!("unexpanded macro in resolve!") } @@ -1128,7 +1134,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); this.with_constant_rib(|this| { - visit::walk_impl_item(this, impl_item) + visit::walk_assoc_item( + this, + impl_item, + AssocCtxt::Impl, + ) }); } AssocItemKind::Fn(..) => { @@ -1139,7 +1149,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { impl_item.span, |n, s| MethodNotMemberOfTrait(n, s)); - visit::walk_impl_item(this, impl_item); + visit::walk_assoc_item( + this, + impl_item, + AssocCtxt::Impl, + ) } AssocItemKind::TyAlias(_, _) => { // If this is a trait impl, ensure the type @@ -1149,7 +1163,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { impl_item.span, |n, s| TypeNotMemberOfTrait(n, s)); - visit::walk_impl_item(this, impl_item); + visit::walk_assoc_item( + this, + impl_item, + AssocCtxt::Impl, + ) } AssocItemKind::Macro(_) => panic!("unexpanded macro in resolve!"), diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 6e9ed5fdc179c..0ba9b4f17068e 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -5,9 +5,7 @@ //! used between functions, and they operate in a purely top-down //! way. Therefore, we break lifetime name resolution into a separate pass. -use crate::diagnostics::{ - add_missing_lifetime_specifiers_label, report_missing_lifetime_specifiers, -}; +use crate::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; use rustc::hir::map::Map; use rustc::lint; use rustc::middle::resolve_lifetime::*; @@ -153,8 +151,8 @@ struct NamedRegionMap { object_lifetime_defaults: HirIdMap>, } -struct LifetimeContext<'a, 'tcx> { - tcx: TyCtxt<'tcx>, +crate struct LifetimeContext<'a, 'tcx> { + crate tcx: TyCtxt<'tcx>, map: &'a mut NamedRegionMap, scope: ScopeRef<'a>, @@ -186,7 +184,7 @@ struct LifetimeContext<'a, 'tcx> { /// When encountering an undefined named lifetime, we will suggest introducing it in these /// places. - missing_named_lifetime_spots: Vec<&'tcx hir::Generics<'tcx>>, + crate missing_named_lifetime_spots: Vec>, } #[derive(Debug)] @@ -264,13 +262,14 @@ enum Elide { } #[derive(Clone, Debug)] -struct ElisionFailureInfo { +crate struct ElisionFailureInfo { /// Where we can find the argument pattern. parent: Option, /// The index of the argument in the original definition. index: usize, lifetime_count: usize, have_bound_regions: bool, + crate span: Span, } type ScopeRef<'a> = &'a Scope<'a>; @@ -389,7 +388,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { match item.kind { hir::ItemKind::Fn(ref sig, ref generics, _) => { - self.missing_named_lifetime_spots.push(generics); + self.missing_named_lifetime_spots.push(generics.into()); self.visit_early_late(None, &sig.decl, generics, |this| { intravisit::walk_item(this, item); }); @@ -424,7 +423,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { | hir::ItemKind::Trait(_, _, ref generics, ..) | hir::ItemKind::TraitAlias(ref generics, ..) | hir::ItemKind::Impl { ref generics, .. } => { - self.missing_named_lifetime_spots.push(generics); + self.missing_named_lifetime_spots.push(generics.into()); // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name". // This is not true for other kinds of items.x @@ -492,6 +491,21 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let next_early_index = self.next_early_index(); let was_in_fn_syntax = self.is_in_fn_syntax; self.is_in_fn_syntax = true; + let lifetime_span: Option = c + .generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(param.span), + _ => None, + }) + .last(); + let (span, span_type) = if let Some(span) = lifetime_span { + (span.shrink_to_hi(), ForLifetimeSpanType::TypeTail) + } else { + (ty.span.shrink_to_lo(), ForLifetimeSpanType::TypeEmpty) + }; + self.missing_named_lifetime_spots + .push(MissingLifetimeSpot::HigherRanked { span, span_type }); let scope = Scope::Binder { lifetimes: c .generic_params @@ -514,6 +528,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.check_lifetime_params(old_scope, &c.generic_params); intravisit::walk_ty(this, ty); }); + self.missing_named_lifetime_spots.pop(); self.is_in_fn_syntax = was_in_fn_syntax; } hir::TyKind::TraitObject(bounds, ref lifetime) => { @@ -696,7 +711,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { use self::hir::TraitItemKind::*; - self.missing_named_lifetime_spots.push(&trait_item.generics); + self.missing_named_lifetime_spots.push((&trait_item.generics).into()); match trait_item.kind { Method(ref sig, _) => { let tcx = self.tcx; @@ -753,7 +768,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { use self::hir::ImplItemKind::*; - self.missing_named_lifetime_spots.push(&impl_item.generics); + self.missing_named_lifetime_spots.push((&impl_item.generics).into()); match impl_item.kind { Method(ref sig, _) => { let tcx = self.tcx; @@ -953,6 +968,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ) { debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); + let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref); if !self.trait_ref_hack || trait_ref.bound_generic_params.iter().any(|param| match param.kind { GenericParamKind::Lifetime { .. } => true, @@ -988,10 +1004,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); - this.visit_trait_ref(&trait_ref.trait_ref) + this.visit_trait_ref(&trait_ref.trait_ref); }) } else { - self.visit_trait_ref(&trait_ref.trait_ref) + self.visit_trait_ref(&trait_ref.trait_ref); + } + if should_pop_missing_lt { + self.missing_named_lifetime_spots.pop(); } } } @@ -1824,29 +1843,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.insert_lifetime(lifetime_ref, def); } else { - let mut err = struct_span_err!( - self.tcx.sess, - lifetime_ref.span, - E0261, - "use of undeclared lifetime name `{}`", - lifetime_ref - ); - err.span_label(lifetime_ref.span, "undeclared lifetime"); - if !self.is_in_fn_syntax { - for generics in &self.missing_named_lifetime_spots { - let (span, sugg) = match &generics.params { - [] => (generics.span, format!("<{}>", lifetime_ref)), - [param, ..] => (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)), - }; - err.span_suggestion( - span, - &format!("consider introducing lifetime `{}` here", lifetime_ref), - sugg, - Applicability::MaybeIncorrect, - ); - } - } - err.emit(); + self.emit_undeclared_lifetime_error(lifetime_ref); } } @@ -2230,6 +2227,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { index: i, lifetime_count: gather.lifetimes.len(), have_bound_regions: gather.have_bound_regions, + span: input.span, } }) .collect(); @@ -2385,7 +2383,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } }; - let mut err = report_missing_lifetime_specifiers(self.tcx.sess, span, lifetime_refs.len()); + let mut err = self.report_missing_lifetime_specifiers(span, lifetime_refs.len()); let mut add_label = true; if let Some(params) = error { @@ -2394,13 +2392,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } if add_label { - add_missing_lifetime_specifiers_label( + self.add_missing_lifetime_specifiers_label( &mut err, span, lifetime_refs.len(), &lifetime_names, - self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()), - &self.missing_named_lifetime_spots, + error.map(|p| &p[..]).unwrap_or(&[]), ); } @@ -2442,8 +2439,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let elided_len = elided_params.len(); for (i, info) in elided_params.into_iter().enumerate() { - let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions } = info; + let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = + info; + db.span_label(span, ""); let help_name = if let Some(ident) = parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) { @@ -2477,7 +2476,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { if len == 0 { db.help( "this function's return type contains a borrowed value, \ - but there is no value for it to be borrowed from", + but there is no value for it to be borrowed from", ); self.suggest_lifetime(db, span, "consider giving it a 'static lifetime") } else if elided_len == 0 { @@ -2491,14 +2490,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } else if elided_len == 1 { db.help(&format!( "this function's return type contains a borrowed value, \ - but the signature does not say which {} it is borrowed from", + but the signature does not say which {} it is borrowed from", m )); true } else { db.help(&format!( "this function's return type contains a borrowed value, \ - but the signature does not say whether it is borrowed from {}", + but the signature does not say whether it is borrowed from {}", m )); true diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3f436a1e27c2c..5ce81c104e17c 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -358,7 +358,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { decl: &'l ast::FnDecl, header: &'l ast::FnHeader, ty_params: &'l ast::Generics, - body: &'l ast::Block, + body: Option<&'l ast::Block>, ) { let hir_id = self.tcx.hir().node_to_hir_id(item.id); self.nest_tables(item.id, |v| { @@ -392,7 +392,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } } - v.visit_block(&body); + walk_list!(v, visit_block, body); }); } @@ -1291,7 +1291,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { } } Fn(ref sig, ref ty_params, ref body) => { - self.process_fn(item, &sig.decl, &sig.header, ty_params, &body) + self.process_fn(item, &sig.decl, &sig.header, ty_params, body.as_deref()) } Static(ref typ, _, ref expr) => self.process_static_or_const_item(item, typ, expr), Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr), @@ -1515,7 +1515,8 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { let access = access_from!(self.save_ctxt, item, hir_id); match item.kind { - ast::ForeignItemKind::Fn(ref decl, ref generics) => { + ast::ForeignItemKind::Fn(ref sig, ref generics, _) => { + let decl = &sig.decl; if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) { down_cast_data!(fn_data, DefData, item.span); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 89054441fa3bf..e32f47443667b 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -133,7 +133,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(item.id)) ); match item.kind { - ast::ForeignItemKind::Fn(ref decl, ref generics) => { + ast::ForeignItemKind::Fn(ref sig, ref generics, _) => { filter!(self.span_utils, item.ident.span); Some(Data::DefData(Def { @@ -142,7 +142,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { span: self.span_from_span(item.ident.span), name: item.ident.to_string(), qualname, - value: make_signature(decl, generics), + value: make_signature(&sig.decl, generics), parent: None, children: vec![], decl_id: None, diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index dbf29b6531d2a..6401cabdcd5c1 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -723,7 +723,8 @@ impl Sig for ast::ForeignItem { fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext<'_, '_>) -> Result { let id = Some(self.id); match self.kind { - ast::ForeignItemKind::Fn(ref decl, ref generics) => { + ast::ForeignItemKind::Fn(ref sig, ref generics, _) => { + let decl = &sig.decl; let mut text = String::new(); text.push_str("fn "); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 231aed48fb6be..6bd120d818d09 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1307,12 +1307,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); } }; + // FIXME: point at the type params that don't have appropriate lifetimes: + // struct S1 Fn(&i32, &i32) -> &'a i32>(F); + // ---- ---- ^^^^^^^ struct_span_err!( tcx.sess, binding.span, E0582, "binding for associated type `{}` references lifetime `{}`, \ - which does not appear in the trait input types", + which does not appear in the trait input types", binding.item_name, br_name ) diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index e4dec97183c7d..d436733d19a36 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -250,8 +250,8 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa ) .span_label(span, "deref recursion limit reached") .help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + suggested_limit, tcx.crate_name, )) .emit(); } diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index 2310441997872..6707f790cab0a 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -282,7 +282,6 @@ mod inner { (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) || (cfg!(target_os = "linux") && cfg!(target_arch = "x86")) || cfg!(target_os = "fuchsia") - || false // last clause, used so `||` is always trailing above } pub fn checked_sub_instant(&self, other: &Instant) -> Option { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 5a8c9f76ea943..b22406124e098 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2533,6 +2533,17 @@ pub struct FnHeader { pub ext: Extern, } +impl FnHeader { + /// Does this function header have any qualifiers or is it empty? + pub fn has_qualifiers(&self) -> bool { + let Self { unsafety, asyncness, constness, ext } = self; + matches!(unsafety, Unsafety::Unsafe) + || asyncness.node.is_async() + || matches!(constness.node, Constness::Const) + || !matches!(ext, Extern::None) + } +} + impl Default for FnHeader { fn default() -> FnHeader { FnHeader { @@ -2565,7 +2576,7 @@ pub enum ItemKind { /// A function declaration (`fn`). /// /// E.g., `fn foo(bar: usize) -> usize { .. }`. - Fn(FnSig, Generics, P), + Fn(FnSig, Generics, Option>), /// A module declaration (`mod`). /// /// E.g., `mod foo;` or `mod foo { .. }`. @@ -2667,7 +2678,7 @@ pub type ForeignItem = Item; #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum ForeignItemKind { /// A foreign function. - Fn(P, Generics), + Fn(FnSig, Generics, Option>), /// A foreign static item (`static ext: u8`). Static(P, Mutability), /// A foreign type. diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 3bcdf8fe286e4..8517f223f92e3 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -901,7 +901,7 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { ItemKind::Fn(sig, generics, body) => { visit_fn_sig(sig, vis); vis.visit_generics(generics); - vis.visit_block(body); + visit_opt(body, |body| vis.visit_block(body)); } ItemKind::Mod(m) => vis.visit_mod(m), ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), @@ -1044,9 +1044,10 @@ pub fn noop_flat_map_foreign_item( visitor.visit_ident(ident); visit_attrs(attrs, visitor); match kind { - ForeignItemKind::Fn(fdec, generics) => { - visitor.visit_fn_decl(fdec); + ForeignItemKind::Fn(sig, generics, body) => { + visit_fn_sig(sig, visitor); visitor.visit_generics(generics); + visit_opt(body, |body| visitor.visit_block(body)); } ForeignItemKind::Static(t, _m) => visitor.visit_ty(t), ForeignItemKind::Ty => {} diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 946a0d29cd399..73e731397c329 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -19,24 +19,47 @@ use crate::tokenstream::{TokenStream, TokenTree}; use rustc_span::Span; +#[derive(Copy, Clone, PartialEq)] +pub enum AssocCtxt { + Trait, + Impl, +} + +#[derive(Copy, Clone, PartialEq)] +pub enum FnCtxt { + Free, + Foreign, + Assoc(AssocCtxt), +} + #[derive(Copy, Clone)] pub enum FnKind<'a> { - /// E.g., `fn foo()` or `extern "Abi" fn foo()`. - ItemFn(Ident, &'a FnHeader, &'a Visibility, &'a Block), - - /// E.g., `fn foo(&self)`. - Method(Ident, &'a FnSig, &'a Visibility, &'a Block), + /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. + Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>), /// E.g., `|x, y| body`. - Closure(&'a Expr), + Closure(&'a FnDecl, &'a Expr), } impl<'a> FnKind<'a> { pub fn header(&self) -> Option<&'a FnHeader> { match *self { - FnKind::ItemFn(_, header, _, _) => Some(header), - FnKind::Method(_, sig, _, _) => Some(&sig.header), - FnKind::Closure(_) => None, + FnKind::Fn(_, _, sig, _, _) => Some(&sig.header), + FnKind::Closure(_, _) => None, + } + } + + pub fn decl(&self) -> &'a FnDecl { + match self { + FnKind::Fn(_, _, sig, _, _) => &sig.decl, + FnKind::Closure(decl, _) => decl, + } + } + + pub fn ctxt(&self) -> Option { + match self { + FnKind::Fn(ctxt, ..) => Some(*ctxt), + FnKind::Closure(..) => None, } } } @@ -106,17 +129,11 @@ pub trait Visitor<'ast>: Sized { fn visit_where_predicate(&mut self, p: &'ast WherePredicate) { walk_where_predicate(self, p) } - fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl, s: Span, _: NodeId) { - walk_fn(self, fk, fd, s) - } - fn visit_trait_item(&mut self, i: &'ast AssocItem) { - walk_trait_item(self, i) + fn visit_fn(&mut self, fk: FnKind<'ast>, s: Span, _: NodeId) { + walk_fn(self, fk, s) } - fn visit_impl_item(&mut self, i: &'ast AssocItem) { - walk_impl_item(self, i) - } - fn visit_assoc_item(&mut self, i: &'ast AssocItem) { - walk_assoc_item(self, i) + fn visit_assoc_item(&mut self, i: &'ast AssocItem, ctxt: AssocCtxt) { + walk_assoc_item(self, i, ctxt) } fn visit_trait_ref(&mut self, t: &'ast TraitRef) { walk_trait_ref(self, t) @@ -287,13 +304,8 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { } ItemKind::Fn(ref sig, ref generics, ref body) => { visitor.visit_generics(generics); - visitor.visit_fn_header(&sig.header); - visitor.visit_fn( - FnKind::ItemFn(item.ident, &sig.header, &item.vis, body), - &sig.decl, - item.span, - item.id, - ) + let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref()); + visitor.visit_fn(kind, item.span, item.id) } ItemKind::Mod(ref module) => visitor.visit_mod(module, item.span, &item.attrs, item.id), ItemKind::ForeignMod(ref foreign_module) => { @@ -321,17 +333,17 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { visitor.visit_generics(generics); walk_list!(visitor, visit_trait_ref, of_trait); visitor.visit_ty(self_ty); - walk_list!(visitor, visit_impl_item, items); + walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Impl); } ItemKind::Struct(ref struct_definition, ref generics) | ItemKind::Union(ref struct_definition, ref generics) => { visitor.visit_generics(generics); visitor.visit_variant_data(struct_definition); } - ItemKind::Trait(.., ref generics, ref bounds, ref methods) => { + ItemKind::Trait(.., ref generics, ref bounds, ref items) => { visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds); - walk_list!(visitor, visit_trait_item, methods); + walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait); } ItemKind::TraitAlias(ref generics, ref bounds) => { visitor.visit_generics(generics); @@ -512,21 +524,22 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { } } -pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a ForeignItem) { - visitor.visit_vis(&foreign_item.vis); - visitor.visit_ident(foreign_item.ident); +pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignItem) { + visitor.visit_vis(&item.vis); + visitor.visit_ident(item.ident); - match foreign_item.kind { - ForeignItemKind::Fn(ref function_declaration, ref generics) => { - walk_fn_decl(visitor, function_declaration); - visitor.visit_generics(generics) + match item.kind { + ForeignItemKind::Fn(ref sig, ref generics, ref body) => { + visitor.visit_generics(generics); + let kind = FnKind::Fn(FnCtxt::Foreign, item.ident, sig, &item.vis, body.as_deref()); + visitor.visit_fn(kind, item.span, item.id); } ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ), ForeignItemKind::Ty => (), ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac), } - walk_list!(visitor, visit_attribute, &foreign_item.attrs); + walk_list!(visitor, visit_attribute, &item.attrs); } pub fn walk_global_asm<'a, V: Visitor<'a>>(_: &mut V, _: &'a GlobalAsm) { @@ -594,37 +607,21 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: & visitor.visit_fn_ret_ty(&function_declaration.output); } -pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl, _span: Span) -where - V: Visitor<'a>, -{ +pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Span) { match kind { - FnKind::ItemFn(_, header, _, body) => { - visitor.visit_fn_header(header); - walk_fn_decl(visitor, declaration); - visitor.visit_block(body); - } - FnKind::Method(_, sig, _, body) => { + FnKind::Fn(_, _, sig, _, body) => { visitor.visit_fn_header(&sig.header); - walk_fn_decl(visitor, declaration); - visitor.visit_block(body); + walk_fn_decl(visitor, &sig.decl); + walk_list!(visitor, visit_block, body); } - FnKind::Closure(body) => { - walk_fn_decl(visitor, declaration); + FnKind::Closure(decl, body) => { + walk_fn_decl(visitor, decl); visitor.visit_expr(body); } } } -pub fn walk_impl_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) { - visitor.visit_assoc_item(item); -} - -pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) { - visitor.visit_assoc_item(item); -} - -pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) { +pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, ctxt: AssocCtxt) { visitor.visit_vis(&item.vis); visitor.visit_ident(item.ident); walk_list!(visitor, visit_attribute, &item.attrs); @@ -634,17 +631,9 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) visitor.visit_ty(ty); walk_list!(visitor, visit_expr, expr); } - AssocItemKind::Fn(ref sig, None) => { - visitor.visit_fn_header(&sig.header); - walk_fn_decl(visitor, &sig.decl); - } - AssocItemKind::Fn(ref sig, Some(ref body)) => { - visitor.visit_fn( - FnKind::Method(item.ident, sig, &item.vis, body), - &sig.decl, - item.span, - item.id, - ); + AssocItemKind::Fn(ref sig, ref body) => { + let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref()); + visitor.visit_fn(kind, item.span, item.id); } AssocItemKind::TyAlias(ref bounds, ref ty) => { walk_list!(visitor, visit_param_bound, bounds); @@ -765,8 +754,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(subexpression); walk_list!(visitor, visit_arm, arms); } - ExprKind::Closure(_, _, _, ref function_declaration, ref body, _decl_span) => visitor - .visit_fn(FnKind::Closure(body), function_declaration, expression.span, expression.id), + ExprKind::Closure(_, _, _, ref decl, ref body, _decl_span) => { + visitor.visit_fn(FnKind::Closure(decl, body), expression.span, expression.id) + } ExprKind::Block(ref block, ref opt_label) => { walk_list!(visitor, visit_label, opt_label); visitor.visit_block(block); diff --git a/src/test/ui/async-await/issues/issue-63388-2.stderr b/src/test/ui/async-await/issues/issue-63388-2.stderr index 7e45d588c6c6c..9f51ced9c3f49 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.stderr +++ b/src/test/ui/async-await/issues/issue-63388-2.stderr @@ -1,6 +1,8 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-63388-2.rs:12:10 | +LL | foo: &dyn Foo, bar: &'a dyn Foo + | -------- ----------- LL | ) -> &dyn Foo | ^ help: consider using the named lifetime: `&'a` | diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index b05b92bf1e94b..fc14b7fa5b75c 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -7,7 +7,7 @@ LL | fn is_send() { } LL | is_send::(); | ^^^^^^^^^^^^ | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate + = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit`) = note: required because it appears within the type `I` = note: required because it appears within the type `H` = note: required because it appears within the type `G` diff --git a/src/test/ui/did_you_mean/recursion_limit_deref.stderr b/src/test/ui/did_you_mean/recursion_limit_deref.stderr index fdbb5af9b3243..e8d11530b08aa 100644 --- a/src/test/ui/did_you_mean/recursion_limit_deref.stderr +++ b/src/test/ui/did_you_mean/recursion_limit_deref.stderr @@ -4,7 +4,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `I` LL | let x: &Bottom = &t; | ^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate + = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit_deref`) error[E0308]: mismatched types --> $DIR/recursion_limit_deref.rs:50:22 diff --git a/src/test/ui/did_you_mean/recursion_limit_macro.stderr b/src/test/ui/did_you_mean/recursion_limit_macro.stderr index 1cc59051605cd..18d321c24d80c 100644 --- a/src/test/ui/did_you_mean/recursion_limit_macro.stderr +++ b/src/test/ui/did_you_mean/recursion_limit_macro.stderr @@ -7,7 +7,7 @@ LL | ($t:tt $($tail:tt)*) => { recurse!($($tail)*) }; LL | recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9); | -------------------------------------------------- in this macro invocation | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate + = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit_macro`) error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0055.stderr b/src/test/ui/error-codes/E0055.stderr index d06566ffbe9a9..01411e585abdd 100644 --- a/src/test/ui/error-codes/E0055.stderr +++ b/src/test/ui/error-codes/E0055.stderr @@ -4,7 +4,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | ref_foo.foo(); | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="10"]` attribute to your crate + = help: consider adding a `#![recursion_limit="10"]` attribute to your crate (`E0055`) error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr index e01e0a6f54b07..a23bcbfd71a56 100644 --- a/src/test/ui/error-codes/E0106.stderr +++ b/src/test/ui/error-codes/E0106.stderr @@ -6,8 +6,8 @@ LL | x: &bool, | help: consider introducing a named lifetime parameter | -LL | struct Foo<'lifetime> { -LL | x: &'lifetime bool, +LL | struct Foo<'a> { +LL | x: &'a bool, | error[E0106]: missing lifetime specifier @@ -18,9 +18,9 @@ LL | B(&bool), | help: consider introducing a named lifetime parameter | -LL | enum Bar<'lifetime> { +LL | enum Bar<'a> { LL | A(u8), -LL | B(&'lifetime bool), +LL | B(&'a bool), | error[E0106]: missing lifetime specifier @@ -31,8 +31,8 @@ LL | type MyStr = &str; | help: consider introducing a named lifetime parameter | -LL | type MyStr<'lifetime> = &'lifetime str; - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | type MyStr<'a> = &'a str; + | ^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:17:10 @@ -42,8 +42,8 @@ LL | baz: Baz, | help: consider introducing a named lifetime parameter | -LL | struct Quux<'lifetime> { -LL | baz: Baz<'lifetime>, +LL | struct Quux<'a> { +LL | baz: Baz<'a>, | error[E0106]: missing lifetime specifiers diff --git a/src/test/ui/error-codes/E0275.stderr b/src/test/ui/error-codes/E0275.stderr index 1d087a465942e..c551a00096e23 100644 --- a/src/test/ui/error-codes/E0275.stderr +++ b/src/test/ui/error-codes/E0275.stderr @@ -7,7 +7,7 @@ LL | trait Foo {} LL | impl Foo for T where Bar: Foo {} | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`E0275`) = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` diff --git a/src/test/ui/extern/extern-ffi-fn-with-body.rs b/src/test/ui/extern/extern-ffi-fn-with-body.rs index 4cf563514ea60..ef234e8afd8ca 100644 --- a/src/test/ui/extern/extern-ffi-fn-with-body.rs +++ b/src/test/ui/extern/extern-ffi-fn-with-body.rs @@ -1,5 +1,5 @@ extern "C" { - fn foo() -> i32 { //~ ERROR incorrect `fn` inside `extern` block + fn foo() -> i32 { //~ ERROR incorrect function inside `extern` block return 0; } } diff --git a/src/test/ui/extern/extern-ffi-fn-with-body.stderr b/src/test/ui/extern/extern-ffi-fn-with-body.stderr index 4ac3ce1f93eab..079c9cecd8ed4 100644 --- a/src/test/ui/extern/extern-ffi-fn-with-body.stderr +++ b/src/test/ui/extern/extern-ffi-fn-with-body.stderr @@ -1,17 +1,17 @@ -error: incorrect `fn` inside `extern` block +error: incorrect function inside `extern` block --> $DIR/extern-ffi-fn-with-body.rs:2:8 | LL | extern "C" { - | ------ `extern` blocks define existing foreign functions and `fn`s inside of them cannot have a body + | ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body LL | fn foo() -> i32 { | ________^^^__________- | | | - | | can't have a body + | | cannot have a body LL | | return 0; LL | | } - | |_____- this body is invalid here + | |_____- help: remove the invalid body: `;` | - = help: you might have meant to write a function accessible through ffi, which can be done by writing `extern fn` outside of the `extern` block + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html error: aborting due to previous error diff --git a/src/test/ui/generic/generic-extern-lifetime.stderr b/src/test/ui/generic/generic-extern-lifetime.stderr index 39372c9315831..72951aea4aaf0 100644 --- a/src/test/ui/generic/generic-extern-lifetime.stderr +++ b/src/test/ui/generic/generic-extern-lifetime.stderr @@ -9,12 +9,24 @@ error[E0261]: use of undeclared lifetime name `'a` | LL | pub fn life4<'b>(x: for<'c> fn(&'a i32)); | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | pub fn life4<'b>(x: for<'c, 'a> fn(&'a i32)); + | ^^^^ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/generic-extern-lifetime.rs:11:38 | LL | pub fn life7<'b>() -> for<'c> fn(&'a i32); | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | pub fn life7<'b>() -> for<'c, 'a> fn(&'a i32); + | ^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr index 14c53f906654b..211a3286cc355 100644 --- a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr +++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr @@ -6,8 +6,8 @@ LL | type Output = &i32; | help: consider introducing a named lifetime parameter | -LL | type Output<'lifetime> = &'lifetime i32; - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | type Output<'a> = &'a i32; + | ^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/assoc-type.rs:16:20 @@ -17,8 +17,8 @@ LL | type Output = &'_ i32; | help: consider introducing a named lifetime parameter | -LL | type Output<'lifetime> = &'lifetime i32; - | ^^^^^^^^^^^ ^^^^^^^^^ +LL | type Output<'a> = &'a i32; + | ^^^^ ^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr index 5f101a24c1d43..f2a4150632d2f 100644 --- a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr +++ b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr @@ -6,8 +6,8 @@ LL | struct Heartbreak(Betrayal); | help: consider introducing a named lifetime parameter | -LL | struct Heartbreak<'lifetime>(Betrayal<'lifetime>); - | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ +LL | struct Heartbreak<'a>(Betrayal<'a>); + | ^^^^ ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr index bfb20ade035cf..a43b49041ec2a 100644 --- a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr +++ b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr @@ -11,6 +11,16 @@ error[E0261]: use of undeclared lifetime name `'test` | LL | let y: fn(&'test u32) = foo2; | ^^^^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing lifetime `'test` here + | +LL | fn bar<'test>() { + | ^^^^^^^ +help: consider making the type lifetime-generic with a new `'test` lifetime + | +LL | let y: for<'test> fn(&'test u32) = foo2; + | ^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/infinite/infinite-autoderef.stderr b/src/test/ui/infinite/infinite-autoderef.stderr index 8c59fbd530129..e7d90f00d24de 100644 --- a/src/test/ui/infinite/infinite-autoderef.stderr +++ b/src/test/ui/infinite/infinite-autoderef.stderr @@ -13,7 +13,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | Foo.foo; | ^^^^^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_autoderef`) error[E0055]: reached the recursion limit while auto-dereferencing `Foo` --> $DIR/infinite-autoderef.rs:25:9 @@ -21,7 +21,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | Foo.foo; | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_autoderef`) error[E0609]: no field `foo` on type `Foo` --> $DIR/infinite-autoderef.rs:25:9 @@ -35,7 +35,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | Foo.bar(); | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_autoderef`) error[E0599]: no method named `bar` found for struct `Foo` in the current scope --> $DIR/infinite-autoderef.rs:26:9 diff --git a/src/test/ui/infinite/infinite-macro-expansion.stderr b/src/test/ui/infinite/infinite-macro-expansion.stderr index 159312e5c1b53..ff67eea568866 100644 --- a/src/test/ui/infinite/infinite-macro-expansion.stderr +++ b/src/test/ui/infinite/infinite-macro-expansion.stderr @@ -7,7 +7,7 @@ LL | () => (recursive!()) LL | recursive!() | ------------ in this macro invocation | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_macro_expansion`) error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16098.stderr b/src/test/ui/issues/issue-16098.stderr index 2b9657d46283b..a34039a6eec7d 100644 --- a/src/test/ui/issues/issue-16098.stderr +++ b/src/test/ui/issues/issue-16098.stderr @@ -7,7 +7,7 @@ LL | $n + prob1!($n - 1); LL | println!("Problem 1: {}", prob1!(1000)); | ------------ in this macro invocation | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_16098`) error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18400.stderr b/src/test/ui/issues/issue-18400.stderr index 85cfa5663f13c..57067ad51759a 100644 --- a/src/test/ui/issues/issue-18400.stderr +++ b/src/test/ui/issues/issue-18400.stderr @@ -4,7 +4,7 @@ error[E0275]: overflow evaluating the requirement `_: std::marker::Sized` LL | 0.contains(bits); | ^^^^^^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_18400`) = note: required because of the requirements on the impl of `Set<&[_]>` for `{integer}` = note: required because of the requirements on the impl of `Set<&[&[_]]>` for `{integer}` = note: required because of the requirements on the impl of `Set<&[&[&[_]]]>` for `{integer}` diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index 8a627bc0bd4de..337f2f971ede0 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -2,25 +2,35 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:3:28 | LL | type Foo = fn(&u8, &u8) -> &u8; - | ^ expected named lifetime parameter + | --- --- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | type Foo = for<'a> fn(&'a u8, &'a u8) -> &'a u8; + | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ help: consider introducing a named lifetime parameter | -LL | type Foo<'lifetime> = fn(&u8, &u8) -> &'lifetime u8; - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | type Foo<'a> = fn(&'a u8, &'a u8) -> &'a u8; + | ^^^^ ^^^^^^ ^^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:5:27 | LL | fn bar &u8>(f: &F) {} - | ^ expected named lifetime parameter + | --- --- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | fn bar Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {} + | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ help: consider introducing a named lifetime parameter | -LL | fn bar<'lifetime, F: Fn(&u8, &u8) -> &'lifetime u8>(f: &F) {} - | ^^^^^^^^^^ ^^^^^^^^^^ +LL | fn bar<'a, F: Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {} + | ^^^ ^^^^^^ ^^^^^^ ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr index e765144ff0b48..84e64ff74ae96 100644 --- a/src/test/ui/issues/issue-20413.stderr +++ b/src/test/ui/issues/issue-20413.stderr @@ -15,7 +15,7 @@ LL | trait Foo { LL | impl Foo for T where NoData: Foo { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` @@ -153,7 +153,7 @@ LL | trait Foo { LL | impl Foo for T where NoData: Foo { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr index d2c1421e29e0e..7625e30498ac3 100644 --- a/src/test/ui/issues/issue-23122-2.stderr +++ b/src/test/ui/issues/issue-23122-2.stderr @@ -4,7 +4,7 @@ error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<< LL | impl Next for GetNext { | ^^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` @@ -13,7 +13,7 @@ error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<< LL | type Next = as Next>::Next; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-26638.stderr b/src/test/ui/issues/issue-26638.stderr index 85d5d9cc42e9a..1d8fbdc63c5e0 100644 --- a/src/test/ui/issues/issue-26638.stderr +++ b/src/test/ui/issues/issue-26638.stderr @@ -2,13 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-26638.rs:1:62 | LL | fn parse_type(iter: Box+'static>) -> &str { iter.next() } - | ^ expected named lifetime parameter + | ------------------------------------ ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn parse_type<'lifetime>(iter: Box+'static>) -> &'lifetime str { iter.next() } - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn parse_type<'a>(iter: Box+'static>) -> &'a str { iter.next() } + | ^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-26638.rs:4:40 diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr index c940227764099..ab43d4a3c6002 100644 --- a/src/test/ui/issues/issue-30255.stderr +++ b/src/test/ui/issues/issue-30255.stderr @@ -2,37 +2,37 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:9:24 | LL | fn f(a: &S, b: i32) -> &i32 { - | ^ expected named lifetime parameter + | -- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `a`'s 2 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn f<'lifetime>(a: &S, b: i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn f<'a>(a: &'a S, b: i32) -> &'a i32 { + | ^^^^ ^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:14:34 | LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { - | ^ expected named lifetime parameter + | -- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `a`'s 2 lifetimes or `c` help: consider introducing a named lifetime parameter | -LL | fn g<'lifetime>(a: &S, b: bool, c: &i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn g<'a>(a: &'a S, b: bool, c: &'a i32) -> &'a i32 { + | ^^^^ ^^^^^ ^^^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:19:44 | LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { - | ^ expected named lifetime parameter + | ----- -- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a`, one of `c`'s 2 lifetimes, or `d` help: consider introducing a named lifetime parameter | -LL | fn h<'lifetime>(a: &bool, b: bool, c: &S, d: &i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S, d: &'a i32) -> &'a i32 { + | ^^^^ ^^^^^^^^ ^^^^^ ^^^^^^^ ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-38940.stderr b/src/test/ui/issues/issue-38940.stderr index f60387f841aed..36117278fd814 100644 --- a/src/test/ui/issues/issue-38940.stderr +++ b/src/test/ui/issues/issue-38940.stderr @@ -4,7 +4,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `I` LL | let x: &Bottom = &t; | ^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate + = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`issue_38940`) error[E0308]: mismatched types --> $DIR/issue-38940.rs:43:22 diff --git a/src/test/ui/issues/issue-39616.rs b/src/test/ui/issues/issue-39616.rs index 3d8e28e5c2f52..428856a36b425 100644 --- a/src/test/ui/issues/issue-39616.rs +++ b/src/test/ui/issues/issue-39616.rs @@ -1,5 +1,4 @@ fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0` -//~| ERROR expected one of `)`, `,`, `->`, `where`, or `{`, found `]` -// FIXME(jseyfried): avoid emitting the second error (preexisting) +//~| ERROR expected `;` or `{`, found `]` fn main() {} diff --git a/src/test/ui/issues/issue-39616.stderr b/src/test/ui/issues/issue-39616.stderr index 74e94eda51faa..ced582746617b 100644 --- a/src/test/ui/issues/issue-39616.stderr +++ b/src/test/ui/issues/issue-39616.stderr @@ -4,11 +4,11 @@ error: expected type, found `0` LL | fn foo(a: [0; 1]) {} | ^ expected type -error: expected one of `)`, `,`, `->`, `where`, or `{`, found `]` +error: expected `;` or `{`, found `]` --> $DIR/issue-39616.rs:1:16 | LL | fn foo(a: [0; 1]) {} - | ^ expected one of `)`, `,`, `->`, `where`, or `{` + | ^ expected `;` or `{` error: aborting due to 2 previous errors diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr index 1d5eeac23f96a..461c1832e9af9 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr @@ -10,25 +10,25 @@ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33 | LL | fn g(_x: &isize, _y: &isize) -> &isize { - | ^ expected named lifetime parameter + | ------ ------ ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_x` or `_y` help: consider introducing a named lifetime parameter | -LL | fn g<'lifetime>(_x: &isize, _y: &isize) -> &'lifetime isize { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn g<'a>(_x: &'a isize, _y: &'a isize) -> &'a isize { + | ^^^^ ^^^^^^^^^ ^^^^^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:19 | LL | fn h(_x: &Foo) -> &isize { - | ^ expected named lifetime parameter + | ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn h<'lifetime>(_x: &Foo) -> &'lifetime isize { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn h<'a>(_x: &'a Foo) -> &'a isize { + | ^^^^ ^^^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20 diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr index 2990ab8682434..c1fcab2409f64 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr @@ -2,13 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/ex1b-return-no-names-if-else.rs:1:29 | LL | fn foo(x: &i32, y: &i32) -> &i32 { - | ^ expected named lifetime parameter + | ---- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` help: consider introducing a named lifetime parameter | -LL | fn foo<'lifetime>(x: &i32, y: &i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { + | ^^^^ ^^^^^^^ ^^^^^^^ ^^^ error: aborting due to previous error diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr index 1139ef06a1263..92d1afe1b645a 100644 --- a/src/test/ui/macros/issue-54441.stderr +++ b/src/test/ui/macros/issue-54441.stderr @@ -1,8 +1,8 @@ -error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found keyword `let` +error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `static`, `type`, or `unsafe`, found keyword `let` --> $DIR/issue-54441.rs:3:9 | LL | let - | ^^^ expected one of `crate`, `fn`, `pub`, `static`, or `type` + | ^^^ expected one of 9 possible tokens ... LL | m!(); | ----- in this macro invocation diff --git a/src/test/ui/macros/trace_faulty_macros.stderr b/src/test/ui/macros/trace_faulty_macros.stderr index 4e86daffb61ba..021c51fd726d3 100644 --- a/src/test/ui/macros/trace_faulty_macros.stderr +++ b/src/test/ui/macros/trace_faulty_macros.stderr @@ -29,7 +29,7 @@ LL | my_recursive_macro!(); LL | my_recursive_macro!(); | ---------------------- in this macro invocation | - = help: consider adding a `#![recursion_limit="8"]` attribute to your crate + = help: consider adding a `#![recursion_limit="8"]` attribute to your crate (`trace_faulty_macros`) note: trace_macro --> $DIR/trace_faulty_macros.rs:34:5 diff --git a/src/test/ui/no-patterns-in-args-2.rs b/src/test/ui/no-patterns-in-args-2.rs index ccf57478b4850..85b7fc5cdba49 100644 --- a/src/test/ui/no-patterns-in-args-2.rs +++ b/src/test/ui/no-patterns-in-args-2.rs @@ -1,9 +1,9 @@ #![deny(patterns_in_fns_without_body)] trait Tr { - fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in methods without bodies + fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in functions without bodies //~^ WARN was previously accepted - fn f2(&arg: u8); //~ ERROR patterns aren't allowed in methods without bodies + fn f2(&arg: u8); //~ ERROR patterns aren't allowed in functions without bodies fn g1(arg: u8); // OK fn g2(_: u8); // OK #[allow(anonymous_parameters)] diff --git a/src/test/ui/no-patterns-in-args-2.stderr b/src/test/ui/no-patterns-in-args-2.stderr index 905a89af4e587..21f4439d89009 100644 --- a/src/test/ui/no-patterns-in-args-2.stderr +++ b/src/test/ui/no-patterns-in-args-2.stderr @@ -1,10 +1,10 @@ -error[E0642]: patterns aren't allowed in methods without bodies +error[E0642]: patterns aren't allowed in functions without bodies --> $DIR/no-patterns-in-args-2.rs:6:11 | LL | fn f2(&arg: u8); - | ^^^^ + | ^^^^ pattern not allowed in function without body -error: patterns aren't allowed in methods without bodies +error: patterns aren't allowed in functions without bodies --> $DIR/no-patterns-in-args-2.rs:4:11 | LL | fn f1(mut arg: u8); diff --git a/src/test/ui/no-patterns-in-args-macro.rs b/src/test/ui/no-patterns-in-args-macro.rs index 59cb99453987c..b5109f9c28696 100644 --- a/src/test/ui/no-patterns-in-args-macro.rs +++ b/src/test/ui/no-patterns-in-args-macro.rs @@ -6,10 +6,10 @@ macro_rules! m { type A = fn($pat: u8); - extern { + extern "C" { fn foreign_fn($pat: u8); } - } + }; } mod good_pat { @@ -20,7 +20,7 @@ mod bad_pat { m!((bad, pat)); //~^ ERROR patterns aren't allowed in function pointer types //~| ERROR patterns aren't allowed in foreign function declarations - //~| ERROR patterns aren't allowed in methods without bodies + //~| ERROR patterns aren't allowed in functions without bodies } fn main() {} diff --git a/src/test/ui/no-patterns-in-args-macro.stderr b/src/test/ui/no-patterns-in-args-macro.stderr index f21df68d5a2cc..0016c7953f344 100644 --- a/src/test/ui/no-patterns-in-args-macro.stderr +++ b/src/test/ui/no-patterns-in-args-macro.stderr @@ -1,8 +1,8 @@ -error[E0642]: patterns aren't allowed in methods without bodies +error[E0642]: patterns aren't allowed in functions without bodies --> $DIR/no-patterns-in-args-macro.rs:20:8 | LL | m!((bad, pat)); - | ^^^^^^^^^^ + | ^^^^^^^^^^ pattern not allowed in function without body error[E0561]: patterns aren't allowed in function pointer types --> $DIR/no-patterns-in-args-macro.rs:20:8 diff --git a/src/test/ui/parser/duplicate-visibility.rs b/src/test/ui/parser/duplicate-visibility.rs index bb17e97e950c6..a8f0b7d61b985 100644 --- a/src/test/ui/parser/duplicate-visibility.rs +++ b/src/test/ui/parser/duplicate-visibility.rs @@ -1,4 +1,4 @@ -// error-pattern:expected one of `(`, `fn`, `static`, or `type` +// error-pattern: expected one of `(`, `async`, `const`, `extern`, `fn` extern { pub pub fn foo(); } diff --git a/src/test/ui/parser/duplicate-visibility.stderr b/src/test/ui/parser/duplicate-visibility.stderr index 313e88e812bb5..cba4058e48255 100644 --- a/src/test/ui/parser/duplicate-visibility.stderr +++ b/src/test/ui/parser/duplicate-visibility.stderr @@ -1,8 +1,8 @@ -error: expected one of `(`, `fn`, `static`, or `type`, found keyword `pub` +error: expected one of `(`, `async`, `const`, `extern`, `fn`, `static`, `type`, or `unsafe`, found keyword `pub` --> $DIR/duplicate-visibility.rs:3:9 | LL | pub pub fn foo(); - | ^^^ expected one of `(`, `fn`, `static`, or `type` + | ^^^ expected one of 8 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/fn-body-optional-semantic-fail.rs b/src/test/ui/parser/fn-body-optional-semantic-fail.rs new file mode 100644 index 0000000000000..38def05e8f2b3 --- /dev/null +++ b/src/test/ui/parser/fn-body-optional-semantic-fail.rs @@ -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 + } +} diff --git a/src/test/ui/parser/fn-body-optional-semantic-fail.stderr b/src/test/ui/parser/fn-body-optional-semantic-fail.stderr new file mode 100644 index 0000000000000..23ce98fb5d787 --- /dev/null +++ b/src/test/ui/parser/fn-body-optional-semantic-fail.stderr @@ -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: `{ }` + +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: `{ }` + +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: `{ }` + +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 + diff --git a/src/test/ui/parser/fn-body-optional-syntactic-pass.rs b/src/test/ui/parser/fn-body-optional-syntactic-pass.rs new file mode 100644 index 0000000000000..e7991c73b4b77 --- /dev/null +++ b/src/test/ui/parser/fn-body-optional-syntactic-pass.rs @@ -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() {} + } +} diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs new file mode 100644 index 0000000000000..c2b7e69c80d8e --- /dev/null +++ b/src/test/ui/parser/fn-header-semantic-fail.rs @@ -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. + } +} diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr new file mode 100644 index 0000000000000..41d2d9b7faaf1 --- /dev/null +++ b/src/test/ui/parser/fn-header-semantic-fail.stderr @@ -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`. diff --git a/src/test/ui/parser/fn-header-syntactic-pass.rs b/src/test/ui/parser/fn-header-syntactic-pass.rs new file mode 100644 index 0000000000000..145a208cb249d --- /dev/null +++ b/src/test/ui/parser/fn-header-syntactic-pass.rs @@ -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. + } +} diff --git a/src/test/ui/parser/issue-24780.rs b/src/test/ui/parser/issue-24780.rs index 799cdd8022257..8b46aa2bf22a1 100644 --- a/src/test/ui/parser/issue-24780.rs +++ b/src/test/ui/parser/issue-24780.rs @@ -3,6 +3,6 @@ // expected one of ..., `>`, ... found `>` fn foo() -> Vec> { - //~^ ERROR expected one of `!`, `+`, `::`, `where`, or `{`, found `>` + //~^ ERROR expected `;` or `{`, found `>` Vec::new() } diff --git a/src/test/ui/parser/issue-24780.stderr b/src/test/ui/parser/issue-24780.stderr index d9470191b25a4..d65a5f448739a 100644 --- a/src/test/ui/parser/issue-24780.stderr +++ b/src/test/ui/parser/issue-24780.stderr @@ -1,8 +1,8 @@ -error: expected one of `!`, `+`, `::`, `where`, or `{`, found `>` +error: expected `;` or `{`, found `>` --> $DIR/issue-24780.rs:5:23 | LL | fn foo() -> Vec> { - | ^ expected one of `!`, `+`, `::`, `where`, or `{` + | ^ expected `;` or `{` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-63135.rs b/src/test/ui/parser/issue-63135.rs index d5f5f1469f35a..7d46b8904f033 100644 --- a/src/test/ui/parser/issue-63135.rs +++ b/src/test/ui/parser/issue-63135.rs @@ -1,3 +1,3 @@ -// error-pattern: aborting due to 6 previous errors +// error-pattern: aborting due to 7 previous errors fn i(n{...,f # diff --git a/src/test/ui/parser/issue-63135.stderr b/src/test/ui/parser/issue-63135.stderr index 462fdf11f40a9..04afae93be0e5 100644 --- a/src/test/ui/parser/issue-63135.stderr +++ b/src/test/ui/parser/issue-63135.stderr @@ -43,5 +43,11 @@ error: expected one of `:` or `|`, found `)` LL | fn i(n{...,f # | ^ expected one of `:` or `|` -error: aborting due to 6 previous errors +error: expected `;` or `{`, found `` + --> $DIR/issue-63135.rs:3:16 + | +LL | fn i(n{...,f # + | ^ expected `;` or `{` + +error: aborting due to 7 previous errors diff --git a/src/test/ui/parser/missing_right_paren.rs b/src/test/ui/parser/missing_right_paren.rs index c35236ce7934e..810dee9571d81 100644 --- a/src/test/ui/parser/missing_right_paren.rs +++ b/src/test/ui/parser/missing_right_paren.rs @@ -1,3 +1,3 @@ // ignore-tidy-trailing-newlines -// error-pattern: aborting due to 3 previous errors +// error-pattern: aborting due to 4 previous errors fn main((ؼ \ No newline at end of file diff --git a/src/test/ui/parser/missing_right_paren.stderr b/src/test/ui/parser/missing_right_paren.stderr index d67e7c88912a5..c1ceb81a07c47 100644 --- a/src/test/ui/parser/missing_right_paren.stderr +++ b/src/test/ui/parser/missing_right_paren.stderr @@ -22,5 +22,11 @@ error: expected one of `:` or `|`, found `)` LL | fn main((ؼ | ^ expected one of `:` or `|` -error: aborting due to 3 previous errors +error: expected `;` or `{`, found `` + --> $DIR/missing_right_paren.rs:3:11 + | +LL | fn main((ؼ + | ^ expected `;` or `{` + +error: aborting due to 4 previous errors diff --git a/src/test/ui/parser/no-const-fn-in-extern-block.rs b/src/test/ui/parser/no-const-fn-in-extern-block.rs index 29f26389ded18..4cae703a16395 100644 --- a/src/test/ui/parser/no-const-fn-in-extern-block.rs +++ b/src/test/ui/parser/no-const-fn-in-extern-block.rs @@ -1,8 +1,8 @@ extern { const fn foo(); - //~^ ERROR extern items cannot be `const` + //~^ ERROR functions in `extern` blocks cannot have qualifiers const unsafe fn bar(); - //~^ ERROR extern items cannot be `const` + //~^ ERROR functions in `extern` blocks cannot have qualifiers } fn main() {} diff --git a/src/test/ui/parser/no-const-fn-in-extern-block.stderr b/src/test/ui/parser/no-const-fn-in-extern-block.stderr index 5b4663a702f06..de653987e406d 100644 --- a/src/test/ui/parser/no-const-fn-in-extern-block.stderr +++ b/src/test/ui/parser/no-const-fn-in-extern-block.stderr @@ -1,14 +1,23 @@ -error: extern items cannot be `const` - --> $DIR/no-const-fn-in-extern-block.rs:2:5 +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/no-const-fn-in-extern-block.rs:2:14 | +LL | extern { + | ------ in this `extern` block LL | const fn foo(); - | ^^^^^ + | ---------^^^ + | | + | help: remove the qualifiers: `fn` -error: extern items cannot be `const` - --> $DIR/no-const-fn-in-extern-block.rs:4:5 +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/no-const-fn-in-extern-block.rs:4:21 | +LL | extern { + | ------ in this `extern` block +... LL | const unsafe fn bar(); - | ^^^^^ + | ----------------^^^ + | | + | help: remove the qualifiers: `fn` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/not-a-pred.stderr b/src/test/ui/parser/not-a-pred.stderr index 90246b92bf0fa..dce54655fa027 100644 --- a/src/test/ui/parser/not-a-pred.stderr +++ b/src/test/ui/parser/not-a-pred.stderr @@ -1,8 +1,8 @@ -error: expected one of `->`, `where`, or `{`, found `:` +error: expected `;` or `{`, found `:` --> $DIR/not-a-pred.rs:3:26 | LL | fn f(a: isize, b: isize) : lt(a, b) { } - | ^ expected one of `->`, `where`, or `{` + | ^ expected `;` or `{` error: aborting due to previous error diff --git a/src/test/ui/proc-macro/item-error.stderr b/src/test/ui/proc-macro/item-error.stderr index 01eadbe252e9f..27f7639d213d2 100644 --- a/src/test/ui/proc-macro/item-error.stderr +++ b/src/test/ui/proc-macro/item-error.stderr @@ -6,8 +6,8 @@ LL | a: &u64 | help: consider introducing a named lifetime parameter | -LL | struct A<'lifetime> { -LL | a: &'lifetime u64 +LL | struct A<'a> { +LL | a: &'a u64 | error: aborting due to previous error diff --git a/src/test/ui/regions/regions-in-enums-anon.stderr b/src/test/ui/regions/regions-in-enums-anon.stderr index 41655a210b3c0..b3649c5b48530 100644 --- a/src/test/ui/regions/regions-in-enums-anon.stderr +++ b/src/test/ui/regions/regions-in-enums-anon.stderr @@ -6,8 +6,8 @@ LL | Bar(&isize) | help: consider introducing a named lifetime parameter | -LL | enum Foo<'lifetime> { -LL | Bar(&'lifetime isize) +LL | enum Foo<'a> { +LL | Bar(&'a isize) | error: aborting due to previous error diff --git a/src/test/ui/regions/regions-in-structs-anon.stderr b/src/test/ui/regions/regions-in-structs-anon.stderr index fbe8036880f48..60a6fb9a0fad9 100644 --- a/src/test/ui/regions/regions-in-structs-anon.stderr +++ b/src/test/ui/regions/regions-in-structs-anon.stderr @@ -6,8 +6,8 @@ LL | x: &isize | help: consider introducing a named lifetime parameter | -LL | struct Foo<'lifetime> { -LL | x: &'lifetime isize +LL | struct Foo<'a> { +LL | x: &'a isize | error: aborting due to previous error diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index 79ebef41dccd6..eb19a30c52b97 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -88,12 +88,32 @@ error[E0261]: use of undeclared lifetime name `'b` | LL | ... &'b isize, | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing lifetime `'b` here + | +LL | fn fn_types<'b>(a: &'a isize, + | ^^^^ +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | b: Box FnOnce(&'a isize, + | ^^^^ error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:45:36 | LL | ... &'b isize)>, | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing lifetime `'b` here + | +LL | fn fn_types<'b>(a: &'a isize, + | ^^^^ +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | b: Box FnOnce(&'a isize, + | ^^^^ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:46:17 diff --git a/src/test/ui/rfc1623-2.rs b/src/test/ui/rfc1623-2.rs new file mode 100644 index 0000000000000..35a2ef10c2e3c --- /dev/null +++ b/src/test/ui/rfc1623-2.rs @@ -0,0 +1,13 @@ +#![allow(dead_code)] + +fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { + a +} + +// the boundaries of elision +static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = +//~^ ERROR missing lifetime specifier [E0106] + &(non_elidable as fn(&u8, &u8) -> &u8); + //~^ ERROR missing lifetime specifier [E0106] + +fn main() {} diff --git a/src/test/ui/rfc1623-2.stderr b/src/test/ui/rfc1623-2.stderr new file mode 100644 index 0000000000000..732bb61e6eebb --- /dev/null +++ b/src/test/ui/rfc1623-2.stderr @@ -0,0 +1,29 @@ +error[E0106]: missing lifetime specifier + --> $DIR/rfc1623-2.rs:8:42 + | +LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = + | --- --- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 = + | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/rfc1623-2.rs:10:39 + | +LL | &(non_elidable as fn(&u8, &u8) -> &u8); + | --- --- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8); + | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/rfc1623.rs b/src/test/ui/rfc1623.rs index ebb4d56af9eec..55f5d0b94dcb0 100644 --- a/src/test/ui/rfc1623.rs +++ b/src/test/ui/rfc1623.rs @@ -4,11 +4,10 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } -// the boundaries of elision -static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = -//~^ ERROR missing lifetime specifier [E0106] - &(non_elidable as fn(&u8, &u8) -> &u8); - //~^ ERROR missing lifetime specifier [E0106] +// The incorrect case without `for<'a>` is tested for in `rfc1623-2.rs` +static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 = + &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8); + struct SomeStruct<'x, 'y, 'z: 'x> { foo: &'x Foo<'z>, @@ -20,10 +19,12 @@ fn id(t: T) -> T { t } -static SOME_STRUCT: &SomeStruct = SomeStruct { +static SOME_STRUCT: &SomeStruct = SomeStruct { //~ ERROR mismatched types foo: &Foo { bools: &[false, true] }, bar: &Bar { bools: &[true, true] }, f: &id, + //~^ ERROR type mismatch in function arguments + //~| ERROR type mismatch resolving }; // very simple test for a 'static static with default lifetime diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index 5b665e181412a..ca956004ef76f 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -1,19 +1,46 @@ -error[E0106]: missing lifetime specifier - --> $DIR/rfc1623.rs:8:42 +error[E0308]: mismatched types + --> $DIR/rfc1623.rs:22:35 | -LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = - | ^ expected named lifetime parameter +LL | static SOME_STRUCT: &SomeStruct = SomeStruct { + | ___________________________________^ +LL | | foo: &Foo { bools: &[false, true] }, +LL | | bar: &Bar { bools: &[true, true] }, +LL | | f: &id, +LL | | +LL | | +LL | | }; + | |_^ expected `&SomeStruct<'static, 'static, 'static>`, found struct `SomeStruct` | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 +help: consider borrowing here + | +LL | static SOME_STRUCT: &SomeStruct = &SomeStruct { +LL | foo: &Foo { bools: &[false, true] }, +LL | bar: &Bar { bools: &[true, true] }, +LL | f: &id, +LL | +LL | + ... + +error[E0631]: type mismatch in function arguments + --> $DIR/rfc1623.rs:25:8 + | +LL | fn id(t: T) -> T { + | ------------------- found signature of `fn(_) -> _` +... +LL | f: &id, + | ^^^ expected signature of `for<'a, 'b> fn(&'a Foo<'b>) -> _` + | + = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` -error[E0106]: missing lifetime specifier - --> $DIR/rfc1623.rs:10:39 +error[E0271]: type mismatch resolving `for<'a, 'b> _ {id::<_>} as std::ops::FnOnce<(&'a Foo<'b>,)>>::Output == &'a Foo<'b>` + --> $DIR/rfc1623.rs:25:8 | -LL | &(non_elidable as fn(&u8, &u8) -> &u8); - | ^ expected named lifetime parameter +LL | f: &id, + | ^^^ expected bound lifetime parameter 'a, found concrete lifetime | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0106`. +Some errors have detailed explanations: E0271, E0308, E0631. +For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/suggestions/fn-missing-lifetime-in-item.rs b/src/test/ui/suggestions/fn-missing-lifetime-in-item.rs new file mode 100644 index 0000000000000..dac6610b3355f --- /dev/null +++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.rs @@ -0,0 +1,8 @@ +struct S1 &'a i32>(F); //~ ERROR use of undeclared lifetime name `'a` +struct S2 &i32>(F); //~ ERROR missing lifetime specifier +struct S3 Fn(&i32, &i32) -> &'a i32>(F); +//~^ ERROR binding for associated type `Output` references lifetime `'a`, which does not appear +struct S4 Fn(&'x i32, &'x i32) -> &'x i32>(F); +const C: Option Fn(&usize, &usize) -> &'a usize>> = None; +//~^ ERROR binding for associated type `Output` references lifetime `'a`, which does not appear +fn main() {} diff --git a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr new file mode 100644 index 0000000000000..fe9c3445fc46f --- /dev/null +++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr @@ -0,0 +1,49 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/fn-missing-lifetime-in-item.rs:1:33 + | +LL | struct S1 &'a i32>(F); + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing lifetime `'a` here + | +LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F); + | ^^^ +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | struct S1 Fn(&i32, &i32) -> &'a i32>(F); + | ^^^^^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/fn-missing-lifetime-in-item.rs:2:32 + | +LL | struct S2 &i32>(F); + | ---- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | struct S2 Fn(&'a i32, &'a i32) -> &'a i32>(F); + | ^^^^^^^ ^^^^^^^ ^^^^^^^ ^^^ +help: consider introducing a named lifetime parameter + | +LL | struct S2<'a, F: Fn(&'a i32, &'a i32) -> &'a i32>(F); + | ^^^ ^^^^^^^ ^^^^^^^ ^^^ + +error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/fn-missing-lifetime-in-item.rs:3:40 + | +LL | struct S3 Fn(&i32, &i32) -> &'a i32>(F); + | ^^^^^^^ + +error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/fn-missing-lifetime-in-item.rs:6:55 + | +LL | const C: Option Fn(&usize, &usize) -> &'a usize>> = None; + | ^^^^^^^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0106, E0261, E0582. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.rs b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs new file mode 100644 index 0000000000000..22dc448c97ff0 --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs @@ -0,0 +1,2 @@ +fn f(_: impl Iterator) {} //~ ERROR missing lifetime specifier +fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr new file mode 100644 index 0000000000000..e31f25ab60304 --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr @@ -0,0 +1,14 @@ +error[E0106]: missing lifetime specifier + --> $DIR/impl-trait-missing-lifetime.rs:1:31 + | +LL | fn f(_: impl Iterator) {} + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | fn f<'a>(_: impl Iterator) {} + | ^^^^ ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr index 7f5ff95938e30..ce3b1748da435 100644 --- a/src/test/ui/suggestions/return-without-lifetime.stderr +++ b/src/test/ui/suggestions/return-without-lifetime.stderr @@ -8,7 +8,7 @@ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:5:34 | LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } - | ^ help: consider using the named lifetime: `&'a` + | --------- ^ help: consider using the named lifetime: `&'a` | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from @@ -16,7 +16,7 @@ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:7:35 | LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } - | ^ help: consider using the named lifetime: `&'a` + | ---------- ^ help: consider using the named lifetime: `&'a` | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr index 0a028e44919a6..1719a99d421d0 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr @@ -2,12 +2,12 @@ error[E0106]: missing lifetime specifier --> $DIR/unboxed-closure-sugar-lifetime-elision.rs:26:39 | LL | let _: dyn Foo(&isize, &usize) -> &usize; - | ^ expected named lifetime parameter + | ------ ------ ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 help: consider introducing a named lifetime parameter | -LL | fn main<'lifetime>() { +LL | fn main<'a>() { LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=&'a isize>, LL | dyn Foo(&isize) -> &isize >(); LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=(&'a isize, &'a isize)>, diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr index 04df2e4570396..fe242e6a909e3 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr @@ -6,8 +6,8 @@ LL | x: Box, | help: consider introducing a named lifetime parameter | -LL | struct Foo<'lifetime> { -LL | x: Box, +LL | struct Foo<'a> { +LL | x: Box, | error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound diff --git a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr index cf820249c80af..8d2c82e59edc1 100644 --- a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr @@ -2,13 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/in-fn-return-illegal.rs:5:30 | LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } - | ^^ expected named lifetime parameter + | ---- ---- ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` help: consider introducing a named lifetime parameter | -LL | fn foo<'lifetime>(x: &u32, y: &u32) -> &'lifetime u32 { loop { } } - | ^^^^^^^^^^^ ^^^^^^^^^ +LL | fn foo<'a>(x: &'a u32, y: &'a u32) -> &'a u32 { loop { } } + | ^^^^ ^^^^^^^ ^^^^^^^ ^^ error: aborting due to previous error diff --git a/src/test/ui/underscore-lifetime/in-struct.stderr b/src/test/ui/underscore-lifetime/in-struct.stderr index e01b39a4b64f4..4275cc26f735f 100644 --- a/src/test/ui/underscore-lifetime/in-struct.stderr +++ b/src/test/ui/underscore-lifetime/in-struct.stderr @@ -6,8 +6,8 @@ LL | x: &'_ u32, | help: consider introducing a named lifetime parameter | -LL | struct Foo<'lifetime> { -LL | x: &'lifetime u32, +LL | struct Foo<'a> { +LL | x: &'a u32, | error[E0106]: missing lifetime specifier @@ -18,8 +18,8 @@ LL | Variant(&'_ u32), | help: consider introducing a named lifetime parameter | -LL | enum Bar<'lifetime> { -LL | Variant(&'lifetime u32), +LL | enum Bar<'a> { +LL | Variant(&'a u32), | error: aborting due to 2 previous errors diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index 517904ee62869..c7cda38e47691 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -28,13 +28,13 @@ error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:16:35 | LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } - | ^^ expected named lifetime parameter + | ------ ------ ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or `y` help: consider introducing a named lifetime parameter | -LL | fn foo2<'lifetime>(_: &'_ u8, y: &'_ u8) -> &'lifetime u8 { y } - | ^^^^^^^^^^^ ^^^^^^^^^ +LL | fn foo2<'a>(_: &'a u8, y: &'a u8) -> &'a u8 { y } + | ^^^^ ^^^^^^ ^^^^^^ ^^ error: aborting due to 5 previous errors