Skip to content

Commit d0ccb54

Browse files
committed
Auto merge of rust-lang#122505 - oli-obk:visit_nested_body2, r=tmiasko
Don't walk the bodies of free constants for reachability. follow-up to rust-lang#122371 cc rust-lang#119214 This avoids codegening items (e.g. functions) that are only used during const eval, but do not reach their final constant value (e.g. via function pointers). r? `@tmiasko`
2 parents 72fdf91 + a0358f4 commit d0ccb54

File tree

3 files changed

+55
-8
lines changed

3 files changed

+55
-8
lines changed

Diff for: compiler/rustc_middle/src/mir/interpret/queries.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId};
1+
use super::{
2+
ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId,
3+
};
24

35
use crate::mir;
46
use crate::query::TyCtxtEnsure;
@@ -13,7 +15,7 @@ use tracing::{debug, instrument};
1315

1416
impl<'tcx> TyCtxt<'tcx> {
1517
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
16-
/// that can't take any generic arguments like statics, const items or enum discriminants. If a
18+
/// that can't take any generic arguments like const items or enum discriminants. If a
1719
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
1820
#[instrument(skip(self), level = "debug")]
1921
pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> {
@@ -27,6 +29,24 @@ impl<'tcx> TyCtxt<'tcx> {
2729
let param_env = self.param_env(def_id).with_reveal_all_normalized(self);
2830
self.const_eval_global_id(param_env, cid, DUMMY_SP)
2931
}
32+
33+
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
34+
/// that can't take any generic arguments like const items or enum discriminants. If a
35+
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
36+
#[instrument(skip(self), level = "debug")]
37+
pub fn const_eval_poly_to_alloc(self, def_id: DefId) -> EvalToAllocationRawResult<'tcx> {
38+
// In some situations def_id will have generic parameters within scope, but they aren't allowed
39+
// to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
40+
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
41+
// encountered.
42+
let args = GenericArgs::identity_for_item(self, def_id);
43+
let instance = ty::Instance::new(def_id, args);
44+
let cid = GlobalId { instance, promoted: None };
45+
let param_env = self.param_env(def_id).with_reveal_all_normalized(self);
46+
let inputs = self.erase_regions(param_env.and(cid));
47+
self.eval_to_allocation_raw(inputs)
48+
}
49+
3050
/// Resolves and evaluates a constant.
3151
///
3252
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
@@ -177,7 +197,7 @@ impl<'tcx> TyCtxt<'tcx> {
177197

178198
impl<'tcx> TyCtxtEnsure<'tcx> {
179199
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
180-
/// that can't take any generic arguments like statics, const items or enum discriminants. If a
200+
/// that can't take any generic arguments like const items or enum discriminants. If a
181201
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
182202
#[instrument(skip(self), level = "debug")]
183203
pub fn const_eval_poly(self, def_id: DefId) {

Diff for: compiler/rustc_passes/src/reachable.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use rustc_hir::Node;
3232
use rustc_middle::bug;
3333
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
3434
use rustc_middle::middle::privacy::{self, Level};
35-
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc};
35+
use rustc_middle::mir::interpret::{ConstAllocation, ErrorHandled, GlobalAlloc};
3636
use rustc_middle::query::Providers;
3737
use rustc_middle::ty::{self, ExistentialTraitRef, TyCtxt};
3838
use rustc_privacy::DefIdVisitor;
@@ -206,11 +206,21 @@ impl<'tcx> ReachableContext<'tcx> {
206206
}
207207
}
208208

209-
// Reachable constants will be inlined into other crates
210-
// unconditionally, so we need to make sure that their
211-
// contents are also reachable.
212209
hir::ItemKind::Const(_, _, init) => {
213-
self.visit_nested_body(init);
210+
// Only things actually ending up in the final constant need to be reachable.
211+
// Everything else is either already available as `mir_for_ctfe`, or can't be used
212+
// by codegen anyway.
213+
match self.tcx.const_eval_poly_to_alloc(item.owner_id.def_id.into()) {
214+
Ok(alloc) => {
215+
let alloc = self.tcx.global_alloc(alloc.alloc_id).unwrap_memory();
216+
self.propagate_from_alloc(alloc);
217+
}
218+
// Reachable generic constants will be inlined into other crates
219+
// unconditionally, so we need to make sure that their
220+
// contents are also reachable.
221+
Err(ErrorHandled::TooGeneric(_)) => self.visit_nested_body(init),
222+
Err(ErrorHandled::Reported(..)) => {}
223+
}
214224
}
215225
hir::ItemKind::Static(..) => {
216226
if let Ok(alloc) = self.tcx.eval_static_initializer(item.owner_id.def_id) {

Diff for: tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs

+17
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,25 @@
33
44
//@compile-flags: --crate-type=lib -Copt-level=0
55

6+
#![feature(generic_const_items)]
7+
68
const fn foo() {}
79

810
pub static FOO: () = foo();
911

1012
// CHECK-NOT: define{{.*}}foo{{.*}}
13+
14+
const fn bar() {}
15+
16+
pub const BAR: () = bar();
17+
18+
// CHECK-NOT: define{{.*}}bar{{.*}}
19+
20+
const fn baz() {}
21+
22+
#[rustfmt::skip]
23+
pub const BAZ<const C: bool>: () = if C {
24+
baz()
25+
};
26+
27+
// CHECK: define{{.*}}baz{{.*}}

0 commit comments

Comments
 (0)