Skip to content

Commit 339cd14

Browse files
committed
Adds new lint arc_with_non_send_or_sync
1 parent 2360f80 commit 339cd14

File tree

6 files changed

+98
-0
lines changed

6 files changed

+98
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4628,6 +4628,7 @@ Released 2018-09-13
46284628
[`almost_complete_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range
46294629
[`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
46304630
[`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
4631+
[`arc_with_non_send_sync`]: https://rust-lang.github.io/rust-clippy/master/index.html#arc_with_non_send_sync
46314632
[`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects
46324633
[`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
46334634
[`as_ptr_cast_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_ptr_cast_mut
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use clippy_utils::diagnostics::span_lint_and_help;
2+
use clippy_utils::last_path_segment;
3+
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
4+
use if_chain::if_chain;
5+
6+
use rustc_hir::{Expr, ExprKind};
7+
use rustc_lint::LateContext;
8+
use rustc_lint::LateLintPass;
9+
use rustc_session::{declare_lint_pass, declare_tool_lint};
10+
use rustc_span::symbol::sym;
11+
12+
declare_clippy_lint! {
13+
/// ### What it does.
14+
/// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`.
15+
///
16+
/// ### Why is this bad?
17+
/// Wrapping a type in Arc doesn't add thread safety to the underlying data, so data races
18+
/// could occur when touching the underlying data.
19+
///
20+
/// ### Example.
21+
/// ```rust
22+
/// use std::cell::RefCell;
23+
/// use std::sync::Arc;
24+
///
25+
/// fn main() {
26+
/// // This is safe, as `i32` implements `Send` and `Sync`.
27+
/// let a = Arc::new(42);
28+
///
29+
/// // This is not safe, as `RefCell` does not implement `Sync`.
30+
/// let b = Arc::new(RefCell::new(42));
31+
/// }
32+
/// ```
33+
/// ```
34+
#[clippy::version = "1.72.0"]
35+
pub ARC_WITH_NON_SEND_SYNC,
36+
correctness,
37+
"using `Arc` with a type that does not implement `Send` or `Sync`"
38+
}
39+
declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]);
40+
41+
impl LateLintPass<'_> for ArcWithNonSendSync {
42+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
43+
let ty = cx.typeck_results().expr_ty(expr);
44+
if_chain! {
45+
if is_type_diagnostic_item(cx, ty, sym::Arc);
46+
if let ExprKind::Call(func, [arg]) = expr.kind;
47+
if let ExprKind::Path(func_path) = func.kind;
48+
if last_path_segment(&func_path).ident.name == sym::new;
49+
if let arg_ty = cx.typeck_results().expr_ty(arg);
50+
if !cx.tcx
51+
.lang_items()
52+
.sync_trait()
53+
.map_or(false, |id| implements_trait(cx, arg_ty, id, &[])) ||
54+
!cx.tcx
55+
.get_diagnostic_item(sym::Send)
56+
.map_or(false, |id| implements_trait(cx, arg_ty, id, &[]));
57+
58+
then {
59+
span_lint_and_help(
60+
cx,
61+
ARC_WITH_NON_SEND_SYNC,
62+
expr.span,
63+
"usage of `Arc<T>` where `T` is not `Send` or `Sync`",
64+
None,
65+
"consider using `Rc<T>` instead or wrapping `T` in a std::sync type like \
66+
Mutex<T>",
67+
);
68+
}
69+
}
70+
}
71+
}

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
4040
crate::allow_attributes::ALLOW_ATTRIBUTES_INFO,
4141
crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
4242
crate::approx_const::APPROX_CONSTANT_INFO,
43+
crate::arc_with_non_send_sync::ARC_WITH_NON_SEND_SYNC_INFO,
4344
crate::as_conversions::AS_CONVERSIONS_INFO,
4445
crate::asm_syntax::INLINE_ASM_X86_ATT_SYNTAX_INFO,
4546
crate::asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ mod renamed_lints;
6868
mod allow_attributes;
6969
mod almost_complete_range;
7070
mod approx_const;
71+
mod arc_with_non_send_sync;
7172
mod as_conversions;
7273
mod asm_syntax;
7374
mod assertions_on_constants;
@@ -1014,6 +1015,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10141015
store.register_late_pass(|_| Box::new(missing_fields_in_debug::MissingFieldsInDebug));
10151016
store.register_late_pass(|_| Box::new(endian_bytes::EndianBytes));
10161017
store.register_late_pass(|_| Box::new(redundant_type_annotations::RedundantTypeAnnotations));
1018+
store.register_late_pass(|_| Box::new(arc_with_non_send_sync::ArcWithNonSendSync));
10171019
// add lints here, do not remove this comment, it's used in `new_lint`
10181020
}
10191021

tests/ui/arc_with_non_send_sync.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![warn(clippy::arc_with_non_send_sync)]
2+
#![allow(unused_variables)]
3+
use std::cell::RefCell;
4+
use std::sync::{Arc, Mutex};
5+
6+
fn main() {
7+
// This is safe, as `i32` implements `Send` and `Sync`.
8+
let a = Arc::new(42);
9+
10+
// This is not safe, as `RefCell` does not implement `Sync`.
11+
let b = Arc::new(RefCell::new(42));
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: usage of `Arc<T>` where `T` is not `Send` or `Sync`
2+
--> $DIR/arc_with_non_send_sync.rs:11:13
3+
|
4+
LL | let b = Arc::new(RefCell::new(42));
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= help: consider using `Rc<T>` instead or wrapping `T` in a std::sync type like Mutex<T>
8+
= note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings`
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)