Skip to content

Commit 75b29dd

Browse files
committed
Move global variables check to non_copy_const.rs
1 parent 2c457fd commit 75b29dd

File tree

6 files changed

+128
-91
lines changed

6 files changed

+128
-91
lines changed

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
192192
crate::functions::TOO_MANY_ARGUMENTS_INFO,
193193
crate::functions::TOO_MANY_LINES_INFO,
194194
crate::future_not_send::FUTURE_NOT_SEND_INFO,
195-
crate::global_variables::GLOBAL_VARIABLES_INFO,
196195
crate::if_let_mutex::IF_LET_MUTEX_INFO,
197196
crate::if_not_else::IF_NOT_ELSE_INFO,
198197
crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO,
@@ -557,6 +556,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
557556
crate::non_canonical_impls::NON_CANONICAL_PARTIAL_ORD_IMPL_INFO,
558557
crate::non_copy_const::BORROW_INTERIOR_MUTABLE_CONST_INFO,
559558
crate::non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST_INFO,
559+
crate::non_copy_const::GLOBAL_VARIABLES_INFO,
560560
crate::non_expressive_names::JUST_UNDERSCORES_AND_DIGITS_INFO,
561561
crate::non_expressive_names::MANY_SINGLE_CHAR_NAMES_INFO,
562562
crate::non_expressive_names::SIMILAR_NAMES_INFO,

clippy_lints/src/global_variables.rs

Lines changed: 0 additions & 67 deletions
This file was deleted.

clippy_lints/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ mod from_raw_with_void_ptr;
155155
mod from_str_radix_10;
156156
mod functions;
157157
mod future_not_send;
158-
mod global_variables;
159158
mod if_let_mutex;
160159
mod if_not_else;
161160
mod if_then_some_else_none;
@@ -944,6 +943,5 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
944943
store.register_late_pass(|_| Box::new(manual_option_as_slice::ManualOptionAsSlice::new(conf)));
945944
store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap));
946945
store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix));
947-
store.register_late_pass(|_| Box::new(global_variables::GlobalVariables));
948946
// add lints here, do not remove this comment, it's used in `new_lint`
949947
}

clippy_lints/src/non_copy_const.rs

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,51 @@ declare_clippy_lint! {
7474
"declaring `const` with interior mutability"
7575
}
7676

77+
declare_clippy_lint! {
78+
/// ### What it does
79+
///
80+
/// Checks whether a global variable defined.
81+
///
82+
/// ### Why restrict this?
83+
///
84+
/// - Global variables can be modified from any part of the program, making it difficult to
85+
/// track and control their state.
86+
/// - Global variables introduce implicit dependencies that are not visible in function
87+
/// signatures, making the code harder to understand and maintain.
88+
/// - Global variables introduce persistent state, complicating unit tests and making them
89+
/// prone to side effects.
90+
/// - Global variables create tight coupling between different parts of the program, making it
91+
/// harder to modify one part without affecting others.
92+
///
93+
/// ### Example
94+
///
95+
/// ```no_run
96+
/// use std::sync::Mutex;
97+
///
98+
/// struct State {}
99+
///
100+
/// static STATE: Mutex<State> = Mutex::new(State {});
101+
///
102+
/// fn foo() {
103+
/// // Access global variable `STATE`.
104+
/// }
105+
/// ```
106+
///
107+
/// Use instead:
108+
///
109+
/// ```no_run
110+
/// struct State {}
111+
///
112+
/// fn foo(state: &mut State) {
113+
/// // Access `state` argument instead of a global variable.
114+
/// }
115+
/// ```
116+
#[clippy::version = "1.88.0"]
117+
pub GLOBAL_VARIABLES,
118+
nursery,
119+
"declaring global variables"
120+
}
121+
77122
// FIXME: this is a correctness problem but there's no suitable
78123
// warn-by-default category.
79124
declare_clippy_lint! {
@@ -115,7 +160,8 @@ declare_clippy_lint! {
115160

116161
#[derive(Copy, Clone)]
117162
enum Source<'tcx> {
118-
Item { item: Span, ty: Ty<'tcx> },
163+
ConstItem { item: Span, ty: Ty<'tcx> },
164+
StaticItem { item: Span },
119165
Assoc { item: Span },
120166
Expr { expr: Span },
121167
}
@@ -124,11 +170,12 @@ impl Source<'_> {
124170
#[must_use]
125171
fn lint(&self) -> (&'static Lint, &'static str, Span) {
126172
match self {
127-
Self::Item { item, .. } | Self::Assoc { item, .. } => (
173+
Self::ConstItem { item, .. } | Self::Assoc { item, .. } => (
128174
DECLARE_INTERIOR_MUTABLE_CONST,
129175
"a `const` item should not be interior mutable",
130176
*item,
131177
),
178+
Self::StaticItem { item } => (GLOBAL_VARIABLES, "global variable should not be used", *item),
132179
Self::Expr { expr } => (
133180
BORROW_INTERIOR_MUTABLE_CONST,
134181
"a `const` item with interior mutability should not be borrowed",
@@ -145,7 +192,7 @@ fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) {
145192
return; // Don't give suggestions into macros.
146193
}
147194
match source {
148-
Source::Item { ty, .. } => {
195+
Source::ConstItem { ty, .. } => {
149196
let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else {
150197
return;
151198
};
@@ -157,6 +204,9 @@ fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) {
157204
);
158205
}
159206
},
207+
Source::StaticItem { .. } => {
208+
diag.help("consider passing this as function arguments or using a `thread_local`");
209+
},
160210
Source::Assoc { .. } => (),
161211
Source::Expr { .. } => {
162212
diag.help("assign this const to a local or static variable, and use the variable here");
@@ -169,7 +219,7 @@ pub struct NonCopyConst<'tcx> {
169219
interior_mut: InteriorMut<'tcx>,
170220
}
171221

172-
impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
222+
impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, GLOBAL_VARIABLES, BORROW_INTERIOR_MUTABLE_CONST]);
173223

174224
impl<'tcx> NonCopyConst<'tcx> {
175225
pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self {
@@ -310,14 +360,27 @@ impl<'tcx> NonCopyConst<'tcx> {
310360

311361
impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
312362
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
313-
if let ItemKind::Const(.., body_id) = it.kind {
314-
let ty = cx.tcx.type_of(it.owner_id).instantiate_identity();
315-
if !ignored_macro(cx, it)
316-
&& self.interior_mut.is_interior_mut_ty(cx, ty)
317-
&& Self::is_value_unfrozen_poly(cx, body_id, ty)
318-
{
319-
lint(cx, Source::Item { item: it.span, ty });
320-
}
363+
let tcx = cx.tcx;
364+
365+
match it.kind {
366+
ItemKind::Const(.., body_id) => {
367+
let ty = tcx.type_of(it.owner_id).instantiate_identity();
368+
if !ignored_macro(cx, it)
369+
&& self.interior_mut.is_interior_mut_ty(cx, ty)
370+
&& Self::is_value_unfrozen_poly(cx, body_id, ty)
371+
{
372+
lint(cx, Source::ConstItem { item: it.span, ty });
373+
}
374+
},
375+
ItemKind::Static(..) => {
376+
let ty = tcx.type_of(it.owner_id).instantiate_identity();
377+
378+
if !tcx.is_thread_local_static(it.owner_id.to_def_id()) && self.interior_mut.is_interior_mut_ty(cx, ty)
379+
{
380+
lint(cx, Source::StaticItem { item: it.span });
381+
}
382+
},
383+
_ => {},
321384
}
322385
}
323386

tests/ui/global_variables.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ macro_rules! define_global_variable_with_macro {
1313
};
1414
}
1515

16+
#[allow(clippy::missing_const_for_thread_local)]
1617
fn main() {
1718
define_global_variable_with_macro!();
1819

@@ -22,7 +23,29 @@ fn main() {
2223
static GLOBAL_VARIABLE_3: Mutex<u32> = Mutex::new(3);
2324
//~^ global_variables
2425

26+
static GLOBAL_VARIABLE_4: Option<AtomicU32> = Some(AtomicU32::new(0));
27+
//~^ global_variables
28+
2529
static NOT_GLOBAL_VARIABLE_0: u32 = 1;
26-
static NOT_GLOBAL_VARIABLE_1: Vec<AtomicU32> = Vec::new();
27-
static NOT_GLOBAL_VARIABLE_2: Vec<Mutex<u32>> = Vec::new();
30+
31+
// Does not work yet: ZST fields should be ignored.
32+
// static NOT_GLOBAL_VARIABLE_1: Vec<AtomicU32> = Vec::new();
33+
34+
// Does not work yet: Initializer with variant value that does not contain interior fields
35+
// should not be considered global variable.
36+
// static NOT_GLOBAL_VARIABLE_2: Option<AtomicU32> = None;
37+
38+
// Thread-local variables are ignored.
39+
thread_local! {
40+
static THREAD_LOCAL_VARIABLE_0: u32 = 0;
41+
static THREAD_LOCAL_VARIABLE_1: AtomicU32 = AtomicU32::new(0);
42+
static THREAD_LOCAL_VARIABLE_2: u32 = const { 0 };
43+
static THREAD_LOCAL_VARIABLE_3: AtomicU32 = const { AtomicU32::new(0) };
44+
45+
static THREAD_LOCAL_VARIABLE_4: () = {
46+
// Global variables inside a thread-local initializer are also considered.
47+
static GLOBAL_VARIABLE_IN_THREAD_LOCAL: AtomicU32 = AtomicU32::new(0);
48+
//~^ global_variables
49+
};
50+
}
2851
}

tests/ui/global_variables.stderr

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: found global variable
1+
error: global variable should not be used
22
--> tests/ui/global_variables.rs:8:9
33
|
44
LL | static GLOBAL_VARIABLE_0: AtomicU32 = AtomicU32::new(2);
@@ -11,7 +11,7 @@ LL | define_global_variable_with_macro!();
1111
= help: to override `-D warnings` add `#[allow(clippy::global_variables)]`
1212
= note: this error originates in the macro `define_global_variable_with_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
1313

14-
error: found global variable
14+
error: global variable should not be used
1515
--> tests/ui/global_variables.rs:11:9
1616
|
1717
LL | static GLOBAL_VARIABLE_1: Mutex<u32> = Mutex::new(3);
@@ -22,17 +22,37 @@ LL | define_global_variable_with_macro!();
2222
|
2323
= note: this error originates in the macro `define_global_variable_with_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
2424

25-
error: found global variable
26-
--> tests/ui/global_variables.rs:19:5
25+
error: global variable should not be used
26+
--> tests/ui/global_variables.rs:20:5
2727
|
2828
LL | static GLOBAL_VARIABLE_2: AtomicU32 = AtomicU32::new(2);
2929
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30+
|
31+
= help: consider passing this as function arguments or using a `thread_local`
3032

31-
error: found global variable
32-
--> tests/ui/global_variables.rs:22:5
33+
error: global variable should not be used
34+
--> tests/ui/global_variables.rs:23:5
3335
|
3436
LL | static GLOBAL_VARIABLE_3: Mutex<u32> = Mutex::new(3);
3537
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
38+
|
39+
= help: consider passing this as function arguments or using a `thread_local`
40+
41+
error: global variable should not be used
42+
--> tests/ui/global_variables.rs:26:5
43+
|
44+
LL | static GLOBAL_VARIABLE_4: Option<AtomicU32> = Some(AtomicU32::new(0));
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
46+
|
47+
= help: consider passing this as function arguments or using a `thread_local`
48+
49+
error: global variable should not be used
50+
--> tests/ui/global_variables.rs:47:13
51+
|
52+
LL | static GLOBAL_VARIABLE_IN_THREAD_LOCAL: AtomicU32 = AtomicU32::new(0);
53+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
54+
|
55+
= help: consider passing this as function arguments or using a `thread_local`
3656

37-
error: aborting due to 4 previous errors
57+
error: aborting due to 6 previous errors
3858

0 commit comments

Comments
 (0)