diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index da954cf4ed740..fccb6b171b1c2 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -280,22 +280,110 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { interp_ok(match (a, b) { // Comparisons between integers are always known. (Scalar::Int(a), Scalar::Int(b)) => (a == b) as u8, - // Comparisons of null with an arbitrary scalar can be known if `scalar_may_be_null` - // indicates that the scalar can definitely *not* be null. - (Scalar::Int(int), ptr) | (ptr, Scalar::Int(int)) - if int.is_null() && !self.scalar_may_be_null(ptr)? => - { - 0 + // Comparing a pointer `ptr` with an integer `int` is equivalent to comparing + // `ptr-int` with null, so we can reduce this case to a `scalar_may_be_null` test. + (Scalar::Int(int), Scalar::Ptr(ptr, _)) | (Scalar::Ptr(ptr, _), Scalar::Int(int)) => { + let int = int.to_target_usize(*self.tcx); + // The `wrapping_neg` here may produce a value that is not + // a valid target usize any more... but `wrapping_offset` handles that correctly. + let offset_ptr = ptr.wrapping_offset(Size::from_bytes(int.wrapping_neg()), self); + if !self.scalar_may_be_null(Scalar::from_pointer(offset_ptr, self))? { + // `ptr.wrapping_sub(int)` is definitely not equal to `0`, so `ptr != int` + 0 + } else { + // `ptr.wrapping_sub(int)` could be equal to `0`, but might not be, + // so we cannot know for sure if `ptr == int` or not + 2 + } + } + (Scalar::Ptr(a, _), Scalar::Ptr(b, _)) => { + let (a_prov, a_offset) = a.prov_and_relative_offset(); + let (b_prov, b_offset) = b.prov_and_relative_offset(); + let a_allocid = a_prov.alloc_id(); + let b_allocid = b_prov.alloc_id(); + let a_info = self.get_alloc_info(a_allocid); + let b_info = self.get_alloc_info(b_allocid); + + // Check if the pointers cannot be equal due to alignment + if a_info.align > Align::ONE && b_info.align > Align::ONE { + let min_align = Ord::min(a_info.align.bytes(), b_info.align.bytes()); + let a_residue = a_offset.bytes() % min_align; + let b_residue = b_offset.bytes() % min_align; + if a_residue != b_residue { + // If the two pointers have a different residue modulo their + // common alignment, they cannot be equal. + return interp_ok(0); + } + // The pointers have the same residue modulo their common alignment, + // so they could be equal. Try the other checks. + } + + if let (Some(GlobalAlloc::Static(a_did)), Some(GlobalAlloc::Static(b_did))) = ( + self.tcx.try_get_global_alloc(a_allocid), + self.tcx.try_get_global_alloc(b_allocid), + ) { + if a_allocid == b_allocid { + debug_assert_eq!( + a_did, b_did, + "different static item DefIds had same AllocId? {a_allocid:?} == {b_allocid:?}, {a_did:?} != {b_did:?}" + ); + // Comparing two pointers into the same static. As per + // https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.intro + // a static cannot be duplicated, so if two pointers are into the same + // static, they are equal if and only if their offsets are equal. + (a_offset == b_offset) as u8 + } else { + debug_assert_ne!( + a_did, b_did, + "same static item DefId had two different AllocIds? {a_allocid:?} != {b_allocid:?}, {a_did:?} == {b_did:?}" + ); + // Comparing two pointers into the different statics. + // We can never determine for sure that two pointers into different statics + // are *equal*, but we can know that they are *inequal* if they are both + // strictly in-bounds (i.e. in-bounds and not one-past-the-end) of + // their respective static, as different non-zero-sized statics cannot + // overlap or be deduplicated as per + // https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.intro + // (non-deduplication), and + // https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.storage-disjointness + // (non-overlapping). + if a_offset < a_info.size && b_offset < b_info.size { + 0 + } else { + // Otherwise, conservatively say we don't know. + // There are some cases we could still return `0` for, e.g. + // if the pointers being equal would require their statics to overlap + // one or more bytes, but for simplicity we currently only check + // strictly in-bounds pointers. + 2 + } + } + } else { + // All other cases we conservatively say we don't know. + // + // For comparing statics to non-statics, as per https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.storage-disjointness + // immutable statics can overlap with other kinds of allocations sometimes. + // + // FIXME: We could be more decisive for (non-zero-sized) mutable statics, + // which cannot overlap with other kinds of allocations. + // + // Functions and vtables can be duplicated and deduplicated, so we + // cannot be sure of runtime equality of pointers to the same one, or the + // runtime inequality of pointers to different ones (see e.g. #73722), + // so comparing those should return 2, whether they are the same allocation + // or not. + // + // `GlobalAlloc::TypeId` exists mostly to prevent consteval from comparing + // `TypeId`s, so comparing those should always return 2, whether they are the + // same allocation or not. + // + // FIXME: We could revisit comparing pointers into the same + // `GlobalAlloc::Memory` once https://github.com/rust-lang/rust/issues/128775 + // is fixed (but they can be deduplicated, so comparing pointers into different + // ones should return 2). + 2 + } } - // Other ways of comparing integers and pointers can never be known for sure. - (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => 2, - // FIXME: return a `1` for when both sides are the same pointer, *except* that - // some things (like functions and vtables) do not have stable addresses - // so we need to be careful around them (see e.g. #73722). - // FIXME: return `0` for at least some comparisons where we can reliably - // determine the result of runtime inequality tests at compile-time. - // Examples include comparison of addresses in different static items. - (Scalar::Ptr(..), Scalar::Ptr(..)) => 2, }) } } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 940a07c94df87..417e5a97069c3 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -462,6 +462,14 @@ lint_invalid_reference_casting_note_book = for more information, visit + .help_exposed_provenance = for more information about exposed provenance, see + .suggestion_with_exposed_provenance = use `std::ptr::with_exposed_provenance{$suffix}` instead to use a previously exposed provenance + .suggestion_without_provenance_mut = if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + lint_legacy_derive_helpers = derive helper attribute is used before it is introduced .label = the attribute is introduced here diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 464f4fc34b966..413525eb6e514 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -214,9 +214,9 @@ impl LifetimeSyntaxCategories> { } } - pub fn flatten(&self) -> impl Iterator { - let Self { hidden, elided, named } = self; - [hidden.iter(), elided.iter(), named.iter()].into_iter().flatten() + pub fn iter_unnamed(&self) -> impl Iterator { + let Self { hidden, elided, named: _ } = self; + [hidden.iter(), elided.iter()].into_iter().flatten() } } @@ -495,7 +495,7 @@ fn emit_mismatch_diagnostic<'tcx>( cx.emit_span_lint( MISMATCHED_LIFETIME_SYNTAXES, - inputs.flatten().copied().collect::>(), + inputs.iter_unnamed().chain(outputs.iter_unnamed()).copied().collect::>(), lints::MismatchedLifetimeSyntaxes { inputs, outputs, suggestions }, ); } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 6c50973462684..426500dda4a72 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + #![allow(rustc::untranslatable_diagnostic)] use std::num::NonZero; @@ -1542,6 +1544,48 @@ impl<'a> LintDiagnostic<'a, ()> for DropGlue<'_> { } } +// transmute.rs +#[derive(LintDiagnostic)] +#[diag(lint_int_to_ptr_transmutes)] +#[note] +#[note(lint_note_exposed_provenance)] +#[help(lint_suggestion_without_provenance_mut)] +#[help(lint_help_transmute)] +#[help(lint_help_exposed_provenance)] +pub(crate) struct IntegerToPtrTransmutes<'tcx> { + #[subdiagnostic] + pub suggestion: IntegerToPtrTransmutesSuggestion<'tcx>, +} + +#[derive(Subdiagnostic)] +pub(crate) enum IntegerToPtrTransmutesSuggestion<'tcx> { + #[multipart_suggestion( + lint_suggestion_with_exposed_provenance, + applicability = "machine-applicable", + style = "verbose" + )] + ToPtr { + dst: Ty<'tcx>, + suffix: &'static str, + #[suggestion_part(code = "std::ptr::with_exposed_provenance{suffix}::<{dst}>(")] + start_call: Span, + }, + #[multipart_suggestion( + lint_suggestion_with_exposed_provenance, + applicability = "machine-applicable", + style = "verbose" + )] + ToRef { + dst: Ty<'tcx>, + suffix: &'static str, + ref_mutbl: &'static str, + #[suggestion_part( + code = "&{ref_mutbl}*std::ptr::with_exposed_provenance{suffix}::<{dst}>(" + )] + start_call: Span, + }, +} + // types.rs #[derive(LintDiagnostic)] #[diag(lint_range_endpoint_out_of_range)] diff --git a/compiler/rustc_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs index bc1d4587d076e..239c864904163 100644 --- a/compiler/rustc_lint/src/transmute.rs +++ b/compiler/rustc_lint/src/transmute.rs @@ -1,3 +1,4 @@ +use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; @@ -7,6 +8,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::sym; +use crate::lints::{IntegerToPtrTransmutes, IntegerToPtrTransmutesSuggestion}; use crate::{LateContext, LateLintPass}; declare_lint! { @@ -67,9 +69,44 @@ declare_lint! { "detects transmutes that can also be achieved by other operations" } +declare_lint! { + /// The `integer_to_ptr_transmutes` lint detects integer to pointer + /// transmutes where the resulting pointers are undefined behavior to dereference. + /// + /// ### Example + /// + /// ```rust + /// fn foo(a: usize) -> *const u8 { + /// unsafe { + /// std::mem::transmute::(a) + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Any attempt to use the resulting pointers are undefined behavior as the resulting + /// pointers won't have any provenance. + /// + /// Alternatively, [`std::ptr::with_exposed_provenance`] should be used, as they do not + /// carry the provenance requirement. If wanting to create pointers without provenance + /// [`std::ptr::without_provenance`] should be used instead. + /// + /// See [`std::mem::transmute`] in the reference for more details. + /// + /// [`std::mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html + /// [`std::ptr::with_exposed_provenance`]: https://doc.rust-lang.org/std/ptr/fn.with_exposed_provenance.html + /// [`std::ptr::without_provenance`]: https://doc.rust-lang.org/std/ptr/fn.without_provenance.html + pub INTEGER_TO_PTR_TRANSMUTES, + Warn, + "detects integer to pointer transmutes", +} + pub(crate) struct CheckTransmutes; -impl_lint_pass!(CheckTransmutes => [PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, UNNECESSARY_TRANSMUTES]); +impl_lint_pass!(CheckTransmutes => [PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, UNNECESSARY_TRANSMUTES, INTEGER_TO_PTR_TRANSMUTES]); impl<'tcx> LateLintPass<'tcx> for CheckTransmutes { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { @@ -94,9 +131,62 @@ impl<'tcx> LateLintPass<'tcx> for CheckTransmutes { check_ptr_transmute_in_const(cx, expr, body_owner_def_id, const_context, src, dst); check_unnecessary_transmute(cx, expr, callee, arg, const_context, src, dst); + check_int_to_ptr_transmute(cx, expr, arg, src, dst); } } +/// Check for transmutes from integer to pointers (*const/*mut and &/&mut). +/// +/// Using the resulting pointers would be undefined behavior. +fn check_int_to_ptr_transmute<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + arg: &'tcx hir::Expr<'tcx>, + src: Ty<'tcx>, + dst: Ty<'tcx>, +) { + if !matches!(src.kind(), ty::Uint(_) | ty::Int(_)) { + return; + } + let (ty::Ref(_, inner_ty, mutbl) | ty::RawPtr(inner_ty, mutbl)) = dst.kind() else { + return; + }; + // bail-out if the argument is literal 0 as we have other lints for those cases + if matches!(arg.kind, hir::ExprKind::Lit(hir::Lit { node: LitKind::Int(v, _), .. }) if v == 0) { + return; + } + // bail-out if the inner type is a ZST + let Ok(layout_inner_ty) = cx.tcx.layout_of(cx.typing_env().as_query_input(*inner_ty)) else { + return; + }; + if layout_inner_ty.is_1zst() { + return; + } + + let suffix = if mutbl.is_mut() { "_mut" } else { "" }; + cx.tcx.emit_node_span_lint( + INTEGER_TO_PTR_TRANSMUTES, + expr.hir_id, + expr.span, + IntegerToPtrTransmutes { + suggestion: if dst.is_ref() { + IntegerToPtrTransmutesSuggestion::ToRef { + dst: *inner_ty, + suffix, + ref_mutbl: mutbl.prefix_str(), + start_call: expr.span.shrink_to_lo().until(arg.span), + } + } else { + IntegerToPtrTransmutesSuggestion::ToPtr { + dst: *inner_ty, + suffix, + start_call: expr.span.shrink_to_lo().until(arg.span), + } + }, + }, + ); +} + /// Check for transmutes that exhibit undefined behavior. /// For example, transmuting pointers to integers in a const context. /// diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index f5c490ca7cea3..6fc85a83e179e 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -914,6 +914,7 @@ pub const fn dangling() -> *const T { #[must_use] #[stable(feature = "strict_provenance", since = "1.84.0")] #[rustc_const_stable(feature = "strict_provenance", since = "1.84.0")] +#[allow(integer_to_ptr_transmutes)] // Expected semantics here. pub const fn without_provenance_mut(addr: usize) -> *mut T { // An int-to-pointer transmute currently has exactly the intended semantics: it creates a // pointer without provenance. Note that this is *not* a stable guarantee about transmute diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ab417b6c72f9b..f0de03c9a2806 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -15,7 +15,7 @@ //! //! If you already know the name of what you are looking for, the fastest way to //! find it is to use the search -//! bar at the top of the page. +//! button at the top of the page. //! //! Otherwise, you may want to jump to one of these useful sections: //! diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index a40e29a772a9c..3231125f7a13a 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -244,7 +244,11 @@ impl T> LazyLock { #[inline] #[stable(feature = "lazy_cell", since = "1.80.0")] pub fn force(this: &LazyLock) -> &T { - this.once.call_once(|| { + this.once.call_once_force(|state| { + if state.is_poisoned() { + panic_poisoned(); + } + // SAFETY: `call_once` only runs this closure once, ever. let data = unsafe { &mut *this.data.get() }; let f = unsafe { ManuallyDrop::take(&mut data.f) }; @@ -257,8 +261,7 @@ impl T> LazyLock { // * the closure was called and initialized `value`. // * the closure was called and panicked, so this point is never reached. // * the closure was not called, but a previous call initialized `value`. - // * the closure was not called because the Once is poisoned, so this point - // is never reached. + // * the closure was not called because the Once is poisoned, which we handled above. // So `value` has definitely been initialized and will not be modified again. unsafe { &*(*this.data.get()).value } } diff --git a/library/std/tests/sync/lazy_lock.rs b/library/std/tests/sync/lazy_lock.rs index 6c14b79f2ce7c..68aeea834b4fa 100644 --- a/library/std/tests/sync/lazy_lock.rs +++ b/library/std/tests/sync/lazy_lock.rs @@ -33,16 +33,6 @@ fn lazy_default() { assert_eq!(CALLED.load(SeqCst), 1); } -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn lazy_poisoning() { - let x: LazyCell = LazyCell::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); - assert!(res.is_err()); - } -} - #[test] #[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn sync_lazy_new() { @@ -123,16 +113,6 @@ fn static_sync_lazy_via_fn() { assert_eq!(xs(), &vec![1, 2, 3]); } -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn sync_lazy_poisoning() { - let x: LazyLock = LazyLock::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(|| x.len()); - assert!(res.is_err()); - } -} - // Check that we can infer `T` from closure's type. #[test] fn lazy_type_inference() { @@ -145,17 +125,6 @@ fn is_sync_send() { assert_traits::>(); } -#[test] -#[should_panic = "has previously been poisoned"] -fn lazy_force_mut_panic() { - let mut lazy = LazyLock::::new(|| panic!()); - panic::catch_unwind(panic::AssertUnwindSafe(|| { - let _ = LazyLock::force_mut(&mut lazy); - })) - .unwrap_err(); - let _ = &*lazy; -} - #[test] fn lazy_force_mut() { let s = "abc".to_owned(); @@ -165,3 +134,56 @@ fn lazy_force_mut() { p.clear(); LazyLock::force_mut(&mut lazy); } + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn lazy_poisoning() { + let x: LazyCell = LazyCell::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); + assert!(res.is_err()); + } +} + +/// Verifies that when a `LazyLock` is poisoned, it panics with the correct error message ("LazyLock +/// instance has previously been poisoned") instead of the underlying `Once` error message. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +#[should_panic(expected = "LazyLock instance has previously been poisoned")] +fn lazy_lock_deref_panic() { + let lazy: LazyLock = LazyLock::new(|| panic!("initialization failed")); + + // First access will panic during initialization. + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { + let _ = &*lazy; + })); + + // Second access should panic with the poisoned message. + let _ = &*lazy; +} + +#[test] +#[should_panic(expected = "LazyLock instance has previously been poisoned")] +fn lazy_lock_deref_mut_panic() { + let mut lazy: LazyLock = LazyLock::new(|| panic!("initialization failed")); + + // First access will panic during initialization. + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { + let _ = LazyLock::force_mut(&mut lazy); + })); + + // Second access should panic with the poisoned message. + let _ = &*lazy; +} + +/// Verifies that when the initialization closure panics with a custom message, that message is +/// preserved and not overridden by `LazyLock`. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +#[should_panic(expected = "custom panic message from closure")] +fn lazy_lock_preserves_closure_panic_message() { + let lazy: LazyLock = LazyLock::new(|| panic!("custom panic message from closure")); + + // This should panic with the original message from the closure. + let _ = &*lazy; +} diff --git a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml index 04d6469aeaa42..5ff3118960da6 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml @@ -3,8 +3,8 @@ name: rustc-pull on: workflow_dispatch: schedule: - # Run at 04:00 UTC every Monday and Thursday - - cron: '0 4 * * 1,4' + # Run at 04:00 UTC every Monday + - cron: '0 4 * * 1' jobs: pull: diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 6ec700b9b4dc1..a399b5cd77e54 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -6bcdcc73bd11568fd85f5a38b58e1eda054ad1cd +425a9c0a0e365c0b8c6cfd00c2ded83a73bed9a0 diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md index 057e4a4cceed3..f3957724967c3 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -74,7 +74,6 @@ You might also find the following sites useful: of the team procedures, active working groups, and the team calendar. - [std-dev-guide] -- a similar guide for developing the standard library. - [The t-compiler zulip][z] -- `#contribute` and `#wg-rustup` on [Discord](https://discord.gg/rust-lang). - The [Rust Internals forum][rif], a place to ask questions and discuss Rust's internals - The [Rust reference][rr], even though it doesn't specifically talk about diff --git a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md index 1b6b87e4c8d50..1693432b90de7 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md @@ -20,7 +20,7 @@ explanations should help users understand why their code cannot be accepted by the compiler. Rust prides itself on helpful error messages and long-form explanations are no exception. However, before error explanations are overhauled[^new-explanations] it is a bit open as to how exactly they should be -written, as always: ask your reviewer or ask around on the Rust Discord or Zulip. +written, as always: ask your reviewer or ask around on the Rust Zulip. [^new-explanations]: See the draft RFC [here][new-explanations-rfc]. diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md index 04d2e37732fa9..87e26d3796881 100644 --- a/src/doc/rustc-dev-guide/src/getting-started.md +++ b/src/doc/rustc-dev-guide/src/getting-started.md @@ -11,7 +11,6 @@ quick guide for the most useful things. For more information, [see this chapter on how to build and run the compiler](./building/how-to-build-and-run.md). [internals]: https://internals.rust-lang.org -[rust-discord]: http://discord.gg/rust-lang [rust-zulip]: https://rust-lang.zulipchat.com [coc]: https://www.rust-lang.org/policies/code-of-conduct [walkthrough]: ./walkthrough.md @@ -20,8 +19,7 @@ chapter on how to build and run the compiler](./building/how-to-build-and-run.md ## Asking Questions If you have questions, please make a post on the [Rust Zulip server][rust-zulip] or -[internals.rust-lang.org][internals]. If you are contributing to Rustup, be aware they are not on -Zulip - you can ask questions in `#wg-rustup` [on Discord][rust-discord]. +[internals.rust-lang.org][internals]. See the [list of teams and working groups][governance] and [the Community page][community] on the official website for more resources. @@ -30,19 +28,23 @@ official website for more resources. As a reminder, all contributors are expected to follow our [Code of Conduct][coc]. -The compiler team (or `t-compiler`) usually hangs out in Zulip [in this -"stream"][z]; it will be easiest to get questions answered there. +The compiler team (or `t-compiler`) usually hangs out in Zulip in +[the #t-compiler channel][z-t-compiler]; +questions about how the compiler works can go in [#t-compiler/help][z-help]. -[z]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler +[z-t-compiler]: https://rust-lang.zulipchat.com/#narrow/channel/131828-t-compiler +[z-help]: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp **Please ask questions!** A lot of people report feeling that they are "wasting -expert time", but nobody on `t-compiler` feels this way. Contributors are +expert's time", but nobody on `t-compiler` feels this way. Contributors are important to us. Also, if you feel comfortable, prefer public topics, as this means others can see the questions and answers, and perhaps even integrate them back into this guide :) +**Tip**: If you're not a native English speaker and feel unsure about writing, try using a translator to help. But avoid using LLM tools that generate long, complex words. In daily teamwork, **simple and clear words** are best for easy understanding. Even small typos or grammar mistakes can make you seem more human, and people connect better with humans. + ### Experts Not all `t-compiler` members are experts on all parts of `rustc`; it's a @@ -162,15 +164,12 @@ incredibly helpful: - [Triaging issues][triage]: categorizing, replicating, and minimizing issues is very helpful to the Rust maintainers. - [Working groups][wg]: there are a bunch of working groups on a wide variety of rust-related things. -- Answer questions in the _Get Help!_ channels on the [Rust Discord - server][rust-discord], on [users.rust-lang.org][users], or on - [StackOverflow][so]. +- Answer questions on [users.rust-lang.org][users], or on [Stack Overflow][so]. - Participate in the [RFC process](https://github.com/rust-lang/rfcs). - Find a [requested community library][community-library], build it, and publish it to [Crates.io](http://crates.io). Easier said than done, but very, very valuable! -[rust-discord]: https://discord.gg/rust-lang [users]: https://users.rust-lang.org/ [so]: http://stackoverflow.com/questions/tagged/rust [community-library]: https://github.com/rust-lang/rfcs/labels/A-community-library diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index 447c6fd454671..8f0511a4548af 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md @@ -338,13 +338,13 @@ your fork with `git push --force-with-lease`. ### Keeping things up to date -The above section on [Rebasing](#rebasing) is a specific +The [above section](#rebasing) is a specific guide on rebasing work and dealing with merge conflicts. Here is some general advice about how to keep your local repo up-to-date with upstream changes: Using `git pull upstream master` while on your local master branch regularly -will keep it up-to-date. You will also want to rebase your feature branches +will keep it up-to-date. You will also want to keep your feature branches up-to-date as well. After pulling, you can checkout the feature branches and rebase them: diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs index ec5fb2793f976..b898920baefc2 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs @@ -49,17 +49,7 @@ pub(super) fn check<'tcx>( true }, (ty::Int(_) | ty::Uint(_), ty::RawPtr(_, _)) => { - span_lint_and_then( - cx, - USELESS_TRANSMUTE, - e.span, - "transmute from an integer to a pointer", - |diag| { - if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - diag.span_suggestion(e.span, "try", arg.as_ty(to_ty.to_string()), Applicability::Unspecified); - } - }, - ); + // Handled by the upstream rustc `integer_to_ptr_transmutes` lint true }, _ => false, diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 87235057349e3..f32e83d8b8184 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -268,10 +268,10 @@ LL | fn barbar(_x: &mut Vec, y: &mut String) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: eliding a lifetime that's named elsewhere is confusing - --> tests/ui/ptr_arg.rs:314:36 + --> tests/ui/ptr_arg.rs:314:56 | LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { - | ^^ ^^ ---- the same lifetime is elided here + | -- -- ^^^^ the same lifetime is elided here | | | | | the lifetime is named here | the lifetime is named here diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs index e968e7a59244d..e7099104f942d 100644 --- a/src/tools/clippy/tests/ui/transmute.rs +++ b/src/tools/clippy/tests/ui/transmute.rs @@ -4,6 +4,7 @@ dead_code, clippy::borrow_as_ptr, unnecessary_transmutes, + integer_to_ptr_transmutes, clippy::needless_lifetimes, clippy::missing_transmute_annotations )] @@ -60,12 +61,10 @@ fn useless() { //~^ useless_transmute let _: *const usize = std::mem::transmute(5_isize); - //~^ useless_transmute let _ = std::ptr::dangling::(); let _: *const usize = std::mem::transmute(1 + 1usize); - //~^ useless_transmute let _ = (1 + 1_usize) as *const usize; } diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index 79528ec06f1bf..9478db09481a8 100644 --- a/src/tools/clippy/tests/ui/transmute.stderr +++ b/src/tools/clippy/tests/ui/transmute.stderr @@ -1,5 +1,5 @@ error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:33:27 + --> tests/ui/transmute.rs:34:27 | LL | let _: *const T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` @@ -8,61 +8,49 @@ LL | let _: *const T = core::mem::transmute(t); = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:36:25 + --> tests/ui/transmute.rs:37:25 | LL | let _: *mut T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:39:27 + --> tests/ui/transmute.rs:40:27 | LL | let _: *const U = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:47:27 + --> tests/ui/transmute.rs:48:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:50:27 + --> tests/ui/transmute.rs:51:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:53:27 + --> tests/ui/transmute.rs:54:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:56:27 + --> tests/ui/transmute.rs:57:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:59:27 + --> tests/ui/transmute.rs:60:27 | LL | let _: Vec = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ -error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:62:31 - | -LL | let _: *const usize = std::mem::transmute(5_isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` - -error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:67:31 - | -LL | let _: *const usize = std::mem::transmute(1 + 1usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize` - error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:99:24 + --> tests/ui/transmute.rs:98:24 | LL | let _: Usize = core::mem::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,25 +59,25 @@ LL | let _: Usize = core::mem::transmute(int_const_ptr); = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:102:24 + --> tests/ui/transmute.rs:101:24 | LL | let _: Usize = core::mem::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> tests/ui/transmute.rs:105:31 + --> tests/ui/transmute.rs:104:31 | LL | let _: *const Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> tests/ui/transmute.rs:108:29 + --> tests/ui/transmute.rs:107:29 | LL | let _: *mut Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u8` to a `bool` - --> tests/ui/transmute.rs:115:28 + --> tests/ui/transmute.rs:114:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -98,7 +86,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:122:28 + --> tests/ui/transmute.rs:121:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -107,16 +95,16 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> tests/ui/transmute.rs:125:32 + --> tests/ui/transmute.rs:124:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:128:30 + --> tests/ui/transmute.rs:127:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 18 previous errors +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed index e7ad2a1cbbcb1..02f67f79e2b19 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -13,9 +13,6 @@ fn main() { // We should see an error message for each transmute, and no error messages for // the casts, since the casts are the recommended fixes. - // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast - let _ptr_i32_transmute = unsafe { usize::MAX as *const i32 }; - //~^ useless_transmute let ptr_i32 = usize::MAX as *const i32; // e has type *T, U is *U_0, and either U_0: Sized ... diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs index 42a81777a8267..c5e156405ebca 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -13,9 +13,6 @@ fn main() { // We should see an error message for each transmute, and no error messages for // the casts, since the casts are the recommended fixes. - // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast - let _ptr_i32_transmute = unsafe { transmute::(usize::MAX) }; - //~^ useless_transmute let ptr_i32 = usize::MAX as *const i32; // e has type *T, U is *U_0, and either U_0: Sized ... diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr index 7746f087cc714..f39a64d57eb49 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr @@ -1,14 +1,5 @@ -error: transmute from an integer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:17:39 - | -LL | let _ptr_i32_transmute = unsafe { transmute::(usize::MAX) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `usize::MAX as *const i32` - | - = note: `-D clippy::useless-transmute` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` - error: transmute from a pointer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:22:38 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:19:38 | LL | let _ptr_i8_transmute = unsafe { transmute::<*const i32, *const i8>(ptr_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +13,7 @@ LL + let _ptr_i8_transmute = unsafe { ptr_i32.cast::() }; | error: transmute from a pointer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:29:46 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:26:46 | LL | let _ptr_to_unsized_transmute = unsafe { transmute::<*const [i32], *const [u32]>(slice_ptr) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +25,7 @@ LL + let _ptr_to_unsized_transmute = unsafe { slice_ptr as *const [u32] }; | error: transmute from `*const i32` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:36:50 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:33:50 | LL | let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, usize>(ptr_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr_i32 as usize` @@ -43,40 +34,43 @@ LL | let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, us = help: to override `-D warnings` add `#[allow(clippy::transmutes_expressible_as_ptr_casts)]` error: transmute from a reference to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:43:41 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:40:41 | LL | let _array_ptr_transmute = unsafe { transmute::<&[i32; 4], *const [i32; 4]>(array_ref) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `array_ref as *const [i32; 4]` + | + = note: `-D clippy::useless-transmute` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from `fn(usize) -> u8` to `*const usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:52:41 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:49:41 | LL | let _usize_ptr_transmute = unsafe { transmute:: u8, *const usize>(foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as *const usize` error: transmute from `fn(usize) -> u8` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:57:49 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:54:49 | LL | let _usize_from_fn_ptr_transmute = unsafe { transmute:: u8, usize>(foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize` error: transmute from `*const u32` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:61:36 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:58:36 | LL | let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&1u32 as *const u32 as usize` error: transmute from a reference to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:73:14 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:70:14 | LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8` error: transmute from `fn()` to `*const u8` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:92:28 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:89:28 | LL | let _x: u8 = unsafe { *std::mem::transmute::(f) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(f as *const u8)` -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs b/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs index 2b861e5447b03..7147813c4b6c1 100644 --- a/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs +++ b/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs @@ -1,3 +1,5 @@ +#![allow(integer_to_ptr_transmutes)] + use std::mem::transmute; #[cfg(target_pointer_width = "32")] diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.rs b/src/tools/miri/tests/fail/provenance/provenance_transmute.rs index d72f10530d7ab..60cb9a7f6bfb1 100644 --- a/src/tools/miri/tests/fail/provenance/provenance_transmute.rs +++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.rs @@ -1,5 +1,7 @@ //@compile-flags: -Zmiri-permissive-provenance +#![allow(integer_to_ptr_transmutes)] + use std::mem; // This is the example from diff --git a/src/tools/miri/tests/fail/validity/dangling_ref1.rs b/src/tools/miri/tests/fail/validity/dangling_ref1.rs index fc3a9f344638f..57ba1117e765e 100644 --- a/src/tools/miri/tests/fail/validity/dangling_ref1.rs +++ b/src/tools/miri/tests/fail/validity/dangling_ref1.rs @@ -1,5 +1,8 @@ // Make sure we catch this even without Stacked Borrows //@compile-flags: -Zmiri-disable-stacked-borrows + +#![allow(integer_to_ptr_transmutes)] + use std::mem; fn main() { diff --git a/src/tools/miri/tests/panic/transmute_fat2.rs b/src/tools/miri/tests/panic/transmute_fat2.rs index e695ff2d57ba5..7441f25d03ea7 100644 --- a/src/tools/miri/tests/panic/transmute_fat2.rs +++ b/src/tools/miri/tests/panic/transmute_fat2.rs @@ -1,3 +1,5 @@ +#![allow(integer_to_ptr_transmutes)] + fn main() { #[cfg(all(target_endian = "little", target_pointer_width = "64"))] let bad = unsafe { std::mem::transmute::(42) }; diff --git a/src/tools/miri/tests/pass/binops.rs b/src/tools/miri/tests/pass/binops.rs index 0aff7acb29d44..fcbe6c85b7b8f 100644 --- a/src/tools/miri/tests/pass/binops.rs +++ b/src/tools/miri/tests/pass/binops.rs @@ -32,6 +32,7 @@ fn test_bool() { assert_eq!(true ^ true, false); } +#[allow(integer_to_ptr_transmutes)] fn test_ptr() { unsafe { let p1: *const u8 = ::std::mem::transmute(0_usize); diff --git a/src/tools/miri/tests/pass/too-large-primval-write-problem.rs b/src/tools/miri/tests/pass/too-large-primval-write-problem.rs index f4c418bd78a99..00882b7ecca6e 100644 --- a/src/tools/miri/tests/pass/too-large-primval-write-problem.rs +++ b/src/tools/miri/tests/pass/too-large-primval-write-problem.rs @@ -7,6 +7,8 @@ // // This is just intended as a regression test to make sure we don't reintroduce this problem. +#![allow(integer_to_ptr_transmutes)] + #[cfg(target_pointer_width = "32")] fn main() { use std::mem::transmute; diff --git a/tests/ui/binop/binops.rs b/tests/ui/binop/binops.rs index 7142190a45b9a..702e9a61345b7 100644 --- a/tests/ui/binop/binops.rs +++ b/tests/ui/binop/binops.rs @@ -35,6 +35,7 @@ fn test_bool() { assert_eq!(true ^ true, false); } +#[allow(integer_to_ptr_transmutes)] fn test_ptr() { unsafe { let p1: *const u8 = ::std::mem::transmute(0_usize); diff --git a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr index 32fa46b92b306..299ae68009385 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr +++ b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr @@ -1,8 +1,8 @@ warning: hiding a lifetime that's named elsewhere is confusing - --> $DIR/issue-71348.rs:18:40 + --> $DIR/issue-71348.rs:18:56 | LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target - | ^^ -- ------------------------ the same lifetime is hidden here + | -- -- ^^^^^^^^^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | | | the same lifetime is named here | the lifetime is named here diff --git a/tests/ui/consts/ptr_comparisons.rs b/tests/ui/consts/ptr_comparisons.rs index e142ab3a754a4..0682184e5567c 100644 --- a/tests/ui/consts/ptr_comparisons.rs +++ b/tests/ui/consts/ptr_comparisons.rs @@ -1,43 +1,221 @@ //@ compile-flags: --crate-type=lib //@ check-pass +//@ edition: 2024 +#![feature(const_raw_ptr_comparison)] +#![feature(fn_align)] +// Generally: +// For any `Some` return, `None` would also be valid, unless otherwise noted. +// For any `None` return, only `None` is valid, unless otherwise noted. -#![feature( - core_intrinsics, - const_raw_ptr_comparison, -)] +macro_rules! do_test { + ($a:expr, $b:expr, $expected:pat) => { + const _: () = { + let a: *const _ = $a; + let b: *const _ = $b; + assert!(matches!(<*const u8>::guaranteed_eq(a.cast(), b.cast()), $expected)); + }; + }; +} -const FOO: &usize = &42; +#[repr(align(2))] +struct T(#[allow(unused)] u16); -macro_rules! check { - (eq, $a:expr, $b:expr) => { - pub const _: () = - assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 1); - }; - (ne, $a:expr, $b:expr) => { - pub const _: () = - assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 0); +#[repr(align(2))] +struct AlignedZst; + +static A: T = T(42); +static B: T = T(42); +static mut MUT_STATIC: T = T(42); +static ZST: () = (); +static ALIGNED_ZST: AlignedZst = AlignedZst; +static LARGE_WORD_ALIGNED: [usize; 2] = [0, 1]; +static mut MUT_LARGE_WORD_ALIGNED: [usize; 2] = [0, 1]; + +const FN_PTR: *const () = { + fn foo() {} + unsafe { std::mem::transmute(foo as fn()) } +}; + +const ALIGNED_FN_PTR: *const () = { + #[rustc_align(2)] + fn aligned_foo() {} + unsafe { std::mem::transmute(aligned_foo as fn()) } +}; + +// Only on armv5te-* and armv4t-* +#[cfg(all( + target_arch = "arm", + not(target_feature = "v6"), +))] +const ALIGNED_THUMB_FN_PTR: *const () = { + #[rustc_align(2)] + #[instruction_set(arm::t32)] + fn aligned_thumb_foo() {} + unsafe { std::mem::transmute(aligned_thumb_foo as fn()) } +}; + +trait Trait { + #[allow(unused)] + fn method(&self) -> u8; +} +impl Trait for u32 { + fn method(&self) -> u8 { 1 } +} +impl Trait for i32 { + fn method(&self) -> u8 { 2 } +} + +const VTABLE_PTR_1: *const () = { + let [_data, vtable] = unsafe { + std::mem::transmute::<&dyn Trait, [*const (); 2]>(&42_u32 as &dyn Trait) }; - (!, $a:expr, $b:expr) => { - pub const _: () = - assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 2); + vtable +}; +const VTABLE_PTR_2: *const () = { + let [_data, vtable] = unsafe { + std::mem::transmute::<&dyn Trait, [*const (); 2]>(&42_i32 as &dyn Trait) }; -} + vtable +}; -check!(eq, 0, 0); -check!(ne, 0, 1); -check!(ne, FOO as *const _, 0); -check!(ne, unsafe { (FOO as *const usize).offset(1) }, 0); -check!(ne, unsafe { (FOO as *const usize as *const u8).offset(3) }, 0); +// Cannot be `None`: `is_null` is stable with strong guarantees about integer-valued pointers. +do_test!(0 as *const u8, 0 as *const u8, Some(true)); +do_test!(0 as *const u8, 1 as *const u8, Some(false)); -// We want pointers to be equal to themselves, but aren't checking this yet because -// there are some open questions (e.g. whether function pointers to the same function -// compare equal: they don't necessarily do at runtime). -check!(!, FOO as *const _, FOO as *const _); +// Integer-valued pointers can always be compared. +do_test!(1 as *const u8, 1 as *const u8, Some(true)); +do_test!(1 as *const u8, 2 as *const u8, Some(false)); + +// Cannot be `None`: `static`s' addresses, references, (and within and one-past-the-end of those), +// and `fn` pointers cannot be null, and `is_null` is stable with strong guarantees, and +// `is_null` is implemented using `guaranteed_cmp`. +do_test!(&A, 0 as *const u8, Some(false)); +do_test!((&raw const A).cast::().wrapping_add(1), 0 as *const u8, Some(false)); +do_test!((&raw const A).wrapping_add(1), 0 as *const u8, Some(false)); +do_test!(&ZST, 0 as *const u8, Some(false)); +do_test!(&(), 0 as *const u8, Some(false)); +do_test!(const { &() }, 0 as *const u8, Some(false)); +do_test!(FN_PTR, 0 as *const u8, Some(false)); + +// This pointer is out-of-bounds, but still cannot be equal to 0 because of alignment. +do_test!((&raw const A).cast::().wrapping_add(size_of::() + 1), 0 as *const u8, Some(false)); // aside from 0, these pointers might end up pretty much anywhere. -check!(!, FOO as *const _, 1); // this one could be `ne` by taking into account alignment -check!(!, FOO as *const _, 1024); +do_test!(&A, align_of::() as *const u8, None); +do_test!((&raw const A).wrapping_byte_add(1), (align_of::() + 1) as *const u8, None); + +// except that they must still be aligned +do_test!(&A, 1 as *const u8, Some(false)); +do_test!((&raw const A).wrapping_byte_add(1), align_of::() as *const u8, Some(false)); + +// If `ptr.wrapping_sub(int)` cannot be null (because it is in-bounds or one-past-the-end of +// `ptr`'s allocation, or because it is misaligned from `ptr`'s allocation), then we know that +// `ptr != int`, even if `ptr` itself is out-of-bounds or one-past-the-end of its allocation. +do_test!((&raw const A).wrapping_byte_add(1), 1 as *const u8, Some(false)); +do_test!((&raw const A).wrapping_byte_add(2), 2 as *const u8, Some(false)); +do_test!((&raw const A).wrapping_byte_add(3), 1 as *const u8, Some(false)); +do_test!((&raw const ZST).wrapping_byte_add(1), 1 as *const u8, Some(false)); +do_test!(VTABLE_PTR_1.wrapping_byte_add(1), 1 as *const u8, Some(false)); +do_test!(FN_PTR.wrapping_byte_add(1), 1 as *const u8, Some(false)); +do_test!(&A, size_of::().wrapping_neg() as *const u8, Some(false)); +do_test!(&LARGE_WORD_ALIGNED, size_of::().wrapping_neg() as *const u8, Some(false)); +// (`ptr - int != 0` due to misalignment) +do_test!((&raw const A).wrapping_byte_add(2), 1 as *const u8, Some(false)); +do_test!((&raw const ALIGNED_ZST).wrapping_byte_add(2), 1 as *const u8, Some(false)); // When pointers go out-of-bounds, they *might* become null, so these comparions cannot work. -check!(!, unsafe { (FOO as *const usize).wrapping_add(2) }, 0); -check!(!, unsafe { (FOO as *const usize).wrapping_sub(1) }, 0); +do_test!((&raw const A).wrapping_add(2), 0 as *const u8, None); +do_test!((&raw const A).wrapping_sub(1), 0 as *const u8, None); + +// Statics cannot be duplicated +do_test!(&A, &A, Some(true)); + +// Two non-ZST statics cannot have the same address +do_test!(&A, &B, Some(false)); +do_test!(&A, &raw const MUT_STATIC, Some(false)); + +// One-past-the-end of one static can be equal to the address of another static. +do_test!(&A, (&raw const B).wrapping_add(1), None); + +// Cannot know if ZST static is at the same address with anything non-null (if alignment allows). +do_test!(&A, &ZST, None); +do_test!(&A, &ALIGNED_ZST, None); + +// Unclear if ZST statics can be placed "in the middle of" non-ZST statics. +// For now, we conservatively say they could, and return None here. +do_test!(&ZST, (&raw const A).wrapping_byte_add(1), None); + +// As per https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.storage-disjointness +// immutable statics are allowed to overlap with const items and promoteds. +do_test!(&A, &T(42), None); +do_test!(&A, const { &T(42) }, None); +do_test!(&A, { const X: T = T(42); &X }, None); + +// These could return Some(false), since only immutable statics can overlap with const items +// and promoteds. +do_test!(&raw const MUT_STATIC, &T(42), None); +do_test!(&raw const MUT_STATIC, const { &T(42) }, None); +do_test!(&raw const MUT_STATIC, { const X: T = T(42); &X }, None); + +// An odd offset from a 2-aligned allocation can never be equal to an even offset from a +// 2-aligned allocation, even if the offsets are out-of-bounds. +do_test!(&A, (&raw const B).wrapping_byte_add(1), Some(false)); +do_test!(&A, (&raw const B).wrapping_byte_add(5), Some(false)); +do_test!(&A, (&raw const ALIGNED_ZST).wrapping_byte_add(1), Some(false)); +do_test!(&ALIGNED_ZST, (&raw const A).wrapping_byte_add(1), Some(false)); +do_test!(&A, (&T(42) as *const T).wrapping_byte_add(1), Some(false)); +do_test!(&A, (const { &T(42) } as *const T).wrapping_byte_add(1), Some(false)); +do_test!(&A, ({ const X: T = T(42); &X } as *const T).wrapping_byte_add(1), Some(false)); + +// We could return `Some(false)` for these, as pointers to different statics can never be equal if +// that would require the statics to overlap, even if the pointers themselves are offset out of +// bounds or one-past-the-end. We currently only check strictly in-bounds pointers when comparing +// pointers to different statics, however. +do_test!((&raw const A).wrapping_add(1), (&raw const B).wrapping_add(1), None); +do_test!( + (&raw const LARGE_WORD_ALIGNED).cast::().wrapping_add(2), + (&raw const MUT_LARGE_WORD_ALIGNED).cast::().wrapping_add(1), + None +); + +// Pointers into the same static are equal if and only if their offset is the same, +// even if either is out-of-bounds. +do_test!(&A, &A, Some(true)); +do_test!(&A, &A.0, Some(true)); +do_test!(&A, (&raw const A).wrapping_byte_add(1), Some(false)); +do_test!(&A, (&raw const A).wrapping_byte_add(2), Some(false)); +do_test!(&A, (&raw const A).wrapping_byte_add(51), Some(false)); +do_test!((&raw const A).wrapping_byte_add(51), (&raw const A).wrapping_byte_add(51), Some(true)); + +// Pointers to the same fn may be unequal, since `fn`s can be duplicated. +do_test!(FN_PTR, FN_PTR, None); +do_test!(ALIGNED_FN_PTR, ALIGNED_FN_PTR, None); + +// Pointers to different fns may be equal, since `fn`s can be deduplicated. +do_test!(FN_PTR, ALIGNED_FN_PTR, None); + +// Pointers to the same vtable may be unequal, since vtables can be duplicated. +do_test!(VTABLE_PTR_1, VTABLE_PTR_1, None); + +// Pointers to different vtables may be equal, since vtables can be deduplicated. +do_test!(VTABLE_PTR_1, VTABLE_PTR_2, None); + +// Function pointers to aligned function allocations are not necessarily actually aligned, +// due to platform-specific semantics. +// See https://github.com/rust-lang/rust/issues/144661 +// FIXME: This could return `Some` on platforms where function pointers' addresses actually +// correspond to function addresses including alignment, or on ARM if t32 function pointers +// have their low bit set for consteval. +do_test!(ALIGNED_FN_PTR, ALIGNED_FN_PTR.wrapping_byte_offset(1), None); +#[cfg(all( + target_arch = "arm", + not(target_feature = "v6"), +))] +do_test!(ALIGNED_THUMB_FN_PTR, ALIGNED_THUMB_FN_PTR.wrapping_byte_offset(1), None); + +// Conservatively say we don't know. +do_test!(FN_PTR, VTABLE_PTR_1, None); +do_test!((&raw const LARGE_WORD_ALIGNED).cast::().wrapping_add(1), VTABLE_PTR_1, None); +do_test!((&raw const MUT_LARGE_WORD_ALIGNED).cast::().wrapping_add(1), VTABLE_PTR_1, None); +do_test!((&raw const LARGE_WORD_ALIGNED).cast::().wrapping_add(1), FN_PTR, None); +do_test!((&raw const MUT_LARGE_WORD_ALIGNED).cast::().wrapping_add(1), FN_PTR, None); diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr index 3651226e0c39d..7a9254bac608e 100644 --- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr +++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:31 + --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:82 | LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator { - | ^^ the lifetime is named here ---- the same lifetime is elided here + | -- the lifetime is named here ^^^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr index 5a7a5a6ebf95c..2b7d6a6da2751 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr @@ -1,8 +1,8 @@ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/example-from-issue48686.rs:6:21 + --> $DIR/example-from-issue48686.rs:6:50 | LL | pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { - | ^^^^^^^ ------- the same lifetime is elided here + | ------- ^^^^^^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr index af56a0a0ea5a4..c4d6e78d78729 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr @@ -1,8 +1,8 @@ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/missing-lifetime-kind.rs:3:22 + --> $DIR/missing-lifetime-kind.rs:3:32 | LL | fn ampersand<'a>(x: &'a u8) -> &u8 { - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -18,10 +18,10 @@ LL | fn ampersand<'a>(x: &'a u8) -> &'a u8 { | ++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/missing-lifetime-kind.rs:10:21 + --> $DIR/missing-lifetime-kind.rs:10:31 | LL | fn brackets<'a>(x: &'a u8) -> Brackets { - | ^^ -------- the same lifetime is hidden here + | -- ^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -32,10 +32,10 @@ LL | fn brackets<'a>(x: &'a u8) -> Brackets<'a> { | ++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/missing-lifetime-kind.rs:17:18 + --> $DIR/missing-lifetime-kind.rs:17:28 | LL | fn comma<'a>(x: &'a u8) -> Comma { - | ^^ --------- the same lifetime is hidden here + | -- ^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -46,10 +46,10 @@ LL | fn comma<'a>(x: &'a u8) -> Comma<'a, u8> { | +++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/missing-lifetime-kind.rs:22:23 + --> $DIR/missing-lifetime-kind.rs:22:34 | LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr index cf0a29678fada..28de809faab43 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/not-tied-to-crate.rs:8:16 + --> $DIR/not-tied-to-crate.rs:8:31 | LL | fn bar(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -18,10 +18,10 @@ LL | fn bar(x: &'static u8) -> &'static u8 { | +++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/not-tied-to-crate.rs:14:16 + --> $DIR/not-tied-to-crate.rs:14:31 | LL | fn baz(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr index d60bec6f7e492..5f21a2877a71b 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr @@ -1,8 +1,8 @@ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/static.rs:16:18 + --> $DIR/static.rs:16:33 | LL | fn ampersand(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -18,10 +18,10 @@ LL | fn ampersand(x: &'static u8) -> &'static u8 { | +++++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/static.rs:23:17 + --> $DIR/static.rs:23:32 | LL | fn brackets(x: &'static u8) -> Brackets { - | ^^^^^^^ -------- the same lifetime is hidden here + | ------- ^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -32,10 +32,10 @@ LL | fn brackets(x: &'static u8) -> Brackets<'static> { | +++++++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/static.rs:30:14 + --> $DIR/static.rs:30:29 | LL | fn comma(x: &'static u8) -> Comma { - | ^^^^^^^ --------- the same lifetime is hidden here + | ------- ^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -46,10 +46,10 @@ LL | fn comma(x: &'static u8) -> Comma<'static, u8> { | ++++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/static.rs:35:19 + --> $DIR/static.rs:35:35 | LL | fn underscore(x: &'static u8) -> &'_ u8 { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs index f6260c4720296..f404c4163a9fa 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs @@ -36,8 +36,8 @@ fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> Contains fn explicit_bound_path_to_explicit_anonymous_path<'a>( v: ContainsLifetime<'a>, - //~^ ERROR eliding a lifetime that's named elsewhere is confusing ) -> ContainsLifetime<'_> { + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } @@ -188,8 +188,8 @@ mod impl_trait { fn explicit_bound_path_to_impl_trait_precise_capture<'a>( v: ContainsLifetime<'a>, - //~^ ERROR eliding a lifetime that's named elsewhere is confusing ) -> impl FnOnce() + use<'_> { + //~^ ERROR eliding a lifetime that's named elsewhere is confusing move || _ = v } } @@ -208,8 +208,8 @@ mod dyn_trait { fn explicit_bound_path_to_dyn_trait_bound<'a>( v: ContainsLifetime<'a>, - //~^ ERROR hiding a lifetime that's named elsewhere is confusing ) -> Box + '_> { + //~^ ERROR hiding a lifetime that's named elsewhere is confusing Box::new(iter::once(v)) } } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr index 20b7561c594c5..89768fc764a41 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr @@ -1,8 +1,8 @@ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:10:47 + --> $DIR/mismatched-lifetime-syntaxes.rs:10:57 | LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 { - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -18,10 +18,10 @@ LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &'a u8 { | ++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:15:57 + --> $DIR/mismatched-lifetime-syntaxes.rs:15:68 | LL | fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -36,7 +36,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:22:48 | LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> { - | ^^^^^^^^^^^^^^^^ -- the same lifetime is elided here + | ^^^^^^^^^^^^^^^^ ^^ the same lifetime is elided here | | | the lifetime is hidden here | @@ -50,7 +50,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:27:65 | LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | ^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -61,10 +61,10 @@ LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> Con | ++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:32:65 + --> $DIR/mismatched-lifetime-syntaxes.rs:32:73 | LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | -- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -75,13 +75,12 @@ LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> Con | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:38:25 + --> $DIR/mismatched-lifetime-syntaxes.rs:39:23 | LL | v: ContainsLifetime<'a>, - | ^^ the lifetime is named here -LL | + | -- the lifetime is named here LL | ) -> ContainsLifetime<'_> { - | -- the same lifetime is elided here + | ^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -94,7 +93,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:46:37 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - | ^^^ ---------------- the same lifetime is hidden here + | ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -108,7 +107,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:51:48 | LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | ^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -119,10 +118,10 @@ LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime<' | ++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:56:48 + --> $DIR/mismatched-lifetime-syntaxes.rs:56:58 | LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | -- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -133,10 +132,10 @@ LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime<' | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:61:58 + --> $DIR/mismatched-lifetime-syntaxes.rs:61:85 | LL | fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -151,7 +150,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:68:37 | LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 { - | ^^^^^^^^^^^^^^^^ --- the same lifetime is elided here + | ^^^^^^^^^^^^^^^^ ^^^ the same lifetime is elided here | | | the lifetime is hidden here | @@ -165,7 +164,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:73:47 | LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { - | ^^^^^^^^^^^^^^^^ -- the same lifetime is elided here + | ^^^^^^^^^^^^^^^^ ^^ the same lifetime is elided here | | | the lifetime is hidden here | @@ -176,10 +175,10 @@ LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &'_ | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:78:64 + --> $DIR/mismatched-lifetime-syntaxes.rs:78:72 | LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 { - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -190,10 +189,10 @@ LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &'a | ++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:83:74 + --> $DIR/mismatched-lifetime-syntaxes.rs:83:83 | LL | fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -205,10 +204,10 @@ LL + fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:89:55 + --> $DIR/mismatched-lifetime-syntaxes.rs:89:67 | LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 { - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -219,10 +218,10 @@ LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &'a u8 { | ++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:94:65 + --> $DIR/mismatched-lifetime-syntaxes.rs:94:78 | LL | fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -237,7 +236,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:101:56 | LL | fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | ^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -248,10 +247,10 @@ LL | fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> Contains | ++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:106:56 + --> $DIR/mismatched-lifetime-syntaxes.rs:106:68 | LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | -- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -262,10 +261,10 @@ LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> Contains | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:111:66 + --> $DIR/mismatched-lifetime-syntaxes.rs:111:95 | LL | fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -277,10 +276,10 @@ LL + fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) - | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:126:39 + --> $DIR/mismatched-lifetime-syntaxes.rs:126:54 | LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -291,10 +290,10 @@ LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &'static u8 { | +++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:131:49 + --> $DIR/mismatched-lifetime-syntaxes.rs:131:65 | LL | fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -306,10 +305,10 @@ LL + fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'static u8 | error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:136:40 + --> $DIR/mismatched-lifetime-syntaxes.rs:136:55 | LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime { - | ^^^^^^^ ---------------- the same lifetime is hidden here + | ------- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -320,10 +319,10 @@ LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime<'sta | +++++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:141:50 + --> $DIR/mismatched-lifetime-syntaxes.rs:141:82 | LL | fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -335,10 +334,10 @@ LL + fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLif | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:147:40 + --> $DIR/mismatched-lifetime-syntaxes.rs:147:57 | LL | fn static_ref_to_implicit_ref(&'static self) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -349,10 +348,10 @@ LL | fn static_ref_to_implicit_ref(&'static self) -> &'static u8 { | +++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:152:50 + --> $DIR/mismatched-lifetime-syntaxes.rs:152:68 | LL | fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -364,10 +363,10 @@ LL + fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'static | error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:157:41 + --> $DIR/mismatched-lifetime-syntaxes.rs:157:58 | LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime { - | ^^^^^^^ ---------------- the same lifetime is hidden here + | ------- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -378,10 +377,10 @@ LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime<' | +++++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:162:51 + --> $DIR/mismatched-lifetime-syntaxes.rs:162:85 | LL | fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -393,10 +392,10 @@ LL + fn static_ref_to_explicit_anonymous_path(&'static self) -> Contains | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:174:55 + --> $DIR/mismatched-lifetime-syntaxes.rs:174:81 | LL | fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -408,10 +407,10 @@ LL + fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:179:65 + --> $DIR/mismatched-lifetime-syntaxes.rs:179:95 | LL | fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { - | ^^ the lifetime is named here -- the same lifetime is elided here + | -- the lifetime is named here ^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -421,10 +420,10 @@ LL + fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> i | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:184:72 + --> $DIR/mismatched-lifetime-syntaxes.rs:184:96 | LL | fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -436,13 +435,12 @@ LL + fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:190:29 + --> $DIR/mismatched-lifetime-syntaxes.rs:191:30 | LL | v: ContainsLifetime<'a>, - | ^^ the lifetime is named here -LL | + | -- the lifetime is named here LL | ) -> impl FnOnce() + use<'_> { - | -- the same lifetime is elided here + | ^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -452,10 +450,10 @@ LL + ) -> impl FnOnce() + use<'a> { | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:204:54 + --> $DIR/mismatched-lifetime-syntaxes.rs:204:88 | LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box + '_> { - | ^^ the lifetime is named here --- the same lifetime is elided here + | -- the lifetime is named here ^^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -464,13 +462,12 @@ LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box $DIR/mismatched-lifetime-syntaxes.rs:210:29 + --> $DIR/mismatched-lifetime-syntaxes.rs:211:34 | LL | v: ContainsLifetime<'a>, - | ^^ the lifetime is named here -LL | + | -- the lifetime is named here LL | ) -> Box + '_> { - | ---------------- the same lifetime is hidden here + | ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -479,10 +476,10 @@ LL | ) -> Box> + '_> { | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:222:33 + --> $DIR/mismatched-lifetime-syntaxes.rs:222:52 | LL | fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 { - | ^^ ^^ --- the same lifetime is elided here + | -- -- ^^^ the same lifetime is elided here | | | | | the lifetime is named here | the lifetime is named here @@ -494,10 +491,10 @@ LL | fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &'a u8 { | ++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:227:33 + --> $DIR/mismatched-lifetime-syntaxes.rs:227:44 | LL | fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { - | ^^ --- --- the same lifetime is elided here + | -- ^^^ ^^^ the same lifetime is elided here | | | | | the same lifetime is elided here | the lifetime is named here @@ -509,10 +506,10 @@ LL | fn multiple_outputs<'a>(v: &'a u8) -> (&'a u8, &'a u8) { | ++ ++ error: hiding or eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:232:53 + --> $DIR/mismatched-lifetime-syntaxes.rs:232:62 | LL | fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) { - | ^^ --- ---------------- the same lifetime is hidden here + | -- ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | | | the same lifetime is elided here | the lifetime is named here @@ -524,10 +521,10 @@ LL | fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&'a u8, Contai | ++ ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:237:38 + --> $DIR/mismatched-lifetime-syntaxes.rs:237:49 | LL | fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) { - | ^^ --- -- -- the same lifetime is named here + | -- ^^^ -- -- the same lifetime is named here | | | | | | | the same lifetime is named here | | the same lifetime is elided here @@ -543,7 +540,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:250:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - | ^^^ ---------------- the same lifetime is hidden here + | ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -557,7 +554,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:253:49 | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime; - | ^^^^^ ---------------- the same lifetime is hidden here + | ^^^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -571,7 +568,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:258:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - | ^^^ ---------------- the same lifetime is hidden here + | ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -585,7 +582,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:263:49 | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime { - | ^^^^^ ---------------- the same lifetime is hidden here + | ^^^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -599,7 +596,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:277:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - | ^^^ ---------------- the same lifetime is hidden here + | ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | diff --git a/tests/ui/lint/int_to_ptr.fixed b/tests/ui/lint/int_to_ptr.fixed new file mode 100644 index 0000000000000..8f373492e6fb8 --- /dev/null +++ b/tests/ui/lint/int_to_ptr.fixed @@ -0,0 +1,47 @@ +// Checks for the `integer_to_pointer_transmutes` lint + +//@ check-pass +//@ run-rustfix + +#![allow(unused_unsafe)] +#![allow(dead_code)] + +unsafe fn should_lint(a: usize) { + let _ptr: *const u8 = unsafe { std::ptr::with_exposed_provenance::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr: *mut u8 = unsafe { std::ptr::with_exposed_provenance_mut::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static u8 = unsafe { &*std::ptr::with_exposed_provenance::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static mut u8 = unsafe { &mut *std::ptr::with_exposed_provenance_mut::(a) }; + //~^ WARN transmuting an integer to a pointer + + let _ptr = unsafe { std::ptr::with_exposed_provenance::(42usize) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::ptr::with_exposed_provenance::(a + a) }; + //~^ WARN transmuting an integer to a pointer +} + +const unsafe fn should_lintin_const(a: usize) { + let _ptr: *const u8 = unsafe { std::ptr::with_exposed_provenance::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr: *mut u8 = unsafe { std::ptr::with_exposed_provenance_mut::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static u8 = unsafe { &*std::ptr::with_exposed_provenance::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static mut u8 = unsafe { &mut *std::ptr::with_exposed_provenance_mut::(a) }; + //~^ WARN transmuting an integer to a pointer + + let _ptr = unsafe { std::ptr::with_exposed_provenance::(42usize) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::ptr::with_exposed_provenance::(a + a) }; + //~^ WARN transmuting an integer to a pointer +} + +unsafe fn should_not_lint(a: usize) { + let _ptr = unsafe { std::mem::transmute::(0usize) }; // linted by other lints + let _ptr = unsafe { std::mem::transmute::(a) }; // inner type is a ZST + let _ptr = unsafe { std::mem::transmute::(a) }; // omit fn-ptr for now +} + +fn main() {} diff --git a/tests/ui/lint/int_to_ptr.rs b/tests/ui/lint/int_to_ptr.rs new file mode 100644 index 0000000000000..7f60da47b85d8 --- /dev/null +++ b/tests/ui/lint/int_to_ptr.rs @@ -0,0 +1,47 @@ +// Checks for the `integer_to_pointer_transmutes` lint + +//@ check-pass +//@ run-rustfix + +#![allow(unused_unsafe)] +#![allow(dead_code)] + +unsafe fn should_lint(a: usize) { + let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + + let _ptr = unsafe { std::mem::transmute::(42usize) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::mem::transmute::(a + a) }; + //~^ WARN transmuting an integer to a pointer +} + +const unsafe fn should_lintin_const(a: usize) { + let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + + let _ptr = unsafe { std::mem::transmute::(42usize) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::mem::transmute::(a + a) }; + //~^ WARN transmuting an integer to a pointer +} + +unsafe fn should_not_lint(a: usize) { + let _ptr = unsafe { std::mem::transmute::(0usize) }; // linted by other lints + let _ptr = unsafe { std::mem::transmute::(a) }; // inner type is a ZST + let _ptr = unsafe { std::mem::transmute::(a) }; // omit fn-ptr for now +} + +fn main() {} diff --git a/tests/ui/lint/int_to_ptr.stderr b/tests/ui/lint/int_to_ptr.stderr new file mode 100644 index 0000000000000..4035bda8fb2cf --- /dev/null +++ b/tests/ui/lint/int_to_ptr.stderr @@ -0,0 +1,207 @@ +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:10:36 + | +LL | let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see + = note: `#[warn(integer_to_ptr_transmutes)]` on by default +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ptr: *const u8 = unsafe { std::ptr::with_exposed_provenance::(a) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:12:34 + | +LL | let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance_mut` instead to use a previously exposed provenance + | +LL - let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ptr: *mut u8 = unsafe { std::ptr::with_exposed_provenance_mut::(a) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:14:38 + | +LL | let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ref: &'static u8 = unsafe { &*std::ptr::with_exposed_provenance::(a) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:16:42 + | +LL | let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance_mut` instead to use a previously exposed provenance + | +LL - let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ref: &'static mut u8 = unsafe { &mut *std::ptr::with_exposed_provenance_mut::(a) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:19:25 + | +LL | let _ptr = unsafe { std::mem::transmute::(42usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(42usize) }; +LL + let _ptr = unsafe { std::ptr::with_exposed_provenance::(42usize) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:21:25 + | +LL | let _ptr = unsafe { std::mem::transmute::(a + a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(a + a) }; +LL + let _ptr = unsafe { std::ptr::with_exposed_provenance::(a + a) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:26:36 + | +LL | let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ptr: *const u8 = unsafe { std::ptr::with_exposed_provenance::(a) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:28:34 + | +LL | let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance_mut` instead to use a previously exposed provenance + | +LL - let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ptr: *mut u8 = unsafe { std::ptr::with_exposed_provenance_mut::(a) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:30:38 + | +LL | let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ref: &'static u8 = unsafe { &*std::ptr::with_exposed_provenance::(a) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:32:42 + | +LL | let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance_mut` instead to use a previously exposed provenance + | +LL - let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ref: &'static mut u8 = unsafe { &mut *std::ptr::with_exposed_provenance_mut::(a) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:35:25 + | +LL | let _ptr = unsafe { std::mem::transmute::(42usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(42usize) }; +LL + let _ptr = unsafe { std::ptr::with_exposed_provenance::(42usize) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:37:25 + | +LL | let _ptr = unsafe { std::mem::transmute::(a + a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(a + a) }; +LL + let _ptr = unsafe { std::ptr::with_exposed_provenance::(a + a) }; + | + +warning: 12 warnings emitted + diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr index 7108fa1a2908b..1a5c87114d476 100644 --- a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr +++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/ignore-non-reference-lifetimes.rs:6:30 + --> $DIR/ignore-non-reference-lifetimes.rs:6:41 | LL | fn a<'a>(self: Self, a: &'a str) -> &str { - | ^^ ---- the same lifetime is elided here + | -- ^^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -14,10 +14,10 @@ LL | fn a<'a>(self: Self, a: &'a str) -> &'a str { | ++ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/ignore-non-reference-lifetimes.rs:10:33 + --> $DIR/ignore-non-reference-lifetimes.rs:10:44 | LL | fn b<'a>(self: Foo<'b>, a: &'a str) -> &str { - | ^^ ---- the same lifetime is elided here + | -- ^^^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/self/self_lifetime-async.stderr b/tests/ui/self/self_lifetime-async.stderr index 43dc96abdc2ed..78cc610fd0436 100644 --- a/tests/ui/self/self_lifetime-async.stderr +++ b/tests/ui/self/self_lifetime-async.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/self_lifetime-async.rs:6:29 + --> $DIR/self_lifetime-async.rs:6:44 | LL | async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -14,10 +14,10 @@ LL | async fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } | ++ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/self_lifetime-async.rs:12:42 + --> $DIR/self_lifetime-async.rs:12:52 | LL | async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/self/self_lifetime.stderr b/tests/ui/self/self_lifetime.stderr index 4f9b2fcd2ad05..84f6345463306 100644 --- a/tests/ui/self/self_lifetime.stderr +++ b/tests/ui/self/self_lifetime.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/self_lifetime.rs:7:23 + --> $DIR/self_lifetime.rs:7:38 | LL | fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -14,10 +14,10 @@ LL | fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } | ++ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/self_lifetime.rs:13:36 + --> $DIR/self_lifetime.rs:13:46 | LL | fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here |