Skip to content

Commit 60258b0

Browse files
committed
Auto merge of #10898 - avborhanian:master, r=Manishearth,Centri3
Adds new lint `arc_with_non_send_or_sync` Fixes #653 Adds a new lint to check for uses of non-Send/Sync types within Arc. ``` changelog: [`arc_with_non_send_sync`]: Added a lint to detect uses of non-Send/Sync types within Arc. ```
2 parents 177c6fe + 20548eb commit 60258b0

File tree

6 files changed

+104
-0
lines changed

6 files changed

+104
-0
lines changed

CHANGELOG.md

+1
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
+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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_middle::ty;
10+
use rustc_session::{declare_lint_pass, declare_tool_lint};
11+
use rustc_span::symbol::sym;
12+
13+
declare_clippy_lint! {
14+
/// ### What it does.
15+
/// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`.
16+
///
17+
/// ### Why is this bad?
18+
/// Wrapping a type in Arc doesn't add thread safety to the underlying data, so data races
19+
/// could occur when touching the underlying data.
20+
///
21+
/// ### Example
22+
/// ```rust
23+
/// # use std::cell::RefCell;
24+
/// # use std::sync::Arc;
25+
///
26+
/// fn main() {
27+
/// // This is safe, as `i32` implements `Send` and `Sync`.
28+
/// let a = Arc::new(42);
29+
///
30+
/// // This is not safe, as `RefCell` does not implement `Sync`.
31+
/// let b = Arc::new(RefCell::new(42));
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 !matches!(arg_ty.kind(), ty::Param(_));
51+
if !cx.tcx
52+
.lang_items()
53+
.sync_trait()
54+
.map_or(false, |id| implements_trait(cx, arg_ty, id, &[])) ||
55+
!cx.tcx
56+
.get_diagnostic_item(sym::Send)
57+
.map_or(false, |id| implements_trait(cx, arg_ty, id, &[]));
58+
59+
then {
60+
span_lint_and_help(
61+
cx,
62+
ARC_WITH_NON_SEND_SYNC,
63+
expr.span,
64+
"usage of `Arc<T>` where `T` is not `Send` or `Sync`",
65+
None,
66+
"consider using `Rc<T>` instead or wrapping `T` in a std::sync type like \
67+
`Mutex<T>`",
68+
);
69+
}
70+
}
71+
}
72+
}

clippy_lints/src/declared_lints.rs

+1
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

+2
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

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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 foo<T>(x: T) {
7+
// Should not lint - purposefully ignoring generic args.
8+
let a = Arc::new(x);
9+
}
10+
11+
fn main() {
12+
// This is safe, as `i32` implements `Send` and `Sync`.
13+
let a = Arc::new(42);
14+
15+
// This is not safe, as `RefCell` does not implement `Sync`.
16+
let b = Arc::new(RefCell::new(42));
17+
}
+11
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:16: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)