From c423a8649c0bac16fd4d1b9cbea657e4245bb5ac Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Sat, 15 Feb 2020 11:56:23 +1300 Subject: [PATCH 01/16] Change const eval to return `ConstValue`, instead of `Const` as the type inside it shouldn't be used. --- src/librustc/mir/interpret/error.rs | 3 +- src/librustc/mir/interpret/value.rs | 33 ++++++++++++++++++++- src/librustc/ty/mod.rs | 6 ++-- src/librustc/ty/sty.rs | 4 ++- src/librustc_codegen_llvm/consts.rs | 8 ++--- src/librustc_codegen_llvm/intrinsic.rs | 3 +- src/librustc_codegen_ssa/mir/constant.rs | 8 ++++- src/librustc_codegen_ssa/mir/operand.rs | 2 +- src/librustc_mir/const_eval.rs | 6 ++-- src/librustc_mir/const_eval/eval_queries.rs | 18 +++++------ src/librustc_mir/interpret/eval_context.rs | 4 ++- src/librustc_mir/interpret/intrinsics.rs | 22 +++++--------- src/librustc_mir/interpret/operand.rs | 4 +-- src/librustc_mir/monomorphize/collector.rs | 32 ++++++++++++-------- src/librustc_mir_build/hair/cx/expr.rs | 12 +++++++- src/librustc_mir_build/hair/pattern/mod.rs | 9 ++++-- src/librustc_typeck/check/expr.rs | 9 ++++-- src/librustc_typeck/check/mod.rs | 17 +++++------ src/librustdoc/clean/mod.rs | 6 +++- src/librustdoc/clean/utils.rs | 19 +++++++----- 20 files changed, 145 insertions(+), 80 deletions(-) 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..538d955762ec3 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(cx: &impl HasDataLayout, i: u64) -> Self { + ConstValue::Scalar(Scalar::from_machine_usize(cx, i)) + } } /// 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(cx: &impl HasDataLayout, i: u64) -> 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(); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index ad51c60ab0178..605baae6c24fa 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2380,10 +2380,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/sty.rs b/src/librustc/ty/sty.rs index 0718853b1df59..57b55c0f897b2 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2471,7 +2471,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| tcx.mk_const(Const { val: ConstKind::Value(val), ty: 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..341a4a77c3c0a 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -193,7 +193,8 @@ 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) + let const_ = ty::Const { val: ty::ConstKind::Value(ty_name), ty: ret_ty }; + OperandRef::from_const(self, &const_).immediate_or_packed_pair(self) } "init" => { let ty = substs.type_at(0); diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 3ce916d781279..d7e87419c1714 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -30,7 +30,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } _ => { let val = self.eval_mir_constant(constant)?; - Ok(OperandRef::from_const(bx, val)) + Ok(OperandRef::from_const(bx, &val)) } } } @@ -45,6 +45,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.cx .tcx() .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None) + .map(|val| { + self.cx.tcx().mk_const(ty::Const { + val: ty::ConstKind::Value(val), + ty: constant.literal.ty, + }) + }) .map_err(|err| { if promoted.is_none() { self.cx diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index a33cd2ddad97b..7745606b84173 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -66,7 +66,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { pub fn from_const>( bx: &mut Bx, - val: &'tcx ty::Const<'tcx>, + val: &ty::Const<'tcx>, ) -> Self { let layout = bx.layout_of(val.ty); diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index aad0e1629359a..5e6db565a7d04 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -40,7 +40,8 @@ pub(crate) fn const_field<'tcx>( let field = ecx.operand_field(down, field.index() as u64).unwrap(); // and finally move back to the const world, always normalizing because // this is not called for statics. - op_to_const(&ecx, field) + let val = op_to_const(&ecx, field); + tcx.mk_const(ty::Const { val: ty::ConstKind::Value(val), ty: op.layout.ty }) } pub(crate) fn const_caller_location<'tcx>( @@ -84,7 +85,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); + tcx.mk_const(ty::Const { val: ty::ConstKind::Value(val), ty: 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 2e8e4dac237bc..6ac828521f326 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..1b1481580a90f 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(&tcx, n) } + 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,8 @@ 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 = instance.ty_env(*self.tcx, self.param_env); + 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/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/mod.rs b/src/librustc_mir_build/hair/pattern/mod.rs index bd8a9877719e4..f403b1432c429 100644 --- a/src/librustc_mir_build/hair/pattern/mod.rs +++ b/src/librustc_mir_build/hair/pattern/mod.rs @@ -769,7 +769,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { Some(span), ) { Ok(value) => { - let pattern = self.const_to_pat(value, id, span); + let const_ = self.tcx.mk_const(ty::Const { + val: ty::ConstKind::Value(value), + ty: self.tables.node_type(id), + }); + + let pattern = self.const_to_pat(&const_, id, span); if !is_associated_const { return pattern; } @@ -789,7 +794,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 90b7b300da9d5..dc9d5003a414b 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -25,7 +25,7 @@ use rustc::ty; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::Ty; use rustc::ty::TypeFoldable; -use rustc::ty::{AdtKind, Visibility}; +use rustc::ty::{AdtKind, ConstKind, Visibility}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; @@ -1011,7 +1011,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let count = if self.const_param_def_id(count).is_some() { Ok(self.to_const(count, tcx.type_of(count_def_id))) } else { - tcx.const_eval_poly(count_def_id) + tcx.const_eval_poly(count_def_id).map(|val| { + tcx.mk_const(ty::Const { + val: ConstKind::Value(val), + ty: 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 a825856e38aa0..7862154a0be6f 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 87edc88611f3a..79019d0b95039 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1332,7 +1332,11 @@ 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) => { + let const_ = + ty::Const { val: ty::ConstKind::Value(length), ty: cx.tcx.types.usize }; + print_const(cx, &const_) + } Err(_) => cx .sess() .source_map() diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index ef35705650452..f8c657477f70c 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -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 { val: ty::ConstKind::Value(val), ty }; + Some(print_const_with_custom_print_scalar(cx, &const_)) } _ => None, - }); + } + }); value } @@ -510,7 +513,7 @@ fn format_integer_with_underscore_sep(num: &str) -> String { .collect() } -fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const<'tcx>) -> String { +fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &ty::Const<'tcx>) -> String { // Use a slightly different format for integer types which always shows the actual value. // For all other types, fallback to the original `pretty_print_const`. match (ct.val, &ct.ty.kind) { From c7aadcfa567f363e302ac797a4805668eb7bc77c Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Sat, 15 Feb 2020 12:57:46 +1300 Subject: [PATCH 02/16] Change `const_field` and `const_caller_location` to return `ConstValue` instead of `Const` as the type in the returned const isn't needed. --- src/librustc/query/mod.rs | 4 +-- src/librustc/ty/query/mod.rs | 2 +- src/librustc_codegen_llvm/intrinsic.rs | 3 +- src/librustc_codegen_ssa/mir/block.rs | 2 +- src/librustc_codegen_ssa/mir/constant.rs | 35 +++++++++++++----------- src/librustc_codegen_ssa/mir/operand.rs | 14 ++++------ src/librustc_mir/const_eval.rs | 15 +++------- 7 files changed, 33 insertions(+), 42 deletions(-) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 11b079806af2d..d9bf93dd6793c 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -517,7 +517,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" } } @@ -531,7 +531,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/query/mod.rs b/src/librustc/ty/query/mod.rs index ddaaab412a477..33312e730f209 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_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 341a4a77c3c0a..3d1e72e1c73d7 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -193,8 +193,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { .tcx .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) .unwrap(); - let const_ = ty::Const { val: ty::ConstKind::Value(ty_name), ty: ret_ty }; - OperandRef::from_const(self, &const_).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 d7e87419c1714..8722aacca721f 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,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } _ => { let val = self.eval_mir_constant(constant)?; - Ok(OperandRef::from_const(bx, &val)) + Ok(OperandRef::from_const(bx, val.clone(), constant.literal.ty)) } } } @@ -38,19 +38,13 @@ 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); self.cx .tcx() .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None) - .map(|val| { - self.cx.tcx().mk_const(ty::Const { - val: ty::ConstKind::Value(val), - ty: constant.literal.ty, - }) - }) .map_err(|err| { if promoted.is_none() { self.cx @@ -61,7 +55,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 { + bug!("encountered bad ConstKind in codegen"); + } + } } } @@ -71,21 +73,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 = bx.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(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 7745606b84173..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: &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_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 5e6db565a7d04..5915520535d24 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 @@ -40,26 +40,19 @@ pub(crate) fn const_field<'tcx>( let field = ecx.operand_field(down, field.index() as u64).unwrap(); // and finally move back to the const world, always normalizing because // this is not called for statics. - let val = op_to_const(&ecx, field); - tcx.mk_const(ty::Const { val: ty::ConstKind::Value(val), ty: op.layout.ty }) + op_to_const(&ecx, field) } 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 From 99a864be39d551362bc29bb76ac06d639afedb42 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Sat, 15 Feb 2020 14:45:36 +1300 Subject: [PATCH 03/16] Fix emulate intrinsics return type. --- src/librustc_mir/interpret/intrinsics.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 1b1481580a90f..b7333ac3aae33 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -110,8 +110,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | sym::type_id | sym::type_name => { let gid = GlobalId { instance, promoted: None }; - let ty = instance.ty_env(*self.tcx, self.param_env); - let val = self.const_eval(gid, ty)?; + let val = self.const_eval(gid, dest.layout.ty)?; self.copy_op(val, dest)?; } From 821f4a9dfb38dab30df861d3c19788b2e7ed0d95 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Sat, 15 Feb 2020 17:43:14 +1300 Subject: [PATCH 04/16] Monomorphize const type during codegen. --- src/librustc_codegen_ssa/mir/constant.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 8722aacca721f..3bd1755927bcd 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -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.clone(), constant.literal.ty)) + let ty = self.monomorphize(&constant.literal.ty); + Ok(OperandRef::from_const(bx, val.clone(), ty)) } } } From 6351bfd182267133409c5174decdff2071f90454 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 16 Feb 2020 02:53:58 +0900 Subject: [PATCH 05/16] Add test for issue-39618 --- src/test/ui/specialization/issue-39618.rs | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/test/ui/specialization/issue-39618.rs diff --git a/src/test/ui/specialization/issue-39618.rs b/src/test/ui/specialization/issue-39618.rs new file mode 100644 index 0000000000000..78894a5699775 --- /dev/null +++ b/src/test/ui/specialization/issue-39618.rs @@ -0,0 +1,24 @@ +// Regression test for #39618, shouldn't crash. +// 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() {} From f32447d54138e9f42ba5a729550603573913397f Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 16 Feb 2020 02:54:16 +0900 Subject: [PATCH 06/16] Add test for issue-51798 --- src/test/ui/issues/auxiliary/issue-51798.rs | 3 +++ src/test/ui/issues/issue-51798.rs | 14 ++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/test/ui/issues/auxiliary/issue-51798.rs create mode 100644 src/test/ui/issues/issue-51798.rs 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() {} From ecb8bf069e0a32d8c76884786a5a0b1ea7ccf8d9 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 16 Feb 2020 02:54:33 +0900 Subject: [PATCH 07/16] Add test for issue-62894 --- src/test/ui/parser/issue-62894.rs | 7 ++++ src/test/ui/parser/issue-62894.stderr | 47 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/test/ui/parser/issue-62894.rs create mode 100644 src/test/ui/parser/issue-62894.stderr 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 + From 426dcf0da03b4287991e378c50ddb0718960941b Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 16 Feb 2020 02:54:51 +0900 Subject: [PATCH 08/16] Add test for issue-63952 --- src/test/ui/consts/issue-63952.rs | 28 +++++++++++++++++++++++++++ src/test/ui/consts/issue-63952.stderr | 17 ++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/test/ui/consts/issue-63952.rs create mode 100644 src/test/ui/consts/issue-63952.stderr 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`. From 9478503315795401ce037fbca87bf1dbf82f8d31 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 16 Feb 2020 02:55:03 +0900 Subject: [PATCH 09/16] Add test for issue-68653 --- .../ui/generic-associated-types/issue-68653.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/test/ui/generic-associated-types/issue-68653.rs 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() {} From 2f39ec24b20bc1ef09c7810f8210ea48bb5a3d29 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 16 Feb 2020 04:36:44 +0900 Subject: [PATCH 10/16] Add FIXME note --- src/test/ui/specialization/issue-39618.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/ui/specialization/issue-39618.rs b/src/test/ui/specialization/issue-39618.rs index 78894a5699775..20e81e4359bac 100644 --- a/src/test/ui/specialization/issue-39618.rs +++ b/src/test/ui/specialization/issue-39618.rs @@ -1,4 +1,7 @@ // 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)] From 774a029e9629a461355c9e9cb423820e9936dc65 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Sun, 16 Feb 2020 09:59:01 +1300 Subject: [PATCH 11/16] Code review changes. --- src/librustc/mir/interpret/value.rs | 11 ++++++++--- src/librustc/ty/sty.rs | 9 +++++++-- src/librustc_codegen_ssa/mir/constant.rs | 4 ++-- src/librustc_mir/const_eval.rs | 2 +- src/librustc_mir/interpret/intrinsics.rs | 2 +- src/librustc_mir_build/hair/constant.rs | 2 +- src/librustc_mir_build/hair/pattern/_match.rs | 11 +++++------ src/librustc_mir_build/hair/pattern/mod.rs | 6 ++---- src/librustc_typeck/check/expr.rs | 10 +++------- src/librustdoc/clean/mod.rs | 4 +--- src/librustdoc/clean/utils.rs | 8 ++++---- 11 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 538d955762ec3..2c146b5d7b426 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -89,8 +89,8 @@ impl<'tcx> ConstValue<'tcx> { ConstValue::Scalar(Scalar::from_u64(i)) } - pub fn from_machine_usize(cx: &impl HasDataLayout, i: u64) -> Self { - ConstValue::Scalar(Scalar::from_machine_usize(cx, i)) + pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self { + ConstValue::Scalar(Scalar::from_machine_usize(i, cx)) } } @@ -314,7 +314,7 @@ impl<'tcx, Tag> Scalar { } #[inline] - pub fn from_machine_usize(cx: &impl HasDataLayout, i: u64) -> Self { + pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self { Self::from_uint(i, cx.data_layout().pointer_size) } @@ -337,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/ty/sty.rs b/src/librustc/ty/sty.rs index 57b55c0f897b2..a23c44d1921e1 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2415,9 +2415,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,7 @@ impl<'tcx> Const<'tcx> { // evaluate the const. tcx.const_eval_resolve(param_env, did, substs, promoted, None) .ok() - .map(|val| tcx.mk_const(Const { val: ConstKind::Value(val), ty: self.ty })) + .map(|val| Const::from_value(tcx, val, self.ty)) }; match self.val { diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 3bd1755927bcd..9ceb75a603bc4 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -62,7 +62,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if let ty::ConstKind::Value(value) = const_.val { Ok(value) } else { - bug!("encountered bad ConstKind in codegen"); + span_bug!(constant.span, "encountered bad ConstKind in codegen: {:?}", const_); } } } @@ -83,7 +83,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ty::Array(_, n) => n.eval_usize(bx.tcx(), ty::ParamEnv::reveal_all()), _ => bug!("invalid simd shuffle type: {}", ty), }; - let c = bx.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(val), ty }); + let c = ty::Const::from_value(bx.tcx(), val, ty); let values: Vec<_> = (0..fields) .map(|field| { let field = bx.tcx().const_field( diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 5915520535d24..04e2558a308b3 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -79,7 +79,7 @@ pub(crate) fn destructure_const<'tcx>( let fields_iter = (0..field_count).map(|i| { let field_op = ecx.operand_field(down, i).unwrap(); let val = op_to_const(&ecx, field_op); - tcx.mk_const(ty::Const { val: ty::ConstKind::Value(val), ty: field_op.layout.ty }) + 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/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index b7333ac3aae33..42d4996c25391 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -65,7 +65,7 @@ crate fn eval_nullary_intrinsic<'tcx>( sym::size_of => layout.size.bytes(), _ => bug!(), }; - ConstValue::from_machine_usize(&tcx, n) + 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), 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/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 f403b1432c429..9101174646959 100644 --- a/src/librustc_mir_build/hair/pattern/mod.rs +++ b/src/librustc_mir_build/hair/pattern/mod.rs @@ -769,10 +769,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { Some(span), ) { Ok(value) => { - let const_ = self.tcx.mk_const(ty::Const { - val: ty::ConstKind::Value(value), - ty: self.tables.node_type(id), - }); + 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 { diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index dc9d5003a414b..e694d845a9b78 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -25,7 +25,7 @@ use rustc::ty; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::Ty; use rustc::ty::TypeFoldable; -use rustc::ty::{AdtKind, ConstKind, Visibility}; +use rustc::ty::{AdtKind, Visibility}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; @@ -1011,12 +1011,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let count = if self.const_param_def_id(count).is_some() { Ok(self.to_const(count, tcx.type_of(count_def_id))) } else { - tcx.const_eval_poly(count_def_id).map(|val| { - tcx.mk_const(ty::Const { - val: ConstKind::Value(val), - ty: tcx.type_of(count_def_id), - }) - }) + 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/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 79019d0b95039..67c9b9565db00 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1333,9 +1333,7 @@ impl Clean for hir::Ty<'_> { let def_id = cx.tcx.hir().local_def_id(length.hir_id); let length = match cx.tcx.const_eval_poly(def_id) { Ok(length) => { - let const_ = - ty::Const { val: ty::ConstKind::Value(length), ty: cx.tcx.types.usize }; - print_const(cx, &const_) + print_const(cx, ty::Const::from_value(cx.tcx, length, cx.tcx.types.usize)) } Err(_) => cx .sess() diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index f8c657477f70c..704583467b4f3 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) { @@ -493,8 +493,8 @@ pub fn print_evaluated_const(cx: &DocContext<'_>, def_id: DefId) -> Option None, (ConstValue::Scalar(_), &ty::Adt(_, _)) => None, (ConstValue::Scalar(_), _) => { - let const_ = ty::Const { val: ty::ConstKind::Value(val), ty }; - Some(print_const_with_custom_print_scalar(cx, &const_)) + let const_ = ty::Const::from_value(cx.tcx, val, ty); + Some(print_const_with_custom_print_scalar(cx, const_)) } _ => None, } @@ -513,7 +513,7 @@ fn format_integer_with_underscore_sep(num: &str) -> String { .collect() } -fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &ty::Const<'tcx>) -> String { +fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const<'tcx>) -> String { // Use a slightly different format for integer types which always shows the actual value. // For all other types, fallback to the original `pretty_print_const`. match (ct.val, &ct.ty.kind) { From 8904bddec5abea92c88e5c991925c08a3df5faf3 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Sun, 16 Feb 2020 11:39:04 +1300 Subject: [PATCH 12/16] Determine type of intrinsics instead of assuming the destination type is the same. --- src/librustc_mir/interpret/intrinsics.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 42d4996c25391..04f0f92d67ff2 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -110,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, dest.layout.ty)?; + 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)?; } From 759526e513f28443b845b63176f15424686d0254 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 16 Feb 2020 00:57:48 +0100 Subject: [PATCH 13/16] Fix printing of `Yield` terminator --- src/librustc/mir/mod.rs | 18 ++++++++++-------- .../mir-opt/generator-storage-dead-unwind.rs | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 4520d3a333316..a3e3a26db05d6 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1468,21 +1468,23 @@ 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, "{:?} = suspend({:?})", 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 +1496,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/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs index 4442fa5f52126..98acce8375974 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 = suspend(move _6) -> [resume: bb2, drop: bb4]; // } // bb1 (cleanup): { // resume; From bb482ebf2870bae6e1b69822f1c7d7d9d4b33103 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 16 Feb 2020 13:08:36 +0100 Subject: [PATCH 14/16] suspend -> yield --- src/librustc/mir/mod.rs | 4 +--- src/test/mir-opt/generator-storage-dead-unwind.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index a3e3a26db05d6..9b94f92acd476 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1475,9 +1475,7 @@ impl<'tcx> TerminatorKind<'tcx> { GeneratorDrop => write!(fmt, "generator_drop"), Resume => write!(fmt, "resume"), Abort => write!(fmt, "abort"), - Yield { value, resume_arg, .. } => { - write!(fmt, "{:?} = suspend({:?})", resume_arg, value) - } + Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value), Unreachable => write!(fmt, "unreachable"), Drop { location, .. } => write!(fmt, "drop({:?})", location), DropAndReplace { location, value, .. } => { diff --git a/src/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs index 98acce8375974..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,); // ... -// _5 = suspend(move _6) -> [resume: bb2, drop: bb4]; +// _5 = yield(move _6) -> [resume: bb2, drop: bb4]; // } // bb1 (cleanup): { // resume; From d1a7ae7d1659dae412dde2eadeaf1cf7c9d87570 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 16 Feb 2020 17:12:03 +0900 Subject: [PATCH 15/16] Allow whitespaces in revision flags --- src/tools/compiletest/src/header.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) 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()); From 73283f1b32f2c607be6ba5d51d867f8862eca95e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 17 Feb 2020 14:16:45 +0100 Subject: [PATCH 16/16] Clean up E0310 explanation --- src/librustc_error_codes/error_codes/E0310.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) 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: ```