From c00f63541e42fb6c4ac4efccbf70a4566f3e209b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 9 Feb 2022 18:42:32 -0800 Subject: [PATCH 01/16] Remove in-band lifetimes --- compiler/rustc_ast_lowering/src/lib.rs | 57 +---- .../src/error_codes/E0687.md | 4 +- .../src/error_codes/E0688.md | 4 +- compiler/rustc_feature/src/active.rs | 2 - compiler/rustc_feature/src/removed.rs | 3 + compiler/rustc_hir/src/hir.rs | 5 - .../src/middle/resolve_lifetime.rs | 3 - .../rustc_resolve/src/late/diagnostics.rs | 11 - compiler/rustc_resolve/src/late/lifetimes.rs | 70 +----- .../ui/async-await/generics-and-bounds.rs | 11 - src/test/ui/error-codes/E0261.stderr | 4 - .../feature-gate-in_band_lifetimes.rs | 62 ----- .../feature-gate-in_band_lifetimes.stderr | 231 ------------------ ...t-in-trait-path-undeclared-lifetime.stderr | 2 - ...ssociated_type_undeclared_lifetimes.stderr | 2 - .../issue-67510.stderr | 4 - ...-escape-via-bound-contravariant-closure.rs | 3 +- .../region-escape-via-bound-contravariant.rs | 5 +- .../ui/impl-trait/region-escape-via-bound.rs | 5 +- .../impl-trait/region-escape-via-bound.stderr | 15 +- src/test/ui/in-band-lifetimes/E0687.rs | 16 -- src/test/ui/in-band-lifetimes/E0687.stderr | 27 -- src/test/ui/in-band-lifetimes/E0687_where.rs | 8 - .../ui/in-band-lifetimes/E0687_where.stderr | 15 -- src/test/ui/in-band-lifetimes/E0688.rs | 16 -- src/test/ui/in-band-lifetimes/E0688.stderr | 27 -- .../in-band-lifetimes/elided-lifetimes.fixed | 119 --------- .../ui/in-band-lifetimes/elided-lifetimes.rs | 119 --------- .../in-band-lifetimes/elided-lifetimes.stderr | 120 --------- .../ui/in-band-lifetimes/in-band-lifetimes.rs | 96 -------- ...124-anon-lifetime-in-struct-declaration.rs | 10 - ...anon-lifetime-in-struct-declaration.stderr | 14 -- .../in-band-lifetimes/mismatched.nll.stderr | 22 -- src/test/ui/in-band-lifetimes/mismatched.rs | 8 - .../ui/in-band-lifetimes/mismatched.stderr | 20 -- .../ui/in-band-lifetimes/mismatched_trait.rs | 10 - .../in-band-lifetimes/mismatched_trait.stderr | 11 - .../mismatched_trait_impl-2.rs | 14 -- .../mismatched_trait_impl-2.stderr | 18 -- .../mismatched_trait_impl.nll.stderr | 16 -- .../mismatched_trait_impl.rs | 14 -- .../mismatched_trait_impl.stderr | 27 -- .../ui/in-band-lifetimes/mut_while_borrow.rs | 11 - .../in-band-lifetimes/mut_while_borrow.stderr | 13 - src/test/ui/in-band-lifetimes/nested-items.rs | 20 -- .../in-band-lifetimes/no_in_band_in_struct.rs | 12 - .../no_in_band_in_struct.stderr | 19 -- .../no_introducing_in_band_in_locals.rs | 13 - .../no_introducing_in_band_in_locals.stderr | 27 -- .../missing-lifetime-in-alias.rs | 1 - .../missing-lifetime-in-alias.stderr | 10 +- src/test/ui/lifetimes/nested.rs | 7 + .../shadow.rs | 5 +- .../shadow.stderr | 12 +- ...ime-used-in-debug-macro-issue-70152.stderr | 5 - ...ethod-call-lifetime-args-unresolved.stderr | 2 - src/test/ui/nll/issue-52742.rs | 2 - src/test/ui/nll/issue-52742.stderr | 6 +- src/test/ui/regions/regions-in-enums.stderr | 4 - src/test/ui/regions/regions-in-structs.stderr | 4 - .../ui/regions/regions-name-undeclared.stderr | 18 -- src/test/ui/regions/regions-undeclared.stderr | 8 - .../one-use-in-fn-argument-in-band.fixed | 18 -- .../one-use-in-fn-argument-in-band.rs | 18 -- .../one-use-in-fn-argument-in-band.stderr | 26 -- .../where-lifetime-resolution.stderr | 4 - 66 files changed, 57 insertions(+), 1458 deletions(-) delete mode 100644 src/test/ui/feature-gates/feature-gate-in_band_lifetimes.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr delete mode 100644 src/test/ui/in-band-lifetimes/E0687.rs delete mode 100644 src/test/ui/in-band-lifetimes/E0687.stderr delete mode 100644 src/test/ui/in-band-lifetimes/E0687_where.rs delete mode 100644 src/test/ui/in-band-lifetimes/E0687_where.stderr delete mode 100644 src/test/ui/in-band-lifetimes/E0688.rs delete mode 100644 src/test/ui/in-band-lifetimes/E0688.stderr delete mode 100644 src/test/ui/in-band-lifetimes/elided-lifetimes.fixed delete mode 100644 src/test/ui/in-band-lifetimes/elided-lifetimes.rs delete mode 100644 src/test/ui/in-band-lifetimes/elided-lifetimes.stderr delete mode 100644 src/test/ui/in-band-lifetimes/in-band-lifetimes.rs delete mode 100644 src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.rs delete mode 100644 src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr delete mode 100644 src/test/ui/in-band-lifetimes/mismatched.nll.stderr delete mode 100644 src/test/ui/in-band-lifetimes/mismatched.rs delete mode 100644 src/test/ui/in-band-lifetimes/mismatched.stderr delete mode 100644 src/test/ui/in-band-lifetimes/mismatched_trait.rs delete mode 100644 src/test/ui/in-band-lifetimes/mismatched_trait.stderr delete mode 100644 src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs delete mode 100644 src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr delete mode 100644 src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr delete mode 100644 src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs delete mode 100644 src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr delete mode 100644 src/test/ui/in-band-lifetimes/mut_while_borrow.rs delete mode 100644 src/test/ui/in-band-lifetimes/mut_while_borrow.stderr delete mode 100644 src/test/ui/in-band-lifetimes/nested-items.rs delete mode 100644 src/test/ui/in-band-lifetimes/no_in_band_in_struct.rs delete mode 100644 src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr delete mode 100644 src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.rs delete mode 100644 src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr rename src/test/ui/{in-band-lifetimes => lifetimes}/missing-lifetime-in-alias.rs (97%) rename src/test/ui/{in-band-lifetimes => lifetimes}/missing-lifetime-in-alias.stderr (83%) create mode 100644 src/test/ui/lifetimes/nested.rs rename src/test/ui/{in-band-lifetimes => lifetimes}/shadow.rs (71%) rename src/test/ui/{in-band-lifetimes => lifetimes}/shadow.stderr (74%) delete mode 100644 src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.fixed delete mode 100644 src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs delete mode 100644 src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ae7f22923dfc5..5badec1fc0524 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -141,13 +141,9 @@ struct LoweringContext<'a, 'hir: 'a> { /// indicate whether or not we're in a place where new lifetimes will result /// in in-band lifetime definitions, such a function or an impl header, /// including implicit lifetimes from `impl_header_lifetime_elision`. - is_collecting_in_band_lifetimes: bool, + is_collecting_anonymous_lifetimes: bool, /// Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB. - /// When `is_collecting_in_band_lifetimes` is true, each lifetime is checked - /// against this list to see if it is already in-scope, or if a definition - /// needs to be created for it. - /// /// We always store a `normalize_to_macros_2_0()` version of the param-name in this /// vector. in_scope_lifetimes: Vec, @@ -374,7 +370,7 @@ pub fn lower_crate<'a, 'hir>( task_context: None, current_item: None, lifetimes_to_define: Vec::new(), - is_collecting_in_band_lifetimes: false, + is_collecting_anonymous_lifetimes: false, in_scope_lifetimes: Vec::new(), allow_try_trait: Some([sym::try_trait_v2][..].into()), allow_gen_future: Some([sym::gen_future][..].into()), @@ -718,13 +714,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, f: impl FnOnce(&mut Self) -> T, ) -> (Vec<(Span, ParamName)>, T) { - let was_collecting = std::mem::replace(&mut self.is_collecting_in_band_lifetimes, true); + let was_collecting = std::mem::replace(&mut self.is_collecting_anonymous_lifetimes, true); let len = self.lifetimes_to_define.len(); let res = f(self); let lifetimes_to_define = self.lifetimes_to_define.split_off(len); - self.is_collecting_in_band_lifetimes = was_collecting; + self.is_collecting_anonymous_lifetimes = was_collecting; (lifetimes_to_define, res) } @@ -741,7 +737,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // that collisions are ok here and this shouldn't // really show up for end-user. let (str_name, kind) = match hir_name { - ParamName::Plain(ident) => (ident.name, hir::LifetimeParamKind::InBand), + ParamName::Plain(ident) => (ident.name, hir::LifetimeParamKind::Explicit), ParamName::Fresh(_) => (kw::UnderscoreLifetime, hir::LifetimeParamKind::Elided), ParamName::Error => (kw::UnderscoreLifetime, hir::LifetimeParamKind::Error), }; @@ -765,38 +761,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - /// When there is a reference to some lifetime `'a`, and in-band - /// lifetimes are enabled, then we want to push that lifetime into - /// the vector of names to define later. In that case, it will get - /// added to the appropriate generics. - fn maybe_collect_in_band_lifetime(&mut self, ident: Ident) { - if !self.is_collecting_in_band_lifetimes { - return; - } - - if !self.sess.features_untracked().in_band_lifetimes { - return; - } - - if self.in_scope_lifetimes.contains(&ParamName::Plain(ident.normalize_to_macros_2_0())) { - return; - } - - let hir_name = ParamName::Plain(ident); - - if self.lifetimes_to_define.iter().any(|(_, lt_name)| { - lt_name.normalize_to_macros_2_0() == hir_name.normalize_to_macros_2_0() - }) { - return; - } - - self.lifetimes_to_define.push((ident.span, hir_name)); - } - /// When we have either an elided or `'_` lifetime in an impl /// header, we convert it to an in-band lifetime. - fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> ParamName { - assert!(self.is_collecting_in_band_lifetimes); + fn collect_fresh_anonymous_lifetime(&mut self, span: Span) -> ParamName { + assert!(self.is_collecting_anonymous_lifetimes); let index = self.lifetimes_to_define.len() + self.in_scope_lifetimes.len(); let hir_name = ParamName::Fresh(index); self.lifetimes_to_define.push((span, hir_name)); @@ -1938,7 +1906,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } ident if ident.name == kw::UnderscoreLifetime => match self.anonymous_lifetime_mode { AnonymousLifetimeMode::CreateParameter => { - let fresh_name = self.collect_fresh_in_band_lifetime(span); + let fresh_name = self.collect_fresh_anonymous_lifetime(span); self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(fresh_name)) } @@ -1949,7 +1917,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span), }, ident => { - self.maybe_collect_in_band_lifetime(ident); let param_name = ParamName::Plain(self.lower_ident(ident)); self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(param_name)) } @@ -1993,8 +1960,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (name, kind) = match param.kind { GenericParamKind::Lifetime => { - let was_collecting_in_band = self.is_collecting_in_band_lifetimes; - self.is_collecting_in_band_lifetimes = false; + let was_collecting_in_band = self.is_collecting_anonymous_lifetimes; + self.is_collecting_anonymous_lifetimes = false; let lt = self .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| { @@ -2017,7 +1984,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let kind = hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }; - self.is_collecting_in_band_lifetimes = was_collecting_in_band; + self.is_collecting_anonymous_lifetimes = was_collecting_in_band; (param_name, kind) } @@ -2376,7 +2343,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Hence `impl Foo for &u32` becomes `impl<'f> Foo for &'f u32` for some fresh // `'f`. AnonymousLifetimeMode::CreateParameter => { - let fresh_name = self.collect_fresh_in_band_lifetime(span); + let fresh_name = self.collect_fresh_anonymous_lifetime(span); hir::Lifetime { hir_id: self.next_id(), span: self.lower_span(span), diff --git a/compiler/rustc_error_codes/src/error_codes/E0687.md b/compiler/rustc_error_codes/src/error_codes/E0687.md index 67b7db2d31fde..05c4915535de8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0687.md +++ b/compiler/rustc_error_codes/src/error_codes/E0687.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + In-band lifetimes cannot be used in `fn`/`Fn` syntax. Erroneous code examples: -```compile_fail,E0687 +```ignore (feature got removed) #![feature(in_band_lifetimes)] fn foo(x: fn(&'a u32)) {} // error! diff --git a/compiler/rustc_error_codes/src/error_codes/E0688.md b/compiler/rustc_error_codes/src/error_codes/E0688.md index db50f490208f4..44e641a2a0b5a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0688.md +++ b/compiler/rustc_error_codes/src/error_codes/E0688.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + In-band lifetimes were mixed with explicit lifetime binders. Erroneous code example: -```compile_fail,E0688 +```ignore (feature got removed) #![feature(in_band_lifetimes)] fn foo<'a>(x: &'a u32, y: &'b u32) {} // error! diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 5545abc6024af..1d9d16e85cb21 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -400,8 +400,6 @@ declare_features! ( (active, if_let_guard, "1.47.0", Some(51114), None), /// Allows using imported `main` function (active, imported_main, "1.53.0", Some(28937), None), - /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). - (active, in_band_lifetimes, "1.23.0", Some(44524), None), /// Allows inferring `'static` outlives requirements (RFC 2093). (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), /// Allows associated types in inherent impls. diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index f5f944db5e90b..fae9bd633afff 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -104,6 +104,9 @@ declare_features! ( (removed, impl_trait_in_bindings, "1.55.0", Some(63065), None, Some("the implementation was not maintainable, the feature may get reintroduced once the current refactorings are done")), (removed, import_shadowing, "1.0.0", None, None, None), + /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). + (removed, in_band_lifetimes, "1.23.0", Some(44524), None, + Some("removed due to unsolved ergonomic questions and added lifetime resolution complexity")), /// Lazily evaluate constants. This allows constants to depend on type parameters. (removed, lazy_normalization_consts, "1.46.0", Some(72219), None, Some("superseded by `generic_const_exprs`")), /// Allows using the `#[link_args]` attribute. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 255e661652db9..4cc3e4e7a91ac 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -470,11 +470,6 @@ pub enum LifetimeParamKind { // `fn foo<'a>(x: &'a u8) -> &'a u8 { x }`). Explicit, - // Indicates that the lifetime definition was synthetically added - // as a result of an in-band lifetime usage (e.g., in - // `fn foo(x: &'a u8) -> &'a u8 { x }`). - InBand, - // Indication that the lifetime was elided (e.g., in both cases in // `fn foo(x: &u8) -> &'_ u8 { x }`). Elided, diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 2665ea8d7fd73..4f1b391e94d01 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -15,8 +15,6 @@ use rustc_macros::HashStable; pub enum LifetimeDefOrigin { // Explicit binders like `fn foo<'a>(x: &'a u8)` or elided like `impl Foo<&u32>` ExplicitOrElided, - // In-band declarations like `fn foo(x: &'a u8)` - InBand, // Some kind of erroneous origin Error, } @@ -25,7 +23,6 @@ impl LifetimeDefOrigin { pub fn from_param(param: &GenericParam<'_>) -> Self { match param.kind { GenericParamKind::Lifetime { kind } => match kind { - LifetimeParamKind::InBand => LifetimeDefOrigin::InBand, LifetimeParamKind::Explicit => LifetimeDefOrigin::ExplicitOrElided, LifetimeParamKind::Elided => LifetimeDefOrigin::ExplicitOrElided, LifetimeParamKind::Error => LifetimeDefOrigin::Error, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index f20cf29cc89d1..260fc81500a86 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1844,7 +1844,6 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { lifetime_ref ); err.span_label(lifetime_ref.span, "undeclared lifetime"); - let mut suggests_in_band = false; let mut suggested_spans = vec![]; for missing in &self.missing_named_lifetime_spots { match missing { @@ -1860,7 +1859,6 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { }) { (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)) } else { - suggests_in_band = true; (generics.span, format!("<{}>", lifetime_ref)) }; if suggested_spans.contains(&span) { @@ -1895,15 +1893,6 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { _ => {} } } - if self.tcx.sess.is_nightly_build() - && !self.tcx.features().in_band_lifetimes - && suggests_in_band - { - err.help( - "if you want to experiment with in-band lifetime bindings, \ - add `#![feature(in_band_lifetimes)]` to the crate attributes", - ); - } err.emit(); } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 2f0ad60709dac..aa25304992b25 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -16,7 +16,7 @@ use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::hir_id::ItemLocalId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath}; -use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind}; +use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime::*; @@ -1325,9 +1325,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { - if !self.trait_definition_only { - check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params); - } let scope = Scope::TraitRefBoundary { s: self.scope }; self.with(scope, |_, this| { for param in generics.params { @@ -1535,30 +1532,6 @@ impl ShadowKind { } } -fn check_mixed_explicit_and_in_band_defs(tcx: TyCtxt<'_>, params: &[hir::GenericParam<'_>]) { - let lifetime_params: Vec<_> = params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)), - _ => None, - }) - .collect(); - let explicit = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::Explicit); - let in_band = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::InBand); - - if let (Some((_, explicit_span)), Some((_, in_band_span))) = (explicit, in_band) { - struct_span_err!( - tcx.sess, - *in_band_span, - E0688, - "cannot mix in-band and explicit lifetime definitions" - ) - .span_label(*in_band_span, "in-band lifetime definition here") - .span_label(*explicit_span, "explicit lifetime definition here") - .emit(); - } -} - fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shadower: Shadower) { let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) { // lifetime/lifetime shadowing is an error @@ -1845,13 +1818,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn lifetime_deletion_span(&self, name: Ident, generics: &hir::Generics<'_>) -> Option { generics.params.iter().enumerate().find_map(|(i, param)| { if param.name.ident() == name { - let in_band = matches!( - param.kind, - hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::InBand } - ); - if in_band { - Some(param.span) - } else if generics.params.len() == 1 { + if generics.params.len() == 1 { // if sole lifetime, remove the entire `<>` brackets Some(generics.span) } else { @@ -2337,39 +2304,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - // Check for fn-syntax conflicts with in-band lifetime definitions - if !self.trait_definition_only && self.is_in_fn_syntax { - match def { - Region::EarlyBound(_, _, LifetimeDefOrigin::InBand) - | Region::LateBound(_, _, _, LifetimeDefOrigin::InBand) => { - struct_span_err!( - self.tcx.sess, - lifetime_ref.span, - E0687, - "lifetimes used in `fn` or `Fn` syntax must be \ - explicitly declared using `<...>` binders" - ) - .span_label(lifetime_ref.span, "in-band lifetime definition") - .emit(); - } - - Region::Static - | Region::EarlyBound( - _, - _, - LifetimeDefOrigin::ExplicitOrElided | LifetimeDefOrigin::Error, - ) - | Region::LateBound( - _, - _, - _, - LifetimeDefOrigin::ExplicitOrElided | LifetimeDefOrigin::Error, - ) - | Region::LateBoundAnon(..) - | Region::Free(..) => {} - } - } - self.insert_lifetime(lifetime_ref, def); } else { self.emit_undeclared_lifetime_error(lifetime_ref); diff --git a/src/test/ui/async-await/generics-and-bounds.rs b/src/test/ui/async-await/generics-and-bounds.rs index 90ab0c01f5450..963b19b34a620 100644 --- a/src/test/ui/async-await/generics-and-bounds.rs +++ b/src/test/ui/async-await/generics-and-bounds.rs @@ -2,8 +2,6 @@ // edition:2018 // compile-flags: --crate-type lib -#![feature(in_band_lifetimes)] - use std::future::Future; pub async fn simple_generic() {} @@ -73,10 +71,6 @@ pub fn call_with_ref_block<'a>(f: &'a (impl Foo + 'a)) -> impl Future impl Future + 'a { - async move { f.foo() } -} - pub fn async_block_with_same_generic_params_unifies() { let mut a = call_generic_bound_block(FooType); a = call_generic_bound_block(FooType); @@ -91,9 +85,4 @@ pub fn async_block_with_same_generic_params_unifies() { let f_two = FooType; let mut d = call_with_ref_block(&f_one); d = call_with_ref_block(&f_two); - - let f_one = FooType; - let f_two = FooType; - let mut d = call_with_ref_block_in_band(&f_one); - d = call_with_ref_block_in_band(&f_two); } diff --git a/src/test/ui/error-codes/E0261.stderr b/src/test/ui/error-codes/E0261.stderr index 33d74feead513..0eab2dc0ee05f 100644 --- a/src/test/ui/error-codes/E0261.stderr +++ b/src/test/ui/error-codes/E0261.stderr @@ -5,8 +5,6 @@ LL | fn foo(x: &'a str) { } | - ^^ undeclared lifetime | | | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'a` --> $DIR/E0261.rs:5:9 @@ -15,8 +13,6 @@ LL | struct Foo { | - help: consider introducing lifetime `'a` here: `<'a>` LL | x: &'a str, | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.rs b/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.rs deleted file mode 100644 index 0e5f968892f33..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.rs +++ /dev/null @@ -1,62 +0,0 @@ -#![allow(warnings)] - -fn foo(x: &'x u8) -> &'x u8 { x } -//~^ ERROR use of undeclared lifetime name -//~^^ ERROR use of undeclared lifetime name - -struct X<'a>(&'a u8); - -impl<'a> X<'a> { - fn inner(&self) -> &'a u8 { - self.0 - } -} - -impl<'a> X<'b> { -//~^ ERROR use of undeclared lifetime name - fn inner_2(&self) -> &'b u8 { - //~^ ERROR use of undeclared lifetime name - self.0 - } -} - -impl X<'b> { -//~^ ERROR use of undeclared lifetime name - fn inner_3(&self) -> &'b u8 { - //~^ ERROR use of undeclared lifetime name - self.0 - } -} - -struct Y(T); - -impl Y<&'a u8> { - //~^ ERROR use of undeclared lifetime name - fn inner(&self) -> &'a u8 { - //~^ ERROR use of undeclared lifetime name - self.0 - } -} - -trait MyTrait<'a> { - fn my_lifetime(&self) -> &'a u8; - fn any_lifetime() -> &'b u8; - //~^ ERROR use of undeclared lifetime name - fn borrowed_lifetime(&'b self) -> &'b u8; - //~^ ERROR use of undeclared lifetime name - //~^^ ERROR use of undeclared lifetime name -} - -impl MyTrait<'a> for Y<&'a u8> { -//~^ ERROR use of undeclared lifetime name -//~^^ ERROR use of undeclared lifetime name - fn my_lifetime(&self) -> &'a u8 { self.0 } - //~^ ERROR use of undeclared lifetime name - fn any_lifetime() -> &'b u8 { &0 } - //~^ ERROR use of undeclared lifetime name - fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 } - //~^ ERROR use of undeclared lifetime name - //~^^ ERROR use of undeclared lifetime name -} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr b/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr deleted file mode 100644 index 41fb1456f869e..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr +++ /dev/null @@ -1,231 +0,0 @@ -error[E0261]: use of undeclared lifetime name `'x` - --> $DIR/feature-gate-in_band_lifetimes.rs:3:12 - | -LL | fn foo(x: &'x u8) -> &'x u8 { x } - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'x` here: `<'x>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'x` - --> $DIR/feature-gate-in_band_lifetimes.rs:3:23 - | -LL | fn foo(x: &'x u8) -> &'x u8 { x } - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'x` here: `<'x>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:15:12 - | -LL | impl<'a> X<'b> { - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'b` here: `'b,` - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:17:27 - | -LL | fn inner_2(&self) -> &'b u8 { - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | impl<'b, 'a> X<'b> { - | +++ -help: consider introducing lifetime `'b` here - | -LL | fn inner_2<'b>(&self) -> &'b u8 { - | ++++ - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:23:8 - | -LL | impl X<'b> { - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'b` here: `<'b>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:25:27 - | -LL | fn inner_3(&self) -> &'b u8 { - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | impl<'b> X<'b> { - | ++++ -help: consider introducing lifetime `'b` here - | -LL | fn inner_3<'b>(&self) -> &'b u8 { - | ++++ - -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/feature-gate-in_band_lifetimes.rs:33:9 - | -LL | impl Y<&'a u8> { - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/feature-gate-in_band_lifetimes.rs:35:25 - | -LL | fn inner(&self) -> &'a u8 { - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'a` here - | -LL | impl<'a> Y<&'a u8> { - | ++++ -help: consider introducing lifetime `'a` here - | -LL | fn inner<'a>(&self) -> &'a u8 { - | ++++ - -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/feature-gate-in_band_lifetimes.rs:50:14 - | -LL | impl MyTrait<'a> for Y<&'a u8> { - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/feature-gate-in_band_lifetimes.rs:50:25 - | -LL | impl MyTrait<'a> for Y<&'a u8> { - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/feature-gate-in_band_lifetimes.rs:53:31 - | -LL | fn my_lifetime(&self) -> &'a u8 { self.0 } - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'a` here - | -LL | impl<'a> MyTrait<'a> for Y<&'a u8> { - | ++++ -help: consider introducing lifetime `'a` here - | -LL | fn my_lifetime<'a>(&self) -> &'a u8 { self.0 } - | ++++ - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:55:27 - | -LL | fn any_lifetime() -> &'b u8 { &0 } - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | impl<'b> MyTrait<'a> for Y<&'a u8> { - | ++++ -help: consider introducing lifetime `'b` here - | -LL | fn any_lifetime<'b>() -> &'b u8 { &0 } - | ++++ - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:57:27 - | -LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 } - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | impl<'b> MyTrait<'a> for Y<&'a u8> { - | ++++ -help: consider introducing lifetime `'b` here - | -LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 } - | ++++ - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:57:40 - | -LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 } - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | impl<'b> MyTrait<'a> for Y<&'a u8> { - | ++++ -help: consider introducing lifetime `'b` here - | -LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 } - | ++++ - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:43:27 - | -LL | fn any_lifetime() -> &'b u8; - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | trait MyTrait<'b, 'a> { - | +++ -help: consider introducing lifetime `'b` here - | -LL | fn any_lifetime<'b>() -> &'b u8; - | ++++ - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:45:27 - | -LL | fn borrowed_lifetime(&'b self) -> &'b u8; - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | trait MyTrait<'b, 'a> { - | +++ -help: consider introducing lifetime `'b` here - | -LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8; - | ++++ - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:45:40 - | -LL | fn borrowed_lifetime(&'b self) -> &'b u8; - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | trait MyTrait<'b, 'a> { - | +++ -help: consider introducing lifetime `'b` here - | -LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8; - | ++++ - -error: aborting due to 17 previous errors - -For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr b/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr index ce9df46483d13..317897ae70f72 100644 --- a/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr +++ b/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr @@ -5,8 +5,6 @@ LL | fn _f(arg : Box X = &'a [u32]>>) {} | - ^^ undeclared lifetime | | | help: consider introducing lifetime `'x` here: `<'x>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0582]: binding for associated type `Y` references lifetime `'a`, which does not appear in the trait input types --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:8:33 diff --git a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr index adbd47ac16f45..bf0ca8715036b 100644 --- a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr +++ b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr @@ -4,7 +4,6 @@ error[E0261]: use of undeclared lifetime name `'b` LL | + Deref>; | ^^ undeclared lifetime | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes help: consider introducing lifetime `'b` here | LL | trait Iterable<'b> { @@ -20,7 +19,6 @@ error[E0261]: use of undeclared lifetime name `'undeclared` LL | fn iter<'a>(&'a self) -> Self::Iter<'undeclared>; | ^^^^^^^^^^^ undeclared lifetime | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes help: consider introducing lifetime `'undeclared` here | LL | trait Iterable<'undeclared> { diff --git a/src/test/ui/generic-associated-types/issue-67510.stderr b/src/test/ui/generic-associated-types/issue-67510.stderr index 8ed2854ed3057..abc02b33e0e6a 100644 --- a/src/test/ui/generic-associated-types/issue-67510.stderr +++ b/src/test/ui/generic-associated-types/issue-67510.stderr @@ -5,8 +5,6 @@ LL | fn f(x: Box=&'a ()>>) {} | - ^^ undeclared lifetime | | | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'a` --> $DIR/issue-67510.rs:7:26 @@ -15,8 +13,6 @@ LL | fn f(x: Box=&'a ()>>) {} | - ^^ undeclared lifetime | | | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs b/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs index adaa474474f67..9f63a8617babd 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs @@ -8,9 +8,8 @@ // run-pass #![allow(dead_code)] -#![feature(in_band_lifetimes)] -fn foo(x: &'x u32) -> impl Fn() -> &'y u32 +fn foo<'x, 'y>(x: &'x u32) -> impl Fn() -> &'y u32 where 'x: 'y { move || x diff --git a/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs b/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs index 204c2ff304114..79319dfe796a2 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs @@ -8,13 +8,12 @@ // run-pass #![allow(dead_code)] -#![feature(in_band_lifetimes)] trait Trait<'a> { } -impl Trait<'b> for &'a u32 { } +impl<'a, 'b> Trait<'b> for &'a u32 { } -fn foo(x: &'x u32) -> impl Trait<'y> +fn foo<'x, 'y>(x: &'x u32) -> impl Trait<'y> where 'x: 'y { x diff --git a/src/test/ui/impl-trait/region-escape-via-bound.rs b/src/test/ui/impl-trait/region-escape-via-bound.rs index 29243699e44fd..e834f96dbbeeb 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound.rs @@ -4,15 +4,14 @@ // See https://github.com/rust-lang/rust/issues/46541 for more details. #![allow(dead_code)] -#![feature(in_band_lifetimes)] use std::cell::Cell; trait Trait<'a> { } -impl Trait<'b> for Cell<&'a u32> { } +impl<'a, 'b> Trait<'b> for Cell<&'a u32> { } -fn foo(x: Cell<&'x u32>) -> impl Trait<'y> +fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0700] where 'x: 'y { diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr index cf854f67d0456..ecec34e0115c6 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.stderr +++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr @@ -1,16 +1,15 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/region-escape-via-bound.rs:15:29 + --> $DIR/region-escape-via-bound.rs:14:37 | -LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y> - | ^^^^^^^^^^^^^^ -LL | -LL | where 'x: 'y - | -- hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here +LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> + | -- ^^^^^^^^^^^^^^ + | | + | hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here | help: to declare that the `impl Trait` captures `'x`, you can add an explicit `'x` lifetime bound | -LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y> + 'x - | ++++ +LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> + 'x + | ++++ error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/E0687.rs b/src/test/ui/in-band-lifetimes/E0687.rs deleted file mode 100644 index 2e262ddaea3f4..0000000000000 --- a/src/test/ui/in-band-lifetimes/E0687.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![allow(warnings)] -#![feature(in_band_lifetimes)] - -fn foo(x: fn(&'a u32)) {} //~ ERROR must be explicitly - -fn bar(x: &Fn(&'a u32)) {} //~ ERROR must be explicitly - -fn baz(x: fn(&'a u32), y: &'a u32) {} //~ ERROR must be explicitly - -struct Foo<'a> { x: &'a u32 } - -impl Foo<'a> { - fn bar(&self, x: fn(&'a u32)) {} //~ ERROR must be explicitly -} - -fn main() {} diff --git a/src/test/ui/in-band-lifetimes/E0687.stderr b/src/test/ui/in-band-lifetimes/E0687.stderr deleted file mode 100644 index 7aea2f220466c..0000000000000 --- a/src/test/ui/in-band-lifetimes/E0687.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders - --> $DIR/E0687.rs:4:15 - | -LL | fn foo(x: fn(&'a u32)) {} - | ^^ in-band lifetime definition - -error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders - --> $DIR/E0687.rs:6:16 - | -LL | fn bar(x: &Fn(&'a u32)) {} - | ^^ in-band lifetime definition - -error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders - --> $DIR/E0687.rs:8:15 - | -LL | fn baz(x: fn(&'a u32), y: &'a u32) {} - | ^^ in-band lifetime definition - -error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders - --> $DIR/E0687.rs:13:26 - | -LL | fn bar(&self, x: fn(&'a u32)) {} - | ^^ in-band lifetime definition - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0687`. diff --git a/src/test/ui/in-band-lifetimes/E0687_where.rs b/src/test/ui/in-band-lifetimes/E0687_where.rs deleted file mode 100644 index 6cf8053287d8f..0000000000000 --- a/src/test/ui/in-band-lifetimes/E0687_where.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![allow(warnings)] -#![feature(in_band_lifetimes)] - -fn bar(x: &F) where F: Fn(&'a u32) {} //~ ERROR must be explicitly - -fn baz(x: &impl Fn(&'a u32)) {} //~ ERROR must be explicitly - -fn main() {} diff --git a/src/test/ui/in-band-lifetimes/E0687_where.stderr b/src/test/ui/in-band-lifetimes/E0687_where.stderr deleted file mode 100644 index af0f9665f5d06..0000000000000 --- a/src/test/ui/in-band-lifetimes/E0687_where.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders - --> $DIR/E0687_where.rs:4:31 - | -LL | fn bar(x: &F) where F: Fn(&'a u32) {} - | ^^ in-band lifetime definition - -error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders - --> $DIR/E0687_where.rs:6:21 - | -LL | fn baz(x: &impl Fn(&'a u32)) {} - | ^^ in-band lifetime definition - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0687`. diff --git a/src/test/ui/in-band-lifetimes/E0688.rs b/src/test/ui/in-band-lifetimes/E0688.rs deleted file mode 100644 index a4e1f01c1781a..0000000000000 --- a/src/test/ui/in-band-lifetimes/E0688.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![allow(warnings)] -#![feature(in_band_lifetimes)] - -fn foo<'a>(x: &'a u32, y: &'b u32) {} //~ ERROR cannot mix - -struct Foo<'a> { x: &'a u32 } - -impl Foo<'a> { - fn bar<'b>(x: &'a u32, y: &'b u32, z: &'c u32) {} //~ ERROR cannot mix -} - -impl<'b> Foo<'a> { //~ ERROR cannot mix - fn baz() {} -} - -fn main() {} diff --git a/src/test/ui/in-band-lifetimes/E0688.stderr b/src/test/ui/in-band-lifetimes/E0688.stderr deleted file mode 100644 index afefcd9fc2c66..0000000000000 --- a/src/test/ui/in-band-lifetimes/E0688.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0688]: cannot mix in-band and explicit lifetime definitions - --> $DIR/E0688.rs:4:28 - | -LL | fn foo<'a>(x: &'a u32, y: &'b u32) {} - | -- ^^ in-band lifetime definition here - | | - | explicit lifetime definition here - -error[E0688]: cannot mix in-band and explicit lifetime definitions - --> $DIR/E0688.rs:9:44 - | -LL | fn bar<'b>(x: &'a u32, y: &'b u32, z: &'c u32) {} - | -- ^^ in-band lifetime definition here - | | - | explicit lifetime definition here - -error[E0688]: cannot mix in-band and explicit lifetime definitions - --> $DIR/E0688.rs:12:14 - | -LL | impl<'b> Foo<'a> { - | -- ^^ in-band lifetime definition here - | | - | explicit lifetime definition here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0688`. diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed b/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed deleted file mode 100644 index 87a79b8813777..0000000000000 --- a/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed +++ /dev/null @@ -1,119 +0,0 @@ -// run-rustfix -// edition:2018 - -#![allow(unused)] -#![deny(elided_lifetimes_in_paths)] -//~^ NOTE the lint level is defined here - -use std::cell::{Ref, RefCell}; - -struct Foo<'a> { - x: &'a u32, -} - -fn foo(x: &Foo<'_>) { - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime -} - -fn bar(x: &Foo<'_>) {} - -struct Wrapped<'a>(&'a str); - -struct WrappedWithBow<'a> { - gift: &'a str, -} - -struct MatchedSet<'a, 'b> { - one: &'a str, - another: &'b str, -} - -fn wrap_gift(gift: &str) -> Wrapped<'_> { - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime - Wrapped(gift) -} - -fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow<'_> { - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime - WrappedWithBow { gift } -} - -fn inspect_matched_set(set: MatchedSet<'_, '_>) { - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected 2 lifetime parameters - //~| HELP consider using the `'_` lifetime - println!("{} {}", set.one, set.another); -} - -// Verify that the lint does not fire, because the added `'_` wouldn't be resolved correctly. -fn match_sets() -> MatchedSet<'static, 'static> { - //~^ ERROR missing lifetime specifiers - //~| NOTE expected 2 lifetime parameters - //~| HELP this function's return type contains a borrowed value - //~| HELP consider using the `'static` lifetime - MatchedSet { one: "one", another: "another" } -} - -macro_rules! autowrapper { - ($type_name:ident, $fn_name:ident, $lt:lifetime) => { - struct $type_name<$lt> { - gift: &$lt str - } - - fn $fn_name(gift: &str) -> $type_name<'_> { - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime - //~| ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime - $type_name { gift } - } - } -} - -autowrapper!(Autowrapped, autowrap_gift, 'a); -//~^ NOTE in this expansion of autowrapper! -//~| NOTE in this expansion of autowrapper! - -// Verify that rustfix does not try to apply the fix twice. -autowrapper!(AutowrappedAgain, autowrap_gift_again, 'a); -//~^ NOTE in this expansion of autowrapper! -//~| NOTE in this expansion of autowrapper! - -macro_rules! anytuple_ref_ty { - ($($types:ty),*) => { - Ref<'_, ($($types),*)> - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime - } -} - -#[allow(elided_lifetimes_in_paths)] -mod blah { - struct Thing<'a>(&'a i32); - struct Bar(T); - - fn foo(b: Bar) {} -} - -fn main() { - let honesty = RefCell::new((4, 'e')); - let loyalty: Ref<'_, (u32, char)> = honesty.borrow(); - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime - let generosity = Ref::map(loyalty, |t| &t.0); - - let laughter = RefCell::new((true, "magic")); - let yellow: anytuple_ref_ty!(bool, &str) = laughter.borrow(); - //~^ NOTE in this expansion of anytuple_ref_ty! - //~| NOTE in this expansion of anytuple_ref_ty! -} diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.rs b/src/test/ui/in-band-lifetimes/elided-lifetimes.rs deleted file mode 100644 index 28323a22427b6..0000000000000 --- a/src/test/ui/in-band-lifetimes/elided-lifetimes.rs +++ /dev/null @@ -1,119 +0,0 @@ -// run-rustfix -// edition:2018 - -#![allow(unused)] -#![deny(elided_lifetimes_in_paths)] -//~^ NOTE the lint level is defined here - -use std::cell::{Ref, RefCell}; - -struct Foo<'a> { - x: &'a u32, -} - -fn foo(x: &Foo) { - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime -} - -fn bar(x: &Foo<'_>) {} - -struct Wrapped<'a>(&'a str); - -struct WrappedWithBow<'a> { - gift: &'a str, -} - -struct MatchedSet<'a, 'b> { - one: &'a str, - another: &'b str, -} - -fn wrap_gift(gift: &str) -> Wrapped { - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime - Wrapped(gift) -} - -fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow { - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime - WrappedWithBow { gift } -} - -fn inspect_matched_set(set: MatchedSet) { - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected 2 lifetime parameters - //~| HELP consider using the `'_` lifetime - println!("{} {}", set.one, set.another); -} - -// Verify that the lint does not fire, because the added `'_` wouldn't be resolved correctly. -fn match_sets() -> MatchedSet { - //~^ ERROR missing lifetime specifiers - //~| NOTE expected 2 lifetime parameters - //~| HELP this function's return type contains a borrowed value - //~| HELP consider using the `'static` lifetime - MatchedSet { one: "one", another: "another" } -} - -macro_rules! autowrapper { - ($type_name:ident, $fn_name:ident, $lt:lifetime) => { - struct $type_name<$lt> { - gift: &$lt str - } - - fn $fn_name(gift: &str) -> $type_name { - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime - //~| ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime - $type_name { gift } - } - } -} - -autowrapper!(Autowrapped, autowrap_gift, 'a); -//~^ NOTE in this expansion of autowrapper! -//~| NOTE in this expansion of autowrapper! - -// Verify that rustfix does not try to apply the fix twice. -autowrapper!(AutowrappedAgain, autowrap_gift_again, 'a); -//~^ NOTE in this expansion of autowrapper! -//~| NOTE in this expansion of autowrapper! - -macro_rules! anytuple_ref_ty { - ($($types:ty),*) => { - Ref<($($types),*)> - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime - } -} - -#[allow(elided_lifetimes_in_paths)] -mod blah { - struct Thing<'a>(&'a i32); - struct Bar(T); - - fn foo(b: Bar) {} -} - -fn main() { - let honesty = RefCell::new((4, 'e')); - let loyalty: Ref<(u32, char)> = honesty.borrow(); - //~^ ERROR hidden lifetime parameters in types are deprecated - //~| NOTE expected named lifetime parameter - //~| HELP consider using the `'_` lifetime - let generosity = Ref::map(loyalty, |t| &t.0); - - let laughter = RefCell::new((true, "magic")); - let yellow: anytuple_ref_ty!(bool, &str) = laughter.borrow(); - //~^ NOTE in this expansion of anytuple_ref_ty! - //~| NOTE in this expansion of anytuple_ref_ty! -} diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr b/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr deleted file mode 100644 index 2e65461b321e9..0000000000000 --- a/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr +++ /dev/null @@ -1,120 +0,0 @@ -error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:14:12 - | -LL | fn foo(x: &Foo) { - | ^^^ expected named lifetime parameter - | -note: the lint level is defined here - --> $DIR/elided-lifetimes.rs:5:9 - | -LL | #![deny(elided_lifetimes_in_paths)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -help: consider using the `'_` lifetime - | -LL | fn foo(x: &Foo<'_>) { - | ~~~~~~~ - -error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:33:29 - | -LL | fn wrap_gift(gift: &str) -> Wrapped { - | ^^^^^^^ expected named lifetime parameter - | -help: consider using the `'_` lifetime - | -LL | fn wrap_gift(gift: &str) -> Wrapped<'_> { - | ~~~~~~~~~~~ - -error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:40:38 - | -LL | fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow { - | ^^^^^^^^^^^^^^ expected named lifetime parameter - | -help: consider using the `'_` lifetime - | -LL | fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow<'_> { - | ~~~~~~~~~~~~~~~~~~ - -error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:47:29 - | -LL | fn inspect_matched_set(set: MatchedSet) { - | ^^^^^^^^^^ expected 2 lifetime parameters - | -help: consider using the `'_` lifetime - | -LL | fn inspect_matched_set(set: MatchedSet<'_, '_>) { - | ~~~~~~~~~~~~~~~~~~ - -error[E0106]: missing lifetime specifiers - --> $DIR/elided-lifetimes.rs:55:20 - | -LL | fn match_sets() -> MatchedSet { - | ^^^^^^^^^^ 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 - | -LL | fn match_sets() -> MatchedSet<'static, 'static> { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:69:36 - | -LL | fn $fn_name(gift: &str) -> $type_name { - | ^^^^^^^^^^ expected named lifetime parameter -... -LL | autowrapper!(Autowrapped, autowrap_gift, 'a); - | -------------------------------------------- in this macro invocation - | - = note: this error originates in the macro `autowrapper` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider using the `'_` lifetime - | -LL | fn $fn_name(gift: &str) -> $type_name<'_> { - | ~~~~~~~~~~~~~~ - -error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:69:36 - | -LL | fn $fn_name(gift: &str) -> $type_name { - | ^^^^^^^^^^ expected named lifetime parameter -... -LL | autowrapper!(AutowrappedAgain, autowrap_gift_again, 'a); - | ------------------------------------------------------- in this macro invocation - | - = note: this error originates in the macro `autowrapper` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider using the `'_` lifetime - | -LL | fn $fn_name(gift: &str) -> $type_name<'_> { - | ~~~~~~~~~~~~~~ - -error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:109:22 - | -LL | let loyalty: Ref<(u32, char)> = honesty.borrow(); - | ^ expected named lifetime parameter - | -help: consider using the `'_` lifetime - | -LL | let loyalty: Ref<'_, (u32, char)> = honesty.borrow(); - | +++ - -error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:92:13 - | -LL | Ref<($($types),*)> - | ^ expected named lifetime parameter -... -LL | let yellow: anytuple_ref_ty!(bool, &str) = laughter.borrow(); - | ---------------------------- in this macro invocation - | - = note: this error originates in the macro `anytuple_ref_ty` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider using the `'_` lifetime - | -LL | Ref<'_, ($($types),*)> - | +++ - -error: aborting due to 9 previous errors - -For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/in-band-lifetimes/in-band-lifetimes.rs b/src/test/ui/in-band-lifetimes/in-band-lifetimes.rs deleted file mode 100644 index 9b2e1fe83c1cc..0000000000000 --- a/src/test/ui/in-band-lifetimes/in-band-lifetimes.rs +++ /dev/null @@ -1,96 +0,0 @@ -// run-pass - -#![allow(warnings)] -#![feature(in_band_lifetimes)] - -fn foo(x: &'x u8) -> &'x u8 { x } -fn foo2(x: &'a u8, y: &u8) -> &'a u8 { x } - -fn check_in_band_can_be_late_bound() { - let _: for<'x> fn(&'x u8, &u8) -> &'x u8 = foo2; -} - -struct ForInherentNoParams; - -impl ForInherentNoParams { - fn foo(x: &'a u32, y: &u32) -> &'a u32 { x } -} - -struct X<'a>(&'a u8); - -impl<'a> X<'a> { - fn inner(&self) -> &'a u8 { - self.0 - } - - fn same_lifetime_as_parameter(&mut self, x: &'a u8) { - self.0 = x; - } -} - -impl X<'b> { - fn inner_2(&self) -> &'b u8 { - self.0 - } - - fn reference_already_introduced_in_band_from_method_with_explicit_binders<'a>( - &'b self, x: &'a u32 - ) {} -} - -struct Y(T); - -impl Y<&'a u8> { - fn inner(&self) -> &'a u8 { - self.0 - } -} - -trait MyTrait<'a> { - fn my_lifetime(&self) -> &'a u8; - fn any_lifetime() -> &'b u8; - fn borrowed_lifetime(&'b self) -> &'b u8; - fn default_impl(&self, x: &'b u32, y: &u32) -> &'b u32 { x } - fn in_band_def_explicit_impl(&self, x: &'b u8); -} - -impl MyTrait<'a> for Y<&'a u8> { - fn my_lifetime(&self) -> &'a u8 { self.0 } - fn any_lifetime() -> &'b u8 { &0 } - fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 } - fn in_band_def_explicit_impl<'b>(&self, x: &'b u8) {} -} - -fn test_hrtb_defined_lifetime_where(_: F) where for<'a> F: Fn(&'a u8) {} -fn test_hrtb_defined_lifetime_polytraitref(_: F) where F: for<'a> Fn(&'a u8) {} - -fn reference_in_band_from_locals(x: &'test u32) -> &'test u32 { - let y: &'test u32 = x; - y -} - -fn in_generics_in_band>(x: &T) {} -fn where_clause_in_band(x: &T) where T: MyTrait<'a> {} -fn impl_trait_in_band(x: &impl MyTrait<'a>) {} - -// Tests around using in-band lifetimes within existential traits. - -trait FunkyTrait<'a> { } -impl<'a, T> FunkyTrait<'a> for T { } -fn ret_pos_impl_trait_in_band_outlives(x: &'a u32) -> impl ::std::fmt::Debug + 'a { - x -} -fn ret_pos_impl_trait_in_band_param(x: &'a u32) -> impl FunkyTrait<'a> { - x -} -fn ret_pos_impl_trait_in_band_param_static(x: &'a u32) -> impl FunkyTrait<'static> + 'a { - x -} -fn ret_pos_impl_trait_in_band_param_outlives(x: &'a u32) -> impl FunkyTrait<'a> + 'a { - x -} -fn ret_pos_impl_trait_in_band_higher_ranked(x: &'a u32) -> impl for<'b> FunkyTrait<'b> + 'a { - x -} - -fn main() {} diff --git a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.rs b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.rs deleted file mode 100644 index cf08cb7eeacd8..0000000000000 --- a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![deny(elided_lifetimes_in_paths)] - -// Previously, the elided-lifetimes-in-path lint would fire, but we don't want -// that, because `'_` isn't legal in struct declarations. - -struct Betrayal<'a> { x: &'a u8 } - -struct Heartbreak(Betrayal); //~ ERROR missing lifetime specifier - -fn main() {} diff --git a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr deleted file mode 100644 index 20369a543b3ae..0000000000000 --- a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0106]: missing lifetime specifier - --> $DIR/issue-61124-anon-lifetime-in-struct-declaration.rs:8:19 - | -LL | struct Heartbreak(Betrayal); - | ^^^^^^^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | struct Heartbreak<'a>(Betrayal<'a>); - | ++++ ~~~~~~~~~~~~ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/in-band-lifetimes/mismatched.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched.nll.stderr deleted file mode 100644 index db028e63a8244..0000000000000 --- a/src/test/ui/in-band-lifetimes/mismatched.nll.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0621]: explicit lifetime required in the type of `y` - --> $DIR/mismatched.rs:4:42 - | -LL | fn foo(x: &'a u32, y: &u32) -> &'a u32 { y } - | ---- ^ lifetime `'a` required - | | - | help: add explicit lifetime `'a` to the type of `y`: `&'a u32` - -error: lifetime may not live long enough - --> $DIR/mismatched.rs:6:46 - | -LL | fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y } - | -- -- ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` - | | | - | | lifetime `'b` defined here - | lifetime `'a` defined here - | - = help: consider adding the following bound: `'b: 'a` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/in-band-lifetimes/mismatched.rs b/src/test/ui/in-band-lifetimes/mismatched.rs deleted file mode 100644 index 11c41eae954d4..0000000000000 --- a/src/test/ui/in-band-lifetimes/mismatched.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![allow(warnings)] -#![feature(in_band_lifetimes)] - -fn foo(x: &'a u32, y: &u32) -> &'a u32 { y } //~ ERROR explicit lifetime required - -fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y } //~ ERROR lifetime mismatch - -fn main() {} diff --git a/src/test/ui/in-band-lifetimes/mismatched.stderr b/src/test/ui/in-band-lifetimes/mismatched.stderr deleted file mode 100644 index db72c20697108..0000000000000 --- a/src/test/ui/in-band-lifetimes/mismatched.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0621]: explicit lifetime required in the type of `y` - --> $DIR/mismatched.rs:4:42 - | -LL | fn foo(x: &'a u32, y: &u32) -> &'a u32 { y } - | ---- ^ lifetime `'a` required - | | - | help: add explicit lifetime `'a` to the type of `y`: `&'a u32` - -error[E0623]: lifetime mismatch - --> $DIR/mismatched.rs:6:46 - | -LL | fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y } - | ------- ------- ^ ...but data from `y` is returned here - | | - | this parameter and the return type are declared with different lifetimes... - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0621, E0623. -For more information about an error, try `rustc --explain E0621`. diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait.rs b/src/test/ui/in-band-lifetimes/mismatched_trait.rs deleted file mode 100644 index 221f4fc271bbf..0000000000000 --- a/src/test/ui/in-band-lifetimes/mismatched_trait.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![allow(warnings)] -#![feature(in_band_lifetimes)] - -trait Get { - fn baz(&self, x: &'a u32, y: &u32) -> &'a u32 { - y //~ ERROR explicit lifetime required - } -} - -fn main() {} diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait.stderr deleted file mode 100644 index ac66daa21c7a9..0000000000000 --- a/src/test/ui/in-band-lifetimes/mismatched_trait.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0621]: explicit lifetime required in the type of `y` - --> $DIR/mismatched_trait.rs:6:9 - | -LL | fn baz(&self, x: &'a u32, y: &u32) -> &'a u32 { - | ---- help: add explicit lifetime `'a` to the type of `y`: `&'a u32` -LL | y - | ^ lifetime `'a` required - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs deleted file mode 100644 index 1b524ec3833e8..0000000000000 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::ops::Deref; -trait Trait {} - -struct Struct; - -impl Deref for Struct { - type Target = dyn Trait; - fn deref(&self) -> &dyn Trait { - //~^ ERROR `impl` item signature doesn't match `trait` item signature - unimplemented!(); - } -} - -fn main() {} diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr deleted file mode 100644 index 0546b6b51b273..0000000000000 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: `impl` item signature doesn't match `trait` item signature - --> $DIR/mismatched_trait_impl-2.rs:8:5 - | -LL | fn deref(&self) -> &dyn Trait { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Struct) -> &'1 (dyn Trait + '1)` - | - ::: $SRC_DIR/core/src/ops/deref.rs:LL:COL - | -LL | fn deref(&self) -> &Self::Target; - | --------------------------------- expected `fn(&'1 Struct) -> &'1 (dyn Trait + 'static)` - | - = note: expected `fn(&'1 Struct) -> &'1 (dyn Trait + 'static)` - found `fn(&'1 Struct) -> &'1 (dyn Trait + '1)` - = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` - = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output - -error: aborting due to previous error - diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr deleted file mode 100644 index c7a90c57add83..0000000000000 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: `impl` item signature doesn't match `trait` item signature - --> $DIR/mismatched_trait_impl.rs:9:5 - | -LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32; - | ---------------------------------------------- expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32` -... -LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32` - | - = note: expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32` - found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32` - = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` - = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output - -error: aborting due to previous error - diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs deleted file mode 100644 index b9e02e967c126..0000000000000 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![allow(warnings)] -#![feature(in_band_lifetimes)] - -trait Get { - fn foo(&self, x: &'a u32, y: &u32) -> &'a u32; -} - -impl Get for i32 { - fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR `impl` item signature doesn't match - x //~ ERROR lifetime mismatch - } -} - -fn main() {} diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr deleted file mode 100644 index 84e5339122ead..0000000000000 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error: `impl` item signature doesn't match `trait` item signature - --> $DIR/mismatched_trait_impl.rs:9:5 - | -LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32; - | ---------------------------------------------- expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32` -... -LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32` - | - = note: expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32` - found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32` - = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` - = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output - -error[E0623]: lifetime mismatch - --> $DIR/mismatched_trait_impl.rs:10:9 - | -LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { - | ---- ------- - | | - | this parameter and the return type are declared with different lifetimes... -LL | x - | ^ ...but data from `x` is returned here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/in-band-lifetimes/mut_while_borrow.rs b/src/test/ui/in-band-lifetimes/mut_while_borrow.rs deleted file mode 100644 index 97e8ed0d2813e..0000000000000 --- a/src/test/ui/in-band-lifetimes/mut_while_borrow.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![allow(warnings)] -#![feature(in_band_lifetimes)] - -fn foo(x: &'a u32) -> &'a u32 { x } - -fn main() { - let mut p = 3; - let r = foo(&p); - p += 1; //~ ERROR cannot assign to `p` because it is borrowed - println!("{}", r); -} diff --git a/src/test/ui/in-band-lifetimes/mut_while_borrow.stderr b/src/test/ui/in-band-lifetimes/mut_while_borrow.stderr deleted file mode 100644 index f96ff9dd4e674..0000000000000 --- a/src/test/ui/in-band-lifetimes/mut_while_borrow.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0506]: cannot assign to `p` because it is borrowed - --> $DIR/mut_while_borrow.rs:9:5 - | -LL | let r = foo(&p); - | -- borrow of `p` occurs here -LL | p += 1; - | ^^^^^^ assignment to borrowed `p` occurs here -LL | println!("{}", r); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/in-band-lifetimes/nested-items.rs b/src/test/ui/in-band-lifetimes/nested-items.rs deleted file mode 100644 index 7de20712fba94..0000000000000 --- a/src/test/ui/in-band-lifetimes/nested-items.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that the `'a` from the impl doesn't -// prevent us from creating a `'a` parameter -// on the `blah` function. -// -// check-pass - -#![feature(in_band_lifetimes)] - -struct Foo<'a> { - x: &'a u32 - -} - -impl Foo<'a> { - fn method(&self) { - fn blah(f: Foo<'a>) { } - } -} - -fn main() { } diff --git a/src/test/ui/in-band-lifetimes/no_in_band_in_struct.rs b/src/test/ui/in-band-lifetimes/no_in_band_in_struct.rs deleted file mode 100644 index 9b0c0cda77220..0000000000000 --- a/src/test/ui/in-band-lifetimes/no_in_band_in_struct.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![allow(warnings)] -#![feature(in_band_lifetimes)] - -struct Foo { - x: &'test u32, //~ ERROR undeclared lifetime -} - -enum Bar { - Baz(&'test u32), //~ ERROR undeclared lifetime -} - -fn main() {} diff --git a/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr b/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr deleted file mode 100644 index fe656f7af7e01..0000000000000 --- a/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0261]: use of undeclared lifetime name `'test` - --> $DIR/no_in_band_in_struct.rs:5:9 - | -LL | struct Foo { - | - help: consider introducing lifetime `'test` here: `<'test>` -LL | x: &'test u32, - | ^^^^^ undeclared lifetime - -error[E0261]: use of undeclared lifetime name `'test` - --> $DIR/no_in_band_in_struct.rs:9:10 - | -LL | enum Bar { - | - help: consider introducing lifetime `'test` here: `<'test>` -LL | Baz(&'test u32), - | ^^^^^ undeclared lifetime - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.rs b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.rs deleted file mode 100644 index c1c40afdbab55..0000000000000 --- a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![allow(warnings)] -#![feature(in_band_lifetimes)] - -fn foo(x: &u32) { - let y: &'test u32 = x; //~ ERROR use of undeclared lifetime -} - -fn foo2(x: &u32) {} -fn bar() { - let y: fn(&'test u32) = foo2; //~ ERROR use of undeclared lifetime -} - -fn main() {} diff --git a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr deleted file mode 100644 index 5f0de61e69d29..0000000000000 --- a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0261]: use of undeclared lifetime name `'test` - --> $DIR/no_introducing_in_band_in_locals.rs:5:13 - | -LL | fn foo(x: &u32) { - | - help: consider introducing lifetime `'test` here: `<'test>` -LL | let y: &'test u32 = x; - | ^^^^^ undeclared lifetime - -error[E0261]: use of undeclared lifetime name `'test` - --> $DIR/no_introducing_in_band_in_locals.rs:10:16 - | -LL | let y: fn(&'test u32) = foo2; - | ^^^^^ undeclared lifetime - | - = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html -help: consider introducing lifetime `'test` here - | -LL | fn bar<'test>() { - | +++++++ -help: consider making the type lifetime-generic with a new `'test` lifetime - | -LL | let y: for<'test> fn(&'test u32) = foo2; - | ++++++++++ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.rs b/src/test/ui/lifetimes/missing-lifetime-in-alias.rs similarity index 97% rename from src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.rs rename to src/test/ui/lifetimes/missing-lifetime-in-alias.rs index 800f03302ed38..af7b6412780d8 100644 --- a/src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.rs +++ b/src/test/ui/lifetimes/missing-lifetime-in-alias.rs @@ -1,5 +1,4 @@ #![feature(generic_associated_types)] -#![allow(unused)] trait Trait<'a> { type Foo; diff --git a/src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.stderr b/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr similarity index 83% rename from src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.stderr rename to src/test/ui/lifetimes/missing-lifetime-in-alias.stderr index f1b951fc82632..b16b792aefee9 100644 --- a/src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.stderr +++ b/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-alias.rs:23:24 + --> $DIR/missing-lifetime-in-alias.rs:22:24 | LL | type B<'a> = as Trait>::Foo; | ^^^^^ expected named lifetime parameter @@ -10,25 +10,25 @@ LL | type B<'a> = as Trait<'a>>::Foo; | ~~~~~~~~~ error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-alias.rs:27:28 + --> $DIR/missing-lifetime-in-alias.rs:26:28 | LL | type C<'a, 'b> = as Trait>::Bar; | ^^^^^ expected named lifetime parameter | note: these named lifetimes are available to use - --> $DIR/missing-lifetime-in-alias.rs:27:8 + --> $DIR/missing-lifetime-in-alias.rs:26:8 | LL | type C<'a, 'b> = as Trait>::Bar; | ^^ ^^ error[E0107]: missing generics for associated type `Trait::Bar` - --> $DIR/missing-lifetime-in-alias.rs:27:36 + --> $DIR/missing-lifetime-in-alias.rs:26:36 | LL | type C<'a, 'b> = as Trait>::Bar; | ^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'b` - --> $DIR/missing-lifetime-in-alias.rs:7:10 + --> $DIR/missing-lifetime-in-alias.rs:6:10 | LL | type Bar<'b> | ^^^ -- diff --git a/src/test/ui/lifetimes/nested.rs b/src/test/ui/lifetimes/nested.rs new file mode 100644 index 0000000000000..f3f1f2016f237 --- /dev/null +++ b/src/test/ui/lifetimes/nested.rs @@ -0,0 +1,7 @@ +// check-pass + +fn method<'a>(_i: &'a i32) { + fn inner<'a>(_j: &'a f32) {} +} + +fn main() {} diff --git a/src/test/ui/in-band-lifetimes/shadow.rs b/src/test/ui/lifetimes/shadow.rs similarity index 71% rename from src/test/ui/in-band-lifetimes/shadow.rs rename to src/test/ui/lifetimes/shadow.rs index 27b5d57488c91..e2124887e0f09 100644 --- a/src/test/ui/in-band-lifetimes/shadow.rs +++ b/src/test/ui/lifetimes/shadow.rs @@ -1,9 +1,6 @@ -#![allow(warnings)] -#![feature(in_band_lifetimes)] - struct Foo(T); -impl Foo<&'s u8> { +impl<'s> Foo<&'s u8> { fn bar<'s>(&self, x: &'s u8) {} //~ ERROR shadows a lifetime name fn baz(x: for<'s> fn(&'s u32)) {} //~ ERROR shadows a lifetime name } diff --git a/src/test/ui/in-band-lifetimes/shadow.stderr b/src/test/ui/lifetimes/shadow.stderr similarity index 74% rename from src/test/ui/in-band-lifetimes/shadow.stderr rename to src/test/ui/lifetimes/shadow.stderr index c7a6f3ac3ad14..b834e90d8d079 100644 --- a/src/test/ui/in-band-lifetimes/shadow.stderr +++ b/src/test/ui/lifetimes/shadow.stderr @@ -1,16 +1,16 @@ error[E0496]: lifetime name `'s` shadows a lifetime name that is already in scope - --> $DIR/shadow.rs:7:12 + --> $DIR/shadow.rs:4:12 | -LL | impl Foo<&'s u8> { - | -- first declared here +LL | impl<'s> Foo<&'s u8> { + | -- first declared here LL | fn bar<'s>(&self, x: &'s u8) {} | ^^ lifetime `'s` already in scope error[E0496]: lifetime name `'s` shadows a lifetime name that is already in scope - --> $DIR/shadow.rs:8:19 + --> $DIR/shadow.rs:5:19 | -LL | impl Foo<&'s u8> { - | -- first declared here +LL | impl<'s> Foo<&'s u8> { + | -- first declared here LL | fn bar<'s>(&self, x: &'s u8) {} LL | fn baz(x: for<'s> fn(&'s u32)) {} | ^^ lifetime `'s` already in scope diff --git a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr index a208689523401..cb459f31cd243 100644 --- a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr +++ b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr @@ -5,8 +5,6 @@ LL | struct Test { | - help: consider introducing lifetime `'b` here: `<'b>` LL | a: &'b str, | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'b` --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9 @@ -15,8 +13,6 @@ LL | struct Test { | - help: consider introducing lifetime `'b` here: `<'b>` LL | a: &'b str, | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'b` --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:13:13 @@ -24,7 +20,6 @@ error[E0261]: use of undeclared lifetime name `'b` LL | fn foo(&'b self) {} | ^^ undeclared lifetime | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes help: consider introducing lifetime `'b` here | LL | impl<'b> T for Test { diff --git a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr index 93c0384fcc266..c9f235c4f7df7 100644 --- a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr +++ b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr @@ -5,8 +5,6 @@ LL | fn main() { | - help: consider introducing lifetime `'a` here: `<'a>` LL | 0.clone::<'a>(); | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error: aborting due to previous error diff --git a/src/test/ui/nll/issue-52742.rs b/src/test/ui/nll/issue-52742.rs index db9ddfff285b3..d3e201b8ae8e7 100644 --- a/src/test/ui/nll/issue-52742.rs +++ b/src/test/ui/nll/issue-52742.rs @@ -1,5 +1,3 @@ -#![feature(in_band_lifetimes)] - struct Foo<'a, 'b> { x: &'a u32, y: &'b u32, diff --git a/src/test/ui/nll/issue-52742.stderr b/src/test/ui/nll/issue-52742.stderr index 3f8481219a9ad..67bac14b6e4e1 100644 --- a/src/test/ui/nll/issue-52742.stderr +++ b/src/test/ui/nll/issue-52742.stderr @@ -1,16 +1,16 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content... - --> $DIR/issue-52742.rs:14:18 + --> $DIR/issue-52742.rs:12:18 | LL | self.y = b.z | ^^^ | note: ...the reference is valid for the lifetime `'_` as defined here... - --> $DIR/issue-52742.rs:12:10 + --> $DIR/issue-52742.rs:10:10 | LL | impl Foo<'_, '_> { | ^^ note: ...but the borrowed content is only valid for the anonymous lifetime defined here - --> $DIR/issue-52742.rs:13:31 + --> $DIR/issue-52742.rs:11:31 | LL | fn take_bar(&mut self, b: Bar<'_>) { | ^^^^^^^ diff --git a/src/test/ui/regions/regions-in-enums.stderr b/src/test/ui/regions/regions-in-enums.stderr index d56c1fbd119c8..66537653291c7 100644 --- a/src/test/ui/regions/regions-in-enums.stderr +++ b/src/test/ui/regions/regions-in-enums.stderr @@ -5,8 +5,6 @@ LL | enum No0 { | - help: consider introducing lifetime `'foo` here: `<'foo>` LL | X5(&'foo usize) | ^^^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-in-enums.rs:17:9 @@ -15,8 +13,6 @@ LL | enum No1 { | - help: consider introducing lifetime `'a` here: `<'a>` LL | X6(&'a usize) | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-in-structs.stderr b/src/test/ui/regions/regions-in-structs.stderr index 2750149d09735..5dfdc2ee93b43 100644 --- a/src/test/ui/regions/regions-in-structs.stderr +++ b/src/test/ui/regions/regions-in-structs.stderr @@ -5,8 +5,6 @@ LL | struct StructDecl { | - help: consider introducing lifetime `'a` here: `<'a>` LL | a: &'a isize, | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-in-structs.rs:11:9 @@ -16,8 +14,6 @@ LL | struct StructDecl { LL | a: &'a isize, LL | b: &'a isize, | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index 250752c9b9e68..4399263f716ed 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -5,8 +5,6 @@ LL | enum E { | - help: consider introducing lifetime `'a` here: `<'a>` LL | E1(&'a isize) | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:31:13 @@ -15,8 +13,6 @@ LL | struct S { | - help: consider introducing lifetime `'a` here: `<'a>` LL | f: &'a isize | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:16:24 @@ -24,7 +20,6 @@ error[E0261]: use of undeclared lifetime name `'b` LL | fn m4(&self, arg: &'b isize) { } | ^^ undeclared lifetime | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes help: consider introducing lifetime `'b` here | LL | impl<'b, 'a> Foo<'a> { @@ -40,7 +35,6 @@ error[E0261]: use of undeclared lifetime name `'b` LL | fn m5(&'b self) { } | ^^ undeclared lifetime | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes help: consider introducing lifetime `'b` here | LL | impl<'b, 'a> Foo<'a> { @@ -56,7 +50,6 @@ error[E0261]: use of undeclared lifetime name `'b` LL | fn m6(&self, arg: Foo<'b>) { } | ^^ undeclared lifetime | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes help: consider introducing lifetime `'b` here | LL | impl<'b, 'a> Foo<'a> { @@ -73,8 +66,6 @@ LL | type X = Option<&'a isize>; | - ^^ undeclared lifetime | | | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:33:14 @@ -83,8 +74,6 @@ LL | fn f(a: &'a isize) { } | - ^^ undeclared lifetime | | | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:41:17 @@ -93,8 +82,6 @@ LL | fn fn_types(a: &'a isize, | - ^^ undeclared lifetime | | | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:43:36 @@ -103,7 +90,6 @@ LL | ... &'b isize, | ^^ undeclared lifetime | = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes help: consider introducing lifetime `'b` here | LL | fn fn_types<'b>(a: &'a isize, @@ -120,7 +106,6 @@ LL | ... &'b isize)>, | ^^ undeclared lifetime | = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes help: consider introducing lifetime `'b` here | LL | fn fn_types<'b>(a: &'a isize, @@ -138,8 +123,6 @@ LL | fn fn_types(a: &'a isize, ... LL | c: &'a isize) | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:53:31 @@ -147,7 +130,6 @@ error[E0261]: use of undeclared lifetime name `'a` LL | async fn buggy(&self) -> &'a str { | ^^ undeclared lifetime | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes help: consider introducing lifetime `'a` here | LL | impl<'a> Bug { diff --git a/src/test/ui/regions/regions-undeclared.stderr b/src/test/ui/regions/regions-undeclared.stderr index f3cae184ccde8..6bfde5524ac49 100644 --- a/src/test/ui/regions/regions-undeclared.stderr +++ b/src/test/ui/regions/regions-undeclared.stderr @@ -11,8 +11,6 @@ LL | enum EnumDecl { | - help: consider introducing lifetime `'a` here: `<'a>` LL | Foo(&'a isize), | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-undeclared.rs:5:10 @@ -22,8 +20,6 @@ LL | enum EnumDecl { LL | Foo(&'a isize), LL | Bar(&'a isize), | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-undeclared.rs:8:15 @@ -32,8 +28,6 @@ LL | fn fnDecl(x: &'a isize, | - ^^ undeclared lifetime | | | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-undeclared.rs:9:15 @@ -42,8 +36,6 @@ LL | fn fnDecl(x: &'a isize, | - help: consider introducing lifetime `'a` here: `<'a>` LL | y: &'a isize) | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error: aborting due to 5 previous errors diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.fixed b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.fixed deleted file mode 100644 index 6bc07afccbf39..0000000000000 --- a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.fixed +++ /dev/null @@ -1,18 +0,0 @@ -// run-rustfix - -#![feature(in_band_lifetimes)] -#![deny(single_use_lifetimes)] -#![allow(dead_code)] -#![allow(unused_variables)] - -// Test that we DO warn when lifetime name is used only -// once in a fn argument, even with in band lifetimes. - -fn a(x: &u32, y: &u32) { - //~^ ERROR `'a` only used once - //~| ERROR `'b` only used once - //~| HELP elide the single-use lifetime - //~| HELP elide the single-use lifetime -} - -fn main() { } diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs deleted file mode 100644 index 22c6a5a9d3869..0000000000000 --- a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs +++ /dev/null @@ -1,18 +0,0 @@ -// run-rustfix - -#![feature(in_band_lifetimes)] -#![deny(single_use_lifetimes)] -#![allow(dead_code)] -#![allow(unused_variables)] - -// Test that we DO warn when lifetime name is used only -// once in a fn argument, even with in band lifetimes. - -fn a(x: &'a u32, y: &'b u32) { - //~^ ERROR `'a` only used once - //~| ERROR `'b` only used once - //~| HELP elide the single-use lifetime - //~| HELP elide the single-use lifetime -} - -fn main() { } diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr deleted file mode 100644 index b251e8a438ac1..0000000000000 --- a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: lifetime parameter `'a` only used once - --> $DIR/one-use-in-fn-argument-in-band.rs:11:10 - | -LL | fn a(x: &'a u32, y: &'b u32) { - | ^^- - | | - | this lifetime is only used here - | help: elide the single-use lifetime - | -note: the lint level is defined here - --> $DIR/one-use-in-fn-argument-in-band.rs:4:9 - | -LL | #![deny(single_use_lifetimes)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: lifetime parameter `'b` only used once - --> $DIR/one-use-in-fn-argument-in-band.rs:11:22 - | -LL | fn a(x: &'a u32, y: &'b u32) { - | ^^- - | | - | this lifetime is only used here - | help: elide the single-use lifetime - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.stderr b/src/test/ui/where-clauses/where-lifetime-resolution.stderr index a704fea282899..6c52664154bbf 100644 --- a/src/test/ui/where-clauses/where-lifetime-resolution.stderr +++ b/src/test/ui/where-clauses/where-lifetime-resolution.stderr @@ -6,8 +6,6 @@ LL | fn f() where LL | for<'a> dyn Trait1<'a>: Trait1<'a>, // OK LL | (dyn for<'a> Trait1<'a>): Trait1<'a>, | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'b` --> $DIR/where-lifetime-resolution.rs:8:52 @@ -17,8 +15,6 @@ LL | fn f() where ... LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error: aborting due to 2 previous errors From 43dbd83e566dcff5eb9b190cb6f539f73b3990d6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 20 Feb 2022 10:22:57 -0800 Subject: [PATCH 02/16] Remove LifetimeDefOrigin --- .../nice_region_error/find_anon_type.rs | 16 ++--- .../src/middle/resolve_lifetime.rs | 36 +----------- compiler/rustc_resolve/src/late/lifetimes.rs | 58 ++++++++----------- compiler/rustc_typeck/src/astconv/mod.rs | 4 +- compiler/rustc_typeck/src/collect.rs | 2 +- src/librustdoc/clean/mod.rs | 4 +- 6 files changed, 41 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index b1535701bb399..135714af2a6c1 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -125,7 +125,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { // Find the index of the named region that was part of the // error. We will then search the function parameters for a bound // region at the right depth with the same index - (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => { + (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); if id == def_id { self.found_type = Some(arg); @@ -137,7 +137,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { // error. We will then search the function parameters for a bound // region at the right depth with the same index ( - Some(rl::Region::LateBound(debruijn_index, _, id, _)), + Some(rl::Region::LateBound(debruijn_index, _, id)), ty::BrNamed(def_id, _), ) => { debug!( @@ -155,8 +155,8 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { Some( rl::Region::Static | rl::Region::Free(_, _) - | rl::Region::EarlyBound(_, _, _) - | rl::Region::LateBound(_, _, _, _) + | rl::Region::EarlyBound(_, _) + | rl::Region::LateBound(_, _, _) | rl::Region::LateBoundAnon(_, _, _), ) | None, @@ -221,7 +221,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { } } - (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => { + (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); if id == def_id { self.found_it = true; @@ -229,7 +229,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { } } - (Some(rl::Region::LateBound(debruijn_index, _, id, _)), ty::BrNamed(def_id, _)) => { + (Some(rl::Region::LateBound(debruijn_index, _, id)), ty::BrNamed(def_id, _)) => { debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", debruijn_index,); debug!("id={:?}", id); debug!("def_id={:?}", def_id); @@ -242,8 +242,8 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { ( Some( rl::Region::Static - | rl::Region::EarlyBound(_, _, _) - | rl::Region::LateBound(_, _, _, _) + | rl::Region::EarlyBound(_, _) + | rl::Region::LateBound(_, _, _) | rl::Region::LateBoundAnon(_, _, _) | rl::Region::Free(_, _), ) diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 4f1b391e94d01..98375cbad9f9b 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -4,44 +4,14 @@ use crate::ty; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{GenericParam, ItemLocalId}; -use rustc_hir::{GenericParamKind, LifetimeParamKind}; +use rustc_hir::ItemLocalId; use rustc_macros::HashStable; -/// The origin of a named lifetime definition. -/// -/// This is used to prevent the usage of in-band lifetimes in `Fn`/`fn` syntax. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] -pub enum LifetimeDefOrigin { - // Explicit binders like `fn foo<'a>(x: &'a u8)` or elided like `impl Foo<&u32>` - ExplicitOrElided, - // Some kind of erroneous origin - Error, -} - -impl LifetimeDefOrigin { - pub fn from_param(param: &GenericParam<'_>) -> Self { - match param.kind { - GenericParamKind::Lifetime { kind } => match kind { - LifetimeParamKind::Explicit => LifetimeDefOrigin::ExplicitOrElided, - LifetimeParamKind::Elided => LifetimeDefOrigin::ExplicitOrElided, - LifetimeParamKind::Error => LifetimeDefOrigin::Error, - }, - _ => bug!("expected a lifetime param"), - } - } -} - #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] pub enum Region { Static, - EarlyBound(/* index */ u32, /* lifetime decl */ DefId, LifetimeDefOrigin), - LateBound( - ty::DebruijnIndex, - /* late-bound index */ u32, - /* lifetime decl */ DefId, - LifetimeDefOrigin, - ), + EarlyBound(/* index */ u32, /* lifetime decl */ DefId), + LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* lifetime decl */ DefId), LateBoundAnon(ty::DebruijnIndex, /* late-bound index */ u32, /* anon index */ u32), Free(DefId, /* lifetime decl */ DefId), } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index aa25304992b25..7a7b466d82743 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1,4 +1,3 @@ -// ignore-tidy-filelength //! Name resolution for lifetimes. //! //! Name resolution for lifetimes follows *much* simpler rules than the @@ -63,23 +62,18 @@ impl RegionExt for Region { let i = *index; *index += 1; let def_id = hir_map.local_def_id(param.hir_id); - let origin = LifetimeDefOrigin::from_param(param); debug!("Region::early: index={} def_id={:?}", i, def_id); - (param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id(), origin)) + (param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id())) } fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) { let depth = ty::INNERMOST; let def_id = hir_map.local_def_id(param.hir_id); - let origin = LifetimeDefOrigin::from_param(param); debug!( - "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?} origin={:?}", - idx, param, depth, def_id, origin, + "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}", + idx, param, depth, def_id, ); - ( - param.name.normalize_to_macros_2_0(), - Region::LateBound(depth, idx, def_id.to_def_id(), origin), - ) + (param.name.normalize_to_macros_2_0(), Region::LateBound(depth, idx, def_id.to_def_id())) } fn late_anon(named_late_bound_vars: u32, index: &Cell) -> Region { @@ -93,7 +87,7 @@ impl RegionExt for Region { match *self { Region::Static | Region::LateBoundAnon(..) => None, - Region::EarlyBound(_, id, _) | Region::LateBound(_, _, id, _) | Region::Free(_, id) => { + Region::EarlyBound(_, id) | Region::LateBound(_, _, id) | Region::Free(_, id) => { Some(id) } } @@ -101,8 +95,8 @@ impl RegionExt for Region { fn shifted(self, amount: u32) -> Region { match self { - Region::LateBound(debruijn, idx, id, origin) => { - Region::LateBound(debruijn.shifted_in(amount), idx, id, origin) + Region::LateBound(debruijn, idx, id) => { + Region::LateBound(debruijn.shifted_in(amount), idx, id) } Region::LateBoundAnon(debruijn, index, anon_index) => { Region::LateBoundAnon(debruijn.shifted_in(amount), index, anon_index) @@ -113,8 +107,8 @@ impl RegionExt for Region { fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region { match self { - Region::LateBound(debruijn, index, id, origin) => { - Region::LateBound(debruijn.shifted_out_to_binder(binder), index, id, origin) + Region::LateBound(debruijn, index, id) => { + Region::LateBound(debruijn.shifted_out_to_binder(binder), index, id) } Region::LateBoundAnon(debruijn, index, anon_index) => { Region::LateBoundAnon(debruijn.shifted_out_to_binder(binder), index, anon_index) @@ -127,7 +121,7 @@ impl RegionExt for Region { where L: Iterator, { - if let Region::EarlyBound(index, _, _) = self { + if let Region::EarlyBound(index, _) = self { params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.hir_id).cloned()) } else { Some(self) @@ -568,7 +562,7 @@ fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool { fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind { match region { - Region::LateBound(_, _, def_id, _) => { + Region::LateBound(_, _, def_id) => { let name = tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local())); ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name)) } @@ -1010,7 +1004,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // well-supported at the moment, so this doesn't work. // In the future, this should be fixed and this error should be removed. let def = self.map.defs.get(&lifetime.hir_id).cloned(); - let Some(Region::LateBound(_, _, def_id, _)) = def else { + let Some(Region::LateBound(_, _, def_id)) = def else { continue }; let Some(def_id) = def_id.as_local() else { @@ -1046,7 +1040,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { match param.kind { GenericParamKind::Lifetime { .. } => { let (name, reg) = Region::early(self.tcx.hir(), &mut index, ¶m); - let Region::EarlyBound(_, def_id, _) = reg else { + let Region::EarlyBound(_, def_id) = reg else { bug!(); }; // We cannot predict what lifetimes are unused in opaque type. @@ -1668,7 +1662,7 @@ fn compute_object_lifetime_defaults<'tcx>( .map(|set| match *set { Set1::Empty => "BaseDefault".into(), Set1::One(Region::Static) => "'static".into(), - Set1::One(Region::EarlyBound(mut i, _, _)) => generics + Set1::One(Region::EarlyBound(mut i, _)) => generics .params .iter() .find_map(|param| match param.kind { @@ -1749,18 +1743,16 @@ fn object_lifetime_defaults_for_item<'tcx>( .params .iter() .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some(( - param.hir_id, - hir::LifetimeName::Param(param.name), - LifetimeDefOrigin::from_param(param), - )), + GenericParamKind::Lifetime { .. } => { + Some((param.hir_id, hir::LifetimeName::Param(param.name))) + } _ => None, }) .enumerate() - .find(|&(_, (_, lt_name, _))| lt_name == name) - .map_or(Set1::Many, |(i, (id, _, origin))| { + .find(|&(_, (_, lt_name))| lt_name == name) + .map_or(Set1::Many, |(i, (id, _))| { let def_id = tcx.hir().local_def_id(id); - Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id(), origin)) + Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id())) }) } } @@ -1948,8 +1940,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let def_ids: Vec<_> = defined_by .values() .flat_map(|region| match region { - Region::EarlyBound(_, def_id, _) - | Region::LateBound(_, _, def_id, _) + Region::EarlyBound(_, def_id) + | Region::LateBound(_, _, def_id) | Region::Free(_, def_id) => Some(*def_id), Region::LateBoundAnon(..) | Region::Static => None, @@ -2883,7 +2875,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { match lifetime { - Region::LateBound(debruijn, _, _, _) + Region::LateBound(debruijn, _, _) | Region::LateBoundAnon(debruijn, _, _) if debruijn < self.outer_index => { @@ -3289,8 +3281,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } Region::Free(_, def_id) - | Region::LateBound(_, _, def_id, _) - | Region::EarlyBound(_, def_id, _) => { + | Region::LateBound(_, _, def_id) + | Region::EarlyBound(_, def_id) => { // A lifetime declared by the user. let track_lifetime_uses = self.track_lifetime_uses(); debug!(?track_lifetime_uses); diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index dbe7ddeb6a824..1ba7534d8699b 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -205,7 +205,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let r = match tcx.named_region(lifetime.hir_id) { Some(rl::Region::Static) => tcx.lifetimes.re_static, - Some(rl::Region::LateBound(debruijn, index, def_id, _)) => { + Some(rl::Region::LateBound(debruijn, index, def_id)) => { let name = lifetime_name(def_id.expect_local()); let br = ty::BoundRegion { var: ty::BoundVar::from_u32(index), @@ -222,7 +222,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.mk_region(ty::ReLateBound(debruijn, br)) } - Some(rl::Region::EarlyBound(index, id, _)) => { + Some(rl::Region::EarlyBound(index, id)) => { let name = lifetime_name(id.expect_local()); tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name })) } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 19b3d35566b24..b03640e78ead9 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1373,7 +1373,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option {} Some( - rl::Region::LateBound(debruijn, _, _, _) + rl::Region::LateBound(debruijn, _, _) | rl::Region::LateBoundAnon(debruijn, _, _), ) if debruijn < self.outer_index => {} Some( diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 187bc13357a90..270a16ab373cc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -193,8 +193,8 @@ impl Clean for hir::Lifetime { fn clean(&self, cx: &mut DocContext<'_>) -> Lifetime { let def = cx.tcx.named_region(self.hir_id); if let Some( - rl::Region::EarlyBound(_, node_id, _) - | rl::Region::LateBound(_, _, node_id, _) + rl::Region::EarlyBound(_, node_id) + | rl::Region::LateBound(_, _, node_id) | rl::Region::Free(_, node_id), ) = def { From 8ca47d7ae4e068c94b4ab7b25cc0ccc38d01d52c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 20 Feb 2022 23:25:18 -0800 Subject: [PATCH 03/16] Stop manually SIMDing in swap_nonoverlapping Like I previously did for `reverse`, this leaves it to LLVM to pick how to vectorize it, since it can know better the chunk size to use, compared to the "32 bytes always" approach we currently have. It does still need logic to type-erase where appropriate, though, as while LLVM is now smart enough to vectorize over slices of things like `[u8; 4]`, it fails to do so over slices of `[u8; 3]`. As a bonus, this also means one no longer gets the spurious `memcpy`(s?) at the end up swapping a slice of `__m256`s: --- library/core/benches/slice.rs | 43 ++++++++- library/core/src/mem/mod.rs | 45 ++++++++- library/core/src/ptr/mod.rs | 132 +++++++++------------------ src/test/codegen/swap-large-types.rs | 64 +++++++++++++ src/test/codegen/swap-simd-types.rs | 32 +++++++ src/test/codegen/swap-small-types.rs | 44 +++++++++ 6 files changed, 263 insertions(+), 97 deletions(-) create mode 100644 src/test/codegen/swap-large-types.rs create mode 100644 src/test/codegen/swap-simd-types.rs diff --git a/library/core/benches/slice.rs b/library/core/benches/slice.rs index 04efa52078778..9b86a0ca97c09 100644 --- a/library/core/benches/slice.rs +++ b/library/core/benches/slice.rs @@ -89,6 +89,15 @@ fn binary_search_l3_worst_case(b: &mut Bencher) { binary_search_worst_case(b, Cache::L3); } +#[derive(Clone)] +struct Rgb(u8, u8, u8); + +impl Rgb { + fn gen(i: usize) -> Self { + Rgb(i as u8, (i as u8).wrapping_add(7), (i as u8).wrapping_add(42)) + } +} + macro_rules! rotate { ($fn:ident, $n:expr, $mapper:expr) => { #[bench] @@ -104,17 +113,43 @@ macro_rules! rotate { }; } -#[derive(Clone)] -struct Rgb(u8, u8, u8); - rotate!(rotate_u8, 32, |i| i as u8); -rotate!(rotate_rgb, 32, |i| Rgb(i as u8, (i as u8).wrapping_add(7), (i as u8).wrapping_add(42))); +rotate!(rotate_rgb, 32, Rgb::gen); rotate!(rotate_usize, 32, |i| i); rotate!(rotate_16_usize_4, 16, |i| [i; 4]); rotate!(rotate_16_usize_5, 16, |i| [i; 5]); rotate!(rotate_64_usize_4, 64, |i| [i; 4]); rotate!(rotate_64_usize_5, 64, |i| [i; 5]); +macro_rules! swap_with_slice { + ($fn:ident, $n:expr, $mapper:expr) => { + #[bench] + fn $fn(b: &mut Bencher) { + let mut x = (0usize..$n).map(&$mapper).collect::>(); + let mut y = ($n..($n * 2)).map(&$mapper).collect::>(); + let mut skip = 0; + b.iter(|| { + for _ in 0..32 { + x[skip..].swap_with_slice(&mut y[..($n - skip)]); + skip = black_box(skip + 1) % 8; + } + black_box((x[$n / 3].clone(), y[$n * 2 / 3].clone())) + }) + } + }; +} + +swap_with_slice!(swap_with_slice_u8_30, 30, |i| i as u8); +swap_with_slice!(swap_with_slice_u8_3000, 3000, |i| i as u8); +swap_with_slice!(swap_with_slice_rgb_30, 30, Rgb::gen); +swap_with_slice!(swap_with_slice_rgb_3000, 3000, Rgb::gen); +swap_with_slice!(swap_with_slice_usize_30, 30, |i| i); +swap_with_slice!(swap_with_slice_usize_3000, 3000, |i| i); +swap_with_slice!(swap_with_slice_4x_usize_30, 30, |i| [i; 4]); +swap_with_slice!(swap_with_slice_4x_usize_3000, 3000, |i| [i; 4]); +swap_with_slice!(swap_with_slice_5x_usize_30, 30, |i| [i; 5]); +swap_with_slice!(swap_with_slice_5x_usize_3000, 3000, |i| [i; 5]); + #[bench] fn fill_byte_sized(b: &mut Bencher) { #[derive(Copy, Clone)] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 989ec0639cd6b..b5c1ae37e5e89 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -700,10 +700,49 @@ pub unsafe fn uninitialized() -> T { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] pub const fn swap(x: &mut T, y: &mut T) { - // SAFETY: the raw pointers have been created from safe mutable references satisfying all the - // constraints on `ptr::swap_nonoverlapping_one` + // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary + // reinterpretation of values as (chunkable) byte arrays, and the loop in the + // block optimization in `swap_slice` is hard to rewrite back + // into the (unoptimized) direct swapping implementation, so we disable it. + // FIXME(eddyb) the block optimization also prevents MIR optimizations from + // understanding `mem::replace`, `Option::take`, etc. - a better overall + // solution might be to make `ptr::swap_nonoverlapping` into an intrinsic, which + // a backend can choose to implement using the block optimization, or not. + #[cfg(not(target_arch = "spirv"))] + { + // For types that are larger multiples of their alignment, the simple way + // tends to copy the whole thing to stack rather than doing it one part + // at a time, so instead treat them as one-element slices and piggy-back + // the slice optimizations that will split up the swaps. + if size_of::() / align_of::() > 4 { + // SAFETY: exclusive references always point to one non-overlapping + // element and are non-null and properly aligned. + return unsafe { ptr::swap_nonoverlapping(x, y, 1) }; + } + } + + // If a scalar consists of just a small number of alignment units, let + // the codegen just swap those pieces directly, as it's likely just a + // few instructions and anything else is probably overcomplicated. + // + // Most importantly, this covers primitives and simd types that tend to + // have size=align where doing anything else can be a pessimization. + // (This will also be used for ZSTs, though any solution works for them.) + swap_simple(x, y); +} + +/// Same as [`swap`] semantically, but always uses the simple implementation. +/// +/// Used elsewhere in `mem` and `ptr` at the bottom layer of calls. +#[rustc_const_unstable(feature = "const_swap", issue = "83163")] +#[inline] +pub(crate) const fn swap_simple(x: &mut T, y: &mut T) { + // SAFETY: exclusive references are always valid to read/write, + // are non-overlapping, and nothing here panics so it's drop-safe. unsafe { - ptr::swap_nonoverlapping_one(x, y); + let z = ptr::read(x); + ptr::copy_nonoverlapping(y, x, 1); + ptr::write(y, z); } } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 8ab72e6aeeafa..ff71fadb61418 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -419,106 +419,58 @@ pub const unsafe fn swap(x: *mut T, y: *mut T) { #[stable(feature = "swap_nonoverlapping", since = "1.27.0")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { - let x = x as *mut u8; - let y = y as *mut u8; - let len = mem::size_of::() * count; - // SAFETY: the caller must guarantee that `x` and `y` are - // valid for writes and properly aligned. - unsafe { swap_nonoverlapping_bytes(x, y, len) } -} + macro_rules! attempt_swap_as_chunks { + ($ChunkTy:ty) => { + if mem::align_of::() >= mem::align_of::<$ChunkTy>() + && mem::size_of::() % mem::size_of::<$ChunkTy>() == 0 + { + let x: *mut MaybeUninit<$ChunkTy> = x.cast(); + let y: *mut MaybeUninit<$ChunkTy> = y.cast(); + let count = count * (mem::size_of::() / mem::size_of::<$ChunkTy>()); + // SAFETY: these are the same bytes that the caller promised were + // ok, just typed as `MaybeUninit`s instead of as `T`s. + // The `if` condition above ensures that we're not violating + // alignment requirements, and that the division is exact so + // that we don't lose any bytes off the end. + return unsafe { swap_nonoverlapping_simple(x, y, count) }; + } + }; + } -#[inline] -#[rustc_const_unstable(feature = "const_swap", issue = "83163")] -pub(crate) const unsafe fn swap_nonoverlapping_one(x: *mut T, y: *mut T) { - // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary - // reinterpretation of values as (chunkable) byte arrays, and the loop in the - // block optimization in `swap_nonoverlapping_bytes` is hard to rewrite back - // into the (unoptimized) direct swapping implementation, so we disable it. - // FIXME(eddyb) the block optimization also prevents MIR optimizations from - // understanding `mem::replace`, `Option::take`, etc. - a better overall - // solution might be to make `swap_nonoverlapping` into an intrinsic, which - // a backend can choose to implement using the block optimization, or not. - #[cfg(not(target_arch = "spirv"))] + // Split up the slice into small power-of-two-sized chunks that LLVM is able + // to vectorize (unless it's a special type with more-than-pointer alignment, + // because we don't want to pessimize things like slices of SIMD vectors.) + if mem::align_of::() <= mem::size_of::() + && (!mem::size_of::().is_power_of_two() + || mem::size_of::() > mem::size_of::() * 2) { - // Only apply the block optimization in `swap_nonoverlapping_bytes` for types - // at least as large as the block size, to avoid pessimizing codegen. - if mem::size_of::() >= 32 { - // SAFETY: the caller must uphold the safety contract for `swap_nonoverlapping`. - unsafe { swap_nonoverlapping(x, y, 1) }; - return; - } + attempt_swap_as_chunks!(usize); + attempt_swap_as_chunks!(u8); } - // Direct swapping, for the cases not going through the block optimization. - // SAFETY: the caller must guarantee that `x` and `y` are valid - // for writes, properly aligned, and non-overlapping. - unsafe { - let z = read(x); - copy_nonoverlapping(y, x, 1); - write(y, z); - } + // SAFETY: Same preconditions as this function + unsafe { swap_nonoverlapping_simple(x, y, count) } } +/// Same behaviour and safety conditions as [`swap_nonoverlapping`] +/// +/// LLVM can vectorize this (at least it can for the power-of-two-sized types +/// `swap_nonoverlapping` tries to use) so no need to manually SIMD it. #[inline] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] -const unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { - // The approach here is to utilize simd to swap x & y efficiently. Testing reveals - // that swapping either 32 bytes or 64 bytes at a time is most efficient for Intel - // Haswell E processors. LLVM is more able to optimize if we give a struct a - // #[repr(simd)], even if we don't actually use this struct directly. - // - // FIXME repr(simd) broken on emscripten and redox - #[cfg_attr(not(any(target_os = "emscripten", target_os = "redox")), repr(simd))] - struct Block(u64, u64, u64, u64); - struct UnalignedBlock(u64, u64, u64, u64); - - let block_size = mem::size_of::(); - - // Loop through x & y, copying them `Block` at a time - // The optimizer should unroll the loop fully for most types - // N.B. We can't use a for loop as the `range` impl calls `mem::swap` recursively +const unsafe fn swap_nonoverlapping_simple(x: *mut T, y: *mut T, count: usize) { let mut i = 0; - while i + block_size <= len { - // Create some uninitialized memory as scratch space - // Declaring `t` here avoids aligning the stack when this loop is unused - let mut t = mem::MaybeUninit::::uninit(); - let t = t.as_mut_ptr() as *mut u8; - - // SAFETY: As `i < len`, and as the caller must guarantee that `x` and `y` are valid - // for `len` bytes, `x + i` and `y + i` must be valid addresses, which fulfills the - // safety contract for `add`. - // - // Also, the caller must guarantee that `x` and `y` are valid for writes, properly aligned, - // and non-overlapping, which fulfills the safety contract for `copy_nonoverlapping`. - unsafe { - let x = x.add(i); - let y = y.add(i); + while i < count { + let x: &mut T = + // SAFETY: By precondition, `i` is in-bounds because it's below `n` + unsafe { &mut *x.add(i) }; + let y: &mut T = + // SAFETY: By precondition, `i` is in-bounds because it's below `n` + // and it's distinct from `x` since the ranges are non-overlapping + unsafe { &mut *y.add(i) }; + mem::swap_simple(x, y); - // Swap a block of bytes of x & y, using t as a temporary buffer - // This should be optimized into efficient SIMD operations where available - copy_nonoverlapping(x, t, block_size); - copy_nonoverlapping(y, x, block_size); - copy_nonoverlapping(t, y, block_size); - } - i += block_size; - } - - if i < len { - // Swap any remaining bytes - let mut t = mem::MaybeUninit::::uninit(); - let rem = len - i; - - let t = t.as_mut_ptr() as *mut u8; - - // SAFETY: see previous safety comment. - unsafe { - let x = x.add(i); - let y = y.add(i); - - copy_nonoverlapping(x, t, rem); - copy_nonoverlapping(y, x, rem); - copy_nonoverlapping(t, y, rem); - } + i += 1; } } diff --git a/src/test/codegen/swap-large-types.rs b/src/test/codegen/swap-large-types.rs new file mode 100644 index 0000000000000..535d301a3d27b --- /dev/null +++ b/src/test/codegen/swap-large-types.rs @@ -0,0 +1,64 @@ +// compile-flags: -O +// only-x86_64 +// ignore-debug: the debug assertions get in the way + +#![crate_type = "lib"] + +use std::mem::swap; +use std::ptr::{read, copy_nonoverlapping, write}; + +type KeccakBuffer = [[u64; 5]; 5]; + +// A basic read+copy+write swap implementation ends up copying one of the values +// to stack for large types, which is completely unnecessary as the lack of +// overlap means we can just do whatever fits in registers at a time. + +// CHECK-LABEL: @swap_basic +#[no_mangle] +pub fn swap_basic(x: &mut KeccakBuffer, y: &mut KeccakBuffer) { +// CHECK: alloca [5 x [5 x i64]] + + // SAFETY: exclusive references are always valid to read/write, + // are non-overlapping, and nothing here panics so it's drop-safe. + unsafe { + let z = read(x); + copy_nonoverlapping(y, x, 1); + write(y, z); + } +} + +// This test verifies that the library does something smarter, and thus +// doesn't need any scratch space on the stack. + +// CHECK-LABEL: @swap_std +#[no_mangle] +pub fn swap_std(x: &mut KeccakBuffer, y: &mut KeccakBuffer) { +// CHECK-NOT: alloca +// CHECK: load <{{[0-9]+}} x i64> +// CHECK: store <{{[0-9]+}} x i64> + swap(x, y) +} + +// CHECK-LABEL: @swap_slice +#[no_mangle] +pub fn swap_slice(x: &mut [KeccakBuffer], y: &mut [KeccakBuffer]) { +// CHECK-NOT: alloca +// CHECK: load <{{[0-9]+}} x i64> +// CHECK: store <{{[0-9]+}} x i64> + if x.len() == y.len() { + x.swap_with_slice(y); + } +} + +type OneKilobyteBuffer = [u8; 1024]; + +// CHECK-LABEL: @swap_1kb_slices +#[no_mangle] +pub fn swap_1kb_slices(x: &mut [OneKilobyteBuffer], y: &mut [OneKilobyteBuffer]) { +// CHECK-NOT: alloca +// CHECK: load <{{[0-9]+}} x i8> +// CHECK: store <{{[0-9]+}} x i8> + if x.len() == y.len() { + x.swap_with_slice(y); + } +} diff --git a/src/test/codegen/swap-simd-types.rs b/src/test/codegen/swap-simd-types.rs new file mode 100644 index 0000000000000..c90b277eb4487 --- /dev/null +++ b/src/test/codegen/swap-simd-types.rs @@ -0,0 +1,32 @@ +// compile-flags: -O -C target-feature=+avx +// only-x86_64 +// ignore-debug: the debug assertions get in the way + +#![crate_type = "lib"] + +use std::mem::swap; + +// SIMD types are highly-aligned already, so make sure the swap code leaves their +// types alone and doesn't pessimize them (such as by swapping them as `usize`s). +extern crate core; +use core::arch::x86_64::__m256; + +// CHECK-LABEL: @swap_single_m256 +#[no_mangle] +pub fn swap_single_m256(x: &mut __m256, y: &mut __m256) { +// CHECK-NOT: alloca +// CHECK: load <8 x float>{{.+}}align 32 +// CHECK: store <8 x float>{{.+}}align 32 + swap(x, y) +} + +// CHECK-LABEL: @swap_m256_slice +#[no_mangle] +pub fn swap_m256_slice(x: &mut [__m256], y: &mut [__m256]) { +// CHECK-NOT: alloca +// CHECK: load <8 x float>{{.+}}align 32 +// CHECK: store <8 x float>{{.+}}align 32 + if x.len() == y.len() { + x.swap_with_slice(y); + } +} diff --git a/src/test/codegen/swap-small-types.rs b/src/test/codegen/swap-small-types.rs index 6205e6a6559c9..2f375844cc716 100644 --- a/src/test/codegen/swap-small-types.rs +++ b/src/test/codegen/swap-small-types.rs @@ -16,3 +16,47 @@ pub fn swap_rgb48(x: &mut RGB48, y: &mut RGB48) { // CHECK: store i48 swap(x, y) } + +// LLVM doesn't vectorize a loop over 3-byte elements, +// so we chunk it down to bytes and loop over those instead. +type RGB24 = [u8; 3]; + +// CHECK-LABEL: @swap_rgb24_slices +#[no_mangle] +pub fn swap_rgb24_slices(x: &mut [RGB24], y: &mut [RGB24]) { +// CHECK-NOT: alloca +// CHECK: load <{{[0-9]+}} x i8> +// CHECK: store <{{[0-9]+}} x i8> + if x.len() == y.len() { + x.swap_with_slice(y); + } +} + +// This one has a power-of-two size, so we iterate over it directly +type RGBA32 = [u8; 4]; + +// CHECK-LABEL: @swap_rgba32_slices +#[no_mangle] +pub fn swap_rgba32_slices(x: &mut [RGBA32], y: &mut [RGBA32]) { +// CHECK-NOT: alloca +// CHECK: load <{{[0-9]+}} x i32> +// CHECK: store <{{[0-9]+}} x i32> + if x.len() == y.len() { + x.swap_with_slice(y); + } +} + +// Strings have a non-power-of-two size, but have pointer alignment, +// so we swap usizes instead of dropping all the way down to bytes. +const _: () = assert!(!std::mem::size_of::().is_power_of_two()); + +// CHECK-LABEL: @swap_string_slices +#[no_mangle] +pub fn swap_string_slices(x: &mut [String], y: &mut [String]) { +// CHECK-NOT: alloca +// CHECK: load <{{[0-9]+}} x i64> +// CHECK: store <{{[0-9]+}} x i64> + if x.len() == y.len() { + x.swap_with_slice(y); + } +} From da896d35f471a27eb7b9385d6eadf50a5f761265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20BRANSTETT?= Date: Sat, 19 Feb 2022 23:06:11 +0100 Subject: [PATCH 04/16] Improve CheckCfg internal representation --- compiler/rustc_attr/src/builtin.rs | 31 ++++++++------- compiler/rustc_interface/src/interface.rs | 22 ++++++++--- compiler/rustc_session/src/config.rs | 48 ++++++++++++----------- 3 files changed, 58 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 49043e9f5f9d6..cd2e150a1907d 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -463,27 +463,30 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat MetaItemKind::NameValue(..) | MetaItemKind::Word => { let name = cfg.ident().expect("multi-segment cfg predicate").name; let value = cfg.value_str(); - if sess.check_config.names_checked && !sess.check_config.names_valid.contains(&name) - { - sess.buffer_lint( - UNEXPECTED_CFGS, - cfg.span, - CRATE_NODE_ID, - "unexpected `cfg` condition name", - ); - } - if let Some(val) = value { - if sess.check_config.values_checked.contains(&name) - && !sess.check_config.values_valid.contains(&(name, val)) - { + if let Some(names_valid) = &sess.check_config.names_valid { + if !names_valid.contains(&name) { sess.buffer_lint( UNEXPECTED_CFGS, cfg.span, CRATE_NODE_ID, - "unexpected `cfg` condition value", + "unexpected `cfg` condition name", ); } } + if let Some(val) = value { + if let Some(values_valid) = &sess.check_config.values_valid { + if let Some(values) = values_valid.get(&name) { + if !values.contains(&val) { + sess.buffer_lint( + UNEXPECTED_CFGS, + cfg.span, + CRATE_NODE_ID, + "unexpected `cfg` condition value", + ); + } + } + } + } sess.config.contains(&(name, value)) } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 609fc4b78c0de..5e0d59bf1b136 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -169,11 +169,12 @@ pub fn parse_check_cfg(specs: Vec) -> CheckCfg { Ok(meta_item) if parser.token == token::Eof => { if let Some(args) = meta_item.meta_item_list() { if meta_item.has_name(sym::names) { - cfg.names_checked = true; + let names_valid = + cfg.names_valid.get_or_insert_with(|| FxHashSet::default()); for arg in args { if arg.is_word() && arg.ident().is_some() { let ident = arg.ident().expect("multi-segment cfg key"); - cfg.names_valid.insert(ident.name.to_string()); + names_valid.insert(ident.name.to_string()); } else { error!("`names()` arguments must be simple identifers"); } @@ -182,14 +183,19 @@ pub fn parse_check_cfg(specs: Vec) -> CheckCfg { } else if meta_item.has_name(sym::values) { if let Some((name, values)) = args.split_first() { if name.is_word() && name.ident().is_some() { + let values_valid = cfg + .values_valid + .get_or_insert_with(|| FxHashMap::default()); let ident = name.ident().expect("multi-segment cfg key"); - cfg.values_checked.insert(ident.to_string()); + let ident_values = values_valid + .entry(ident.to_string()) + .or_insert_with(|| FxHashSet::default()); + for val in values { if let Some(LitKind::Str(s, _)) = val.literal().map(|lit| &lit.kind) { - cfg.values_valid - .insert((ident.to_string(), s.to_string())); + ident_values.insert(s.to_string()); } else { error!( "`values()` arguments must be string literals" @@ -219,7 +225,11 @@ pub fn parse_check_cfg(specs: Vec) -> CheckCfg { ); } - cfg.names_valid.extend(cfg.values_checked.iter().cloned()); + if let Some(values_valid) = &cfg.values_valid { + if let Some(names_valid) = &mut cfg.names_valid { + names_valid.extend(values_valid.keys().cloned()); + } + } cfg }) } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 7a0d9a212c9d9..e0a3cc78b1772 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -8,7 +8,7 @@ use crate::search_paths::SearchPath; use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; use crate::{early_error, early_warn, Session}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::impl_stable_hash_via_hash; use rustc_target::abi::{Align, TargetDataLayout}; @@ -1023,34 +1023,28 @@ pub fn to_crate_config(cfg: FxHashSet<(String, Option)>) -> CrateConfig /// The parsed `--check-cfg` options pub struct CheckCfg { - /// Set if `names()` checking is enabled - pub names_checked: bool, - /// The union of all `names()` - pub names_valid: FxHashSet, - /// The set of names for which `values()` was used - pub values_checked: FxHashSet, - /// The set of all (name, value) pairs passed in `values()` - pub values_valid: FxHashSet<(T, T)>, + /// The set of all `names()`, if none no names checking is performed + pub names_valid: Option>, + /// The set of all `values()`, if none no values chcking is performed + pub values_valid: Option>>, } impl Default for CheckCfg { fn default() -> Self { - CheckCfg { - names_checked: false, - names_valid: FxHashSet::default(), - values_checked: FxHashSet::default(), - values_valid: FxHashSet::default(), - } + CheckCfg { names_valid: Default::default(), values_valid: Default::default() } } } impl CheckCfg { fn map_data(&self, f: impl Fn(&T) -> O) -> CheckCfg { CheckCfg { - names_checked: self.names_checked, - names_valid: self.names_valid.iter().map(|a| f(a)).collect(), - values_checked: self.values_checked.iter().map(|a| f(a)).collect(), - values_valid: self.values_valid.iter().map(|(a, b)| (f(a), f(b))).collect(), + names_valid: self + .names_valid + .as_ref() + .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()), + values_valid: self.values_valid.as_ref().map(|values_valid| { + values_valid.iter().map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect())).collect() + }), } } } @@ -1090,17 +1084,25 @@ impl CrateCheckConfig { sym::doctest, sym::feature, ]; - for &name in WELL_KNOWN_NAMES { - self.names_valid.insert(name); + if let Some(names_valid) = &mut self.names_valid { + for &name in WELL_KNOWN_NAMES { + names_valid.insert(name); + } } } /// Fills a `CrateCheckConfig` with configuration names and values that are actually active. pub fn fill_actual(&mut self, cfg: &CrateConfig) { for &(k, v) in cfg { - self.names_valid.insert(k); + if let Some(names_valid) = &mut self.names_valid { + names_valid.insert(k); + } if let Some(v) = v { - self.values_valid.insert((k, v)); + if let Some(values_valid) = &mut self.values_valid { + values_valid.entry(k).and_modify(|values| { + values.insert(v); + }); + } } } } From fbe1c153ecc88651a147517a6c1aea3da6aca8fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20BRANSTETT?= Date: Sun, 20 Feb 2022 00:04:10 +0100 Subject: [PATCH 05/16] Add test for well known names defined by rustc --- src/test/ui/check-cfg/well-known-names.rs | 27 +++++++++++++++++++ src/test/ui/check-cfg/well-known-names.stderr | 22 +++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/test/ui/check-cfg/well-known-names.rs create mode 100644 src/test/ui/check-cfg/well-known-names.stderr diff --git a/src/test/ui/check-cfg/well-known-names.rs b/src/test/ui/check-cfg/well-known-names.rs new file mode 100644 index 0000000000000..a66568a2ffdc9 --- /dev/null +++ b/src/test/ui/check-cfg/well-known-names.rs @@ -0,0 +1,27 @@ +// This test checks that we lint on non well known names and that we don't lint on well known names +// +// check-pass +// compile-flags: --check-cfg=names() -Z unstable-options + +#[cfg(target_oz = "linux")] +//~^ WARNING unexpected `cfg` condition name +fn target_os_misspell() {} + +#[cfg(target_os = "linux")] +fn target_os() {} + +#[cfg(features = "foo")] +//~^ WARNING unexpected `cfg` condition name +fn feature_misspell() {} + +#[cfg(feature = "foo")] +fn feature() {} + +#[cfg(uniw)] +//~^ WARNING unexpected `cfg` condition name +fn unix_misspell() {} + +#[cfg(unix)] +fn unix() {} + +fn main() {} diff --git a/src/test/ui/check-cfg/well-known-names.stderr b/src/test/ui/check-cfg/well-known-names.stderr new file mode 100644 index 0000000000000..a6b9a77dc8d9a --- /dev/null +++ b/src/test/ui/check-cfg/well-known-names.stderr @@ -0,0 +1,22 @@ +warning: unexpected `cfg` condition name + --> $DIR/well-known-names.rs:6:7 + | +LL | #[cfg(target_oz = "linux")] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name + --> $DIR/well-known-names.rs:13:7 + | +LL | #[cfg(features = "foo")] + | ^^^^^^^^^^^^^^^^ + +warning: unexpected `cfg` condition name + --> $DIR/well-known-names.rs:20:7 + | +LL | #[cfg(uniw)] + | ^^^^ + +warning: 3 warnings emitted + From 3d234770b1c83840d18305e8625da38e97da3174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20BRANSTETT?= Date: Sun, 20 Feb 2022 00:48:10 +0100 Subject: [PATCH 06/16] Improve diagnostic of the unexpected_cfgs lint --- compiler/rustc_attr/src/builtin.rs | 15 ++++++-- compiler/rustc_lint/src/context.rs | 34 ++++++++++++++++++- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint_defs/src/lib.rs | 1 + src/test/ui/check-cfg/invalid-cfg-name.stderr | 2 +- .../ui/check-cfg/invalid-cfg-value.stderr | 1 + src/test/ui/check-cfg/well-known-names.stderr | 10 ++++-- 7 files changed, 57 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index cd2e150a1907d..503e172b6873f 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -8,6 +8,7 @@ use rustc_errors::{struct_span_err, Applicability}; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; use rustc_macros::HashStable_Generic; use rustc_session::lint::builtin::UNEXPECTED_CFGS; +use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; use rustc_session::Session; use rustc_span::hygiene::Transparency; @@ -465,11 +466,16 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat let value = cfg.value_str(); if let Some(names_valid) = &sess.check_config.names_valid { if !names_valid.contains(&name) { - sess.buffer_lint( + sess.buffer_lint_with_diagnostic( UNEXPECTED_CFGS, cfg.span, CRATE_NODE_ID, "unexpected `cfg` condition name", + BuiltinLintDiagnostics::UnexpectedCfg( + cfg.ident().unwrap().span, + name, + None, + ), ); } } @@ -477,11 +483,16 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat if let Some(values_valid) = &sess.check_config.values_valid { if let Some(values) = values_valid.get(&name) { if !values.contains(&val) { - sess.buffer_lint( + sess.buffer_lint_with_diagnostic( UNEXPECTED_CFGS, cfg.span, CRATE_NODE_ID, "unexpected `cfg` condition value", + BuiltinLintDiagnostics::UnexpectedCfg( + cfg.name_value_literal_span().unwrap(), + name, + Some(val), + ), ); } } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index d2d853efda2d2..72a3f5d5fc9b8 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -766,7 +766,39 @@ pub trait LintContext: Sized { BuiltinLintDiagnostics::NamedAsmLabel(help) => { db.help(&help); db.note("see the asm section of Rust By Example for more information"); - } + }, + BuiltinLintDiagnostics::UnexpectedCfg(span, name, value) => { + let mut possibilities: Vec = if value.is_some() { + let Some(values_valid) = &sess.parse_sess.check_config.values_valid else { + bug!("it shouldn't be possible to have a diagnostic on a value if values checking is not enable"); + }; + let Some(values) = values_valid.get(&name) else { + bug!("it shouldn't be possible to have a diagnostic on a value whose name is not in values"); + }; + values.iter().map(|&s| s).collect() + } else { + let Some(names_valid) = &sess.parse_sess.check_config.names_valid else { + bug!("it shouldn't be possible to have a diagnostic on a value if values checking is not enable"); + }; + names_valid.iter().map(|s| *s).collect() + }; + + // Show the full list if all possible values for a given name, but don't do it + // for names as the possibilities could be very long + if value.is_some() { + // Sorting can take some time, so we only do it if required + possibilities.sort(); + + let possibilities = possibilities.iter().map(Symbol::as_str).intersperse(", ").collect::(); + db.note(&format!("possible values for `{name}` are: {possibilities}")); + } + + // Suggest the most probable if we found one + if let Some(best_match) = find_best_match_for_name(&possibilities, value.unwrap_or(name), None) { + let ponctuation = if value.is_some() { "\"" } else { "" }; + db.span_suggestion(span, "did you mean", format!("{ponctuation}{best_match}{ponctuation}"), Applicability::MaybeIncorrect); + } + }, } // Rewrap `db`, and pass control to the user. decorate(LintDiagnosticBuilder::new(db)); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 69863b5ff827f..7182022d25298 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -31,6 +31,7 @@ #![feature(box_patterns)] #![feature(crate_visibility_modifier)] #![feature(if_let_guard)] +#![feature(iter_intersperse)] #![feature(iter_order_by)] #![feature(let_else)] #![feature(never_type)] diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 1f834b7212fe5..e9c62fc400651 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -310,6 +310,7 @@ pub enum BuiltinLintDiagnostics { BreakWithLabelAndLoop(Span), NamedAsmLabel(String), UnicodeTextFlow(Span, String), + UnexpectedCfg(Span, Symbol, Option), } /// Lints that are buffered up early on in the `Session` before the diff --git a/src/test/ui/check-cfg/invalid-cfg-name.stderr b/src/test/ui/check-cfg/invalid-cfg-name.stderr index 2587685afa048..2bd1821c9422b 100644 --- a/src/test/ui/check-cfg/invalid-cfg-name.stderr +++ b/src/test/ui/check-cfg/invalid-cfg-name.stderr @@ -2,7 +2,7 @@ warning: unexpected `cfg` condition name --> $DIR/invalid-cfg-name.rs:7:7 | LL | #[cfg(widnows)] - | ^^^^^^^ + | ^^^^^^^ help: did you mean: `windows` | = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/src/test/ui/check-cfg/invalid-cfg-value.stderr b/src/test/ui/check-cfg/invalid-cfg-value.stderr index c591d8474a261..23fd5c8c759cf 100644 --- a/src/test/ui/check-cfg/invalid-cfg-value.stderr +++ b/src/test/ui/check-cfg/invalid-cfg-value.stderr @@ -5,6 +5,7 @@ LL | #[cfg(feature = "sedre")] | ^^^^^^^^^^^^^^^^^ | = note: `#[warn(unexpected_cfgs)]` on by default + = note: possible values for `feature` are: rand, serde, full warning: 1 warning emitted diff --git a/src/test/ui/check-cfg/well-known-names.stderr b/src/test/ui/check-cfg/well-known-names.stderr index a6b9a77dc8d9a..bdbe4d29d30fe 100644 --- a/src/test/ui/check-cfg/well-known-names.stderr +++ b/src/test/ui/check-cfg/well-known-names.stderr @@ -2,7 +2,9 @@ warning: unexpected `cfg` condition name --> $DIR/well-known-names.rs:6:7 | LL | #[cfg(target_oz = "linux")] - | ^^^^^^^^^^^^^^^^^^^ + | ---------^^^^^^^^^^ + | | + | help: did you mean: `target_os` | = note: `#[warn(unexpected_cfgs)]` on by default @@ -10,13 +12,15 @@ warning: unexpected `cfg` condition name --> $DIR/well-known-names.rs:13:7 | LL | #[cfg(features = "foo")] - | ^^^^^^^^^^^^^^^^ + | --------^^^^^^^^ + | | + | help: did you mean: `feature` warning: unexpected `cfg` condition name --> $DIR/well-known-names.rs:20:7 | LL | #[cfg(uniw)] - | ^^^^ + | ^^^^ help: did you mean: `unix` warning: 3 warnings emitted From 8d3de56da1eba68d012977d4c743d5eaaa1baee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20BRANSTETT?= Date: Sun, 20 Feb 2022 01:26:52 +0100 Subject: [PATCH 07/16] Continue improvements on the --check-cfg implementation - Test the combinations of --check-cfg with partial values() and --cfg - Test that we detect unexpected value when none are expected --- compiler/rustc_attr/src/builtin.rs | 39 +++++------ compiler/rustc_interface/src/interface.rs | 14 ++-- compiler/rustc_lint/src/context.rs | 25 +++---- compiler/rustc_session/src/config.rs | 22 +++---- .../ui/check-cfg/invalid-cfg-value.stderr | 2 +- src/test/ui/check-cfg/mix.rs | 50 ++++++++++++++ src/test/ui/check-cfg/mix.stderr | 66 +++++++++++++++++++ src/test/ui/check-cfg/no-values.rs | 10 +++ src/test/ui/check-cfg/no-values.stderr | 11 ++++ 9 files changed, 184 insertions(+), 55 deletions(-) create mode 100644 src/test/ui/check-cfg/mix.rs create mode 100644 src/test/ui/check-cfg/mix.stderr create mode 100644 src/test/ui/check-cfg/no-values.rs create mode 100644 src/test/ui/check-cfg/no-values.stderr diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 503e172b6873f..50eb6b6e5da52 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -462,7 +462,8 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat true } MetaItemKind::NameValue(..) | MetaItemKind::Word => { - let name = cfg.ident().expect("multi-segment cfg predicate").name; + let ident = cfg.ident().expect("multi-segment cfg predicate"); + let name = ident.name; let value = cfg.value_str(); if let Some(names_valid) = &sess.check_config.names_valid { if !names_valid.contains(&name) { @@ -471,30 +472,24 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat cfg.span, CRATE_NODE_ID, "unexpected `cfg` condition name", - BuiltinLintDiagnostics::UnexpectedCfg( - cfg.ident().unwrap().span, - name, - None, - ), + BuiltinLintDiagnostics::UnexpectedCfg(ident.span, name, None), ); } } - if let Some(val) = value { - if let Some(values_valid) = &sess.check_config.values_valid { - if let Some(values) = values_valid.get(&name) { - if !values.contains(&val) { - sess.buffer_lint_with_diagnostic( - UNEXPECTED_CFGS, - cfg.span, - CRATE_NODE_ID, - "unexpected `cfg` condition value", - BuiltinLintDiagnostics::UnexpectedCfg( - cfg.name_value_literal_span().unwrap(), - name, - Some(val), - ), - ); - } + if let Some(value) = value { + if let Some(values) = &sess.check_config.values_valid.get(&name) { + if !values.contains(&value) { + sess.buffer_lint_with_diagnostic( + UNEXPECTED_CFGS, + cfg.span, + CRATE_NODE_ID, + "unexpected `cfg` condition value", + BuiltinLintDiagnostics::UnexpectedCfg( + cfg.name_value_literal_span().unwrap(), + name, + Some(value), + ), + ); } } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 5e0d59bf1b136..91ced2a2d90e2 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -183,12 +183,10 @@ pub fn parse_check_cfg(specs: Vec) -> CheckCfg { } else if meta_item.has_name(sym::values) { if let Some((name, values)) = args.split_first() { if name.is_word() && name.ident().is_some() { - let values_valid = cfg - .values_valid - .get_or_insert_with(|| FxHashMap::default()); let ident = name.ident().expect("multi-segment cfg key"); - let ident_values = values_valid - .entry(ident.to_string()) + let ident_values = cfg + .values_valid + .entry(ident.name.to_string()) .or_insert_with(|| FxHashSet::default()); for val in values { @@ -225,10 +223,8 @@ pub fn parse_check_cfg(specs: Vec) -> CheckCfg { ); } - if let Some(values_valid) = &cfg.values_valid { - if let Some(names_valid) = &mut cfg.names_valid { - names_valid.extend(values_valid.keys().cloned()); - } + if let Some(names_valid) = &mut cfg.names_valid { + names_valid.extend(cfg.values_valid.keys().cloned()); } cfg }) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 72a3f5d5fc9b8..5f07cf08c2ea3 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -768,17 +768,14 @@ pub trait LintContext: Sized { db.note("see the asm section of Rust By Example for more information"); }, BuiltinLintDiagnostics::UnexpectedCfg(span, name, value) => { - let mut possibilities: Vec = if value.is_some() { - let Some(values_valid) = &sess.parse_sess.check_config.values_valid else { - bug!("it shouldn't be possible to have a diagnostic on a value if values checking is not enable"); - }; - let Some(values) = values_valid.get(&name) else { + let possibilities: Vec = if value.is_some() { + let Some(values) = &sess.parse_sess.check_config.values_valid.get(&name) else { bug!("it shouldn't be possible to have a diagnostic on a value whose name is not in values"); }; values.iter().map(|&s| s).collect() } else { let Some(names_valid) = &sess.parse_sess.check_config.names_valid else { - bug!("it shouldn't be possible to have a diagnostic on a value if values checking is not enable"); + bug!("it shouldn't be possible to have a diagnostic on a name if name checking is not enabled"); }; names_valid.iter().map(|s| *s).collect() }; @@ -786,17 +783,21 @@ pub trait LintContext: Sized { // Show the full list if all possible values for a given name, but don't do it // for names as the possibilities could be very long if value.is_some() { - // Sorting can take some time, so we only do it if required - possibilities.sort(); + if !possibilities.is_empty() { + let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::>(); + possibilities.sort(); - let possibilities = possibilities.iter().map(Symbol::as_str).intersperse(", ").collect::(); - db.note(&format!("possible values for `{name}` are: {possibilities}")); + let possibilities = possibilities.join(", "); + db.note(&format!("expected values for `{name}` are: {possibilities}")); + } else { + db.note(&format!("no expected value for `{name}`")); + } } // Suggest the most probable if we found one if let Some(best_match) = find_best_match_for_name(&possibilities, value.unwrap_or(name), None) { - let ponctuation = if value.is_some() { "\"" } else { "" }; - db.span_suggestion(span, "did you mean", format!("{ponctuation}{best_match}{ponctuation}"), Applicability::MaybeIncorrect); + let punctuation = if value.is_some() { "\"" } else { "" }; + db.span_suggestion(span, "did you mean", format!("{punctuation}{best_match}{punctuation}"), Applicability::MaybeIncorrect); } }, } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e0a3cc78b1772..f9b75690e375f 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1023,10 +1023,10 @@ pub fn to_crate_config(cfg: FxHashSet<(String, Option)>) -> CrateConfig /// The parsed `--check-cfg` options pub struct CheckCfg { - /// The set of all `names()`, if none no names checking is performed + /// The set of all `names()`, if None no name checking is performed pub names_valid: Option>, - /// The set of all `values()`, if none no values chcking is performed - pub values_valid: Option>>, + /// The set of all `values()` + pub values_valid: FxHashMap>, } impl Default for CheckCfg { @@ -1042,9 +1042,11 @@ impl CheckCfg { .names_valid .as_ref() .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()), - values_valid: self.values_valid.as_ref().map(|values_valid| { - values_valid.iter().map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect())).collect() - }), + values_valid: self + .values_valid + .iter() + .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect())) + .collect(), } } } @@ -1098,11 +1100,9 @@ impl CrateCheckConfig { names_valid.insert(k); } if let Some(v) = v { - if let Some(values_valid) = &mut self.values_valid { - values_valid.entry(k).and_modify(|values| { - values.insert(v); - }); - } + self.values_valid.entry(k).and_modify(|values| { + values.insert(v); + }); } } } diff --git a/src/test/ui/check-cfg/invalid-cfg-value.stderr b/src/test/ui/check-cfg/invalid-cfg-value.stderr index 23fd5c8c759cf..bc2c053fed65a 100644 --- a/src/test/ui/check-cfg/invalid-cfg-value.stderr +++ b/src/test/ui/check-cfg/invalid-cfg-value.stderr @@ -5,7 +5,7 @@ LL | #[cfg(feature = "sedre")] | ^^^^^^^^^^^^^^^^^ | = note: `#[warn(unexpected_cfgs)]` on by default - = note: possible values for `feature` are: rand, serde, full + = note: expected values for `feature` are: full, rand, serde warning: 1 warning emitted diff --git a/src/test/ui/check-cfg/mix.rs b/src/test/ui/check-cfg/mix.rs new file mode 100644 index 0000000000000..26c735c4a10bd --- /dev/null +++ b/src/test/ui/check-cfg/mix.rs @@ -0,0 +1,50 @@ +// This test checks the combination of well known names, their activation via names(), the usage of +// partial values() with a --cfg and test that we also correctly lint on the `cfg!` macro and +// `cfg_attr` attribute. +// +// check-pass +// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --cfg feature="bar" -Z unstable-options + +#[cfg(windows)] +fn do_windows_stuff() {} + +#[cfg(widnows)] +//~^ WARNING unexpected `cfg` condition name +fn do_windows_stuff() {} + +#[cfg(feature = "foo")] +fn use_foo() {} + +#[cfg(feature = "bar")] +fn use_bar() {} + +#[cfg(feature = "zebra")] +//~^ WARNING unexpected `cfg` condition value +fn use_zebra() {} + +#[cfg_attr(uu, test)] +//~^ WARNING unexpected `cfg` condition name +fn do_test() {} + +#[cfg_attr(feature = "foo", no_mangle)] +fn do_test_foo() {} + +fn test_cfg_macro() { + cfg!(windows); + cfg!(widnows); + //~^ WARNING unexpected `cfg` condition name + cfg!(feature = "foo"); + cfg!(feature = "bar"); + cfg!(feature = "zebra"); + //~^ WARNING unexpected `cfg` condition value + cfg!(xxx = "foo"); + //~^ WARNING unexpected `cfg` condition name + cfg!(xxx); + //~^ WARNING unexpected `cfg` condition name + cfg!(any(xxx, windows)); + //~^ WARNING unexpected `cfg` condition name + cfg!(any(feature = "bad", windows)); + //~^ WARNING unexpected `cfg` condition value +} + +fn main() {} diff --git a/src/test/ui/check-cfg/mix.stderr b/src/test/ui/check-cfg/mix.stderr new file mode 100644 index 0000000000000..b273be774224d --- /dev/null +++ b/src/test/ui/check-cfg/mix.stderr @@ -0,0 +1,66 @@ +warning: unexpected `cfg` condition name + --> $DIR/mix.rs:11:7 + | +LL | #[cfg(widnows)] + | ^^^^^^^ help: did you mean: `windows` + | + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value + --> $DIR/mix.rs:21:7 + | +LL | #[cfg(feature = "zebra")] + | ^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: bar, foo + +warning: unexpected `cfg` condition name + --> $DIR/mix.rs:25:12 + | +LL | #[cfg_attr(uu, test)] + | ^^ + +warning: unexpected `cfg` condition name + --> $DIR/mix.rs:34:10 + | +LL | cfg!(widnows); + | ^^^^^^^ help: did you mean: `windows` + +warning: unexpected `cfg` condition value + --> $DIR/mix.rs:38:10 + | +LL | cfg!(feature = "zebra"); + | ^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: bar, foo + +warning: unexpected `cfg` condition name + --> $DIR/mix.rs:40:10 + | +LL | cfg!(xxx = "foo"); + | ^^^^^^^^^^^ + +warning: unexpected `cfg` condition name + --> $DIR/mix.rs:42:10 + | +LL | cfg!(xxx); + | ^^^ + +warning: unexpected `cfg` condition name + --> $DIR/mix.rs:44:14 + | +LL | cfg!(any(xxx, windows)); + | ^^^ + +warning: unexpected `cfg` condition value + --> $DIR/mix.rs:46:14 + | +LL | cfg!(any(feature = "bad", windows)); + | ^^^^^^^^^^----- + | | + | help: did you mean: `"bar"` + | + = note: expected values for `feature` are: bar, foo + +warning: 9 warnings emitted + diff --git a/src/test/ui/check-cfg/no-values.rs b/src/test/ui/check-cfg/no-values.rs new file mode 100644 index 0000000000000..2440757e52da9 --- /dev/null +++ b/src/test/ui/check-cfg/no-values.rs @@ -0,0 +1,10 @@ +// Check that we detect unexpected value when none are allowed +// +// check-pass +// compile-flags: --check-cfg=values(feature) -Z unstable-options + +#[cfg(feature = "foo")] +//~^ WARNING unexpected `cfg` condition value +fn do_foo() {} + +fn main() {} diff --git a/src/test/ui/check-cfg/no-values.stderr b/src/test/ui/check-cfg/no-values.stderr new file mode 100644 index 0000000000000..ea1c9107d4c2f --- /dev/null +++ b/src/test/ui/check-cfg/no-values.stderr @@ -0,0 +1,11 @@ +warning: unexpected `cfg` condition value + --> $DIR/no-values.rs:6:7 + | +LL | #[cfg(feature = "foo")] + | ^^^^^^^^^^^^^^^ + | + = note: `#[warn(unexpected_cfgs)]` on by default + = note: no expected value for `feature` + +warning: 1 warning emitted + From a556a2a8e60501203f310407b27cf739618c0000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20BRANSTETT?= Date: Mon, 21 Feb 2022 15:29:04 +0100 Subject: [PATCH 08/16] Add compiler flag `--check-cfg` to the unstable book --- .../src/compiler-flags/check-cfg.md | 221 ++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/check-cfg.md diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md new file mode 100644 index 0000000000000..d7345ad0c33f2 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -0,0 +1,221 @@ +# `check-cfg` + +The tracking issue for this feature is: [#82450](https://github.com/rust-lang/rust/issues/82450). + +------------------------ + +This feature allows you to enable complete or partial checking of configuration. + +`rustc` accepts the `--check-cfg` option, which specifies whether to check conditions and how to +check them. The `--check-cfg` option takes a value, called the _check cfg specification_. The +check cfg specification is parsed using the Rust metadata syntax, just as the `--cfg` option is. + +`--check-cfg` option can take one of two forms: + +1. `--check-cfg names(...)` enables checking condition names. +2. `--check-cfg values(...)` enables checking the values within list-valued conditions. + +These two options are independent. `names` checks only the namespace of condition names +while `values` checks only the namespace of the values of list-valued conditions. + +## The `names(...)` form + +The `names(...)` form enables checking the names. This form uses a named list: + +```bash +rustc --check-cfg 'names(name1, name2, ... nameN)' +``` + +where each `name` is a bare identifier (has no quotes). The order of the names is not significant. + +If `--check-cfg names(...)` is specified at least once, then `rustc` will check all references to +condition names. `rustc` will check every `#[cfg]` attribute, `#[cfg_attr]` attribute, `cfg` clause +inside `#[link]` attribute and `cfg!(...)` call against the provided list of expected condition +names. If a name is not present in this list, then `rustc` will report an `unexpected_cfgs` lint +diagnostic. The default diagnostic level for this lint is `Warn`. + +If `--check-cfg names(...)` is not specified, then `rustc` will not check references to condition +names. + +`--check-cfg names(...)` may be specified more than once. The result is that the list of valid +condition names is merged across all options. It is legal for a condition name to be specified +more than once; redundantly specifying a condition name has no effect. + +To enable checking condition names with an empty set of valid condition names, use the following +form. The parentheses are required. + +```bash +rustc --check-cfg 'names()' +``` + +Note that `--check-cfg 'names()'` is _not_ equivalent to omitting the option entirely. +The first form enables checking condition names, while specifying that there are no valid +condition names (outside of the set of well-known names defined by `rustc`). Omitting the +`--check-cfg 'names(...)'` option does not enable checking condition names. + +Conditions that are enabled are implicitly valid; it is unnecessary (but legal) to specify a +condition name as both enabled and valid. For example, the following invocations are equivalent: + +```bash +# condition names will be checked, and 'has_time_travel' is valid +rustc --cfg 'has_time_travel' --check-cfg 'names()' + +# condition names will be checked, and 'has_time_travel' is valid +rustc --cfg 'has_time_travel' --check-cfg 'names(has_time_travel)' +``` + +In contrast, the following two invocations are _not_ equivalent: + +```bash +# condition names will not be checked (because there is no --check-cfg names(...)) +rustc --cfg 'has_time_travel' + +# condition names will be checked, and 'has_time_travel' is both valid and enabled. +rustc --cfg 'has_time_travel' --check-cfg 'names(has_time_travel)' +``` + +## The `values(...)` form + +The `values(...)` form enables checking the values within list-valued conditions. It has this +form: + +```bash +rustc --check-cfg `values(name, "value1", "value2", ... "valueN")' +``` + +where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal +string. `name` specifies the name of the condition, such as `feature` or `target_os`. + +When the `values(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]` +attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]` +and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the +list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs` +lint diagnostic. The default diagnostic level for this lint is `Warn`. + +The form `values()` is an error, because it does not specify a condition name. + +To enable checking of values, but to provide an empty set of valid values, use this form: + +```bash +rustc --check-cfg `values(name)` +``` + +The `--check-cfg values(...)` option can be repeated, both for the same condition name and for +different names. If it is repeated for the same condition name, then the sets of values for that +condition are merged together. + +## Examples + +Consider this command line: + +```bash +rustc --check-cfg 'names(feature)' \ + --check-cfg 'values(feature,"lion","zebra")' \ + --cfg 'feature="lion"' -Z unstable-options \ + example.rs +``` + +This command line indicates that this crate has two features: `lion` and `zebra`. The `lion` +feature is enabled, while the `zebra` feature is disabled. Consider compiling this code: + +```rust +// This is expected, and tame_lion() will be compiled +#[cfg(feature = "lion")] +fn tame_lion(lion: Lion) {} + +// This is expected, and ride_zebra() will NOT be compiled. +#[cfg(feature = "zebra")] +fn ride_zebra(zebra: Zebra) {} + +// This is UNEXPECTED, and will cause a compiler warning (by default). +#[cfg(feature = "platypus")] +fn poke_platypus() {} + +// This is UNEXPECTED, because 'feechure' is not a known condition name, +// and will cause a compiler warning (by default). +#[cfg(feechure = "lion")] +fn tame_lion() {} +``` + +> Note: The `--check-cfg names(feature)` option is necessary only to enable checking the condition +> name, as in the last example. `feature` is a well-known (always-expected) condition name, and so +> it is not necessary to specify it in a `--check-cfg 'names(...)'` option. That option can be +> shortened to > `--check-cfg names()` in order to enable checking well-known condition names. + +### Example: Checking condition names, but not values + +```bash +# This turns on checking for condition names, but not values, such as 'feature' values. +rustc --check-cfg 'names(is_embedded, has_feathers)' \ + --cfg has_feathers --cfg 'feature = "zapping"' -Z unstable-options +``` + +```rust +#[cfg(is_embedded)] // This is expected as "is_embedded" was provided in names() +fn do_embedded() {} + +#[cfg(has_feathers)] // This is expected as "has_feathers" was provided in names() +fn do_features() {} + +#[cfg(has_mumble_frotz)] // This is UNEXPECTED because names checking is enable and + // "has_mumble_frotz" was not provided in names() +fn do_mumble_frotz() {} + +#[cfg(feature = "lasers")] // This doesn't raise a warning, because values checking for "feature" + // was never used +fn shoot_lasers() {} +``` + +### Example: Checking feature values, but not condition names + +```bash +# This turns on checking for feature values, but not for condition names. +rustc --check-cfg 'values(feature, "zapping", "lasers")' \ + --cfg 'feature="zapping"' -Z unstable-options +``` + +```rust +#[cfg(is_embedded)] // This is doesn't raise a warning, because names checking was not + // enable (ie not names()) +fn do_embedded() {} + +#[cfg(has_feathers)] // Same as above, --check-cfg names(...) was never used so no name + // checking is performed +fn do_features() {} + + +#[cfg(feature = "lasers")] // This is expected, "lasers" is in the values(feature) list +fn shoot_lasers() {} + +#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in the + // --check-cfg values(feature) list +fn write_shakespeare() {} +``` + +### Example: Checking both condition names and feature values + +```bash +# This turns on checking for feature values and for condition names. +rustc --check-cfg 'names(is_embedded, has_feathers)' \ + --check-cfg 'values(feature, "zapping", "lasers")' \ + --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options +``` + +```rust +#[cfg(is_embedded)] // This is expected because "is_embedded" was provided in names() +fn do_embedded() {} + +#[cfg(has_feathers)] // This is expected because "has_feathers" was provided in names() +fn do_features() {} + +#[cfg(has_mumble_frotz)] // This is UNEXPECTED, because has_mumble_frotz is not in the + // --check-cfg names(...) list +fn do_mumble_frotz() {} + +#[cfg(feature = "lasers")] // This is expected, "lasers" is in the values(feature) list +fn shoot_lasers() {} + +#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in + // the values(feature) list +fn write_shakespear() {} +``` From c73a2f8a652134bd7bf00ca61ca65bd7adb8aec7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 23 Feb 2022 08:11:50 -0800 Subject: [PATCH 09/16] properly handle fat pointers to uninhabitable types --- .../src/debuginfo/metadata.rs | 5 ++- .../rustc_codegen_llvm/src/debuginfo/utils.rs | 33 +++++++++---------- ...uginfo-emit-llvm-ir-and-split-debuginfo.rs | 0 ...fo_with_uninhabitable_field_and_unsized.rs | 29 ++++++++++++++++ 4 files changed, 49 insertions(+), 18 deletions(-) rename src/test/ui/{ => debuginfo}/debuginfo-emit-llvm-ir-and-split-debuginfo.rs (100%) create mode 100644 src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index ef87b7b1a7e07..517c539b45ac8 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -449,7 +449,10 @@ fn pointer_or_reference_metadata<'ll, 'tcx>( // This is a thin pointer. Create a regular pointer type and give it the correct name. debug_assert_eq!( (thin_pointer_size, thin_pointer_align), - cx.size_and_align_of(ptr_type) + cx.size_and_align_of(ptr_type), + "ptr_type={}, pointee_type={}", + ptr_type, + pointee_type, ); unsafe { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index acd032a7dc6d0..fa75463067f47 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -4,9 +4,9 @@ use super::namespace::item_namespace; use super::CrateDebugContext; use rustc_hir::def_id::DefId; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, DefIdTree, Ty}; -use rustc_target::abi::Variants; +use tracing::trace; use crate::common::CodegenCx; use crate::llvm; @@ -63,30 +63,26 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, pointee_ty: Ty<'tcx>, ) -> Option { - let layout = cx.layout_of(pointee_ty); + let pointee_tail_ty = cx.tcx.struct_tail_erasing_lifetimes(pointee_ty, cx.param_env()); + let layout = cx.layout_of(pointee_tail_ty); + trace!( + "fat_pointer_kind: {:?} has layout {:?} (is_unsized? {})", + pointee_tail_ty, + layout, + layout.is_unsized() + ); if !layout.is_unsized() { return None; } - match *pointee_ty.kind() { + match *pointee_tail_ty.kind() { ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice), ty::Dynamic(..) => Some(FatPtrKind::Dyn), - ty::Adt(..) | ty::Tuple(..) if matches!(layout.variants, Variants::Single { .. }) => { - let last_field_index = layout.fields.count() - 1; - debug_assert!( - (0..last_field_index) - .all(|field_index| { !layout.field(cx, field_index).is_unsized() }) - ); - - let unsized_field = layout.field(cx, last_field_index); - debug_assert!(unsized_field.is_unsized()); - fat_pointer_kind(cx, unsized_field.ty) - } ty::Foreign(_) => { // Assert that pointers to foreign types really are thin: debug_assert_eq!( - cx.size_of(cx.tcx.mk_imm_ptr(pointee_ty)), + cx.size_of(cx.tcx.mk_imm_ptr(pointee_tail_ty)), cx.size_of(cx.tcx.mk_imm_ptr(cx.tcx.types.u8)) ); None @@ -94,7 +90,10 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>( _ => { // For all other pointee types we should already have returned None // at the beginning of the function. - panic!("fat_pointer_kind() - Encountered unexpected `pointee_ty`: {:?}", pointee_ty) + panic!( + "fat_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {:?}", + pointee_tail_ty + ) } } } diff --git a/src/test/ui/debuginfo-emit-llvm-ir-and-split-debuginfo.rs b/src/test/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs similarity index 100% rename from src/test/ui/debuginfo-emit-llvm-ir-and-split-debuginfo.rs rename to src/test/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs diff --git a/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs b/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs new file mode 100644 index 0000000000000..833a4726acb0f --- /dev/null +++ b/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs @@ -0,0 +1,29 @@ +// check-pass +// compile-flags: -Cdebuginfo=2 +// fixes issue #94149 + +#![allow(dead_code)] + +pub fn main() { + let _ = Foo::::new(); +} + +pub struct Foo { + base: FooBase, + value: T, +} + +impl Foo { + pub fn new() -> Box> { + todo!() + } +} + +pub trait FooTrait {} + +pub struct FooBase { + cls: Bar, +} + +// Bar *must* be a fieldless enum +pub enum Bar {} From f047af24b3b90f19b89fac80822acd69613b89ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 23 Feb 2022 00:00:00 +0000 Subject: [PATCH 10/16] Normalize main return type during mono item collection & codegen --- compiler/rustc_codegen_cranelift/src/main_shim.rs | 5 ++++- compiler/rustc_codegen_ssa/src/base.rs | 5 ++++- compiler/rustc_monomorphize/src/collector.rs | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 9ce727279c27c..2f71a70a44946 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -51,7 +51,10 @@ pub(crate) fn maybe_create_entry_wrapper( // late-bound regions, since late-bound // regions must appear in the argument // listing. - let main_ret_ty = tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap()); + let main_ret_ty = tcx.normalize_erasing_regions( + ty::ParamEnv::reveal_all(), + main_ret_ty.no_bound_vars().unwrap(), + ); let cmain_sig = Signature { params: vec![ diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index ed6c156547e29..11f32d92e44cd 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -407,7 +407,10 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // late-bound regions, since late-bound // regions must appear in the argument // listing. - let main_ret_ty = cx.tcx().erase_regions(main_ret_ty.no_bound_vars().unwrap()); + let main_ret_ty = cx.tcx().normalize_erasing_regions( + ty::ParamEnv::reveal_all(), + main_ret_ty.no_bound_vars().unwrap(), + ); let Some(llfn) = cx.declare_c_main(llfty) else { // FIXME: We should be smart and show a better diagnostic here. diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index a517e4879aafa..2f88c45a2a389 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1270,7 +1270,10 @@ impl<'v> RootCollector<'_, 'v> { // late-bound regions, since late-bound // regions must appear in the argument // listing. - let main_ret_ty = self.tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap()); + let main_ret_ty = self.tcx.normalize_erasing_regions( + ty::ParamEnv::reveal_all(), + main_ret_ty.no_bound_vars().unwrap(), + ); let start_instance = Instance::resolve( self.tcx, From 37d9ea745b358a5b9f48560600841fc6619e545d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Feb 2022 16:10:36 +1100 Subject: [PATCH 11/16] Improve `scan_escape`. `scan_escape` currently has a fast path (for when the first char isn't '\\') and a slow path. This commit changes `scan_escape` so it only handles the slow path, i.e. the actual escaping code. The fast path is inlined into the two call sites. This change makes the code faster, because there is no function call overhead on the fast path. (`scan_escape` is a big function and doesn't get inlined.) This change also improves readability, because it removes a bunch of mode checks on the the fast paths. --- compiler/rustc_lexer/src/unescape.rs | 45 ++++++++++++++-------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index d789237e692d2..97f9588ae1ef5 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -159,26 +159,8 @@ impl Mode { } } -fn scan_escape(first_char: char, chars: &mut Chars<'_>, mode: Mode) -> Result { - if first_char != '\\' { - // Previous character was not a slash, and we don't expect it to be - // an escape-only character. - return match first_char { - '\t' | '\n' => Err(EscapeError::EscapeOnlyChar), - '\r' => Err(EscapeError::BareCarriageReturn), - '\'' if mode.in_single_quotes() => Err(EscapeError::EscapeOnlyChar), - '"' if mode.in_double_quotes() => Err(EscapeError::EscapeOnlyChar), - _ => { - if mode.is_bytes() && !first_char.is_ascii() { - // Byte literal can't be a non-ascii character. - return Err(EscapeError::NonAsciiCharInByte); - } - Ok(first_char) - } - }; - } - - // Previous character is '\\', try to unescape it. +fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result { + // Previous character was '\\', unescape what follows. let second_char = chars.next().ok_or(EscapeError::LoneSlash)?; @@ -270,9 +252,24 @@ fn scan_escape(first_char: char, chars: &mut Chars<'_>, mode: Mode) -> Result Result { + if mode.is_bytes() && !first_char.is_ascii() { + // Byte literal can't be a non-ascii character. + Err(EscapeError::NonAsciiCharInByte) + } else { + Ok(first_char) + } +} + fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result { let first_char = chars.next().ok_or(EscapeError::ZeroChars)?; - let res = scan_escape(first_char, chars, mode)?; + let res = match first_char { + '\\' => scan_escape(chars, mode), + '\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar), + '\r' => Err(EscapeError::BareCarriageReturn), + _ => ascii_check(first_char, mode), + }?; if chars.next().is_some() { return Err(EscapeError::MoreThanOneChar); } @@ -303,12 +300,14 @@ where skip_ascii_whitespace(&mut chars, start, callback); continue; } - _ => scan_escape(first_char, &mut chars, mode), + _ => scan_escape(&mut chars, mode), } } '\n' => Ok('\n'), '\t' => Ok('\t'), - _ => scan_escape(first_char, &mut chars, mode), + '"' => Err(EscapeError::EscapeOnlyChar), + '\r' => Err(EscapeError::BareCarriageReturn), + _ => ascii_check(first_char, mode), }; let end = initial_len - chars.as_str().len(); callback(start..end, unescaped_char); From 44308dc3489e39958b2ce6dd297b895514b6f425 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Feb 2022 16:49:37 +1100 Subject: [PATCH 12/16] Inline a hot closure in `from_lit_token`. The change looks big because `rustfmt` rearranges things, but the only real change is the inlining annotation. --- compiler/rustc_ast/src/lib.rs | 1 + compiler/rustc_ast/src/util/literal.rs | 39 +++++++++++++++----------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 84fe9ad26720e..21183121e15a0 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -16,6 +16,7 @@ #![feature(min_specialization)] #![recursion_limit = "256"] #![feature(slice_internals)] +#![feature(stmt_expr_attributes)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 1cc5ddfd8ee29..224afbd553fb8 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -56,25 +56,30 @@ impl LitKind { // new symbol because the string in the LitKind is different to the // string in the token. let s = symbol.as_str(); - let symbol = - if s.contains(&['\\', '\r']) { - let mut buf = String::with_capacity(s.len()); - let mut error = Ok(()); - unescape_literal(&s, Mode::Str, &mut |_, unescaped_char| { - match unescaped_char { - Ok(c) => buf.push(c), - Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } + let symbol = if s.contains(&['\\', '\r']) { + let mut buf = String::with_capacity(s.len()); + let mut error = Ok(()); + // Force-inlining here is aggressive but the closure is + // called on every char in the string, so it can be + // hot in programs with many long strings. + unescape_literal( + &s, + Mode::Str, + &mut #[inline(always)] + |_, unescaped_char| match unescaped_char { + Ok(c) => buf.push(c), + Err(err) => { + if err.is_fatal() { + error = Err(LitError::LexerError); } } - }); - error?; - Symbol::intern(&buf) - } else { - symbol - }; + }, + ); + error?; + Symbol::intern(&buf) + } else { + symbol + }; LitKind::Str(symbol, ast::StrStyle::Cooked) } token::StrRaw(n) => { From 70018c19cb34679e6de8b18f84c264abe280f28a Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 24 Feb 2022 08:36:29 +0100 Subject: [PATCH 13/16] update auto trait lint --- compiler/rustc_typeck/src/coherence/orphan.rs | 1 + .../ui/auto-traits/suspicious-impls-lint.rs | 10 +++++++ .../auto-traits/suspicious-impls-lint.stderr | 29 ++++++++++++++----- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index 54fffeb3cdaa6..811136a7eb4ee 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -439,6 +439,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: } match t.kind() { + ty::Adt(def, substs) if def.is_phantom_data() => substs.super_visit_with(self), ty::Adt(def, substs) => { // @lcnr: This is the only place where cycles can happen. We avoid this // by only visiting each `DefId` once. diff --git a/src/test/ui/auto-traits/suspicious-impls-lint.rs b/src/test/ui/auto-traits/suspicious-impls-lint.rs index 1026a35a455ac..1574a7e02e97f 100644 --- a/src/test/ui/auto-traits/suspicious-impls-lint.rs +++ b/src/test/ui/auto-traits/suspicious-impls-lint.rs @@ -1,5 +1,7 @@ #![deny(suspicious_auto_trait_impls)] +use std::marker::PhantomData; + struct MayImplementSendOk(T); unsafe impl Send for MayImplementSendOk {} // ok @@ -31,4 +33,12 @@ unsafe impl Send for TwoParamsSame {} //~^ ERROR //~| WARNING this will change its meaning +pub struct WithPhantomDataNonSend(PhantomData<*const T>, U); +unsafe impl Send for WithPhantomDataNonSend {} // ok + +pub struct WithPhantomDataSend(PhantomData, U); +unsafe impl Send for WithPhantomDataSend<*const T, i8> {} +//~^ ERROR +//~| WARNING this will change its meaning + fn main() {} diff --git a/src/test/ui/auto-traits/suspicious-impls-lint.stderr b/src/test/ui/auto-traits/suspicious-impls-lint.stderr index f91aa862271d3..084bfef49c029 100644 --- a/src/test/ui/auto-traits/suspicious-impls-lint.stderr +++ b/src/test/ui/auto-traits/suspicious-impls-lint.stderr @@ -1,5 +1,5 @@ error: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/suspicious-impls-lint.rs:7:1 + --> $DIR/suspicious-impls-lint.rs:9:1 | LL | unsafe impl Send for MayImplementSendErr<&T> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,14 +12,14 @@ LL | #![deny(suspicious_auto_trait_impls)] = warning: this will change its meaning in a future release! = note: for more information, see issue #93367 note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-impls-lint.rs:6:1 + --> $DIR/suspicious-impls-lint.rs:8:1 | LL | struct MayImplementSendErr(T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `&T` is not a generic parameter error: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/suspicious-impls-lint.rs:19:1 + --> $DIR/suspicious-impls-lint.rs:21:1 | LL | unsafe impl Send for ContainsVec {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,14 +27,14 @@ LL | unsafe impl Send for ContainsVec {} = warning: this will change its meaning in a future release! = note: for more information, see issue #93367 note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-impls-lint.rs:18:1 + --> $DIR/suspicious-impls-lint.rs:20:1 | LL | struct ContainsVec(Vec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `i32` is not a generic parameter error: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/suspicious-impls-lint.rs:30:1 + --> $DIR/suspicious-impls-lint.rs:32:1 | LL | unsafe impl Send for TwoParamsSame {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,11 +42,26 @@ LL | unsafe impl Send for TwoParamsSame {} = warning: this will change its meaning in a future release! = note: for more information, see issue #93367 note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-impls-lint.rs:29:1 + --> $DIR/suspicious-impls-lint.rs:31:1 | LL | struct TwoParamsSame(T, U); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `T` is mentioned multiple times -error: aborting due to 3 previous errors +error: cross-crate traits with a default impl, like `Send`, should not be specialized + --> $DIR/suspicious-impls-lint.rs:40:1 + | +LL | unsafe impl Send for WithPhantomDataSend<*const T, i8> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #93367 +note: try using the same sequence of generic parameters as the struct definition + --> $DIR/suspicious-impls-lint.rs:39:1 + | +LL | pub struct WithPhantomDataSend(PhantomData, U); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `*const T` is not a generic parameter + +error: aborting due to 4 previous errors From 34319ff4e1d4b50a2406c03df0befe15362b4227 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 24 Feb 2022 11:16:45 -0500 Subject: [PATCH 14/16] Avoid emitting full macro body into JSON --- compiler/rustc_errors/src/json.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index ff3478073d92b..dc28d1bb45234 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -454,8 +454,14 @@ impl DiagnosticSpan { let end = je.sm.lookup_char_pos(span.hi()); let backtrace_step = backtrace.next().map(|bt| { let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je); - let def_site_span = - Self::from_span_full(bt.def_site, false, None, None, [].into_iter(), je); + let def_site_span = Self::from_span_full( + je.sm.guess_head_span(bt.def_site), + false, + None, + None, + [].into_iter(), + je, + ); Box::new(DiagnosticSpanMacroExpansion { span: call_site, macro_decl_name: bt.kind.descr(), From 8ba74369c210a0cdb1b1440c47f19f2145e1640f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 6 Feb 2022 13:03:28 -0800 Subject: [PATCH 15/16] better ObligationCause for normalization errors in can_type_implement_copy --- compiler/rustc_lint/src/builtin.rs | 11 +++++-- .../rustc_trait_selection/src/traits/misc.rs | 4 +-- .../rustc_typeck/src/coherence/builtin.rs | 3 +- src/test/ui/issues/issue-50480.rs | 4 +-- src/test/ui/issues/issue-50480.stderr | 30 ++++++++++--------- .../ui/traits/copy-impl-cannot-normalize.rs | 25 ++++++++++++++++ .../traits/copy-impl-cannot-normalize.stderr | 14 +++++++++ .../src/needless_pass_by_value.rs | 2 +- 8 files changed, 71 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/traits/copy-impl-cannot-normalize.rs create mode 100644 src/test/ui/traits/copy-impl-cannot-normalize.stderr diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 30b5f9b34d099..0a218c2d25584 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -51,7 +51,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, InnerSpan, MultiSpan, Span}; use rustc_target::abi::VariantIdx; -use rustc_trait_selection::traits::misc::can_type_implement_copy; +use rustc_trait_selection::traits::{self, misc::can_type_implement_copy}; use crate::nonstandard_style::{method_context, MethodLateContext}; @@ -764,7 +764,14 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) { return; } - if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() { + if can_type_implement_copy( + cx.tcx, + param_env, + ty, + traits::ObligationCause::misc(item.span, item.hir_id()), + ) + .is_ok() + { cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| { lint.build( "type could implement `Copy`; consider adding `impl \ diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index b23dce8a58130..dc72945af24e3 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -20,6 +20,7 @@ pub fn can_type_implement_copy<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, self_type: Ty<'tcx>, + cause: ObligationCause<'tcx>, ) -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt().enter(|infcx| { @@ -49,9 +50,8 @@ pub fn can_type_implement_copy<'tcx>( continue; } let span = tcx.def_span(field.did); - let cause = ObligationCause::dummy_with_span(span); let ctx = traits::FulfillmentContext::new(); - match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) { + match traits::fully_normalize(&infcx, ctx, cause.clone(), param_env, ty) { Ok(ty) => { if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { infringing.push(field); diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index 401ba188728c1..a43f7f871167e 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -74,7 +74,8 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type); - match can_type_implement_copy(tcx, param_env, self_type) { + let cause = traits::ObligationCause::misc(span, impl_hir_id); + match can_type_implement_copy(tcx, param_env, self_type, cause) { Ok(()) => {} Err(CopyImplementationError::InfrigingFields(fields)) => { let item = tcx.hir().expect_item(impl_did); diff --git a/src/test/ui/issues/issue-50480.rs b/src/test/ui/issues/issue-50480.rs index 10597caf5b2dc..ca81db023ec3b 100644 --- a/src/test/ui/issues/issue-50480.rs +++ b/src/test/ui/issues/issue-50480.rs @@ -1,17 +1,17 @@ #[derive(Clone, Copy)] //~^ ERROR the trait `Copy` may not be implemented for this type +//~| ERROR `i32` is not an iterator struct Foo(N, NotDefined, ::Item, Vec, String); //~^ ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `N` in this scope //~| ERROR cannot find type `N` in this scope -//~| ERROR `i32` is not an iterator #[derive(Clone, Copy)] //~^ ERROR the trait `Copy` may not be implemented for this type +//~| ERROR `i32` is not an iterator struct Bar(T, N, NotDefined, ::Item, Vec, String); //~^ ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `N` in this scope -//~| ERROR `i32` is not an iterator fn main() {} diff --git a/src/test/ui/issues/issue-50480.stderr b/src/test/ui/issues/issue-50480.stderr index 0bb1f9ae03500..48ec4aa434cd7 100644 --- a/src/test/ui/issues/issue-50480.stderr +++ b/src/test/ui/issues/issue-50480.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `N` in this scope - --> $DIR/issue-50480.rs:3:12 + --> $DIR/issue-50480.rs:4:12 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | -^ not found in this scope @@ -7,13 +7,13 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); | help: you might be missing a type parameter: `` error[E0412]: cannot find type `NotDefined` in this scope - --> $DIR/issue-50480.rs:3:15 + --> $DIR/issue-50480.rs:4:15 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | ^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `N` in this scope - --> $DIR/issue-50480.rs:3:12 + --> $DIR/issue-50480.rs:4:12 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | -^ not found in this scope @@ -21,7 +21,7 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); | help: you might be missing a type parameter: `` error[E0412]: cannot find type `NotDefined` in this scope - --> $DIR/issue-50480.rs:3:15 + --> $DIR/issue-50480.rs:4:15 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | - ^^^^^^^^^^ not found in this scope @@ -29,7 +29,7 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); | help: you might be missing a type parameter: `` error[E0412]: cannot find type `N` in this scope - --> $DIR/issue-50480.rs:12:18 + --> $DIR/issue-50480.rs:13:18 | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | - ^ @@ -46,26 +46,27 @@ LL | struct Bar(T, N, NotDefined, ::Item, Vec, Strin | +++ error[E0412]: cannot find type `NotDefined` in this scope - --> $DIR/issue-50480.rs:12:21 + --> $DIR/issue-50480.rs:13:21 | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | ^^^^^^^^^^ not found in this scope error[E0277]: `i32` is not an iterator - --> $DIR/issue-50480.rs:3:27 + --> $DIR/issue-50480.rs:1:17 | -LL | struct Foo(N, NotDefined, ::Item, Vec, String); - | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator +LL | #[derive(Clone, Copy)] + | ^^^^ `i32` is not an iterator | = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` + = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/issue-50480.rs:1:17 | LL | #[derive(Clone, Copy)] | ^^^^ -LL | +... LL | struct Foo(N, NotDefined, ::Item, Vec, String); | -------- ------ this field does not implement `Copy` | | @@ -74,20 +75,21 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `i32` is not an iterator - --> $DIR/issue-50480.rs:12:33 + --> $DIR/issue-50480.rs:10:17 | -LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); - | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator +LL | #[derive(Clone, Copy)] + | ^^^^ `i32` is not an iterator | = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` + = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/issue-50480.rs:10:17 | LL | #[derive(Clone, Copy)] | ^^^^ -LL | +... LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | -------- ------ this field does not implement `Copy` | | diff --git a/src/test/ui/traits/copy-impl-cannot-normalize.rs b/src/test/ui/traits/copy-impl-cannot-normalize.rs new file mode 100644 index 0000000000000..a78ff046e97f9 --- /dev/null +++ b/src/test/ui/traits/copy-impl-cannot-normalize.rs @@ -0,0 +1,25 @@ +trait TraitFoo { + type Bar; +} + +struct Foo +where + T: TraitFoo, +{ + inner: T::Bar, +} + +impl Clone for Foo +where + T: TraitFoo, + T::Bar: Clone, +{ + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } +} + +impl Copy for Foo {} +//~^ ERROR the trait bound `T: TraitFoo` is not satisfied + +fn main() {} diff --git a/src/test/ui/traits/copy-impl-cannot-normalize.stderr b/src/test/ui/traits/copy-impl-cannot-normalize.stderr new file mode 100644 index 0000000000000..cc540ea905a10 --- /dev/null +++ b/src/test/ui/traits/copy-impl-cannot-normalize.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `T: TraitFoo` is not satisfied + --> $DIR/copy-impl-cannot-normalize.rs:22:1 + | +LL | impl Copy for Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitFoo` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | impl Copy for Foo {} + | ++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index ebd4fb0bf51cc..d27e1383d012b 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -199,7 +199,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let sugg = |diag: &mut DiagnosticBuilder<'_>| { if let ty::Adt(def, ..) = ty.kind() { if let Some(span) = cx.tcx.hir().span_if_local(def.did) { - if can_type_implement_copy(cx.tcx, cx.param_env, ty).is_ok() { + if can_type_implement_copy(cx.tcx, cx.param_env, ty, traits::ObligationCause::dummy_with_span(span)).is_ok() { diag.span_help(span, "consider marking this type as `Copy`"); } } From ee98dc8b3bdff99591630ca225f4769201100603 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 6 Feb 2022 15:57:29 -0800 Subject: [PATCH 16/16] restore spans for issue-50480 --- .../rustc_trait_selection/src/traits/misc.rs | 15 +++++++++- src/test/ui/issues/issue-50480.rs | 4 +-- src/test/ui/issues/issue-50480.stderr | 30 +++++++++---------- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index dc72945af24e3..c293708dcc929 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -50,8 +50,21 @@ pub fn can_type_implement_copy<'tcx>( continue; } let span = tcx.def_span(field.did); + // FIXME(compiler-errors): This gives us better spans for bad + // projection types like in issue-50480. + // If the ADT has substs, point to the cause we are given. + // If it does not, then this field probably doesn't normalize + // to begin with, and point to the bad field's span instead. + let cause = if field + .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did)) + .has_param_types_or_consts() + { + cause.clone() + } else { + ObligationCause::dummy_with_span(span) + }; let ctx = traits::FulfillmentContext::new(); - match traits::fully_normalize(&infcx, ctx, cause.clone(), param_env, ty) { + match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) { Ok(ty) => { if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { infringing.push(field); diff --git a/src/test/ui/issues/issue-50480.rs b/src/test/ui/issues/issue-50480.rs index ca81db023ec3b..10597caf5b2dc 100644 --- a/src/test/ui/issues/issue-50480.rs +++ b/src/test/ui/issues/issue-50480.rs @@ -1,17 +1,17 @@ #[derive(Clone, Copy)] //~^ ERROR the trait `Copy` may not be implemented for this type -//~| ERROR `i32` is not an iterator struct Foo(N, NotDefined, ::Item, Vec, String); //~^ ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `N` in this scope //~| ERROR cannot find type `N` in this scope +//~| ERROR `i32` is not an iterator #[derive(Clone, Copy)] //~^ ERROR the trait `Copy` may not be implemented for this type -//~| ERROR `i32` is not an iterator struct Bar(T, N, NotDefined, ::Item, Vec, String); //~^ ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `N` in this scope +//~| ERROR `i32` is not an iterator fn main() {} diff --git a/src/test/ui/issues/issue-50480.stderr b/src/test/ui/issues/issue-50480.stderr index 48ec4aa434cd7..0bb1f9ae03500 100644 --- a/src/test/ui/issues/issue-50480.stderr +++ b/src/test/ui/issues/issue-50480.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `N` in this scope - --> $DIR/issue-50480.rs:4:12 + --> $DIR/issue-50480.rs:3:12 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | -^ not found in this scope @@ -7,13 +7,13 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); | help: you might be missing a type parameter: `` error[E0412]: cannot find type `NotDefined` in this scope - --> $DIR/issue-50480.rs:4:15 + --> $DIR/issue-50480.rs:3:15 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | ^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `N` in this scope - --> $DIR/issue-50480.rs:4:12 + --> $DIR/issue-50480.rs:3:12 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | -^ not found in this scope @@ -21,7 +21,7 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); | help: you might be missing a type parameter: `` error[E0412]: cannot find type `NotDefined` in this scope - --> $DIR/issue-50480.rs:4:15 + --> $DIR/issue-50480.rs:3:15 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | - ^^^^^^^^^^ not found in this scope @@ -29,7 +29,7 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); | help: you might be missing a type parameter: `` error[E0412]: cannot find type `N` in this scope - --> $DIR/issue-50480.rs:13:18 + --> $DIR/issue-50480.rs:12:18 | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | - ^ @@ -46,27 +46,26 @@ LL | struct Bar(T, N, NotDefined, ::Item, Vec, Strin | +++ error[E0412]: cannot find type `NotDefined` in this scope - --> $DIR/issue-50480.rs:13:21 + --> $DIR/issue-50480.rs:12:21 | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | ^^^^^^^^^^ not found in this scope error[E0277]: `i32` is not an iterator - --> $DIR/issue-50480.rs:1:17 + --> $DIR/issue-50480.rs:3:27 | -LL | #[derive(Clone, Copy)] - | ^^^^ `i32` is not an iterator +LL | struct Foo(N, NotDefined, ::Item, Vec, String); + | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator | = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/issue-50480.rs:1:17 | LL | #[derive(Clone, Copy)] | ^^^^ -... +LL | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | -------- ------ this field does not implement `Copy` | | @@ -75,21 +74,20 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `i32` is not an iterator - --> $DIR/issue-50480.rs:10:17 + --> $DIR/issue-50480.rs:12:33 | -LL | #[derive(Clone, Copy)] - | ^^^^ `i32` is not an iterator +LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); + | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator | = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/issue-50480.rs:10:17 | LL | #[derive(Clone, Copy)] | ^^^^ -... +LL | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | -------- ------ this field does not implement `Copy` | |