Rollup merge of #153029 - nnethercote:disallowed-pass-by-ref, r=Urgau

Rename `rustc::pass_by_value` lint as `rustc::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)

r? @Urgau
This commit is contained in:
Jacob Pratt
2026-02-25 21:42:57 -05:00
committed by GitHub
10 changed files with 35 additions and 34 deletions
+4 -2
View File
@@ -757,9 +757,11 @@ fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
) -> 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 {
@@ -3,34 +3,34 @@
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<TyKind>`)
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<TyKind>`)
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 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>)
}
}
fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<String> {
fn path_for_rustc_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<String> {
if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind {
match path.res {
Res::Def(_, def_id) if find_attr!(cx.tcx, def_id, RustcPassByValue(_)) => {
+5 -5
View File
@@ -37,6 +37,7 @@
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 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 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 nonstandard_style::*;
use noop_method_call::*;
use opaque_hidden_inferred_bound::*;
use pass_by_value::*;
use precedence::*;
use ptr_nulls::*;
use redundant_semicolon::*;
@@ -659,8 +659,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());
@@ -678,7 +678,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),
+2 -2
View File
@@ -1807,10 +1807,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,
+3 -5
View File
@@ -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
+2 -1
View File
@@ -302,7 +302,8 @@ fn insert_unique(
/// 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,
@@ -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;
@@ -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
@@ -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]
@@ -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