From 22d0073d47e7f82b0943db94babe40420205eb6a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 14 Mar 2024 17:19:06 +0000 Subject: [PATCH] Don't walk the bodies of free constants for reachability. --- .../rustc_middle/src/mir/interpret/queries.rs | 26 ++++++++++++++++--- compiler/rustc_passes/src/reachable.rs | 18 ++++++++++--- ...rivate_const_fn_only_used_in_const_eval.rs | 2 +- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index fe743fa4aac..95857e8579d 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,4 +1,6 @@ -use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; +use super::{ + ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId, +}; use crate::mir; use crate::query::TyCtxtEnsure; @@ -13,7 +15,7 @@ use tracing::{debug, instrument}; impl<'tcx> TyCtxt<'tcx> { /// 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. #[instrument(skip(self), level = "debug")] pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> { @@ -27,6 +29,24 @@ impl<'tcx> TyCtxt<'tcx> { let param_env = self.param_env(def_id).with_reveal_all_normalized(self); 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. /// /// The constant can be located on a trait like `::C`, in which case the given @@ -177,7 +197,7 @@ impl<'tcx> TyCtxt<'tcx> { impl<'tcx> TyCtxtEnsure<'tcx> { /// 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. #[instrument(skip(self), level = "debug")] pub fn const_eval_poly(self, def_id: DefId) { diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 954a1ab6560..ee632ea5df3 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -29,12 +29,12 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; -use rustc_middle::bug; 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::mir::interpret::{ConstAllocation, ErrorHandled, GlobalAlloc}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ExistentialTraitRef, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_privacy::DefIdVisitor; use rustc_session::config::CrateType; use tracing::debug; @@ -209,8 +209,18 @@ 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) => { - self.visit_nested_body(init); + hir::ItemKind::Const(..) => { + 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(..) => { if let Ok(alloc) = self.tcx.eval_static_initializer(item.owner_id.def_id) { diff --git a/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs b/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs index 98ccf93fb5e..35071e238f3 100644 --- a/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs +++ b/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs @@ -13,4 +13,4 @@ const fn bar() {} pub const BAR: () = bar(); -// CHECK: define{{.*}}bar{{.*}} +// CHECK-NOT: define{{.*}}bar{{.*}}