diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs index 3322d56513bbe..8fd87e565e4e7 100644 --- a/compiler/rustc_codegen_gcc/src/mono_item.rs +++ b/compiler/rustc_codegen_gcc/src/mono_item.rs @@ -6,6 +6,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; +use rustc_hir::def::DefKind; use crate::attributes; use crate::base; @@ -17,7 +18,10 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn predefine_static(&self, def_id: DefId, _linkage: Linkage, visibility: Visibility, symbol_name: &str) { let attrs = self.tcx.codegen_fn_attrs(def_id); let instance = Instance::mono(self.tcx, def_id); - let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); + let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() }; + // Nested statics do not have a type, so pick a random type and let `define_static` figure out + // the llvm type from the actual evaluated initializer. + let ty = if nested { self.tcx.types.unit} else { instance.ty(self.tcx, ty::ParamEnv::reveal_all()) }; let gcc_type = self.layout_of(ty).gcc_type(self); let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index e39f2b6cd6196..39ad025e58a10 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -9,6 +9,7 @@ use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; use rustc_codegen_ssa::traits::*; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::interpret::{ @@ -229,9 +230,17 @@ impl<'ll> CodegenCx<'ll, '_> { pub(crate) fn get_static(&self, def_id: DefId) -> &'ll Value { let instance = Instance::mono(self.tcx, def_id); trace!(?instance); - let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); - trace!(?ty); - let llty = self.layout_of(ty).llvm_type(self); + + let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() }; + // Nested statics do not have a type, so pick a random type and let `define_static` figure out + // the llvm type from the actual evaluated initializer. + let llty = if nested { + self.type_i8() + } else { + let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); + trace!(?ty); + self.layout_of(ty).llvm_type(self) + }; self.get_static_inner(def_id, llty) } @@ -346,6 +355,9 @@ impl<'ll> CodegenCx<'ll, '_> { fn codegen_static_item(&self, def_id: DefId) { unsafe { + assert!( + llvm::LLVMGetInitializer(self.statics.borrow().get(&def_id).unwrap()).is_none() + ); let attrs = self.tcx.codegen_fn_attrs(def_id); let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else { diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index ab09ce2c2b749..ca8853b689b35 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -5,7 +5,9 @@ use crate::errors::SymbolAlreadyDefined; use crate::llvm; use crate::type_of::LayoutLlvmExt; use rustc_codegen_ssa::traits::*; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_middle::bug; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; @@ -21,7 +23,14 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> { symbol_name: &str, ) { let instance = Instance::mono(self.tcx, def_id); - let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); + let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() }; + // Nested statics do not have a type, so pick a random type and let `define_static` figure out + // the llvm type from the actual evaluated initializer. + let ty = if nested { + self.tcx.types.unit + } else { + instance.ty(self.tcx, ty::ParamEnv::reveal_all()) + }; let llty = self.layout_of(ty).llvm_type(self); let g = self.define_global(symbol_name, llty).unwrap_or_else(|| { diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 58916c6001f9b..64ace89b01968 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -59,7 +59,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( }; let ret = if let InternKind::Static(_) = intern_kind { - create_static_alloc(ecx, cid.instance.def_id(), layout)? + create_static_alloc(ecx, cid.instance.def_id().expect_local(), layout)? } else { ecx.allocate(layout, MemoryKind::Stack)? }; @@ -381,10 +381,10 @@ pub fn eval_in_interpreter<'mir, 'tcx>( Ok(mplace) => { // Since evaluation had no errors, validate the resulting constant. - // Temporarily allow access to the static_root_alloc_id for the purpose of validation. - let static_root_alloc_id = ecx.machine.static_root_alloc_id.take(); + // Temporarily allow access to the static_root_ids for the purpose of validation. + let static_root_ids = ecx.machine.static_root_ids.take(); let validation = const_validate_mplace(&ecx, &mplace, cid); - ecx.machine.static_root_alloc_id = static_root_alloc_id; + ecx.machine.static_root_ids = static_root_ids; let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 946ffc05cc14f..40d848dab9702 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::IndexEntry; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_hir::LangItem; use rustc_middle::mir; use rustc_middle::mir::AssertMessage; @@ -60,7 +61,19 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> { pub(super) check_alignment: CheckAlignment, /// Used to prevent reads from a static's base allocation, as that may allow for self-initialization. - pub(crate) static_root_alloc_id: Option, + pub(crate) static_root_ids: Option<(AllocId, LocalDefId)>, +} + +pub trait HasStaticRootDefId { + /// Returns the `DefId` of the static item that is currently being evaluated. + /// Used for interning to be able to handle nested allocations. + fn static_def_id(&self) -> Option; +} + +impl HasStaticRootDefId for CompileTimeInterpreter<'_, '_> { + fn static_def_id(&self) -> Option { + Some(self.static_root_ids?.1) + } } #[derive(Copy, Clone)] @@ -94,7 +107,7 @@ impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { stack: Vec::new(), can_access_mut_global, check_alignment, - static_root_alloc_id: None, + static_root_ids: None, } } } @@ -751,7 +764,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ecx: &InterpCx<'mir, 'tcx, Self>, alloc_id: AllocId, ) -> InterpResult<'tcx> { - if Some(alloc_id) == ecx.machine.static_root_alloc_id { + if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) { Err(ConstEvalErrKind::RecursiveStatic.into()) } else { Ok(()) diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 959ec2ca86558..d9476b9150211 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -13,12 +13,16 @@ //! but that would require relying on type information, and given how many ways Rust has to lie //! about type information, we want to avoid doing that. +use hir::def::DefKind; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; -use rustc_middle::mir::interpret::{CtfeProvenance, InterpResult}; +use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult}; +use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::TyAndLayout; +use rustc_span::def_id::LocalDefId; +use rustc_span::sym; use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy}; use crate::const_eval; @@ -33,7 +37,7 @@ pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine< FrameExtra = (), AllocExtra = (), MemoryMap = FxIndexMap, Allocation)>, - >; + > + const_eval::HasStaticRootDefId; /// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory. /// @@ -67,10 +71,34 @@ fn intern_shallow<'rt, 'mir, 'tcx, T, M: CompileTimeMachine<'mir, 'tcx, T>>( } // link the alloc id to the actual allocation let alloc = ecx.tcx.mk_const_alloc(alloc); - ecx.tcx.set_alloc_id_memory(alloc_id, alloc); + if let Some(static_id) = ecx.machine.static_def_id() { + intern_as_new_static(ecx.tcx, static_id, alloc_id, alloc); + } else { + ecx.tcx.set_alloc_id_memory(alloc_id, alloc); + } Ok(alloc.0.0.provenance().ptrs().iter().map(|&(_, prov)| prov)) } +/// Creates a new `DefId` and feeds all the right queries to make this `DefId` +/// appear as if it were a user-written `static` (though it has no HIR). +fn intern_as_new_static<'tcx>( + tcx: TyCtxtAt<'tcx>, + static_id: LocalDefId, + alloc_id: AllocId, + alloc: ConstAllocation<'tcx>, +) { + let feed = tcx.create_def( + static_id, + sym::nested, + DefKind::Static { mt: alloc.0.mutability, nested: true }, + ); + tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); + feed.codegen_fn_attrs(tcx.codegen_fn_attrs(static_id).clone()); + feed.eval_static_initializer(Ok(alloc)); + feed.generics_of(tcx.generics_of(static_id).clone()); + feed.def_ident_span(tcx.def_ident_span(static_id)); + feed.explicit_predicates_of(tcx.explicit_predicates_of(static_id)); +} /// How a constant value should be interned. #[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)] pub enum InternKind { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 3b2208b8caa8a..8c36393301f36 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -14,6 +14,7 @@ use std::ptr; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_hir::def::DefKind; use rustc_middle::mir::display_allocation; use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; use rustc_target::abi::{Align, HasDataLayout, Size}; @@ -744,19 +745,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // be held throughout the match. match self.tcx.try_get_global_alloc(id) { Some(GlobalAlloc::Static(def_id)) => { - assert!(self.tcx.is_static(def_id)); // Thread-local statics do not have a constant address. They *must* be accessed via // `ThreadLocalRef`; we can never have a pointer to them as a regular constant value. assert!(!self.tcx.is_thread_local_static(def_id)); - // Use size and align of the type. - let ty = self - .tcx - .type_of(def_id) - .no_bound_vars() - .expect("statics should not have generic parameters"); - let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); - assert!(layout.is_sized()); - (layout.size, layout.align.abi, AllocKind::LiveData) + + let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { + bug!("GlobalAlloc::Static is not a static") + }; + + let (size, align) = if nested { + // Nested anonymous statics are untyped, so let's get their + // size and alignment from the allocaiton itself. This always + // succeeds, as the query is fed at DefId creation time, so no + // evaluation actually occurs. + let alloc = self.tcx.eval_static_initializer(def_id).unwrap(); + (alloc.0.size(), alloc.0.align) + } else { + // Use size and align of the type. + let ty = self + .tcx + .type_of(def_id) + .no_bound_vars() + .expect("statics should not have generic parameters"); + let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); + assert!(layout.is_sized()); + (layout.size, layout.align.abi) + }; + (size, align, AllocKind::LiveData) } Some(GlobalAlloc::Memory(alloc)) => { // Need to duplicate the logic here, because the global allocations have diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 2a13671a82978..e7566886857dd 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,11 +1,11 @@ use crate::const_eval::CompileTimeEvalContext; use crate::interpret::{MemPlaceMeta, MemoryKind}; +use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::interpret::{AllocId, Allocation, InterpResult, Pointer}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; -use rustc_span::def_id::DefId; use std::ops::ControlFlow; use super::MPlaceTy; @@ -89,13 +89,13 @@ pub(crate) fn take_static_root_alloc<'mir, 'tcx: 'mir>( pub(crate) fn create_static_alloc<'mir, 'tcx: 'mir>( ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, - static_def_id: DefId, + static_def_id: LocalDefId, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let alloc = Allocation::try_uninit(layout.size, layout.align.abi)?; - let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id); - assert_eq!(ecx.machine.static_root_alloc_id, None); - ecx.machine.static_root_alloc_id = Some(alloc_id); + let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into()); + assert_eq!(ecx.machine.static_root_ids, None); + ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none()); Ok(ecx.ptr_with_meta_to_mplace(Pointer::from(alloc_id).into(), MemPlaceMeta::None, layout)) } diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 63dee3a5738ce..361ca167010b3 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -250,6 +250,9 @@ impl DefKind { | DefKind::AssocTy | DefKind::TyParam | DefKind::ExternCrate => DefPathData::TypeNs(name), + // It's not exactly an anon const, but wrt DefPathData, there + // is not difference. + DefKind::Static { nested: true, .. } => DefPathData::AnonConst, DefKind::Fn | DefKind::Const | DefKind::ConstParam diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 34f58e466f95f..58367cc2f2a0f 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -882,7 +882,7 @@ fn should_encode_attrs(def_kind: DefKind) -> bool { | DefKind::AssocTy | DefKind::Fn | DefKind::Const - | DefKind::Static { .. } + | DefKind::Static { nested: false, .. } | DefKind::AssocFn | DefKind::AssocConst | DefKind::Macro(_) @@ -903,6 +903,7 @@ fn should_encode_attrs(def_kind: DefKind) -> bool { | DefKind::InlineConst | DefKind::OpaqueTy | DefKind::LifetimeParam + | DefKind::Static { nested: true, .. } | DefKind::GlobalAsm => false, } } @@ -956,7 +957,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { | DefKind::AssocTy | DefKind::Fn | DefKind::Const - | DefKind::Static { .. } + | DefKind::Static { nested: false, .. } | DefKind::Ctor(..) | DefKind::AssocFn | DefKind::AssocConst @@ -969,6 +970,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { | DefKind::LifetimeParam | DefKind::AnonConst | DefKind::InlineConst + | DefKind::Static { nested: true, .. } | DefKind::OpaqueTy | DefKind::GlobalAsm | DefKind::Impl { .. } @@ -1148,7 +1150,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::Field | DefKind::Fn | DefKind::Const - | DefKind::Static { .. } + | DefKind::Static { nested: false, .. } | DefKind::TyAlias | DefKind::ForeignTy | DefKind::Impl { .. } @@ -1190,6 +1192,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::Mod | DefKind::ForeignMod | DefKind::Macro(..) + | DefKind::Static { nested: true, .. } | DefKind::Use | DefKind::LifetimeParam | DefKind::GlobalAsm diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 5be09b06d9e4b..ad46ee45d89a9 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -130,7 +130,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{HashMapExt, Lock}; use rustc_data_structures::tiny_list::TinyList; use rustc_errors::ErrorGuaranteed; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::HashStable; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_serialize::{Decodable, Encodable}; @@ -627,6 +627,16 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Freezes an `AllocId` created with `reserve` by pointing it at a static item. Trying to + /// call this function twice, even with the same `DefId` will ICE the compiler. + pub fn set_nested_alloc_id_static(self, id: AllocId, def_id: LocalDefId) { + if let Some(old) = + self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Static(def_id.to_def_id())) + { + bug!("tried to set allocation ID {id:?}, but it was already existing as {old:#?}"); + } + } + /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called /// twice for the same `(AllocId, Allocation)` pair. fn set_alloc_id_same_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index e87bc581e6eab..f9e4b0e8f158c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1080,6 +1080,7 @@ rustc_queries! { } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// Evaluates const items or anonymous constants @@ -1238,6 +1239,7 @@ rustc_queries! { arena_cache cache_on_disk_if { def_id.is_local() } separate_provide_extern + feedable } query asm_target_features(def_id: DefId) -> &'tcx FxIndexSet { diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 9dc7a50eca9f5..ab621842f1886 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -2,6 +2,7 @@ //! //! Currently, this pass only propagates scalar values. +use rustc_const_eval::const_eval::HasStaticRootDefId; use rustc_const_eval::interpret::{ ImmTy, Immediate, InterpCx, OpTy, PlaceTy, PointerArithmetic, Projectable, }; @@ -889,6 +890,12 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> { pub(crate) struct DummyMachine; +impl HasStaticRootDefId for DummyMachine { + fn static_def_id(&self) -> Option { + None + } +} + impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachine { rustc_const_eval::interpret::compile_time_machine!(<'mir, 'tcx>); type MemoryKind = !; diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 8c1105cf8339e..f08934a94a7c7 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -380,8 +380,12 @@ fn collect_items_rec<'tcx>( // Sanity check whether this ended up being collected accidentally debug_assert!(should_codegen_locally(tcx, &instance)); - let ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); - visit_drop_use(tcx, ty, true, starting_item.span, &mut used_items); + let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() }; + // Nested statics have no type. + if !nested { + let ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); + visit_drop_use(tcx, ty, true, starting_item.span, &mut used_items); + } recursion_depth_reset = None; diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 9a22f5a1b63ac..d95acbd75b30e 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -13,6 +13,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::privacy::{self, Level}; +use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::CrateType; @@ -197,10 +198,20 @@ impl<'tcx> ReachableContext<'tcx> { // Reachable constants will be inlined into other crates // unconditionally, so we need to make sure that their // contents are also reachable. - hir::ItemKind::Const(_, _, init) | hir::ItemKind::Static(_, _, init) => { + hir::ItemKind::Const(_, _, init) => { self.visit_nested_body(init); } + // Reachable statics are inlined if read from another constant or static + // in other crates. Additionally anonymous nested statics may be created + // when evaluating a static, so preserve those, too. + hir::ItemKind::Static(_, _, init) => { + self.visit_nested_body(init); + if let Ok(alloc) = self.tcx.eval_static_initializer(item.owner_id.def_id) { + self.propagate_statics_from_alloc(item.owner_id.def_id, alloc); + } + } + // These are normal, nothing reachable about these // inherently and their children are already in the // worklist, as determined by the privacy pass @@ -266,6 +277,27 @@ impl<'tcx> ReachableContext<'tcx> { } } } + + /// Finds anonymous nested statics created for nested allocations. + fn propagate_statics_from_alloc(&mut self, root: LocalDefId, alloc: ConstAllocation<'tcx>) { + if !self.any_library { + return; + } + for (_, prov) in alloc.0.provenance().ptrs().iter() { + match self.tcx.global_alloc(prov.alloc_id()) { + GlobalAlloc::Static(def_id) => { + if let Some(def_id) = def_id.as_local() + && self.tcx.local_parent(def_id) == root + && self.reachable_symbols.insert(def_id) + && let Ok(alloc) = self.tcx.eval_static_initializer(def_id) + { + self.propagate_statics_from_alloc(root, alloc); + } + } + GlobalAlloc::Function(_) | GlobalAlloc::VTable(_, _) | GlobalAlloc::Memory(_) => {} + } + } + } } fn check_item<'tcx>( diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 46472a131ff4b..795d874db774f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1109,6 +1109,7 @@ symbols! { negative_bounds, negative_impls, neon, + nested, never, never_patterns, never_type, diff --git a/tests/ui/consts/const-mut-refs-crate.rs b/tests/ui/consts/const-mut-refs-crate.rs index 96df2cefce27b..c540cbf2b5c51 100644 --- a/tests/ui/consts/const-mut-refs-crate.rs +++ b/tests/ui/consts/const-mut-refs-crate.rs @@ -24,12 +24,11 @@ static ONE_STEP_ABOVE: &i32 = *DOUBLE_REF; pub fn main() { unsafe { - assert_ne!(FOO as *const i32, BAR as *const i32); + assert_eq!(FOO as *const i32, BAR as *const i32); assert_eq!(INNER_MOD_FOO as *const i32, INNER_MOD_BAR as *const i32); assert_eq!(LOCAL_FOO as *const i32, LOCAL_BAR as *const i32); assert_eq!(*DOUBLE_REF as *const i32, ONE_STEP_ABOVE as *const i32); - // bug! - assert_ne!(FOO as *const i32, COPY_OF_REMOTE_FOO as *const i32); + assert_eq!(FOO as *const i32, COPY_OF_REMOTE_FOO as *const i32); } }