diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 190fae9565210..5755ae8a8bc47 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -676,6 +676,19 @@ impl Pat { }); could_be_never_pattern } + + /// Whether this contains a `!` pattern. This in particular means that a feature gate error will + /// be raised if the feature is off. Used to avoid gating the feature twice. + pub fn contains_never_pattern(&self) -> bool { + let mut contains_never_pattern = false; + self.walk(&mut |pat| { + if matches!(pat.kind, PatKind::Never) { + contains_never_pattern = true; + } + true + }); + contains_never_pattern + } } /// A single field in a struct pattern. diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index e9f88d5093714..a44b408feec25 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -581,8 +581,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } else { // Either `body.is_none()` or `is_never_pattern` here. if !is_never_pattern { - let suggestion = span.shrink_to_hi(); - self.tcx.sess.emit_err(MatchArmWithNoBody { span, suggestion }); + if self.tcx.features().never_patterns { + // If the feature is off we already emitted the error after parsing. + let suggestion = span.shrink_to_hi(); + self.tcx.sess.emit_err(MatchArmWithNoBody { span, suggestion }); + } } else if let Some(body) = &arm.body { self.tcx.sess.emit_err(NeverPatternWithBody { span: body.span }); guard = None; diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 876126b02ea95..28bd6c2111b72 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -174,6 +174,10 @@ ast_passes_item_underscore = `{$kind}` items in this context need a name ast_passes_keyword_lifetime = lifetimes cannot use keyword names +ast_passes_match_arm_with_no_body = + `match` arm with no body + .suggestion = add a body after the pattern + ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name .help = consider using the `#[path]` attribute to specify filesystem path diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 7f6fcb493171c..928bf19759ada 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -758,3 +758,12 @@ pub struct AnonStructOrUnionNotAllowed { pub span: Span, pub struct_or_union: &'static str, } + +#[derive(Diagnostic)] +#[diag(ast_passes_match_arm_with_no_body)] +pub struct MatchArmWithNoBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " => todo!(),", applicability = "has-placeholders")] + pub suggestion: Span, +} diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 897f35a5c4ad9..ac55c6cabd0eb 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -554,7 +554,34 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(explicit_tail_calls, "`become` expression is experimental"); gate_all!(generic_const_items, "generic const items are experimental"); gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented"); - gate_all!(never_patterns, "`!` patterns are experimental"); + + if !visitor.features.never_patterns { + if let Some(spans) = spans.get(&sym::never_patterns) { + for &span in spans { + if span.allows_unstable(sym::never_patterns) { + continue; + } + let sm = sess.source_map(); + // We gate two types of spans: the span of a `!` pattern, and the span of a + // match arm without a body. For the latter we want to give the user a normal + // error. + if let Ok(snippet) = sm.span_to_snippet(span) + && snippet == "!" + { + feature_err( + &sess.parse_sess, + sym::never_patterns, + span, + "`!` patterns are experimental", + ) + .emit(); + } else { + let suggestion = span.shrink_to_hi(); + sess.emit_err(errors::MatchArmWithNoBody { span, suggestion }); + } + } + } + } if !visitor.features.negative_bounds { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index abc33a045982a..97444f1a5bd39 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -816,6 +816,9 @@ impl ThinLTOKeysMap { use std::io::Write; let file = File::create(path)?; let mut writer = io::BufWriter::new(file); + // The entries are loaded back into a hash map in `load_from_file()`, so + // the order in which we write them to file here does not matter. + #[allow(rustc::potential_query_instability)] for (module, key) in &self.keys { writeln!(writer, "{module} {key}")?; } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 51df14df644e0..33bfde03a31c3 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -58,6 +58,11 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { return; } + // The entries of the map are only used to get a list of all files with + // coverage info. In the end the list of files is passed into + // `GlobalFileTable::new()` which internally do `.sort_unstable_by()`, so + // the iteration order here does not matter. + #[allow(rustc::potential_query_instability)] let function_coverage_entries = function_coverage_map .into_iter() .map(|(instance, function_coverage)| (instance, function_coverage.into_finished())) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 33b19ab362af2..116108ae5a987 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -17,7 +17,6 @@ #![feature(never_type)] #![feature(impl_trait_in_assoc_type)] #![recursion_limit = "256"] -#![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index de0abe04611d7..a25cfe68e0d3c 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -345,12 +345,34 @@ pub struct FutureIncompatibleInfo { } /// The reason for future incompatibility +/// +/// Future-incompatible lints come in roughly two categories: +/// +/// 1. There was a mistake in the compiler (such as a soundness issue), and +/// we're trying to fix it, but it may be a breaking change. +/// 2. A change across an Edition boundary, typically used for the +/// introduction of new language features that can't otherwise be +/// introduced in a backwards-compatible way. +/// +/// See and +/// +/// for more information. #[derive(Copy, Clone, Debug)] pub enum FutureIncompatibilityReason { /// This will be an error in a future release for all editions /// /// This will *not* show up in cargo's future breakage report. /// The warning will hence only be seen in local crates, not in dependencies. + /// + /// Choose this variant when you are first introducing a "future + /// incompatible" warning that is intended to eventually be fixed in the + /// future. This allows crate developers an opportunity to fix the warning + /// before blasting all dependents with a warning they can't fix + /// (dependents have to wait for a new release of the affected crate to be + /// published). + /// + /// After a lint has been in this state for a while, consider graduating + /// it to [`FutureIncompatibilityReason::FutureReleaseErrorReportInDeps`]. FutureReleaseErrorDontReportInDeps, /// This will be an error in a future release, and /// Cargo should create a report even for dependencies @@ -358,17 +380,62 @@ pub enum FutureIncompatibilityReason { /// This is the *only* reason that will make future incompatibility warnings show up in cargo's /// reports. All other future incompatibility warnings are not visible when they occur in a /// dependency. + /// + /// Choose this variant after the lint has been sitting in the + /// [`FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps`] + /// state for a while, and you feel like it is ready to graduate to + /// warning everyone. It is a good signal that it is ready if you can + /// determine that all or most affected crates on crates.io have been + /// updated. + /// + /// After some period of time, lints with this variant can be turned into + /// hard errors (and the lint removed). Preferably when there is some + /// confidence that the number of impacted projects is very small (few + /// should have a broken dependency in their dependency tree). FutureReleaseErrorReportInDeps, /// Code that changes meaning in some way in a /// future release. + /// + /// Choose this variant when the semantics of existing code is changing, + /// (as opposed to + /// [`FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps`], + /// which is for when code is going to be rejected in the future). FutureReleaseSemanticsChange, /// Previously accepted code that will become an /// error in the provided edition + /// + /// Choose this variant for code that you want to start rejecting across + /// an edition boundary. This will automatically include the lint in the + /// `rust-20xx-compatibility` lint group, which is used by `cargo fix + /// --edition` to do migrations. The lint *should* be auto-fixable with + /// [`Applicability::MachineApplicable`]. + /// + /// The lint can either be `Allow` or `Warn` by default. If it is `Allow`, + /// users usually won't see this warning unless they are doing an edition + /// migration manually or there is a problem during the migration (cargo's + /// automatic migrations will force the level to `Warn`). If it is `Warn` + /// by default, users on all editions will see this warning (only do this + /// if you think it is important for everyone to be aware of the change, + /// and to encourage people to update their code on all editions). + /// + /// See also [`FutureIncompatibilityReason::EditionSemanticsChange`] if + /// you have code that is changing semantics across the edition (as + /// opposed to being rejected). EditionError(Edition), /// Code that changes meaning in some way in /// the provided edition + /// + /// This is the same as [`FutureIncompatibilityReason::EditionError`], + /// except for situations where the semantics change across an edition. It + /// slightly changes the text of the diagnostic, but is otherwise the + /// same. EditionSemanticsChange(Edition), /// A custom reason. + /// + /// Choose this variant if the built-in text of the diagnostic of the + /// other variants doesn't match your situation. This is behaviorally + /// equivalent to + /// [`FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps`]. Custom(&'static str), } diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 2601d96b8c869..556dc890a8429 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -37,7 +37,9 @@ #include "llvm/Transforms/Utils/FunctionImportUtils.h" #include "llvm/LTO/LTO.h" #include "llvm/Bitcode/BitcodeWriter.h" - +#if LLVM_VERSION_GE(18, 0) +#include "llvm/TargetParser/Host.h" +#endif #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Instrumentation/AddressSanitizer.h" #include "llvm/Support/TimeProfiler.h" diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 3c0627526bed5..5b0011e9f706c 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2918,7 +2918,15 @@ impl<'a> Parser<'a> { let mut result = if !is_fat_arrow && !is_almost_fat_arrow { // A pattern without a body, allowed for never patterns. arm_body = None; - this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)]) + this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)]).map( + |x| { + // Don't gate twice + if !pat.contains_never_pattern() { + this.sess.gated_spans.gate(sym::never_patterns, pat.span); + } + x + }, + ) } else { if let Err(mut err) = this.expect(&token::FatArrow) { // We might have a `=>` -> `=` or `->` typo (issue #89396). diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index cbe75b3dab6ee..81055431f649d 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -6,9 +6,9 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::MetaItemKind; use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem}; -use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; +use rustc_session::errors::report_lit_error; use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_session::parse::ParseSess; use rustc_span::{sym, Span, Symbol}; @@ -51,28 +51,44 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta MetaItemKind::List(nmis) } AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => { - if let ast::ExprKind::Lit(token_lit) = expr.kind - && let Ok(lit) = ast::MetaItemLit::from_token_lit(token_lit, expr.span) - { - if token_lit.suffix.is_some() { - let mut err = sess.span_diagnostic.struct_span_err( - expr.span, - "suffixed literals are not allowed in attributes", - ); - err.help( - "instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \ - use an unsuffixed version (`1`, `1.0`, etc.)", - ); - return Err(err); - } else { - MetaItemKind::NameValue(lit) - } + if let ast::ExprKind::Lit(token_lit) = expr.kind { + let res = ast::MetaItemLit::from_token_lit(token_lit, expr.span); + let res = match res { + Ok(lit) => { + if token_lit.suffix.is_some() { + let mut err = sess.span_diagnostic.struct_span_err( + expr.span, + "suffixed literals are not allowed in attributes", + ); + err.help( + "instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \ + use an unsuffixed version (`1`, `1.0`, etc.)", + ); + return Err(err); + } else { + MetaItemKind::NameValue(lit) + } + } + Err(err) => { + report_lit_error(sess, err, token_lit, expr.span); + let lit = ast::MetaItemLit { + symbol: token_lit.symbol, + suffix: token_lit.suffix, + kind: ast::LitKind::Err, + span: expr.span, + }; + MetaItemKind::NameValue(lit) + } + }; + res } else { - // The non-error case can happen with e.g. `#[foo = 1+1]`. The error case can - // happen with e.g. `#[foo = include_str!("nonexistent-file.rs")]`; in that - // case we delay the error because an earlier error will have already been - // reported. - let msg = format!("unexpected expression: `{}`", pprust::expr_to_string(expr)); + // Example cases: + // - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`. + // - `#[foo = include_str!("nonexistent-file.rs")]`: + // results in `ast::ExprKind::Err`. In that case we delay + // the error because an earlier error will have already + // been reported. + let msg = format!("attribute value must be a literal"); let mut err = sess.span_diagnostic.struct_span_err(expr.span, msg); if let ast::ExprKind::Err = expr.kind { err.downgrade_to_delayed_bug(); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index df30c185c6062..61c7846ea61a3 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -8,7 +8,7 @@ use crate::{PathResult, PathSource, Segment}; use rustc_hir::def::Namespace::{self, *}; use rustc_ast::ptr::P; -use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt}; +use rustc_ast::visit::{walk_ty, FnCtxt, FnKind, LifetimeCtxt, Visitor}; use rustc_ast::{ self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, MethodCall, NodeId, Path, Ty, TyKind, DUMMY_NODE_ID, @@ -2830,6 +2830,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .collect(); debug!(?in_scope_lifetimes); + let mut maybe_static = false; debug!(?function_param_lifetimes); if let Some((param_lifetimes, params)) = &function_param_lifetimes { let elided_len = param_lifetimes.len(); @@ -2868,10 +2869,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { if num_params == 0 { err.help( - "this function's return type contains a borrowed value, \ - but there is no value for it to be borrowed from", + "this function's return type contains a borrowed value, but there is no value \ + for it to be borrowed from", ); if in_scope_lifetimes.is_empty() { + maybe_static = true; in_scope_lifetimes = vec![( Ident::with_dummy_span(kw::StaticLifetime), (DUMMY_NODE_ID, LifetimeRes::Static), @@ -2879,11 +2881,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } else if elided_len == 0 { err.help( - "this function's return type contains a borrowed value with \ - an elided lifetime, but the lifetime cannot be derived from \ - the arguments", + "this function's return type contains a borrowed value with an elided \ + lifetime, but the lifetime cannot be derived from the arguments", ); if in_scope_lifetimes.is_empty() { + maybe_static = true; in_scope_lifetimes = vec![( Ident::with_dummy_span(kw::StaticLifetime), (DUMMY_NODE_ID, LifetimeRes::Static), @@ -2891,13 +2893,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } else if num_params == 1 { err.help(format!( - "this function's return type contains a borrowed value, \ - but the signature does not say which {m} it is borrowed from" + "this function's return type contains a borrowed value, but the signature does \ + not say which {m} it is borrowed from", )); } else { err.help(format!( - "this function's return type contains a borrowed value, \ - but the signature does not say whether it is borrowed from {m}" + "this function's return type contains a borrowed value, but the signature does \ + not say whether it is borrowed from {m}", )); } } @@ -2962,11 +2964,238 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ); } 1 => { + let post = if maybe_static { + let owned = if let [lt] = &lifetime_refs[..] + && lt.kind != MissingLifetimeKind::Ampersand + { + ", or if you will only have owned values" + } else { + "" + }; + format!( + ", but this is uncommon unless you're returning a borrowed value from a \ + `const` or a `static`{owned}", + ) + } else { + String::new() + }; err.multipart_suggestion_verbose( - format!("consider using the `{existing_name}` lifetime"), + format!("consider using the `{existing_name}` lifetime{post}"), spans_suggs, Applicability::MaybeIncorrect, ); + if maybe_static { + // FIXME: what follows are general suggestions, but we'd want to perform some + // minimal flow analysis to provide more accurate suggestions. For example, if + // we identified that the return expression references only one argument, we + // would suggest borrowing only that argument, and we'd skip the prior + // "use `'static`" suggestion entirely. + if let [lt] = &lifetime_refs[..] + && (lt.kind == MissingLifetimeKind::Ampersand + || lt.kind == MissingLifetimeKind::Underscore) + { + let pre = if lt.kind == MissingLifetimeKind::Ampersand + && let Some((kind, _span)) = self.diagnostic_metadata.current_function + && let FnKind::Fn(_, _, sig, _, _, _) = kind + && !sig.decl.inputs.is_empty() + && let sugg = sig + .decl + .inputs + .iter() + .filter_map(|param| { + if param.ty.span.contains(lt.span) { + // We don't want to suggest `fn elision(_: &fn() -> &i32)` + // when we have `fn elision(_: fn() -> &i32)` + None + } else if let TyKind::CVarArgs = param.ty.kind { + // Don't suggest `&...` for ffi fn with varargs + None + } else if let TyKind::ImplTrait(..) = ¶m.ty.kind { + // We handle these in the next `else if` branch. + None + } else { + Some((param.ty.span.shrink_to_lo(), "&".to_string())) + } + }) + .collect::>() + && !sugg.is_empty() + { + let (the, s) = if sig.decl.inputs.len() == 1 { + ("the", "") + } else { + ("one of the", "s") + }; + err.multipart_suggestion_verbose( + format!( + "instead, you are more likely to want to change {the} \ + argument{s} to be borrowed...", + ), + sugg, + Applicability::MaybeIncorrect, + ); + "...or alternatively, you might want" + } else if (lt.kind == MissingLifetimeKind::Ampersand + || lt.kind == MissingLifetimeKind::Underscore) + && let Some((kind, _span)) = self.diagnostic_metadata.current_function + && let FnKind::Fn(_, _, sig, _, _, _) = kind + && let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output + && !sig.decl.inputs.is_empty() + && let arg_refs = sig + .decl + .inputs + .iter() + .filter_map(|param| match ¶m.ty.kind { + TyKind::ImplTrait(_, bounds) => Some(bounds), + _ => None, + }) + .flat_map(|bounds| bounds.into_iter()) + .collect::>() + && !arg_refs.is_empty() + { + // We have a situation like + // fn g(mut x: impl Iterator) -> Option<&()> + // So we look at every ref in the trait bound. If there's any, we + // suggest + // fn g<'a>(mut x: impl Iterator) -> Option<&'a ()> + let mut lt_finder = + LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] }; + for bound in arg_refs { + if let ast::GenericBound::Trait(trait_ref, _) = bound { + lt_finder.visit_trait_ref(&trait_ref.trait_ref); + } + } + lt_finder.visit_ty(ret_ty); + let spans_suggs: Vec<_> = lt_finder + .seen + .iter() + .filter_map(|ty| match &ty.kind { + TyKind::Ref(_, mut_ty) => { + let span = ty.span.with_hi(mut_ty.ty.span.lo()); + Some((span, "&'a ".to_string())) + } + _ => None, + }) + .collect(); + self.suggest_introducing_lifetime( + err, + None, + |err, higher_ranked, span, message, intro_sugg| { + err.multipart_suggestion_verbose( + message, + std::iter::once((span, intro_sugg)) + .chain(spans_suggs.iter().cloned()) + .collect(), + Applicability::MaybeIncorrect, + ); + higher_ranked + }, + ); + "alternatively, you might want" + } else { + "instead, you are more likely to want" + }; + let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand; + let mut sugg = vec![(lt.span, String::new())]; + if let Some((kind, _span)) = self.diagnostic_metadata.current_function + && let FnKind::Fn(_, _, sig, _, _, _) = kind + && let ast::FnRetTy::Ty(ty) = &sig.decl.output + { + let mut lt_finder = + LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] }; + lt_finder.visit_ty(&ty); + + if let [Ty { span, kind: TyKind::Ref(_, mut_ty), .. }] = + <_finder.seen[..] + { + // We might have a situation like + // fn g(mut x: impl Iterator) -> Option<&'_ ()> + // but `lt.span` only points at `'_`, so to suggest `-> Option<()>` + // we need to find a more accurate span to end up with + // fn g<'a>(mut x: impl Iterator) -> Option<()> + sugg = vec![(span.with_hi(mut_ty.ty.span.lo()), String::new())]; + owned_sugg = true; + } + if let Some(ty) = lt_finder.found { + if let TyKind::Path(None, path) = &ty.kind { + // Check if the path being borrowed is likely to be owned. + let path: Vec<_> = Segment::from_path(path); + match self.resolve_path(&path, Some(TypeNS), None) { + PathResult::Module(ModuleOrUniformRoot::Module(module)) => { + match module.res() { + Some(Res::PrimTy(PrimTy::Str)) => { + // Don't suggest `-> str`, suggest `-> String`. + sugg = vec![( + lt.span.with_hi(ty.span.hi()), + "String".to_string(), + )]; + } + Some(Res::PrimTy(..)) => {} + Some(Res::Def( + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::ForeignTy + | DefKind::AssocTy + | DefKind::OpaqueTy + | DefKind::TyParam, + _, + )) => {} + _ => { + // Do not suggest in all other cases. + owned_sugg = false; + } + } + } + PathResult::NonModule(res) => { + match res.base_res() { + Res::PrimTy(PrimTy::Str) => { + // Don't suggest `-> str`, suggest `-> String`. + sugg = vec![( + lt.span.with_hi(ty.span.hi()), + "String".to_string(), + )]; + } + Res::PrimTy(..) => {} + Res::Def( + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::ForeignTy + | DefKind::AssocTy + | DefKind::OpaqueTy + | DefKind::TyParam, + _, + ) => {} + _ => { + // Do not suggest in all other cases. + owned_sugg = false; + } + } + } + _ => { + // Do not suggest in all other cases. + owned_sugg = false; + } + } + } + if let TyKind::Slice(inner_ty) = &ty.kind { + // Don't suggest `-> [T]`, suggest `-> Vec`. + sugg = vec![ + (lt.span.with_hi(inner_ty.span.lo()), "Vec<".to_string()), + (ty.span.with_lo(inner_ty.span.hi()), ">".to_string()), + ]; + } + } + } + if owned_sugg { + err.multipart_suggestion_verbose( + format!("{pre} to return an owned value"), + sugg, + Applicability::MaybeIncorrect, + ); + } + } + } // Record as using the suggested resolution. let (_, (_, res)) = in_scope_lifetimes[0]; @@ -2996,7 +3225,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn mk_where_bound_predicate( path: &Path, poly_trait_ref: &ast::PolyTraitRef, - ty: &ast::Ty, + ty: &Ty, ) -> Option { use rustc_span::DUMMY_SP; let modified_segments = { @@ -3073,6 +3302,24 @@ pub(super) fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: I err.emit(); } +struct LifetimeFinder<'ast> { + lifetime: Span, + found: Option<&'ast Ty>, + seen: Vec<&'ast Ty>, +} + +impl<'ast> Visitor<'ast> for LifetimeFinder<'ast> { + fn visit_ty(&mut self, t: &'ast Ty) { + if let TyKind::Ref(_, mut_ty) = &t.kind { + self.seen.push(t); + if t.span.lo() == self.lifetime.lo() { + self.found = Some(&mut_ty.ty); + } + } + walk_ty(self, t) + } +} + /// Shadowing involving a label is only a warning for historical reasons. //FIXME: make this a proper lint. pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 8fa0dceda8742..4988222c135eb 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -3525,20 +3525,30 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => { - let ty::ConstKind::Unevaluated(uv) = ct.kind() else { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => match ct.kind() { + ty::ConstKind::Unevaluated(uv) => { + let mut err = + self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); + let const_span = self.tcx.def_span(uv.def); + match self.tcx.sess.source_map().span_to_snippet(const_span) { + Ok(snippet) => err.help(format!( + "try adding a `where` bound using this expression: `where [(); {snippet}]:`" + )), + _ => err.help("consider adding a `where` bound using this expression"), + }; + Some(err) + } + ty::ConstKind::Expr(_) => { + let err = self + .tcx + .sess + .struct_span_err(span, format!("unconstrained generic constant `{ct}`")); + Some(err) + } + _ => { bug!("const evaluatable failed for non-unevaluated const `{ct:?}`"); - }; - let mut err = self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); - let const_span = self.tcx.def_span(uv.def); - match self.tcx.sess.source_map().span_to_snippet(const_span) { - Ok(snippet) => err.help(format!( - "try adding a `where` bound using this expression: `where [(); {snippet}]:`" - )), - _ => err.help("consider adding a `where` bound using this expression"), - }; - Some(err) - } + } + }, _ => { span_bug!( span, diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index a521bf66bedd8..f2875b7f01e45 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -298,10 +298,6 @@ function initSearch(rawSearchIndex) { return "=,>-]".indexOf(c) !== -1; } - function isStopCharacter(c) { - return isEndCharacter(c); - } - function isErrorCharacter(c) { return "()".indexOf(c) !== -1; } @@ -617,8 +613,7 @@ function initSearch(rawSearchIndex) { } } else if ( c === "[" || - c === "=" || - isStopCharacter(c) || + isEndCharacter(c) || isSpecialStartCharacter(c) || isSeparatorCharacter(c) ) { @@ -917,7 +912,7 @@ function initSearch(rawSearchIndex) { while (parserState.pos < parserState.length) { const c = parserState.userQuery[parserState.pos]; - if (isStopCharacter(c)) { + if (isEndCharacter(c)) { foundStopChar = true; if (isSeparatorCharacter(c)) { parserState.pos += 1; diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index dfa386b49de7c..40149f8f1c3b6 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -11,7 +11,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: usize = 1852; -const ROOT_ENTRY_LIMIT: usize = 867; +const ROOT_ENTRY_LIMIT: usize = 866; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/incremental/thinlto/cgu_invalidated_via_import.rs b/tests/incremental/thinlto/cgu_invalidated_via_import.rs index 5fe435d796f56..e0cd385eff3b9 100644 --- a/tests/incremental/thinlto/cgu_invalidated_via_import.rs +++ b/tests/incremental/thinlto/cgu_invalidated_via_import.rs @@ -4,7 +4,7 @@ // revisions: cfail1 cfail2 cfail3 // compile-flags: -Z query-dep-graph -O -// build-pass (FIXME(62277): could be check-pass?) +// build-pass #![feature(rustc_attrs)] #![crate_type="rlib"] diff --git a/tests/incremental/thinlto/cgu_keeps_identical_fn.rs b/tests/incremental/thinlto/cgu_keeps_identical_fn.rs index 368a726ea904d..781aae578d443 100644 --- a/tests/incremental/thinlto/cgu_keeps_identical_fn.rs +++ b/tests/incremental/thinlto/cgu_keeps_identical_fn.rs @@ -5,7 +5,7 @@ // revisions: cfail1 cfail2 cfail3 // compile-flags: -Z query-dep-graph -O -// build-pass (FIXME(62277): could be check-pass?) +// build-pass #![feature(rustc_attrs)] #![crate_type = "rlib"] diff --git a/tests/incremental/thinlto/independent_cgus_dont_affect_each_other.rs b/tests/incremental/thinlto/independent_cgus_dont_affect_each_other.rs index 045f2011958bd..8aa036ec97876 100644 --- a/tests/incremental/thinlto/independent_cgus_dont_affect_each_other.rs +++ b/tests/incremental/thinlto/independent_cgus_dont_affect_each_other.rs @@ -3,7 +3,7 @@ // revisions: cfail1 cfail2 cfail3 // compile-flags: -Z query-dep-graph -O -// build-pass (FIXME(62277): could be check-pass?) +// build-pass #![feature(rustc_attrs)] #![crate_type="rlib"] diff --git a/tests/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr b/tests/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr index 8ccfb2122167b..24fd38f31adf2 100644 --- a/tests/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr +++ b/tests/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr @@ -5,10 +5,15 @@ LL | fn elision &i32>() { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn elision &'static i32>() { | +++++++ +help: instead, you are more likely to want to return an owned value + | +LL - fn elision &i32>() { +LL + fn elision i32>() { + | error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/bound-lifetime-in-return-only.elision.stderr b/tests/ui/associated-types/bound-lifetime-in-return-only.elision.stderr index 0593a62a75074..d24378487e777 100644 --- a/tests/ui/associated-types/bound-lifetime-in-return-only.elision.stderr +++ b/tests/ui/associated-types/bound-lifetime-in-return-only.elision.stderr @@ -5,10 +5,15 @@ LL | fn elision(_: fn() -> &i32) { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn elision(_: fn() -> &'static i32) { | +++++++ +help: instead, you are more likely to want to return an owned value + | +LL - fn elision(_: fn() -> &i32) { +LL + fn elision(_: fn() -> i32) { + | error: aborting due to 1 previous error diff --git a/tests/ui/attributes/issue-90873.rs b/tests/ui/attributes/issue-90873.rs index 1411f61744d25..53339ce7e28fb 100644 --- a/tests/ui/attributes/issue-90873.rs +++ b/tests/ui/attributes/issue-90873.rs @@ -1,9 +1,9 @@ #![u=||{static d=||1;}] -//~^ unexpected expression +//~^ attribute value must be a literal //~| cannot find attribute `u` in this scope //~| missing type for `static` item #![a={impl std::ops::Neg for i8 {}}] -//~^ ERROR unexpected expression +//~^ ERROR attribute value must be a literal //~| ERROR cannot find attribute `a` in this scope //~| ERROR `main` function not found in crate `issue_90873` diff --git a/tests/ui/attributes/issue-90873.stderr b/tests/ui/attributes/issue-90873.stderr index 894ec8341f8e0..5a8bbaf8ec191 100644 --- a/tests/ui/attributes/issue-90873.stderr +++ b/tests/ui/attributes/issue-90873.stderr @@ -1,15 +1,10 @@ -error: unexpected expression: `|| - { - static d: _ = || 1; - }` +error: attribute value must be a literal --> $DIR/issue-90873.rs:1:6 | LL | #![u=||{static d=||1;}] | ^^^^^^^^^^^^^^^^^ -error: unexpected expression: `{ - impl std::ops::Neg for i8 {} - }` +error: attribute value must be a literal --> $DIR/issue-90873.rs:6:6 | LL | #![a={impl std::ops::Neg for i8 {}}] diff --git a/tests/ui/attributes/key-value-expansion-on-mac.rs b/tests/ui/attributes/key-value-expansion-on-mac.rs index c1d68d8cda9e7..ea7cf7c4f640f 100644 --- a/tests/ui/attributes/key-value-expansion-on-mac.rs +++ b/tests/ui/attributes/key-value-expansion-on-mac.rs @@ -7,8 +7,8 @@ macro_rules! bar { // FIXME?: `bar` here expands before `stringify` has a chance to expand. // `#[rustc_dummy = ...]` is validated and dropped during expansion of `bar`, -// the "unexpected expression" errors comes from the validation. -#[rustc_dummy = stringify!(b)] //~ ERROR unexpected expression: `stringify!(b)` +// the "attribute value must be a literal" error comes from the validation. +#[rustc_dummy = stringify!(b)] //~ ERROR attribute value must be a literal bar!(); fn main() {} diff --git a/tests/ui/attributes/key-value-expansion-on-mac.stderr b/tests/ui/attributes/key-value-expansion-on-mac.stderr index 7d817da13626d..260462cfeefac 100644 --- a/tests/ui/attributes/key-value-expansion-on-mac.stderr +++ b/tests/ui/attributes/key-value-expansion-on-mac.stderr @@ -1,4 +1,4 @@ -error: unexpected expression: `stringify!(b)` +error: attribute value must be a literal --> $DIR/key-value-expansion-on-mac.rs:11:17 | LL | #[rustc_dummy = stringify!(b)] diff --git a/tests/ui/attributes/key-value-expansion.rs b/tests/ui/attributes/key-value-expansion.rs index 83d601e5e3a79..3065c12749c2c 100644 --- a/tests/ui/attributes/key-value-expansion.rs +++ b/tests/ui/attributes/key-value-expansion.rs @@ -18,13 +18,13 @@ macro_rules! bug { // Any expressions containing macro call `X` that's more complex than `X` itself. // Parentheses will work. -bug!((column!())); //~ ERROR unexpected expression: `(7u32)` +bug!((column!())); //~ ERROR attribute value must be a literal // Original test case. macro_rules! bug { () => { - bug!("bug" + stringify!(found)); //~ ERROR unexpected expression: `"bug" + "found"` + bug!("bug" + stringify!(found)); //~ ERROR attribute value must be a literal }; ($test:expr) => { #[doc = $test] @@ -46,7 +46,7 @@ macro_rules! doc_comment { macro_rules! some_macro { ($t1: ty) => { doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()} - //~^ ERROR unexpected expression: `{ + //~^ ERROR attribute value must be a literal }; } diff --git a/tests/ui/attributes/key-value-expansion.stderr b/tests/ui/attributes/key-value-expansion.stderr index aaa8b169583fd..54d79c5bebb7f 100644 --- a/tests/ui/attributes/key-value-expansion.stderr +++ b/tests/ui/attributes/key-value-expansion.stderr @@ -1,10 +1,10 @@ -error: unexpected expression: `(7u32)` +error: attribute value must be a literal --> $DIR/key-value-expansion.rs:21:6 | LL | bug!((column!())); | ^^^^^^^^^^^ -error: unexpected expression: `"bug" + "found"` +error: attribute value must be a literal --> $DIR/key-value-expansion.rs:27:14 | LL | bug!("bug" + stringify!(found)); @@ -15,7 +15,7 @@ LL | bug!(); | = note: this error originates in the macro `bug` (in Nightly builds, run with -Z macro-backtrace for more info) -error: unexpected expression: `{ let res = ::alloc::fmt::format(format_args!("{0}", "u8")); res }.as_str()` +error: attribute value must be a literal --> $DIR/key-value-expansion.rs:48:23 | LL | doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()} diff --git a/tests/ui/attributes/unused-item-in-attr.rs b/tests/ui/attributes/unused-item-in-attr.rs index 70dcd5413f1ee..fda0a5d6a3f16 100644 --- a/tests/ui/attributes/unused-item-in-attr.rs +++ b/tests/ui/attributes/unused-item-in-attr.rs @@ -1,5 +1,5 @@ #[w = { extern crate alloc; }] -//~^ ERROR unexpected expression: `{ +//~^ ERROR attribute value must be a literal //~| ERROR cannot find attribute `w` in this scope fn f() {} diff --git a/tests/ui/attributes/unused-item-in-attr.stderr b/tests/ui/attributes/unused-item-in-attr.stderr index 92a8f58582136..84130965d31cf 100644 --- a/tests/ui/attributes/unused-item-in-attr.stderr +++ b/tests/ui/attributes/unused-item-in-attr.stderr @@ -1,6 +1,4 @@ -error: unexpected expression: `{ - extern crate alloc; - }` +error: attribute value must be a literal --> $DIR/unused-item-in-attr.rs:1:7 | LL | #[w = { extern crate alloc; }] diff --git a/tests/ui/c-variadic/variadic-ffi-6.stderr b/tests/ui/c-variadic/variadic-ffi-6.stderr index 1ceff5704786d..344bfed4b42a2 100644 --- a/tests/ui/c-variadic/variadic-ffi-6.stderr +++ b/tests/ui/c-variadic/variadic-ffi-6.stderr @@ -5,10 +5,19 @@ LL | ) -> &usize { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | ) -> &'static usize { | +++++++ +help: instead, you are more likely to want to change one of the arguments to be borrowed... + | +LL | x: &usize, + | + +help: ...or alternatively, you might want to return an owned value + | +LL - ) -> &usize { +LL + ) -> usize { + | error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.rs b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.rs new file mode 100644 index 0000000000000..6256000b4919b --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.rs @@ -0,0 +1,25 @@ +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +fn foo( + _: [u8; { + { + N + } + }], +) { +} + +fn ice() +where + [(); (L - 1) + 1 + L]:, +{ + foo::<_, L>([(); L + 1 + L]); + //~^ ERROR: mismatched types + //~^^ ERROR: unconstrained generic constant + //~^^^ ERROR: function takes 1 generic argument but 2 generic arguments were supplied + //~^^^^ ERROR: unconstrained generic constant + //~^^^^^ ERROR: unconstrained generic constant `{const expr}` +} + +fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr new file mode 100644 index 0000000000000..6001d8247876a --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr @@ -0,0 +1,64 @@ +error[E0107]: function takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/issue_114151.rs:17:5 + | +LL | foo::<_, L>([(); L + 1 + L]); + | ^^^ - help: remove this generic argument + | | + | expected 1 generic argument + | +note: function defined here, with 1 generic parameter: `N` + --> $DIR/issue_114151.rs:4:4 + | +LL | fn foo( + | ^^^ -------------- + +error[E0308]: mismatched types + --> $DIR/issue_114151.rs:17:18 + | +LL | foo::<_, L>([(); L + 1 + L]); + | ^^ expected `u8`, found `()` + +error: unconstrained generic constant + --> $DIR/issue_114151.rs:17:22 + | +LL | foo::<_, L>([(); L + 1 + L]); + | ^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); L + 1 + L]:` + +error: unconstrained generic constant + --> $DIR/issue_114151.rs:17:17 + | +LL | foo::<_, L>([(); L + 1 + L]); + | ----------- ^^^^^^^^^^^^^^^ + | | + | required by a bound introduced by this call + | + = help: try adding a `where` bound using this expression: `where [(); { + { + N + } + }]:` +note: required by a bound in `foo` + --> $DIR/issue_114151.rs:5:13 + | +LL | fn foo( + | --- required by a bound in this function +LL | _: [u8; { + | _____________^ +LL | | { +LL | | N +LL | | } +LL | | }], + | |_____^ required by this bound in `foo` + +error: unconstrained generic constant `{const expr}` + --> $DIR/issue_114151.rs:17:5 + | +LL | foo::<_, L>([(); L + 1 + L]); + | ^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0107, E0308. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/consts/issue-90878-2.rs b/tests/ui/consts/issue-90878-2.rs index e5bcecce6ee8f..0e61c65305fbe 100644 --- a/tests/ui/consts/issue-90878-2.rs +++ b/tests/ui/consts/issue-90878-2.rs @@ -1,4 +1,4 @@ - #![l=|x|[b;x ]] //~ ERROR unexpected expression: `|x| [b; x]` + #![l=|x|[b;x ]] //~ ERROR attribute value must be a literal //~^ ERROR cannot find attribute `l` in this scope // notice the space at the start, diff --git a/tests/ui/consts/issue-90878-2.stderr b/tests/ui/consts/issue-90878-2.stderr index 71b8d21fb4dc2..0b332840042ef 100644 --- a/tests/ui/consts/issue-90878-2.stderr +++ b/tests/ui/consts/issue-90878-2.stderr @@ -1,4 +1,4 @@ -error: unexpected expression: `|x| [b; x]` +error: attribute value must be a literal --> $DIR/issue-90878-2.rs:1:7 | LL | #![l=|x|[b;x ]] diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.rs b/tests/ui/feature-gates/feature-gate-never_patterns.rs index ca5ce3b948943..f3910622313d5 100644 --- a/tests/ui/feature-gates/feature-gate-never_patterns.rs +++ b/tests/ui/feature-gates/feature-gate-never_patterns.rs @@ -12,16 +12,63 @@ fn main() { unsafe { let ptr: *const Void = NonNull::dangling().as_ptr(); match *ptr { - ! //~ ERROR `!` patterns are experimental + ! + //~^ ERROR `!` patterns are experimental + } + // Check that the gate operates even behind `cfg`. + #[cfg(FALSE)] + match *ptr { + ! + //~^ ERROR `!` patterns are experimental + } + #[cfg(FALSE)] + match *ptr { + ! => {} + //~^ ERROR `!` patterns are experimental } } + // Correctly gate match arms with no body. + match Some(0) { + None => {} + Some(_), + //~^ ERROR unexpected `,` in pattern + } + match Some(0) { + None => {} + Some(_) + //~^ ERROR `match` arm with no body + } + match Some(0) { + _ => {} + Some(_) if false, + //~^ ERROR `match` arm with no body + Some(_) if false + //~^ ERROR `match` arm with no body + } + match res { + Ok(_) => {} + Err(!), + //~^ ERROR `!` patterns are experimental + } + match res { + Err(!) if false, + //~^ ERROR `!` patterns are experimental + //~| ERROR a guard on a never pattern will never be run + _ => {} + } + // Check that the gate operates even behind `cfg`. - #[cfg(FALSE)] - unsafe { - let ptr: *const Void = NonNull::dangling().as_ptr(); - match *ptr { - ! => {} //~ ERROR `!` patterns are experimental - } + match Some(0) { + None => {} + #[cfg(FALSE)] + Some(_) + //~^ ERROR `match` arm with no body + } + match Some(0) { + _ => {} + #[cfg(FALSE)] + Some(_) if false + //~^ ERROR `match` arm with no body } } diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.stderr b/tests/ui/feature-gates/feature-gate-never_patterns.stderr index 2354a3b0476d8..dd10829d49594 100644 --- a/tests/ui/feature-gates/feature-gate-never_patterns.stderr +++ b/tests/ui/feature-gates/feature-gate-never_patterns.stderr @@ -1,3 +1,18 @@ +error: unexpected `,` in pattern + --> $DIR/feature-gate-never_patterns.rs:34:16 + | +LL | Some(_), + | ^ + | +help: try adding parentheses to match on a tuple... + | +LL | (Some(_),) + | + + +help: ...or a vertical bar to match on multiple alternatives + | +LL | Some(_) | + | + error[E0408]: variable `_x` is not bound in all patterns --> $DIR/feature-gate-never_patterns.rs:8:19 | @@ -25,7 +40,16 @@ LL | ! = help: add `#![feature(never_patterns)]` to the crate attributes to enable error[E0658]: `!` patterns are experimental - --> $DIR/feature-gate-never_patterns.rs:24:13 + --> $DIR/feature-gate-never_patterns.rs:21:13 + | +LL | ! + | ^ + | + = note: see issue #118155 for more information + = help: add `#![feature(never_patterns)]` to the crate attributes to enable + +error[E0658]: `!` patterns are experimental + --> $DIR/feature-gate-never_patterns.rs:26:13 | LL | ! => {} | ^ @@ -33,7 +57,61 @@ LL | ! => {} = note: see issue #118155 for more information = help: add `#![feature(never_patterns)]` to the crate attributes to enable -error: aborting due to 4 previous errors +error: `match` arm with no body + --> $DIR/feature-gate-never_patterns.rs:39:9 + | +LL | Some(_) + | ^^^^^^^- help: add a body after the pattern: `=> todo!(),` + +error: `match` arm with no body + --> $DIR/feature-gate-never_patterns.rs:44:9 + | +LL | Some(_) if false, + | ^^^^^^^- help: add a body after the pattern: `=> todo!(),` + +error: `match` arm with no body + --> $DIR/feature-gate-never_patterns.rs:46:9 + | +LL | Some(_) if false + | ^^^^^^^- help: add a body after the pattern: `=> todo!(),` + +error[E0658]: `!` patterns are experimental + --> $DIR/feature-gate-never_patterns.rs:51:13 + | +LL | Err(!), + | ^ + | + = note: see issue #118155 for more information + = help: add `#![feature(never_patterns)]` to the crate attributes to enable + +error[E0658]: `!` patterns are experimental + --> $DIR/feature-gate-never_patterns.rs:55:13 + | +LL | Err(!) if false, + | ^ + | + = note: see issue #118155 for more information + = help: add `#![feature(never_patterns)]` to the crate attributes to enable + +error: `match` arm with no body + --> $DIR/feature-gate-never_patterns.rs:65:9 + | +LL | Some(_) + | ^^^^^^^- help: add a body after the pattern: `=> todo!(),` + +error: `match` arm with no body + --> $DIR/feature-gate-never_patterns.rs:71:9 + | +LL | Some(_) if false + | ^^^^^^^- help: add a body after the pattern: `=> todo!(),` + +error: a guard on a never pattern will never be run + --> $DIR/feature-gate-never_patterns.rs:55:19 + | +LL | Err(!) if false, + | ^^^^^ help: remove this guard + +error: aborting due to 14 previous errors Some errors have detailed explanations: E0408, E0658. For more information about an error, try `rustc --explain E0408`. diff --git a/tests/ui/foreign-fn-return-lifetime.fixed b/tests/ui/foreign-fn-return-lifetime.fixed deleted file mode 100644 index 143d6343d26cd..0000000000000 --- a/tests/ui/foreign-fn-return-lifetime.fixed +++ /dev/null @@ -1,8 +0,0 @@ -// run-rustfix - -extern "C" { - pub fn g(_: &u8) -> &u8; // OK - pub fn f() -> &'static u8; //~ ERROR missing lifetime specifier -} - -fn main() {} diff --git a/tests/ui/foreign-fn-return-lifetime.rs b/tests/ui/foreign-fn-return-lifetime.rs index 76fe50a340ae4..35595bab36d42 100644 --- a/tests/ui/foreign-fn-return-lifetime.rs +++ b/tests/ui/foreign-fn-return-lifetime.rs @@ -1,5 +1,3 @@ -// run-rustfix - extern "C" { pub fn g(_: &u8) -> &u8; // OK pub fn f() -> &u8; //~ ERROR missing lifetime specifier diff --git a/tests/ui/foreign-fn-return-lifetime.stderr b/tests/ui/foreign-fn-return-lifetime.stderr index 43edcbde35c6b..e24c0f23c3518 100644 --- a/tests/ui/foreign-fn-return-lifetime.stderr +++ b/tests/ui/foreign-fn-return-lifetime.stderr @@ -1,14 +1,19 @@ error[E0106]: missing lifetime specifier - --> $DIR/foreign-fn-return-lifetime.rs:5:19 + --> $DIR/foreign-fn-return-lifetime.rs:3:19 | LL | pub fn f() -> &u8; | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | pub fn f() -> &'static u8; | +++++++ +help: instead, you are more likely to want to return an owned value + | +LL - pub fn f() -> &u8; +LL + pub fn f() -> u8; + | error: aborting due to 1 previous error diff --git a/tests/ui/generic-associated-types/issue-70304.stderr b/tests/ui/generic-associated-types/issue-70304.stderr index 99339e9685959..9b02c1b076837 100644 --- a/tests/ui/generic-associated-types/issue-70304.stderr +++ b/tests/ui/generic-associated-types/issue-70304.stderr @@ -11,7 +11,7 @@ LL | fn create_doc() -> impl Document = DocCursorImpl<'_>> { | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values | LL | fn create_doc() -> impl Document = DocCursorImpl<'static>> { | ~~~~~~~ diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr index 443ffeb55cdee..a5982a5542a54 100644 --- a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr +++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr @@ -5,7 +5,7 @@ LL | fn d() -> impl Fn() -> (impl Debug + '_) { | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values | LL | fn d() -> impl Fn() -> (impl Debug + 'static) { | ~~~~~~~ diff --git a/tests/ui/issues/issue-13497.stderr b/tests/ui/issues/issue-13497.stderr index 236e6b48607f9..fb3de637a7985 100644 --- a/tests/ui/issues/issue-13497.stderr +++ b/tests/ui/issues/issue-13497.stderr @@ -5,10 +5,14 @@ LL | &str | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | &'static str | +++++++ +help: instead, you are more likely to want to return an owned value + | +LL | String + | ~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/issue-26638.stderr b/tests/ui/lifetimes/issue-26638.stderr index e61158a5d4d02..ee958686259aa 100644 --- a/tests/ui/lifetimes/issue-26638.stderr +++ b/tests/ui/lifetimes/issue-26638.stderr @@ -17,10 +17,18 @@ LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &'static str { iter() } | +++++++ +help: instead, you are more likely to want to change the argument to be borrowed... + | +LL | fn parse_type_2(iter: &fn(&u8)->&u8) -> &str { iter() } + | + +help: ...or alternatively, you might want to return an owned value + | +LL | fn parse_type_2(iter: fn(&u8)->&u8) -> String { iter() } + | ~~~~~~ error[E0106]: missing lifetime specifier --> $DIR/issue-26638.rs:10:22 @@ -29,10 +37,14 @@ LL | fn parse_type_3() -> &str { unimplemented!() } | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn parse_type_3() -> &'static str { unimplemented!() } | +++++++ +help: instead, you are more likely to want to return an owned value + | +LL | fn parse_type_3() -> String { unimplemented!() } + | ~~~~~~ error[E0308]: mismatched types --> $DIR/issue-26638.rs:1:69 diff --git a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr index 5eee953ef189f..23ef36888f079 100644 --- a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr +++ b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr @@ -5,10 +5,15 @@ LL | fn f() -> &isize { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn f() -> &'static isize { | +++++++ +help: instead, you are more likely to want to return an owned value + | +LL - fn f() -> &isize { +LL + fn f() -> isize { + | error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33 @@ -41,10 +46,19 @@ LL | fn i(_x: isize) -> &isize { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn i(_x: isize) -> &'static isize { | +++++++ +help: instead, you are more likely to want to change the argument to be borrowed... + | +LL | fn i(_x: &isize) -> &isize { + | + +help: ...or alternatively, you might want to return an owned value + | +LL - fn i(_x: isize) -> &isize { +LL + fn i(_x: isize) -> isize { + | error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:34:24 @@ -53,10 +67,19 @@ LL | fn j(_x: StaticStr) -> &isize { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn j(_x: StaticStr) -> &'static isize { | +++++++ +help: instead, you are more likely to want to change the argument to be borrowed... + | +LL | fn j(_x: &StaticStr) -> &isize { + | + +help: ...or alternatively, you might want to return an owned value + | +LL - fn j(_x: StaticStr) -> &isize { +LL + fn j(_x: StaticStr) -> isize { + | error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:40:49 diff --git a/tests/ui/malformed/malformed-interpolated.rs b/tests/ui/malformed/malformed-interpolated.rs index 0d84e723fc3dd..0d801ebd3ac9a 100644 --- a/tests/ui/malformed/malformed-interpolated.rs +++ b/tests/ui/malformed/malformed-interpolated.rs @@ -10,7 +10,7 @@ macro_rules! check { check!("0"); // OK check!(0); // OK check!(0u8); //~ ERROR suffixed literals are not allowed in attributes -check!(-0); //~ ERROR unexpected expression: `-0` -check!(0 + 0); //~ ERROR unexpected expression: `0 + 0` +check!(-0); //~ ERROR attribute value must be a literal +check!(0 + 0); //~ ERROR attribute value must be a literal fn main() {} diff --git a/tests/ui/malformed/malformed-interpolated.stderr b/tests/ui/malformed/malformed-interpolated.stderr index c24d9f15388fc..92e99b7a70b34 100644 --- a/tests/ui/malformed/malformed-interpolated.stderr +++ b/tests/ui/malformed/malformed-interpolated.stderr @@ -6,13 +6,13 @@ LL | check!(0u8); | = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) -error: unexpected expression: `-0` +error: attribute value must be a literal --> $DIR/malformed-interpolated.rs:13:8 | LL | check!(-0); | ^^ -error: unexpected expression: `0 + 0` +error: attribute value must be a literal --> $DIR/malformed-interpolated.rs:14:8 | LL | check!(0 + 0); diff --git a/tests/ui/parser/bad-lit-suffixes.rs b/tests/ui/parser/bad-lit-suffixes.rs index 8cb9ef7e0c921..c614f49388574 100644 --- a/tests/ui/parser/bad-lit-suffixes.rs +++ b/tests/ui/parser/bad-lit-suffixes.rs @@ -28,11 +28,12 @@ fn main() { } #[rustc_dummy = "string"suffix] -//~^ ERROR unexpected expression: `"string"suffix` +//~^ ERROR suffixes on string literals are invalid fn f() {} #[must_use = "string"suffix] -//~^ ERROR unexpected expression: `"string"suffix` +//~^ ERROR suffixes on string literals are invalid +//~| ERROR malformed `must_use` attribute input fn g() {} #[link(name = "string"suffix)] diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr index 756f99ab12c82..b5dacdf7d0d3d 100644 --- a/tests/ui/parser/bad-lit-suffixes.stderr +++ b/tests/ui/parser/bad-lit-suffixes.stderr @@ -10,26 +10,39 @@ error: suffixes on string literals are invalid LL | "C"suffix | ^^^^^^^^^ invalid suffix `suffix` -error: unexpected expression: `"string"suffix` +error: suffixes on string literals are invalid --> $DIR/bad-lit-suffixes.rs:30:17 | LL | #[rustc_dummy = "string"suffix] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ invalid suffix `suffix` -error: unexpected expression: `"string"suffix` +error: suffixes on string literals are invalid --> $DIR/bad-lit-suffixes.rs:34:14 | LL | #[must_use = "string"suffix] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ invalid suffix `suffix` + +error: malformed `must_use` attribute input + --> $DIR/bad-lit-suffixes.rs:34:1 + | +LL | #[must_use = "string"suffix] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[must_use = "reason"] + | +LL | #[must_use] + | error: suffixes on string literals are invalid - --> $DIR/bad-lit-suffixes.rs:38:15 + --> $DIR/bad-lit-suffixes.rs:39:15 | LL | #[link(name = "string"suffix)] | ^^^^^^^^^^^^^^ invalid suffix `suffix` error: invalid suffix `suffix` for number literal - --> $DIR/bad-lit-suffixes.rs:42:41 + --> $DIR/bad-lit-suffixes.rs:43:41 | LL | #[rustc_layout_scalar_valid_range_start(0suffix)] | ^^^^^^^ invalid suffix `suffix` @@ -136,5 +149,5 @@ LL | 1.0e10suffix; | = help: valid suffixes are `f32` and `f64` -error: aborting due to 20 previous errors +error: aborting due to 21 previous errors diff --git a/tests/ui/parser/issues/issue-104620.rs b/tests/ui/parser/issues/issue-104620.rs index f49476c44084c..fd0916b44110a 100644 --- a/tests/ui/parser/issues/issue-104620.rs +++ b/tests/ui/parser/issues/issue-104620.rs @@ -1,4 +1,4 @@ #![feature(rustc_attrs)] -#![rustc_dummy=5z] //~ ERROR unexpected expression: `5z` +#![rustc_dummy=5z] //~ ERROR invalid suffix `z` for number literal fn main() {} diff --git a/tests/ui/parser/issues/issue-104620.stderr b/tests/ui/parser/issues/issue-104620.stderr index fa20b5f8b1625..040c63a5fbfbf 100644 --- a/tests/ui/parser/issues/issue-104620.stderr +++ b/tests/ui/parser/issues/issue-104620.stderr @@ -1,8 +1,10 @@ -error: unexpected expression: `5z` +error: invalid suffix `z` for number literal --> $DIR/issue-104620.rs:3:16 | LL | #![rustc_dummy=5z] - | ^^ + | ^^ invalid suffix `z` + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) error: aborting due to 1 previous error diff --git a/tests/ui/parser/match-arm-without-body.rs b/tests/ui/parser/match-arm-without-body.rs index c3487c2c658ba..4723abff8b6ae 100644 --- a/tests/ui/parser/match-arm-without-body.rs +++ b/tests/ui/parser/match-arm-without-body.rs @@ -66,8 +66,6 @@ fn main() { pat!() //~^ ERROR expected `,` following `match` arm //~| HELP missing a comma here - //~| ERROR `match` arm with no body - //~| HELP add a body after the pattern _ => {} } match Some(false) { diff --git a/tests/ui/parser/match-arm-without-body.stderr b/tests/ui/parser/match-arm-without-body.stderr index 3a06ed050b562..d98c7ec282601 100644 --- a/tests/ui/parser/match-arm-without-body.stderr +++ b/tests/ui/parser/match-arm-without-body.stderr @@ -68,19 +68,19 @@ error: `match` arm with no body --> $DIR/match-arm-without-body.rs:30:9 | LL | Some(_) if true - | ^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),` + | ^^^^^^^- help: add a body after the pattern: `=> todo!(),` error: `match` arm with no body --> $DIR/match-arm-without-body.rs:40:9 | LL | Some(_) if true, - | ^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),` + | ^^^^^^^- help: add a body after the pattern: `=> todo!(),` error: `match` arm with no body --> $DIR/match-arm-without-body.rs:45:9 | LL | Some(_) if true, - | ^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),` + | ^^^^^^^- help: add a body after the pattern: `=> todo!(),` error: `match` arm with no body --> $DIR/match-arm-without-body.rs:51:9 @@ -98,19 +98,13 @@ error: `match` arm with no body --> $DIR/match-arm-without-body.rs:61:9 | LL | pat!() if true, - | ^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),` - -error: `match` arm with no body - --> $DIR/match-arm-without-body.rs:66:9 - | -LL | pat!() | ^^^^^^- help: add a body after the pattern: `=> todo!(),` error: `match` arm with no body - --> $DIR/match-arm-without-body.rs:74:9 + --> $DIR/match-arm-without-body.rs:72:9 | LL | pat!(), | ^^^^^^- help: add a body after the pattern: `=> todo!(),` -error: aborting due to 14 previous errors +error: aborting due to 13 previous errors diff --git a/tests/ui/self/elision/nested-item.stderr b/tests/ui/self/elision/nested-item.stderr index 752fd82332c38..7bad26fa13303 100644 --- a/tests/ui/self/elision/nested-item.stderr +++ b/tests/ui/self/elision/nested-item.stderr @@ -21,10 +21,19 @@ LL | fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &() { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &'static () { | +++++++ +help: instead, you are more likely to want to change the argument to be borrowed... + | +LL | fn wrap(self: &Wrap<{ fn bar(&self) {} }>) -> &() { + | + +help: ...or alternatively, you might want to return an owned value + | +LL - fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &() { +LL + fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> () { + | error[E0412]: cannot find type `Wrap` in this scope --> $DIR/nested-item.rs:5:15 diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr index 50806a6725500..2dfaa7311948f 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr @@ -5,10 +5,19 @@ LL | fn g(mut x: impl Iterator) -> Option<&()> { x.next() } | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn g(mut x: impl Iterator) -> Option<&'static ()> { x.next() } | +++++++ +help: consider introducing a named lifetime parameter + | +LL | fn g<'a>(mut x: impl Iterator) -> Option<&'a ()> { x.next() } + | ++++ ~~~ ~~~ +help: alternatively, you might want to return an owned value + | +LL - fn g(mut x: impl Iterator) -> Option<&()> { x.next() } +LL + fn g(mut x: impl Iterator) -> Option<()> { x.next() } + | error[E0106]: missing lifetime specifier --> $DIR/impl-trait-missing-lifetime-gated.rs:19:60 @@ -17,10 +26,19 @@ LL | async fn i(mut x: impl Iterator) -> Option<&()> { x.next() | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | async fn i(mut x: impl Iterator) -> Option<&'static ()> { x.next() } | +++++++ +help: consider introducing a named lifetime parameter + | +LL | async fn i<'a>(mut x: impl Iterator) -> Option<&'a ()> { x.next() } + | ++++ ~~~ ~~~ +help: alternatively, you might want to return an owned value + | +LL - async fn i(mut x: impl Iterator) -> Option<&()> { x.next() } +LL + async fn i(mut x: impl Iterator) -> Option<()> { x.next() } + | error[E0106]: missing lifetime specifier --> $DIR/impl-trait-missing-lifetime-gated.rs:27:58 @@ -29,10 +47,19 @@ LL | fn g(mut x: impl Iterator) -> Option<&'_ ()> { x.next() | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values | LL | fn g(mut x: impl Iterator) -> Option<&'static ()> { x.next() } | ~~~~~~~ +help: consider introducing a named lifetime parameter + | +LL | fn g<'a>(mut x: impl Iterator) -> Option<&'a ()> { x.next() } + | ++++ ~~~ ~~~ +help: alternatively, you might want to return an owned value + | +LL - fn g(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } +LL + fn g(mut x: impl Iterator) -> Option<()> { x.next() } + | error[E0106]: missing lifetime specifier --> $DIR/impl-trait-missing-lifetime-gated.rs:37:64 @@ -41,10 +68,19 @@ LL | async fn i(mut x: impl Iterator) -> Option<&'_ ()> { x.n | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values | LL | async fn i(mut x: impl Iterator) -> Option<&'static ()> { x.next() } | ~~~~~~~ +help: consider introducing a named lifetime parameter + | +LL | async fn i<'a>(mut x: impl Iterator) -> Option<&'a ()> { x.next() } + | ++++ ~~~ ~~~ +help: alternatively, you might want to return an owned value + | +LL - async fn i(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } +LL + async fn i(mut x: impl Iterator) -> Option<()> { x.next() } + | error[E0106]: missing lifetime specifier --> $DIR/impl-trait-missing-lifetime-gated.rs:47:37 @@ -53,10 +89,19 @@ LL | fn g(mut x: impl Foo) -> Option<&()> { x.next() } | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn g(mut x: impl Foo) -> Option<&'static ()> { x.next() } | +++++++ +help: consider introducing a named lifetime parameter + | +LL | fn g<'a>(mut x: impl Foo) -> Option<&'a ()> { x.next() } + | ++++ ~~~ +help: alternatively, you might want to return an owned value + | +LL - fn g(mut x: impl Foo) -> Option<&()> { x.next() } +LL + fn g(mut x: impl Foo) -> Option<()> { x.next() } + | error[E0106]: missing lifetime specifier --> $DIR/impl-trait-missing-lifetime-gated.rs:58:41 @@ -65,10 +110,19 @@ LL | fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() } | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn g(mut x: impl Foo<()>) -> Option<&'static ()> { x.next() } | +++++++ +help: consider introducing a named lifetime parameter + | +LL | fn g<'a>(mut x: impl Foo<()>) -> Option<&'a ()> { x.next() } + | ++++ ~~~ +help: alternatively, you might want to return an owned value + | +LL - fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() } +LL + fn g(mut x: impl Foo<()>) -> Option<()> { x.next() } + | error[E0658]: anonymous lifetimes in `impl Trait` are unstable --> $DIR/impl-trait-missing-lifetime-gated.rs:6:35 diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime.stderr b/tests/ui/suggestions/impl-trait-missing-lifetime.stderr index 2c29cfa0b910f..c1dbaae0649a0 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime.stderr +++ b/tests/ui/suggestions/impl-trait-missing-lifetime.stderr @@ -5,10 +5,19 @@ LL | fn g(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values | LL | fn g(mut x: impl Iterator) -> Option<&'static ()> { x.next() } | ~~~~~~~ +help: consider introducing a named lifetime parameter + | +LL | fn g<'a>(mut x: impl Iterator) -> Option<&'a ()> { x.next() } + | ++++ ~~~ ~~~ +help: alternatively, you might want to return an owned value + | +LL - fn g(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } +LL + fn g(mut x: impl Iterator) -> Option<()> { x.next() } + | error[E0106]: missing lifetime specifier --> $DIR/impl-trait-missing-lifetime.rs:16:60 @@ -17,10 +26,19 @@ LL | async fn i(mut x: impl Iterator) -> Option<&'_ ()> { x.next( | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values | LL | async fn i(mut x: impl Iterator) -> Option<&'static ()> { x.next() } | ~~~~~~~ +help: consider introducing a named lifetime parameter + | +LL | async fn i<'a>(mut x: impl Iterator) -> Option<&'a ()> { x.next() } + | ++++ ~~~ ~~~ +help: alternatively, you might want to return an owned value + | +LL - async fn i(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } +LL + async fn i(mut x: impl Iterator) -> Option<()> { x.next() } + | error: lifetime may not live long enough --> $DIR/impl-trait-missing-lifetime.rs:16:69 diff --git a/tests/ui/suggestions/missing-lifetime-specifier.stderr b/tests/ui/suggestions/missing-lifetime-specifier.stderr index fa4bc2fa79d7c..e41f547ce9b23 100644 --- a/tests/ui/suggestions/missing-lifetime-specifier.stderr +++ b/tests/ui/suggestions/missing-lifetime-specifier.stderr @@ -5,7 +5,7 @@ LL | static a: RefCell>>> = RefCell::new(HashMap:: | ^^^ expected 2 lifetime parameters | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values | LL | static a: RefCell>>>> = RefCell::new(HashMap::new()); | ++++++++++++++++++ @@ -32,7 +32,7 @@ LL | static b: RefCell>>> = RefCell::new(HashMap: | expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | static b: RefCell>>>> = RefCell::new(HashMap::new()); | +++++++ ++++++++++++++++++ @@ -59,7 +59,7 @@ LL | static c: RefCell>>>> = RefCell::new(Hash | ^ expected 2 lifetime parameters | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values | LL | static c: RefCell>>>> = RefCell::new(HashMap::new()); | +++++++++++++++++ @@ -86,7 +86,7 @@ LL | static d: RefCell>>>> = RefCell::new(Has | expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); | +++++++ +++++++++++++++++ @@ -113,7 +113,7 @@ LL | static f: RefCell>>>> = RefCell | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | +++++++ diff --git a/tests/ui/suggestions/return-elided-lifetime.stderr b/tests/ui/suggestions/return-elided-lifetime.stderr index 273d95bc747d3..7bfffd30184f8 100644 --- a/tests/ui/suggestions/return-elided-lifetime.stderr +++ b/tests/ui/suggestions/return-elided-lifetime.stderr @@ -5,10 +5,15 @@ LL | fn f1() -> &i32 { loop {} } | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn f1() -> &'static i32 { loop {} } | +++++++ +help: instead, you are more likely to want to return an owned value + | +LL - fn f1() -> &i32 { loop {} } +LL + fn f1() -> i32 { loop {} } + | error[E0106]: missing lifetime specifiers --> $DIR/return-elided-lifetime.rs:8:14 @@ -19,7 +24,7 @@ LL | fn f1_() -> (&i32, &i32) { loop {} } | expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn f1_() -> (&'static i32, &'static i32) { loop {} } | +++++++ +++++++ @@ -31,10 +36,19 @@ LL | fn f2(a: i32, b: i32) -> &i32 { loop {} } | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn f2(a: i32, b: i32) -> &'static i32 { loop {} } | +++++++ +help: instead, you are more likely to want to change one of the arguments to be borrowed... + | +LL | fn f2(a: &i32, b: &i32) -> &i32 { loop {} } + | + + +help: ...or alternatively, you might want to return an owned value + | +LL - fn f2(a: i32, b: i32) -> &i32 { loop {} } +LL + fn f2(a: i32, b: i32) -> i32 { loop {} } + | error[E0106]: missing lifetime specifiers --> $DIR/return-elided-lifetime.rs:13:28 @@ -45,7 +59,7 @@ LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} } | expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | LL | fn f2_(a: i32, b: i32) -> (&'static i32, &'static i32) { loop {} } | +++++++ +++++++ diff --git a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr index 50401791effb8..cd74d27dcb55f 100644 --- a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -28,7 +28,7 @@ LL | fn meh() -> Box Meh<'_>> | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values | LL | fn meh() -> Box Meh<'static>> | ~~~~~~~