diff --git a/clippy_lints/src/missing_const_for_thread_local.rs b/clippy_lints/src/missing_const_for_thread_local.rs index 0c0548029f5e..08056ae5b2ff 100644 --- a/clippy_lints/src/missing_const_for_thread_local.rs +++ b/clippy_lints/src/missing_const_for_thread_local.rs @@ -122,6 +122,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForThreadLocal { && let ExprKind::Block(block, _) = body.value.kind && let Some(unpeeled) = block.expr && let ret_expr = peel_blocks(unpeeled) + // The initializer is already a `const` block: there is nothing to suggest. + // On targets without `#[thread_local]` (e.g. x86_64-pc-windows-gnu), the + // generated init fn is not a `const fn` even for `const` initializers, + // so the `is_const_fn` check above does not cover this case. + && !matches!(ret_expr.kind, ExprKind::ConstBlock(_)) // A common pattern around threadlocal! is to make the value unreachable // to force an initialization before usage // https://github.com/rust-lang/rust-clippy/issues/12637 diff --git a/tests/ui/missing_const_for_thread_local.fixed b/tests/ui/missing_const_for_thread_local.fixed index 2efe10c153da..8480d81dccd8 100644 --- a/tests/ui/missing_const_for_thread_local.fixed +++ b/tests/ui/missing_const_for_thread_local.fixed @@ -69,6 +69,14 @@ fn issue_12637() { println!("{}", STATE_12637_UNREACHABLE.get()); } +fn issue_17566() { + // On targets without native `#[thread_local]`, a `const` initializer expands to a + // non-`const` init fn, which used to slip past the `is_const_fn` guard and lint here. + thread_local! { + static STATE_17566: Cell> = const { Cell::new(None) }; + } +} + #[clippy::msrv = "1.58"] fn f() { thread_local! { diff --git a/tests/ui/missing_const_for_thread_local.rs b/tests/ui/missing_const_for_thread_local.rs index 119cc5a99fa0..4ea1f80867a1 100644 --- a/tests/ui/missing_const_for_thread_local.rs +++ b/tests/ui/missing_const_for_thread_local.rs @@ -69,6 +69,14 @@ fn issue_12637() { println!("{}", STATE_12637_UNREACHABLE.get()); } +fn issue_17566() { + // On targets without native `#[thread_local]`, a `const` initializer expands to a + // non-`const` init fn, which used to slip past the `is_const_fn` guard and lint here. + thread_local! { + static STATE_17566: Cell> = const { Cell::new(None) }; + } +} + #[clippy::msrv = "1.58"] fn f() { thread_local! {