Skip to content

Commit b539c71

Browse files
authored
Rollup merge of rust-lang#61626 - oli-obk:const_eval_intrinsics, r=eddyb
Get rid of special const intrinsic query in favour of `const_eval` r? @eddyb
2 parents 9150f84 + 0de9485 commit b539c71

File tree

14 files changed

+117
-130
lines changed

14 files changed

+117
-130
lines changed

src/librustc/mir/interpret/error.rs

+9
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,15 @@ fn print_backtrace(backtrace: &mut Backtrace) {
213213
eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
214214
}
215215

216+
impl From<ErrorHandled> for InterpErrorInfo<'tcx> {
217+
fn from(err: ErrorHandled) -> Self {
218+
match err {
219+
ErrorHandled::Reported => err_inval!(ReferencedConstant),
220+
ErrorHandled::TooGeneric => err_inval!(TooGeneric),
221+
}.into()
222+
}
223+
}
224+
216225
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
217226
fn from(kind: InterpError<'tcx>) -> Self {
218227
let backtrace = match env::var("RUSTC_CTFE_BACKTRACE") {

src/librustc/query/mod.rs

-9
Original file line numberDiff line numberDiff line change
@@ -462,15 +462,6 @@ rustc_queries! {
462462
no_force
463463
desc { "extract field of const" }
464464
}
465-
466-
/// Produces an absolute path representation of the given type. See also the documentation
467-
/// on `std::any::type_name`.
468-
query type_name(key: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
469-
eval_always
470-
no_force
471-
desc { "get absolute path of type" }
472-
}
473-
474465
}
475466

476467
TypeChecking {

src/librustc_codegen_llvm/intrinsic.rs

+13-23
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_codegen_ssa::glue;
1515
use rustc_codegen_ssa::base::{to_immediate, wants_msvc_seh, compare_simd_types};
1616
use rustc::ty::{self, Ty};
1717
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive};
18+
use rustc::mir::interpret::GlobalId;
1819
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
1920
use rustc::hir;
2021
use syntax::ast::{self, FloatTy};
@@ -81,13 +82,14 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Valu
8182
impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
8283
fn codegen_intrinsic_call(
8384
&mut self,
84-
callee_ty: Ty<'tcx>,
85+
instance: ty::Instance<'tcx>,
8586
fn_ty: &FnType<'tcx, Ty<'tcx>>,
8687
args: &[OperandRef<'tcx, &'ll Value>],
8788
llresult: &'ll Value,
8889
span: Span,
8990
) {
9091
let tcx = self.tcx;
92+
let callee_ty = instance.ty(tcx);
9193

9294
let (def_id, substs) = match callee_ty.sty {
9395
ty::FnDef(def_id, substs) => (def_id, substs),
@@ -133,10 +135,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
133135
let llfn = self.get_intrinsic(&("llvm.debugtrap"));
134136
self.call(llfn, &[], None)
135137
}
136-
"size_of" => {
137-
let tp_ty = substs.type_at(0);
138-
self.const_usize(self.size_of(tp_ty).bytes())
139-
}
140138
"va_start" => {
141139
self.va_start(args[0].immediate())
142140
}
@@ -188,10 +186,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
188186
self.const_usize(self.size_of(tp_ty).bytes())
189187
}
190188
}
191-
"min_align_of" => {
192-
let tp_ty = substs.type_at(0);
193-
self.const_usize(self.align_of(tp_ty).bytes())
194-
}
195189
"min_align_of_val" => {
196190
let tp_ty = substs.type_at(0);
197191
if let OperandValue::Pair(_, meta) = args[0].val {
@@ -201,18 +195,19 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
201195
self.const_usize(self.align_of(tp_ty).bytes())
202196
}
203197
}
204-
"pref_align_of" => {
205-
let tp_ty = substs.type_at(0);
206-
self.const_usize(self.layout_of(tp_ty).align.pref.bytes())
207-
}
198+
"size_of" |
199+
"pref_align_of" |
200+
"min_align_of" |
201+
"needs_drop" |
202+
"type_id" |
208203
"type_name" => {
209-
let tp_ty = substs.type_at(0);
210-
let ty_name = self.tcx.type_name(tp_ty);
204+
let gid = GlobalId {
205+
instance,
206+
promoted: None,
207+
};
208+
let ty_name = self.tcx.const_eval(ty::ParamEnv::reveal_all().and(gid)).unwrap();
211209
OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self)
212210
}
213-
"type_id" => {
214-
self.const_u64(self.tcx.type_id_hash(substs.type_at(0)))
215-
}
216211
"init" => {
217212
let ty = substs.type_at(0);
218213
if !self.layout_of(ty).is_zst() {
@@ -235,11 +230,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
235230
"uninit" | "forget" => {
236231
return;
237232
}
238-
"needs_drop" => {
239-
let tp_ty = substs.type_at(0);
240-
241-
self.const_bool(self.type_needs_drop(tp_ty))
242-
}
243233
"offset" => {
244234
let ptr = args[0].immediate();
245235
let offset = args[1].immediate();

src/librustc_codegen_ssa/mir/block.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -667,8 +667,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
667667
}).collect();
668668

669669

670-
let callee_ty = instance.as_ref().unwrap().ty(bx.tcx());
671-
bx.codegen_intrinsic_call(callee_ty, &fn_ty, &args, dest,
670+
bx.codegen_intrinsic_call(*instance.as_ref().unwrap(), &fn_ty, &args, dest,
672671
terminator.source_info.span);
673672

674673
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {

src/librustc_codegen_ssa/traits/intrinsic.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::BackendTypes;
22
use crate::mir::operand::OperandRef;
3-
use rustc::ty::Ty;
3+
use rustc::ty::{self, Ty};
44
use rustc_target::abi::call::FnType;
55
use syntax_pos::Span;
66

@@ -10,7 +10,7 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes {
1010
/// add them to librustc_codegen_llvm/context.rs
1111
fn codegen_intrinsic_call(
1212
&mut self,
13-
callee_ty: Ty<'tcx>,
13+
instance: ty::Instance<'tcx>,
1414
fn_ty: &FnType<'tcx, Ty<'tcx>>,
1515
args: &[OperandRef<'tcx, Self::Value>],
1616
llresult: Self::Value,

src/librustc_mir/const_eval.rs

+18
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc::ty::{self, Ty, TyCtxt, subst::Subst};
1515
use rustc::ty::layout::{self, LayoutOf, VariantIdx};
1616
use rustc::traits::Reveal;
1717
use rustc_data_structures::fx::FxHashMap;
18+
use crate::interpret::eval_nullary_intrinsic;
1819

1920
use syntax::source_map::{Span, DUMMY_SP};
2021

@@ -602,6 +603,23 @@ pub fn const_eval_provider<'tcx>(
602603
other => return other,
603604
}
604605
}
606+
607+
// We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
608+
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
609+
if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def {
610+
let ty = key.value.instance.ty(tcx);
611+
let substs = match ty.sty {
612+
ty::FnDef(_, substs) => substs,
613+
_ => bug!("intrinsic with type {:?}", ty),
614+
};
615+
return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs)
616+
.map_err(|error| {
617+
let span = tcx.def_span(def_id);
618+
let error = ConstEvalErr { error: error.kind, stacktrace: vec![], span };
619+
error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic")
620+
})
621+
}
622+
605623
tcx.const_eval_raw(key).and_then(|val| {
606624
validate_and_turn_into_const(tcx, val, key)
607625
})

src/librustc_mir/interpret/eval_context.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
1414
use rustc::ty::query::TyCtxtAt;
1515
use rustc_data_structures::indexed_vec::IndexVec;
1616
use rustc::mir::interpret::{
17-
ErrorHandled,
1817
GlobalId, Scalar, Pointer, FrameInfo, AllocId,
1918
InterpResult, truncate, sign_extend,
2019
};
@@ -672,14 +671,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
672671
// Our result will later be validated anyway, and there seems no good reason
673672
// to have to fail early here. This is also more consistent with
674673
// `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
675-
let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| {
676-
match err {
677-
ErrorHandled::Reported =>
678-
err_inval!(ReferencedConstant),
679-
ErrorHandled::TooGeneric =>
680-
err_inval!(TooGeneric),
681-
}
682-
})?;
674+
let val = self.tcx.const_eval_raw(param_env.and(gid))?;
683675
self.raw_const_to_mplace(val)
684676
}
685677

src/librustc_mir/interpret/intrinsics.rs

+61-38
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@
55
use syntax::symbol::Symbol;
66
use rustc::ty;
77
use rustc::ty::layout::{LayoutOf, Primitive, Size};
8+
use rustc::ty::subst::SubstsRef;
9+
use rustc::hir::def_id::DefId;
10+
use rustc::ty::TyCtxt;
811
use rustc::mir::BinOp;
9-
use rustc::mir::interpret::{InterpResult, Scalar};
12+
use rustc::mir::interpret::{InterpResult, Scalar, GlobalId, ConstValue};
1013

1114
use super::{
12-
Machine, PlaceTy, OpTy, InterpCx, Immediate,
15+
Machine, PlaceTy, OpTy, InterpCx,
1316
};
1417

1518
mod type_name;
1619

17-
pub use type_name::*;
18-
1920
fn numeric_intrinsic<'tcx, Tag>(
2021
name: &str,
2122
bits: u128,
@@ -37,6 +38,50 @@ fn numeric_intrinsic<'tcx, Tag>(
3738
Ok(Scalar::from_uint(bits_out, size))
3839
}
3940

41+
/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated
42+
/// inside an `InterpCx` and instead have their value computed directly from rustc internal info.
43+
crate fn eval_nullary_intrinsic<'tcx>(
44+
tcx: TyCtxt<'tcx>,
45+
param_env: ty::ParamEnv<'tcx>,
46+
def_id: DefId,
47+
substs: SubstsRef<'tcx>,
48+
) -> InterpResult<'tcx, &'tcx ty::Const<'tcx>> {
49+
let tp_ty = substs.type_at(0);
50+
let name = &*tcx.item_name(def_id).as_str();
51+
Ok(match name {
52+
"type_name" => {
53+
let alloc = type_name::alloc_type_name(tcx, tp_ty);
54+
tcx.mk_const(ty::Const {
55+
val: ConstValue::Slice {
56+
data: alloc,
57+
start: 0,
58+
end: alloc.len(),
59+
},
60+
ty: tcx.mk_static_str(),
61+
})
62+
},
63+
"needs_drop" => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)),
64+
"size_of" |
65+
"min_align_of" |
66+
"pref_align_of" => {
67+
let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
68+
let n = match name {
69+
"pref_align_of" => layout.align.pref.bytes(),
70+
"min_align_of" => layout.align.abi.bytes(),
71+
"size_of" => layout.size.bytes(),
72+
_ => bug!(),
73+
};
74+
ty::Const::from_usize(tcx, n)
75+
},
76+
"type_id" => ty::Const::from_bits(
77+
tcx,
78+
tcx.type_id_hash(tp_ty).into(),
79+
param_env.and(tcx.types.u64),
80+
),
81+
other => bug!("`{}` is not a zero arg intrinsic", other),
82+
})
83+
}
84+
4085
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
4186
/// Returns `true` if emulation happened.
4287
pub fn emulate_intrinsic(
@@ -49,41 +94,19 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
4994

5095
let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
5196
match intrinsic_name {
52-
"min_align_of" => {
53-
let elem_ty = substs.type_at(0);
54-
let elem_align = self.layout_of(elem_ty)?.align.abi.bytes();
55-
let align_val = Scalar::from_uint(elem_align, dest.layout.size);
56-
self.write_scalar(align_val, dest)?;
57-
}
58-
59-
"needs_drop" => {
60-
let ty = substs.type_at(0);
61-
let ty_needs_drop = ty.needs_drop(self.tcx.tcx, self.param_env);
62-
let val = Scalar::from_bool(ty_needs_drop);
63-
self.write_scalar(val, dest)?;
64-
}
65-
66-
"size_of" => {
67-
let ty = substs.type_at(0);
68-
let size = self.layout_of(ty)?.size.bytes() as u128;
69-
let size_val = Scalar::from_uint(size, dest.layout.size);
70-
self.write_scalar(size_val, dest)?;
71-
}
72-
73-
"type_id" => {
74-
let ty = substs.type_at(0);
75-
let type_id = self.tcx.type_id_hash(ty) as u128;
76-
let id_val = Scalar::from_uint(type_id, dest.layout.size);
77-
self.write_scalar(id_val, dest)?;
78-
}
79-
97+
"min_align_of" |
98+
"pref_align_of" |
99+
"needs_drop" |
100+
"size_of" |
101+
"type_id" |
80102
"type_name" => {
81-
let alloc = alloc_type_name(self.tcx.tcx, substs.type_at(0));
82-
let name_id = self.tcx.alloc_map.lock().create_memory_alloc(alloc);
83-
let id_ptr = self.memory.tag_static_base_pointer(name_id.into());
84-
let alloc_len = alloc.size.bytes();
85-
let name_val = Immediate::new_slice(Scalar::Ptr(id_ptr), alloc_len, self);
86-
self.write_immediate(name_val, dest)?;
103+
let gid = GlobalId {
104+
instance,
105+
promoted: None,
106+
};
107+
let val = self.tcx.const_eval(self.param_env.and(gid))?;
108+
let val = self.eval_const_to_op(val, None)?;
109+
self.copy_op(val, dest)?;
87110
}
88111

89112
| "ctpop"

src/librustc_mir/interpret/intrinsics/type_name.rs

+5-16
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc::ty::{
77
use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
88
use rustc::hir::def_id::CrateNum;
99
use std::fmt::Write;
10-
use rustc::mir::interpret::{Allocation, ConstValue};
10+
use rustc::mir::interpret::Allocation;
1111

1212
struct AbsolutePathPrinter<'tcx> {
1313
tcx: TyCtxt<'tcx>,
@@ -213,22 +213,11 @@ impl Write for AbsolutePathPrinter<'_> {
213213
}
214214
}
215215

216-
/// Produces an absolute path representation of the given type. See also the documentation on
217-
/// `std::any::type_name`
218-
pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
219-
let alloc = alloc_type_name(tcx, ty);
220-
tcx.mk_const(ty::Const {
221-
val: ConstValue::Slice {
222-
data: alloc,
223-
start: 0,
224-
end: alloc.len(),
225-
},
226-
ty: tcx.mk_static_str(),
227-
})
228-
}
229-
230216
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
231-
pub(super) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation {
217+
crate fn alloc_type_name<'tcx>(
218+
tcx: TyCtxt<'tcx>,
219+
ty: Ty<'tcx>
220+
) -> &'tcx Allocation {
232221
let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
233222
let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes());
234223
tcx.intern_const_alloc(alloc)

src/librustc_mir/interpret/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ pub use self::visitor::{ValueVisitor, MutValueVisitor};
3434

3535
pub use self::validity::RefTracking;
3636

37-
pub(super) use self::intrinsics::type_name;
38-
3937
pub use self::intern::intern_const_alloc_recursive;
38+
39+
crate use self::intrinsics::eval_nullary_intrinsic;

src/librustc_mir/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,4 @@ pub fn provide(providers: &mut Providers<'_>) {
5959
let (param_env, (value, field)) = param_env_and_value.into_parts();
6060
const_eval::const_field(tcx, param_env, None, field, value)
6161
};
62-
providers.type_name = interpret::type_name;
6362
}
File renamed without changes.

src/test/ui/consts/const-size_of-cycle.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`...
1414
|
1515
LL | intrinsics::size_of::<T>()
1616
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
17+
note: ...which requires const-evaluating + checking `std::intrinsics::size_of`...
18+
--> $SRC_DIR/libcore/intrinsics.rs:LL:COL
19+
|
20+
LL | pub fn size_of<T>() -> usize;
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1722
= note: ...which requires computing layout of `Foo`...
1823
= note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
1924
= note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle

0 commit comments

Comments
 (0)