@@ -9,7 +9,7 @@ use rustc_session::declare_tool_lint;
99
1010declare_clippy_lint ! {
1111 /// **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 .
1313 ///
1414 /// **Why is this bad?** Using an invalid atomic ordering
1515 /// will cause a panic at run-time.
@@ -18,7 +18,7 @@ declare_clippy_lint! {
1818 ///
1919 /// **Example:**
2020 /// ```rust,no_run
21- /// # use std::sync::atomic::{AtomicBool, Ordering};
21+ /// # use std::sync::atomic::{self, AtomicBool, Ordering};
2222 ///
2323 /// let x = AtomicBool::new(true);
2424 ///
@@ -27,10 +27,13 @@ declare_clippy_lint! {
2727 ///
2828 /// x.store(false, Ordering::Acquire);
2929 /// x.store(false, Ordering::AcqRel);
30+ ///
31+ /// atomic::fence(Ordering::Relaxed);
32+ /// atomic::compiler_fence(Ordering::Relaxed);
3033 /// ```
3134 pub INVALID_ATOMIC_ORDERING ,
3235 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 "
3437}
3538
3639declare_lint_pass ! ( AtomicOrdering => [ INVALID_ATOMIC_ORDERING ] ) ;
@@ -66,37 +69,65 @@ fn match_ordering_def_path(cx: &LateContext<'_, '_>, did: DefId, orderings: &[&s
6669 . any ( |ordering| match_def_path ( cx, did, & [ "core" , "sync" , "atomic" , "Ordering" , ordering] ) )
6770}
6871
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+ ) ;
99100 }
100101 }
101102 }
102103}
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