@@ -9,7 +9,7 @@ use rustc_session::declare_tool_lint;
9
9
10
10
declare_clippy_lint ! {
11
11
/// **What it does:** Checks for usage of invalid atomic
12
- /// ordering in Atomic*::{load, store} calls .
12
+ /// ordering in atomic loads/stores and memory fences .
13
13
///
14
14
/// **Why is this bad?** Using an invalid atomic ordering
15
15
/// will cause a panic at run-time.
@@ -18,7 +18,7 @@ declare_clippy_lint! {
18
18
///
19
19
/// **Example:**
20
20
/// ```rust,no_run
21
- /// # use std::sync::atomic::{AtomicBool, Ordering};
21
+ /// # use std::sync::atomic::{self, AtomicBool, Ordering};
22
22
///
23
23
/// let x = AtomicBool::new(true);
24
24
///
@@ -27,10 +27,13 @@ declare_clippy_lint! {
27
27
///
28
28
/// x.store(false, Ordering::Acquire);
29
29
/// x.store(false, Ordering::AcqRel);
30
+ ///
31
+ /// atomic::fence(Ordering::Relaxed);
32
+ /// atomic::compiler_fence(Ordering::Relaxed);
30
33
/// ```
31
34
pub INVALID_ATOMIC_ORDERING ,
32
35
correctness,
33
- "usage of invalid atomic ordering in atomic load/store calls "
36
+ "usage of invalid atomic ordering in atomic loads/stores and memory fences "
34
37
}
35
38
36
39
declare_lint_pass ! ( AtomicOrdering => [ INVALID_ATOMIC_ORDERING ] ) ;
@@ -66,37 +69,65 @@ fn match_ordering_def_path(cx: &LateContext<'_, '_>, did: DefId, orderings: &[&s
66
69
. any ( |ordering| match_def_path ( cx, did, & [ "core" , "sync" , "atomic" , "Ordering" , ordering] ) )
67
70
}
68
71
69
- impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for AtomicOrdering {
70
- fn check_expr ( & mut self , cx : & LateContext < ' a , ' tcx > , expr : & ' tcx Expr < ' _ > ) {
71
- if_chain ! {
72
- if let ExprKind :: MethodCall ( ref method_path, _, args) = & expr. kind;
73
- let method = method_path. ident. name. as_str( ) ;
74
- if type_is_atomic( cx, & args[ 0 ] ) ;
75
- if method == "load" || method == "store" ;
76
- let ordering_arg = if method == "load" { & args[ 1 ] } else { & args[ 2 ] } ;
77
- if let ExprKind :: Path ( ref ordering_qpath) = ordering_arg. kind;
78
- if let Some ( ordering_def_id) = cx. tables. qpath_res( ordering_qpath, ordering_arg. hir_id) . opt_def_id( ) ;
79
- then {
80
- if method == "load" &&
81
- match_ordering_def_path( cx, ordering_def_id, & [ "Release" , "AcqRel" ] ) {
82
- span_help_and_lint(
83
- cx,
84
- INVALID_ATOMIC_ORDERING ,
85
- ordering_arg. span,
86
- "atomic loads cannot have `Release` and `AcqRel` ordering" ,
87
- "consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`"
88
- ) ;
89
- } else if method == "store" &&
90
- match_ordering_def_path( cx, ordering_def_id, & [ "Acquire" , "AcqRel" ] ) {
91
- span_help_and_lint(
92
- cx,
93
- INVALID_ATOMIC_ORDERING ,
94
- ordering_arg. span,
95
- "atomic stores cannot have `Acquire` and `AcqRel` ordering" ,
96
- "consider using ordering modes `Release`, `SeqCst` or `Relaxed`"
97
- ) ;
98
- }
72
+ fn check_atomic_load_store ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > ) {
73
+ if_chain ! {
74
+ if let ExprKind :: MethodCall ( ref method_path, _, args) = & expr. kind;
75
+ let method = method_path. ident. name. as_str( ) ;
76
+ if type_is_atomic( cx, & args[ 0 ] ) ;
77
+ if method == "load" || method == "store" ;
78
+ let ordering_arg = if method == "load" { & args[ 1 ] } else { & args[ 2 ] } ;
79
+ if let ExprKind :: Path ( ref ordering_qpath) = ordering_arg. kind;
80
+ if let Some ( ordering_def_id) = cx. tables. qpath_res( ordering_qpath, ordering_arg. hir_id) . opt_def_id( ) ;
81
+ then {
82
+ if method == "load" &&
83
+ match_ordering_def_path( cx, ordering_def_id, & [ "Release" , "AcqRel" ] ) {
84
+ span_help_and_lint(
85
+ cx,
86
+ INVALID_ATOMIC_ORDERING ,
87
+ ordering_arg. span,
88
+ "atomic loads cannot have `Release` and `AcqRel` ordering" ,
89
+ "consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`"
90
+ ) ;
91
+ } else if method == "store" &&
92
+ match_ordering_def_path( cx, ordering_def_id, & [ "Acquire" , "AcqRel" ] ) {
93
+ span_help_and_lint(
94
+ cx,
95
+ INVALID_ATOMIC_ORDERING ,
96
+ ordering_arg. span,
97
+ "atomic stores cannot have `Acquire` and `AcqRel` ordering" ,
98
+ "consider using ordering modes `Release`, `SeqCst` or `Relaxed`"
99
+ ) ;
99
100
}
100
101
}
101
102
}
102
103
}
104
+
105
+ fn check_memory_fence ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > ) {
106
+ if_chain ! {
107
+ if let ExprKind :: Call ( ref func, ref args) = expr. kind;
108
+ if let ExprKind :: Path ( ref func_qpath) = func. kind;
109
+ if let Some ( def_id) = cx. tables. qpath_res( func_qpath, func. hir_id) . opt_def_id( ) ;
110
+ if [ "fence" , "compiler_fence" ]
111
+ . iter( )
112
+ . any( |func| match_def_path( cx, def_id, & [ "core" , "sync" , "atomic" , func] ) ) ;
113
+ if let ExprKind :: Path ( ref ordering_qpath) = & args[ 0 ] . kind;
114
+ if let Some ( ordering_def_id) = cx. tables. qpath_res( ordering_qpath, args[ 0 ] . hir_id) . opt_def_id( ) ;
115
+ if match_ordering_def_path( cx, ordering_def_id, & [ "Relaxed" ] ) ;
116
+ then {
117
+ span_help_and_lint(
118
+ cx,
119
+ INVALID_ATOMIC_ORDERING ,
120
+ args[ 0 ] . span,
121
+ "memory fences cannot have `Relaxed` ordering" ,
122
+ "consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`"
123
+ ) ;
124
+ }
125
+ }
126
+ }
127
+
128
+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for AtomicOrdering {
129
+ fn check_expr ( & mut self , cx : & LateContext < ' a , ' tcx > , expr : & ' tcx Expr < ' _ > ) {
130
+ check_atomic_load_store ( cx, expr) ;
131
+ check_memory_fence ( cx, expr) ;
132
+ }
133
+ }
0 commit comments