@@ -8,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
88
99declare_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
3538declare_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+ }
0 commit comments