Don't walk the bodies of free constants for reachability.

This commit is contained in:
Oli Scherer 2024-03-14 17:19:06 +00:00
parent 50b07aa899
commit 22d0073d47
3 changed files with 38 additions and 8 deletions

View File

@ -1,4 +1,6 @@
use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; use super::{
ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId,
};
use crate::mir; use crate::mir;
use crate::query::TyCtxtEnsure; use crate::query::TyCtxtEnsure;
@ -13,7 +15,7 @@
impl<'tcx> TyCtxt<'tcx> { impl<'tcx> TyCtxt<'tcx> {
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
/// that can't take any generic arguments like statics, const items or enum discriminants. If a /// that can't take any generic arguments like const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> { pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> {
@ -27,6 +29,24 @@ pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> {
let param_env = self.param_env(def_id).with_reveal_all_normalized(self); let param_env = self.param_env(def_id).with_reveal_all_normalized(self);
self.const_eval_global_id(param_env, cid, DUMMY_SP) self.const_eval_global_id(param_env, cid, DUMMY_SP)
} }
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
/// that can't take any generic arguments like const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
#[instrument(skip(self), level = "debug")]
pub fn const_eval_poly_to_alloc(self, def_id: DefId) -> EvalToAllocationRawResult<'tcx> {
// In some situations def_id will have generic parameters within scope, but they aren't allowed
// to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
// encountered.
let args = GenericArgs::identity_for_item(self, def_id);
let instance = ty::Instance::new(def_id, args);
let cid = GlobalId { instance, promoted: None };
let param_env = self.param_env(def_id).with_reveal_all_normalized(self);
let inputs = self.erase_regions(param_env.and(cid));
self.eval_to_allocation_raw(inputs)
}
/// Resolves and evaluates a constant. /// Resolves and evaluates a constant.
/// ///
/// The constant can be located on a trait like `<A as B>::C`, in which case the given /// The constant can be located on a trait like `<A as B>::C`, in which case the given
@ -177,7 +197,7 @@ pub fn const_eval_global_id_for_typeck(
impl<'tcx> TyCtxtEnsure<'tcx> { impl<'tcx> TyCtxtEnsure<'tcx> {
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
/// that can't take any generic arguments like statics, const items or enum discriminants. If a /// that can't take any generic arguments like const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
pub fn const_eval_poly(self, def_id: DefId) { pub fn const_eval_poly(self, def_id: DefId) {

View File

@ -29,12 +29,12 @@
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::Node; use rustc_hir::Node;
use rustc_middle::bug;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::middle::privacy::{self, Level}; use rustc_middle::middle::privacy::{self, Level};
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc}; use rustc_middle::mir::interpret::{ConstAllocation, ErrorHandled, GlobalAlloc};
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::ty::{self, ExistentialTraitRef, TyCtxt}; use rustc_middle::ty::{self, ExistentialTraitRef, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_privacy::DefIdVisitor; use rustc_privacy::DefIdVisitor;
use rustc_session::config::CrateType; use rustc_session::config::CrateType;
use tracing::debug; use tracing::debug;
@ -209,8 +209,18 @@ fn propagate_node(&mut self, node: &Node<'tcx>, search_item: LocalDefId) {
// Reachable constants will be inlined into other crates // Reachable constants will be inlined into other crates
// unconditionally, so we need to make sure that their // unconditionally, so we need to make sure that their
// contents are also reachable. // contents are also reachable.
hir::ItemKind::Const(_, _, init) => { hir::ItemKind::Const(..) => {
self.visit_nested_body(init); match self.tcx.const_eval_poly_to_alloc(item.owner_id.def_id.into()) {
Ok(alloc) => {
let alloc = self.tcx.global_alloc(alloc.alloc_id).unwrap_memory();
self.propagate_from_alloc(alloc);
}
Err(ErrorHandled::TooGeneric(span)) => span_bug!(
span,
"generic constants aren't implemented in reachability"
),
Err(ErrorHandled::Reported(..)) => {}
}
} }
hir::ItemKind::Static(..) => { hir::ItemKind::Static(..) => {
if let Ok(alloc) = self.tcx.eval_static_initializer(item.owner_id.def_id) { if let Ok(alloc) = self.tcx.eval_static_initializer(item.owner_id.def_id) {

View File

@ -13,4 +13,4 @@ const fn bar() {}
pub const BAR: () = bar(); pub const BAR: () = bar();
// CHECK: define{{.*}}bar{{.*}} // CHECK-NOT: define{{.*}}bar{{.*}}