diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index bf81eb648f8ae..b1a52a1b9357a 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -332,7 +332,12 @@ impl<'ll> CodegenCx<'ll, '_> { debug!(?sym, ?fn_attrs); - let g = if def_id.is_local() && !self.tcx.is_foreign_item(def_id) { + let define_in_every_cgu_used = + fn_attrs.flags.contains(CodegenFnAttrFlags::DEFINE_IN_EVERY_CGU_USED); + + let g = if define_in_every_cgu_used + || (def_id.is_local() && !self.tcx.is_foreign_item(def_id)) + { if let Some(g) = self.get_declared_value(sym) { if self.val_ty(g) != self.type_ptr() { span_bug!(self.tcx.def_span(def_id), "Conflicting types for static"); @@ -345,6 +350,12 @@ impl<'ll> CodegenCx<'ll, '_> { llvm::set_visibility(g, llvm::Visibility::Hidden); } + if define_in_every_cgu_used { + self.instances.borrow_mut().insert(instance, g); + self.codegen_static_item(def_id); + return g; + } + g } else { check_and_apply_linkage(self, fn_attrs, llty, sym, def_id) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index aa55a0e0f1488..50097d6136cb1 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -467,6 +467,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { )) }) } + sym::define_in_every_cgu_used => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEFINE_IN_EVERY_CGU_USED + } _ => {} } } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index c117e0fcf7ccc..cb354b2ddf70d 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -619,6 +619,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::Yes, min_generic_const_args, experimental!(type_const), ), + // `#[unsafe(define_in_every_cgu_used)]` + gated!( + unsafe define_in_every_cgu_used, Normal, template!(Word), ErrorPreceding, + EncodeCrossCrate::No, experimental!(define_in_every_cgu_used), + ), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 6cdcf451f37e3..fb9fb108975e1 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -461,6 +461,8 @@ declare_features! ( /// Allows the use of default values on struct definitions and the construction of struct /// literals with the functional update syntax without a base. (unstable, default_field_values, "1.85.0", Some(132162)), + /// Allows using the `#[define_in_every_cgu_used]` attribute. + (unstable, define_in_every_cgu_used, "CURRENT_RUSTC_VERSION", Some(141339)), /// Allows using `#[deprecated_safe]` to deprecate the safeness of a function or trait (unstable, deprecated_safe, "1.61.0", Some(94978)), /// Allows having using `suggestion` in the `#[deprecated]` attribute. diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 00da1a6aeec7d..a04a3c90e1486 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -139,6 +139,9 @@ bitflags::bitflags! { const ALLOCATOR_ZEROED = 1 << 18; /// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function. const NO_BUILTINS = 1 << 19; + /// `#[define_in_every_cgu_used]`: indicates that the item + /// needs to be defined in every codegen unit where it gets used. + const DEFINE_IN_EVERY_CGU_USED = 1 << 20; } } rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 6d815e510ea20..ae40537f961cc 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -139,6 +139,10 @@ passes_debug_visualizer_placement = passes_debug_visualizer_unreadable = couldn't read {$file}: {$error} +passes_define_in_every_cgu_used_static = + attribute must be applied to a `static` variable + .label = but this is a {$target} + passes_deprecated = attribute is ignored here diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5c0d0cf47969a..2a8abb48c874b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -283,6 +283,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::pointee // FIXME(derive_coerce_pointee) | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) | sym::used // handled elsewhere to restrict to static items + | sym::define_in_every_cgu_used // handled elsewhere to restrict to static items | sym::repr // handled elsewhere to restrict to type decls items | sym::instruction_set // broken on stable!!! | sym::windows_subsystem // broken on stable!!! @@ -354,6 +355,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_repr(attrs, span, target, item, hir_id); self.check_used(attrs, target, span); + self.check_define_in_every_cgu_used(attrs, target, span); self.check_rustc_force_inline(hir_id, attrs, span, target); } @@ -2179,6 +2181,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + fn check_define_in_every_cgu_used( + &self, + attrs: &[Attribute], + target: Target, + target_span: Span, + ) { + for attr in attrs.iter().filter(|attr| attr.has_name(sym::define_in_every_cgu_used)) { + if target != Target::Static { + self.dcx().emit_err(errors::DefineInEveryCguUsedStatic { + attr_span: attr.span(), + span: target_span, + target: target.name(), + }); + } + } + } + /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. /// (Allows proc_macro functions) // FIXME(jdonszelmann): if possible, move to attr parsing diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 00682a9c7a794..ae31c66606f9d 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -619,6 +619,16 @@ pub(crate) struct UsedCompilerLinker { pub spans: Vec, } +#[derive(Diagnostic)] +#[diag(passes_define_in_every_cgu_used_static)] +pub(crate) struct DefineInEveryCguUsedStatic { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, + pub target: &'static str, +} + #[derive(Diagnostic)] #[diag(passes_allow_internal_unstable)] pub(crate) struct AllowInternalUnstable { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index efae6250b0720..858819bb14085 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -809,6 +809,7 @@ symbols! { // -------------------------- default_type_parameter_fallback, default_type_params, + define_in_every_cgu_used, define_opaque, delayed_bug_from_inside_query, deny, diff --git a/tests/ui/feature-gates/feature-gate-define-in-every-cgu-used.rs b/tests/ui/feature-gates/feature-gate-define-in-every-cgu-used.rs new file mode 100644 index 0000000000000..8eb33ccafd645 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-define-in-every-cgu-used.rs @@ -0,0 +1,4 @@ +#[define_in_every_cgu_used] //~ ERROR: the `#[define_in_every_cgu_used]` attribute is an experimental feature +static STATIC: i32 = 0; + +fn main() {}