diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index d59b148154c93..ee46bdcf7d8bb 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -762,7 +762,7 @@ impl<'a> AstValidator<'a> { match fn_ctxt { FnCtxt::Foreign => return, FnCtxt::Free | FnCtxt::Assoc(_) => { - if !self.sess.target.arch.supports_c_variadic_definitions() { + if !self.sess.target.supports_c_variadic_definitions() { self.dcx().emit_err(errors::CVariadicNotSupported { variadic_span: variadic_param.span, target: &*self.sess.target.llvm_target, diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index fbe9cb813fc53..19735a29dfb2b 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -1186,9 +1186,10 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( // Clang uses the LLVM implementation for these architectures. bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx)) } - Arch::Other(_) => { - // For custom targets, use the LLVM va_arg instruction as a fallback. - bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx)) + Arch::Other(ref arch) => { + // Just to be safe we error out explicitly here, instead of crossing our fingers that + // the default LLVM implementation has the correct behavior for this target. + bug!("c-variadic functions are not currently implemented for custom target {arch}") } } } diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 0cac91c234080..6c65673acd0d8 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -387,9 +387,7 @@ fn emit_mismatch_diagnostic<'tcx>( build_mismatch_suggestion(info.lifetime.ident.as_str(), &suggest_change_to_explicit_bound) }); - let is_bound_static = bound_lifetime.is_some_and(|info| info.lifetime.is_static()); - - tracing::debug!(?bound_lifetime, ?explicit_bound_suggestion, ?is_bound_static); + tracing::debug!(?bound_lifetime, ?explicit_bound_suggestion); let should_suggest_mixed = // Do we have a mixed case? @@ -397,16 +395,16 @@ fn emit_mismatch_diagnostic<'tcx>( // Is there anything to change? (!suggest_change_to_mixed_implicit.is_empty() || !suggest_change_to_mixed_explicit_anonymous.is_empty()) && - // If we have `'static`, we don't want to remove it. - !is_bound_static; + // If we have a named lifetime, prefer consistent naming. + bound_lifetime.is_none(); let mixed_suggestion = should_suggest_mixed.then(|| { let implicit_suggestions = make_implicit_suggestions(&suggest_change_to_mixed_implicit); - let explicit_anonymous_suggestions = suggest_change_to_mixed_explicit_anonymous - .iter() - .map(|info| info.suggestion("'_")) - .collect(); + let explicit_anonymous_suggestions = build_mismatch_suggestions_for_lifetime( + "'_", + &suggest_change_to_mixed_explicit_anonymous, + ); lints::MismatchedLifetimeSyntaxesSuggestion::Mixed { implicit_suggestions, @@ -426,8 +424,8 @@ fn emit_mismatch_diagnostic<'tcx>( !suggest_change_to_implicit.is_empty() && // We never want to hide the lifetime in a path (or similar). allow_suggesting_implicit && - // If we have `'static`, we don't want to remove it. - !is_bound_static; + // If we have a named lifetime, prefer consistent naming. + bound_lifetime.is_none(); let implicit_suggestion = should_suggest_implicit.then(|| { let suggestions = make_implicit_suggestions(&suggest_change_to_implicit); @@ -448,8 +446,10 @@ fn emit_mismatch_diagnostic<'tcx>( let should_suggest_explicit_anonymous = // Is there anything to change? !suggest_change_to_explicit_anonymous.is_empty() && - // If we have `'static`, we don't want to remove it. - !is_bound_static; + // If we already have a mixed suggestion, avoid overlapping alternatives. + mixed_suggestion.is_none() && + // If we have a named lifetime, prefer consistent naming. + bound_lifetime.is_none(); let explicit_anonymous_suggestion = should_suggest_explicit_anonymous .then(|| build_mismatch_suggestion("'_", &suggest_change_to_explicit_anonymous)); @@ -483,7 +483,7 @@ fn build_mismatch_suggestion( ) -> lints::MismatchedLifetimeSyntaxesSuggestion { let lifetime_name = lifetime_name.to_owned(); - let suggestions = infos.iter().map(|info| info.suggestion(&lifetime_name)).collect(); + let suggestions = build_mismatch_suggestions_for_lifetime(&lifetime_name, infos); lints::MismatchedLifetimeSyntaxesSuggestion::Explicit { lifetime_name, @@ -492,6 +492,57 @@ fn build_mismatch_suggestion( } } +fn build_mismatch_suggestions_for_lifetime( + lifetime_name: &str, + infos: &[&Info<'_>], +) -> Vec<(Span, String)> { + use hir::{AngleBrackets, LifetimeSource, LifetimeSyntax}; + + #[derive(Clone, Copy, PartialEq, Eq, Hash)] + enum PathSuggestionKind { + Missing, + Empty, + Full, + } + + let mut suggestions = Vec::new(); + let mut path_counts: FxIndexMap<(hir::HirId, PathSuggestionKind), (Span, usize)> = + FxIndexMap::default(); + + for info in infos { + let lifetime = info.lifetime; + if matches!(lifetime.syntax, LifetimeSyntax::Implicit) { + if let LifetimeSource::Path { angle_brackets } = lifetime.source { + let (span, kind) = match angle_brackets { + AngleBrackets::Missing => { + (lifetime.ident.span.shrink_to_hi(), PathSuggestionKind::Missing) + } + AngleBrackets::Empty => (lifetime.ident.span, PathSuggestionKind::Empty), + AngleBrackets::Full => (lifetime.ident.span, PathSuggestionKind::Full), + }; + let entry = path_counts.entry((info.ty.hir_id, kind)).or_insert((span, 0)); + entry.1 += 1; + continue; + } + } + suggestions.push(info.suggestion(lifetime_name)); + } + + for ((_ty_hir_id, kind), (span, count)) in path_counts { + let repeated = std::iter::repeat(lifetime_name).take(count).collect::>().join(", "); + + let suggestion = match kind { + PathSuggestionKind::Missing => format!("<{repeated}>"), + PathSuggestionKind::Empty => repeated, + PathSuggestionKind::Full => format!("{repeated}, "), + }; + + suggestions.push((span, suggestion)); + } + + suggestions +} + #[derive(Debug)] struct Info<'tcx> { lifetime: &'tcx hir::Lifetime, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index f111f8134499e..f89d9e51af917 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2,6 +2,7 @@ use std::num::NonZero; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; use rustc_errors::{ @@ -3231,8 +3232,23 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MismatchedLifetimeSyntaxes diag.span_label(s, msg!("the lifetime is named here")); } + let mut hidden_output_counts: FxIndexMap = FxIndexMap::default(); for s in self.outputs.hidden { - diag.span_label(s, msg!("the same lifetime is hidden here")); + *hidden_output_counts.entry(s).or_insert(0) += 1; + } + for (span, count) in hidden_output_counts { + let label = msg!( + "the same {$count -> + [one] lifetime + *[other] lifetimes + } {$count -> + [one] is + *[other] are + } hidden here" + ) + .arg("count", count) + .format(); + diag.span_label(span, label); } for s in self.outputs.elided { diag.span_label(s, msg!("the same lifetime is elided here")); diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 81c3c7baa07af..7a31682b4ad98 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -109,8 +109,6 @@ pub fn restore_val(erased_value: Erased) -> T { unsafe { transmute_unchecked::, T>(data) } } -// FIXME(#151565): Using `T: ?Sized` here should let us remove the separate -// impls for fat reference types. impl Erasable for &'_ T { type Storage = [u8; size_of::<&'_ ()>()]; } @@ -119,12 +117,14 @@ impl Erasable for &'_ [T] { type Storage = [u8; size_of::<&'_ [()]>()]; } -impl Erasable for &'_ ty::List { - type Storage = [u8; size_of::<&'_ ty::List<()>>()]; -} - -impl Erasable for &'_ ty::ListWithCachedTypeInfo { - type Storage = [u8; size_of::<&'_ ty::ListWithCachedTypeInfo<()>>()]; +// Note: this impl does not overlap with the impl for `&'_ T` above because `RawList` is unsized +// and does not satisfy the implicit `T: Sized` bound. +// +// Furthermore, even if that implicit bound was removed (by adding `T: ?Sized`) this impl still +// wouldn't overlap because `?Sized` is equivalent to `MetaSized` and `RawList` does not satisfy +// `MetaSized` because it contains an extern type. +impl Erasable for &'_ ty::RawList { + type Storage = [u8; size_of::<&'_ ty::RawList<(), ()>>()]; } impl Erasable for Result<&'_ T, traits::query::NoSolution> { diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 82c23abefce45..a2bbc1ec75b99 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -37,7 +37,18 @@ pub type List = RawList<(), T>; #[repr(C)] pub struct RawList { skel: ListSkeleton, - opaque: OpaqueListContents, + + // `List`/`RawList` is variable-sized. So we want it to be an unsized + // type because calling `size_of::>` would be dangerous. + // + // We also want `&List`/`&RawList` to be thin pointers. + // + // A field with an extern type is a hacky way to achieve this. (See + // https://github.com/rust-lang/rust/pull/154399#issuecomment-4157036415 + // for some discussion.) This field is never directly manipulated because + // `RawList` instances are created with manual memory layout in + // `from_arena`. + _extern_ty: ExternTy, } /// A [`RawList`] without the unsized tail. This type is used for layout computation @@ -47,7 +58,8 @@ struct ListSkeleton { header: H, len: usize, /// Although this claims to be a zero-length array, in practice `len` - /// elements are actually present. + /// elements are actually present. This is achieved with manual memory + /// layout in `from_arena`. See also the comment on `RawList::_extern_ty`. data: [T; 0], } @@ -58,9 +70,7 @@ impl Default for &List { } unsafe extern "C" { - /// A dummy type used to force `List` to be unsized while not requiring - /// references to it be wide pointers. - type OpaqueListContents; + type ExternTy; } impl RawList { @@ -257,12 +267,13 @@ impl<'a, H, T: Copy> IntoIterator for &'a RawList { unsafe impl Sync for RawList {} -// We need this since `List` uses extern type `OpaqueListContents`. +// We need this because `List` uses the extern type `ExternTy`. unsafe impl DynSync for RawList {} // Safety: -// Layouts of `ListSkeleton` and `RawList` are the same, modulo opaque tail, -// thus aligns of `ListSkeleton` and `RawList` must be the same. +// Layouts of `ListSkeleton` and `RawList` are the same, modulo the +// `_extern_ty` field (which is never instantiated in practice). Therefore, +// aligns of `ListSkeleton` and `RawList` must be the same. unsafe impl Aligned for RawList { #[cfg(bootstrap)] const ALIGN: ptr::Alignment = align_of::>(); @@ -310,3 +321,14 @@ impl<'tcx> From>> for TypeInfo { } } } + +#[cfg(target_pointer_width = "64")] +mod size_asserts { + use rustc_data_structures::static_assert_size; + + use super::*; + // tidy-alphabetical-start + static_assert_size!(&List, 8); // thin pointer + static_assert_size!(&RawList, 8); // thin pointer + // tidy-alphabetical-end +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 674799cb41bad..822bbe079327f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -85,6 +85,7 @@ pub use self::context::{ }; pub use self::fold::*; pub use self::instance::{Instance, InstanceKind, ReifyReason}; +pub(crate) use self::list::RawList; pub use self::list::{List, ListWithCachedTypeInfo}; pub use self::opaque_types::OpaqueTypeKey; pub use self::pattern::{Pattern, PatternKind}; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 14746da57c47c..68d6162bd590e 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1952,24 +1952,6 @@ impl Arch { } } - pub fn supports_c_variadic_definitions(&self) -> bool { - use Arch::*; - - match self { - // These targets just do not support c-variadic definitions. - Bpf | SpirV => false, - - // We don't know if the target supports c-variadic definitions, but we don't want - // to needlessly restrict custom target.json configurations. - Other(_) => true, - - AArch64 | AmdGpu | Arm | Arm64EC | Avr | CSky | Hexagon | LoongArch32 | LoongArch64 - | M68k | Mips | Mips32r6 | Mips64 | Mips64r6 | Msp430 | Nvptx64 | PowerPC - | PowerPC64 | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 | Wasm64 | X86 - | X86_64 | Xtensa => true, - } - } - /// Whether `#[rustc_scalable_vector]` is supported for a target architecture pub fn supports_scalable_vectors(&self) -> bool { use Arch::*; @@ -2214,6 +2196,33 @@ impl Target { Ok(dl) } + + pub fn supports_c_variadic_definitions(&self) -> bool { + use Arch::*; + + match self.arch { + // The c-variadic ABI for this target may change in the future, per this comment in + // clang: + // + // > To be compatible with GCC's behaviors, we force arguments with + // > 2×XLEN-bit alignment and size at most 2×XLEN bits like `long long`, + // > `unsigned long long` and `double` to have 4-byte alignment. This + // > behavior may be changed when RV32E/ILP32E is ratified. + RiscV32 if self.llvm_abiname == LlvmAbi::Ilp32e => false, + + // These targets just do not support c-variadic definitions. + Bpf | SpirV => false, + + // We don't know how c-variadics work for this target. Using the default LLVM + // fallback implementation may work, but just to be safe we disallow this. + Other(_) => false, + + AArch64 | AmdGpu | Arm | Arm64EC | Avr | CSky | Hexagon | LoongArch32 | LoongArch64 + | M68k | Mips | Mips32r6 | Mips64 | Mips64r6 | Msp430 | Nvptx64 | PowerPC + | PowerPC64 | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 | Wasm64 | X86 + | X86_64 | Xtensa => true, + } + } } pub trait HasTargetSpec { diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index ffdcd9fad49a5..ea3ba8cf3a94f 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -740,7 +740,7 @@ //! //! While counter-intuitive, it's often the easier choice: if you do not expose a //! [Pin]<[&mut] Field>, you do not need to be careful about other code -//! moving out of that field, you just have to ensure is that you never create pinning +//! moving out of that field, you just have to ensure that you never create a pinning //! reference to that field. This does of course also mean that if you decide a field does not //! have structural pinning, you must not write [`unsafe`] code that assumes (invalidly) that the //! field *is* structurally pinned! diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index 59f515d31aff9..e2ee2482125c5 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -260,7 +260,7 @@ impl Socket { pub fn set_linger(&self, linger: Option) -> io::Result<()> { let linger = netc::linger { l_onoff: linger.is_some() as i32, - l_linger: linger.unwrap_or_default().as_secs() as libc::c_int, + l_linger: cmp::min(linger.unwrap_or_default().as_secs(), c_int::MAX as u64) as c_int, }; unsafe { setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) } diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index e20a3fbb76b72..7305100ca4a35 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -319,7 +319,8 @@ impl Socket { pub fn set_linger(&self, linger: Option) -> io::Result<()> { let linger = netc::linger { l_onoff: linger.is_some() as netc::c_int, - l_linger: linger.unwrap_or_default().as_secs() as netc::c_int, + l_linger: cmp::min(linger.unwrap_or_default().as_secs(), netc::c_int::MAX as u64) + as netc::c_int, }; unsafe { setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) } diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index f3c860804de03..71d819add1fcc 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -432,8 +432,8 @@ impl Socket { #[cfg(not(target_os = "cygwin"))] pub fn set_linger(&self, linger: Option) -> io::Result<()> { let linger = libc::linger { - l_onoff: linger.is_some() as libc::c_int, - l_linger: linger.unwrap_or_default().as_secs() as libc::c_int, + l_onoff: linger.is_some() as c_int, + l_linger: cmp::min(linger.unwrap_or_default().as_secs(), c_int::MAX as u64) as c_int, }; unsafe { setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger) } @@ -443,7 +443,8 @@ impl Socket { pub fn set_linger(&self, linger: Option) -> io::Result<()> { let linger = libc::linger { l_onoff: linger.is_some() as libc::c_ushort, - l_linger: linger.unwrap_or_default().as_secs() as libc::c_ushort, + l_linger: cmp::min(linger.unwrap_or_default().as_secs(), libc::c_ushort::MAX as u64) + as libc::c_ushort, }; unsafe { setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger) } diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index b23fb9c09f871..e533f310213dd 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -413,7 +413,8 @@ impl Socket { pub fn set_linger(&self, linger: Option) -> io::Result<()> { let linger = c::LINGER { l_onoff: linger.is_some() as c_ushort, - l_linger: linger.unwrap_or_default().as_secs() as c_ushort, + l_linger: cmp::min(linger.unwrap_or_default().as_secs(), c_ushort::MAX as u64) + as c_ushort, }; unsafe { setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger) } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/macro.fixed b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/macro.fixed new file mode 100644 index 0000000000000..cd5cda6d27a97 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/macro.fixed @@ -0,0 +1,19 @@ +//! Regression test for +//@ run-rustfix +#![deny(mismatched_lifetime_syntaxes)] +#![allow(unused)] + +struct Pair<'a, 'b>(&'a u8, &'b u8); + +macro_rules! repeated { + ($($pair:ident),+ ; $middle:ty) => { + ($($pair<'a, 'a>),+, $middle, $($pair<'a, 'a>),+) + //~^ ERROR hiding or eliding a lifetime that's named elsewhere is confusing + }; +} + +fn repeated_macro<'a>(x: &'a u8) -> repeated!(Pair, Pair; &'a u8) { + (Pair(x, x), Pair(x, x), x, Pair(x, x), Pair(x, x)) +} + +fn main() {} diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/macro.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/macro.rs new file mode 100644 index 0000000000000..8e8b6d9d7e099 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/macro.rs @@ -0,0 +1,19 @@ +//! Regression test for +//@ run-rustfix +#![deny(mismatched_lifetime_syntaxes)] +#![allow(unused)] + +struct Pair<'a, 'b>(&'a u8, &'b u8); + +macro_rules! repeated { + ($($pair:ident),+ ; $middle:ty) => { + ($($pair),+, $middle, $($pair),+) + //~^ ERROR hiding or eliding a lifetime that's named elsewhere is confusing + }; +} + +fn repeated_macro<'a>(x: &'a u8) -> repeated!(Pair, Pair; &'_ u8) { + (Pair(x, x), Pair(x, x), x, Pair(x, x), Pair(x, x)) +} + +fn main() {} diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/macro.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/macro.stderr new file mode 100644 index 0000000000000..5412c943ec087 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/macro.stderr @@ -0,0 +1,33 @@ +error: hiding or eliding a lifetime that's named elsewhere is confusing + --> $DIR/macro.rs:10:12 + | +LL | ($($pair),+, $middle, $($pair),+) + | ^^^^^ ^^^^^ the same lifetimes are hidden here + | | + | the same lifetimes are hidden here +... +LL | fn repeated_macro<'a>(x: &'a u8) -> repeated!(Pair, Pair; &'_ u8) { + | -- -----------------------^^---- + | | | | + | | | the same lifetime is elided here + | | in this macro invocation + | the lifetime is named here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +note: the lint level is defined here + --> $DIR/macro.rs:3:9 + | +LL | #![deny(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `repeated` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consistently use `'a` + | +LL ~ ($($pair<'a, 'a>),+, $middle, $($pair<'a, 'a>),+) +LL | +... +LL | +LL ~ fn repeated_macro<'a>(x: &'a u8) -> repeated!(Pair, Pair; &'a u8) { + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/mismatched-lifetime-syntaxes.rs similarity index 100% rename from tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs rename to tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/mismatched-lifetime-syntaxes.rs diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/mismatched-lifetime-syntaxes.stderr similarity index 100% rename from tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr rename to tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/mismatched-lifetime-syntaxes.stderr diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/path-count.fixed b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/path-count.fixed new file mode 100644 index 0000000000000..5689eed81ddea --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/path-count.fixed @@ -0,0 +1,69 @@ +//! Regression test for +//@ run-rustfix +#![deny(mismatched_lifetime_syntaxes)] +#![allow(unused)] + +struct Foo<'a, 'b> { + ptr1: &'a str, + ptr2: &'b str, +} + +// with generic +struct Bar<'a, 'b, T> { + ptr1: &'a T, + ptr2: &'b T, +} + +struct Wrapper(T); + +fn missing(_: &str) -> Foo<'_, '_> { + //~^ ERROR: hiding a lifetime that's elided elsewhere is confusing + todo!() +} + +fn missing_double(_: &str) -> (Foo<'_, '_>, Foo<'_, '_>) { + //~^ ERROR: hiding a lifetime that's elided elsewhere is confusing + todo!() +} + +fn empty(_: &str) -> Foo<'_, '_> { + //~^ ERROR: hiding a lifetime that's elided elsewhere is confusing + todo!() +} + +fn wrapper_missing(_: &str) -> Wrapper> { + //~^ ERROR: hiding a lifetime that's elided elsewhere is confusing + todo!() +} + +fn missing_generic(_: &str) -> Bar<'_, '_, u8> { + //~^ ERROR: hiding a lifetime that's elided elsewhere is confusing + todo!() +} + +fn named_missing<'a>(_: &'a u8) -> Foo<'a, 'a> { + //~^ ERROR: hiding a lifetime that's named elsewhere is confusing + todo!() +} + +fn named_empty<'a>(_: &'a u8) -> Foo<'a, 'a> { + //~^ ERROR: hiding a lifetime that's named elsewhere is confusing + todo!() +} + +fn static_missing(_: &'static u8) -> Foo<'static, 'static> { + //~^ ERROR: hiding a lifetime that's named elsewhere is confusing + todo!() +} + +fn static_empty(_: &'static u8) -> Foo<'static, 'static> { + //~^ ERROR: hiding a lifetime that's named elsewhere is confusing + todo!() +} + +fn static_missing_generic(_: &'static str) -> Bar<'static, 'static, u8> { + //~^ ERROR: hiding a lifetime that's named elsewhere is confusing + todo!() +} + +fn main() {} diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/path-count.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/path-count.rs new file mode 100644 index 0000000000000..3c12600e07a5e --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/path-count.rs @@ -0,0 +1,69 @@ +//! Regression test for +//@ run-rustfix +#![deny(mismatched_lifetime_syntaxes)] +#![allow(unused)] + +struct Foo<'a, 'b> { + ptr1: &'a str, + ptr2: &'b str, +} + +// with generic +struct Bar<'a, 'b, T> { + ptr1: &'a T, + ptr2: &'b T, +} + +struct Wrapper(T); + +fn missing(_: &str) -> Foo { + //~^ ERROR: hiding a lifetime that's elided elsewhere is confusing + todo!() +} + +fn missing_double(_: &str) -> (Foo, Foo) { + //~^ ERROR: hiding a lifetime that's elided elsewhere is confusing + todo!() +} + +fn empty(_: &str) -> Foo<> { + //~^ ERROR: hiding a lifetime that's elided elsewhere is confusing + todo!() +} + +fn wrapper_missing(_: &str) -> Wrapper { + //~^ ERROR: hiding a lifetime that's elided elsewhere is confusing + todo!() +} + +fn missing_generic(_: &str) -> Bar { + //~^ ERROR: hiding a lifetime that's elided elsewhere is confusing + todo!() +} + +fn named_missing<'a>(_: &'a u8) -> Foo { + //~^ ERROR: hiding a lifetime that's named elsewhere is confusing + todo!() +} + +fn named_empty<'a>(_: &'a u8) -> Foo<> { + //~^ ERROR: hiding a lifetime that's named elsewhere is confusing + todo!() +} + +fn static_missing(_: &'static u8) -> Foo { + //~^ ERROR: hiding a lifetime that's named elsewhere is confusing + todo!() +} + +fn static_empty(_: &'static u8) -> Foo<> { + //~^ ERROR: hiding a lifetime that's named elsewhere is confusing + todo!() +} + +fn static_missing_generic(_: &'static str) -> Bar { + //~^ ERROR: hiding a lifetime that's named elsewhere is confusing + todo!() +} + +fn main() {} diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/path-count.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/path-count.stderr new file mode 100644 index 0000000000000..45e135bd1daab --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/path-count.stderr @@ -0,0 +1,148 @@ +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/path-count.rs:19:15 + | +LL | fn missing(_: &str) -> Foo { + | ^^^^ ^^^ the same lifetimes are hidden here + | | + | the lifetime is elided here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +note: the lint level is defined here + --> $DIR/path-count.rs:3:9 + | +LL | #![deny(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use `'_` for type paths + | +LL | fn missing(_: &str) -> Foo<'_, '_> { + | ++++++++ + +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/path-count.rs:24:22 + | +LL | fn missing_double(_: &str) -> (Foo, Foo) { + | ^^^^ ^^^ ^^^ the same lifetimes are hidden here + | | | + | | the same lifetimes are hidden here + | the lifetime is elided here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths + | +LL | fn missing_double(_: &str) -> (Foo<'_, '_>, Foo<'_, '_>) { + | ++++++++ ++++++++ + +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/path-count.rs:29:13 + | +LL | fn empty(_: &str) -> Foo<> { + | ^^^^ ^^^^^ the same lifetimes are hidden here + | | + | the lifetime is elided here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths + | +LL | fn empty(_: &str) -> Foo<'_, '_> { + | ++++++ + +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/path-count.rs:34:23 + | +LL | fn wrapper_missing(_: &str) -> Wrapper { + | ^^^^ ^^^ the same lifetimes are hidden here + | | + | the lifetime is elided here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths + | +LL | fn wrapper_missing(_: &str) -> Wrapper> { + | ++++++++ + +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/path-count.rs:39:23 + | +LL | fn missing_generic(_: &str) -> Bar { + | ^^^^ ^^^^^^^ the same lifetimes are hidden here + | | + | the lifetime is elided here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths + | +LL | fn missing_generic(_: &str) -> Bar<'_, '_, u8> { + | +++++++ + +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/path-count.rs:44:36 + | +LL | fn named_missing<'a>(_: &'a u8) -> Foo { + | -- ^^^ the same lifetimes are hidden here + | | + | the lifetime is named here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` + | +LL | fn named_missing<'a>(_: &'a u8) -> Foo<'a, 'a> { + | ++++++++ + +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/path-count.rs:49:34 + | +LL | fn named_empty<'a>(_: &'a u8) -> Foo<> { + | -- ^^^^^ the same lifetimes are hidden here + | | + | the lifetime is named here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` + | +LL | fn named_empty<'a>(_: &'a u8) -> Foo<'a, 'a> { + | ++++++ + +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/path-count.rs:54:38 + | +LL | fn static_missing(_: &'static u8) -> Foo { + | ------- ^^^ the same lifetimes are hidden here + | | + | the lifetime is named here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` + | +LL | fn static_missing(_: &'static u8) -> Foo<'static, 'static> { + | ++++++++++++++++++ + +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/path-count.rs:59:36 + | +LL | fn static_empty(_: &'static u8) -> Foo<> { + | ------- ^^^^^ the same lifetimes are hidden here + | | + | the lifetime is named here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` + | +LL | fn static_empty(_: &'static u8) -> Foo<'static, 'static> { + | ++++++++++++++++ + +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/path-count.rs:64:47 + | +LL | fn static_missing_generic(_: &'static str) -> Bar { + | ------- ^^^^^^^ the same lifetimes are hidden here + | | + | the lifetime is named here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` + | +LL | fn static_missing_generic(_: &'static str) -> Bar<'static, 'static, u8> { + | +++++++++++++++++ + +error: aborting due to 10 previous errors +