Skip to content

Commit ca499a4

Browse files
committed
Add unnecessary_refs lint
1 parent cdd8af2 commit ca499a4

File tree

4 files changed

+85
-0
lines changed

4 files changed

+85
-0
lines changed

compiler/rustc_lint/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,9 @@ lint_unnameable_test_items = cannot test inner items
894894
lint_unnecessary_qualification = unnecessary qualification
895895
.suggestion = remove the unnecessary path segments
896896
897+
lint_unnecessary_refs = creating a intermediate reference implies aliasing requirements even when immediately casting to raw pointers
898+
.suggestion = consider using `&raw const` for a safer and more explicit raw pointer
899+
897900
lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
898901
.note_duplicated_fn = the address of the same function can vary between different codegen units
899902
.note_deduplicated_fn = furthermore, different functions could have the same address after being merged together

compiler/rustc_lint/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ mod static_mut_refs;
7878
mod traits;
7979
mod types;
8080
mod unit_bindings;
81+
mod unnecessary_refs;
8182
mod unqualified_local_imports;
8283
mod unused;
8384

@@ -119,6 +120,7 @@ use static_mut_refs::*;
119120
use traits::*;
120121
use types::*;
121122
use unit_bindings::*;
123+
use unnecessary_refs::*;
122124
use unqualified_local_imports::*;
123125
use unused::*;
124126

@@ -244,6 +246,7 @@ late_lint_methods!(
244246
IfLetRescope: IfLetRescope::default(),
245247
StaticMutRefs: StaticMutRefs,
246248
UnqualifiedLocalImports: UnqualifiedLocalImports,
249+
UnecessaryRefs: UnecessaryRefs,
247250
]
248251
]
249252
);

compiler/rustc_lint/src/lints.rs

+17
Original file line numberDiff line numberDiff line change
@@ -3163,3 +3163,20 @@ pub(crate) struct ReservedMultihash {
31633163
#[suggestion(code = " ", applicability = "machine-applicable")]
31643164
pub suggestion: Span,
31653165
}
3166+
3167+
#[derive(LintDiagnostic)]
3168+
#[diag(lint_unnecessary_refs)]
3169+
pub(crate) struct UnnecessaryRefs<'a> {
3170+
#[subdiagnostic]
3171+
pub suggestion: UnnecessaryRefsSuggestion<'a>,
3172+
}
3173+
3174+
#[derive(Subdiagnostic)]
3175+
#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")]
3176+
pub(crate) struct UnnecessaryRefsSuggestion<'a> {
3177+
#[suggestion_part(code = "&raw {mutbl} ")]
3178+
pub left: Span,
3179+
#[suggestion_part(code = "")]
3180+
pub right: Span,
3181+
pub mutbl: &'a str,
3182+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use rustc_ast::{BorrowKind, UnOp};
2+
use rustc_hir::{Expr, ExprKind, TyKind};
3+
use rustc_session::{declare_lint, declare_lint_pass};
4+
5+
use crate::lints::{UnnecessaryRefs, UnnecessaryRefsSuggestion};
6+
use crate::{LateContext, LateLintPass, LintContext};
7+
8+
declare_lint! {
9+
/// The `unnecessary_refs` lint checks for unnecessary references.
10+
///
11+
/// ### Example
12+
///
13+
/// ```rust
14+
/// fn via_ref(x: *const (i32, i32)) -> *const i32 {
15+
/// unsafe { &(*x).0 as *const i32 }
16+
/// }
17+
///
18+
/// fn main() {
19+
/// let x = 0;
20+
/// let _r = via_ref(&x);
21+
/// }
22+
/// ```
23+
///
24+
/// {{produces}}
25+
///
26+
/// ### Explanation
27+
///
28+
/// Creating unnecessary references is discouraged because it can reduce
29+
/// readability, introduce performance overhead, and lead to undefined
30+
/// behavior if the reference is unaligned or uninitialized. Avoiding them
31+
/// ensures safer and more efficient code.
32+
pub UNNECESSARY_REFS,
33+
Warn,
34+
"creating unecessary reference is discouraged"
35+
}
36+
37+
declare_lint_pass!(UnecessaryRefs => [UNNECESSARY_REFS]);
38+
39+
impl<'tcx> LateLintPass<'tcx> for UnecessaryRefs {
40+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
41+
if let ExprKind::Cast(exp, ty) = expr.kind
42+
&& let ExprKind::AddrOf(bk, mutbl, addr_of_exp) = exp.kind
43+
&& matches!(bk, BorrowKind::Ref)
44+
&& let ExprKind::Field(exp, _) = addr_of_exp.kind
45+
&& let ExprKind::Unary(uo, _) = exp.kind
46+
&& matches!(uo, UnOp::Deref)
47+
&& let TyKind::Ptr(_) = ty.kind
48+
{
49+
cx.emit_span_lint(
50+
UNNECESSARY_REFS,
51+
expr.span,
52+
UnnecessaryRefs {
53+
suggestion: UnnecessaryRefsSuggestion {
54+
left: expr.span.until(addr_of_exp.span),
55+
right: addr_of_exp.span.shrink_to_hi().until(ty.span.shrink_to_hi()),
56+
mutbl: mutbl.ptr_str(),
57+
},
58+
},
59+
);
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)