From 7a2cb7d9e4e47ea31fa7c4d95a728ab2365f7b38 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 7 Jun 2019 19:22:42 +0200 Subject: [PATCH 01/12] Get rid of special const intrinsic query in favour of `const_eval` --- src/librustc/query/mod.rs | 9 ----- src/librustc_codegen_llvm/intrinsic.rs | 11 ++++-- src/librustc_codegen_ssa/mir/block.rs | 3 +- src/librustc_codegen_ssa/traits/intrinsic.rs | 4 +-- src/librustc_mir/const_eval.rs | 34 ++++++++++++++++++- src/librustc_mir/interpret/intrinsics.rs | 2 +- .../interpret/intrinsics/type_name.rs | 21 +++--------- src/librustc_mir/interpret/mod.rs | 4 +-- src/librustc_mir/lib.rs | 1 - 9 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 5ab1b90642a6a..91983361945f5 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -449,15 +449,6 @@ rustc_queries! { 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 199170182e4b4..7a0d42eeae88d 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -15,6 +15,7 @@ use rustc_codegen_ssa::glue; 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 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Valu 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), @@ -206,8 +208,11 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.const_usize(self.layout_of(tp_ty).align.pref.bytes()) } "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" => { diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 006ebcbdec672..83d6262bb3334 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -666,8 +666,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }).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 ede30a0bed756..7c79cd6021031 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 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { /// 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 36d80d0cb5767..1e304bf327a10 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -13,9 +13,10 @@ use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef}; use rustc::mir; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{self, LayoutOf, VariantIdx}; -use rustc::ty::subst::Subst; +use rustc::ty::subst::{Subst, SubstsRef}; use rustc::traits::Reveal; use rustc_data_structures::fx::FxHashMap; +use crate::interpret::alloc_type_name; use syntax::source_map::{Span, DUMMY_SP}; @@ -610,11 +611,42 @@ pub fn const_eval_provider<'tcx>( other => return other, } } + + 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 Ok(eval_intrinsic(tcx, def_id, substs)); + } + tcx.const_eval_raw(key).and_then(|val| { validate_and_turn_into_const(tcx, val, key) }) } +fn eval_intrinsic<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, +) -> &'tcx ty::Const<'tcx> { + match &*tcx.item_name(def_id).as_str() { + "type_name" => { + let alloc = alloc_type_name(tcx, substs.type_at(0)); + tcx.mk_const(ty::Const { + val: ConstValue::Slice { + data: alloc, + start: 0, + end: alloc.bytes.len(), + }, + ty: tcx.mk_static_str(), + }) + }, + other => bug!("`{}` is not a zero arg intrinsic", other), + } +} + pub fn const_eval_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 89c5be137a4e5..d70c28dbec806 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -14,7 +14,7 @@ use super::{ mod type_name; -pub use type_name::*; +pub(crate) use type_name::alloc_type_name; fn numeric_intrinsic<'tcx, Tag>( name: &str, diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/src/librustc_mir/interpret/intrinsics/type_name.rs index f207cfc6b39cd..b9e81266d2dc0 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::ty::{ 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 @@ impl Write for AbsolutePathPrinter<'_> { } } -/// 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.bytes.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 { +pub(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 45d24347e4efd..3dd9689ad6c72 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -34,6 +34,6 @@ pub use self::visitor::{ValueVisitor, MutValueVisitor}; pub use self::validity::RefTracking; -pub(super) use self::intrinsics::type_name; - pub use self::intern::intern_const_alloc_recursive; + +pub(crate) use self::intrinsics::alloc_type_name; diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 20d5e54d2ce49..99b07f6b10bcd 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -59,7 +59,6 @@ pub fn provide(providers: &mut Providers<'_>) { 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; } __build_diagnostic_array! { librustc_mir, DIAGNOSTICS } From b9f70c5b41fbed1eb7cd45708097a71894839523 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 19 Jun 2019 19:41:44 +0200 Subject: [PATCH 02/12] Port more zero arg intrinsics to the `const_eval` query --- src/librustc/mir/interpret/error.rs | 9 ++++ src/librustc_codegen_llvm/intrinsic.rs | 25 ++-------- src/librustc_mir/const_eval.rs | 27 ++++++++-- src/librustc_mir/interpret/eval_context.rs | 10 +--- src/librustc_mir/interpret/intrinsics.rs | 49 +++++-------------- src/test/ui/consts/const-size_of-cycle.stderr | 10 ++++ src/test/ui/issues/issue-44415.stderr | 10 ++++ 7 files changed, 72 insertions(+), 68 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index f53d2ffb6df54..17224e22a63ed 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -215,6 +215,15 @@ fn print_backtrace(backtrace: &mut Backtrace) { eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace); } +impl From for InterpErrorInfo<'tcx> { + fn from(err: ErrorHandled) -> Self { + match err { + ErrorHandled::Reported => err_inval!(ReferencedConstant), + ErrorHandled::TooGeneric => err_inval!(TooGeneric), + } + } +} + impl<'tcx> From> for InterpErrorInfo<'tcx> { fn from(kind: InterpError<'tcx>) -> Self { let backtrace = match env::var("RUST_CTFE_BACKTRACE") { diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 7a0d42eeae88d..bcedf7f7fe584 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -135,10 +135,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { 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()) } @@ -190,10 +186,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { 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 { @@ -203,10 +195,11 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { 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 gid = GlobalId { instance, @@ -215,9 +208,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { 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() { @@ -240,11 +230,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { "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_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 1e304bf327a10..dfea55e426f8e 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -618,7 +618,7 @@ pub fn const_eval_provider<'tcx>( ty::FnDef(_, substs) => substs, _ => bug!("intrinsic with type {:?}", ty), }; - return Ok(eval_intrinsic(tcx, def_id, substs)); + return Ok(eval_intrinsic(tcx, key.param_env, def_id, substs)); } tcx.const_eval_raw(key).and_then(|val| { @@ -628,12 +628,15 @@ pub fn const_eval_provider<'tcx>( fn eval_intrinsic<'tcx>( tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, ) -> &'tcx ty::Const<'tcx> { - match &*tcx.item_name(def_id).as_str() { + let tp_ty = substs.type_at(0); + let name = &*tcx.item_name(def_id).as_str(); + match name { "type_name" => { - let alloc = alloc_type_name(tcx, substs.type_at(0)); + let alloc = alloc_type_name(tcx, tp_ty); tcx.mk_const(ty::Const { val: ConstValue::Slice { data: alloc, @@ -643,6 +646,24 @@ fn eval_intrinsic<'tcx>( 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)).unwrap(); + 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), } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 1f23d8c017ccd..b936948587deb 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -14,7 +14,6 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; 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, }; @@ -692,14 +691,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // 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 d70c28dbec806..de9adb5297f4b 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -6,10 +6,10 @@ use syntax::symbol::Symbol; use rustc::ty; use rustc::ty::layout::{LayoutOf, Primitive, Size}; use rustc::mir::BinOp; -use rustc::mir::interpret::{InterpResult, Scalar}; +use rustc::mir::interpret::{InterpResult, Scalar, GlobalId}; use super::{ - Machine, PlaceTy, OpTy, InterpCx, Immediate, + Machine, PlaceTy, OpTy, InterpCx, }; mod type_name; @@ -49,41 +49,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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" | + "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.bytes.len() as u64; - 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(ty::ParamEnv::reveal_all().and(gid))?; + let val = self.eval_const_to_op(val, None)?; + self.copy_op(val, dest)?; } | "ctpop" diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 113ec29239616..fc772830a972d 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -9,6 +9,16 @@ note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`... | LL | intrinsics::size_of::() | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `std::intrinsics::size_of`... + --> $SRC_DIR/libcore/intrinsics.rs:LL:COL + | +LL | pub fn size_of() -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `std::intrinsics::size_of`... + --> $SRC_DIR/libcore/intrinsics.rs:LL:COL + | +LL | pub fn size_of() -> 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 requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... diff --git a/src/test/ui/issues/issue-44415.stderr b/src/test/ui/issues/issue-44415.stderr index df8e804c87a3f..e27375bf958d9 100644 --- a/src/test/ui/issues/issue-44415.stderr +++ b/src/test/ui/issues/issue-44415.stderr @@ -9,6 +9,16 @@ note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`... | LL | bytes: [u8; unsafe { intrinsics::size_of::() }], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `std::intrinsics::size_of`... + --> $SRC_DIR/libcore/intrinsics.rs:LL:COL + | +LL | pub fn size_of() -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `std::intrinsics::size_of`... + --> $SRC_DIR/libcore/intrinsics.rs:LL:COL + | +LL | pub fn size_of() -> 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 requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... From b0fd253cc2aa6372c5054465d5970d7f56f69f5c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 21 Jun 2019 09:34:09 +0200 Subject: [PATCH 03/12] Rename `eval_intrinsic` to `eval_nulary_intrinsic` --- src/librustc_mir/const_eval.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index dfea55e426f8e..1e3a92ead6064 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -618,7 +618,7 @@ pub fn const_eval_provider<'tcx>( ty::FnDef(_, substs) => substs, _ => bug!("intrinsic with type {:?}", ty), }; - return Ok(eval_intrinsic(tcx, key.param_env, def_id, substs)); + return Ok(eval_nulary_intrinsic(tcx, key.param_env, def_id, substs)); } tcx.const_eval_raw(key).and_then(|val| { @@ -626,7 +626,7 @@ pub fn const_eval_provider<'tcx>( }) } -fn eval_intrinsic<'tcx>( +fn eval_nulary_intrinsic<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, def_id: DefId, From cc3d6266d0f0ad3affa557fbb1e29c6d63baf72a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 18 Jul 2019 16:19:43 +0200 Subject: [PATCH 04/12] Move nulary intrinsic logic to the other intrinsic logic --- src/librustc_mir/const_eval.rs | 46 +--------------------- src/librustc_mir/interpret/intrinsics.rs | 50 ++++++++++++++++++++++-- src/librustc_mir/interpret/mod.rs | 2 +- 3 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 1e3a92ead6064..150864bbfe417 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -13,10 +13,10 @@ use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef}; use rustc::mir; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{self, LayoutOf, VariantIdx}; -use rustc::ty::subst::{Subst, SubstsRef}; +use rustc::ty::subst::Subst; use rustc::traits::Reveal; use rustc_data_structures::fx::FxHashMap; -use crate::interpret::alloc_type_name; +use crate::interpret::eval_nulary_intrinsic; use syntax::source_map::{Span, DUMMY_SP}; @@ -626,48 +626,6 @@ pub fn const_eval_provider<'tcx>( }) } -fn eval_nulary_intrinsic<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, -) -> &'tcx ty::Const<'tcx> { - let tp_ty = substs.type_at(0); - let name = &*tcx.item_name(def_id).as_str(); - match name { - "type_name" => { - let alloc = alloc_type_name(tcx, tp_ty); - tcx.mk_const(ty::Const { - val: ConstValue::Slice { - data: alloc, - start: 0, - end: alloc.bytes.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)).unwrap(); - 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), - } -} - pub fn const_eval_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index de9adb5297f4b..275f468310690 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -5,8 +5,11 @@ 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, GlobalId}; +use rustc::mir::interpret::{InterpResult, Scalar, GlobalId, ConstValue}; use super::{ Machine, PlaceTy, OpTy, InterpCx, @@ -14,8 +17,6 @@ use super::{ mod type_name; -pub(crate) use type_name::alloc_type_name; - fn numeric_intrinsic<'tcx, Tag>( name: &str, bits: u128, @@ -37,6 +38,49 @@ fn numeric_intrinsic<'tcx, Tag>( Ok(Scalar::from_uint(bits_out, size)) } + +crate fn eval_nulary_intrinsic<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, +) -> &'tcx ty::Const<'tcx> { + let tp_ty = substs.type_at(0); + let name = &*tcx.item_name(def_id).as_str(); + 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.bytes.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)).unwrap(); + 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( diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index 3dd9689ad6c72..f4bed928c8d0a 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -36,4 +36,4 @@ pub use self::validity::RefTracking; pub use self::intern::intern_const_alloc_recursive; -pub(crate) use self::intrinsics::alloc_type_name; +pub(crate) use self::intrinsics::eval_nulary_intrinsic; From 102048ca942579417055f9762dcb9d19227d963a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 9 Aug 2019 16:05:39 +0200 Subject: [PATCH 05/12] Fixup interp error conversion --- src/librustc/mir/interpret/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 17224e22a63ed..dba097d76cba1 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -220,7 +220,7 @@ impl From for InterpErrorInfo<'tcx> { match err { ErrorHandled::Reported => err_inval!(ReferencedConstant), ErrorHandled::TooGeneric => err_inval!(TooGeneric), - } + }.into() } } From 869e2c8181e73c74aa26753b97ef835b436c8a44 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 11 Aug 2019 17:37:27 +0200 Subject: [PATCH 06/12] Add more documentation --- src/librustc_mir/const_eval.rs | 6 ++++-- src/librustc_mir/interpret/intrinsics.rs | 5 +++-- src/librustc_mir/interpret/intrinsics/type_name.rs | 2 +- src/librustc_mir/interpret/mod.rs | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 150864bbfe417..23f7a009e23c1 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -16,7 +16,7 @@ use rustc::ty::layout::{self, LayoutOf, VariantIdx}; use rustc::ty::subst::Subst; use rustc::traits::Reveal; use rustc_data_structures::fx::FxHashMap; -use crate::interpret::eval_nulary_intrinsic; +use crate::interpret::eval_nullary_intrinsic; use syntax::source_map::{Span, DUMMY_SP}; @@ -612,13 +612,15 @@ pub fn const_eval_provider<'tcx>( } } + // 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 Ok(eval_nulary_intrinsic(tcx, key.param_env, def_id, substs)); + return Ok(eval_nullary_intrinsic(tcx, key.param_env, def_id, substs)); } tcx.const_eval_raw(key).and_then(|val| { diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 275f468310690..7ba057aa23fce 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -38,8 +38,9 @@ fn numeric_intrinsic<'tcx, Tag>( Ok(Scalar::from_uint(bits_out, size)) } - -crate fn eval_nulary_intrinsic<'tcx>( +/// 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, diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/src/librustc_mir/interpret/intrinsics/type_name.rs index b9e81266d2dc0..1e765a4ed982c 100644 --- a/src/librustc_mir/interpret/intrinsics/type_name.rs +++ b/src/librustc_mir/interpret/intrinsics/type_name.rs @@ -214,7 +214,7 @@ impl Write for AbsolutePathPrinter<'_> { } /// Directly returns an `Allocation` containing an absolute path representation of the given type. -pub(crate) fn alloc_type_name<'tcx>( +crate fn alloc_type_name<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx> ) -> &'tcx Allocation { diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index f4bed928c8d0a..0c61be283dfd0 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -36,4 +36,4 @@ pub use self::validity::RefTracking; pub use self::intern::intern_const_alloc_recursive; -pub(crate) use self::intrinsics::eval_nulary_intrinsic; +crate use self::intrinsics::eval_nullary_intrinsic; From a44a72ef37bcc7aa9f78bea0503b211681fa552b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 11 Aug 2019 17:37:42 +0200 Subject: [PATCH 07/12] Also link "pref_align_of" --- src/librustc_mir/interpret/intrinsics.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 7ba057aa23fce..ec6fa685eb4ff 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -95,6 +95,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "min_align_of" | + "pref_align_of" | "needs_drop" | "size_of" | "type_id" | From 1fb854a0f5ec500414f7e4fd4eac30357a9dd666 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 16 Aug 2019 16:05:36 +0200 Subject: [PATCH 08/12] Do not generate allocations for zero sized allocations --- src/librustc_codegen_llvm/common.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs index b0c94a139be08..a2026e1461d8e 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/src/librustc_codegen_llvm/common.rs @@ -333,14 +333,19 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { offset: Size, ) -> PlaceRef<'tcx, &'ll Value> { assert_eq!(alloc.align, layout.align.abi); - let init = const_alloc_to_llvm(self, alloc); - let base_addr = self.static_addr_of(init, alloc.align, None); - - let llval = unsafe { llvm::LLVMConstInBoundsGEP( - self.const_bitcast(base_addr, self.type_i8p()), - &self.const_usize(offset.bytes()), - 1, - )}; + let llval = if layout.size == Size::ZERO { + let llval = self.const_usize(alloc.align.bytes()); + unsafe { llvm::LLVMConstIntToPtr(llval, self.type_ptr_to(self.type_i8p())) } + } else { + let init = const_alloc_to_llvm(self, alloc); + let base_addr = self.static_addr_of(init, alloc.align, None); + + unsafe { llvm::LLVMConstInBoundsGEP( + self.const_bitcast(base_addr, self.type_i8p()), + &self.const_usize(offset.bytes()), + 1, + )} + }; let llval = self.const_bitcast(llval, self.type_ptr_to(layout.llvm_type(self))); PlaceRef::new_sized(llval, layout, alloc.align) } From ab949fdd64433749ebb7f8ef516ee2cdfe217a9d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 17 Aug 2019 11:29:17 +0200 Subject: [PATCH 09/12] Cast only where necessary --- src/librustc_codegen_llvm/common.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs index a2026e1461d8e..19f18088579b3 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/src/librustc_codegen_llvm/common.rs @@ -333,20 +333,21 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { offset: Size, ) -> PlaceRef<'tcx, &'ll Value> { assert_eq!(alloc.align, layout.align.abi); + let llty = self.type_ptr_to(layout.llvm_type(self)); let llval = if layout.size == Size::ZERO { let llval = self.const_usize(alloc.align.bytes()); - unsafe { llvm::LLVMConstIntToPtr(llval, self.type_ptr_to(self.type_i8p())) } + unsafe { llvm::LLVMConstIntToPtr(llval, llty) } } else { let init = const_alloc_to_llvm(self, alloc); let base_addr = self.static_addr_of(init, alloc.align, None); - unsafe { llvm::LLVMConstInBoundsGEP( + let llval = unsafe { llvm::LLVMConstInBoundsGEP( self.const_bitcast(base_addr, self.type_i8p()), &self.const_usize(offset.bytes()), 1, - )} + )}; + self.const_bitcast(llval, llty) }; - let llval = self.const_bitcast(llval, self.type_ptr_to(layout.llvm_type(self))); PlaceRef::new_sized(llval, layout, alloc.align) } From 1ea88a8689a461638fef31e01e62fffc63ac5b79 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 17 Aug 2019 11:31:09 +0200 Subject: [PATCH 10/12] Add tests --- src/test/ui/consts/zst_no_llvm_alloc.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/test/ui/consts/zst_no_llvm_alloc.rs diff --git a/src/test/ui/consts/zst_no_llvm_alloc.rs b/src/test/ui/consts/zst_no_llvm_alloc.rs new file mode 100644 index 0000000000000..5d779355400cc --- /dev/null +++ b/src/test/ui/consts/zst_no_llvm_alloc.rs @@ -0,0 +1,19 @@ +// run-pass + +#[repr(align(4))] +struct Foo; + +static FOO: Foo = Foo; + +fn main() { + let x: &'static () = &(); + assert_eq!(x as *const () as usize, 1); + let x: &'static Foo = &Foo; + assert_eq!(x as *const Foo as usize, 4); + + // statics must have a unique address + assert_ne!(&FOO as *const Foo as usize, 4); + + assert_eq!(>::new().as_ptr(), <&[i32]>::default().as_ptr()); + assert_eq!(>::default().as_ptr(), (&[]).as_ptr()); +} From 612af946f6576ad03d10c7184b2b3b4e3f7a5d8a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 17 Aug 2019 15:26:04 +0200 Subject: [PATCH 11/12] Don't panic on layout errors --- src/librustc_mir/const_eval.rs | 111 ++++++++++++----------- src/librustc_mir/interpret/intrinsics.rs | 8 +- 2 files changed, 62 insertions(+), 57 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 23f7a009e23c1..a9ce05e5f1869 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -620,7 +620,12 @@ pub fn const_eval_provider<'tcx>( ty::FnDef(_, substs) => substs, _ => bug!("intrinsic with type {:?}", ty), }; - return Ok(eval_nullary_intrinsic(tcx, key.param_env, def_id, substs)); + 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| { @@ -691,63 +696,63 @@ pub fn const_eval_raw_provider<'tcx>( }) }).map_err(|error| { let err = error_to_const_error(&ecx, error); - // errors in statics are always emitted as fatal errors - if tcx.is_static(def_id) { - // Ensure that if the above error was either `TooGeneric` or `Reported` - // an error must be reported. + // errors in statics are always emitted as fatal errors + if tcx.is_static(def_id) { + // Ensure that if the above error was either `TooGeneric` or `Reported` + // an error must be reported. let v = err.report_as_error(ecx.tcx, "could not evaluate static initializer"); - tcx.sess.delay_span_bug( - err.span, - &format!("static eval failure did not emit an error: {:#?}", v) - ); - v - } else if def_id.is_local() { - // constant defined in this crate, we can figure out a lint level! - match tcx.def_kind(def_id) { - // constants never produce a hard error at the definition site. Anything else is - // a backwards compatibility hazard (and will break old versions of winapi for sure) - // - // note that validation may still cause a hard error on this very same constant, - // because any code that existed before validation could not have failed validation - // thus preventing such a hard error from being a backwards compatibility hazard - Some(DefKind::Const) | Some(DefKind::AssocConst) => { - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + tcx.sess.delay_span_bug( + err.span, + &format!("static eval failure did not emit an error: {:#?}", v) + ); + v + } else if def_id.is_local() { + // constant defined in this crate, we can figure out a lint level! + match tcx.def_kind(def_id) { + // constants never produce a hard error at the definition site. Anything else is + // a backwards compatibility hazard (and will break old versions of winapi for sure) + // + // note that validation may still cause a hard error on this very same constant, + // because any code that existed before validation could not have failed validation + // thus preventing such a hard error from being a backwards compatibility hazard + Some(DefKind::Const) | Some(DefKind::AssocConst) => { + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + err.report_as_lint( + tcx.at(tcx.def_span(def_id)), + "any use of this value will cause an error", + hir_id, + Some(err.span), + ) + }, + // promoting runtime code is only allowed to error if it references broken constants + // any other kind of error will be reported to the user as a deny-by-default lint + _ => if let Some(p) = cid.promoted { + let span = tcx.promoted_mir(def_id)[p].span; + if let err_inval!(ReferencedConstant) = err.error { + err.report_as_error( + tcx.at(span), + "evaluation of constant expression failed", + ) + } else { err.report_as_lint( - tcx.at(tcx.def_span(def_id)), - "any use of this value will cause an error", - hir_id, + tcx.at(span), + "reaching this expression at runtime will panic or abort", + tcx.hir().as_local_hir_id(def_id).unwrap(), Some(err.span), ) - }, - // promoting runtime code is only allowed to error if it references broken constants - // any other kind of error will be reported to the user as a deny-by-default lint - _ => if let Some(p) = cid.promoted { - let span = tcx.promoted_mir(def_id)[p].span; - if let err_inval!(ReferencedConstant) = err.error { - err.report_as_error( - tcx.at(span), - "evaluation of constant expression failed", - ) - } else { - err.report_as_lint( - tcx.at(span), - "reaching this expression at runtime will panic or abort", - tcx.hir().as_local_hir_id(def_id).unwrap(), - Some(err.span), - ) - } - // anything else (array lengths, enum initializers, constant patterns) are reported - // as hard errors - } else { - err.report_as_error( + } + // anything else (array lengths, enum initializers, constant patterns) are reported + // as hard errors + } else { + err.report_as_error( ecx.tcx, - "evaluation of constant value failed", - ) - }, - } - } else { - // use of broken constant from other crate - err.report_as_error(ecx.tcx, "could not evaluate constant") + "evaluation of constant value failed", + ) + }, } + } else { + // use of broken constant from other crate + err.report_as_error(ecx.tcx, "could not evaluate constant") + } }) } diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index ec6fa685eb4ff..01833fb80209e 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -45,10 +45,10 @@ crate fn eval_nullary_intrinsic<'tcx>( param_env: ty::ParamEnv<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, -) -> &'tcx ty::Const<'tcx> { +) -> InterpResult<'tcx, &'tcx ty::Const<'tcx>> { let tp_ty = substs.type_at(0); let name = &*tcx.item_name(def_id).as_str(); - match name { + Ok(match name { "type_name" => { let alloc = type_name::alloc_type_name(tcx, tp_ty); tcx.mk_const(ty::Const { @@ -64,7 +64,7 @@ crate fn eval_nullary_intrinsic<'tcx>( "size_of" | "min_align_of" | "pref_align_of" => { - let layout = tcx.layout_of(param_env.and(tp_ty)).unwrap(); + 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(), @@ -79,7 +79,7 @@ crate fn eval_nullary_intrinsic<'tcx>( 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> { From 1e02bc62bc72d2145a9f11c740714a1a5d94e2b4 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Sat, 17 Aug 2019 12:17:02 +0100 Subject: [PATCH 12/12] Better error message for break in async blocks. --- src/librustc_passes/loops.rs | 17 ++++++++++++++--- ...async-block-control-flow-static-semantics.rs | 5 ++--- ...c-block-control-flow-static-semantics.stderr | 14 +++++++------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index afe4c78dcfc37..1547e607b9c61 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -7,7 +7,7 @@ use rustc::ty::TyCtxt; use rustc::hir::def_id::DefId; use rustc::hir::map::Map; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; -use rustc::hir::{self, Node, Destination}; +use rustc::hir::{self, Node, Destination, GeneratorMovability}; use syntax::struct_span_err; use syntax_pos::Span; use errors::Applicability; @@ -17,6 +17,7 @@ enum Context { Normal, Loop(hir::LoopSource), Closure, + AsyncClosure, LabeledBlock, AnonConst, } @@ -57,9 +58,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { hir::ExprKind::Loop(ref b, _, source) => { self.with_context(Loop(source), |v| v.visit_block(&b)); } - hir::ExprKind::Closure(_, ref function_decl, b, _, _) => { + hir::ExprKind::Closure(_, ref function_decl, b, _, movability) => { + let cx = if let Some(GeneratorMovability::Static) = movability { + AsyncClosure + } else { + Closure + }; self.visit_fn_decl(&function_decl); - self.with_context(Closure, |v| v.visit_nested_body(b)); + self.with_context(cx, |v| v.visit_nested_body(b)); } hir::ExprKind::Block(ref b, Some(_label)) => { self.with_context(LabeledBlock, |v| v.visit_block(&b)); @@ -171,6 +177,11 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { .span_label(span, "cannot break inside of a closure") .emit(); } + AsyncClosure => { + struct_span_err!(self.sess, span, E0267, "`{}` inside of an async block", name) + .span_label(span, "cannot break inside of an async block") + .emit(); + } Normal | AnonConst => { struct_span_err!(self.sess, span, E0268, "`{}` outside of loop", name) .span_label(span, "cannot break outside of a loop") diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs index 6a766ede0ed87..4ddcdcac82282 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs @@ -32,15 +32,14 @@ async fn return_targets_async_block_not_async_fn() -> u8 { fn no_break_in_async_block() { async { - break 0u8; //~ ERROR `break` inside of a closure - // FIXME: This diagnostic is pretty bad. + break 0u8; //~ ERROR `break` inside of an async block }; } fn no_break_in_async_block_even_with_outer_loop() { loop { async { - break 0u8; //~ ERROR `break` inside of a closure + break 0u8; //~ ERROR `break` inside of an async block }; } } diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index f3f2d14584ef7..a0a5ac63d8427 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -1,14 +1,14 @@ -error[E0267]: `break` inside of a closure +error[E0267]: `break` inside of an async block --> $DIR/async-block-control-flow-static-semantics.rs:35:9 | LL | break 0u8; - | ^^^^^^^^^ cannot break inside of a closure + | ^^^^^^^^^ cannot break inside of an async block -error[E0267]: `break` inside of a closure - --> $DIR/async-block-control-flow-static-semantics.rs:43:13 +error[E0267]: `break` inside of an async block + --> $DIR/async-block-control-flow-static-semantics.rs:42:13 | LL | break 0u8; - | ^^^^^^^^^ cannot break inside of a closure + | ^^^^^^^^^ cannot break inside of an async block error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:15:43 @@ -52,7 +52,7 @@ LL | async fn return_targets_async_block_not_async_fn() -> u8 { = note: the return type of a function must have a statically known size error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:51:44 + --> $DIR/async-block-control-flow-static-semantics.rs:50:44 | LL | fn rethrow_targets_async_block_not_fn() -> Result { | ---------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found () @@ -63,7 +63,7 @@ LL | fn rethrow_targets_async_block_not_fn() -> Result { found type `()` error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:60:50 + --> $DIR/async-block-control-flow-static-semantics.rs:59:50 | LL | fn rethrow_targets_async_block_not_async_fn() -> Result { | ---------------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found ()