From d4c2c736098d9cdf7de322bf7295dcaf372459a4 Mon Sep 17 00:00:00 2001 From: zhiping <18238287433@163.com> Date: Tue, 25 Nov 2025 10:06:03 +0800 Subject: [PATCH 1/2] fix: Disallow #[global_allocator] with #[thread_local] This change adds a check in the #[global_allocator] macro to prevent simultaneous use with #[thread_local], which is logically incompatible. The global allocator must be a single instance across all threads. Fixes #85517 --- compiler/rustc_builtin_macros/messages.ftl | 6 ++++++ compiler/rustc_builtin_macros/src/errors.rs | 8 ++++++++ compiler/rustc_builtin_macros/src/global_allocator.rs | 10 +++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index c9dd92ff2f243..ee3a2ae510fad 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -306,3 +306,9 @@ builtin_macros_unexpected_lit = expected path to a trait, found literal .other = for example, write `#[derive(Debug)]` for `Debug` builtin_macros_unnameable_test_items = cannot test inner items + +# New: Disallow simultaneous use of #[global_allocator] and #[thread_local] +builtin_macros_global_allocator_thread_local_conflict = + `#[global_allocator]` cannot be used with `#[thread_local]` on the same static + .note = The global allocator must be a single, program-wide instance. + .help = Remove either the `#[global_allocator]` or `#[thread_local]` attribute. diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index dd6a5a20ccebc..db0f419e3a576 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -150,6 +150,14 @@ pub(crate) struct AllocMustStatics { pub(crate) span: Span, } +/// The `#[global_allocator]` attribute cannot be used with `#[thread_local]`. +#[derive(Diagnostic)] +#[diag(builtin_macros_global_allocator_thread_local_conflict)] +pub(crate) struct GlobalAllocatorThreadLocalConflict { + #[primary_span] + pub(crate) span: Span, +} + pub(crate) use autodiff::*; mod autodiff { diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index e69f0838f22e9..24bdf0b30e1e6 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -37,7 +37,15 @@ pub(crate) fn expand( ecx.dcx().emit_err(errors::AllocMustStatics { span: item.span() }); return vec![orig_item]; }; - + + // Check if the static item also has the `#[thread_local]` attribute, which is incompatible with `#[global_allocator]`. + if item.attrs.iter().any(|a| a.path().is_ident(sym::thread_local)) { + ecx.dcx().emit_err(errors::GlobalAllocatorThreadLocalConflict { + span: item.span, + }); + return vec![orig_item]; + } + // Generate a bunch of new items using the AllocFnFactory let span = ecx.with_def_site_ctxt(item.span); let f = AllocFnFactory { span, ty_span, global: ident, cx: ecx }; From 1dc61b9c2f0054bb35682ca526555bdd30955900 Mon Sep 17 00:00:00 2001 From: zhiping <18238287433@163.com> Date: Tue, 25 Nov 2025 12:42:43 +0800 Subject: [PATCH 2/2] fix: Disallow #[global_allocator] with #[thread_local] This change adds a check in the #[global_allocator] macro to prevent simultaneous use with #[thread_local], which is logically incompatible. The global allocator must be a single instance across all threads. --- compiler/rustc_builtin_macros/messages.ftl | 1 - compiler/rustc_builtin_macros/src/errors.rs | 1 - compiler/rustc_builtin_macros/src/global_allocator.rs | 3 --- 3 files changed, 5 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index ee3a2ae510fad..a65bbf1830f5f 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -307,7 +307,6 @@ builtin_macros_unexpected_lit = expected path to a trait, found literal builtin_macros_unnameable_test_items = cannot test inner items -# New: Disallow simultaneous use of #[global_allocator] and #[thread_local] builtin_macros_global_allocator_thread_local_conflict = `#[global_allocator]` cannot be used with `#[thread_local]` on the same static .note = The global allocator must be a single, program-wide instance. diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index db0f419e3a576..6107ad16f5148 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -150,7 +150,6 @@ pub(crate) struct AllocMustStatics { pub(crate) span: Span, } -/// The `#[global_allocator]` attribute cannot be used with `#[thread_local]`. #[derive(Diagnostic)] #[diag(builtin_macros_global_allocator_thread_local_conflict)] pub(crate) struct GlobalAllocatorThreadLocalConflict { diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 24bdf0b30e1e6..22502a9a6f4d1 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -37,15 +37,12 @@ pub(crate) fn expand( ecx.dcx().emit_err(errors::AllocMustStatics { span: item.span() }); return vec![orig_item]; }; - - // Check if the static item also has the `#[thread_local]` attribute, which is incompatible with `#[global_allocator]`. if item.attrs.iter().any(|a| a.path().is_ident(sym::thread_local)) { ecx.dcx().emit_err(errors::GlobalAllocatorThreadLocalConflict { span: item.span, }); return vec![orig_item]; } - // Generate a bunch of new items using the AllocFnFactory let span = ecx.with_def_site_ctxt(item.span); let f = AllocFnFactory { span, ty_span, global: ident, cx: ecx };