authorbors <bors@rust-lang.org> 2026-05-25 13:13:32 UTC
committerbors <bors@rust-lang.org> 2026-05-25 13:13:32 UTC
log50439483a755a404e7d36f877fe283d44662b50f
treeb4dd8c5ee6254d1c771a23f0a176e39484822777
parent6083f7891b5088184968e050d0eaecc7bcfd2b3d
parent9545845017f8922623e6613c7d860bbfe020c8c6

Auto merge of #156916 - JonathanBrouwer:rollup-CbeVZH2, r=JonathanBrouwer

Rollup of 3 pull requests Successful merges: - rust-lang/rust#156862 (Convert strict_provenance_lints to late lint passes) - rust-lang/rust#156879 (Replace rustfmt code of conduct with link) - rust-lang/rust#156901 (compiletest: Simplify `//@ needs-asm-mnemonic: ret` to just `//@ needs-asm-ret`)

19 files changed, 296 insertions(+), 468 deletions(-)

compiler/rustc_hir_typeck/src/cast.rs+3-62
......@@ -28,7 +28,6 @@
2828//! expression, `e as U2` is not necessarily so (in fact it will only be valid if
2929//! `U1` coerces to `U2`).
3030
31use rustc_ast::util::parser::ExprPrecedence;
3231use rustc_data_structures::fx::FxHashSet;
3332use rustc_errors::codes::*;
3433use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
......@@ -860,19 +859,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
860859 (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
861860
862861 // ptr-addr-cast
863 (Ptr(m_expr), Int(t_c)) => {
864 self.lossy_provenance_ptr2int_lint(fcx, t_c);
865 self.check_ptr_addr_cast(fcx, m_expr)
866 }
862 (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr),
863
867864 (FnPtr, Int(_)) => {
868865 // FIXME(#95489): there should eventually be a lint for these casts
869866 Ok(CastKind::FnPtrAddrCast)
870867 }
871868 // addr-ptr-cast
872 (Int(_), Ptr(mt)) => {
873 self.fuzzy_provenance_int2ptr_lint(fcx);
874 self.check_addr_ptr_cast(fcx, mt)
875 }
869 (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt),
876870 // fn-ptr-cast
877871 (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
878872
......@@ -1133,59 +1127,6 @@ impl<'a, 'tcx> CastCheck<'tcx> {
11331127 }
11341128 }
11351129
1136 fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
1137 let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
1138 let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
1139
1140 let sugg = self.span.can_be_used_for_suggestions().then(|| {
1141 let expr_prec = fcx.precedence(self.expr);
1142 let needs_parens = expr_prec < ExprPrecedence::Unambiguous;
1143 let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize));
1144 let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
1145 let expr_span = self.expr_span.shrink_to_lo();
1146 match (needs_parens, needs_cast) {
1147 (true, true) => errors::LossyProvenancePtr2IntSuggestion::NeedsParensCast {
1148 expr_span,
1149 cast_span,
1150 cast_ty,
1151 },
1152 (true, false) => {
1153 errors::LossyProvenancePtr2IntSuggestion::NeedsParens { expr_span, cast_span }
1154 }
1155 (false, true) => {
1156 errors::LossyProvenancePtr2IntSuggestion::NeedsCast { cast_span, cast_ty }
1157 }
1158 (false, false) => errors::LossyProvenancePtr2IntSuggestion::Other { cast_span },
1159 }
1160 });
1161
1162 let lint = errors::LossyProvenancePtr2Int { expr_ty, cast_ty, sugg };
1163 fcx.tcx.emit_node_span_lint(
1164 lint::builtin::LOSSY_PROVENANCE_CASTS,
1165 self.expr.hir_id,
1166 self.span,
1167 lint,
1168 );
1169 }
1170
1171 fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
1172 let sugg = self.span.can_be_used_for_suggestions().then(|| {
1173 errors::LossyProvenanceInt2PtrSuggestion {
1174 lo: self.expr_span.shrink_to_lo(),
1175 hi: self.expr_span.shrink_to_hi().to(self.cast_span),
1176 }
1177 });
1178 let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
1179 let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
1180 let lint = errors::LossyProvenanceInt2Ptr { expr_ty, cast_ty, sugg };
1181 fcx.tcx.emit_node_span_lint(
1182 lint::builtin::FUZZY_PROVENANCE_CASTS,
1183 self.expr.hir_id,
1184 self.span,
1185 lint,
1186 );
1187 }
1188
11891130 /// Attempt to suggest using `.is_empty` when trying to cast from a
11901131 /// collection type to a boolean.
11911132 fn try_suggest_collection_to_bool(&self, fcx: &FnCtxt<'a, 'tcx>, err: &mut Diag<'_>) {
compiler/rustc_hir_typeck/src/errors.rs-82
......@@ -377,18 +377,6 @@ impl Subdiagnostic for TypeMismatchFruTypo {
377377 }
378378}
379379
380#[derive(Diagnostic)]
381#[diag("strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`")]
382#[help(
383 "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"
384)]
385pub(crate) struct LossyProvenanceInt2Ptr<'tcx> {
386 pub expr_ty: Ty<'tcx>,
387 pub cast_ty: Ty<'tcx>,
388 #[subdiagnostic]
389 pub sugg: Option<LossyProvenanceInt2PtrSuggestion>,
390}
391
392380#[derive(Diagnostic)]
393381#[diag("cannot add {$traits_len ->
394382 [1] auto trait {$traits}
......@@ -404,76 +392,6 @@ pub(crate) struct PtrCastAddAutoToObject {
404392 pub traits: DiagSymbolList<String>,
405393}
406394
407#[derive(Subdiagnostic)]
408#[multipart_suggestion(
409 "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address",
410 applicability = "has-placeholders"
411)]
412pub(crate) struct LossyProvenanceInt2PtrSuggestion {
413 #[suggestion_part(code = "(...).with_addr(")]
414 pub lo: Span,
415 #[suggestion_part(code = ")")]
416 pub hi: Span,
417}
418
419#[derive(Diagnostic)]
420#[diag(
421 "under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}`"
422)]
423#[help(
424 "if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead"
425)]
426pub(crate) struct LossyProvenancePtr2Int<'tcx> {
427 pub expr_ty: Ty<'tcx>,
428 pub cast_ty: Ty<'tcx>,
429 #[subdiagnostic]
430 pub sugg: Option<LossyProvenancePtr2IntSuggestion<'tcx>>,
431}
432
433#[derive(Subdiagnostic)]
434pub(crate) enum LossyProvenancePtr2IntSuggestion<'tcx> {
435 #[multipart_suggestion(
436 "use `.addr()` to obtain the address of a pointer",
437 applicability = "maybe-incorrect"
438 )]
439 NeedsParensCast {
440 #[suggestion_part(code = "(")]
441 expr_span: Span,
442 #[suggestion_part(code = ").addr() as {cast_ty}")]
443 cast_span: Span,
444 cast_ty: Ty<'tcx>,
445 },
446 #[multipart_suggestion(
447 "use `.addr()` to obtain the address of a pointer",
448 applicability = "maybe-incorrect"
449 )]
450 NeedsParens {
451 #[suggestion_part(code = "(")]
452 expr_span: Span,
453 #[suggestion_part(code = ").addr()")]
454 cast_span: Span,
455 },
456 #[suggestion(
457 "use `.addr()` to obtain the address of a pointer",
458 code = ".addr() as {cast_ty}",
459 applicability = "maybe-incorrect"
460 )]
461 NeedsCast {
462 #[primary_span]
463 cast_span: Span,
464 cast_ty: Ty<'tcx>,
465 },
466 #[suggestion(
467 "use `.addr()` to obtain the address of a pointer",
468 code = ".addr()",
469 applicability = "maybe-incorrect"
470 )]
471 Other {
472 #[primary_span]
473 cast_span: Span,
474 },
475}
476
477395#[derive(Subdiagnostic)]
478396pub(crate) enum HelpUseLatestEdition {
479397 #[help("set `edition = \"{$edition}\"` in `Cargo.toml`")]
compiler/rustc_lint/src/fuzzy_provenance_casts.rs created+79
......@@ -0,0 +1,79 @@
1use rustc_hir as hir;
2use rustc_session::{declare_lint, declare_lint_pass};
3
4use crate::lints::{LossyProvenanceInt2Ptr, LossyProvenanceInt2PtrSuggestion};
5use crate::{LateContext, LateLintPass};
6
7declare_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
51declare_lint_pass!(
52 /// Lint for `as` casts between an integer and a pointer.
53 FuzzyProvenanceCasts => [FUZZY_PROVENANCE_CASTS]
54);
55
56impl<'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/lib.rs+6
......@@ -45,6 +45,7 @@ mod expect;
4545mod for_loops_over_fallibles;
4646mod foreign_modules;
4747mod function_cast_as_integer;
48mod fuzzy_provenance_casts;
4849mod gpukernel_abi;
4950mod if_let_rescope;
5051mod impl_trait_overcaptures;
......@@ -56,6 +57,7 @@ mod let_underscore;
5657mod levels;
5758pub mod lifetime_syntax;
5859mod lints;
60mod lossy_provenance_casts;
5961mod macro_expr_fragment_specifier_2024_migration;
6062mod map_unit_fn;
6163mod multiple_supertrait_upcastable;
......@@ -92,6 +94,7 @@ use drop_forget_useless::*;
9294use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
9395use for_loops_over_fallibles::*;
9496use function_cast_as_integer::*;
97use fuzzy_provenance_casts::FuzzyProvenanceCasts;
9598use gpukernel_abi::*;
9699use if_let_rescope::IfLetRescope;
97100use impl_trait_overcaptures::ImplTraitOvercaptures;
......@@ -100,6 +103,7 @@ use internal::*;
100103use invalid_from_utf8::*;
101104use let_underscore::*;
102105use lifetime_syntax::*;
106use lossy_provenance_casts::LossyProvenanceCasts;
103107use macro_expr_fragment_specifier_2024_migration::*;
104108use map_unit_fn::*;
105109use multiple_supertrait_upcastable::*;
......@@ -250,6 +254,8 @@ late_lint_methods!(
250254 CheckTransmutes: CheckTransmutes,
251255 LifetimeSyntax: LifetimeSyntax,
252256 InternalEqTraitMethodImpls: InternalEqTraitMethodImpls,
257 FuzzyProvenanceCasts: FuzzyProvenanceCasts,
258 LossyProvenanceCasts: LossyProvenanceCasts,
253259 ]
254260 ]
255261);
compiler/rustc_lint/src/lints.rs+82
......@@ -2932,3 +2932,85 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
29322932#[diag("`Eq::assert_receiver_is_total_eq` should never be implemented by hand")]
29332933#[note("this method was used to add checks to the `Eq` derive macro")]
29342934pub(crate) struct EqInternalMethodImplemented;
2935
2936#[derive(Diagnostic)]
2937#[diag("strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`")]
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"
2940)]
2941pub(crate) struct LossyProvenanceInt2Ptr<'tcx> {
2942 pub expr_ty: Ty<'tcx>,
2943 pub cast_ty: Ty<'tcx>,
2944 #[subdiagnostic]
2945 pub sugg: Option<LossyProvenanceInt2PtrSuggestion>,
2946}
2947
2948#[derive(Subdiagnostic)]
2949#[multipart_suggestion(
2950 "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address",
2951 applicability = "has-placeholders"
2952)]
2953pub(crate) struct LossyProvenanceInt2PtrSuggestion {
2954 #[suggestion_part(code = "(...).with_addr(")]
2955 pub lo: Span,
2956 #[suggestion_part(code = ")")]
2957 pub hi: Span,
2958}
2959
2960#[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)]
2967pub(crate) struct LossyProvenancePtr2Int<'tcx> {
2968 pub cast_from_ty: Ty<'tcx>,
2969 pub cast_to_ty: Ty<'tcx>,
2970 #[subdiagnostic]
2971 pub sugg: Option<LossyProvenancePtr2IntSuggestion<'tcx>>,
2972}
2973
2974#[derive(Subdiagnostic)]
2975pub(crate) enum LossyProvenancePtr2IntSuggestion<'tcx> {
2976 #[multipart_suggestion(
2977 "use `.addr()` to obtain the address of a pointer",
2978 applicability = "maybe-incorrect"
2979 )]
2980 NeedsParensCast {
2981 #[suggestion_part(code = "(")]
2982 expr_span: Span,
2983 #[suggestion_part(code = ").addr() as {cast_to_ty}")]
2984 cast_span: Span,
2985 cast_to_ty: Ty<'tcx>,
2986 },
2987 #[multipart_suggestion(
2988 "use `.addr()` to obtain the address of a pointer",
2989 applicability = "maybe-incorrect"
2990 )]
2991 NeedsParens {
2992 #[suggestion_part(code = "(")]
2993 expr_span: Span,
2994 #[suggestion_part(code = ").addr()")]
2995 cast_span: Span,
2996 },
2997 #[suggestion(
2998 "use `.addr()` to obtain the address of a pointer",
2999 code = ".addr() as {cast_to_ty}",
3000 applicability = "maybe-incorrect"
3001 )]
3002 NeedsCast {
3003 #[primary_span]
3004 cast_span: Span,
3005 cast_to_ty: Ty<'tcx>,
3006 },
3007 #[suggestion(
3008 "use `.addr()` to obtain the address of a pointer",
3009 code = ".addr()",
3010 applicability = "maybe-incorrect"
3011 )]
3012 Other {
3013 #[primary_span]
3014 cast_span: Span,
3015 },
3016}
compiler/rustc_lint/src/lossy_provenance_casts.rs created+98
......@@ -0,0 +1,98 @@
1use rustc_ast::util::parser::ExprPrecedence;
2use rustc_hir as hir;
3use rustc_session::{declare_lint, declare_lint_pass};
4
5use crate::lints::{LossyProvenancePtr2Int, LossyProvenancePtr2IntSuggestion};
6use crate::{LateContext, LateLintPass};
7
8declare_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
54declare_lint_pass!(
55 /// Lint for `as` casts between a pointer and an integer.
56 LossyProvenanceCasts => [LOSSY_PROVENANCE_CASTS]
57);
58
59impl<'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}
compiler/rustc_lint_defs/src/builtin.rs-92
......@@ -51,7 +51,6 @@ declare_lint_pass! {
5151 FLOAT_LITERAL_F32_FALLBACK,
5252 FORBIDDEN_LINT_GROUPS,
5353 FUNCTION_ITEM_REFERENCES,
54 FUZZY_PROVENANCE_CASTS,
5554 HIDDEN_GLOB_REEXPORTS,
5655 ILL_FORMED_ATTRIBUTE_INPUT,
5756 INCOMPLETE_INCLUDE,
......@@ -67,7 +66,6 @@ declare_lint_pass! {
6766 LINKER_INFO,
6867 LINKER_MESSAGES,
6968 LONG_RUNNING_CONST_EVAL,
70 LOSSY_PROVENANCE_CASTS,
7169 MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
7270 MACRO_USE_EXTERN_CRATE,
7371 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
......@@ -2593,96 +2591,6 @@ declare_lint! {
25932591 @edition Edition2024 => Warn;
25942592}
25952593
2596declare_lint! {
2597 /// The `fuzzy_provenance_casts` lint detects an `as` cast between an integer
2598 /// and a pointer.
2599 ///
2600 /// ### Example
2601 ///
2602 /// ```rust
2603 /// #![feature(strict_provenance_lints)]
2604 /// #![warn(fuzzy_provenance_casts)]
2605 ///
2606 /// fn main() {
2607 /// let _dangling = 16_usize as *const u8;
2608 /// }
2609 /// ```
2610 ///
2611 /// {{produces}}
2612 ///
2613 /// ### Explanation
2614 ///
2615 /// This lint is part of the strict provenance effort, see [issue #95228].
2616 /// Casting an integer to a pointer is considered bad style, as a pointer
2617 /// contains, besides the *address* also a *provenance*, indicating what
2618 /// memory the pointer is allowed to read/write. Casting an integer, which
2619 /// doesn't have provenance, to a pointer requires the compiler to assign
2620 /// (guess) provenance. The compiler assigns "all exposed valid" (see the
2621 /// docs of [`ptr::with_exposed_provenance`] for more information about this
2622 /// "exposing"). This penalizes the optimiser and is not well suited for
2623 /// dynamic analysis/dynamic program verification (e.g. Miri or CHERI
2624 /// platforms).
2625 ///
2626 /// It is much better to use [`ptr::with_addr`] instead to specify the
2627 /// provenance you want. If using this function is not possible because the
2628 /// code relies on exposed provenance then there is as an escape hatch
2629 /// [`ptr::with_exposed_provenance`].
2630 ///
2631 /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
2632 /// [`ptr::with_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.with_addr
2633 /// [`ptr::with_exposed_provenance`]: https://doc.rust-lang.org/core/ptr/fn.with_exposed_provenance.html
2634 pub FUZZY_PROVENANCE_CASTS,
2635 Allow,
2636 "a fuzzy integer to pointer cast is used",
2637 @feature_gate = strict_provenance_lints;
2638}
2639
2640declare_lint! {
2641 /// The `lossy_provenance_casts` lint detects an `as` cast between a pointer
2642 /// and an integer.
2643 ///
2644 /// ### Example
2645 ///
2646 /// ```rust
2647 /// #![feature(strict_provenance_lints)]
2648 /// #![warn(lossy_provenance_casts)]
2649 ///
2650 /// fn main() {
2651 /// let x: u8 = 37;
2652 /// let _addr: usize = &x as *const u8 as usize;
2653 /// }
2654 /// ```
2655 ///
2656 /// {{produces}}
2657 ///
2658 /// ### Explanation
2659 ///
2660 /// This lint is part of the strict provenance effort, see [issue #95228].
2661 /// Casting a pointer to an integer is a lossy operation, because beyond
2662 /// just an *address* a pointer may be associated with a particular
2663 /// *provenance*. This information is used by the optimiser and for dynamic
2664 /// analysis/dynamic program verification (e.g. Miri or CHERI platforms).
2665 ///
2666 /// Since this cast is lossy, it is considered good style to use the
2667 /// [`ptr::addr`] method instead, which has a similar effect, but doesn't
2668 /// "expose" the pointer provenance. This improves optimisation potential.
2669 /// See the docs of [`ptr::addr`] and [`ptr::expose_provenance`] for more information
2670 /// about exposing pointer provenance.
2671 ///
2672 /// If your code can't comply with strict provenance and needs to expose
2673 /// the provenance, then there is [`ptr::expose_provenance`] as an escape hatch,
2674 /// which preserves the behaviour of `as usize` casts while being explicit
2675 /// about the semantics.
2676 ///
2677 /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
2678 /// [`ptr::addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.addr
2679 /// [`ptr::expose_provenance`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.expose_provenance
2680 pub LOSSY_PROVENANCE_CASTS,
2681 Allow,
2682 "a lossy pointer to integer cast is used",
2683 @feature_gate = strict_provenance_lints;
2684}
2685
26862594declare_lint! {
26872595 /// The `const_evaluatable_unchecked` lint detects a generic constant used
26882596 /// in a type.
src/doc/rustc-dev-guide/src/tests/compiletest.md-11
......@@ -346,17 +346,6 @@ See also the [codegen tests](#codegen-tests) for a similar set of tests.
346346If you need to work with `#![no_std]` cross-compiling tests, consult the
347347[`minicore` test auxiliary](./minicore.md) chapter.
348348
349#### Conditional assembly tests based on instruction support
350
351Tests that depend on specific assembly instructions being available can use the
352`//@ needs-asm-mnemonic: <MNEMONIC>` directive.
353This will skip the test if the target backend does not support the specified instruction mnemonic.
354
355For example, a test that requires the `RET` instruction:
356```rust,ignore
357//@ needs-asm-mnemonic: RET
358```
359
360349[`tests/assembly-llvm`]: https://github.com/rust-lang/rust/tree/HEAD/tests/assembly-llvm
361350
362351
src/doc/rustc-dev-guide/src/tests/directives.md+4-3
......@@ -164,9 +164,10 @@ The following directives will check rustc build settings and target settings:
164164 For tests that cross-compile to explicit targets
165165 via `--target`, use `needs-llvm-components` instead to ensure the appropriate
166166 backend is available.
167- `needs-asm-mnemonic: <MNEMONIC>` — ignores if the target backend does not
168 support the specified assembly mnemonic (e.g., `RET`, `NOP`).
169 Only supported with the LLVM backend.
167- `needs-asm-ret` - ignores if the target does not have a `ret` instruction
168 in its assembly syntax. Most target architectures have this instruction,
169 making it handy for portable inline-assembly tests, but some architectures
170 (e.g. 32-bit ARM) do not have it.
170171- `needs-profiler-runtime` — ignores the test if the profiler runtime was not
171172 enabled for the target (`build.profiler = true` in `bootstrap.toml`)
172173- `needs-sanitizer-support` — ignores if the sanitizer support was not enabled
src/tools/compiletest/src/directives/directive_names.rs+1-1
......@@ -159,7 +159,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
159159 "min-llvm-version",
160160 "min-system-llvm-version",
161161 "minicore-compile-flags",
162 "needs-asm-mnemonic",
162 "needs-asm-ret",
163163 "needs-asm-support",
164164 "needs-backends",
165165 "needs-crate-type",
src/tools/compiletest/src/directives/needs.rs+9-41
......@@ -101,37 +101,6 @@ pub(super) fn handle_needs(
101101 }
102102 }
103103
104 if name == "needs-asm-mnemonic" {
105 let Some(rest) = ln.value_after_colon() else {
106 return IgnoreDecision::Error {
107 message: "expected `needs-asm-mnemonic` to have a mnemonic name after colon"
108 .to_string(),
109 };
110 };
111
112 if !config.default_codegen_backend.is_llvm() {
113 return IgnoreDecision::Ignore {
114 reason: "skipping test as non-LLVM backend does not support mnemonic queries"
115 .to_string(),
116 };
117 }
118
119 let mnemonic = rest.trim();
120 let has_mnemonic = match mnemonic {
121 "ret" => conditions.has_ret_mnemonic,
122 "nop" => conditions.has_nop_mnemonic,
123 _ => has_mnemonic(config, mnemonic),
124 };
125
126 if has_mnemonic {
127 return IgnoreDecision::Continue;
128 } else {
129 return IgnoreDecision::Ignore {
130 reason: format!("skipping test as target does not have `{mnemonic}` mnemonic"),
131 };
132 }
133 }
134
135104 // Handled elsewhere.
136105 if name == "needs-llvm-components" || name == "needs-backends" {
137106 return IgnoreDecision::Continue;
......@@ -163,11 +132,6 @@ struct Need {
163132pub(crate) struct PreparedNeedsConditions {
164133 /// The `//@ needs-*` conditions that can be treated as a simple name->boolean mapping.
165134 simple_needs: HashMap<&'static str, Need>,
166
167 /// Might add particular other mnemonics heavily needed by tests here.
168 /// Otherwise call into llvm for every check
169 has_ret_mnemonic: bool,
170 has_nop_mnemonic: bool,
171135}
172136
173137pub(crate) fn prepare_needs_conditions(config: &Config) -> PreparedNeedsConditions {
......@@ -177,6 +141,14 @@ pub(crate) fn prepare_needs_conditions(config: &Config) -> PreparedNeedsConditio
177141 // Note that we intentionally still put the needs- prefix here to make the file show up when
178142 // grepping for a directive name, even though we could technically strip that.
179143 let simple_needs = vec![
144 // This used to be a more general `//@ needs-asm-mnemonic: ret` directive,
145 // but was simplified to just `//@ needs-asm-ret` because there are very
146 // few other mnemonics (`nop`?) that it could ever be useful with.
147 Need {
148 name: "needs-asm-ret",
149 condition: has_mnemonic(config, "ret"),
150 ignore_reason: "ignored on targets without a `ret` assembly instruction",
151 },
180152 Need {
181153 name: "needs-asm-support",
182154 condition: config.has_asm_support(),
......@@ -398,11 +370,7 @@ pub(crate) fn prepare_needs_conditions(config: &Config) -> PreparedNeedsConditio
398370 })
399371 .collect::<HashMap<_, _>>();
400372
401 PreparedNeedsConditions {
402 simple_needs,
403 has_ret_mnemonic: has_mnemonic(config, "ret"),
404 has_nop_mnemonic: has_mnemonic(config, "nop"),
405 }
373 PreparedNeedsConditions { simple_needs }
406374}
407375
408376fn find_dlltool(config: &Config) -> bool {
src/tools/compiletest/src/directives/tests.rs+9-17
......@@ -1270,23 +1270,15 @@ fn test_edition_range_edition_to_test() {
12701270}
12711271
12721272#[test]
1273fn needs_asm_mnemonic() {
1273fn needs_asm_ret() {
12741274 let config_x86_64 = cfg().target("x86_64-unknown-linux-gnu").build();
12751275 let config_aarch64 = cfg().target("aarch64-unknown-linux-gnu").build();
1276
1277 // invalid mnemonic
1278 assert!(check_ignore(&config_x86_64, "//@ needs-asm-mnemonic:GRUGGY"));
1279 assert!(check_ignore(&config_aarch64, "//@ needs-asm-mnemonic:gruggy"));
1280
1281 // valid x86 and aarch64
1282 assert!(!check_ignore(&config_x86_64, "//@ needs-asm-mnemonic:RET"));
1283 assert!(!check_ignore(&config_aarch64, "//@ needs-asm-mnemonic:ret"));
1284
1285 // this is aarch64 specific
1286 assert!(check_ignore(&config_x86_64, "//@ needs-asm-mnemonic:ldrsbwui"));
1287 assert!(!check_ignore(&config_aarch64, "//@ needs-asm-mnemonic:LDRSBWui"));
1288
1289 // this is x86 specific
1290 assert!(check_ignore(&config_aarch64, "//@ needs-asm-mnemonic:CMPxCHG16B"));
1291 assert!(!check_ignore(&config_x86_64, "//@ needs-asm-mnemonic:CMPXchg16B"));
1276 // 32-bit ARM does not have a "ret" mnemonic.
1277 let config_arm32 = cfg().target("armv7a-none-eabi").build();
1278 let config_wasm = cfg().target("wasm32v1-none").build();
1279
1280 assert!(!check_ignore(&config_x86_64, "//@ needs-asm-ret"));
1281 assert!(!check_ignore(&config_aarch64, "//@ needs-asm-ret"));
1282 assert!(check_ignore(&config_arm32, "//@ needs-asm-ret"));
1283 assert!(check_ignore(&config_wasm, "//@ needs-asm-ret"));
12921284}
src/tools/rustfmt/CODE_OF_CONDUCT.md+1-38
......@@ -1,40 +1,3 @@
11# The Rust Code of Conduct
22
3A version of this document [can be found online](https://www.rust-lang.org/conduct.html).
4
5## Conduct
6
7**Contact**: [rust-mods@rust-lang.org](mailto:rust-mods@rust-lang.org)
8
9* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
10* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
11* Please be kind and courteous. There's no need to be mean or rude.
12* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
13* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
14* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the <a href="https://github.com/stumpsyn/policies/blob/master/citizen_code_of_conduct.md/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
15* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
16* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
17
18## Moderation
19
20
21These are the policies for upholding our community's standards of conduct. If you feel that a thread needs moderation, please contact the [Rust moderation team][mod_team].
22
231. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
242. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
253. Moderators will first respond to such remarks with a warning.
264. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off.
275. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
286. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
297. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed.
308. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.
31
32In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.
33
34And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.
35
36The enforcement policies listed above apply to all official Rust venues; including official IRC channels (#rust, #rust-internals, #rust-tools, #rust-libs, #rustc, #rust-beginners, #rust-docs, #rust-community, #rust-lang, and #cargo); GitHub repositories under rust-lang, rust-lang-nursery, and rust-lang-deprecated; and all forums under rust-lang.org (users.rust-lang.org, internals.rust-lang.org). For other projects adopting the Rust Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion.
37
38*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).*
39
40[mod_team]: https://www.rust-lang.org/team.html#Moderation-team
3The Code of Conduct for this repository [can be found online](https://www.rust-lang.org/conduct.html).
tests/codegen-llvm/cffi/c-variadic-naked.rs+1-1
......@@ -1,5 +1,5 @@
11//@ needs-asm-support
2//@ needs-asm-mnemonic: ret
2//@ needs-asm-ret
33
44// tests that `va_start` is not injected into naked functions
55
tests/codegen-llvm/naked-fn/aligned.rs+1-1
......@@ -1,6 +1,6 @@
11//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
22//@ needs-asm-support
3//@ needs-asm-mnemonic: ret
3//@ needs-asm-ret
44//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368)
55
66#![crate_type = "lib"]
tests/codegen-llvm/naked-fn/min-function-alignment.rs+1-1
......@@ -1,6 +1,6 @@
11//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmin-function-alignment=16
22//@ needs-asm-support
3//@ needs-asm-mnemonic: ret
3//@ needs-asm-ret
44//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368)
55
66// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
tests/run-make/naked-dead-code-elimination/rmake.rs+1-1
......@@ -1,6 +1,6 @@
11//@ ignore-cross-compile
22//@ needs-asm-support
3//@ needs-asm-mnemonic: RET
3//@ needs-asm-ret
44
55use run_make_support::symbols::object_contains_any_symbol;
66use run_make_support::{bin_name, rustc};
tests/ui/lint/ice-fuzzy-provenance-casts-with-inner-attr.rs deleted-24
......@@ -1,24 +0,0 @@
1// Regression test for #137588.
2// The compiler used to ICE when emitting a `fuzzy_provenance_casts` lint
3// diagnostic for code with an inner attribute spanning the entire file,
4// causing `draw_code_line` to panic on an empty `file_lines` from a dummy span.
5
6//@ edition:2024
7//@ compile-flags: -Wfuzzy-provenance-casts
8
9#![feature(strict_provenance_lints)]
10//~^ ERROR too many leading `super` keywords [E0433]
11//~| ERROR cannot find type `Ts` in this scope [E0425]
12//~| ERROR `#[prelude_import]` is for use by rustc only [E0658]
13//~| WARN strict provenance disallows casting integer `usize` to pointer `*const u32`
14#![core::contracts::ensures(|ret| ret.is_none_or(Stars::is_valid))]
15//~^ ERROR use of unstable library feature `contracts` [E0658]
16//~| ERROR inner macro attributes are unstable [E0658]
17//~| ERROR cannot find type `Stars` in this scope [E0433]
18
19pub(super) fn foo() -> *const Ts {
20 unsafe {
21 let p2 = 0x52 as *const u32;
22 }
23}
24//~^ ERROR `main` function not found in crate
tests/ui/lint/ice-fuzzy-provenance-casts-with-inner-attr.stderr deleted-93
......@@ -1,93 +0,0 @@
1error[E0658]: use of unstable library feature `contracts`
2 --> $DIR/ice-fuzzy-provenance-casts-with-inner-attr.rs:14:4
3 |
4LL | #![core::contracts::ensures(|ret| ret.is_none_or(Stars::is_valid))]
5 | ^^^^^^^^^^^^^^^^^^^^^^^^
6 |
7 = note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
8 = help: add `#![feature(contracts)]` to the crate attributes to enable
9 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10
11error[E0658]: inner macro attributes are unstable
12 --> $DIR/ice-fuzzy-provenance-casts-with-inner-attr.rs:14:4
13 |
14LL | #![core::contracts::ensures(|ret| ret.is_none_or(Stars::is_valid))]
15 | ^^^^^^^^^^^^^^^^^^^^^^^^
16 |
17 = note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
18 = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
19 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
20
21error[E0433]: too many leading `super` keywords
22 --> $DIR/ice-fuzzy-provenance-casts-with-inner-attr.rs:9:1
23 |
24LL | / #![feature(strict_provenance_lints)]
25... |
26LL | | }
27 | |_^ there are too many leading `super` keywords
28
29error[E0425]: cannot find type `Ts` in this scope
30 --> $DIR/ice-fuzzy-provenance-casts-with-inner-attr.rs:9:1
31 |
32LL | / #![feature(strict_provenance_lints)]
33... |
34LL | | }
35 | |_^ not found in this scope
36
37error[E0658]: `#[prelude_import]` is for use by rustc only
38 --> $DIR/ice-fuzzy-provenance-casts-with-inner-attr.rs:9:1
39 |
40LL | / #![feature(strict_provenance_lints)]
41... |
42LL | | }
43 | |_^
44 |
45 = help: add `#![feature(prelude_import)]` to the crate attributes to enable
46 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
47
48error[E0601]: `main` function not found in crate `ice_fuzzy_provenance_casts_with_inner_attr`
49 --> $DIR/ice-fuzzy-provenance-casts-with-inner-attr.rs:23:2
50 |
51LL | }
52 | ^ consider adding a `main` function to `$DIR/ice-fuzzy-provenance-casts-with-inner-attr.rs`
53
54error[E0433]: cannot find type `Stars` in this scope
55 --> $DIR/ice-fuzzy-provenance-casts-with-inner-attr.rs:14:50
56 |
57LL | #![core::contracts::ensures(|ret| ret.is_none_or(Stars::is_valid))]
58 | ^^^^^ use of undeclared type `Stars`
59
60warning: strict provenance disallows casting integer `usize` to pointer `*const u32`
61 --> $DIR/ice-fuzzy-provenance-casts-with-inner-attr.rs:9:1
62 |
63LL | / #![feature(strict_provenance_lints)]
64... |
65LL | | }
66 | |_^
67 |
68 = 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
69 = note: requested on the command line with `-W fuzzy-provenance-casts`
70help: use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
71 |
72LL - #![feature(strict_provenance_lints)]
73LL -
74LL -
75LL -
76LL -
77LL - #![core::contracts::ensures(|ret| ret.is_none_or(Stars::is_valid))]
78LL -
79LL -
80LL -
81LL -
82LL - pub(super) fn foo() -> *const Ts {
83LL - unsafe {
84LL - let p2 = 0x52 as *const u32;
85LL - }
86LL - }
87LL + (...).with_addr()
88 |
89
90error: aborting due to 7 previous errors; 1 warning emitted
91
92Some errors have detailed explanations: E0425, E0433, E0601, E0658.
93For more information about an error, try `rustc --explain E0425`.