mirror of https://github.com/rust-lang/rust.git
Auto merge of #121644 - oli-obk:unique_static_innards2, r=RalfJung,nnethercote
Ensure nested allocations in statics neither get deduplicated nor duplicated This PR generates new `DefId`s for nested allocations in static items and feeds all the right queries to make the compiler believe these are regular `static` items. I chose this design, because all other designs are fragile and make the compiler horribly complex for such a niche use case. At present this wrecks incremental compilation performance *in case nested allocations exist* (because any query creating a `DefId` will be recomputed and never loaded from the cache). This will be resolved later in https://github.com/rust-lang/rust/pull/115613 . All other statics are unaffected by this change and will not have performance regressions (heh, famous last words) This PR contains various smaller refactorings that can be pulled out into separate PRs. It is best reviewed commit-by-commit. The last commit is where the actual magic happens. r? `@RalfJung` on the const interner and engine changes fixes https://github.com/rust-lang/rust/issues/79738
This commit is contained in:
commit
3b85d2c7fc
|
@ -196,7 +196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
.get_partial_res(sym.id)
|
||||
.and_then(|res| res.full_res())
|
||||
.and_then(|res| match res {
|
||||
Res::Def(DefKind::Static(_), def_id) => Some(def_id),
|
||||
Res::Def(DefKind::Static { .. }, def_id) => Some(def_id),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
|
|||
global_value
|
||||
}
|
||||
|
||||
fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
|
||||
fn codegen_static(&self, def_id: DefId) {
|
||||
let attrs = self.tcx.codegen_fn_attrs(def_id);
|
||||
|
||||
let value = match codegen_static_initializer(&self, def_id) {
|
||||
|
@ -92,7 +92,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
|
|||
|
||||
// As an optimization, all shared statics which do not have interior
|
||||
// mutability are placed into read-only memory.
|
||||
if !is_mutable && self.type_is_freeze(ty) {
|
||||
if !self.tcx.static_mutability(def_id).unwrap().is_mut() && self.type_is_freeze(ty) {
|
||||
#[cfg(feature = "master")]
|
||||
global.global_set_readonly();
|
||||
}
|
||||
|
@ -349,7 +349,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(
|
|||
cx.const_struct(&llvals, true)
|
||||
}
|
||||
|
||||
pub fn codegen_static_initializer<'gcc, 'tcx>(
|
||||
fn codegen_static_initializer<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
def_id: DefId,
|
||||
) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#[cfg(feature = "master")]
|
||||
use gccjit::{FnAttribute, VarAttribute};
|
||||
use rustc_codegen_ssa::traits::PreDefineMethods;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::mono::{Linkage, Visibility};
|
||||
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
|
||||
|
@ -23,7 +25,14 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
) {
|
||||
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 dummy type and let `codegen_static` figure out
|
||||
// the gcc 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);
|
||||
|
|
|
@ -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::{
|
||||
|
@ -17,7 +18,7 @@ use rustc_middle::mir::interpret::{
|
|||
};
|
||||
use rustc_middle::mir::mono::MonoItem;
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::{self, Instance, Ty};
|
||||
use rustc_middle::ty::{self, Instance};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::config::Lto;
|
||||
use rustc_target::abi::{
|
||||
|
@ -114,7 +115,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
|
|||
cx.const_struct(&llvals, true)
|
||||
}
|
||||
|
||||
pub fn codegen_static_initializer<'ll, 'tcx>(
|
||||
fn codegen_static_initializer<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
def_id: DefId,
|
||||
) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> {
|
||||
|
@ -147,11 +148,10 @@ fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align:
|
|||
fn check_and_apply_linkage<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
attrs: &CodegenFnAttrs,
|
||||
ty: Ty<'tcx>,
|
||||
llty: &'ll Type,
|
||||
sym: &str,
|
||||
def_id: DefId,
|
||||
) -> &'ll Value {
|
||||
let llty = cx.layout_of(ty).llvm_type(cx);
|
||||
if let Some(linkage) = attrs.import_linkage {
|
||||
debug!("get_static: sym={} linkage={:?}", sym, linkage);
|
||||
|
||||
|
@ -226,9 +226,28 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn get_static(&self, def_id: DefId) -> &'ll Value {
|
||||
let instance = Instance::mono(self.tcx, def_id);
|
||||
if let Some(&g) = self.instances.borrow().get(&instance) {
|
||||
trace!(?instance);
|
||||
|
||||
let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() };
|
||||
// Nested statics do not have a type, so pick a dummy type and let `codegen_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)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, llty))]
|
||||
pub(crate) fn get_static_inner(&self, def_id: DefId, llty: &'ll Type) -> &'ll Value {
|
||||
if let Some(&g) = self.instances.borrow().get(&Instance::mono(self.tcx, def_id)) {
|
||||
trace!("used cached value");
|
||||
return g;
|
||||
}
|
||||
|
||||
|
@ -240,14 +259,12 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
statics defined in the same CGU, but did not for `{def_id:?}`"
|
||||
);
|
||||
|
||||
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
|
||||
let sym = self.tcx.symbol_name(instance).name;
|
||||
let sym = self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name;
|
||||
let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
|
||||
|
||||
debug!("get_static: sym={} instance={:?} fn_attrs={:?}", sym, instance, fn_attrs);
|
||||
debug!(?sym, ?fn_attrs);
|
||||
|
||||
let g = if def_id.is_local() && !self.tcx.is_foreign_item(def_id) {
|
||||
let llty = self.layout_of(ty).llvm_type(self);
|
||||
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");
|
||||
|
@ -264,7 +281,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
|
||||
g
|
||||
} else {
|
||||
check_and_apply_linkage(self, fn_attrs, ty, sym, def_id)
|
||||
check_and_apply_linkage(self, fn_attrs, llty, sym, def_id)
|
||||
};
|
||||
|
||||
// Thread-local statics in some other crate need to *always* be linked
|
||||
|
@ -332,34 +349,18 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
self.instances.borrow_mut().insert(instance, g);
|
||||
self.instances.borrow_mut().insert(Instance::mono(self.tcx, def_id), g);
|
||||
g
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
|
||||
fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value {
|
||||
if let Some(&gv) = self.const_globals.borrow().get(&cv) {
|
||||
unsafe {
|
||||
// Upgrade the alignment in cases where the same constant is used with different
|
||||
// alignment requirements
|
||||
let llalign = align.bytes() as u32;
|
||||
if llalign > llvm::LLVMGetAlignment(gv) {
|
||||
llvm::LLVMSetAlignment(gv, llalign);
|
||||
}
|
||||
}
|
||||
return gv;
|
||||
}
|
||||
let gv = self.static_addr_of_mut(cv, align, kind);
|
||||
unsafe {
|
||||
llvm::LLVMSetGlobalConstant(gv, True);
|
||||
}
|
||||
self.const_globals.borrow_mut().insert(cv, gv);
|
||||
gv
|
||||
}
|
||||
|
||||
fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
|
||||
fn codegen_static_item(&self, def_id: DefId) {
|
||||
unsafe {
|
||||
assert!(
|
||||
llvm::LLVMGetInitializer(
|
||||
self.instances.borrow().get(&Instance::mono(self.tcx, 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 {
|
||||
|
@ -368,13 +369,11 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
|
|||
};
|
||||
let alloc = alloc.inner();
|
||||
|
||||
let g = self.get_static(def_id);
|
||||
|
||||
let val_llty = self.val_ty(v);
|
||||
|
||||
let instance = Instance::mono(self.tcx, def_id);
|
||||
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
|
||||
let llty = self.layout_of(ty).llvm_type(self);
|
||||
let g = self.get_static_inner(def_id, val_llty);
|
||||
let llty = self.val_ty(g);
|
||||
|
||||
let g = if val_llty == llty {
|
||||
g
|
||||
} else {
|
||||
|
@ -409,16 +408,15 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
|
|||
self.statics_to_rauw.borrow_mut().push((g, new_g));
|
||||
new_g
|
||||
};
|
||||
set_global_alignment(self, g, self.align_of(ty));
|
||||
set_global_alignment(self, g, alloc.align);
|
||||
llvm::LLVMSetInitializer(g, v);
|
||||
|
||||
if self.should_assume_dso_local(g, true) {
|
||||
llvm::LLVMRustSetDSOLocal(g, true);
|
||||
}
|
||||
|
||||
// As an optimization, all shared statics which do not have interior
|
||||
// mutability are placed into read-only memory.
|
||||
if !is_mutable && self.type_is_freeze(ty) {
|
||||
// Forward the allocation's mutability (picked by the const interner) to LLVM.
|
||||
if alloc.mutability.is_not() {
|
||||
llvm::LLVMSetGlobalConstant(g, llvm::True);
|
||||
}
|
||||
|
||||
|
@ -541,6 +539,32 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
|
||||
fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value {
|
||||
if let Some(&gv) = self.const_globals.borrow().get(&cv) {
|
||||
unsafe {
|
||||
// Upgrade the alignment in cases where the same constant is used with different
|
||||
// alignment requirements
|
||||
let llalign = align.bytes() as u32;
|
||||
if llalign > llvm::LLVMGetAlignment(gv) {
|
||||
llvm::LLVMSetAlignment(gv, llalign);
|
||||
}
|
||||
}
|
||||
return gv;
|
||||
}
|
||||
let gv = self.static_addr_of_mut(cv, align, kind);
|
||||
unsafe {
|
||||
llvm::LLVMSetGlobalConstant(gv, True);
|
||||
}
|
||||
self.const_globals.borrow_mut().insert(cv, gv);
|
||||
gv
|
||||
}
|
||||
|
||||
fn codegen_static(&self, def_id: DefId) {
|
||||
self.codegen_static_item(def_id)
|
||||
}
|
||||
|
||||
/// Add a global value to a list to be stored in the `llvm.used` variable, an array of ptr.
|
||||
fn add_used_global(&self, global: &'ll Value) {
|
||||
|
|
|
@ -26,6 +26,7 @@ use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind;
|
|||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_fs_util::path_to_c_string;
|
||||
use rustc_hir::def::CtorKind;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
|
@ -1309,6 +1310,11 @@ pub fn build_global_var_di_node<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, glo
|
|||
};
|
||||
|
||||
let is_local_to_unit = is_node_local_to_unit(cx, def_id);
|
||||
|
||||
let DefKind::Static { nested, .. } = cx.tcx.def_kind(def_id) else { bug!() };
|
||||
if nested {
|
||||
return;
|
||||
}
|
||||
let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all());
|
||||
let type_di_node = type_di_node(cx, variable_type);
|
||||
let var_name = tcx.item_name(def_id);
|
||||
|
|
|
@ -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 dummy type and let `codegen_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(|| {
|
||||
|
|
|
@ -87,7 +87,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
|
|||
|
||||
// Only consider nodes that actually have exported symbols.
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Fn | DefKind::Static(_) => {}
|
||||
DefKind::Fn | DefKind::Static { .. } => {}
|
||||
DefKind::AssocFn if tcx.impl_of_method(def_id.to_def_id()).is_some() => {}
|
||||
_ => return None,
|
||||
};
|
||||
|
@ -483,7 +483,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel
|
|||
let target = &tcx.sess.target.llvm_target;
|
||||
// WebAssembly cannot export data symbols, so reduce their export level
|
||||
if target.contains("emscripten") {
|
||||
if let DefKind::Static(_) = tcx.def_kind(sym_def_id) {
|
||||
if let DefKind::Static { .. } = tcx.def_kind(sym_def_id) {
|
||||
return SymbolExportLevel::Rust;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
|
|||
|
||||
match *self {
|
||||
MonoItem::Static(def_id) => {
|
||||
cx.codegen_static(def_id, cx.tcx().is_mutable_static(def_id));
|
||||
cx.codegen_static(def_id);
|
||||
}
|
||||
MonoItem::GlobalAsm(item_id) => {
|
||||
let item = cx.tcx().hir().item(item_id);
|
||||
|
|
|
@ -4,7 +4,7 @@ use rustc_target::abi::Align;
|
|||
|
||||
pub trait StaticMethods: BackendTypes {
|
||||
fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value;
|
||||
fn codegen_static(&self, def_id: DefId, is_mutable: bool);
|
||||
fn codegen_static(&self, def_id: DefId);
|
||||
|
||||
/// Mark the given global value as "used", to prevent the compiler and linker from potentially
|
||||
/// removing a static variable that may otherwise appear unused.
|
||||
|
|
|
@ -37,7 +37,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
|
|||
|| matches!(
|
||||
ecx.tcx.def_kind(cid.instance.def_id()),
|
||||
DefKind::Const
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::ConstParam
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
|
@ -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)?
|
||||
};
|
||||
|
@ -380,7 +380,11 @@ 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_ids for the purpose of validation.
|
||||
let static_root_ids = ecx.machine.static_root_ids.take();
|
||||
let res = const_validate_mplace(&ecx, &mplace, cid);
|
||||
ecx.machine.static_root_ids = static_root_ids;
|
||||
|
||||
let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -59,8 +60,10 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
|
|||
/// Whether to check alignment during evaluation.
|
||||
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<AllocId>,
|
||||
/// If `Some`, we are evaluating the initializer of the static with the given `LocalDefId`,
|
||||
/// storing the result in the given `AllocId`.
|
||||
/// Used to prevent reads from a static's base allocation, as that may allow for self-initialization loops.
|
||||
pub(crate) static_root_ids: Option<(AllocId, LocalDefId)>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -94,7 +97,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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -749,7 +752,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(())
|
||||
|
|
|
@ -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,19 @@ pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine<
|
|||
FrameExtra = (),
|
||||
AllocExtra = (),
|
||||
MemoryMap = FxIndexMap<AllocId, (MemoryKind<T>, Allocation)>,
|
||||
>;
|
||||
> + HasStaticRootDefId;
|
||||
|
||||
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<LocalDefId>;
|
||||
}
|
||||
|
||||
impl HasStaticRootDefId for const_eval::CompileTimeInterpreter<'_, '_> {
|
||||
fn static_def_id(&self) -> Option<LocalDefId> {
|
||||
Some(self.static_root_ids?.1)
|
||||
}
|
||||
}
|
||||
|
||||
/// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory.
|
||||
///
|
||||
|
@ -67,10 +83,35 @@ 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 { mutability: 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 {
|
||||
|
|
|
@ -15,6 +15,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};
|
||||
|
@ -761,19 +762,36 @@ 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 for everything else. We need
|
||||
// to do that to
|
||||
// * avoid cycle errors in case of self-referential statics,
|
||||
// * be able to get information on extern statics.
|
||||
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
|
||||
|
|
|
@ -22,7 +22,7 @@ pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in
|
|||
|
||||
pub use self::eval_context::{format_interp_error, Frame, FrameInfo, InterpCx, StackPopCleanup};
|
||||
pub use self::intern::{
|
||||
intern_const_alloc_for_constprop, intern_const_alloc_recursive, InternKind,
|
||||
intern_const_alloc_for_constprop, intern_const_alloc_recursive, HasStaticRootDefId, InternKind,
|
||||
};
|
||||
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
|
||||
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -457,15 +457,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
// Special handling for pointers to statics (irrespective of their type).
|
||||
assert!(!self.ecx.tcx.is_thread_local_static(did));
|
||||
assert!(self.ecx.tcx.is_static(did));
|
||||
let is_mut =
|
||||
matches!(self.ecx.tcx.def_kind(did), DefKind::Static(Mutability::Mut))
|
||||
|| !self
|
||||
.ecx
|
||||
.tcx
|
||||
.type_of(did)
|
||||
.no_bound_vars()
|
||||
.expect("statics should not have generic parameters")
|
||||
.is_freeze(*self.ecx.tcx, ty::ParamEnv::reveal_all());
|
||||
// Mode-specific checks
|
||||
match self.ctfe_mode {
|
||||
Some(
|
||||
|
@ -490,8 +481,28 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
}
|
||||
None => {}
|
||||
}
|
||||
// Return alloc mutability
|
||||
if is_mut { Mutability::Mut } else { Mutability::Not }
|
||||
// Return alloc mutability. For "root" statics we look at the type to account for interior
|
||||
// mutability; for nested statics we have no type and directly use the annotated mutability.
|
||||
let DefKind::Static { mutability, nested } = self.ecx.tcx.def_kind(did)
|
||||
else {
|
||||
bug!()
|
||||
};
|
||||
match (mutability, nested) {
|
||||
(Mutability::Mut, _) => Mutability::Mut,
|
||||
(Mutability::Not, true) => Mutability::Not,
|
||||
(Mutability::Not, false)
|
||||
if !self
|
||||
.ecx
|
||||
.tcx
|
||||
.type_of(did)
|
||||
.no_bound_vars()
|
||||
.expect("statics should not have generic parameters")
|
||||
.is_freeze(*self.ecx.tcx, ty::ParamEnv::reveal_all()) =>
|
||||
{
|
||||
Mutability::Mut
|
||||
}
|
||||
(Mutability::Not, false) => Mutability::Not,
|
||||
}
|
||||
}
|
||||
GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
|
||||
GlobalAlloc::Function(..) | GlobalAlloc::VTable(..) => {
|
||||
|
|
|
@ -75,7 +75,12 @@ pub enum DefKind {
|
|||
Const,
|
||||
/// Constant generic parameter: `struct Foo<const N: usize> { ... }`
|
||||
ConstParam,
|
||||
Static(ast::Mutability),
|
||||
Static {
|
||||
/// Whether it's a `static mut` or just a `static`.
|
||||
mutability: ast::Mutability,
|
||||
/// Whether it's an anonymous static generated for nested allocations.
|
||||
nested: bool,
|
||||
},
|
||||
/// Refers to the struct or enum variant's constructor.
|
||||
///
|
||||
/// The reason `Ctor` exists in addition to [`DefKind::Struct`] and
|
||||
|
@ -136,7 +141,7 @@ impl DefKind {
|
|||
DefKind::Fn => "function",
|
||||
DefKind::Mod if def_id.is_crate_root() && !def_id.is_local() => "crate",
|
||||
DefKind::Mod => "module",
|
||||
DefKind::Static(..) => "static",
|
||||
DefKind::Static { .. } => "static",
|
||||
DefKind::Enum => "enum",
|
||||
DefKind::Variant => "variant",
|
||||
DefKind::Ctor(CtorOf::Variant, CtorKind::Fn) => "tuple variant",
|
||||
|
@ -209,7 +214,7 @@ impl DefKind {
|
|||
DefKind::Fn
|
||||
| DefKind::Const
|
||||
| DefKind::ConstParam
|
||||
| DefKind::Static(..)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Ctor(..)
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst => Some(Namespace::ValueNS),
|
||||
|
@ -245,10 +250,13 @@ impl DefKind {
|
|||
| DefKind::AssocTy
|
||||
| DefKind::TyParam
|
||||
| DefKind::ExternCrate => DefPathData::TypeNs(name),
|
||||
// It's not exactly an anon const, but wrt DefPathData, there
|
||||
// is no difference.
|
||||
DefKind::Static { nested: true, .. } => DefPathData::AnonConst,
|
||||
DefKind::Fn
|
||||
| DefKind::Const
|
||||
| DefKind::ConstParam
|
||||
| DefKind::Static(..)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
| DefKind::Field => DefPathData::ValueNs(name),
|
||||
|
@ -278,7 +286,7 @@ impl DefKind {
|
|||
| DefKind::AssocFn
|
||||
| DefKind::Ctor(..)
|
||||
| DefKind::Closure
|
||||
| DefKind::Static(_) => true,
|
||||
| DefKind::Static { .. } => true,
|
||||
DefKind::Mod
|
||||
| DefKind::Struct
|
||||
| DefKind::Union
|
||||
|
|
|
@ -1616,7 +1616,7 @@ impl Expr<'_> {
|
|||
pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> bool) -> bool {
|
||||
match self.kind {
|
||||
ExprKind::Path(QPath::Resolved(_, ref path)) => {
|
||||
matches!(path.res, Res::Local(..) | Res::Def(DefKind::Static(_), _) | Res::Err)
|
||||
matches!(path.res, Res::Local(..) | Res::Def(DefKind::Static { .. }, _) | Res::Err)
|
||||
}
|
||||
|
||||
// Type ascription inherits its place expression kind from its
|
||||
|
|
|
@ -107,7 +107,7 @@ impl Target {
|
|||
match item.kind {
|
||||
ItemKind::ExternCrate(..) => Target::ExternCrate,
|
||||
ItemKind::Use(..) => Target::Use,
|
||||
ItemKind::Static(..) => Target::Static,
|
||||
ItemKind::Static { .. } => Target::Static,
|
||||
ItemKind::Const(..) => Target::Const,
|
||||
ItemKind::Fn(..) => Target::Fn,
|
||||
ItemKind::Macro(..) => Target::MacroDef,
|
||||
|
@ -130,7 +130,7 @@ impl Target {
|
|||
match def_kind {
|
||||
DefKind::ExternCrate => Target::ExternCrate,
|
||||
DefKind::Use => Target::Use,
|
||||
DefKind::Static(..) => Target::Static,
|
||||
DefKind::Static { .. } => Target::Static,
|
||||
DefKind::Const => Target::Const,
|
||||
DefKind::Fn => Target::Fn,
|
||||
DefKind::Macro(..) => Target::MacroDef,
|
||||
|
|
|
@ -1934,7 +1934,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
|
||||
// Case 3. Reference to a top-level value.
|
||||
DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static(_) => {
|
||||
DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static { .. } => {
|
||||
path_segs.push(PathSeg(def_id, last));
|
||||
}
|
||||
|
||||
|
|
|
@ -226,7 +226,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
Ok(l) => l,
|
||||
// Foreign statics that overflow their allowed size should emit an error
|
||||
Err(LayoutError::SizeOverflow(_))
|
||||
if matches!(tcx.def_kind(def_id), DefKind::Static(_)
|
||||
if matches!(tcx.def_kind(def_id), DefKind::Static{ .. }
|
||||
if tcx.def_kind(tcx.local_parent(def_id)) == DefKind::ForeignMod) =>
|
||||
{
|
||||
tcx.dcx().emit_err(errors::TooLargeStatic { span });
|
||||
|
@ -505,7 +505,7 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let _indenter = indenter();
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Static(..) => {
|
||||
DefKind::Static { .. } => {
|
||||
tcx.ensure().typeck(def_id);
|
||||
maybe_check_static_with_link_section(tcx, def_id);
|
||||
check_static_inhabited(tcx, def_id);
|
||||
|
|
|
@ -48,8 +48,7 @@ fn is_path_static_mut(expr: hir::Expr<'_>) -> Option<String> {
|
|||
if let hir::ExprKind::Path(qpath) = expr.kind
|
||||
&& let hir::QPath::Resolved(_, path) = qpath
|
||||
&& let hir::def::Res::Def(def_kind, _) = path.res
|
||||
&& let hir::def::DefKind::Static(mt) = def_kind
|
||||
&& matches!(mt, Mutability::Mut)
|
||||
&& let hir::def::DefKind::Static { mutability: Mutability::Mut, nested: false } = def_kind
|
||||
{
|
||||
return Some(qpath_to_string(&qpath));
|
||||
}
|
||||
|
|
|
@ -182,7 +182,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
|||
tcx.hir().par_body_owners(|item_def_id| {
|
||||
let def_kind = tcx.def_kind(item_def_id);
|
||||
match def_kind {
|
||||
DefKind::Static(_) => tcx.ensure().eval_static_initializer(item_def_id),
|
||||
DefKind::Static { .. } => tcx.ensure().eval_static_initializer(item_def_id),
|
||||
DefKind::Const => tcx.ensure().const_eval_poly(item_def_id.into()),
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
@ -699,7 +699,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
hir::Path {
|
||||
res:
|
||||
hir::def::Res::Def(
|
||||
hir::def::DefKind::Static(_) | hir::def::DefKind::Const,
|
||||
hir::def::DefKind::Static { .. } | hir::def::DefKind::Const,
|
||||
def_id,
|
||||
),
|
||||
..
|
||||
|
|
|
@ -398,7 +398,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
|||
)
|
||||
| Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, expr_ty)),
|
||||
|
||||
Res::Def(DefKind::Static(_), _) => {
|
||||
Res::Def(DefKind::Static { .. }, _) => {
|
||||
Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new()))
|
||||
}
|
||||
|
||||
|
|
|
@ -372,7 +372,7 @@ impl<T> Trait<T> for X {
|
|||
&& matches!(
|
||||
tcx.def_kind(body_owner_def_id),
|
||||
DefKind::Fn
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Const
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
|
|
|
@ -863,7 +863,7 @@ fn should_encode_span(def_kind: DefKind) -> bool {
|
|||
| DefKind::LifetimeParam
|
||||
| DefKind::Fn
|
||||
| DefKind::Const
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Ctor(..)
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
|
@ -894,7 +894,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(_)
|
||||
|
@ -915,6 +915,7 @@ fn should_encode_attrs(def_kind: DefKind) -> bool {
|
|||
| DefKind::InlineConst
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::Static { nested: true, .. }
|
||||
| DefKind::GlobalAsm => false,
|
||||
}
|
||||
}
|
||||
|
@ -936,7 +937,7 @@ fn should_encode_expn_that_defined(def_kind: DefKind) -> bool {
|
|||
| DefKind::Fn
|
||||
| DefKind::Const
|
||||
| DefKind::ConstParam
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Ctor(..)
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
|
@ -968,7 +969,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
|
||||
|
@ -981,6 +982,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 { .. }
|
||||
|
@ -1001,7 +1003,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
|
|||
| DefKind::AssocConst
|
||||
| DefKind::TyParam
|
||||
| DefKind::ConstParam
|
||||
| DefKind::Static(..)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Const
|
||||
| DefKind::Fn
|
||||
| DefKind::ForeignMod
|
||||
|
@ -1099,7 +1101,7 @@ fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: Def
|
|||
| DefKind::AssocConst
|
||||
| DefKind::TyParam
|
||||
| DefKind::ConstParam
|
||||
| DefKind::Static(..)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Const
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::Impl { .. }
|
||||
|
@ -1131,7 +1133,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
|
|||
| DefKind::AssocTy
|
||||
| DefKind::Fn
|
||||
| DefKind::Const
|
||||
| DefKind::Static(..)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Ctor(..)
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
|
@ -1163,7 +1165,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 { .. }
|
||||
|
@ -1205,6 +1207,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
|
||||
|
@ -1222,7 +1225,7 @@ fn should_encode_fn_sig(def_kind: DefKind) -> bool {
|
|||
| DefKind::Variant
|
||||
| DefKind::Field
|
||||
| DefKind::Const
|
||||
| DefKind::Static(..)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Ctor(..)
|
||||
| DefKind::TyAlias
|
||||
| DefKind::OpaqueTy
|
||||
|
@ -1263,7 +1266,7 @@ fn should_encode_constness(def_kind: DefKind) -> bool {
|
|||
| DefKind::Const
|
||||
| DefKind::AssocConst
|
||||
| DefKind::AnonConst
|
||||
| DefKind::Static(..)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::TyAlias
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::Impl { of_trait: false }
|
||||
|
@ -1295,7 +1298,7 @@ fn should_encode_const(def_kind: DefKind) -> bool {
|
|||
| DefKind::Ctor(..)
|
||||
| DefKind::Field
|
||||
| DefKind::Fn
|
||||
| DefKind::Static(..)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::TyAlias
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::ForeignTy
|
||||
|
@ -1469,7 +1472,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
.coroutine_for_closure
|
||||
.set_some(def_id.index, self.tcx.coroutine_for_closure(def_id).into());
|
||||
}
|
||||
if let DefKind::Static(_) = def_kind {
|
||||
if let DefKind::Static { .. } = def_kind {
|
||||
if !self.tcx.is_foreign_item(def_id) {
|
||||
let data = self.tcx.eval_static_initializer(def_id).unwrap();
|
||||
record!(self.tables.eval_static_initializer[def_id] <- data);
|
||||
|
|
|
@ -155,8 +155,10 @@ fixed_size_enum! {
|
|||
( Impl { of_trait: false } )
|
||||
( Impl { of_trait: true } )
|
||||
( Closure )
|
||||
( Static(ast::Mutability::Not) )
|
||||
( Static(ast::Mutability::Mut) )
|
||||
( Static { mutability: ast::Mutability::Not, nested: false } )
|
||||
( Static { mutability: ast::Mutability::Mut, nested: false } )
|
||||
( Static { mutability: ast::Mutability::Not, nested: true } )
|
||||
( Static { mutability: ast::Mutability::Mut, nested: true } )
|
||||
( Ctor(CtorOf::Struct, CtorKind::Fn) )
|
||||
( Ctor(CtorOf::Struct, CtorKind::Const) )
|
||||
( Ctor(CtorOf::Variant, CtorKind::Fn) )
|
||||
|
|
|
@ -343,7 +343,7 @@ impl<'hir> Map<'hir> {
|
|||
DefKind::InlineConst => BodyOwnerKind::Const { inline: true },
|
||||
DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn,
|
||||
DefKind::Closure => BodyOwnerKind::Closure,
|
||||
DefKind::Static(mt) => BodyOwnerKind::Static(mt),
|
||||
DefKind::Static { mutability, nested: false } => BodyOwnerKind::Static(mutability),
|
||||
dk => bug!("{:?} is not a body node: {:?}", def_id, dk),
|
||||
}
|
||||
}
|
||||
|
@ -359,7 +359,7 @@ impl<'hir> Map<'hir> {
|
|||
let def_id = def_id.into();
|
||||
let ccx = match self.body_owner_kind(def_id) {
|
||||
BodyOwnerKind::Const { inline } => ConstContext::Const { inline },
|
||||
BodyOwnerKind::Static(mt) => ConstContext::Static(mt),
|
||||
BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability),
|
||||
|
||||
BodyOwnerKind::Fn if self.tcx.is_constructor(def_id) => return None,
|
||||
BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn_raw(def_id) => {
|
||||
|
|
|
@ -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>) {
|
||||
|
|
|
@ -498,8 +498,12 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io:
|
|||
match (kind, body.source.promoted) {
|
||||
(_, Some(_)) => write!(w, "const ")?, // promoteds are the closest to consts
|
||||
(DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?,
|
||||
(DefKind::Static(hir::Mutability::Not), _) => write!(w, "static ")?,
|
||||
(DefKind::Static(hir::Mutability::Mut), _) => write!(w, "static mut ")?,
|
||||
(DefKind::Static { mutability: hir::Mutability::Not, nested: false }, _) => {
|
||||
write!(w, "static ")?
|
||||
}
|
||||
(DefKind::Static { mutability: hir::Mutability::Mut, nested: false }, _) => {
|
||||
write!(w, "static mut ")?
|
||||
}
|
||||
(_, _) if is_function => write!(w, "fn ")?,
|
||||
(DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
|
||||
_ => bug!("Unexpected def kind {:?}", kind),
|
||||
|
|
|
@ -1062,6 +1062,7 @@ rustc_queries! {
|
|||
}
|
||||
cache_on_disk_if { key.is_local() }
|
||||
separate_provide_extern
|
||||
feedable
|
||||
}
|
||||
|
||||
/// Evaluates const items or anonymous constants
|
||||
|
@ -1220,6 +1221,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<Symbol> {
|
||||
|
|
|
@ -1708,7 +1708,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
debug!("returned from def_kind: {:?}", def_kind);
|
||||
match def_kind {
|
||||
DefKind::Const
|
||||
| DefKind::Static(..)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::AssocConst
|
||||
| DefKind::Ctor(..)
|
||||
| DefKind::AnonConst
|
||||
|
|
|
@ -359,7 +359,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
| DefKind::TyAlias
|
||||
| DefKind::Fn
|
||||
| DefKind::Const
|
||||
| DefKind::Static(_) = kind
|
||||
| DefKind::Static { .. } = kind
|
||||
{
|
||||
} else {
|
||||
// If not covered above, like for example items out of `impl` blocks, fallback.
|
||||
|
|
|
@ -616,12 +616,16 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// Returns `true` if the node pointed to by `def_id` is a `static` item.
|
||||
#[inline]
|
||||
pub fn is_static(self, def_id: DefId) -> bool {
|
||||
matches!(self.def_kind(def_id), DefKind::Static(_))
|
||||
matches!(self.def_kind(def_id), DefKind::Static { .. })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn static_mutability(self, def_id: DefId) -> Option<hir::Mutability> {
|
||||
if let DefKind::Static(mt) = self.def_kind(def_id) { Some(mt) } else { None }
|
||||
if let DefKind::Static { mutability, .. } = self.def_kind(def_id) {
|
||||
Some(mutability)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a `static` item with the `#[thread_local]` attribute.
|
||||
|
|
|
@ -631,7 +631,7 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) -
|
|||
| DefKind::AssocConst
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::Static(_) => (vec![], tcx.type_of(def_id).instantiate_identity(), None),
|
||||
| DefKind::Static { .. } => (vec![], tcx.type_of(def_id).instantiate_identity(), None),
|
||||
DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => {
|
||||
let sig = tcx.liberate_late_bound_regions(
|
||||
def_id.to_def_id(),
|
||||
|
|
|
@ -942,7 +942,7 @@ impl<'tcx> Cx<'tcx> {
|
|||
|
||||
// We encode uses of statics as a `*&STATIC` where the `&STATIC` part is
|
||||
// a constant reference (or constant raw pointer for `static mut`) in MIR
|
||||
Res::Def(DefKind::Static(_), id) => {
|
||||
Res::Def(DefKind::Static { .. }, id) => {
|
||||
let ty = self.tcx.static_ptr_ty(id);
|
||||
let temp_lifetime = self
|
||||
.rvalue_scopes
|
||||
|
|
|
@ -453,7 +453,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
Res::Def(DefKind::ConstParam, _) => {
|
||||
self.tcx.dcx().emit_err(ConstParamInPattern { span })
|
||||
}
|
||||
Res::Def(DefKind::Static(_), _) => {
|
||||
Res::Def(DefKind::Static { .. }, _) => {
|
||||
self.tcx.dcx().emit_err(StaticInPattern { span })
|
||||
}
|
||||
_ => self.tcx.dcx().emit_err(NonConstPath { span }),
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//! Currently, this pass only propagates scalar values.
|
||||
|
||||
use rustc_const_eval::interpret::{
|
||||
ImmTy, Immediate, InterpCx, OpTy, PlaceTy, PointerArithmetic, Projectable,
|
||||
HasStaticRootDefId, ImmTy, Immediate, InterpCx, OpTy, PlaceTy, PointerArithmetic, Projectable,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def::DefKind;
|
||||
|
@ -889,6 +889,12 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
|
|||
|
||||
pub(crate) struct DummyMachine;
|
||||
|
||||
impl HasStaticRootDefId for DummyMachine {
|
||||
fn static_def_id(&self) -> Option<rustc_hir::def_id::LocalDefId> {
|
||||
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 = !;
|
||||
|
|
|
@ -333,7 +333,7 @@ fn mir_promoted(
|
|||
}
|
||||
DefKind::AssocConst
|
||||
| DefKind::Const
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::InlineConst
|
||||
| DefKind::AnonConst => tcx.mir_const_qualif(def),
|
||||
_ => ConstQualifs::default(),
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -1037,7 +1041,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) ->
|
|||
return false;
|
||||
}
|
||||
|
||||
if let DefKind::Static(_) = tcx.def_kind(def_id) {
|
||||
if let DefKind::Static { .. } = tcx.def_kind(def_id) {
|
||||
// We cannot monomorphize statics from upstream crates.
|
||||
return false;
|
||||
}
|
||||
|
@ -1254,7 +1258,7 @@ impl<'v> RootCollector<'_, 'v> {
|
|||
);
|
||||
self.output.push(dummy_spanned(MonoItem::GlobalAsm(id)));
|
||||
}
|
||||
DefKind::Static(..) => {
|
||||
DefKind::Static { .. } => {
|
||||
let def_id = id.owner_id.to_def_id();
|
||||
debug!("RootCollector: ItemKind::Static({})", self.tcx.def_path_str(def_id));
|
||||
self.output.push(dummy_spanned(MonoItem::Static(def_id)));
|
||||
|
|
|
@ -150,7 +150,7 @@ fn mark_used_by_default_parameters<'tcx>(
|
|||
| DefKind::Fn
|
||||
| DefKind::Const
|
||||
| DefKind::ConstParam
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Ctor(_, _)
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
|
|
|
@ -801,7 +801,7 @@ fn check_foreign_item(
|
|||
worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>,
|
||||
id: hir::ForeignItemId,
|
||||
) {
|
||||
if matches!(tcx.def_kind(id.owner_id), DefKind::Static(_) | DefKind::Fn)
|
||||
if matches!(tcx.def_kind(id.owner_id), DefKind::Static { .. } | DefKind::Fn)
|
||||
&& let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, id.owner_id.def_id)
|
||||
{
|
||||
worklist.push((id.owner_id.def_id, comes_from_allow));
|
||||
|
@ -1058,7 +1058,7 @@ impl<'tcx> DeadVisitor<'tcx> {
|
|||
DefKind::AssocConst
|
||||
| DefKind::AssocFn
|
||||
| DefKind::Fn
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Const
|
||||
| DefKind::TyAlias
|
||||
| DefKind::Enum
|
||||
|
|
|
@ -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;
|
||||
|
@ -73,7 +74,7 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
|
|||
match res {
|
||||
// Reachable constants and reachable statics can have their contents inlined
|
||||
// into other crates. Mark them as reachable and recurse into their body.
|
||||
Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::Static(_), _) => {
|
||||
Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::Static { .. }, _) => {
|
||||
self.worklist.push(def_id);
|
||||
}
|
||||
_ => {
|
||||
|
@ -197,10 +198,23 @@ 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) => {
|
||||
// FIXME(oli-obk): remove this body walking and instead walk the evaluated initializer
|
||||
// to find nested items that end up in the final value instead of also marking symbols
|
||||
// as reachable that are only needed for evaluation.
|
||||
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 +280,29 @@ impl<'tcx> ReachableContext<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds anonymous nested statics created for nested allocations and adds them to `reachable_symbols`.
|
||||
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
|
||||
// This is the main purpose of this function: add the def_id we find
|
||||
// to `reachable_symbols`.
|
||||
&& 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>(
|
||||
|
|
|
@ -549,7 +549,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
|
|||
self.update(def_id, macro_ev, Level::Reachable);
|
||||
match def_kind {
|
||||
// No type privacy, so can be directly marked as reachable.
|
||||
DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => {
|
||||
DefKind::Const | DefKind::Static { .. } | DefKind::TraitAlias | DefKind::TyAlias => {
|
||||
if vis.is_accessible_from(module, self.tcx) {
|
||||
self.update(def_id, macro_ev, Level::Reachable);
|
||||
}
|
||||
|
@ -1170,12 +1170,12 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
|||
let def = def.filter(|(kind, _)| {
|
||||
matches!(
|
||||
kind,
|
||||
DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static(_)
|
||||
DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static { .. }
|
||||
)
|
||||
});
|
||||
if let Some((kind, def_id)) = def {
|
||||
let is_local_static =
|
||||
if let DefKind::Static(_) = kind { def_id.is_local() } else { false };
|
||||
if let DefKind::Static { .. } = kind { def_id.is_local() } else { false };
|
||||
if !self.item_is_accessible(def_id) && !is_local_static {
|
||||
let name = match *qpath {
|
||||
hir::QPath::LangItem(it, ..) => {
|
||||
|
@ -1496,7 +1496,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx, '_> {
|
|||
let def_kind = tcx.def_kind(def_id);
|
||||
|
||||
match def_kind {
|
||||
DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias => {
|
||||
DefKind::Const | DefKind::Static { .. } | DefKind::Fn | DefKind::TyAlias => {
|
||||
if let DefKind::TyAlias = def_kind {
|
||||
self.check_unnameable(def_id, effective_vis);
|
||||
}
|
||||
|
|
|
@ -990,7 +990,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
|||
Res::Def(
|
||||
DefKind::Fn
|
||||
| DefKind::AssocFn
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Const
|
||||
| DefKind::AssocConst
|
||||
| DefKind::Ctor(..),
|
||||
|
|
|
@ -127,7 +127,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
|||
ItemKind::Union(..) => DefKind::Union,
|
||||
ItemKind::ExternCrate(..) => DefKind::ExternCrate,
|
||||
ItemKind::TyAlias(..) => DefKind::TyAlias,
|
||||
ItemKind::Static(s) => DefKind::Static(s.mutability),
|
||||
ItemKind::Static(s) => DefKind::Static { mutability: s.mutability, nested: false },
|
||||
ItemKind::Const(..) => DefKind::Const,
|
||||
ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn,
|
||||
ItemKind::MacroDef(..) => {
|
||||
|
@ -214,7 +214,9 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
|||
|
||||
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||
let def_kind = match fi.kind {
|
||||
ForeignItemKind::Static(_, mt, _) => DefKind::Static(mt),
|
||||
ForeignItemKind::Static(_, mutability, _) => {
|
||||
DefKind::Static { mutability, nested: false }
|
||||
}
|
||||
ForeignItemKind::Fn(_) => DefKind::Fn,
|
||||
ForeignItemKind::TyAlias(_) => DefKind::ForeignTy,
|
||||
ForeignItemKind::MacCall(_) => return self.visit_macro_invoc(fi.id),
|
||||
|
|
|
@ -574,7 +574,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params, def_kind) => {
|
||||
use errs::GenericParamsFromOuterItemLabel as Label;
|
||||
let static_or_const = match def_kind {
|
||||
DefKind::Static(_) => Some(errs::GenericParamsFromOuterItemStaticOrConst::Static),
|
||||
DefKind::Static{ .. } => Some(errs::GenericParamsFromOuterItemStaticOrConst::Static),
|
||||
DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const),
|
||||
_ => None,
|
||||
};
|
||||
|
|
|
@ -500,7 +500,7 @@ impl<'a> PathSource<'a> {
|
|||
Res::Def(
|
||||
DefKind::Ctor(_, CtorKind::Const | CtorKind::Fn)
|
||||
| DefKind::Const
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Fn
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
|
@ -3645,7 +3645,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
}
|
||||
Some(res)
|
||||
}
|
||||
Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static(_), _) => {
|
||||
Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static { .. }, _) => {
|
||||
// This is unambiguously a fresh binding, either syntactically
|
||||
// (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
|
||||
// to something unusable as a pattern (e.g., constructor function),
|
||||
|
|
|
@ -264,7 +264,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
use rustc_hir::def::DefKind;
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Fn => ForeignItemKind::Fn(tables.fn_def(def_id)),
|
||||
DefKind::Static(..) => ForeignItemKind::Static(tables.static_def(def_id)),
|
||||
DefKind::Static { .. } => ForeignItemKind::Static(tables.static_def(def_id)),
|
||||
DefKind::ForeignTy => ForeignItemKind::Type(
|
||||
tables.intern_ty(rustc_middle::ty::Ty::new_foreign(tcx, def_id)),
|
||||
),
|
||||
|
|
|
@ -95,7 +95,7 @@ pub(crate) fn new_item_kind(kind: DefKind) -> ItemKind {
|
|||
DefKind::Const | DefKind::InlineConst | DefKind::AssocConst | DefKind::AnonConst => {
|
||||
ItemKind::Const
|
||||
}
|
||||
DefKind::Static(_) => ItemKind::Static,
|
||||
DefKind::Static { .. } => ItemKind::Static,
|
||||
DefKind::Ctor(_, rustc_hir::def::CtorKind::Const) => ItemKind::Ctor(CtorKind::Const),
|
||||
DefKind::Ctor(_, rustc_hir::def::CtorKind::Fn) => ItemKind::Ctor(CtorKind::Fn),
|
||||
}
|
||||
|
|
|
@ -1205,6 +1205,7 @@ symbols! {
|
|||
negative_bounds,
|
||||
negative_impls,
|
||||
neon,
|
||||
nested,
|
||||
never,
|
||||
never_patterns,
|
||||
never_type,
|
||||
|
|
|
@ -134,7 +134,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
|
|||
| DefKind::TyParam
|
||||
| DefKind::Const
|
||||
| DefKind::ConstParam
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Ctor(_, _)
|
||||
| DefKind::Macro(_)
|
||||
| DefKind::ExternCrate
|
||||
|
|
|
@ -318,7 +318,7 @@ fn opaque_types_defined_by<'tcx>(
|
|||
match kind {
|
||||
DefKind::AssocFn
|
||||
| DefKind::Fn
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Const
|
||||
| DefKind::AssocConst
|
||||
| DefKind::AnonConst => {
|
||||
|
|
|
@ -41,9 +41,9 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
|
|||
}
|
||||
}
|
||||
// Walk over the type behind the alias
|
||||
DefKind::TyAlias {..} | DefKind::AssocTy |
|
||||
DefKind::TyAlias { .. } | DefKind::AssocTy |
|
||||
// Walk over the type of the item
|
||||
DefKind::Static(_) | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
|
||||
DefKind::Static { .. } | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
|
||||
if let Some(ty) = tcx.hir_node_by_def_id(item).ty() {
|
||||
// If the type of the item uses `_`, we're gonna error out anyway, but
|
||||
// typeck (which type_of invokes below), will call back into opaque_types_defined_by
|
||||
|
|
|
@ -120,7 +120,7 @@ pub(crate) fn try_inline(
|
|||
record_extern_fqn(cx, did, ItemType::Module);
|
||||
clean::ModuleItem(build_module(cx, did, visited))
|
||||
}
|
||||
Res::Def(DefKind::Static(_), did) => {
|
||||
Res::Def(DefKind::Static { .. }, did) => {
|
||||
record_extern_fqn(cx, did, ItemType::Static);
|
||||
cx.with_param_env(did, |cx| {
|
||||
clean::StaticItem(build_static(cx, did, cx.tcx.is_mutable_static(did)))
|
||||
|
|
|
@ -526,7 +526,7 @@ pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
|
|||
| Mod
|
||||
| ForeignTy
|
||||
| Const
|
||||
| Static(_)
|
||||
| Static { .. }
|
||||
| Macro(..)
|
||||
| TraitAlias),
|
||||
did,
|
||||
|
|
|
@ -128,7 +128,7 @@ impl ItemType {
|
|||
DefKind::Fn => Self::Function,
|
||||
DefKind::Mod => Self::Module,
|
||||
DefKind::Const => Self::Constant,
|
||||
DefKind::Static(_) => Self::Static,
|
||||
DefKind::Static { .. } => Self::Static,
|
||||
DefKind::Struct => Self::Struct,
|
||||
DefKind::Union => Self::Union,
|
||||
DefKind::Trait => Self::Trait,
|
||||
|
|
|
@ -123,7 +123,7 @@ impl Res {
|
|||
DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst => {
|
||||
"const"
|
||||
}
|
||||
DefKind::Static(_) => "static",
|
||||
DefKind::Static { .. } => "static",
|
||||
// Now handle things that don't have a specific disambiguator
|
||||
_ => match kind
|
||||
.ns()
|
||||
|
@ -1514,7 +1514,7 @@ impl Disambiguator {
|
|||
"union" => Kind(DefKind::Union),
|
||||
"module" | "mod" => Kind(DefKind::Mod),
|
||||
"const" | "constant" => Kind(DefKind::Const),
|
||||
"static" => Kind(DefKind::Static(Mutability::Not)),
|
||||
"static" => Kind(DefKind::Static { mutability: Mutability::Not, nested: false }),
|
||||
"function" | "fn" | "method" => Kind(DefKind::Fn),
|
||||
"derive" => Kind(DefKind::Macro(MacroKind::Derive)),
|
||||
"type" => NS(Namespace::TypeNS),
|
||||
|
@ -1926,7 +1926,7 @@ fn resolution_failure(
|
|||
| OpaqueTy
|
||||
| TraitAlias
|
||||
| TyParam
|
||||
| Static(_) => "associated item",
|
||||
| Static { .. } => "associated item",
|
||||
Impl { .. } | GlobalAsm => unreachable!("not a path"),
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -273,7 +273,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
|
|||
}
|
||||
return false; // no need to walk further *on the variable*
|
||||
},
|
||||
Res::Def(DefKind::Static(_) | DefKind::Const, ..) => {
|
||||
Res::Def(DefKind::Static{..} | DefKind::Const, ..) => {
|
||||
if index_used_directly {
|
||||
self.indexed_directly.insert(
|
||||
seqvar.segments[0].ident.name,
|
||||
|
|
|
@ -101,7 +101,7 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
|
|||
Res::Local(hir_id) => {
|
||||
self.ids.insert(hir_id);
|
||||
},
|
||||
Res::Def(DefKind::Static(_), def_id) => {
|
||||
Res::Def(DefKind::Static{..}, def_id) => {
|
||||
let mutable = self.cx.tcx.is_mutable_static(def_id);
|
||||
self.def_ids.insert(def_id, mutable);
|
||||
},
|
||||
|
|
|
@ -91,7 +91,7 @@ pub(super) fn check<'tcx>(
|
|||
},
|
||||
hir::ExprKind::Path(ref p) => matches!(
|
||||
cx.qpath_res(p, arg.hir_id),
|
||||
hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static(_), _)
|
||||
hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static{..}, _)
|
||||
),
|
||||
_ => false,
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ fn collect_unsafe_exprs<'tcx>(
|
|||
ExprKind::Path(QPath::Resolved(
|
||||
_,
|
||||
hir::Path {
|
||||
res: Res::Def(DefKind::Static(Mutability::Mut), _),
|
||||
res: Res::Def(DefKind::Static{mutability:Mutability::Mut, ..}, _),
|
||||
..
|
||||
},
|
||||
)) => {
|
||||
|
@ -149,7 +149,7 @@ fn collect_unsafe_exprs<'tcx>(
|
|||
ExprKind::Path(QPath::Resolved(
|
||||
_,
|
||||
hir::Path {
|
||||
res: Res::Def(DefKind::Static(Mutability::Mut), _),
|
||||
res: Res::Def(DefKind::Static{mutability:Mutability::Mut, ..}, _),
|
||||
..
|
||||
}
|
||||
))
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// This is a support file for ../const-mut-refs-crate.rs
|
||||
|
||||
// This is to test that static inners from an external
|
||||
// crate like this one, still preserves the alloc.
|
||||
// That is, the address from the standpoint of rustc+llvm
|
||||
// is the same.
|
||||
// The need for this test originated from the GH issue
|
||||
// https://github.com/rust-lang/rust/issues/57349
|
||||
|
||||
// See also ../const-mut-refs-crate.rs for more details
|
||||
// about this test.
|
||||
|
||||
#![feature(const_mut_refs)]
|
||||
|
||||
// if we used immutable references here, then promotion would
|
||||
// turn the `&42` into a promoted, which gets duplicated arbitrarily.
|
||||
pub static mut FOO: &'static mut i32 = &mut 42;
|
||||
pub static mut BAR: &'static mut i32 = unsafe { FOO };
|
||||
|
||||
pub mod inner {
|
||||
pub static INNER_MOD_FOO: &'static i32 = &43;
|
||||
pub static INNER_MOD_BAR: &'static i32 = INNER_MOD_FOO;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//@ run-pass
|
||||
//@ aux-build:const_mut_refs_crate.rs
|
||||
|
||||
#![feature(const_mut_refs)]
|
||||
|
||||
//! Regression test for https://github.com/rust-lang/rust/issues/79738
|
||||
//! Show how we are not duplicating allocations anymore. Statics that
|
||||
//! copy their value from another static used to also duplicate
|
||||
//! memory behind references.
|
||||
|
||||
extern crate const_mut_refs_crate as other;
|
||||
|
||||
use other::{
|
||||
inner::{INNER_MOD_BAR, INNER_MOD_FOO},
|
||||
BAR, FOO,
|
||||
};
|
||||
|
||||
pub static LOCAL_FOO: &'static i32 = &41;
|
||||
pub static LOCAL_BAR: &'static i32 = LOCAL_FOO;
|
||||
pub static mut COPY_OF_REMOTE_FOO: &'static mut i32 = unsafe { FOO };
|
||||
|
||||
static DOUBLE_REF: &&i32 = &&99;
|
||||
static ONE_STEP_ABOVE: &i32 = *DOUBLE_REF;
|
||||
static mut DOUBLE_REF_MUT: &mut &mut i32 = &mut &mut 99;
|
||||
static mut ONE_STEP_ABOVE_MUT: &mut i32 = unsafe { *DOUBLE_REF_MUT };
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
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);
|
||||
assert_eq!(*DOUBLE_REF_MUT as *mut i32, ONE_STEP_ABOVE_MUT as *mut i32);
|
||||
|
||||
assert_eq!(FOO as *const i32, COPY_OF_REMOTE_FOO as *const i32);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
//@ check-pass
|
||||
/// oli-obk added this test after messing up the interner logic
|
||||
/// around mutability of nested allocations. This was not caught
|
||||
/// by the test suite, but by trying to build stage2 rustc.
|
||||
/// There is no real explanation for this test, as it was just
|
||||
/// a bug during a refactoring.
|
||||
|
||||
pub struct Lint {
|
||||
pub name: &'static str,
|
||||
pub desc: &'static str,
|
||||
pub report_in_external_macro: bool,
|
||||
pub is_loaded: bool,
|
||||
pub crate_level_only: bool,
|
||||
}
|
||||
|
||||
static FOO: &Lint = &Lint {
|
||||
name: &"foo",
|
||||
desc: "desc",
|
||||
report_in_external_macro: false,
|
||||
is_loaded: true,
|
||||
crate_level_only: false,
|
||||
};
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue