diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index e747eee30f90d..a23ff6bd66d4b 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -2,6 +2,7 @@ use super::{CheckInAllocMsg, Pointer, RawConst, ScalarMaybeUndef}; use crate::hir::map::definitions::DefPathData; use crate::mir; +use crate::mir::interpret::ConstValue; use crate::ty::layout::{Align, LayoutError, Size}; use crate::ty::query::TyCtxtAt; use crate::ty::{self, layout, Ty}; @@ -40,7 +41,7 @@ CloneTypeFoldableImpls! { } pub type ConstEvalRawResult<'tcx> = Result, ErrorHandled>; -pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>; +pub type ConstEvalResult<'tcx> = Result, ErrorHandled>; #[derive(Debug)] pub struct ConstEvalErr<'tcx> { diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 2be36ad418a5b..2c146b5d7b426 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -7,7 +7,7 @@ use std::fmt; use crate::ty::{ layout::{HasDataLayout, Size}, - Ty, + ParamEnv, Ty, TyCtxt, }; use super::{sign_extend, truncate, AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; @@ -66,6 +66,32 @@ impl<'tcx> ConstValue<'tcx> { ConstValue::Scalar(val) => Some(val), } } + + pub fn try_to_bits(&self, size: Size) -> Option { + self.try_to_scalar()?.to_bits(size).ok() + } + + pub fn try_to_bits_for_ty( + &self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ty: Ty<'tcx>, + ) -> Option { + let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size; + self.try_to_bits(size) + } + + pub fn from_bool(b: bool) -> Self { + ConstValue::Scalar(Scalar::from_bool(b)) + } + + pub fn from_u64(i: u64) -> Self { + ConstValue::Scalar(Scalar::from_u64(i)) + } + + pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self { + ConstValue::Scalar(Scalar::from_machine_usize(i, cx)) + } } /// A `Scalar` represents an immediate, primitive value existing outside of a @@ -287,6 +313,11 @@ impl<'tcx, Tag> Scalar { Scalar::Raw { data: i as u128, size: 8 } } + #[inline] + pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self { + Self::from_uint(i, cx.data_layout().pointer_size) + } + #[inline] pub fn try_from_int(i: impl Into, size: Size) -> Option { let i = i.into(); @@ -306,6 +337,11 @@ impl<'tcx, Tag> Scalar { .unwrap_or_else(|| bug!("Signed value {:#x} does not fit in {} bits", i, size.bits())) } + #[inline] + pub fn from_machine_isize(i: i64, cx: &impl HasDataLayout) -> Self { + Self::from_int(i, cx.data_layout().pointer_size) + } + #[inline] pub fn from_f32(f: Single) -> Self { // We trust apfloat to give us properly truncated data. diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 4520d3a333316..9b94f92acd476 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1468,21 +1468,21 @@ impl<'tcx> TerminatorKind<'tcx> { /// successors, which may be rendered differently between the text and the graphviz format. pub fn fmt_head(&self, fmt: &mut W) -> fmt::Result { use self::TerminatorKind::*; - match *self { + match self { Goto { .. } => write!(fmt, "goto"), - SwitchInt { discr: ref place, .. } => write!(fmt, "switchInt({:?})", place), + SwitchInt { discr, .. } => write!(fmt, "switchInt({:?})", discr), Return => write!(fmt, "return"), GeneratorDrop => write!(fmt, "generator_drop"), Resume => write!(fmt, "resume"), Abort => write!(fmt, "abort"), - Yield { ref value, .. } => write!(fmt, "_1 = suspend({:?})", value), + Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value), Unreachable => write!(fmt, "unreachable"), - Drop { ref location, .. } => write!(fmt, "drop({:?})", location), - DropAndReplace { ref location, ref value, .. } => { + Drop { location, .. } => write!(fmt, "drop({:?})", location), + DropAndReplace { location, value, .. } => { write!(fmt, "replace({:?} <- {:?})", location, value) } - Call { ref func, ref args, ref destination, .. } => { - if let Some((ref destination, _)) = *destination { + Call { func, args, destination, .. } => { + if let Some((destination, _)) = destination { write!(fmt, "{:?} = ", destination)?; } write!(fmt, "{:?}(", func)?; @@ -1494,7 +1494,7 @@ impl<'tcx> TerminatorKind<'tcx> { } write!(fmt, ")") } - Assert { ref cond, expected, ref msg, .. } => { + Assert { cond, expected, msg, .. } => { write!(fmt, "assert(")?; if !expected { write!(fmt, "!")?; diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 5e279975d152d..45ab3fc0b85a6 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -519,7 +519,7 @@ rustc_queries! { /// Extracts a field of a (variant of a) const. query const_field( key: ty::ParamEnvAnd<'tcx, (&'tcx ty::Const<'tcx>, mir::Field)> - ) -> &'tcx ty::Const<'tcx> { + ) -> ConstValue<'tcx> { no_force desc { "extract field of const" } } @@ -533,7 +533,7 @@ rustc_queries! { desc { "destructure constant" } } - query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> &'tcx ty::Const<'tcx> { + query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { no_force desc { "get a &core::panic::Location referring to a span" } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 45ea05efd4a84..a4b4e1d657429 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2388,10 +2388,10 @@ impl<'tcx> AdtDef { let repr_type = self.repr.discr_type(); match tcx.const_eval_poly(expr_did) { Ok(val) => { - // FIXME: Find the right type and use it instead of `val.ty` here - if let Some(b) = val.try_eval_bits(tcx, param_env, val.ty) { + let ty = repr_type.to_ty(tcx); + if let Some(b) = val.try_to_bits_for_ty(tcx, param_env, ty) { trace!("discriminants: {} ({:?})", b, repr_type); - Some(Discr { val: b, ty: val.ty }) + Some(Discr { val: b, ty }) } else { info!("invalid enum discriminant: {:#?}", val); crate::mir::interpret::struct_error( diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 125ee316ed887..21698cd737485 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -14,7 +14,7 @@ use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLife use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; use crate::mir::interpret::GlobalId; -use crate::mir::interpret::{ConstEvalRawResult, ConstEvalResult}; +use crate::mir::interpret::{ConstEvalRawResult, ConstEvalResult, ConstValue}; use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; use crate::session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 02abac975ac84..9cf61ebe88a16 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2417,9 +2417,14 @@ pub struct Const<'tcx> { static_assert_size!(Const<'_>, 48); impl<'tcx> Const<'tcx> { + #[inline] + pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> &'tcx Self { + tcx.mk_const(Self { val: ConstKind::Value(val), ty }) + } + #[inline] pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> &'tcx Self { - tcx.mk_const(Self { val: ConstKind::Value(ConstValue::Scalar(val)), ty }) + Self::from_value(tcx, ConstValue::Scalar(val), ty) } #[inline] @@ -2473,7 +2478,9 @@ impl<'tcx> Const<'tcx> { // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. - tcx.const_eval_resolve(param_env, did, substs, promoted, None).ok() + tcx.const_eval_resolve(param_env, did, substs, promoted, None) + .ok() + .map(|val| Const::from_value(tcx, val, self.ty)) }; match self.val { diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index 38090cb26bc41..09a84aff16811 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -78,11 +78,9 @@ pub fn codegen_static_initializer( cx: &CodegenCx<'ll, 'tcx>, def_id: DefId, ) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> { - let static_ = cx.tcx.const_eval_poly(def_id)?; - - let alloc = match static_.val { - ty::ConstKind::Value(ConstValue::ByRef { alloc, offset }) if offset.bytes() == 0 => alloc, - _ => bug!("static const eval returned {:#?}", static_), + let alloc = match cx.tcx.const_eval_poly(def_id)? { + ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => alloc, + val => bug!("static const eval returned {:#?}", val), }; Ok((const_alloc_to_llvm(cx, alloc), alloc)) } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 031837c1efbe8..3d1e72e1c73d7 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -193,7 +193,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { .tcx .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) .unwrap(); - OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self) + OperandRef::from_const(self, ty_name, ret_ty).immediate_or_packed_pair(self) } "init" => { let ty = substs.type_at(0); diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 916c15eb1b6ea..d684f842ddc69 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -991,7 +991,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { caller.line as u32, caller.col_display as u32 + 1, )); - OperandRef::from_const(bx, const_loc) + OperandRef::from_const(bx, const_loc, bx.tcx().caller_location_ty()) }) } diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 3ce916d781279..9ceb75a603bc4 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -1,7 +1,7 @@ use crate::mir::operand::OperandRef; use crate::traits::*; use rustc::mir; -use rustc::mir::interpret::ErrorHandled; +use rustc::mir::interpret::{ConstValue, ErrorHandled}; use rustc::ty::layout::{self, HasTyCtxt}; use rustc::ty::{self, Ty}; use rustc_index::vec::Idx; @@ -30,7 +30,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } _ => { let val = self.eval_mir_constant(constant)?; - Ok(OperandRef::from_const(bx, val)) + let ty = self.monomorphize(&constant.literal.ty); + Ok(OperandRef::from_const(bx, val.clone(), ty)) } } } @@ -38,7 +39,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn eval_mir_constant( &mut self, constant: &mir::Constant<'tcx>, - ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> { + ) -> Result, ErrorHandled> { match constant.literal.val { ty::ConstKind::Unevaluated(def_id, substs, promoted) => { let substs = self.monomorphize(&substs); @@ -55,7 +56,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { err }) } - _ => Ok(self.monomorphize(&constant.literal)), + ty::ConstKind::Value(value) => Ok(value), + _ => { + let const_ = self.monomorphize(&constant.literal); + if let ty::ConstKind::Value(value) = const_.val { + Ok(value) + } else { + span_bug!(constant.span, "encountered bad ConstKind in codegen: {:?}", const_); + } + } } } @@ -65,21 +74,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &Bx, span: Span, ty: Ty<'tcx>, - constant: Result<&'tcx ty::Const<'tcx>, ErrorHandled>, + constant: Result, ErrorHandled>, ) -> (Bx::Value, Ty<'tcx>) { constant - .map(|c| { - let field_ty = c.ty.builtin_index().unwrap(); - let fields = match c.ty.kind { + .map(|val| { + let field_ty = ty.builtin_index().unwrap(); + let fields = match ty.kind { ty::Array(_, n) => n.eval_usize(bx.tcx(), ty::ParamEnv::reveal_all()), - _ => bug!("invalid simd shuffle type: {}", c.ty), + _ => bug!("invalid simd shuffle type: {}", ty), }; + let c = ty::Const::from_value(bx.tcx(), val, ty); let values: Vec<_> = (0..fields) .map(|field| { let field = bx.tcx().const_field( ty::ParamEnv::reveal_all().and((&c, mir::Field::new(field as usize))), ); - if let Some(prim) = field.val.try_to_scalar() { + if let Some(prim) = field.try_to_scalar() { let layout = bx.layout_of(field_ty); let scalar = match layout.abi { layout::Abi::Scalar(ref x) => x, diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index a33cd2ddad97b..07c8829e7d883 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -8,8 +8,8 @@ use crate::MemFlags; use rustc::mir; use rustc::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar}; -use rustc::ty; use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout}; +use rustc::ty::Ty; use std::fmt; @@ -66,20 +66,16 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { pub fn from_const>( bx: &mut Bx, - val: &'tcx ty::Const<'tcx>, + val: ConstValue<'tcx>, + ty: Ty<'tcx>, ) -> Self { - let layout = bx.layout_of(val.ty); + let layout = bx.layout_of(ty); if layout.is_zst() { return OperandRef::new_zst(bx, layout); } - let val_val = match val.val { - ty::ConstKind::Value(val_val) => val_val, - _ => bug!("encountered bad ConstKind in codegen"), - }; - - let val = match val_val { + let val = match val { ConstValue::Scalar(x) => { let scalar = match layout.abi { layout::Abi::Scalar(ref x) => x, diff --git a/src/librustc_error_codes/error_codes/E0310.md b/src/librustc_error_codes/error_codes/E0310.md index be87ccb114ad0..8d4311d018b21 100644 --- a/src/librustc_error_codes/error_codes/E0310.md +++ b/src/librustc_error_codes/error_codes/E0310.md @@ -1,7 +1,7 @@ -Types in type definitions have lifetimes associated with them that represent -how long the data stored within them is guaranteed to be live. This lifetime -must be as long as the data needs to be alive, and missing the constraint that -denotes this will cause this error. +A parameter type is missing a lifetime constraint or has a lifetime that +does not live long enough. + +Erroneous code example: ```compile_fail,E0310 // This won't compile because T is not constrained to the static lifetime @@ -11,6 +11,11 @@ struct Foo { } ``` +Type parameters in type definitions have lifetimes associated with them that +represent how long the data stored within them is guaranteed to live. This +lifetime must be as long as the data needs to be alive, and missing the +constraint that denotes this will cause this error. + This will compile, because it has the constraint on the type parameter: ``` diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index aad0e1629359a..04e2558a308b3 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -26,7 +26,7 @@ pub(crate) fn const_field<'tcx>( variant: Option, field: mir::Field, value: &'tcx ty::Const<'tcx>, -) -> &'tcx ty::Const<'tcx> { +) -> ConstValue<'tcx> { trace!("const_field: {:?}, {:?}", field, value); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); // get the operand again @@ -46,19 +46,13 @@ pub(crate) fn const_field<'tcx>( pub(crate) fn const_caller_location<'tcx>( tcx: TyCtxt<'tcx>, (file, line, col): (Symbol, u32, u32), -) -> &'tcx ty::Const<'tcx> { +) -> ConstValue<'tcx> { trace!("const_caller_location: {}:{}:{}", file, line, col); let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false); - let loc_ty = tcx.caller_location_ty(); let loc_place = ecx.alloc_caller_location(file, line, col); intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place, false).unwrap(); - let loc_const = ty::Const { - ty: loc_ty, - val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())), - }; - - tcx.mk_const(loc_const) + ConstValue::Scalar(loc_place.ptr.into()) } // this function uses `unwrap` copiously, because an already validated constant @@ -84,7 +78,8 @@ pub(crate) fn destructure_const<'tcx>( let down = ecx.operand_downcast(op, variant).unwrap(); let fields_iter = (0..field_count).map(|i| { let field_op = ecx.operand_field(down, i).unwrap(); - op_to_const(&ecx, field_op) + let val = op_to_const(&ecx, field_op); + ty::Const::from_value(tcx, val, field_op.layout.ty) }); let fields = tcx.arena.alloc_from_iter(fields_iter); diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 4fdabed54b852..4d5464f774ff5 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -97,7 +97,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>( pub(super) fn op_to_const<'tcx>( ecx: &CompileTimeEvalContext<'_, 'tcx>, op: OpTy<'tcx>, -) -> &'tcx ty::Const<'tcx> { +) -> ConstValue<'tcx> { // We do not have value optimizations for everything. // Only scalars and slices, since they are very common. // Note that further down we turn scalars of undefined bits back to `ByRef`. These can result @@ -144,7 +144,7 @@ pub(super) fn op_to_const<'tcx>( ConstValue::Scalar(Scalar::zst()) } }; - let val = match immediate { + match immediate { Ok(mplace) => to_const_value(mplace), // see comment on `let try_as_immediate` above Err(ImmTy { imm: Immediate::Scalar(x), .. }) => match x { @@ -166,8 +166,7 @@ pub(super) fn op_to_const<'tcx>( let len: usize = len.try_into().unwrap(); ConstValue::Slice { data, start, end: start + len } } - }; - ecx.tcx.mk_const(ty::Const { val: ty::ConstKind::Value(val), ty: op.layout.ty }) + } } fn validate_and_turn_into_const<'tcx>( @@ -195,13 +194,10 @@ fn validate_and_turn_into_const<'tcx>( // whether they become immediates. if is_static || cid.promoted.is_some() { let ptr = mplace.ptr.assert_ptr(); - Ok(tcx.mk_const(ty::Const { - val: ty::ConstKind::Value(ConstValue::ByRef { - alloc: ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), - offset: ptr.offset, - }), - ty: mplace.layout.ty, - })) + Ok(ConstValue::ByRef { + alloc: ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), + offset: ptr.offset, + }) } else { Ok(op_to_const(&ecx, mplace.into())) } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 206d3d156735e..fc4ba4d6cd978 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -756,6 +756,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub(super) fn const_eval( &self, gid: GlobalId<'tcx>, + ty: Ty<'tcx>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics // and thus don't care about the parameter environment. While we could just use @@ -777,7 +778,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not // return `ConstValue::Unevaluated`, which is the only way that `eval_const_to_op` will call // `ecx.const_eval`. - self.eval_const_to_op(val, None) + let const_ = ty::Const { val: ty::ConstKind::Value(val), ty }; + self.eval_const_to_op(&const_, None) } pub fn const_eval_raw( diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 1085b85d7cde3..04f0f92d67ff2 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -48,22 +48,15 @@ crate fn eval_nullary_intrinsic<'tcx>( param_env: ty::ParamEnv<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, -) -> InterpResult<'tcx, &'tcx ty::Const<'tcx>> { +) -> InterpResult<'tcx, ConstValue<'tcx>> { let tp_ty = substs.type_at(0); let name = tcx.item_name(def_id); Ok(match name { sym::type_name => { let alloc = type_name::alloc_type_name(tcx, tp_ty); - tcx.mk_const(ty::Const { - val: ty::ConstKind::Value(ConstValue::Slice { - data: alloc, - start: 0, - end: alloc.len(), - }), - ty: tcx.mk_static_str(), - }) + ConstValue::Slice { data: alloc, start: 0, end: alloc.len() } } - sym::needs_drop => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)), + sym::needs_drop => ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env)), sym::size_of | sym::min_align_of | sym::pref_align_of => { let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?; let n = match name { @@ -72,11 +65,9 @@ crate fn eval_nullary_intrinsic<'tcx>( sym::size_of => layout.size.bytes(), _ => bug!(), }; - ty::Const::from_usize(tcx, n) - } - sym::type_id => { - ty::Const::from_bits(tcx, tcx.type_id_hash(tp_ty).into(), param_env.and(tcx.types.u64)) + ConstValue::from_machine_usize(n, &tcx) } + sym::type_id => ConstValue::from_u64(tcx.type_id_hash(tp_ty).into()), other => bug!("`{}` is not a zero arg intrinsic", other), }) } @@ -119,7 +110,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | sym::type_id | sym::type_name => { let gid = GlobalId { instance, promoted: None }; - let val = self.const_eval(gid)?; + let ty = match intrinsic_name { + sym::min_align_of | sym::pref_align_of | sym::size_of => self.tcx.types.usize, + sym::needs_drop => self.tcx.types.bool, + sym::type_id => self.tcx.types.u64, + sym::type_name => self.tcx.mk_static_str(), + _ => span_bug!(span, "Already checked for nullary intrinsics"), + }; + let val = self.const_eval(gid, ty)?; self.copy_op(val, dest)?; } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index d1c08da6cbee5..14b8a341e26a0 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -518,7 +518,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// "universe" (param_env). crate fn eval_const_to_op( &self, - val: &'tcx ty::Const<'tcx>, + val: &ty::Const<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let tag_scalar = |scalar| match scalar { @@ -536,7 +536,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // potentially requiring the current static to be evaluated again. This is not a // problem here, because we are building an operand which means an actual read is // happening. - return Ok(OpTy::from(self.const_eval(GlobalId { instance, promoted })?)); + return Ok(self.const_eval(GlobalId { instance, promoted }, val.ty)?); } ty::ConstKind::Infer(..) | ty::ConstKind::Bound(..) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index dd2071a6c596a..0fa7d6a9b7223 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -357,7 +357,7 @@ fn collect_items_rec<'tcx>( recursion_depth_reset = None; if let Ok(val) = tcx.const_eval_poly(def_id) { - collect_const(tcx, val, InternalSubsts::empty(), &mut neighbors); + collect_const_value(tcx, val, &mut neighbors); } } MonoItem::Fn(instance) => { @@ -971,7 +971,7 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { let def_id = self.tcx.hir().local_def_id(item.hir_id); if let Ok(val) = self.tcx.const_eval_poly(def_id) { - collect_const(self.tcx, val, InternalSubsts::empty(), &mut self.output); + collect_const_value(self.tcx, val, &mut self.output); } } hir::ItemKind::Fn(..) => { @@ -1185,18 +1185,10 @@ fn collect_const<'tcx>( tcx.subst_and_normalize_erasing_regions(param_substs, param_env, &constant); match substituted_constant.val { - ty::ConstKind::Value(ConstValue::Scalar(Scalar::Ptr(ptr))) => { - collect_miri(tcx, ptr.alloc_id, output) - } - ty::ConstKind::Value(ConstValue::Slice { data: alloc, start: _, end: _ }) - | ty::ConstKind::Value(ConstValue::ByRef { alloc, .. }) => { - for &((), id) in alloc.relocations().values() { - collect_miri(tcx, id, output); - } - } + ty::ConstKind::Value(val) => collect_const_value(tcx, val, output), ty::ConstKind::Unevaluated(def_id, substs, promoted) => { match tcx.const_eval_resolve(param_env, def_id, substs, promoted, None) { - Ok(val) => collect_const(tcx, val, param_substs, output), + Ok(val) => collect_const_value(tcx, val, output), Err(ErrorHandled::Reported) => {} Err(ErrorHandled::TooGeneric) => { span_bug!(tcx.def_span(def_id), "collection encountered polymorphic constant",) @@ -1206,3 +1198,19 @@ fn collect_const<'tcx>( _ => {} } } + +fn collect_const_value<'tcx>( + tcx: TyCtxt<'tcx>, + value: ConstValue<'tcx>, + output: &mut Vec>, +) { + match value { + ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output), + ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => { + for &((), id) in alloc.relocations().values() { + collect_miri(tcx, id, output); + } + } + _ => {} + } +} diff --git a/src/librustc_mir_build/hair/constant.rs b/src/librustc_mir_build/hair/constant.rs index 266f4738c50a6..e594e1eeed07e 100644 --- a/src/librustc_mir_build/hair/constant.rs +++ b/src/librustc_mir_build/hair/constant.rs @@ -65,7 +65,7 @@ crate fn lit_to_const<'tcx>( ast::LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)), ast::LitKind::Err(_) => return Err(LitToConstError::Reported), }; - Ok(tcx.mk_const(ty::Const { val: ty::ConstKind::Value(lit), ty })) + Ok(ty::Const::from_value(tcx, lit, ty)) } fn parse_float<'tcx>(num: Symbol, fty: ast::FloatTy, neg: bool) -> Result, ()> { diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs index d6786ea247973..74006c883716c 100644 --- a/src/librustc_mir_build/hair/cx/expr.rs +++ b/src/librustc_mir_build/hair/cx/expr.rs @@ -418,7 +418,17 @@ fn make_mirror_unadjusted<'a, 'tcx>( None, Some(span), ) { - Ok(cv) => cv.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()), + Ok(cv) => { + if let Some(count) = cv.try_to_bits_for_ty( + cx.tcx, + ty::ParamEnv::reveal_all(), + cx.tcx.types.usize, + ) { + count as u64 + } else { + bug!("repeat count constant value can't be converted to usize"); + } + } Err(ErrorHandled::Reported) => 0, Err(ErrorHandled::TooGeneric) => { let span = cx.tcx.def_span(def_id); diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 7ed6c81eb63bd..85f03629b646a 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -343,12 +343,11 @@ impl<'tcx> PatternFolder<'tcx> for LiteralExpander<'tcx> { ty: rty, span: pat.span, kind: box PatKind::Constant { - value: self.tcx.mk_const(Const { - val: ty::ConstKind::Value( - self.fold_const_value_deref(*val, rty, crty), - ), - ty: rty, - }), + value: Const::from_value( + self.tcx, + self.fold_const_value_deref(*val, rty, crty), + rty, + ), }, }, }, diff --git a/src/librustc_mir_build/hair/pattern/mod.rs b/src/librustc_mir_build/hair/pattern/mod.rs index bd8a9877719e4..9101174646959 100644 --- a/src/librustc_mir_build/hair/pattern/mod.rs +++ b/src/librustc_mir_build/hair/pattern/mod.rs @@ -769,7 +769,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { Some(span), ) { Ok(value) => { - let pattern = self.const_to_pat(value, id, span); + let const_ = + ty::Const::from_value(self.tcx, value, self.tables.node_type(id)); + + let pattern = self.const_to_pat(&const_, id, span); if !is_associated_const { return pattern; } @@ -789,7 +792,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { user_ty_span: span, }, }), - ty: value.ty, + ty: const_.ty, } } else { pattern diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index d947544d182cd..38d73256469fe 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1012,6 +1012,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(self.to_const(count, tcx.type_of(count_def_id))) } else { tcx.const_eval_poly(count_def_id) + .map(|val| ty::Const::from_value(tcx, val, tcx.type_of(count_def_id))) }; let uty = match expected { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9656cbb6bd6a1..f714514040141 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1832,18 +1832,17 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: DefId, span: Span) // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is // the consumer's responsibility to ensure all bytes that have been read // have defined values. - if let Ok(static_) = tcx.const_eval_poly(id) { - let alloc = if let ty::ConstKind::Value(ConstValue::ByRef { alloc, .. }) = static_.val { - alloc - } else { - bug!("Matching on non-ByRef static") - }; - if alloc.relocations().len() != 0 { - let msg = "statics with a custom `#[link_section]` must be a \ + match tcx.const_eval_poly(id) { + Ok(ConstValue::ByRef { alloc, .. }) => { + if alloc.relocations().len() != 0 { + let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ extra levels of indirection such as references"; - tcx.sess.span_err(span, msg); + tcx.sess.span_err(span, msg); + } } + Ok(_) => bug!("Matching on non-ByRef static"), + Err(_) => {} } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 820937b21c845..af81087b53ed6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1332,7 +1332,9 @@ impl Clean for hir::Ty<'_> { TyKind::Array(ref ty, ref length) => { let def_id = cx.tcx.hir().local_def_id(length.hir_id); let length = match cx.tcx.const_eval_poly(def_id) { - Ok(length) => print_const(cx, length), + Ok(length) => { + print_const(cx, ty::Const::from_value(cx.tcx, length, cx.tcx.types.usize)) + } Err(_) => cx .sess() .source_map() diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index b76db6804f813..9863a7db6eabe 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -457,7 +457,7 @@ pub fn name_from_pat(p: &hir::Pat) -> String { } } -pub fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String { +pub fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String { match n.val { ty::ConstKind::Unevaluated(def_id, _, promoted) => { let mut s = if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) { @@ -487,15 +487,18 @@ pub fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String { } pub fn print_evaluated_const(cx: &DocContext<'_>, def_id: DefId) -> Option { - let value = - cx.tcx.const_eval_poly(def_id).ok().and_then(|value| match (value.val, &value.ty.kind) { - (_, ty::Ref(..)) => None, - (ty::ConstKind::Value(ConstValue::Scalar(_)), ty::Adt(_, _)) => None, - (ty::ConstKind::Value(ConstValue::Scalar(_)), _) => { - Some(print_const_with_custom_print_scalar(cx, value)) + let value = cx.tcx.const_eval_poly(def_id).ok().and_then(|val| { + let ty = cx.tcx.type_of(def_id); + match (val, &ty.kind) { + (_, &ty::Ref(..)) => None, + (ConstValue::Scalar(_), &ty::Adt(_, _)) => None, + (ConstValue::Scalar(_), _) => { + let const_ = ty::Const::from_value(cx.tcx, val, ty); + Some(print_const_with_custom_print_scalar(cx, const_)) } _ => None, - }); + } + }); value } diff --git a/src/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs index 4442fa5f52126..82b216a99cf55 100644 --- a/src/test/mir-opt/generator-storage-dead-unwind.rs +++ b/src/test/mir-opt/generator-storage-dead-unwind.rs @@ -49,7 +49,7 @@ fn main() { // StorageLive(_4); // _4 = Bar(const 6i32,); // ... -// _1 = suspend(move _6) -> [resume: bb2, drop: bb4]; +// _5 = yield(move _6) -> [resume: bb2, drop: bb4]; // } // bb1 (cleanup): { // resume; diff --git a/src/test/ui/consts/issue-63952.rs b/src/test/ui/consts/issue-63952.rs new file mode 100644 index 0000000000000..35cbc7003f095 --- /dev/null +++ b/src/test/ui/consts/issue-63952.rs @@ -0,0 +1,28 @@ +// Regression test for #63952, shouldn't hang. + +use std::usize; + +#[repr(C)] +#[derive(Copy, Clone)] +struct SliceRepr { + ptr: *const u8, + len: usize, +} + +union SliceTransmute { + repr: SliceRepr, + slice: &'static [u8], +} + +// bad slice: length too big to even exist anywhere +const SLICE_WAY_TOO_LONG: &[u8] = unsafe { //~ ERROR: it is undefined behavior to use this value + SliceTransmute { + repr: SliceRepr { + ptr: &42, + len: usize::MAX, + }, + } + .slice +}; + +fn main() {} diff --git a/src/test/ui/consts/issue-63952.stderr b/src/test/ui/consts/issue-63952.stderr new file mode 100644 index 0000000000000..d5ed970fc3533 --- /dev/null +++ b/src/test/ui/consts/issue-63952.stderr @@ -0,0 +1,17 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/issue-63952.rs:18:1 + | +LL | / const SLICE_WAY_TOO_LONG: &[u8] = unsafe { +LL | | SliceTransmute { +LL | | repr: SliceRepr { +LL | | ptr: &42, +... | +LL | | .slice +LL | | }; + | |__^ invalid slice: total size is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/generic-associated-types/issue-68653.rs b/src/test/ui/generic-associated-types/issue-68653.rs new file mode 100644 index 0000000000000..01f4c95639d19 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68653.rs @@ -0,0 +1,16 @@ +// A regression test for #68653, which was fixed by #68938. + +// check-pass + +#![allow(incomplete_features)] +#![feature(generic_associated_types)] + +trait Fun { + type F<'a: 'a>; +} + +impl Fun for T { + type F<'a> = Self; +} + +fn main() {} diff --git a/src/test/ui/issues/auxiliary/issue-51798.rs b/src/test/ui/issues/auxiliary/issue-51798.rs new file mode 100644 index 0000000000000..fef5213db9f7a --- /dev/null +++ b/src/test/ui/issues/auxiliary/issue-51798.rs @@ -0,0 +1,3 @@ +#![crate_type = "lib"] + +pub fn vec() -> Vec { vec![] } diff --git a/src/test/ui/issues/issue-51798.rs b/src/test/ui/issues/issue-51798.rs new file mode 100644 index 0000000000000..b075809e93ac2 --- /dev/null +++ b/src/test/ui/issues/issue-51798.rs @@ -0,0 +1,14 @@ +// edition:2018 +// aux-build:issue-51798.rs +// check-pass + +extern crate issue_51798; + +mod server { + fn f() { + let mut v = issue_51798::vec(); + v.clear(); + } +} + +fn main() {} diff --git a/src/test/ui/parser/issue-62894.rs b/src/test/ui/parser/issue-62894.rs new file mode 100644 index 0000000000000..b9c0bf834ddb2 --- /dev/null +++ b/src/test/ui/parser/issue-62894.rs @@ -0,0 +1,7 @@ +// Regression test for #62894, shouldn't crash. +// error-pattern: this file contains an unclosed delimiter +// error-pattern: expected one of `(`, `[`, or `{`, found keyword `fn` + +fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + +fn main() {} diff --git a/src/test/ui/parser/issue-62894.stderr b/src/test/ui/parser/issue-62894.stderr new file mode 100644 index 0000000000000..6db380f7a7fe2 --- /dev/null +++ b/src/test/ui/parser/issue-62894.stderr @@ -0,0 +1,47 @@ +error: this file contains an unclosed delimiter + --> $DIR/issue-62894.rs:7:14 + | +LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +LL | +LL | fn main() {} + | ^ + +error: this file contains an unclosed delimiter + --> $DIR/issue-62894.rs:7:14 + | +LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +LL | +LL | fn main() {} + | ^ + +error: this file contains an unclosed delimiter + --> $DIR/issue-62894.rs:7:14 + | +LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +LL | +LL | fn main() {} + | ^ + +error: expected one of `(`, `[`, or `{`, found keyword `fn` + --> $DIR/issue-62894.rs:7:1 + | +LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + | - expected one of `(`, `[`, or `{` +LL | +LL | fn main() {} + | ^^ unexpected token + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/specialization/issue-39618.rs b/src/test/ui/specialization/issue-39618.rs new file mode 100644 index 0000000000000..20e81e4359bac --- /dev/null +++ b/src/test/ui/specialization/issue-39618.rs @@ -0,0 +1,27 @@ +// Regression test for #39618, shouldn't crash. +// FIXME(JohnTitor): Centril pointed out this looks suspicions, we should revisit here. +// More context: https://github.com/rust-lang/rust/pull/69192#discussion_r379846796 + +// check-pass + +#![feature(specialization)] + +trait Foo { + fn foo(&self); +} + +trait Bar { + fn bar(&self); +} + +impl Bar for T where T: Foo { + fn bar(&self) {} +} + +impl Foo for T where T: Bar { + fn foo(&self) {} +} + +impl Foo for u64 {} + +fn main() {} diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 555e79d3e065c..2a24a8c3c9485 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -631,10 +631,6 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, rdr: R, it: &mut dyn let comment = if testfile.to_string_lossy().ends_with(".rs") { "//" } else { "#" }; - // FIXME: would be nice to allow some whitespace between comment and brace :) - // It took me like 2 days to debug why compile-flags weren’t taken into account for my test :) - let comment_with_brace = comment.to_string() + "["; - let mut rdr = BufReader::new(rdr); let mut ln = String::new(); @@ -650,7 +646,7 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, rdr: R, it: &mut dyn let ln = ln.trim(); if ln.starts_with("fn") || ln.starts_with("mod") { return; - } else if ln.starts_with(&comment_with_brace) { + } else if ln.starts_with(comment) && ln[comment.len()..].trim_start().starts_with('[') { // A comment like `//[foo]` is specific to revision `foo` if let Some(close_brace) = ln.find(']') { let open_brace = ln.find('[').unwrap(); @@ -663,10 +659,7 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, rdr: R, it: &mut dyn it(ln[(close_brace + 1)..].trim_start()); } } else { - panic!( - "malformed condition directive: expected `{}foo]`, found `{}`", - comment_with_brace, ln - ) + panic!("malformed condition directive: expected `{}[foo]`, found `{}`", comment, ln) } } else if ln.starts_with(comment) { it(ln[comment.len()..].trim_start());