diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index ceebcd46a6f7f..8cea3a1db13be 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1971,16 +1971,24 @@ pub fn elided_lifetime_in_path_suggestion( insertion_span: Span, ) -> ElidedLifetimeInPathSubdiag { let expected = ExpectedLifetimeParameter { span: path_span, count: n }; + let indicate = indicate_anonymous_lifetime(source_map, n, incl_angl_brckt, insertion_span); + ElidedLifetimeInPathSubdiag { expected, indicate } +} + +pub fn indicate_anonymous_lifetime( + source_map: &SourceMap, + n: usize, + incl_angl_brckt: bool, + insertion_span: Span, +) -> Option { // Do not try to suggest anything if generated by a proc-macro. - let indicate = source_map.is_span_accessible(insertion_span).then(|| { + source_map.is_span_accessible(insertion_span).then(|| { let anon_lts = vec!["'_"; n].join(", "); let suggestion = if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") }; IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion } - }); - - ElidedLifetimeInPathSubdiag { expected, indicate } + }) } pub fn report_ambiguity_error<'a, G: EmissionGuarantee>( diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 7a394a6d6c1ad..c350a8ccd2c7d 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -290,6 +290,8 @@ lint_hidden_glob_reexport = private item shadows public glob re-export lint_hidden_lifetime_parameters = hidden lifetime parameters in types are deprecated +lint_hidden_lifetime_parameters_tied_source = the lifetime comes from here + lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label} .label = this {$label} contains {$count -> [one] an invisible diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index f289d4c81b3c1..80c57c840b453 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -5,7 +5,8 @@ use std::borrow::Cow; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_errors::{ - elided_lifetime_in_path_suggestion, Applicability, Diag, DiagArgValue, LintDiagnostic, + elided_lifetime_in_path_suggestion, indicate_anonymous_lifetime, Applicability, Diag, + DiagArgValue, ExpectedLifetimeParameter, LintDiagnostic, }; use rustc_middle::middle::stability; use rustc_session::lint::BuiltinLintDiag; @@ -82,6 +83,27 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & } .decorate_lint(diag); } + + BuiltinLintDiag::ElidedLifetimesInPathsTied { elided_lifetime_source, suggestions } => { + let elided_lifetime_source = + elided_lifetime_source.map(|span| lints::ElidedLifetimesInPathsTiedSource { span }); + + let expected = suggestions + .iter() + .map(|&(span, count, _)| ExpectedLifetimeParameter { span, count }) + .collect(); + + let suggestions = suggestions + .into_iter() + .flat_map(|(span, n, incl_angl_brckt)| { + indicate_anonymous_lifetime(sess.source_map(), n, incl_angl_brckt, span) + }) + .collect(); + + lints::ElidedLifetimesInPathsTied { expected, suggestions, elided_lifetime_source } + .decorate_lint(diag) + } + BuiltinLintDiag::UnknownCrateTypes { span, candidate } => { let sugg = candidate.map(|candidate| lints::UnknownCrateTypesSub { span, candidate }); lints::UnknownCrateTypes { sugg }.decorate_lint(diag); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 7a43c3b8ac7ba..acfbea78141f3 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -308,7 +308,8 @@ fn register_builtins(store: &mut LintStore) { BARE_TRAIT_OBJECTS, UNUSED_EXTERN_CRATES, ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, - ELIDED_LIFETIMES_IN_PATHS, + ELIDED_LIFETIMES_IN_PATHS_TIED, + ELIDED_LIFETIMES_IN_PATHS_UNTIED, EXPLICIT_OUTLIVES_REQUIREMENTS, // FIXME(#52665, #47816) not always applicable and not all // macros are ready for this yet. @@ -328,9 +329,14 @@ fn register_builtins(store: &mut LintStore) { add_lint_group!("deprecated_safe", DEPRECATED_SAFE_2024); + add_lint_group!( + "elided_lifetimes_in_paths", + ELIDED_LIFETIMES_IN_PATHS_TIED, + ELIDED_LIFETIMES_IN_PATHS_UNTIED, + ); + // Register renamed and removed lints. store.register_renamed("single_use_lifetime", "single_use_lifetimes"); - store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths"); store.register_renamed("bare_trait_object", "bare_trait_objects"); store.register_renamed("unstable_name_collision", "unstable_name_collisions"); store.register_renamed("unused_doc_comment", "unused_doc_comments"); @@ -344,6 +350,9 @@ fn register_builtins(store: &mut LintStore) { store.register_renamed("unused_tuple_struct_fields", "dead_code"); store.register_renamed("static_mut_ref", "static_mut_refs"); + // Register renamed lint groups + store.register_renamed_group("elided_lifetime_in_path", "elided_lifetimes_in_paths"); + // These were moved to tool lints, but rustc still sees them when compiling normally, before // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use // `register_removed` explicitly. diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 03962d796f4e2..2f0b7d9996fbb 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -5,7 +5,8 @@ use std::num::NonZero; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag, - EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, + EmissionGuarantee, ExpectedLifetimeParameter, IndicateAnonymousLifetime, LintDiagnostic, + MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, }; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; @@ -2611,6 +2612,26 @@ pub struct ElidedLifetimesInPaths { pub subdiag: ElidedLifetimeInPathSubdiag, } +#[derive(LintDiagnostic)] +#[diag(lint_hidden_lifetime_parameters)] // deliberately the same translation +pub struct ElidedLifetimesInPathsTied { + #[subdiagnostic] + pub expected: Vec, + + #[subdiagnostic] + pub suggestions: Vec, + + #[subdiagnostic] + pub elided_lifetime_source: Option, +} + +#[derive(Subdiagnostic)] +#[label(lint_hidden_lifetime_parameters_tied_source)] +pub struct ElidedLifetimesInPathsTiedSource { + #[primary_span] + pub span: Span, +} + #[derive(LintDiagnostic)] #[diag(lint_invalid_crate_type_value)] pub struct UnknownCrateTypes { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index c731b03a87590..e1e030f41b2c0 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -41,7 +41,8 @@ declare_lint_pass! { DEPRECATED_WHERE_CLAUSE_LOCATION, DUPLICATE_MACRO_ATTRIBUTES, ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, - ELIDED_LIFETIMES_IN_PATHS, + ELIDED_LIFETIMES_IN_PATHS_TIED, + ELIDED_LIFETIMES_IN_PATHS_UNTIED, EXPLICIT_BUILTIN_CFGS_IN_FLAGS, EXPORTED_PRIVATE_DEPENDENCIES, FFI_UNWIND_CALLS, @@ -1829,19 +1830,21 @@ declare_lint! { } declare_lint! { - /// The `elided_lifetimes_in_paths` lint detects the use of hidden - /// lifetime parameters. + /// The `elided_lifetimes_in_paths_tied` lint detects the use of + /// hidden lifetime parameters when those lifetime parameters tie + /// an input lifetime parameter to an output lifetime parameter. /// /// ### Example /// /// ```rust,compile_fail - /// #![deny(elided_lifetimes_in_paths)] + /// #![deny(elided_lifetimes_in_paths_tied)] /// #![deny(warnings)] /// struct Foo<'a> { /// x: &'a u32 /// } /// - /// fn foo(x: &Foo) { + /// fn foo(x: Foo) -> &u32 { + /// &x.0 /// } /// ``` /// @@ -1858,11 +1861,50 @@ declare_lint! { /// may require a significant transition for old code. /// /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions - pub ELIDED_LIFETIMES_IN_PATHS, + pub ELIDED_LIFETIMES_IN_PATHS_TIED, Allow, "hidden lifetime parameters in types are deprecated" } +declare_lint! { + /// The `elided_lifetimes_in_paths_untied` lint detects the use of + /// hidden lifetime parameters when those lifetime parameters do + /// not tie an input lifetime parameter to an output lifetime + /// parameter. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(elided_lifetimes_in_paths_untied)] + /// #![deny(warnings)] + /// struct Foo<'a> { + /// x: &'a u32 + /// } + /// + /// fn foo(x: Foo) -> u32 { + /// x.0 + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Elided lifetime parameters can make it difficult to see at a glance + /// that borrowing is occurring. This lint ensures that lifetime + /// parameters are always explicitly stated, even if it is the `'_` + /// [placeholder lifetime]. + /// + /// This lint is "allow" by default because it has some known issues, and + /// may require a significant transition for old code. + /// + /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions + pub ELIDED_LIFETIMES_IN_PATHS_UNTIED, + Allow, + "hidden lifetime parameters in types make it hard to tell when borrowing is happening", + crate_level_only +} + declare_lint! { /// The `bare_trait_objects` lint suggests using `dyn Trait` for trait /// objects. diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 0f07de43e80ed..c3ce24b8e1009 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -585,6 +585,12 @@ pub enum BuiltinLintDiag { }, MacroExpandedMacroExportsAccessedByAbsolutePaths(Span), ElidedLifetimesInPaths(usize, Span, bool, Span), + + ElidedLifetimesInPathsTied { + elided_lifetime_source: Option, + suggestions: Vec<(Span, usize, bool)>, + }, + UnknownCrateTypes { span: Span, candidate: Option, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 710099d9e90c8..69135bc4bc51a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -660,10 +660,31 @@ struct DiagMetadata<'ast> { } #[derive(Debug)] -struct ResolvedNestedElisionTarget { +enum ResolvedElisionTarget { + /// Elision in `&u8` -> `&'_ u8` + TopLevel(NodeId, Span), + /// Elision in `Foo` -> `Foo<'_>` + Nested(NestedResolvedElisionTarget), +} + +impl ResolvedElisionTarget { + fn node_id(&self) -> NodeId { + match *self { + Self::TopLevel(n, _) => n, + Self::Nested(NestedResolvedElisionTarget { segment_id, .. }) => segment_id, + } + } +} + +#[derive(Debug)] +struct NestedResolvedElisionTarget { segment_id: NodeId, - elided_lifetime_span: Span, - diagnostic: lint::BuiltinLintDiag, + + // These four are used to enrich diagnostics + type_with_elision: Span, + insert_lifetime: Span, + expected_lifetimes: usize, + include_angle_bracket: bool, } struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { @@ -708,7 +729,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { lifetime_uses: FxHashMap, /// Track which types participated in lifetime elision - resolved_lifetime_elisions: Vec, + resolved_lifetime_elisions: Vec, } /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. @@ -1812,6 +1833,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { LifetimeElisionCandidate::Ignore, ); self.resolve_anonymous_lifetime(<, true); + + self.resolved_lifetime_elisions.push(ResolvedElisionTarget::TopLevel(anchor_id, span)); } #[instrument(level = "debug", skip(self))] @@ -2025,16 +2048,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } if should_lint { - self.resolved_lifetime_elisions.push(ResolvedNestedElisionTarget { - segment_id, - elided_lifetime_span, - diagnostic: lint::BuiltinLintDiag::ElidedLifetimesInPaths( + self.resolved_lifetime_elisions.push(ResolvedElisionTarget::Nested( + NestedResolvedElisionTarget { + segment_id, + type_with_elision: path_span, + insert_lifetime: elided_lifetime_span, expected_lifetimes, - path_span, - !segment.has_generic_args, - elided_lifetime_span, - ), - }); + include_angle_bracket: !segment.has_generic_args, + }, + )); } } } @@ -2096,25 +2118,131 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let elision_failures = replace(&mut self.diag_metadata.current_elision_failures, outer_failures); - if !elision_failures.is_empty() { - let Err(failure_info) = elision_lifetime else { bug!() }; - self.report_missing_lifetime_specifiers(elision_failures, Some(failure_info)); - } + + let elision_lifetime = match (elision_failures.is_empty(), elision_lifetime) { + (true, Ok(lifetime)) => Some(lifetime), + + (true, Err(_)) => None, + + (false, Ok(_)) => bug!(), + + (false, Err(failure_info)) => { + self.report_missing_lifetime_specifiers(elision_failures, Some(failure_info)); + None + } + }; + + // We've recorded all elisions that occurred in the params and + // outputs, categorized by top-level or nested. + // + // Our primary lint case is when an output lifetime is tied to + // an input lifetime. In that case, we want to warn about any + // nested hidden lifetimes in those params or outputs. + // + // The secondary case is for nested elisions that are not part + // of the tied lifetime relationship. let output_resolved_lifetime_elisions = replace(&mut self.resolved_lifetime_elisions, outer_resolved_lifetime_elisions); - let resolved_lifetime_elisions = - param_resolved_lifetime_elisions.into_iter().chain(output_resolved_lifetime_elisions); + match (output_resolved_lifetime_elisions.is_empty(), elision_lifetime) { + (true, _) | (_, None) => { + // Treat all parameters as untied + self.report_untied_lifetimes_elided_in_paths(param_resolved_lifetime_elisions); + } + (false, Some(elision_lifetime)) => { + let (primary, secondary): (Vec<_>, Vec<_>) = + param_resolved_lifetime_elisions.into_iter().partition(|re| { + // Recover the `NodeId` of an elided lifetime + let lvl1 = &self.r.lifetimes_res_map[&re.node_id()]; + let lvl2 = match lvl1 { + LifetimeRes::ElidedAnchor { start, .. } => { + &self.r.lifetimes_res_map[&start] + } + o => o, + }; - for re in resolved_lifetime_elisions { - let ResolvedNestedElisionTarget { segment_id, elided_lifetime_span, diagnostic } = re; + lvl2 == &elision_lifetime + }); + + self.report_tied_lifetimes_elided_in_paths( + fn_id, + primary, + output_resolved_lifetime_elisions, + ); + self.report_untied_lifetimes_elided_in_paths(secondary); + } + } + } + + fn report_untied_lifetimes_elided_in_paths( + &mut self, + resolved_elisions: impl IntoIterator, + ) { + for re in resolved_elisions { + let ResolvedElisionTarget::Nested(d) = re else { continue }; + + let NestedResolvedElisionTarget { + segment_id, + type_with_elision, + insert_lifetime, + expected_lifetimes, + include_angle_bracket, + } = d; self.r.lint_buffer.buffer_lint( - lint::builtin::ELIDED_LIFETIMES_IN_PATHS, + lint::builtin::ELIDED_LIFETIMES_IN_PATHS_UNTIED, segment_id, - elided_lifetime_span, - diagnostic, + insert_lifetime, + lint::BuiltinLintDiag::ElidedLifetimesInPaths( + expected_lifetimes, + type_with_elision, + include_angle_bracket, + insert_lifetime, + ), + ); + } + } + + fn report_tied_lifetimes_elided_in_paths( + &mut self, + fn_id: NodeId, + input_elided_lifetimes: Vec, + output_elided_lifetimes: Vec, + ) { + // Could this be an argument to this function so we don't have + // to re-find it? + let elided_lifetime_source = input_elided_lifetimes.iter().find_map(|hl| match *hl { + ResolvedElisionTarget::TopLevel(_, span) => Some(span), + _ => None, + }); + + let mut error_spans = Vec::new(); + let mut suggestions = Vec::new(); + + let elided_lifetimes = input_elided_lifetimes.into_iter().chain(output_elided_lifetimes); + for el in elided_lifetimes { + let ResolvedElisionTarget::Nested(n) = el else { continue }; + + let NestedResolvedElisionTarget { + segment_id: _, + type_with_elision, + insert_lifetime, + expected_lifetimes, + include_angle_bracket, + } = n; + + error_spans.push(type_with_elision); + + suggestions.push((insert_lifetime, expected_lifetimes, include_angle_bracket)); + } + + if !suggestions.is_empty() { + self.r.lint_buffer.buffer_lint( + lint::builtin::ELIDED_LIFETIMES_IN_PATHS_TIED, + fn_id, + error_spans, + BuiltinLintDiag::ElidedLifetimesInPathsTied { elided_lifetime_source, suggestions }, ); } } diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 526b5323d8974..d63fb0c1ec369 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -12,6 +12,7 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ ("let-underscore", "Lints that detect wildcard let bindings that are likely to be invalid"), ("rustdoc", "Rustdoc-specific lints"), ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"), + ("elided-lifetimes-in-paths", "Lints that detect the use of hidden lifetime parameters"), ("nonstandard-style", "Violation of standard naming conventions"), ("future-incompatible", "Lints that detect code that has future-compatibility problems"), ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"), diff --git a/tests/ui/lifetimes/elided-lifetime-in-path-details.rs b/tests/ui/lifetimes/elided-lifetime-in-path-details.rs new file mode 100644 index 0000000000000..61c94556fff75 --- /dev/null +++ b/tests/ui/lifetimes/elided-lifetime-in-path-details.rs @@ -0,0 +1,239 @@ +//@revisions: tied untied + +#![cfg_attr(tied, deny(elided_lifetimes_in_paths_tied))] +//[tied]~^ NOTE: the lint level is defined here +#![cfg_attr(untied, deny(elided_lifetimes_in_paths_untied))] +//[untied]~^ NOTE: the lint level is defined here + +struct ContainsLifetime<'a>(&'a u8); + +// ========== +// Core desired functionality + +fn top_level_to_nested(v: &u8) -> + //[tied]~^ NOTE lifetime comes from here + ContainsLifetime + //[tied]~^ ERROR hidden lifetime parameters + //[tied]~| NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime +{ + ContainsLifetime(v) +} + +fn nested_to_top_level( + v: ContainsLifetime, + //[tied]~^ ERROR hidden lifetime parameters + //[tied]~| NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime +) -> &u8 +{ + v.0 +} + +fn nested_to_nested( + v: ContainsLifetime, + //[tied]~^ ERROR hidden lifetime parameters + //[tied]~| NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime +) -> ContainsLifetime + //[tied]~^ NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime +{ + v +} + +fn top_level_to_top_level(v: &u8) -> &u8 { + v +} + +// ========== +// Mixed named and elided lifetimes + +fn named_top_level_to_nested<'a>(v: &'a u8) -> + ContainsLifetime + //[tied]~^ ERROR hidden lifetime parameters + //[tied]~| NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime +{ + ContainsLifetime(v) +} + +// ========== +// Using named lifetimes everywhere should not report + +fn named_top_level_to_named_nested<'a>(v: &'a u8) -> ContainsLifetime<'a> { + ContainsLifetime(v) +} + +fn named_nested_to_named_top_level<'a>(v: ContainsLifetime<'a>) -> &'a u8 { + v.0 +} + +fn named_nested_to_named_nested<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'a> { + v +} + +// ========== +// Using anonymous lifetimes everywhere should not report + +fn anon_top_level_to_anon_nested(v: &'_ u8) -> ContainsLifetime<'_> { + ContainsLifetime(v) +} + +fn anon_nested_to_anon_top_level(v: ContainsLifetime<'_>) -> &'_ u8 { + v.0 +} + +fn anon_nested_to_anon_nested(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> { + v +} + +// ========== +// Mixing named and anonymous lifetimes should not report + +fn named_nested_to_anon_top_level<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { + v.0 +} + +fn named_top_level_to_anon_top_level<'a>(v: &'a u8) -> ContainsLifetime<'_> { + ContainsLifetime(v) +} + +// ========== +// Lifetimes with nothing to tie to + +fn top_level_parameter(v: &u8) {} + +fn nested_parameter(v: ContainsLifetime) {} +//[untied]~^ ERROR hidden lifetime parameters +//[untied]~| NOTE expected lifetime parameter + +fn top_level_nested_parameter(v: &ContainsLifetime) {} +//[untied]~^ ERROR hidden lifetime parameters +//[untied]~| NOTE expected lifetime parameter + +// ========== +// More complicated types + +fn top_level_to_multiple_nested(v: &u8) -> ( + //[tied]~^ NOTE lifetime comes from here + ContainsLifetime, + //[tied]~^ ERROR hidden lifetime parameters + //[tied]~| NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime + ContainsLifetime, + //[tied]~^ NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime +) +{ + (ContainsLifetime(v), ContainsLifetime(v)) +} + +// ---------- + +struct AsAMethod(u8); + +impl AsAMethod { + fn top_level_to_nested( + v: &u8, + //[tied]~^ NOTE lifetime comes from here + ) -> + ContainsLifetime + //[tied]~^ ERROR hidden lifetime parameters + //[tied]~| NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime + { + ContainsLifetime(v) + } + + fn nested_to_top_level( + v: ContainsLifetime, + //[tied]~^ ERROR hidden lifetime parameters + //[tied]~| NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime + ) -> &u8 + { + v.0 + } + + fn nested_to_nested( + v: ContainsLifetime, + //[tied]~^ ERROR hidden lifetime parameters + //[tied]~| NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime + ) -> ContainsLifetime + //[tied]~^ NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime + { + v + } + + fn top_level_to_top_level(v: &u8) -> &u8 { + v + } + + fn self_to_nested( + &self, + //[tied]~^ NOTE lifetime comes from here + ) -> + ContainsLifetime + //[tied]~^ ERROR hidden lifetime parameters + //[tied]~| NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime + { + ContainsLifetime(&self.0) + } + + fn self_to_nested_with_irrelevant_top_level_parameter( + &self, + //[tied]~^ NOTE lifetime comes from here + _: &u8 + ) -> + ContainsLifetime + //[tied]~^ ERROR hidden lifetime parameters + //[tied]~| NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime + { + ContainsLifetime(&self.0) + } + + fn self_to_nested_with_irrelevant_nested_parameter( + &self, + //[tied]~^ NOTE lifetime comes from here + _: ContainsLifetime, + //[untied]~^ ERROR hidden lifetime parameters + //[untied]~| NOTE expected lifetime parameter + ) -> ContainsLifetime + //[tied]~^ ERROR hidden lifetime parameters + //[tied]~| NOTE expected lifetime parameter + //[tied]~| HELP indicate the anonymous lifetime + { + ContainsLifetime(&self.0) + } + + fn nested_in_parameter( + &self, + v: ContainsLifetime, + //[untied]~^ ERROR hidden lifetime parameters + //[untied]~| NOTE expected lifetime parameter + ) {} + + fn nested_in_parameter_with_return( + &self, + v: ContainsLifetime, + //[untied]~^ ERROR hidden lifetime parameters + //[untied]~| NOTE expected lifetime parameter + ) -> &u8 + { + &self.0 + } +} + +// // Do we need to worry about nested function signatures? +// // fn outer(_: fn(&) -> &) + +// // Do we need to worry about closures? + +// // Do we need to write tests for `self: Foo` syntax? + +fn main() {} diff --git a/tests/ui/lifetimes/elided-lifetime-in-path-details.tied.stderr b/tests/ui/lifetimes/elided-lifetime-in-path-details.tied.stderr new file mode 100644 index 0000000000000..93c2b6b8afc5b --- /dev/null +++ b/tests/ui/lifetimes/elided-lifetime-in-path-details.tied.stderr @@ -0,0 +1,167 @@ +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:15:5 + | +LL | fn top_level_to_nested(v: &u8) -> + | - the lifetime comes from here +LL | +LL | ContainsLifetime + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +note: the lint level is defined here + --> $DIR/elided-lifetime-in-path-details.rs:3:24 + | +LL | #![cfg_attr(tied, deny(elided_lifetimes_in_paths_tied))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: indicate the anonymous lifetime + | +LL | ContainsLifetime<'_> + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:24:8 + | +LL | v: ContainsLifetime, + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | v: ContainsLifetime<'_>, + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:34:8 + | +LL | v: ContainsLifetime, + | ^^^^^^^^^^^^^^^^ expected lifetime parameter +... +LL | ) -> ContainsLifetime + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | v: ContainsLifetime<'_>, + | ++++ +help: indicate the anonymous lifetime + | +LL | ) -> ContainsLifetime<'_> + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:53:5 + | +LL | ContainsLifetime + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | ContainsLifetime<'_> + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:120:5 + | +LL | fn top_level_to_multiple_nested(v: &u8) -> ( + | - the lifetime comes from here +LL | +LL | ContainsLifetime, + | ^^^^^^^^^^^^^^^^ expected lifetime parameter +... +LL | ContainsLifetime, + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | ContainsLifetime<'_>, + | ++++ +help: indicate the anonymous lifetime + | +LL | ContainsLifetime<'_>, + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:141:9 + | +LL | v: &u8, + | - the lifetime comes from here +... +LL | ContainsLifetime + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | ContainsLifetime<'_> + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:150:12 + | +LL | v: ContainsLifetime, + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | v: ContainsLifetime<'_>, + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:160:12 + | +LL | v: ContainsLifetime, + | ^^^^^^^^^^^^^^^^ expected lifetime parameter +... +LL | ) -> ContainsLifetime + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | v: ContainsLifetime<'_>, + | ++++ +help: indicate the anonymous lifetime + | +LL | ) -> ContainsLifetime<'_> + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:179:9 + | +LL | &self, + | - the lifetime comes from here +... +LL | ContainsLifetime + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | ContainsLifetime<'_> + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:192:9 + | +LL | &self, + | - the lifetime comes from here +... +LL | ContainsLifetime + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | ContainsLifetime<'_> + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:206:10 + | +LL | &self, + | - the lifetime comes from here +... +LL | ) -> ContainsLifetime + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | ) -> ContainsLifetime<'_> + | ++++ + +error: aborting due to 11 previous errors + diff --git a/tests/ui/lifetimes/elided-lifetime-in-path-details.untied.stderr b/tests/ui/lifetimes/elided-lifetime-in-path-details.untied.stderr new file mode 100644 index 0000000000000..a13ae94b570d6 --- /dev/null +++ b/tests/ui/lifetimes/elided-lifetime-in-path-details.untied.stderr @@ -0,0 +1,62 @@ +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:107:24 + | +LL | fn nested_parameter(v: ContainsLifetime) {} + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +note: the lint level is defined here + --> $DIR/elided-lifetime-in-path-details.rs:5:26 + | +LL | #![cfg_attr(untied, deny(elided_lifetimes_in_paths_untied))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: indicate the anonymous lifetime + | +LL | fn nested_parameter(v: ContainsLifetime<'_>) {} + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:111:35 + | +LL | fn top_level_nested_parameter(v: &ContainsLifetime) {} + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | fn top_level_nested_parameter(v: &ContainsLifetime<'_>) {} + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:203:12 + | +LL | _: ContainsLifetime, + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | _: ContainsLifetime<'_>, + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:216:12 + | +LL | v: ContainsLifetime, + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | v: ContainsLifetime<'_>, + | ++++ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetime-in-path-details.rs:223:12 + | +LL | v: ContainsLifetime, + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | v: ContainsLifetime<'_>, + | ++++ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/lifetimes/elided-lint-in-mod.stderr b/tests/ui/lifetimes/elided-lint-in-mod.stderr index 1fee18028c66f..0433ba81cdcfb 100644 --- a/tests/ui/lifetimes/elided-lint-in-mod.stderr +++ b/tests/ui/lifetimes/elided-lint-in-mod.stderr @@ -11,6 +11,7 @@ note: the lint level is defined here | LL | #[deny(elided_lifetimes_in_paths)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(elided_lifetimes_in_paths_untied)]` implied by `#[deny(elided_lifetimes_in_paths)]` help: indicate the anonymous lifetime | LL | fn test2(_: super::Foo<'_>) {} diff --git a/tests/ui/lifetimes/issue-91763.stderr b/tests/ui/lifetimes/issue-91763.stderr index f7293ed809c3a..6d5d219b5b236 100644 --- a/tests/ui/lifetimes/issue-91763.stderr +++ b/tests/ui/lifetimes/issue-91763.stderr @@ -9,6 +9,7 @@ note: the lint level is defined here | LL | #![deny(elided_lifetimes_in_paths)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(elided_lifetimes_in_paths_untied)]` implied by `#[deny(elided_lifetimes_in_paths)]` help: indicate the anonymous lifetime | LL | fn f() -> Ptr<'_>; diff --git a/tests/ui/lint/force-warn/allowed-by-default-lint.stderr b/tests/ui/lint/force-warn/allowed-by-default-lint.stderr index ac98b5896ca7b..31da24c305c67 100644 --- a/tests/ui/lint/force-warn/allowed-by-default-lint.stderr +++ b/tests/ui/lint/force-warn/allowed-by-default-lint.stderr @@ -4,7 +4,7 @@ warning: hidden lifetime parameters in types are deprecated LL | fn foo(x: &Foo) {} | ^^^ expected lifetime parameter | - = note: requested on the command line with `--force-warn elided-lifetimes-in-paths` + = note: `--force-warn elided-lifetimes-in-paths-untied` implied by `--force-warn elided-lifetimes-in-paths` help: indicate the anonymous lifetime | LL | fn foo(x: &Foo<'_>) {} diff --git a/tests/ui/lint/reasons.rs b/tests/ui/lint/reasons.rs index 917e7539aaed3..44751f70ec8c3 100644 --- a/tests/ui/lint/reasons.rs +++ b/tests/ui/lint/reasons.rs @@ -18,6 +18,7 @@ pub struct CheaterDetectionMechanism {} impl fmt::Debug for CheaterDetectionMechanism { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { //~^ WARN hidden lifetime parameters in types are deprecated + //~| NOTE implied by //~| NOTE expected lifetime parameter //~| NOTE explicit anonymous lifetimes aid //~| HELP indicate the anonymous lifetime diff --git a/tests/ui/lint/reasons.stderr b/tests/ui/lint/reasons.stderr index 8028785ab94be..54a28b4630a0e 100644 --- a/tests/ui/lint/reasons.stderr +++ b/tests/ui/lint/reasons.stderr @@ -12,13 +12,14 @@ note: the lint level is defined here | LL | #![warn(elided_lifetimes_in_paths, | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(elided_lifetimes_in_paths_untied)]` implied by `#[warn(elided_lifetimes_in_paths)]` help: indicate the anonymous lifetime | LL | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | ++++ warning: variable `Social_exchange_psychology` should have a snake case name - --> $DIR/reasons.rs:29:9 + --> $DIR/reasons.rs:30:9 | LL | let Social_exchange_psychology = CheaterDetectionMechanism {}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case (notice the capitalization): `social_exchange_psychology`