diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index c36f79351155..8de85aab6e38 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -12,10 +12,10 @@ use rustc::mir::visit::{ MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, }; use rustc::mir::{ - read_only, AggregateKind, BasicBlock, BinOp, Body, BodyAndCache, ClearCrossCrate, Constant, - Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, ReadOnlyBodyAndCache, Rvalue, - SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind, - UnOp, RETURN_PLACE, + read_only, AggregateKind, BasicBlock, BinOp, Body, BodyAndCache, CastKind, ClearCrossCrate, + Constant, Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, + ReadOnlyBodyAndCache, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, + StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, }; use rustc::ty::layout::{ HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout, @@ -29,9 +29,9 @@ use syntax_pos::{Span, DUMMY_SP}; use crate::const_eval::error_to_const_error; use crate::interpret::{ - self, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx, - LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, - ScalarMaybeUndef, StackPopCleanup, + self, intern_const_alloc_recursive, truncate, AllocId, Allocation, Frame, ImmTy, Immediate, + InterpCx, LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, + Pointer, ScalarMaybeUndef, StackPopCleanup, }; use crate::rustc::ty::subst::Subst; use crate::transform::{MirPass, MirSource}; @@ -584,6 +584,45 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } + Rvalue::Cast(CastKind::Misc, op, ty) => { + trace!("checking Cast(Misc, {:?}, {:?})", op, ty); + + if ty.is_integral() && op.ty(&self.local_decls, self.tcx).is_integral() { + let value = self.use_ecx(source_info, |this| { + this.ecx.read_immediate(this.ecx.eval_operand(op, None)?) + })?; + + // Do not try to read bits for ZSTs + if !value.layout.is_zst() { + let value_size = value.layout.size; + let value_bits = value.to_scalar().and_then(|r| r.to_bits(value_size)); + if let Ok(value_bits) = value_bits { + let truncated = truncate(value_bits, place_layout.size); + if truncated != value_bits { + let scope = source_info.scope; + let lint_root = match &self.source_scopes[scope].local_data { + ClearCrossCrate::Set(data) => data.lint_root, + ClearCrossCrate::Clear => return None, + }; + self.tcx.lint_hir( + ::rustc::lint::builtin::CONST_ERR, + lint_root, + span, + &format!( + "truncating cast: the value {} requires {} bits but \ + the target type is only {} bits", + value_bits, + value_size.bits(), + place_layout.size.bits() + ), + ); + return None; + } + } + } + } + } + _ => {} } diff --git a/src/test/mir-opt/const_prop/cast.rs b/src/test/mir-opt/const_prop/cast.rs new file mode 100644 index 000000000000..9cfbfebdcc3d --- /dev/null +++ b/src/test/mir-opt/const_prop/cast.rs @@ -0,0 +1,49 @@ +fn main() { + let x = 42u8 as u32; + + let y = 42u32 as u8; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// let mut _0: (); +// let _1: u32; +// scope 1 { +// debug x => _1; +// let _2: u8; +// scope 2 { +// debug y => _2; +// } +// } +// bb0: { +// StorageLive(_1); +// _1 = const 42u8 as u32 (Misc); +// StorageLive(_2); +// _2 = const 42u32 as u8 (Misc); +// _0 = (); +// StorageDead(_2); +// StorageDead(_1); +// return; +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// let mut _0: (); +// let _1: u32; +// scope 1 { +// debug x => _1; +// let _2: u8; +// scope 2 { +// debug y => _2; +// } +// } +// bb0: { +// StorageLive(_1); +// _1 = const 42u32; +// StorageLive(_2); +// _2 = const 42u8; +// _0 = (); +// StorageDead(_2); +// StorageDead(_1); +// return; +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/ui/consts/const-prop-overflowing-casts.rs b/src/test/ui/consts/const-prop-overflowing-casts.rs new file mode 100644 index 000000000000..11a04611487b --- /dev/null +++ b/src/test/ui/consts/const-prop-overflowing-casts.rs @@ -0,0 +1,9 @@ +// build-fail +// ignore-tidy-linelength + +fn main() { + let _ = 0u8 as u32; + let _ = (1u32 << 31) as u16; //~ ERROR truncating cast: the value 2147483648 requires 32 bits but the target type is only 16 bits + let _ = (1u16 << 15) as u8; //~ ERROR truncating cast: the value 32768 requires 16 bits but the target type is only 8 bits + let _ = (!0u16) as u8; //~ ERROR truncating cast: the value 65535 requires 16 bits but the target type is only 8 bits +} diff --git a/src/test/ui/consts/const-prop-overflowing-casts.stderr b/src/test/ui/consts/const-prop-overflowing-casts.stderr new file mode 100644 index 000000000000..af4e2c7005af --- /dev/null +++ b/src/test/ui/consts/const-prop-overflowing-casts.stderr @@ -0,0 +1,22 @@ +error: truncating cast: the value 2147483648 requires 32 bits but the target type is only 16 bits + --> $DIR/const-prop-overflowing-casts.rs:6:13 + | +LL | let _ = (1u32 << 31) as u16; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(const_err)]` on by default + +error: truncating cast: the value 32768 requires 16 bits but the target type is only 8 bits + --> $DIR/const-prop-overflowing-casts.rs:7:13 + | +LL | let _ = (1u16 << 15) as u8; + | ^^^^^^^^^^^^^^^^^^ + +error: truncating cast: the value 65535 requires 16 bits but the target type is only 8 bits + --> $DIR/const-prop-overflowing-casts.rs:8:13 + | +LL | let _ = (!0u16) as u8; + | ^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/simd/simd-intrinsic-generic-cast.rs b/src/test/ui/simd/simd-intrinsic-generic-cast.rs index 15f232e2c0f7..b81a76851d3c 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-cast.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-cast.rs @@ -4,6 +4,7 @@ #![feature(repr_simd, platform_intrinsics, concat_idents, test)] #![allow(non_camel_case_types)] +#![allow(const_err)] // the test macro casts i32s to i8 and u8 which causes lots of warnings extern crate test;