Get rid of special const intrinsic query in favour of `const_eval`
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 09c822f..67b3ce0 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -213,6 +213,15 @@
eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
}
+impl From<ErrorHandled> for InterpErrorInfo<'tcx> {
+ fn from(err: ErrorHandled) -> Self {
+ match err {
+ ErrorHandled::Reported => err_inval!(ReferencedConstant),
+ ErrorHandled::TooGeneric => err_inval!(TooGeneric),
+ }.into()
+ }
+}
+
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
fn from(kind: InterpError<'tcx>) -> Self {
let backtrace = match env::var("RUSTC_CTFE_BACKTRACE") {
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index 4ebc2e7..c726094 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -462,15 +462,6 @@
no_force
desc { "extract field of const" }
}
-
- /// Produces an absolute path representation of the given type. See also the documentation
- /// on `std::any::type_name`.
- query type_name(key: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
- eval_always
- no_force
- desc { "get absolute path of type" }
- }
-
}
TypeChecking {
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 5fbfe91..3f3c5ac1 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -15,6 +15,7 @@
use rustc_codegen_ssa::base::{to_immediate, wants_msvc_seh, compare_simd_types};
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive};
+use rustc::mir::interpret::GlobalId;
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc::hir;
use syntax::ast::{self, FloatTy};
@@ -81,13 +82,14 @@
impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
fn codegen_intrinsic_call(
&mut self,
- callee_ty: Ty<'tcx>,
+ instance: ty::Instance<'tcx>,
fn_ty: &FnType<'tcx, Ty<'tcx>>,
args: &[OperandRef<'tcx, &'ll Value>],
llresult: &'ll Value,
span: Span,
) {
let tcx = self.tcx;
+ let callee_ty = instance.ty(tcx);
let (def_id, substs) = match callee_ty.sty {
ty::FnDef(def_id, substs) => (def_id, substs),
@@ -133,10 +135,6 @@
let llfn = self.get_intrinsic(&("llvm.debugtrap"));
self.call(llfn, &[], None)
}
- "size_of" => {
- let tp_ty = substs.type_at(0);
- self.const_usize(self.size_of(tp_ty).bytes())
- }
"va_start" => {
self.va_start(args[0].immediate())
}
@@ -188,10 +186,6 @@
self.const_usize(self.size_of(tp_ty).bytes())
}
}
- "min_align_of" => {
- let tp_ty = substs.type_at(0);
- self.const_usize(self.align_of(tp_ty).bytes())
- }
"min_align_of_val" => {
let tp_ty = substs.type_at(0);
if let OperandValue::Pair(_, meta) = args[0].val {
@@ -201,18 +195,19 @@
self.const_usize(self.align_of(tp_ty).bytes())
}
}
- "pref_align_of" => {
- let tp_ty = substs.type_at(0);
- self.const_usize(self.layout_of(tp_ty).align.pref.bytes())
- }
+ "size_of" |
+ "pref_align_of" |
+ "min_align_of" |
+ "needs_drop" |
+ "type_id" |
"type_name" => {
- let tp_ty = substs.type_at(0);
- let ty_name = self.tcx.type_name(tp_ty);
+ let gid = GlobalId {
+ instance,
+ promoted: None,
+ };
+ let ty_name = self.tcx.const_eval(ty::ParamEnv::reveal_all().and(gid)).unwrap();
OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self)
}
- "type_id" => {
- self.const_u64(self.tcx.type_id_hash(substs.type_at(0)))
- }
"init" => {
let ty = substs.type_at(0);
if !self.layout_of(ty).is_zst() {
@@ -235,11 +230,6 @@
"uninit" | "forget" => {
return;
}
- "needs_drop" => {
- let tp_ty = substs.type_at(0);
-
- self.const_bool(self.type_needs_drop(tp_ty))
- }
"offset" => {
let ptr = args[0].immediate();
let offset = args[1].immediate();
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 8829a33..1bb0ea5 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -667,8 +667,7 @@
}).collect();
- let callee_ty = instance.as_ref().unwrap().ty(bx.tcx());
- bx.codegen_intrinsic_call(callee_ty, &fn_ty, &args, dest,
+ bx.codegen_intrinsic_call(*instance.as_ref().unwrap(), &fn_ty, &args, dest,
terminator.source_info.span);
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/src/librustc_codegen_ssa/traits/intrinsic.rs
index ede30a0..7c79cd6 100644
--- a/src/librustc_codegen_ssa/traits/intrinsic.rs
+++ b/src/librustc_codegen_ssa/traits/intrinsic.rs
@@ -1,6 +1,6 @@
use super::BackendTypes;
use crate::mir::operand::OperandRef;
-use rustc::ty::Ty;
+use rustc::ty::{self, Ty};
use rustc_target::abi::call::FnType;
use syntax_pos::Span;
@@ -10,7 +10,7 @@
/// add them to librustc_codegen_llvm/context.rs
fn codegen_intrinsic_call(
&mut self,
- callee_ty: Ty<'tcx>,
+ instance: ty::Instance<'tcx>,
fn_ty: &FnType<'tcx, Ty<'tcx>>,
args: &[OperandRef<'tcx, Self::Value>],
llresult: Self::Value,
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 3f53f84..4351598 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -15,6 +15,7 @@
use rustc::ty::layout::{self, LayoutOf, VariantIdx};
use rustc::traits::Reveal;
use rustc_data_structures::fx::FxHashMap;
+use crate::interpret::eval_nullary_intrinsic;
use syntax::source_map::{Span, DUMMY_SP};
@@ -602,6 +603,23 @@
other => return other,
}
}
+
+ // We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
+ // Catch such calls and evaluate them instead of trying to load a constant's MIR.
+ if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def {
+ let ty = key.value.instance.ty(tcx);
+ let substs = match ty.sty {
+ ty::FnDef(_, substs) => substs,
+ _ => bug!("intrinsic with type {:?}", ty),
+ };
+ return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs)
+ .map_err(|error| {
+ let span = tcx.def_span(def_id);
+ let error = ConstEvalErr { error: error.kind, stacktrace: vec![], span };
+ error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic")
+ })
+ }
+
tcx.const_eval_raw(key).and_then(|val| {
validate_and_turn_into_const(tcx, val, key)
})
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 054b65f..78996ed 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -14,7 +14,6 @@
use rustc::ty::query::TyCtxtAt;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::mir::interpret::{
- ErrorHandled,
GlobalId, Scalar, Pointer, FrameInfo, AllocId,
InterpResult, truncate, sign_extend,
};
@@ -672,14 +671,7 @@
// Our result will later be validated anyway, and there seems no good reason
// to have to fail early here. This is also more consistent with
// `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
- let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| {
- match err {
- ErrorHandled::Reported =>
- err_inval!(ReferencedConstant),
- ErrorHandled::TooGeneric =>
- err_inval!(TooGeneric),
- }
- })?;
+ let val = self.tcx.const_eval_raw(param_env.and(gid))?;
self.raw_const_to_mplace(val)
}
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 0f2305e..ec09e69 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -5,17 +5,18 @@
use syntax::symbol::Symbol;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, Primitive, Size};
+use rustc::ty::subst::SubstsRef;
+use rustc::hir::def_id::DefId;
+use rustc::ty::TyCtxt;
use rustc::mir::BinOp;
-use rustc::mir::interpret::{InterpResult, Scalar};
+use rustc::mir::interpret::{InterpResult, Scalar, GlobalId, ConstValue};
use super::{
- Machine, PlaceTy, OpTy, InterpCx, Immediate,
+ Machine, PlaceTy, OpTy, InterpCx,
};
mod type_name;
-pub use type_name::*;
-
fn numeric_intrinsic<'tcx, Tag>(
name: &str,
bits: u128,
@@ -37,6 +38,50 @@
Ok(Scalar::from_uint(bits_out, size))
}
+/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated
+/// inside an `InterpCx` and instead have their value computed directly from rustc internal info.
+crate fn eval_nullary_intrinsic<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+) -> InterpResult<'tcx, &'tcx ty::Const<'tcx>> {
+ let tp_ty = substs.type_at(0);
+ let name = &*tcx.item_name(def_id).as_str();
+ Ok(match name {
+ "type_name" => {
+ let alloc = type_name::alloc_type_name(tcx, tp_ty);
+ tcx.mk_const(ty::Const {
+ val: ConstValue::Slice {
+ data: alloc,
+ start: 0,
+ end: alloc.len(),
+ },
+ ty: tcx.mk_static_str(),
+ })
+ },
+ "needs_drop" => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)),
+ "size_of" |
+ "min_align_of" |
+ "pref_align_of" => {
+ let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
+ let n = match name {
+ "pref_align_of" => layout.align.pref.bytes(),
+ "min_align_of" => layout.align.abi.bytes(),
+ "size_of" => layout.size.bytes(),
+ _ => bug!(),
+ };
+ ty::Const::from_usize(tcx, n)
+ },
+ "type_id" => ty::Const::from_bits(
+ tcx,
+ tcx.type_id_hash(tp_ty).into(),
+ param_env.and(tcx.types.u64),
+ ),
+ other => bug!("`{}` is not a zero arg intrinsic", other),
+ })
+}
+
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Returns `true` if emulation happened.
pub fn emulate_intrinsic(
@@ -49,41 +94,19 @@
let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
match intrinsic_name {
- "min_align_of" => {
- let elem_ty = substs.type_at(0);
- let elem_align = self.layout_of(elem_ty)?.align.abi.bytes();
- let align_val = Scalar::from_uint(elem_align, dest.layout.size);
- self.write_scalar(align_val, dest)?;
- }
-
- "needs_drop" => {
- let ty = substs.type_at(0);
- let ty_needs_drop = ty.needs_drop(self.tcx.tcx, self.param_env);
- let val = Scalar::from_bool(ty_needs_drop);
- self.write_scalar(val, dest)?;
- }
-
- "size_of" => {
- let ty = substs.type_at(0);
- let size = self.layout_of(ty)?.size.bytes() as u128;
- let size_val = Scalar::from_uint(size, dest.layout.size);
- self.write_scalar(size_val, dest)?;
- }
-
- "type_id" => {
- let ty = substs.type_at(0);
- let type_id = self.tcx.type_id_hash(ty) as u128;
- let id_val = Scalar::from_uint(type_id, dest.layout.size);
- self.write_scalar(id_val, dest)?;
- }
-
+ "min_align_of" |
+ "pref_align_of" |
+ "needs_drop" |
+ "size_of" |
+ "type_id" |
"type_name" => {
- let alloc = alloc_type_name(self.tcx.tcx, substs.type_at(0));
- let name_id = self.tcx.alloc_map.lock().create_memory_alloc(alloc);
- let id_ptr = self.memory.tag_static_base_pointer(name_id.into());
- let alloc_len = alloc.size.bytes();
- let name_val = Immediate::new_slice(Scalar::Ptr(id_ptr), alloc_len, self);
- self.write_immediate(name_val, dest)?;
+ let gid = GlobalId {
+ instance,
+ promoted: None,
+ };
+ let val = self.tcx.const_eval(self.param_env.and(gid))?;
+ let val = self.eval_const_to_op(val, None)?;
+ self.copy_op(val, dest)?;
}
| "ctpop"
diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/src/librustc_mir/interpret/intrinsics/type_name.rs
index 032d16a..1e765a4 100644
--- a/src/librustc_mir/interpret/intrinsics/type_name.rs
+++ b/src/librustc_mir/interpret/intrinsics/type_name.rs
@@ -7,7 +7,7 @@
use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
use rustc::hir::def_id::CrateNum;
use std::fmt::Write;
-use rustc::mir::interpret::{Allocation, ConstValue};
+use rustc::mir::interpret::Allocation;
struct AbsolutePathPrinter<'tcx> {
tcx: TyCtxt<'tcx>,
@@ -213,22 +213,11 @@
}
}
-/// Produces an absolute path representation of the given type. See also the documentation on
-/// `std::any::type_name`
-pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
- let alloc = alloc_type_name(tcx, ty);
- tcx.mk_const(ty::Const {
- val: ConstValue::Slice {
- data: alloc,
- start: 0,
- end: alloc.len(),
- },
- ty: tcx.mk_static_str(),
- })
-}
-
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
-pub(super) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation {
+crate fn alloc_type_name<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>
+) -> &'tcx Allocation {
let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes());
tcx.intern_const_alloc(alloc)
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index 45d2434..0c61be2 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -34,6 +34,6 @@
pub use self::validity::RefTracking;
-pub(super) use self::intrinsics::type_name;
-
pub use self::intern::intern_const_alloc_recursive;
+
+crate use self::intrinsics::eval_nullary_intrinsic;
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index f27db35..034ad5b 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -59,5 +59,4 @@
let (param_env, (value, field)) = param_env_and_value.into_parts();
const_eval::const_field(tcx, param_env, None, field, value)
};
- providers.type_name = interpret::type_name;
}
diff --git a/src/test/ui/issues/issue-44415.rs b/src/test/compile-fail/issue-44415.rs
similarity index 100%
rename from src/test/ui/issues/issue-44415.rs
rename to src/test/compile-fail/issue-44415.rs
diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr
index fdba359..1ae39e7 100644
--- a/src/test/ui/consts/const-size_of-cycle.stderr
+++ b/src/test/ui/consts/const-size_of-cycle.stderr
@@ -14,6 +14,11 @@
|
LL | intrinsics::size_of::<T>()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const-evaluating + checking `std::intrinsics::size_of`...
+ --> $SRC_DIR/libcore/intrinsics.rs:LL:COL
+ |
+LL | pub fn size_of<T>() -> usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing layout of `Foo`...
= note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
= note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle
diff --git a/src/test/ui/issues/issue-44415.stderr b/src/test/ui/issues/issue-44415.stderr
deleted file mode 100644
index 8008e53..0000000
--- a/src/test/ui/issues/issue-44415.stderr
+++ /dev/null
@@ -1,28 +0,0 @@
-error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{constant}}#0`
- --> $DIR/issue-44415.rs:6:17
- |
-LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
- | ^^^^^^
- |
-note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`...
- --> $DIR/issue-44415.rs:6:17
- |
-LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
- | ^^^^^^
-note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`...
- --> $DIR/issue-44415.rs:6:26
- |
-LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: ...which requires computing layout of `Foo`...
- = note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
- = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle
-note: cycle used when processing `Foo`
- --> $DIR/issue-44415.rs:5:1
- |
-LL | struct Foo {
- | ^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0391`.