From 8eed8bd7bbf80ad06fc3262824aa39dd335eaa36 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 24 Feb 2026 08:42:04 +1100 Subject: [PATCH] Rename `pass_by_value` lint as `disallowed_pass_by_ref`. The name `pass_by_value` is completely wrong. The lint actually checks for the use of pass by reference for types marked with `rustc_pass_by_value`. The hardest part of this was choosing the new name. The `disallowed_` part of the name closely matches the following clippy lints: - `disallowed_macros` - `disallowed_methods` - `disallowed_names` - `disallowed_script_idents` - `disallowed_types` The `pass_by_value` part of the name aligns with the following clippy lints: - `needless_pass_by_value` - `needless_pass_by_ref_mut` - `trivially_copy_pass_by_ref` - `large_types_passed_by_value` (less so) --- compiler/rustc_ast/src/visit.rs | 6 +++-- ..._by_value.rs => disallowed_pass_by_ref.rs} | 24 +++++++++---------- compiler/rustc_lint/src/lib.rs | 10 ++++---- compiler/rustc_lint/src/lints.rs | 4 ++-- compiler/rustc_macros/src/query.rs | 8 +++---- compiler/rustc_mir_transform/src/gvn.rs | 3 ++- .../internal-lints/rustc_pass_by_value.rs | 4 ++-- .../internal-lints/rustc_pass_by_value.stderr | 4 ++-- .../rustc_pass_by_value_self.rs | 2 +- .../rustc_pass_by_value_self.stderr | 4 ++-- 10 files changed, 35 insertions(+), 34 deletions(-) rename compiler/rustc_lint/src/{pass_by_value.rs => disallowed_pass_by_ref.rs} (75%) diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 8556e8288670f..ff389607457d4 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -757,9 +757,11 @@ macro_rules! common_visitor_and_walkers { ) -> V::Result; } - // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier + // This is only used by the MutVisitor. We include this symmetry here to make writing other + // functions easier. $(${ignore($lt)} - #[expect(unused, rustc::pass_by_value)] + #[cfg_attr(not(bootstrap), expect(unused, rustc::disallowed_pass_by_ref))] + #[cfg_attr(bootstrap, expect(unused, rustc::pass_by_value))] #[inline] )? fn visit_span<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, span: &$($lt)? $($mut)? Span) -> V::Result { diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/disallowed_pass_by_ref.rs similarity index 75% rename from compiler/rustc_lint/src/pass_by_value.rs rename to compiler/rustc_lint/src/disallowed_pass_by_ref.rs index 5a4eb29433815..2a572a5a76bdb 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/disallowed_pass_by_ref.rs @@ -3,34 +3,34 @@ use rustc_hir::{self as hir, AmbigArg, GenericArg, PathSegment, QPath, TyKind, f use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::lints::PassByValueDiag; +use crate::lints::DisallowedPassByRefDiag; use crate::{LateContext, LateLintPass, LintContext}; declare_tool_lint! { - /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to - /// always be passed by value. This is usually used for types that are thin wrappers around - /// references, so there is no benefit to an extra layer of indirection. (Example: `Ty` which - /// is a reference to an `Interned`) - pub rustc::PASS_BY_VALUE, + /// The `disallowed_pass_by_ref` lint detects if types marked with `#[rustc_pass_by_value]` are + /// passed by reference. Types with this marker are usually thin wrappers around references, so + /// there is no benefit to an extra layer of indirection. (Example: `Ty` which is a reference + /// to an `Interned`) + pub rustc::DISALLOWED_PASS_BY_REF, Warn, "pass by reference of a type flagged as `#[rustc_pass_by_value]`", report_in_external_macro: true } -declare_lint_pass!(PassByValue => [PASS_BY_VALUE]); +declare_lint_pass!(DisallowedPassByRef => [DISALLOWED_PASS_BY_REF]); -impl<'tcx> LateLintPass<'tcx> for PassByValue { +impl<'tcx> LateLintPass<'tcx> for DisallowedPassByRef { fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) { match &ty.kind { TyKind::Ref(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => { if cx.tcx.trait_impl_of_assoc(ty.hir_id.owner.to_def_id()).is_some() { return; } - if let Some(t) = path_for_pass_by_value(cx, inner_ty) { + if let Some(t) = path_for_rustc_pass_by_value(cx, inner_ty) { cx.emit_span_lint( - PASS_BY_VALUE, + DISALLOWED_PASS_BY_REF, ty.span, - PassByValueDiag { ty: t, suggestion: ty.span }, + DisallowedPassByRefDiag { ty: t, suggestion: ty.span }, ); } } @@ -39,7 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue { } } -fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option { +fn path_for_rustc_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option { if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind { match path.res { Res::Def(_, def_id) if find_attr!(cx.tcx, def_id, RustcPassByValue(_)) => { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index a5c3a889826c7..4c847671a070d 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -37,6 +37,7 @@ mod context; mod dangling; mod default_could_be_derived; mod deref_into_dyn_supertrait; +mod disallowed_pass_by_ref; mod drop_forget_useless; mod early; mod enum_intrinsics_non_enums; @@ -65,7 +66,6 @@ mod non_local_def; mod nonstandard_style; mod noop_method_call; mod opaque_hidden_inferred_bound; -mod pass_by_value; mod passes; mod precedence; mod ptr_nulls; @@ -88,6 +88,7 @@ use builtin::*; use dangling::*; use default_could_be_derived::DefaultCouldBeDerived; use deref_into_dyn_supertrait::*; +use disallowed_pass_by_ref::*; use drop_forget_useless::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use for_loops_over_fallibles::*; @@ -109,7 +110,6 @@ use non_local_def::*; use nonstandard_style::*; use noop_method_call::*; use opaque_hidden_inferred_bound::*; -use pass_by_value::*; use precedence::*; use ptr_nulls::*; use redundant_semicolon::*; @@ -657,8 +657,8 @@ fn register_internals(store: &mut LintStore) { store.register_late_mod_pass(|_| Box::new(TypeIr)); store.register_lints(&BadOptAccess::lint_vec()); store.register_late_mod_pass(|_| Box::new(BadOptAccess)); - store.register_lints(&PassByValue::lint_vec()); - store.register_late_mod_pass(|_| Box::new(PassByValue)); + store.register_lints(&DisallowedPassByRef::lint_vec()); + store.register_late_mod_pass(|_| Box::new(DisallowedPassByRef)); store.register_lints(&SpanUseEqCtxt::lint_vec()); store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt)); store.register_lints(&SymbolInternStringLiteral::lint_vec()); @@ -676,7 +676,7 @@ fn register_internals(store: &mut LintStore) { LintId::of(POTENTIAL_QUERY_INSTABILITY), LintId::of(UNTRACKED_QUERY_INFORMATION), LintId::of(USAGE_OF_TY_TYKIND), - LintId::of(PASS_BY_VALUE), + LintId::of(DISALLOWED_PASS_BY_REF), LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), LintId::of(USAGE_OF_QUALIFIED_TY), LintId::of(NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT), diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 5627f34f82e97..b2ee01a9a0ee6 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1806,10 +1806,10 @@ pub(crate) struct AmbiguousNegativeLiteralsCurrentBehaviorSuggestion { pub end_span: Span, } -// pass_by_value.rs +// disallowed_pass_by_ref.rs #[derive(LintDiagnostic)] #[diag("passing `{$ty}` by reference")] -pub(crate) struct PassByValueDiag { +pub(crate) struct DisallowedPassByRefDiag { pub ty: String, #[suggestion("try passing by value", code = "{ty}", applicability = "maybe-incorrect")] pub suggestion: Span, diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 346604a46ef7d..9799d5b430868 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -293,12 +293,10 @@ fn make_helpers_for_query(query: &Query, streams: &mut HelperTokenStreams) { // Generate a function to check whether we should cache the query to disk, for some key. if let Some(CacheOnDiskIf { block, .. }) = modifiers.cache_on_disk_if.as_ref() { - // `pass_by_value`: some keys are marked with `rustc_pass_by_value`, but we take keys by - // reference here. - // FIXME: `pass_by_value` is badly named; `allow(rustc::pass_by_value)` actually means - // "allow pass by reference of `rustc_pass_by_value` types". + // `disallowed_pass_by_ref` is needed because some keys are `rustc_pass_by_value`. streams.cache_on_disk_if_fns_stream.extend(quote! { - #[allow(unused_variables, rustc::pass_by_value)] + #[cfg_attr(not(bootstrap), allow(unused_variables, rustc::disallowed_pass_by_ref))] + #[cfg_attr(bootstrap, allow(unused_variables, rustc::pass_by_value))] #[inline] pub fn #erased_name<'tcx>(tcx: TyCtxt<'tcx>, #key_pat: &#key_ty) -> bool #block diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 4e38b9dd6534b..0ef9a1348527d 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -300,7 +300,8 @@ impl<'a, 'tcx> ValueSet<'a, 'tcx> { /// Insert a `(Value, Ty)` pair to be deduplicated. /// Returns `true` as second tuple field if this value did not exist previously. - #[allow(rustc::pass_by_value)] // closures take `&VnIndex` + #[cfg_attr(not(bootstrap), allow(rustc::disallowed_pass_by_ref))] // closures take `&VnIndex` + #[cfg_attr(bootstrap, allow(rustc::pass_by_value))] fn insert(&mut self, ty: Ty<'tcx>, value: Value<'a, 'tcx>) -> (VnIndex, bool) { debug_assert!(match value { Value::Opaque(_) | Value::Address { .. } => false, diff --git a/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.rs b/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.rs index 06d2232be5179..42d75be966840 100644 --- a/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.rs +++ b/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.rs @@ -1,8 +1,8 @@ //@ compile-flags: -Z unstable-options - +//@ ignore-stage1 (this can be removed when nightly goes to 1.96) #![feature(rustc_attrs)] #![feature(rustc_private)] -#![deny(rustc::pass_by_value)] +#![deny(rustc::disallowed_pass_by_ref)] #![allow(unused)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr b/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr index 69cf20656d7b1..b2906ea1e1195 100644 --- a/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr +++ b/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr @@ -7,8 +7,8 @@ LL | ty_ref: &Ty<'_>, note: the lint level is defined here --> $DIR/rustc_pass_by_value.rs:5:9 | -LL | #![deny(rustc::pass_by_value)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustc::disallowed_pass_by_ref)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: passing `TyCtxt<'_>` by reference --> $DIR/rustc_pass_by_value.rs:16:18 diff --git a/tests/ui/internal-lints/rustc_pass_by_value_self.rs b/tests/ui/internal-lints/rustc_pass_by_value_self.rs index d2e0e272025f6..695c617d32f82 100644 --- a/tests/ui/internal-lints/rustc_pass_by_value_self.rs +++ b/tests/ui/internal-lints/rustc_pass_by_value_self.rs @@ -5,7 +5,7 @@ // Considering that all other `internal-lints` are tested here // this seems like the cleaner solution though. #![feature(rustc_attrs)] -#![deny(rustc::pass_by_value)] +#![deny(rustc::disallowed_pass_by_ref)] #![allow(unused)] #[rustc_pass_by_value] diff --git a/tests/ui/internal-lints/rustc_pass_by_value_self.stderr b/tests/ui/internal-lints/rustc_pass_by_value_self.stderr index fb39ed60b8235..d9e9f7e48506b 100644 --- a/tests/ui/internal-lints/rustc_pass_by_value_self.stderr +++ b/tests/ui/internal-lints/rustc_pass_by_value_self.stderr @@ -7,8 +7,8 @@ LL | fn by_ref(&self) {} note: the lint level is defined here --> $DIR/rustc_pass_by_value_self.rs:8:9 | -LL | #![deny(rustc::pass_by_value)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustc::disallowed_pass_by_ref)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: passing `Ty<'tcx>` by reference --> $DIR/rustc_pass_by_value_self.rs:30:21