Change:
inlined inside a , I get a warning: however, when I involve a variable there is no warning at all but looking at the generated code it is quite clear that this panics:
It warns on current stable, but not on beta and nightly. Might be miri fallout? cc Curiously, when you take a reference (to trigger promotion to static) you get a hard error on beta and nightly (stable is still a warning). Isn't that a regression?
triage: P-medium Still want to get those warnings, but no longer P-high
Hm, what is the status of this? The PR was merged, but with , I don't get a compiler warning for the first example. For the second one I get two though? :confused:
The PR was just for the compilation error. The missing warnings just need an impl for this branch: The warning duplication is unfortunate, but if we deduplicate it, we loose warnings in other edge cases. We could deduplicate it similar to the way the notes about where the lint level was set are deduplicated (note how the second warning has no message). That would probably be the cleanest solution.

Discussion:
<del> use rustc::ty::Ty; use rustc::ty::layout::LayoutOf; </del> <ins> use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, LayoutOf}; </ins> use syntax::ast::{FloatTy, IntTy, UintTy}; use rustc_apfloat::ieee::{Single, Double}; use super::{EvalContext, Machine}; <del> use rustc::mir::interpret::{Scalar, EvalResult, Pointer, PointerArithmetic}; </del> <ins> use rustc::mir::interpret::{Scalar, EvalResult, Pointer, PointerArithmetic, Value, EvalErrorKind}; use rustc::mir::CastKind; </ins> use rustc_apfloat::Float; <ins> use interpret::eval_context::ValTy; use interpret::Place; </ins> impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { <ins> crate fn cast( &mut self, src: ValTy<'tcx>, kind: CastKind, dest_ty: Ty<'tcx>, dest: Place, ) -> EvalResult<'tcx> { use rustc::mir::CastKind::*; match kind { Unsize => { let src_layout = self.layout_of(src.ty)?; let dst_layout = self.layout_of(dest_ty)?; self.unsize_into(src.value, src_layout, dest, dst_layout)?; } Misc => { if self.type_is_fat_ptr(src.ty) { match (src.value, self.type_is_fat_ptr(dest_ty)) { (Value::ByRef { .. }, _) | // pointers to extern types (Value::Scalar(_),_) | // slices and trait objects to other slices/trait objects (Value::ScalarPair(..), true) => { let valty = ValTy { value: src.value, ty: dest_ty, }; self.write_value(valty, dest)?; } // slices and trait objects to thin pointers (dropping the metadata) (Value::ScalarPair(data, _), false) => { let valty = ValTy { value: Value::Scalar(data), ty: dest_ty, }; self.write_value(valty, dest)?; } } } else { let src_layout = self.layout_of(src.ty)?; match src_layout.variants { layout::Variants::Single { index } => { if let Some(def) = src.ty.ty_adt_def() { let discr_val = def .discriminant_for_variant(*self.tcx, index) .val; let defined = self .layout_of(dest_ty) .unwrap() .size .bits() as u8; return self.write_scalar( dest, Scalar::Bits { bits: discr_val, defined, }, dest_ty); } } layout::Variants::Tagged { .. } | layout::Variants::NicheFilling { .. } => {}, } let src_val = self.value_to_scalar(src)?; let dest_val = self.cast_scalar(src_val, src.ty, dest_ty)?; let valty = ValTy { value: Value::Scalar(dest_val), ty: dest_ty, }; self.write_value(valty, dest)?; } } ReifyFnPointer => { match src.ty.sty { ty::TyFnDef(def_id, substs) => { if self.tcx.has_attr(def_id, "rustc_args_required_const") { bug!("reifying a fn ptr that requires  const arguments"); } let instance: EvalResult<'tcx, _> = ty::Instance::resolve( *self.tcx, self.param_env, def_id, substs, ).ok_or_else(|| EvalErrorKind::TooGeneric.into()); let fn_ptr = self.memory.create_fn_alloc(instance?); let valty = ValTy { value: Value::Scalar(fn_ptr.into()), ty: dest_ty, }; self.write_value(valty, dest)?; } ref other => bug!("reify fn pointer on {:?}", other), } } UnsafeFnPointer => { match dest_ty.sty { ty::TyFnPtr(_) => { let mut src = src; src.ty = dest_ty; self.write_value(src, dest)?; } ref other => bug!("fn to unsafe fn cast on {:?}", other), } } ClosureFnPointer => { match src.ty.sty { ty::TyClosure(def_id, substs) => { let substs = self.tcx.subst_and_normalize_erasing_regions( self.substs(), ty::ParamEnv::reveal_all(), &substs, ); let instance = ty::Instance::resolve_closure( *self.tcx, def_id, substs, ty::ClosureKind::FnOnce, ); let fn_ptr = self.memory.create_fn_alloc(instance); let valty = ValTy { value: Value::Scalar(fn_ptr.into()), ty: dest_ty, }; self.write_value(valty, dest)?; } ref other => bug!("closure fn pointer on {:?}", other), } } } Ok(()) } </ins> pub(super) fn cast_scalar( &self, val: Scalar,

Cast(kind, ref operand, cast_ty) => { debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest_ty); <del> use rustc::mir::CastKind::*; match kind { Unsize => { let src = self.eval_operand(operand)?; let src_layout = self.layout_of(src.ty)?; let dst_layout = self.layout_of(dest_ty)?; self.unsize_into(src.value, src_layout, dest, dst_layout)?; } Misc => { let src = self.eval_operand(operand)?; if self.type_is_fat_ptr(src.ty) { match (src.value, self.type_is_fat_ptr(dest_ty)) { (Value::ByRef { .. }, _) | // pointers to extern types (Value::Scalar(_),_) | // slices and trait objects to other slices/trait objects (Value::ScalarPair(..), true) => { let valty = ValTy { value: src.value, ty: dest_ty, }; self.write_value(valty, dest)?; } // slices and trait objects to thin pointers (dropping the metadata) (Value::ScalarPair(data, _), false) => { let valty = ValTy { value: Value::Scalar(data), ty: dest_ty, }; self.write_value(valty, dest)?; } } } else { let src_layout = self.layout_of(src.ty)?; match src_layout.variants { layout::Variants::Single { index } => { if let Some(def) = src.ty.ty_adt_def() { let discr_val = def .discriminant_for_variant(*self.tcx, index) .val; let defined = self .layout_of(dest_ty) .unwrap() .size .bits() as u8; return self.write_scalar( dest, Scalar::Bits { bits: discr_val, defined, }, dest_ty); } } layout::Variants::Tagged { .. } | layout::Variants::NicheFilling { .. } => {}, } let src_val = self.value_to_scalar(src)?; let dest_val = self.cast_scalar(src_val, src.ty, dest_ty)?; let valty = ValTy { value: Value::Scalar(dest_val), ty: dest_ty, }; self.write_value(valty, dest)?; } } ReifyFnPointer => { match self.eval_operand(operand)?.ty.sty { ty::TyFnDef(def_id, substs) => { if self.tcx.has_attr(def_id, "rustc_args_required_const") { bug!("reifying a fn ptr that requires  const arguments"); } let instance: EvalResult<'tcx, _> = ty::Instance::resolve( *self.tcx, self.param_env, def_id, substs, ).ok_or_else(|| EvalErrorKind::TooGeneric.into()); let fn_ptr = self.memory.create_fn_alloc(instance?); let valty = ValTy { value: Value::Scalar(fn_ptr.into()), ty: dest_ty, }; self.write_value(valty, dest)?; } ref other => bug!("reify fn pointer on {:?}", other), } } UnsafeFnPointer => { match dest_ty.sty { ty::TyFnPtr(_) => { let mut src = self.eval_operand(operand)?; src.ty = dest_ty; self.write_value(src, dest)?; } ref other => bug!("fn to unsafe fn cast on {:?}", other), } } ClosureFnPointer => { match self.eval_operand(operand)?.ty.sty { ty::TyClosure(def_id, substs) => { let substs = self.tcx.subst_and_normalize_erasing_regions( self.substs(), ty::ParamEnv::reveal_all(), &substs, ); let instance = ty::Instance::resolve_closure( *self.tcx, def_id, substs, ty::ClosureKind::FnOnce, ); let fn_ptr = self.memory.create_fn_alloc(instance); let valty = ValTy { value: Value::Scalar(fn_ptr.into()), ty: dest_ty, }; self.write_value(valty, dest)?; } ref other => bug!("closure fn pointer on {:?}", other), } } } </del> <ins> let src = self.eval_operand(operand)?; self.cast(src, kind, dest_ty, dest)?; </ins> } Discriminant(ref place) => {

} } <del> fn unsize_into( </del> <ins> crate fn unsize_into( </ins> &mut self, src: Value, src_layout: TyLayout<'tcx>,

use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind}; use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem}; use rustc::mir::visit::{Visitor, PlaceContext}; <del> use rustc::mir::interpret::ConstEvalErr; </del> <ins> use rustc::mir::interpret::{ConstEvalErr, EvalErrorKind}; </ins> use rustc::ty::{TyCtxt, self, Instance}; use rustc::mir::interpret::{Value, Scalar, GlobalId, EvalResult}; use interpret::EvalContext;

let r = match f(self) { Ok(val) => Some(val), Err(err) => { <del> let (frames, span) = self.ecx.generate_stacktrace(None); let err = ConstEvalErr { span, error: err, stacktrace: frames, }; err.report_as_lint( self.ecx.tcx, "this expression will panic at runtime", lint_root, ); </del> <ins> match err.kind { // don't report these, they make no sense in a const prop context EvalErrorKind::MachineError(_) => {}, _ => { let (frames, span) = self.ecx.generate_stacktrace(None); let err = ConstEvalErr { span, error: err, stacktrace: frames, }; err.report_as_lint( self.ecx.tcx, "this expression will panic at runtime", lint_root, ); } } </ins> None }, };

}, Rvalue::Repeat(..) | Rvalue::Ref(..) | <del> Rvalue::Cast(..) | </del> Rvalue::Aggregate(..) | Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::Discriminant(..) => None, <ins> Rvalue::Cast(kind, ref operand, _) => { let (value, ty, span) = self.eval_operand(operand, source_info)?; self.use_ecx(source_info, |this| { let dest_ptr = this.ecx.alloc_ptr(place_ty)?; let place_align = this.ecx.layout_of(place_ty)?.align; let dest = ::interpret::Place::from_ptr(dest_ptr, place_align); this.ecx.cast(ValTy { value, ty }, kind, place_ty, dest)?; Ok(( Value::ByRef(dest_ptr.into(), place_align), place_ty, span, )) }) } </ins> // FIXME(oli-obk): evaluate static/constant slice lengths Rvalue::Len(_) => None, Rvalue::NullaryOp(NullOp::SizeOf, ty) => {

) } else { if overflow { <del> use rustc::mir::interpret::EvalErrorKind; </del> let err = EvalErrorKind::Overflow(op).into(); let _: Option<()> = self.use_ecx(source_info, |_| Err(err)); return None;

assert!(foo as usize != bar as usize); <del> assert_eq!(foo as i16, foo as usize as i16); </del> <ins> // Taking a few bits of a function's address is totally pointless and we detect that // Disabling the lint to ensure that the assertion can still be run #[allow(const_err)] { assert_eq!(foo as i16, foo as usize as i16); } </ins> // fptr-ptr-cast

//~| WARN const_err println!("{}", 1/(false as u32)); //~^ WARN const_err <ins> //~| WARN const_err </ins> let _x = 1/(false as u32); <ins> //~^ WARN const_err //~| WARN const_err </ins> }

LL |     let _x = 1/(1-1); |              ^^^^^^^ attempt to divide by zero <ins> warning: attempt to divide by zero --> $DIR/promoted_errors.rs:25:20 | LL |     println!("{}", 1/(false as u32)); |                    ^^^^^^^^^^^^^^^^ </ins> warning: this expression will panic at runtime --> $DIR/promoted_errors.rs:25:20 | LL |     println!("{}", 1/(false as u32)); |                    ^^^^^^^^^^^^^^^^ attempt to divide by zero <ins> warning: attempt to divide by zero --> $DIR/promoted_errors.rs:28:14 | LL |     let _x = 1/(false as u32); |              ^^^^^^^^^^^^^^^^ warning: this expression will panic at runtime --> $DIR/promoted_errors.rs:28:14 | LL |     let _x = 1/(false as u32); |              ^^^^^^^^^^^^^^^^ attempt to divide by zero </ins>