Skip to content

Commit dd06c06

Browse files
committed
Auto merge of #5028 - krishna-veerareddy:issue-5026-mem-ordering-fences, r=phansch
Detect usage of invalid atomic ordering in memory fences Detect usage of `core::sync::atomic::{fence, compiler_fence}` with `Ordering::Relaxed` and suggest valid alternatives. changelog: Extend `invalid_atomic_ordering` to lint memory fences Fixes #5026
2 parents eca0d8e + 5e058f3 commit dd06c06

File tree

4 files changed

+104
-34
lines changed

4 files changed

+104
-34
lines changed

clippy_lints/src/atomic_ordering.rs

+64-33
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
88

99
declare_clippy_lint! {
1010
/// **What it does:** Checks for usage of invalid atomic
11-
/// ordering in Atomic*::{load, store} calls.
11+
/// ordering in atomic loads/stores and memory fences.
1212
///
1313
/// **Why is this bad?** Using an invalid atomic ordering
1414
/// will cause a panic at run-time.
@@ -17,7 +17,7 @@ declare_clippy_lint! {
1717
///
1818
/// **Example:**
1919
/// ```rust,no_run
20-
/// # use std::sync::atomic::{AtomicBool, Ordering};
20+
/// # use std::sync::atomic::{self, AtomicBool, Ordering};
2121
///
2222
/// let x = AtomicBool::new(true);
2323
///
@@ -26,10 +26,13 @@ declare_clippy_lint! {
2626
///
2727
/// x.store(false, Ordering::Acquire);
2828
/// x.store(false, Ordering::AcqRel);
29+
///
30+
/// atomic::fence(Ordering::Relaxed);
31+
/// atomic::compiler_fence(Ordering::Relaxed);
2932
/// ```
3033
pub INVALID_ATOMIC_ORDERING,
3134
correctness,
32-
"usage of invalid atomic ordering in atomic load/store calls"
35+
"usage of invalid atomic ordering in atomic loads/stores and memory fences"
3336
}
3437

3538
declare_lint_pass!(AtomicOrdering => [INVALID_ATOMIC_ORDERING]);
@@ -65,37 +68,65 @@ fn match_ordering_def_path(cx: &LateContext<'_, '_>, did: DefId, orderings: &[&s
6568
.any(|ordering| match_def_path(cx, did, &["core", "sync", "atomic", "Ordering", ordering]))
6669
}
6770

68-
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AtomicOrdering {
69-
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
70-
if_chain! {
71-
if let ExprKind::MethodCall(ref method_path, _, args) = &expr.kind;
72-
let method = method_path.ident.name.as_str();
73-
if type_is_atomic(cx, &args[0]);
74-
if method == "load" || method == "store";
75-
let ordering_arg = if method == "load" { &args[1] } else { &args[2] };
76-
if let ExprKind::Path(ref ordering_qpath) = ordering_arg.kind;
77-
if let Some(ordering_def_id) = cx.tables.qpath_res(ordering_qpath, ordering_arg.hir_id).opt_def_id();
78-
then {
79-
if method == "load" &&
80-
match_ordering_def_path(cx, ordering_def_id, &["Release", "AcqRel"]) {
81-
span_help_and_lint(
82-
cx,
83-
INVALID_ATOMIC_ORDERING,
84-
ordering_arg.span,
85-
"atomic loads cannot have `Release` and `AcqRel` ordering",
86-
"consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`"
87-
);
88-
} else if method == "store" &&
89-
match_ordering_def_path(cx, ordering_def_id, &["Acquire", "AcqRel"]) {
90-
span_help_and_lint(
91-
cx,
92-
INVALID_ATOMIC_ORDERING,
93-
ordering_arg.span,
94-
"atomic stores cannot have `Acquire` and `AcqRel` ordering",
95-
"consider using ordering modes `Release`, `SeqCst` or `Relaxed`"
96-
);
97-
}
71+
fn check_atomic_load_store(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
72+
if_chain! {
73+
if let ExprKind::MethodCall(ref method_path, _, args) = &expr.kind;
74+
let method = method_path.ident.name.as_str();
75+
if type_is_atomic(cx, &args[0]);
76+
if method == "load" || method == "store";
77+
let ordering_arg = if method == "load" { &args[1] } else { &args[2] };
78+
if let ExprKind::Path(ref ordering_qpath) = ordering_arg.kind;
79+
if let Some(ordering_def_id) = cx.tables.qpath_res(ordering_qpath, ordering_arg.hir_id).opt_def_id();
80+
then {
81+
if method == "load" &&
82+
match_ordering_def_path(cx, ordering_def_id, &["Release", "AcqRel"]) {
83+
span_help_and_lint(
84+
cx,
85+
INVALID_ATOMIC_ORDERING,
86+
ordering_arg.span,
87+
"atomic loads cannot have `Release` and `AcqRel` ordering",
88+
"consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`"
89+
);
90+
} else if method == "store" &&
91+
match_ordering_def_path(cx, ordering_def_id, &["Acquire", "AcqRel"]) {
92+
span_help_and_lint(
93+
cx,
94+
INVALID_ATOMIC_ORDERING,
95+
ordering_arg.span,
96+
"atomic stores cannot have `Acquire` and `AcqRel` ordering",
97+
"consider using ordering modes `Release`, `SeqCst` or `Relaxed`"
98+
);
9899
}
99100
}
100101
}
101102
}
103+
104+
fn check_memory_fence(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
105+
if_chain! {
106+
if let ExprKind::Call(ref func, ref args) = expr.kind;
107+
if let ExprKind::Path(ref func_qpath) = func.kind;
108+
if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id();
109+
if ["fence", "compiler_fence"]
110+
.iter()
111+
.any(|func| match_def_path(cx, def_id, &["core", "sync", "atomic", func]));
112+
if let ExprKind::Path(ref ordering_qpath) = &args[0].kind;
113+
if let Some(ordering_def_id) = cx.tables.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id();
114+
if match_ordering_def_path(cx, ordering_def_id, &["Relaxed"]);
115+
then {
116+
span_help_and_lint(
117+
cx,
118+
INVALID_ATOMIC_ORDERING,
119+
args[0].span,
120+
"memory fences cannot have `Relaxed` ordering",
121+
"consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`"
122+
);
123+
}
124+
}
125+
}
126+
127+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AtomicOrdering {
128+
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
129+
check_atomic_load_store(cx, expr);
130+
check_memory_fence(cx, expr);
131+
}
132+
}

src/lintlist/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,7 @@ pub const ALL_LINTS: [Lint; 348] = [
843843
Lint {
844844
name: "invalid_atomic_ordering",
845845
group: "correctness",
846-
desc: "usage of invalid atomic ordering in atomic load/store calls",
846+
desc: "usage of invalid atomic ordering in atomic loads/stores and memory fences",
847847
deprecation: None,
848848
module: "atomic_ordering",
849849
},

tests/ui/atomic_ordering_fence.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![warn(clippy::invalid_atomic_ordering)]
2+
3+
use std::sync::atomic::{compiler_fence, fence, Ordering};
4+
5+
fn main() {
6+
// Allowed fence ordering modes
7+
fence(Ordering::Acquire);
8+
fence(Ordering::Release);
9+
fence(Ordering::AcqRel);
10+
fence(Ordering::SeqCst);
11+
12+
// Disallowed fence ordering modes
13+
fence(Ordering::Relaxed);
14+
15+
compiler_fence(Ordering::Acquire);
16+
compiler_fence(Ordering::Release);
17+
compiler_fence(Ordering::AcqRel);
18+
compiler_fence(Ordering::SeqCst);
19+
compiler_fence(Ordering::Relaxed);
20+
}

tests/ui/atomic_ordering_fence.stderr

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error: memory fences cannot have `Relaxed` ordering
2+
--> $DIR/atomic_ordering_fence.rs:13:11
3+
|
4+
LL | fence(Ordering::Relaxed);
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings`
8+
= help: consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`
9+
10+
error: memory fences cannot have `Relaxed` ordering
11+
--> $DIR/atomic_ordering_fence.rs:19:20
12+
|
13+
LL | compiler_fence(Ordering::Relaxed);
14+
| ^^^^^^^^^^^^^^^^^
15+
|
16+
= help: consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`
17+
18+
error: aborting due to 2 previous errors
19+

0 commit comments

Comments
 (0)