| author | bors <bors@rust-lang.org> 2026-06-28 11:10:25 UTC |
| committer | bors <bors@rust-lang.org> 2026-06-28 11:10:25 UTC |
| log | b4486cacf58926f02e451d96e71e20882faf5453 |
| tree | 0c1b4dadca2ec3ba45c683cc93a71d69c97f30a9 |
| parent | 11823209557bba4f6acb520109c63aa78c041683 |
| parent | 3d31306f1dc081eeaf46e7890e84274963869305 |
Merge and reframe strict_provenance_lints
There does not seem to be any good reason to have separate lints for ptr2int and int2ptr casts. The main reason to enable this lint is to help with replacing `as` casts with strict provenance APIs (if possible) or explicit provenance APIs (when needed). That applies equally to both directions.
Merging the lints requires coming up with new name and lint explanation. This is a good chance to reconsider the purpose and messaging of the lints which have been essentially unchanged since the early days of the "strict provenance experiment". For reasons described below, I called the merged lint `implicit_provenance_casts`, rewrote its explanation from scratch, and made some changes to diagnostics.
First, the lint is not (only) about strict provenance any more. While strict provenance is often the best fix, migrating `as` casts to exposed provenance APIs also silences the lint. The exposed provenance APIs aren't any better for Miri and CHERI, but at least provenance considerations are made *explicit*, not picked up as side effect of the `as` keyword. (Banning use of exposed provenance APIs can be done with clippy's existing `disallowed_methods` lint.)
Second, provenance is now officially part of the language and prominently explained in the `std::ptr` documentation. The new lint refers to those docs and is more consistent with them.
Third, while strict provenance is encouraged whenever possible, exposed provenance is also part of the language and here to stay. Indeed, if we eventually enable the lint by default and make it `cargo fix`-able to keep the ecosystem migration manageable, we may want to suggest exposed provenance APIs to err on the side of not introducing UB. Thus, I made the diagnostics more neutral and descriptive. I've kept the suggestions that introduce strict provenance APIs, but we may want to reconsider this later.
Tracking issue: rust-lang/rust#13035128 files changed, 253 insertions(+), 291 deletions(-)
compiler/rustc_lint/src/fuzzy_provenance_casts.rs deleted-79| ... | ... | @@ -1,79 +0,0 @@ |
| 1 | use rustc_hir as hir; | |
| 2 | use rustc_session::{declare_lint, declare_lint_pass}; | |
| 3 | ||
| 4 | use crate::lints::{LossyProvenanceInt2Ptr, LossyProvenanceInt2PtrSuggestion}; | |
| 5 | use crate::{LateContext, LateLintPass}; | |
| 6 | ||
| 7 | declare_lint! { | |
| 8 | /// The `fuzzy_provenance_casts` lint detects an `as` cast between an integer | |
| 9 | /// and a pointer. | |
| 10 | /// | |
| 11 | /// ### Example | |
| 12 | /// | |
| 13 | /// ```rust | |
| 14 | /// #![feature(strict_provenance_lints)] | |
| 15 | /// #![warn(fuzzy_provenance_casts)] | |
| 16 | /// | |
| 17 | /// fn main() { | |
| 18 | /// let _dangling = 16_usize as *const u8; | |
| 19 | /// } | |
| 20 | /// ``` | |
| 21 | /// | |
| 22 | /// {{produces}} | |
| 23 | /// | |
| 24 | /// ### Explanation | |
| 25 | /// | |
| 26 | /// This lint is part of the strict provenance effort, see [issue #95228]. | |
| 27 | /// Casting an integer to a pointer is considered bad style, as a pointer | |
| 28 | /// contains, besides the *address* also a *provenance*, indicating what | |
| 29 | /// memory the pointer is allowed to read/write. Casting an integer, which | |
| 30 | /// doesn't have provenance, to a pointer requires the compiler to assign | |
| 31 | /// (guess) provenance. The compiler assigns "all exposed valid" (see the | |
| 32 | /// docs of [`ptr::with_exposed_provenance`] for more information about this | |
| 33 | /// "exposing"). This penalizes the optimiser and is not well suited for | |
| 34 | /// dynamic analysis/dynamic program verification (e.g. Miri or CHERI | |
| 35 | /// platforms). | |
| 36 | /// | |
| 37 | /// It is much better to use [`ptr::with_addr`] instead to specify the | |
| 38 | /// provenance you want. If using this function is not possible because the | |
| 39 | /// code relies on exposed provenance then there is as an escape hatch | |
| 40 | /// [`ptr::with_exposed_provenance`]. | |
| 41 | /// | |
| 42 | /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228 | |
| 43 | /// [`ptr::with_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.with_addr | |
| 44 | /// [`ptr::with_exposed_provenance`]: https://doc.rust-lang.org/core/ptr/fn.with_exposed_provenance.html | |
| 45 | pub FUZZY_PROVENANCE_CASTS, | |
| 46 | Allow, | |
| 47 | "a fuzzy integer to pointer cast is used", | |
| 48 | @feature_gate = strict_provenance_lints; | |
| 49 | } | |
| 50 | ||
| 51 | declare_lint_pass!( | |
| 52 | /// Lint for `as` casts between an integer and a pointer. | |
| 53 | FuzzyProvenanceCasts => [FUZZY_PROVENANCE_CASTS] | |
| 54 | ); | |
| 55 | ||
| 56 | impl<'tcx> LateLintPass<'tcx> for FuzzyProvenanceCasts { | |
| 57 | fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { | |
| 58 | let hir::ExprKind::Cast(cast_from_expr, cast_to_hir) = expr.kind else { return }; | |
| 59 | ||
| 60 | let typeck_results = cx.typeck_results(); | |
| 61 | // Only lint casts from integer to pointer | |
| 62 | let cast_from_ty = typeck_results.expr_ty(cast_from_expr); | |
| 63 | if !cast_from_ty.is_integral() { | |
| 64 | return; | |
| 65 | } | |
| 66 | let cast_to_ty = typeck_results.expr_ty(expr); | |
| 67 | if !cast_to_ty.is_raw_ptr() { | |
| 68 | return; | |
| 69 | } | |
| 70 | ||
| 71 | let sugg = | |
| 72 | expr.span.can_be_used_for_suggestions().then(|| LossyProvenanceInt2PtrSuggestion { | |
| 73 | lo: cast_from_expr.span.shrink_to_lo(), | |
| 74 | hi: cast_from_expr.span.shrink_to_hi().to(cast_to_hir.span), | |
| 75 | }); | |
| 76 | let lint = LossyProvenanceInt2Ptr { expr_ty: cast_from_ty, cast_ty: cast_to_ty, sugg }; | |
| 77 | cx.tcx.emit_node_span_lint(FUZZY_PROVENANCE_CASTS, expr.hir_id, expr.span, lint) | |
| 78 | } | |
| 79 | } |
compiler/rustc_lint/src/implicit_provenance_casts.rs created+122| ... | ... | @@ -0,0 +1,122 @@ |
| 1 | use rustc_ast::util::parser::ExprPrecedence; | |
| 2 | use rustc_hir as hir; | |
| 3 | use rustc_middle::ty::Ty; | |
| 4 | use rustc_session::{declare_lint, declare_lint_pass}; | |
| 5 | ||
| 6 | use crate::lints::{ | |
| 7 | ImplicitProvenanceCastsInt2Ptr, ImplicitProvenanceCastsPtr2Int, Int2PtrSuggestion, | |
| 8 | Ptr2IntSuggestion, | |
| 9 | }; | |
| 10 | use crate::{LateContext, LateLintPass}; | |
| 11 | ||
| 12 | declare_lint! { | |
| 13 | /// The `implicit_provenance_casts` lint detects integer-to-pointer and pointer-to-integer | |
| 14 | /// casts. | |
| 15 | /// | |
| 16 | /// ### Example | |
| 17 | /// | |
| 18 | /// ```rust | |
| 19 | /// #![feature(strict_provenance_lints)] | |
| 20 | /// #![warn(implicit_provenance_casts)] | |
| 21 | /// | |
| 22 | /// fn main() { | |
| 23 | /// let x: u8 = 37; | |
| 24 | /// let addr: usize = &x as *const u8 as usize; | |
| 25 | /// let _ptr = addr as *const u8; | |
| 26 | /// } | |
| 27 | /// ``` | |
| 28 | /// | |
| 29 | /// {{produces}} | |
| 30 | /// | |
| 31 | /// ### Explanation | |
| 32 | /// | |
| 33 | /// This lint exists to help migrate code to [*Strict Provenance* APIs][strict-provenance] where | |
| 34 | /// possible, and make remaining uses of [*Exposed Provenance*][exposed-provenance] explicit. | |
| 35 | /// For more information on pointer provenance, see the [`std::ptr` documentation][provenance]. | |
| 36 | /// | |
| 37 | /// Earlier versions of Rust did not have a clear answer how integer-to-pointer and | |
| 38 | /// pointer-to-integer casts interact with provenance. Such casts are now defined to use the | |
| 39 | /// exposed provenance model, but in many cases the code can be updated to strict provenance | |
| 40 | /// APIs, which is preferable as it enables more precise reasoning about unsafe code, both by | |
| 41 | /// humans and by tools like [Miri]. | |
| 42 | /// | |
| 43 | /// However, there are situations where exposed provenance is required or following the strict | |
| 44 | /// provenance model requires major refactorings. In those cases, it's still useful to replace | |
| 45 | /// the `as` casts with equivalent explicit use of exposed provenance APIs and a comment | |
| 46 | /// explaining why they are needed. | |
| 47 | /// | |
| 48 | /// [provenance]: https://doc.rust-lang.org/core/ptr/index.html#provenance | |
| 49 | /// [strict-provenance]: https://doc.rust-lang.org/core/ptr/index.html#strict-provenance | |
| 50 | /// [exposed-provenance]: https://doc.rust-lang.org/core/ptr/index.html#exposed-provenance | |
| 51 | /// [Miri]: https://github.com/rust-lang/miri | |
| 52 | pub IMPLICIT_PROVENANCE_CASTS, | |
| 53 | Allow, | |
| 54 | "an `as` cast relying on exposed provenance is used", | |
| 55 | @feature_gate = strict_provenance_lints; | |
| 56 | } | |
| 57 | ||
| 58 | declare_lint_pass!( | |
| 59 | /// Lint for int2ptr and ptr2int `as` casts. | |
| 60 | ImplicitProvenanceCasts => [IMPLICIT_PROVENANCE_CASTS] | |
| 61 | ); | |
| 62 | ||
| 63 | impl<'tcx> LateLintPass<'tcx> for ImplicitProvenanceCasts { | |
| 64 | fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { | |
| 65 | let hir::ExprKind::Cast(cast_from_expr, cast_to_hir) = expr.kind else { return }; | |
| 66 | ||
| 67 | let typeck_results = cx.typeck_results(); | |
| 68 | let cast_from_ty = typeck_results.expr_ty(cast_from_expr); | |
| 69 | if cast_from_ty.is_raw_ptr() { | |
| 70 | let cast_to_ty = typeck_results.expr_ty(expr); | |
| 71 | if cast_to_ty.is_integral() { | |
| 72 | lint_ptr2int(cx, expr, cast_from_expr, cast_from_ty, cast_to_hir, cast_to_ty) | |
| 73 | } | |
| 74 | } else if cast_from_ty.is_integral() { | |
| 75 | let cast_to_ty = typeck_results.expr_ty(expr); | |
| 76 | if cast_to_ty.is_raw_ptr() { | |
| 77 | lint_int2ptr(cx, expr, cast_from_expr, cast_from_ty, cast_to_hir, cast_to_ty) | |
| 78 | } | |
| 79 | } | |
| 80 | } | |
| 81 | } | |
| 82 | ||
| 83 | fn lint_ptr2int<'tcx>( | |
| 84 | cx: &LateContext<'tcx>, | |
| 85 | expr: &'tcx hir::Expr<'tcx>, | |
| 86 | cast_from_expr: &'tcx hir::Expr<'tcx>, | |
| 87 | cast_from_ty: Ty<'tcx>, | |
| 88 | cast_to_hir: &'tcx hir::Ty<'tcx>, | |
| 89 | cast_to_ty: Ty<'tcx>, | |
| 90 | ) { | |
| 91 | let sugg = expr.span.can_be_used_for_suggestions().then(|| { | |
| 92 | let needs_parens = cx.precedence(cast_from_expr) < ExprPrecedence::Unambiguous; | |
| 93 | let needs_cast = !cast_to_ty.is_usize(); | |
| 94 | let cast_span = cast_from_expr.span.shrink_to_hi().to(cast_to_hir.span); | |
| 95 | let expr_span = cast_from_expr.span.shrink_to_lo(); | |
| 96 | match (needs_parens, needs_cast) { | |
| 97 | (true, true) => Ptr2IntSuggestion::NeedsParensCast { expr_span, cast_span, cast_to_ty }, | |
| 98 | (true, false) => Ptr2IntSuggestion::NeedsParens { expr_span, cast_span }, | |
| 99 | (false, true) => Ptr2IntSuggestion::NeedsCast { cast_span, cast_to_ty }, | |
| 100 | (false, false) => Ptr2IntSuggestion::Other { cast_span }, | |
| 101 | } | |
| 102 | }); | |
| 103 | ||
| 104 | let lint = ImplicitProvenanceCastsPtr2Int { cast_from_ty, cast_to_ty, sugg }; | |
| 105 | cx.tcx.emit_node_span_lint(IMPLICIT_PROVENANCE_CASTS, expr.hir_id, expr.span, lint); | |
| 106 | } | |
| 107 | ||
| 108 | fn lint_int2ptr<'tcx>( | |
| 109 | cx: &LateContext<'tcx>, | |
| 110 | expr: &'tcx hir::Expr<'tcx>, | |
| 111 | cast_from_expr: &'tcx hir::Expr<'tcx>, | |
| 112 | cast_from_ty: Ty<'tcx>, | |
| 113 | cast_to_hir: &'tcx hir::Ty<'tcx>, | |
| 114 | cast_to_ty: Ty<'tcx>, | |
| 115 | ) { | |
| 116 | let sugg = expr.span.can_be_used_for_suggestions().then(|| Int2PtrSuggestion { | |
| 117 | lo: cast_from_expr.span.shrink_to_lo(), | |
| 118 | hi: cast_from_expr.span.shrink_to_hi().to(cast_to_hir.span), | |
| 119 | }); | |
| 120 | let lint = ImplicitProvenanceCastsInt2Ptr { expr_ty: cast_from_ty, cast_ty: cast_to_ty, sugg }; | |
| 121 | cx.tcx.emit_node_span_lint(IMPLICIT_PROVENANCE_CASTS, expr.hir_id, expr.span, lint) | |
| 122 | } |
compiler/rustc_lint/src/lib.rs+5-6| ... | ... | @@ -45,10 +45,10 @@ mod expect; |
| 45 | 45 | mod for_loops_over_fallibles; |
| 46 | 46 | mod foreign_modules; |
| 47 | 47 | mod function_cast_as_integer; |
| 48 | mod fuzzy_provenance_casts; | |
| 49 | 48 | mod gpukernel_abi; |
| 50 | 49 | mod if_let_rescope; |
| 51 | 50 | mod impl_trait_overcaptures; |
| 51 | mod implicit_provenance_casts; | |
| 52 | 52 | mod interior_mutable_consts; |
| 53 | 53 | mod internal; |
| 54 | 54 | mod invalid_from_utf8; |
| ... | ... | @@ -57,7 +57,6 @@ mod let_underscore; |
| 57 | 57 | mod levels; |
| 58 | 58 | pub mod lifetime_syntax; |
| 59 | 59 | mod lints; |
| 60 | mod lossy_provenance_casts; | |
| 61 | 60 | mod macro_expr_fragment_specifier_2024_migration; |
| 62 | 61 | mod map_unit_fn; |
| 63 | 62 | mod multiple_supertrait_upcastable; |
| ... | ... | @@ -95,16 +94,15 @@ use drop_forget_useless::*; |
| 95 | 94 | use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; |
| 96 | 95 | use for_loops_over_fallibles::*; |
| 97 | 96 | use function_cast_as_integer::*; |
| 98 | use fuzzy_provenance_casts::FuzzyProvenanceCasts; | |
| 99 | 97 | use gpukernel_abi::*; |
| 100 | 98 | use if_let_rescope::IfLetRescope; |
| 101 | 99 | use impl_trait_overcaptures::ImplTraitOvercaptures; |
| 100 | use implicit_provenance_casts::ImplicitProvenanceCasts; | |
| 102 | 101 | use interior_mutable_consts::*; |
| 103 | 102 | use internal::*; |
| 104 | 103 | use invalid_from_utf8::*; |
| 105 | 104 | use let_underscore::*; |
| 106 | 105 | use lifetime_syntax::*; |
| 107 | use lossy_provenance_casts::LossyProvenanceCasts; | |
| 108 | 106 | use macro_expr_fragment_specifier_2024_migration::*; |
| 109 | 107 | use map_unit_fn::*; |
| 110 | 108 | use multiple_supertrait_upcastable::*; |
| ... | ... | @@ -270,8 +268,7 @@ late_lint_methods!( |
| 270 | 268 | CheckTransmutes: CheckTransmutes, |
| 271 | 269 | LifetimeSyntax: LifetimeSyntax, |
| 272 | 270 | InternalEqTraitMethodImpls: InternalEqTraitMethodImpls, |
| 273 | FuzzyProvenanceCasts: FuzzyProvenanceCasts, | |
| 274 | LossyProvenanceCasts: LossyProvenanceCasts, | |
| 271 | ImplicitProvenanceCasts: ImplicitProvenanceCasts, | |
| 275 | 272 | ] |
| 276 | 273 | ] |
| 277 | 274 | ); |
| ... | ... | @@ -410,6 +407,8 @@ fn register_builtins(store: &mut LintStore) { |
| 410 | 407 | store.register_renamed("static_mut_ref", "static_mut_refs"); |
| 411 | 408 | store.register_renamed("temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"); |
| 412 | 409 | store.register_renamed("elided_named_lifetimes", "mismatched_lifetime_syntaxes"); |
| 410 | store.register_renamed("fuzzy_provenance_casts", "implicit_provenance_casts"); | |
| 411 | store.register_renamed("lossy_provenance_casts", "implicit_provenance_casts"); | |
| 413 | 412 | |
| 414 | 413 | // These were moved to tool lints, but rustc still sees them when compiling normally, before |
| 415 | 414 | // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use |
compiler/rustc_lint/src/lints.rs+13-15| ... | ... | @@ -2934,23 +2934,24 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { |
| 2934 | 2934 | pub(crate) struct EqInternalMethodImplemented; |
| 2935 | 2935 | |
| 2936 | 2936 | #[derive(Diagnostic)] |
| 2937 | #[diag("strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`")] | |
| 2937 | #[diag("cast from `{$expr_ty}` to `{$cast_ty}` implicitly relies on exposed provenance")] | |
| 2938 | 2938 | #[help( |
| 2939 | "if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::with_exposed_provenance()` instead" | |
| 2939 | "if conforming to strict provenance is not possible, use `std::ptr::with_exposed_provenance()`" | |
| 2940 | 2940 | )] |
| 2941 | pub(crate) struct LossyProvenanceInt2Ptr<'tcx> { | |
| 2941 | #[note("for more information, visit <https://doc.rust-lang.org/std/ptr/index.html#provenance>")] | |
| 2942 | pub(crate) struct ImplicitProvenanceCastsInt2Ptr<'tcx> { | |
| 2942 | 2943 | pub expr_ty: Ty<'tcx>, |
| 2943 | 2944 | pub cast_ty: Ty<'tcx>, |
| 2944 | 2945 | #[subdiagnostic] |
| 2945 | pub sugg: Option<LossyProvenanceInt2PtrSuggestion>, | |
| 2946 | pub sugg: Option<Int2PtrSuggestion>, | |
| 2946 | 2947 | } |
| 2947 | 2948 | |
| 2948 | 2949 | #[derive(Subdiagnostic)] |
| 2949 | 2950 | #[multipart_suggestion( |
| 2950 | "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address", | |
| 2951 | "use `.with_addr()` to adjust the address of a valid pointer in the same allocation", | |
| 2951 | 2952 | applicability = "has-placeholders" |
| 2952 | 2953 | )] |
| 2953 | pub(crate) struct LossyProvenanceInt2PtrSuggestion { | |
| 2954 | pub(crate) struct Int2PtrSuggestion { | |
| 2954 | 2955 | #[suggestion_part(code = "(...).with_addr(")] |
| 2955 | 2956 | pub lo: Span, |
| 2956 | 2957 | #[suggestion_part(code = ")")] |
| ... | ... | @@ -2958,21 +2959,18 @@ pub(crate) struct LossyProvenanceInt2PtrSuggestion { |
| 2958 | 2959 | } |
| 2959 | 2960 | |
| 2960 | 2961 | #[derive(Diagnostic)] |
| 2961 | #[diag( | |
| 2962 | "under strict provenance it is considered bad style to cast pointer `{$cast_from_ty}` to integer `{$cast_to_ty}`" | |
| 2963 | )] | |
| 2964 | #[help( | |
| 2965 | "if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead" | |
| 2966 | )] | |
| 2967 | pub(crate) struct LossyProvenancePtr2Int<'tcx> { | |
| 2962 | #[diag("cast from `{$cast_from_ty}` to `{$cast_to_ty}` implicitly exposes pointer provenance")] | |
| 2963 | #[help("if conforming to strict provenance is not possible, use `.expose_provenance()`")] | |
| 2964 | #[note("for more information, visit <https://doc.rust-lang.org/std/ptr/index.html#provenance>")] | |
| 2965 | pub(crate) struct ImplicitProvenanceCastsPtr2Int<'tcx> { | |
| 2968 | 2966 | pub cast_from_ty: Ty<'tcx>, |
| 2969 | 2967 | pub cast_to_ty: Ty<'tcx>, |
| 2970 | 2968 | #[subdiagnostic] |
| 2971 | pub sugg: Option<LossyProvenancePtr2IntSuggestion<'tcx>>, | |
| 2969 | pub sugg: Option<Ptr2IntSuggestion<'tcx>>, | |
| 2972 | 2970 | } |
| 2973 | 2971 | |
| 2974 | 2972 | #[derive(Subdiagnostic)] |
| 2975 | pub(crate) enum LossyProvenancePtr2IntSuggestion<'tcx> { | |
| 2973 | pub(crate) enum Ptr2IntSuggestion<'tcx> { | |
| 2976 | 2974 | #[multipart_suggestion( |
| 2977 | 2975 | "use `.addr()` to obtain the address of a pointer", |
| 2978 | 2976 | applicability = "maybe-incorrect" |
compiler/rustc_lint/src/lossy_provenance_casts.rs deleted-98| ... | ... | @@ -1,98 +0,0 @@ |
| 1 | use rustc_ast::util::parser::ExprPrecedence; | |
| 2 | use rustc_hir as hir; | |
| 3 | use rustc_session::{declare_lint, declare_lint_pass}; | |
| 4 | ||
| 5 | use crate::lints::{LossyProvenancePtr2Int, LossyProvenancePtr2IntSuggestion}; | |
| 6 | use crate::{LateContext, LateLintPass}; | |
| 7 | ||
| 8 | declare_lint! { | |
| 9 | /// The `lossy_provenance_casts` lint detects an `as` cast between a pointer | |
| 10 | /// and an integer. | |
| 11 | /// | |
| 12 | /// ### Example | |
| 13 | /// | |
| 14 | /// ```rust | |
| 15 | /// #![feature(strict_provenance_lints)] | |
| 16 | /// #![warn(lossy_provenance_casts)] | |
| 17 | /// | |
| 18 | /// fn main() { | |
| 19 | /// let x: u8 = 37; | |
| 20 | /// let _addr: usize = &x as *const u8 as usize; | |
| 21 | /// } | |
| 22 | /// ``` | |
| 23 | /// | |
| 24 | /// {{produces}} | |
| 25 | /// | |
| 26 | /// ### Explanation | |
| 27 | /// | |
| 28 | /// This lint is part of the strict provenance effort, see [issue #95228]. | |
| 29 | /// Casting a pointer to an integer is a lossy operation, because beyond | |
| 30 | /// just an *address* a pointer may be associated with a particular | |
| 31 | /// *provenance*. This information is used by the optimiser and for dynamic | |
| 32 | /// analysis/dynamic program verification (e.g. Miri or CHERI platforms). | |
| 33 | /// | |
| 34 | /// Since this cast is lossy, it is considered good style to use the | |
| 35 | /// [`ptr::addr`] method instead, which has a similar effect, but doesn't | |
| 36 | /// "expose" the pointer provenance. This improves optimisation potential. | |
| 37 | /// See the docs of [`ptr::addr`] and [`ptr::expose_provenance`] for more information | |
| 38 | /// about exposing pointer provenance. | |
| 39 | /// | |
| 40 | /// If your code can't comply with strict provenance and needs to expose | |
| 41 | /// the provenance, then there is [`ptr::expose_provenance`] as an escape hatch, | |
| 42 | /// which preserves the behaviour of `as usize` casts while being explicit | |
| 43 | /// about the semantics. | |
| 44 | /// | |
| 45 | /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228 | |
| 46 | /// [`ptr::addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.addr | |
| 47 | /// [`ptr::expose_provenance`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.expose_provenance | |
| 48 | pub LOSSY_PROVENANCE_CASTS, | |
| 49 | Allow, | |
| 50 | "a lossy pointer to integer cast is used", | |
| 51 | @feature_gate = strict_provenance_lints; | |
| 52 | } | |
| 53 | ||
| 54 | declare_lint_pass!( | |
| 55 | /// Lint for `as` casts between a pointer and an integer. | |
| 56 | LossyProvenanceCasts => [LOSSY_PROVENANCE_CASTS] | |
| 57 | ); | |
| 58 | ||
| 59 | impl<'tcx> LateLintPass<'tcx> for LossyProvenanceCasts { | |
| 60 | fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { | |
| 61 | let hir::ExprKind::Cast(cast_from_expr, cast_to_hir) = expr.kind else { return }; | |
| 62 | ||
| 63 | let typeck_results = cx.typeck_results(); | |
| 64 | // Only lint casts from pointer to integer | |
| 65 | let cast_from_ty = typeck_results.expr_ty(cast_from_expr); | |
| 66 | if !cast_from_ty.is_raw_ptr() { | |
| 67 | return; | |
| 68 | } | |
| 69 | let cast_to_ty = typeck_results.expr_ty(expr); | |
| 70 | if !cast_to_ty.is_integral() { | |
| 71 | return; | |
| 72 | } | |
| 73 | ||
| 74 | let sugg = expr.span.can_be_used_for_suggestions().then(|| { | |
| 75 | let needs_parens = cx.precedence(cast_from_expr) < ExprPrecedence::Unambiguous; | |
| 76 | let needs_cast = !cast_to_ty.is_usize(); | |
| 77 | let cast_span = cast_from_expr.span.shrink_to_hi().to(cast_to_hir.span); | |
| 78 | let expr_span = cast_from_expr.span.shrink_to_lo(); | |
| 79 | match (needs_parens, needs_cast) { | |
| 80 | (true, true) => LossyProvenancePtr2IntSuggestion::NeedsParensCast { | |
| 81 | expr_span, | |
| 82 | cast_span, | |
| 83 | cast_to_ty, | |
| 84 | }, | |
| 85 | (true, false) => { | |
| 86 | LossyProvenancePtr2IntSuggestion::NeedsParens { expr_span, cast_span } | |
| 87 | } | |
| 88 | (false, true) => { | |
| 89 | LossyProvenancePtr2IntSuggestion::NeedsCast { cast_span, cast_to_ty } | |
| 90 | } | |
| 91 | (false, false) => LossyProvenancePtr2IntSuggestion::Other { cast_span }, | |
| 92 | } | |
| 93 | }); | |
| 94 | ||
| 95 | let lint = LossyProvenancePtr2Int { cast_from_ty, cast_to_ty, sugg }; | |
| 96 | cx.tcx.emit_node_span_lint(LOSSY_PROVENANCE_CASTS, expr.hir_id, expr.span, lint); | |
| 97 | } | |
| 98 | } |
library/alloc/src/lib.rs+1-2| ... | ... | @@ -75,8 +75,7 @@ |
| 75 | 75 | #![needs_allocator] |
| 76 | 76 | // Lints: |
| 77 | 77 | #![deny(unsafe_op_in_unsafe_fn)] |
| 78 | #![deny(fuzzy_provenance_casts)] | |
| 79 | #![deny(lossy_provenance_casts)] | |
| 78 | #![deny(implicit_provenance_casts)] | |
| 80 | 79 | #![warn(deprecated_in_future)] |
| 81 | 80 | #![warn(missing_debug_implementations)] |
| 82 | 81 | #![warn(missing_docs)] |
library/alloctests/benches/lib.rs+1-2| ... | ... | @@ -6,8 +6,7 @@ |
| 6 | 6 | #![feature(slice_partition_dedup)] |
| 7 | 7 | #![feature(strict_provenance_lints)] |
| 8 | 8 | #![feature(test)] |
| 9 | #![deny(fuzzy_provenance_casts)] | |
| 10 | #![deny(lossy_provenance_casts)] | |
| 9 | #![deny(implicit_provenance_casts)] | |
| 11 | 10 | |
| 12 | 11 | extern crate test; |
| 13 | 12 |
library/alloctests/tests/lib.rs+1-2| ... | ... | @@ -43,8 +43,7 @@ |
| 43 | 43 | #![feature(vec_try_remove)] |
| 44 | 44 | #![feature(ptr_cast_slice)] |
| 45 | 45 | #![allow(internal_features)] |
| 46 | #![deny(fuzzy_provenance_casts)] | |
| 47 | #![deny(lossy_provenance_casts)] | |
| 46 | #![deny(implicit_provenance_casts)] | |
| 48 | 47 | #![deny(unsafe_op_in_unsafe_fn)] |
| 49 | 48 | |
| 50 | 49 | extern crate alloc; |
library/core/src/lib.rs+1-2| ... | ... | @@ -68,8 +68,7 @@ |
| 68 | 68 | // Lints: |
| 69 | 69 | #![deny(rust_2021_incompatible_or_patterns)] |
| 70 | 70 | #![deny(unsafe_op_in_unsafe_fn)] |
| 71 | #![deny(fuzzy_provenance_casts)] | |
| 72 | #![deny(lossy_provenance_casts)] | |
| 71 | #![deny(implicit_provenance_casts)] | |
| 73 | 72 | #![warn(deprecated_in_future)] |
| 74 | 73 | #![warn(missing_debug_implementations)] |
| 75 | 74 | #![warn(missing_docs)] |
library/core/src/ptr/const_ptr.rs+1-1| ... | ... | @@ -183,7 +183,7 @@ impl<T: PointeeSized> *const T { |
| 183 | 183 | /// [`with_exposed_provenance`]: with_exposed_provenance |
| 184 | 184 | #[inline(always)] |
| 185 | 185 | #[stable(feature = "exposed_provenance", since = "1.84.0")] |
| 186 | #[expect(lossy_provenance_casts, reason = "this *is* the replacement")] | |
| 186 | #[expect(implicit_provenance_casts, reason = "this *is* the replacement")] | |
| 187 | 187 | pub fn expose_provenance(self) -> usize { |
| 188 | 188 | self.cast::<()>() as usize |
| 189 | 189 | } |
library/core/src/ptr/mod.rs+2-2| ... | ... | @@ -1000,7 +1000,7 @@ pub const fn dangling_mut<T>() -> *mut T { |
| 1000 | 1000 | #[stable(feature = "exposed_provenance", since = "1.84.0")] |
| 1001 | 1001 | #[rustc_const_stable(feature = "const_exposed_provenance", since = "1.91.0")] |
| 1002 | 1002 | #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces |
| 1003 | #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead | |
| 1003 | #[allow(implicit_provenance_casts)] // this *is* the explicit provenance API one should use instead | |
| 1004 | 1004 | pub const fn with_exposed_provenance<T>(addr: usize) -> *const T { |
| 1005 | 1005 | addr as *const T |
| 1006 | 1006 | } |
| ... | ... | @@ -1041,7 +1041,7 @@ pub const fn with_exposed_provenance<T>(addr: usize) -> *const T { |
| 1041 | 1041 | #[stable(feature = "exposed_provenance", since = "1.84.0")] |
| 1042 | 1042 | #[rustc_const_stable(feature = "const_exposed_provenance", since = "1.91.0")] |
| 1043 | 1043 | #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces |
| 1044 | #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead | |
| 1044 | #[allow(implicit_provenance_casts)] // this *is* the explicit provenance API one should use instead | |
| 1045 | 1045 | pub const fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T { |
| 1046 | 1046 | addr as *mut T |
| 1047 | 1047 | } |
library/core/src/ptr/mut_ptr.rs+1-1| ... | ... | @@ -174,7 +174,7 @@ impl<T: PointeeSized> *mut T { |
| 174 | 174 | /// [`with_exposed_provenance_mut`]: with_exposed_provenance_mut |
| 175 | 175 | #[inline(always)] |
| 176 | 176 | #[stable(feature = "exposed_provenance", since = "1.84.0")] |
| 177 | #[expect(lossy_provenance_casts, reason = "this *is* the replacement")] | |
| 177 | #[expect(implicit_provenance_casts, reason = "this *is* the replacement")] | |
| 178 | 178 | pub fn expose_provenance(self) -> usize { |
| 179 | 179 | self.cast::<()>() as usize |
| 180 | 180 | } |
library/coretests/tests/lib.rs+1-2| ... | ... | @@ -128,8 +128,7 @@ |
| 128 | 128 | #![feature(unwrap_infallible)] |
| 129 | 129 | // tidy-alphabetical-end |
| 130 | 130 | #![allow(internal_features)] |
| 131 | #![deny(fuzzy_provenance_casts)] | |
| 132 | #![deny(lossy_provenance_casts)] | |
| 131 | #![deny(implicit_provenance_casts)] | |
| 133 | 132 | #![deny(unsafe_op_in_unsafe_fn)] |
| 134 | 133 | |
| 135 | 134 | /// Version of `assert_matches` that ignores fancy runtime printing in const context and uses structural equality. |
library/std/src/lib.rs+2-9| ... | ... | @@ -245,8 +245,7 @@ |
| 245 | 245 | #![allow(explicit_outlives_requirements)] |
| 246 | 246 | #![allow(unused_lifetimes)] |
| 247 | 247 | #![allow(internal_features)] |
| 248 | #![deny(fuzzy_provenance_casts)] | |
| 249 | #![deny(lossy_provenance_casts)] | |
| 248 | #![deny(implicit_provenance_casts)] | |
| 250 | 249 | #![deny(unsafe_op_in_unsafe_fn)] |
| 251 | 250 | #![allow(rustdoc::redundant_explicit_links)] |
| 252 | 251 | #![warn(rustdoc::unescaped_backticks)] |
| ... | ... | @@ -726,13 +725,7 @@ pub mod alloc; |
| 726 | 725 | mod panicking; |
| 727 | 726 | |
| 728 | 727 | #[path = "../../backtrace/src/lib.rs"] |
| 729 | #[allow( | |
| 730 | dead_code, | |
| 731 | unused_attributes, | |
| 732 | fuzzy_provenance_casts, | |
| 733 | lossy_provenance_casts, | |
| 734 | unsafe_op_in_unsafe_fn | |
| 735 | )] | |
| 728 | #[allow(dead_code, unused_attributes, implicit_provenance_casts, unsafe_op_in_unsafe_fn)] | |
| 736 | 729 | mod backtrace_rs; |
| 737 | 730 | |
| 738 | 731 | #[stable(feature = "cfg_select", since = "1.95.0")] |
library/std/src/os/unix/thread.rs+2-2| ... | ... | @@ -34,12 +34,12 @@ impl<T> JoinHandleExt for JoinHandle<T> { |
| 34 | 34 | // This is an int2ptr cast on some platforms (e.g., *-musl) where RawPthread |
| 35 | 35 | // is an integer but libc::pthread_t is a pointer. Exposed provenance is the |
| 36 | 36 | // safe choice here, but `as` also works when it's int2int or ptr2ptr. |
| 37 | #[allow(lossy_provenance_casts)] | |
| 37 | #[allow(implicit_provenance_casts)] | |
| 38 | 38 | fn as_pthread_t(&self) -> RawPthread { |
| 39 | 39 | self.as_inner().id() as RawPthread |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | #[allow(lossy_provenance_casts)] // see above for why | |
| 42 | #[allow(implicit_provenance_casts)] // see above for why | |
| 43 | 43 | fn into_pthread_t(self) -> RawPthread { |
| 44 | 44 | self.into_inner().into_id() as RawPthread |
| 45 | 45 | } |
library/std/src/os/windows/io/socket.rs+1-1| ... | ... | @@ -75,7 +75,7 @@ impl OwnedSocket { |
| 75 | 75 | } |
| 76 | 76 | |
| 77 | 77 | // FIXME(strict_provenance_magic): we defined RawSocket to be a u64 ;-; |
| 78 | #[allow(fuzzy_provenance_casts)] | |
| 78 | #[allow(implicit_provenance_casts)] | |
| 79 | 79 | #[cfg(not(target_vendor = "uwp"))] |
| 80 | 80 | pub(crate) fn set_no_inherit(&self) -> io::Result<()> { |
| 81 | 81 | cvt(unsafe { |
library/std/src/sys/args/sgx.rs+1-2| ... | ... | @@ -1,5 +1,4 @@ |
| 1 | // FIXME: this module systematically confuses pointers and integers | |
| 2 | #![allow(fuzzy_provenance_casts, lossy_provenance_casts)] | |
| 1 | #![allow(implicit_provenance_casts)] // FIXME: this module systematically confuses pointers and integers | |
| 3 | 2 | |
| 4 | 3 | use crate::ffi::OsString; |
| 5 | 4 | use crate::num::NonZero; |
library/std/src/sys/env/sgx.rs+1-2| ... | ... | @@ -1,5 +1,4 @@ |
| 1 | // FIXME: this module systematically confuses pointers and integers | |
| 2 | #![allow(fuzzy_provenance_casts, lossy_provenance_casts)] | |
| 1 | #![allow(implicit_provenance_casts)] // FIXME: this module systematically confuses pointers and integers | |
| 3 | 2 | |
| 4 | 3 | pub use super::common::Env; |
| 5 | 4 | use crate::collections::HashMap; |
library/std/src/sys/pal/sgx/mod.rs+1-2| ... | ... | @@ -3,8 +3,7 @@ |
| 3 | 3 | //! This module contains the facade (aka platform-specific) implementations of |
| 4 | 4 | //! OS level functionality for Fortanix SGX. |
| 5 | 5 | #![deny(unsafe_op_in_unsafe_fn)] |
| 6 | // FIXME: this entire module systematically confuses pointers and integers | |
| 7 | #![allow(fuzzy_provenance_casts, lossy_provenance_casts)] | |
| 6 | #![allow(implicit_provenance_casts)] // FIXME: this entire module systematically confuses pointers and integers | |
| 8 | 7 | |
| 9 | 8 | use crate::io; |
| 10 | 9 | use crate::sync::atomic::{Atomic, AtomicBool, Ordering}; |
src/doc/unstable-book/src/language-features/strict-provenance-lints.md+6-5| ... | ... | @@ -5,17 +5,18 @@ The tracking issue for this feature is: [#130351] |
| 5 | 5 | [#130351]: https://github.com/rust-lang/rust/issues/130351 |
| 6 | 6 | ----- |
| 7 | 7 | |
| 8 | The `strict_provenance_lints` feature allows to enable the `fuzzy_provenance_casts` and `lossy_provenance_casts` lints. | |
| 9 | These lint on casts between integers and pointers, that are recommended against or invalid in the strict provenance model. | |
| 8 | The `strict_provenance_lints` feature allows to enable the `implicit_provenance_casts` lint. | |
| 10 | 9 | |
| 11 | 10 | ## Example |
| 12 | 11 | |
| 13 | 12 | ```rust |
| 14 | 13 | #![feature(strict_provenance_lints)] |
| 15 | #![warn(fuzzy_provenance_casts)] | |
| 14 | #![warn(implicit_provenance_casts)] | |
| 16 | 15 | |
| 17 | 16 | fn main() { |
| 18 | let _dangling = 16_usize as *const u8; | |
| 19 | //~^ WARNING: strict provenance disallows casting integer `usize` to pointer `*const u8` | |
| 17 | let dangling = 16_usize as *const u8; | |
| 18 | //~^ WARNING: cast from `usize` to `*const u8` implicitly relies on exposed provenance | |
| 19 | let _addr = dangling as usize; | |
| 20 | //~^ WARNING: cast from `*const u8` to `usize` implicitly exposes pointer provenance | |
| 20 | 21 | } |
| 21 | 22 | ``` |
tests/ui/feature-gates/feature-gate-strict_provenance_lints.rs+8-2| ... | ... | @@ -1,9 +1,15 @@ |
| 1 | 1 | //@ check-pass |
| 2 | 2 | |
| 3 | #![deny(implicit_provenance_casts)] | |
| 4 | //~^ WARNING unknown lint: `implicit_provenance_casts` | |
| 5 | ||
| 6 | // feature-gating also applies when the old names are helpfully replaced with the new one: | |
| 3 | 7 | #![deny(fuzzy_provenance_casts)] |
| 4 | //~^ WARNING unknown lint: `fuzzy_provenance_casts` | |
| 8 | //~^ WARNING lint `fuzzy_provenance_casts` has been renamed to `implicit_provenance_casts` | |
| 9 | //~| WARNING unknown lint: `implicit_provenance_casts` | |
| 5 | 10 | #![deny(lossy_provenance_casts)] |
| 6 | //~^ WARNING unknown lint: `lossy_provenance_casts` | |
| 11 | //~^ WARNING lint `lossy_provenance_casts` has been renamed to `implicit_provenance_casts` | |
| 12 | //~| WARNING unknown lint: `implicit_provenance_casts` | |
| 7 | 13 | |
| 8 | 14 | fn main() { |
| 9 | 15 | // no warnings emitted since the lints are not activated |
tests/ui/feature-gates/feature-gate-strict_provenance_lints.stderr+32-7| ... | ... | @@ -1,25 +1,50 @@ |
| 1 | warning: unknown lint: `fuzzy_provenance_casts` | |
| 1 | warning: unknown lint: `implicit_provenance_casts` | |
| 2 | 2 | --> $DIR/feature-gate-strict_provenance_lints.rs:3:9 |
| 3 | 3 | | |
| 4 | LL | #![deny(implicit_provenance_casts)] | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | = note: the `implicit_provenance_casts` lint is unstable | |
| 8 | = note: see issue #130351 <https://github.com/rust-lang/rust/issues/130351> for more information | |
| 9 | = help: add `#![feature(strict_provenance_lints)]` to the crate attributes to enable | |
| 10 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date | |
| 11 | = note: `#[warn(unknown_lints)]` on by default | |
| 12 | ||
| 13 | warning: lint `fuzzy_provenance_casts` has been renamed to `implicit_provenance_casts` | |
| 14 | --> $DIR/feature-gate-strict_provenance_lints.rs:7:9 | |
| 15 | | | |
| 16 | LL | #![deny(fuzzy_provenance_casts)] | |
| 17 | | ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `implicit_provenance_casts` | |
| 18 | | | |
| 19 | = note: `#[warn(renamed_and_removed_lints)]` on by default | |
| 20 | ||
| 21 | warning: unknown lint: `implicit_provenance_casts` | |
| 22 | --> $DIR/feature-gate-strict_provenance_lints.rs:7:9 | |
| 23 | | | |
| 4 | 24 | LL | #![deny(fuzzy_provenance_casts)] |
| 5 | 25 | | ^^^^^^^^^^^^^^^^^^^^^^ |
| 6 | 26 | | |
| 7 | = note: the `fuzzy_provenance_casts` lint is unstable | |
| 27 | = note: the `implicit_provenance_casts` lint is unstable | |
| 8 | 28 | = note: see issue #130351 <https://github.com/rust-lang/rust/issues/130351> for more information |
| 9 | 29 | = help: add `#![feature(strict_provenance_lints)]` to the crate attributes to enable |
| 10 | 30 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date |
| 11 | = note: `#[warn(unknown_lints)]` on by default | |
| 12 | 31 | |
| 13 | warning: unknown lint: `lossy_provenance_casts` | |
| 14 | --> $DIR/feature-gate-strict_provenance_lints.rs:5:9 | |
| 32 | warning: lint `lossy_provenance_casts` has been renamed to `implicit_provenance_casts` | |
| 33 | --> $DIR/feature-gate-strict_provenance_lints.rs:10:9 | |
| 34 | | | |
| 35 | LL | #![deny(lossy_provenance_casts)] | |
| 36 | | ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `implicit_provenance_casts` | |
| 37 | ||
| 38 | warning: unknown lint: `implicit_provenance_casts` | |
| 39 | --> $DIR/feature-gate-strict_provenance_lints.rs:10:9 | |
| 15 | 40 | | |
| 16 | 41 | LL | #![deny(lossy_provenance_casts)] |
| 17 | 42 | | ^^^^^^^^^^^^^^^^^^^^^^ |
| 18 | 43 | | |
| 19 | = note: the `lossy_provenance_casts` lint is unstable | |
| 44 | = note: the `implicit_provenance_casts` lint is unstable | |
| 20 | 45 | = note: see issue #130351 <https://github.com/rust-lang/rust/issues/130351> for more information |
| 21 | 46 | = help: add `#![feature(strict_provenance_lints)]` to the crate attributes to enable |
| 22 | 47 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date |
| 23 | 48 | |
| 24 | warning: 2 warnings emitted | |
| 49 | warning: 5 warnings emitted | |
| 25 | 50 |
tests/ui/lint/lint-strict-provenance-fuzzy-casts.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | #![feature(strict_provenance_lints)] |
| 2 | #![deny(fuzzy_provenance_casts)] | |
| 2 | #![deny(implicit_provenance_casts)] | |
| 3 | 3 | |
| 4 | 4 | fn main() { |
| 5 | 5 | let dangling = 16_usize as *const u8; |
| 6 | //~^ ERROR strict provenance disallows casting integer `usize` to pointer `*const u8` | |
| 6 | //~^ ERROR cast from `usize` to `*const u8` implicitly relies on exposed provenance | |
| 7 | 7 | } |
tests/ui/lint/lint-strict-provenance-fuzzy-casts.stderr+6-5| ... | ... | @@ -1,16 +1,17 @@ |
| 1 | error: strict provenance disallows casting integer `usize` to pointer `*const u8` | |
| 1 | error: cast from `usize` to `*const u8` implicitly relies on exposed provenance | |
| 2 | 2 | --> $DIR/lint-strict-provenance-fuzzy-casts.rs:5:20 |
| 3 | 3 | | |
| 4 | 4 | LL | let dangling = 16_usize as *const u8; |
| 5 | 5 | | ^^^^^^^^^^^^^^^^^^^^^ |
| 6 | 6 | | |
| 7 | = help: if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::with_exposed_provenance()` instead | |
| 7 | = help: if conforming to strict provenance is not possible, use `std::ptr::with_exposed_provenance()` | |
| 8 | = note: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html#provenance> | |
| 8 | 9 | note: the lint level is defined here |
| 9 | 10 | --> $DIR/lint-strict-provenance-fuzzy-casts.rs:2:9 |
| 10 | 11 | | |
| 11 | LL | #![deny(fuzzy_provenance_casts)] | |
| 12 | | ^^^^^^^^^^^^^^^^^^^^^^ | |
| 13 | help: use `.with_addr()` to adjust a valid pointer in the same allocation, to this address | |
| 12 | LL | #![deny(implicit_provenance_casts)] | |
| 13 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 14 | help: use `.with_addr()` to adjust the address of a valid pointer in the same allocation | |
| 14 | 15 | | |
| 15 | 16 | LL - let dangling = 16_usize as *const u8; |
| 16 | 17 | LL + let dangling = (...).with_addr(16_usize); |
tests/ui/lint/lint-strict-provenance-lossy-casts.rs+5-5| ... | ... | @@ -1,18 +1,18 @@ |
| 1 | 1 | #![feature(strict_provenance_lints)] |
| 2 | #![deny(lossy_provenance_casts)] | |
| 2 | #![deny(implicit_provenance_casts)] | |
| 3 | 3 | |
| 4 | 4 | fn main() { |
| 5 | 5 | let x: u8 = 37; |
| 6 | 6 | let addr: usize = &x as *const u8 as usize; |
| 7 | //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize` | |
| 7 | //~^ ERROR cast from `*const u8` to `usize` implicitly exposes pointer provenance | |
| 8 | 8 | |
| 9 | 9 | let addr_32bit = &x as *const u8 as u32; |
| 10 | //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32` | |
| 10 | //~^ ERROR cast from `*const u8` to `u32` implicitly exposes pointer provenance | |
| 11 | 11 | |
| 12 | 12 | // don't add unnecessary parens in the suggestion |
| 13 | 13 | let ptr = &x as *const u8; |
| 14 | 14 | let ptr_addr = ptr as usize; |
| 15 | //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize` | |
| 15 | //~^ ERROR cast from `*const u8` to `usize` implicitly exposes pointer provenance | |
| 16 | 16 | let ptr_addr_32bit = ptr as u32; |
| 17 | //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32` | |
| 17 | //~^ ERROR cast from `*const u8` to `u32` implicitly exposes pointer provenance | |
| 18 | 18 | } |
tests/ui/lint/lint-strict-provenance-lossy-casts.stderr+14-10| ... | ... | @@ -1,34 +1,36 @@ |
| 1 | error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize` | |
| 1 | error: cast from `*const u8` to `usize` implicitly exposes pointer provenance | |
| 2 | 2 | --> $DIR/lint-strict-provenance-lossy-casts.rs:6:23 |
| 3 | 3 | | |
| 4 | 4 | LL | let addr: usize = &x as *const u8 as usize; |
| 5 | 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^ |
| 6 | 6 | | |
| 7 | = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead | |
| 7 | = help: if conforming to strict provenance is not possible, use `.expose_provenance()` | |
| 8 | = note: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html#provenance> | |
| 8 | 9 | note: the lint level is defined here |
| 9 | 10 | --> $DIR/lint-strict-provenance-lossy-casts.rs:2:9 |
| 10 | 11 | | |
| 11 | LL | #![deny(lossy_provenance_casts)] | |
| 12 | | ^^^^^^^^^^^^^^^^^^^^^^ | |
| 12 | LL | #![deny(implicit_provenance_casts)] | |
| 13 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 13 | 14 | help: use `.addr()` to obtain the address of a pointer |
| 14 | 15 | | |
| 15 | 16 | LL - let addr: usize = &x as *const u8 as usize; |
| 16 | 17 | LL + let addr: usize = (&x as *const u8).addr(); |
| 17 | 18 | | |
| 18 | 19 | |
| 19 | error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32` | |
| 20 | error: cast from `*const u8` to `u32` implicitly exposes pointer provenance | |
| 20 | 21 | --> $DIR/lint-strict-provenance-lossy-casts.rs:9:22 |
| 21 | 22 | | |
| 22 | 23 | LL | let addr_32bit = &x as *const u8 as u32; |
| 23 | 24 | | ^^^^^^^^^^^^^^^^^^^^^^ |
| 24 | 25 | | |
| 25 | = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead | |
| 26 | = help: if conforming to strict provenance is not possible, use `.expose_provenance()` | |
| 27 | = note: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html#provenance> | |
| 26 | 28 | help: use `.addr()` to obtain the address of a pointer |
| 27 | 29 | | |
| 28 | 30 | LL | let addr_32bit = (&x as *const u8).addr() as u32; |
| 29 | 31 | | + ++++++++ |
| 30 | 32 | |
| 31 | error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize` | |
| 33 | error: cast from `*const u8` to `usize` implicitly exposes pointer provenance | |
| 32 | 34 | --> $DIR/lint-strict-provenance-lossy-casts.rs:14:20 |
| 33 | 35 | | |
| 34 | 36 | LL | let ptr_addr = ptr as usize; |
| ... | ... | @@ -36,9 +38,10 @@ LL | let ptr_addr = ptr as usize; |
| 36 | 38 | | | |
| 37 | 39 | | help: use `.addr()` to obtain the address of a pointer: `.addr()` |
| 38 | 40 | | |
| 39 | = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead | |
| 41 | = help: if conforming to strict provenance is not possible, use `.expose_provenance()` | |
| 42 | = note: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html#provenance> | |
| 40 | 43 | |
| 41 | error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32` | |
| 44 | error: cast from `*const u8` to `u32` implicitly exposes pointer provenance | |
| 42 | 45 | --> $DIR/lint-strict-provenance-lossy-casts.rs:16:26 |
| 43 | 46 | | |
| 44 | 47 | LL | let ptr_addr_32bit = ptr as u32; |
| ... | ... | @@ -46,7 +49,8 @@ LL | let ptr_addr_32bit = ptr as u32; |
| 46 | 49 | | | |
| 47 | 50 | | help: use `.addr()` to obtain the address of a pointer: `.addr() as u32` |
| 48 | 51 | | |
| 49 | = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead | |
| 52 | = help: if conforming to strict provenance is not possible, use `.expose_provenance()` | |
| 53 | = note: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html#provenance> | |
| 50 | 54 | |
| 51 | 55 | error: aborting due to 4 previous errors |
| 52 | 56 |
tests/ui/lint/lint-strict-provenance-macro-casts.rs+5-6| ... | ... | @@ -1,23 +1,22 @@ |
| 1 | 1 | #![feature(strict_provenance_lints)] |
| 2 | #![deny(lossy_provenance_casts)] | |
| 3 | #![deny(fuzzy_provenance_casts)] | |
| 2 | #![deny(implicit_provenance_casts)] | |
| 4 | 3 | |
| 5 | 4 | macro_rules! cast { |
| 6 | 5 | ($e:expr, $t:ty) => { |
| 7 | 6 | $e as $t |
| 8 | //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize` | |
| 9 | //~| ERROR strict provenance disallows casting integer `usize` to pointer `*const u8` | |
| 7 | //~^ ERROR cast from `*const u8` to `usize` | |
| 8 | //~| ERROR cast from `usize` to `*const u8` | |
| 10 | 9 | }; |
| 11 | 10 | } |
| 12 | 11 | |
| 13 | 12 | macro_rules! p2i { |
| 14 | 13 | ($e:expr) => { $e as usize }; |
| 15 | //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize` | |
| 14 | //~^ ERROR cast from `*const u8` to `usize` | |
| 16 | 15 | } |
| 17 | 16 | |
| 18 | 17 | macro_rules! i2p { |
| 19 | 18 | ($e:expr) => { $e as *const () }; |
| 20 | //~^ ERROR strict provenance disallows casting integer `usize` to pointer `*const ()` | |
| 19 | //~^ ERROR cast from `usize` to `*const ()` | |
| 21 | 20 | } |
| 22 | 21 | |
| 23 | 22 | fn main() { |
tests/ui/lint/lint-strict-provenance-macro-casts.stderr+18-19| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize` | |
| 2 | --> $DIR/lint-strict-provenance-macro-casts.rs:7:9 | |
| 1 | error: cast from `*const u8` to `usize` implicitly exposes pointer provenance | |
| 2 | --> $DIR/lint-strict-provenance-macro-casts.rs:6:9 | |
| 3 | 3 | | |
| 4 | 4 | LL | $e as $t |
| 5 | 5 | | ^^^^^^^^ |
| ... | ... | @@ -7,16 +7,17 @@ LL | $e as $t |
| 7 | 7 | LL | let _addr = cast!(ptr, usize); |
| 8 | 8 | | ----------------- in this macro invocation |
| 9 | 9 | | |
| 10 | = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead | |
| 10 | = help: if conforming to strict provenance is not possible, use `.expose_provenance()` | |
| 11 | = note: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html#provenance> | |
| 11 | 12 | note: the lint level is defined here |
| 12 | 13 | --> $DIR/lint-strict-provenance-macro-casts.rs:2:9 |
| 13 | 14 | | |
| 14 | LL | #![deny(lossy_provenance_casts)] | |
| 15 | | ^^^^^^^^^^^^^^^^^^^^^^ | |
| 15 | LL | #![deny(implicit_provenance_casts)] | |
| 16 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 16 | 17 | = note: this error originates in the macro `cast` (in Nightly builds, run with -Z macro-backtrace for more info) |
| 17 | 18 | |
| 18 | error: strict provenance disallows casting integer `usize` to pointer `*const u8` | |
| 19 | --> $DIR/lint-strict-provenance-macro-casts.rs:7:9 | |
| 19 | error: cast from `usize` to `*const u8` implicitly relies on exposed provenance | |
| 20 | --> $DIR/lint-strict-provenance-macro-casts.rs:6:9 | |
| 20 | 21 | | |
| 21 | 22 | LL | $e as $t |
| 22 | 23 | | ^^^^^^^^ |
| ... | ... | @@ -24,16 +25,12 @@ LL | $e as $t |
| 24 | 25 | LL | let _ptr = cast!(0usize, *const u8); |
| 25 | 26 | | ------------------------ in this macro invocation |
| 26 | 27 | | |
| 27 | = help: if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::with_exposed_provenance()` instead | |
| 28 | note: the lint level is defined here | |
| 29 | --> $DIR/lint-strict-provenance-macro-casts.rs:3:9 | |
| 30 | | | |
| 31 | LL | #![deny(fuzzy_provenance_casts)] | |
| 32 | | ^^^^^^^^^^^^^^^^^^^^^^ | |
| 28 | = help: if conforming to strict provenance is not possible, use `std::ptr::with_exposed_provenance()` | |
| 29 | = note: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html#provenance> | |
| 33 | 30 | = note: this error originates in the macro `cast` (in Nightly builds, run with -Z macro-backtrace for more info) |
| 34 | 31 | |
| 35 | error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize` | |
| 36 | --> $DIR/lint-strict-provenance-macro-casts.rs:14:20 | |
| 32 | error: cast from `*const u8` to `usize` implicitly exposes pointer provenance | |
| 33 | --> $DIR/lint-strict-provenance-macro-casts.rs:13:20 | |
| 37 | 34 | | |
| 38 | 35 | LL | ($e:expr) => { $e as usize }; |
| 39 | 36 | | ^^^^^^^^^^^ |
| ... | ... | @@ -41,11 +38,12 @@ LL | ($e:expr) => { $e as usize }; |
| 41 | 38 | LL | p2i!(&raw const x); |
| 42 | 39 | | ------------------ in this macro invocation |
| 43 | 40 | | |
| 44 | = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead | |
| 41 | = help: if conforming to strict provenance is not possible, use `.expose_provenance()` | |
| 42 | = note: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html#provenance> | |
| 45 | 43 | = note: this error originates in the macro `p2i` (in Nightly builds, run with -Z macro-backtrace for more info) |
| 46 | 44 | |
| 47 | error: strict provenance disallows casting integer `usize` to pointer `*const ()` | |
| 48 | --> $DIR/lint-strict-provenance-macro-casts.rs:19:20 | |
| 45 | error: cast from `usize` to `*const ()` implicitly relies on exposed provenance | |
| 46 | --> $DIR/lint-strict-provenance-macro-casts.rs:18:20 | |
| 49 | 47 | | |
| 50 | 48 | LL | ($e:expr) => { $e as *const () }; |
| 51 | 49 | | ^^^^^^^^^^^^^^^ |
| ... | ... | @@ -53,7 +51,8 @@ LL | ($e:expr) => { $e as *const () }; |
| 53 | 51 | LL | i2p!(0x42); |
| 54 | 52 | | ---------- in this macro invocation |
| 55 | 53 | | |
| 56 | = help: if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::with_exposed_provenance()` instead | |
| 54 | = help: if conforming to strict provenance is not possible, use `std::ptr::with_exposed_provenance()` | |
| 55 | = note: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html#provenance> | |
| 57 | 56 | = note: this error originates in the macro `i2p` (in Nightly builds, run with -Z macro-backtrace for more info) |
| 58 | 57 | |
| 59 | 58 | error: aborting due to 4 previous errors |