From fcb3d0d6ae03c12cbd6d1e8c2917c96de9ba0fe0 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Mon, 21 Jan 2019 21:02:48 +0530 Subject: [PATCH 01/18] Expose alloc/dealloc properly for SGX libunwind --- src/libstd/sys/sgx/rwlock.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs index 47874158ed9..43ceae7d33b 100644 --- a/src/libstd/sys/sgx/rwlock.rs +++ b/src/libstd/sys/sgx/rwlock.rs @@ -1,3 +1,4 @@ +use alloc::{self, Layout}; use num::NonZeroUsize; use slice; use str; @@ -147,6 +148,7 @@ impl RWLock { self.__write_unlock(rguard, wguard); } + // only used by __rust_rwlock_unlock below #[inline] unsafe fn unlock(&self) { let rguard = self.readers.lock(); @@ -164,6 +166,7 @@ impl RWLock { const EINVAL: i32 = 22; +// used by libunwind port #[no_mangle] pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 { if p.is_null() { @@ -190,6 +193,8 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 { return 0; } +// the following functions are also used by the libunwind port. They're +// included here to make sure parallel codegen and LTO don't mess things up. #[no_mangle] pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { if s < 0 { @@ -206,6 +211,16 @@ pub unsafe extern "C" fn __rust_abort() { ::sys::abort_internal(); } +#[no_mangle] +pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 { + alloc::alloc(Layout::from_size_align_unchecked(size, align)) +} + +#[no_mangle] +pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) { + alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) +} + #[cfg(test)] mod tests { From 6abba95045e28e768a2b553f6b0cd2f04a71bfe0 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Mon, 21 Jan 2019 18:50:36 +0530 Subject: [PATCH 02/18] Update libunwind for SGX target --- src/ci/docker/dist-various-2/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/dist-various-2/Dockerfile b/src/ci/docker/dist-various-2/Dockerfile index 906255533ad..952c1ba2ccb 100644 --- a/src/ci/docker/dist-various-2/Dockerfile +++ b/src/ci/docker/dist-various-2/Dockerfile @@ -32,7 +32,7 @@ RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc COPY dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/ # We pass the commit id of the port of LLVM's libunwind to the build script. # Any update to the commit id here, should cause the container image to be re-built from this point on. -RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "bbe23902411be88d7388f381becefadd6e3ef819" +RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "13fad13f8ea83a8da58d04a5faa45943151b3398" COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh From a59eabbc36d7b96bb9e42d9bc6691d28b62c4187 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 14 Jan 2019 17:54:00 +0100 Subject: [PATCH 03/18] Get rid of the fake stack frame --- src/librustc_codegen_ssa/mir/constant.rs | 1 - src/librustc_mir/const_eval.rs | 80 ++++-------------------- src/librustc_mir/hair/pattern/_match.rs | 23 +++++-- src/librustc_mir/hair/pattern/mod.rs | 4 +- src/librustc_mir/transform/const_prop.rs | 6 +- src/test/ui/consts/match_ice.rs | 11 ++++ 6 files changed, 44 insertions(+), 81 deletions(-) create mode 100644 src/test/ui/consts/match_ice.rs diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index e6d6ef1d7a3..56d4342e6e1 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -59,7 +59,6 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let field = const_field( bx.tcx(), ty::ParamEnv::reveal_all(), - self.instance, None, mir::Field::new(field as usize), c, diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 105856fecc7..25b0d1424ca 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -10,16 +10,15 @@ use rustc::hir::{self, def_id::DefId}; use rustc::hir::def::Def; use rustc::mir::interpret::{ConstEvalErr, ErrorHandled}; use rustc::mir; -use rustc::ty::{self, TyCtxt, Instance, query::TyCtxtAt}; +use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{self, LayoutOf, TyLayout, VariantIdx}; use rustc::ty::subst::Subst; use rustc::traits::Reveal; -use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::fx::FxHashMap; use rustc::util::common::ErrorReported; use syntax::ast::Mutability; -use syntax::source_map::{Span, DUMMY_SP}; +use syntax::source_map::DUMMY_SP; use crate::interpret::{self, PlaceTy, MPlaceTy, MemPlace, OpTy, Operand, Immediate, Scalar, RawConst, ConstValue, Pointer, @@ -35,56 +34,6 @@ const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000; /// Should be a power of two for performance reasons. const DETECTOR_SNAPSHOT_PERIOD: isize = 256; -/// Warning: do not use this function if you expect to start interpreting the given `Mir`. -/// The `EvalContext` is only meant to be used to query values from constants and statics. -/// -/// This function is used during const propagation. We cannot use `mk_eval_cx`, because copy -/// propagation happens *during* the computation of the MIR of the current function. So if we -/// tried to call the `optimized_mir` query, we'd get a cycle error because we are (transitively) -/// inside the `optimized_mir` query of the `Instance` given. -/// -/// Since we are looking at the MIR of the function in an abstract manner, we don't have a -/// `ParamEnv` available to us. This function creates a `ParamEnv` for the given instance. -pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, - mir: &'mir mir::Mir<'tcx>, - span: Span, -) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'mir, 'tcx>> { - debug!("mk_borrowck_eval_cx: {:?}", instance); - let param_env = tcx.param_env(instance.def_id()); - mk_eval_cx_inner(tcx, instance, mir, span, param_env) -} - -/// This is just a helper function to reduce code duplication between `mk_borrowck_eval_cx` and -/// `mk_eval_cx`. Do not call this function directly. -fn mk_eval_cx_inner<'a, 'mir, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, - mir: &'mir mir::Mir<'tcx>, - span: Span, - param_env: ty::ParamEnv<'tcx>, -) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'mir, 'tcx>> { - let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new()); - // Insert a stack frame so any queries have the correct substs. - // We also avoid all the extra work performed by push_stack_frame, - // like initializing local variables - ecx.stack.push(interpret::Frame { - block: mir::START_BLOCK, - locals: IndexVec::new(), - local_layouts: IndexVec::new(), - instance, - span, - mir, - return_place: None, - return_to_block: StackPopCleanup::Goto(None), // never pop - stmt: 0, - extra: (), - }); - Ok(ecx) -} - -/// Warning: do not use this function if you expect to start interpreting the given `Mir`. /// The `EvalContext` is only meant to be used to do field and index projections into constants for /// `simd_shuffle` and const patterns in match arms. /// @@ -92,15 +41,12 @@ fn mk_eval_cx_inner<'a, 'mir, 'tcx>( /// that inform us about the generic bounds of the constant. E.g. using an associated constant /// of a function's generic parameter will require knowledge about the bounds on the generic /// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. -fn mk_eval_cx<'a, 'tcx>( +pub(crate) fn mk_eval_cx<'a, 'mir, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, param_env: ty::ParamEnv<'tcx>, -) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'tcx, 'tcx>> { - debug!("mk_eval_cx: {:?}, {:?}", instance, param_env); - let span = tcx.def_span(instance.def_id()); - let mir = tcx.optimized_mir(instance.def.def_id()); - mk_eval_cx_inner(tcx, instance, mir, span, param_env) +) -> CompileTimeEvalContext<'a, 'mir, 'tcx> { + debug!("mk_eval_cx: {:?}", param_env); + EvalContext::new(tcx.at(DUMMY_SP), param_env, CompileTimeInterpreter::new()) } pub(crate) fn eval_promoted<'a, 'mir, 'tcx>( @@ -109,7 +55,7 @@ pub(crate) fn eval_promoted<'a, 'mir, 'tcx>( mir: &'mir mir::Mir<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> EvalResult<'tcx, MPlaceTy<'tcx>> { - let mut ecx = mk_borrowck_eval_cx(tcx, cid.instance, mir, DUMMY_SP).unwrap(); + let mut ecx = mk_eval_cx(tcx, param_env); eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env) } @@ -530,13 +476,12 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> pub fn const_field<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - instance: ty::Instance<'tcx>, variant: Option, field: mir::Field, value: ty::Const<'tcx>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { - trace!("const_field: {:?}, {:?}, {:?}", instance, field, value); - let ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); + trace!("const_field: {:?}, {:?}", field, value); + let ecx = mk_eval_cx(tcx, param_env); let result = (|| { // get the operand again let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(value), value.ty)?; @@ -561,11 +506,10 @@ pub fn const_field<'a, 'tcx>( pub fn const_variant_index<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - instance: ty::Instance<'tcx>, val: ty::Const<'tcx>, ) -> EvalResult<'tcx, VariantIdx> { - trace!("const_variant_index: {:?}, {:?}", instance, val); - let ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); + trace!("const_variant_index: {:?}", val); + let ecx = mk_eval_cx(tcx, param_env); let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(val), val.ty)?; Ok(ecx.read_discriminant(op)?.1) } @@ -585,7 +529,7 @@ fn validate_and_turn_into_const<'a, 'tcx>( key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { let cid = key.value; - let ecx = mk_eval_cx(tcx, cid.instance, key.param_env).unwrap(); + let ecx = mk_eval_cx(tcx, key.param_env); let val = (|| { let op = ecx.raw_const_to_mplace(constant)?.into(); // FIXME: Once the visitor infrastructure landed, change validation to diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 188a1120442..9cc5c93de41 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -427,13 +427,24 @@ pub enum Constructor<'tcx> { } impl<'tcx> Constructor<'tcx> { - fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx { + fn variant_index_for_adt<'a>( + &self, + cx: &MatchCheckCtxt<'a, 'tcx>, + adt: &'tcx ty::AdtDef, + ) -> VariantIdx { match self { &Variant(vid) => adt.variant_index_with_id(vid), &Single => { assert!(!adt.is_enum()); VariantIdx::new(0) } + &ConstantValue(c) => { + ::const_eval::const_variant_index( + cx.tcx, + cx.param_env, + c, + ).unwrap() + }, _ => bug!("bad constructor {:?} for adt {:?}", self, adt) } } @@ -567,7 +578,7 @@ impl<'tcx> Witness<'tcx> { PatternKind::Variant { adt_def: adt, substs, - variant_index: ctor.variant_index_for_adt(adt), + variant_index: ctor.variant_index_for_adt(cx, adt), subpatterns: pats } } else { @@ -1329,7 +1340,7 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>, /// /// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3. /// A struct pattern's arity is the number of fields it contains, etc. -fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 { +fn constructor_arity(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor<'tcx>, ty: Ty<'tcx>) -> u64 { debug!("constructor_arity({:#?}, {:?})", ctor, ty); match ty.sty { ty::Tuple(ref fs) => fs.len() as u64, @@ -1340,7 +1351,7 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 { }, ty::Ref(..) => 1, ty::Adt(adt, _) => { - adt.variants[ctor.variant_index_for_adt(adt)].fields.len() as u64 + adt.variants[ctor.variant_index_for_adt(cx, adt)].fields.len() as u64 } _ => 0 } @@ -1351,7 +1362,7 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 { /// /// For instance, a tuple pattern (43u32, 'a') has sub pattern types [u32, char]. fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, - ctor: &Constructor, + ctor: &Constructor<'tcx>, ty: Ty<'tcx>) -> Vec> { debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty); @@ -1368,7 +1379,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, // Use T as the sub pattern type of Box. vec![substs.type_at(0)] } else { - adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| { + adt.variants[ctor.variant_index_for_adt(cx, adt)].fields.iter().map(|field| { let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); if is_visible { diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 8991a90737c..cdaffe5d456 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -885,7 +885,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let adt_subpattern = |i, variant_opt| { let field = Field::new(i); let val = const_field( - self.tcx, self.param_env, instance, + self.tcx, self.param_env, variant_opt, field, cv, ).expect("field access failed"); self.const_to_pat(instance, val, id, span) @@ -928,7 +928,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }, ty::Adt(adt_def, substs) if adt_def.is_enum() => { let variant_index = const_variant_index( - self.tcx, self.param_env, instance, cv + self.tcx, self.param_env, cv ).expect("const_variant_index failed"); let subpatterns = adt_subpatterns( adt_def.variants[variant_index].fields.len(), diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 03d6d3868c9..fba74514f04 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -20,7 +20,7 @@ use rustc::ty::layout::{ use interpret::{self, EvalContext, ScalarMaybeUndef, Immediate, OpTy, MemoryKind}; use const_eval::{ - CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_borrowck_eval_cx, + CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx, lazy_const_to_op, }; use transform::{MirPass, MirSource}; @@ -110,9 +110,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { source: MirSource, ) -> ConstPropagator<'a, 'mir, 'tcx> { let param_env = tcx.param_env(source.def_id); - let substs = Substs::identity_for_item(tcx, source.def_id); - let instance = Instance::new(source.def_id, substs); - let ecx = mk_borrowck_eval_cx(tcx, instance, mir, DUMMY_SP).unwrap(); + let ecx = mk_eval_cx(tcx, param_env); ConstPropagator { ecx, mir, diff --git a/src/test/ui/consts/match_ice.rs b/src/test/ui/consts/match_ice.rs new file mode 100644 index 00000000000..c785317778b --- /dev/null +++ b/src/test/ui/consts/match_ice.rs @@ -0,0 +1,11 @@ +// compile-pass +// https://github.com/rust-lang/rust/issues/53708 + +struct S; + +fn main() { + const C: &S = &S; + match C { + C => {} + } +} From db2978a73cc4ab71c8839e70d12bc87d5279e632 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 14 Jan 2019 17:54:35 +0100 Subject: [PATCH 04/18] Bail out on overly generic substitutions --- src/librustc_mir/interpret/cast.rs | 6 +--- src/librustc_mir/interpret/eval_context.rs | 42 ++++++++++++++++------ src/librustc_mir/interpret/operand.rs | 2 +- src/librustc_mir/interpret/place.rs | 5 +-- src/librustc_mir/interpret/step.rs | 4 +-- 5 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 190a381cf52..c3b71be8354 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -109,11 +109,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // The src operand does not matter, just its type match src.layout.ty.sty { ty::Closure(def_id, substs) => { - let substs = self.tcx.subst_and_normalize_erasing_regions( - self.substs(), - ty::ParamEnv::reveal_all(), - &substs, - ); + let substs = self.subst_and_normalize_erasing_regions(substs)?; let instance = ty::Instance::resolve_closure( *self.tcx, def_id, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index b2d3328a73f..b2db0fea3d0 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -216,11 +216,21 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc self.frame().mir } - pub fn substs(&self) -> &'tcx Substs<'tcx> { - if let Some(frame) = self.stack.last() { - frame.instance.substs - } else { - Substs::empty() + pub(super) fn subst_and_normalize_erasing_regions>( + &self, + substs: T, + ) -> EvalResult<'tcx, T> { + match self.stack.last() { + Some(frame) => Ok(self.tcx.subst_and_normalize_erasing_regions( + frame.instance.substs, + self.param_env, + &substs, + )), + None => if substs.needs_subst() { + err!(TooGeneric).into() + } else { + Ok(substs) + }, } } @@ -230,13 +240,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc substs: &'tcx Substs<'tcx> ) -> EvalResult<'tcx, ty::Instance<'tcx>> { trace!("resolve: {:?}, {:#?}", def_id, substs); - trace!("substs: {:#?}", self.substs()); trace!("param_env: {:#?}", self.param_env); - let substs = self.tcx.subst_and_normalize_erasing_regions( - self.substs(), - self.param_env, - &substs, - ); + let substs = self.subst_and_normalize_erasing_regions(substs)?; + trace!("substs: {:#?}", substs); ty::Instance::resolve( *self.tcx, self.param_env, @@ -276,6 +282,20 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } } + pub fn monomorphize_in_frame + Subst<'tcx>>( + &self, + t: T, + ) -> EvalResult<'tcx, T> { + match self.stack.last() { + Some(frame) => Ok(self.monomorphize(t, frame.instance.substs)), + None => if t.needs_subst() { + err!(TooGeneric).into() + } else { + Ok(t) + }, + } + } + pub fn monomorphize + Subst<'tcx>>( &self, t: T, diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index b2648480f20..8995d091aaa 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -508,7 +508,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> Constant(ref constant) => { let layout = from_known_layout(layout, || { - let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx), self.substs()); + let ty = self.monomorphize_in_frame(mir_op.ty(self.mir(), *self.tcx))?; self.layout_of(ty) })?; let op = self.const_value_to_op(*constant.literal)?; diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 962e0b7a742..f3a948a6ca3 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -9,6 +9,7 @@ use rustc::hir; use rustc::mir; use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx}; +use rustc::ty::TypeFoldable; use super::{ GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic, @@ -583,8 +584,8 @@ where } Static(ref static_) => { - let ty = self.monomorphize(static_.ty, self.substs()); - let layout = self.layout_of(ty)?; + assert!(!static_.ty.needs_subst()); + let layout = self.layout_of(static_.ty)?; let instance = ty::Instance::mono(*self.tcx, static_.def_id); let cid = GlobalId { instance, diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 2de8b3c1afd..f1b4e6a5055 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -248,7 +248,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } NullaryOp(mir::NullOp::SizeOf, ty) => { - let ty = self.monomorphize(ty, self.substs()); + let ty = self.monomorphize_in_frame(ty)?; let layout = self.layout_of(ty)?; assert!(!layout.is_unsized(), "SizeOf nullary MIR operator called for unsized type"); @@ -260,7 +260,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } Cast(kind, ref operand, cast_ty) => { - debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest.layout.ty); + debug_assert_eq!(self.monomorphize_in_frame(cast_ty)?, dest.layout.ty); let src = self.eval_operand(operand, None)?; self.cast(src, kind, dest)?; } From f6da141b5f1d30f11be503db9783fa61a276c87b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 14 Jan 2019 19:50:49 +0100 Subject: [PATCH 05/18] Span fixup --- src/librustc_mir/const_eval.rs | 14 ++++++++------ src/librustc_mir/transform/const_prop.rs | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 25b0d1424ca..45c6c1b4249 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -18,7 +18,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc::util::common::ErrorReported; use syntax::ast::Mutability; -use syntax::source_map::DUMMY_SP; +use syntax::source_map::{Span, DUMMY_SP}; use crate::interpret::{self, PlaceTy, MPlaceTy, MemPlace, OpTy, Operand, Immediate, Scalar, RawConst, ConstValue, Pointer, @@ -43,10 +43,11 @@ const DETECTOR_SNAPSHOT_PERIOD: isize = 256; /// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. pub(crate) fn mk_eval_cx<'a, 'mir, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, + span: Span, param_env: ty::ParamEnv<'tcx>, ) -> CompileTimeEvalContext<'a, 'mir, 'tcx> { debug!("mk_eval_cx: {:?}", param_env); - EvalContext::new(tcx.at(DUMMY_SP), param_env, CompileTimeInterpreter::new()) + EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new()) } pub(crate) fn eval_promoted<'a, 'mir, 'tcx>( @@ -55,7 +56,8 @@ pub(crate) fn eval_promoted<'a, 'mir, 'tcx>( mir: &'mir mir::Mir<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> EvalResult<'tcx, MPlaceTy<'tcx>> { - let mut ecx = mk_eval_cx(tcx, param_env); + let span = tcx.def_span(cid.instance.def_id()); + let mut ecx = mk_eval_cx(tcx, span, param_env); eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env) } @@ -481,7 +483,7 @@ pub fn const_field<'a, 'tcx>( value: ty::Const<'tcx>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { trace!("const_field: {:?}, {:?}", field, value); - let ecx = mk_eval_cx(tcx, param_env); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env); let result = (|| { // get the operand again let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(value), value.ty)?; @@ -509,7 +511,7 @@ pub fn const_variant_index<'a, 'tcx>( val: ty::Const<'tcx>, ) -> EvalResult<'tcx, VariantIdx> { trace!("const_variant_index: {:?}", val); - let ecx = mk_eval_cx(tcx, param_env); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env); let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(val), val.ty)?; Ok(ecx.read_discriminant(op)?.1) } @@ -529,7 +531,7 @@ fn validate_and_turn_into_const<'a, 'tcx>( key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { let cid = key.value; - let ecx = mk_eval_cx(tcx, key.param_env); + let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env); let val = (|| { let op = ecx.raw_const_to_mplace(constant)?.into(); // FIXME: Once the visitor infrastructure landed, change validation to diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index fba74514f04..dc556a15cd8 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -110,7 +110,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { source: MirSource, ) -> ConstPropagator<'a, 'mir, 'tcx> { let param_env = tcx.param_env(source.def_id); - let ecx = mk_eval_cx(tcx, param_env); + let ecx = mk_eval_cx(tcx, tcx.def_span(source.def_id), param_env); ConstPropagator { ecx, mir, From 2c57d1d256b84d3bd7f4a1d9613091bd9ec3ca02 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 14 Jan 2019 19:51:00 +0100 Subject: [PATCH 06/18] Add regression test --- src/test/ui/consts/match_ice.rs | 5 ++--- src/test/ui/consts/match_ice.stderr | 9 +++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/consts/match_ice.stderr diff --git a/src/test/ui/consts/match_ice.rs b/src/test/ui/consts/match_ice.rs index c785317778b..53c5782a4c7 100644 --- a/src/test/ui/consts/match_ice.rs +++ b/src/test/ui/consts/match_ice.rs @@ -1,11 +1,10 @@ -// compile-pass // https://github.com/rust-lang/rust/issues/53708 struct S; fn main() { const C: &S = &S; - match C { - C => {} + match C { //~ ERROR non-exhaustive + C => {} // this is a common bug around constants and references in patterns } } diff --git a/src/test/ui/consts/match_ice.stderr b/src/test/ui/consts/match_ice.stderr new file mode 100644 index 00000000000..e6e04e2c462 --- /dev/null +++ b/src/test/ui/consts/match_ice.stderr @@ -0,0 +1,9 @@ +error[E0004]: non-exhaustive patterns: `&S` not covered + --> $DIR/match_ice.rs:7:11 + | +LL | match C { //~ ERROR non-exhaustive + | ^ pattern `&S` not covered + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. From b1542341da756013a4a2126cd7628bbc2a8c3ba7 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 22 Jan 2019 15:40:27 -0600 Subject: [PATCH 07/18] don't call get_macro on proc-macro stubs --- src/librustdoc/passes/collect_intra_doc_links.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3d6096b07ce..13ad05101e4 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -431,8 +431,12 @@ fn macro_resolve(cx: &DocContext, path_str: &str) -> Option { let parent_scope = resolver.dummy_parent_scope(); if let Ok(def) = resolver.resolve_macro_to_def_inner(&path, MacroKind::Bang, &parent_scope, false, false) { - if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) { - return Some(def); + if let Def::Macro(_, MacroKind::ProcMacroStub) = def { + // skip proc-macro stubs, they'll cause `get_macro` to crash + } else { + if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) { + return Some(def); + } } } if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) { From b876694734cfc5919b8c12527c287aea1a8d8cfd Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 22 Jan 2019 15:44:19 -0600 Subject: [PATCH 08/18] add intra-doc link test to proc-macro test --- src/test/rustdoc/proc-macro.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/rustdoc/proc-macro.rs b/src/test/rustdoc/proc-macro.rs index d4d70d04f5b..1e396f1be0e 100644 --- a/src/test/rustdoc/proc-macro.rs +++ b/src/test/rustdoc/proc-macro.rs @@ -4,6 +4,11 @@ #![crate_type="proc-macro"] #![crate_name="some_macros"] +// @has some_macros/index.html +// @has - '//a/[@href="attr.some_proc_attr.html"]' 'some_proc_attr' + +//! include a link to [some_proc_attr] to make sure it works. + extern crate proc_macro; use proc_macro::TokenStream; From 55dea0edecc71a88ca11adb0629c0434e5d0f14b Mon Sep 17 00:00:00 2001 From: Alex Berghage Date: Sun, 6 Jan 2019 11:53:47 -0700 Subject: [PATCH 09/18] Simplify units in Duration/Instant math on Windows Right now we do unit conversions between PerfCounter measurements and nanoseconds for every add/sub we do between Durations and Instants on Windows machines. This leads to goofy behavior, like this snippet failing: ``` let now = Instant::now(); let offset = Duration::from_millis(5); assert_eq!((now + offset) - now, (now - now) + offset); ``` with precision problems like this: ``` thread 'main' panicked at 'assertion failed: `(left == right)` left: `4.999914ms`, right: `5ms`', src\main.rs:6:5 ``` To fix it, this changeset does the unit conversion once, when we measure the clock, and all the subsequent math in u64 nanoseconds. It also adds an exact associativity test to the `sys/time.rs` test suite to make sure we don't regress on this in the future. --- src/libstd/sys/windows/time.rs | 120 +++++++++++++++++++++------------ src/libstd/time.rs | 9 +++ 2 files changed, 87 insertions(+), 42 deletions(-) diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index 8e8e9195cf4..b0cdd0a7f3b 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -1,10 +1,7 @@ use cmp::Ordering; use fmt; use mem; -use sync::Once; use sys::c; -use sys::cvt; -use sys_common::mul_div_u64; use time::Duration; use convert::TryInto; use core::hash::{Hash, Hasher}; @@ -14,7 +11,7 @@ const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100; #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] pub struct Instant { - t: c::LARGE_INTEGER, + t: u64, } #[derive(Copy, Clone)] @@ -33,11 +30,12 @@ pub const UNIX_EPOCH: SystemTime = SystemTime { impl Instant { pub fn now() -> Instant { - let mut t = Instant { t: 0 }; - cvt(unsafe { - c::QueryPerformanceCounter(&mut t.t) - }).unwrap(); - t + // High precision timing on windows operates in "Performance Counter" + // units, as returned by the WINAPI QueryPerformanceCounter function. + // These relate to seconds by a factor of QueryPerformanceFrequency. + // In order to keep unit conversions out of normal interval math, we + // measure in QPC units and immediately convert to nanoseconds. + perf_counter::PerformanceCounterInstant::now().into() } pub fn actually_monotonic() -> bool { @@ -49,43 +47,36 @@ impl Instant { } pub fn sub_instant(&self, other: &Instant) -> Duration { - // Values which are +- 1 need to be considered as basically the same - // units in time due to various measurement oddities, according to - // Windows [1] - // - // [1]: - // https://msdn.microsoft.com/en-us/library/windows/desktop - // /dn553408%28v=vs.85%29.aspx#guidance - if other.t > self.t && other.t - self.t == 1 { + // On windows there's a threshold below which we consider two timestamps + // equivalent due to measurement error. For more details + doc link, + // check the docs on epsilon_nanos. + let epsilon_ns = + perf_counter::PerformanceCounterInstant::epsilon_nanos() as u64; + if other.t > self.t && other.t - self.t <= epsilon_ns { return Duration::new(0, 0) } - let diff = (self.t as u64).checked_sub(other.t as u64) - .expect("specified instant was later than \ - self"); - let nanos = mul_div_u64(diff, NANOS_PER_SEC, frequency() as u64); - Duration::new(nanos / NANOS_PER_SEC, (nanos % NANOS_PER_SEC) as u32) + let diff = (self.t).checked_sub(other.t) + .expect("specified instant was later than self"); + Duration::new(diff / NANOS_PER_SEC, (diff % NANOS_PER_SEC) as u32) } pub fn checked_add_duration(&self, other: &Duration) -> Option { - let freq = frequency() as u64; - let t = other.as_secs() - .checked_mul(freq)? - .checked_add(mul_div_u64(other.subsec_nanos() as u64, freq, NANOS_PER_SEC))? + let sum = other.as_secs() + .checked_mul(NANOS_PER_SEC)? + .checked_add(other.subsec_nanos() as u64)? .checked_add(self.t as u64)?; Some(Instant { - t: t as c::LARGE_INTEGER, + t: sum, }) } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - let freq = frequency() as u64; - let t = other.as_secs().checked_mul(freq).and_then(|i| { - (self.t as u64).checked_sub(i) - }).and_then(|i| { - i.checked_sub(mul_div_u64(other.subsec_nanos() as u64, freq, NANOS_PER_SEC)) - })?; + let other_ns = other.as_secs() + .checked_mul(NANOS_PER_SEC)? + .checked_add(other.subsec_nanos() as u64)?; + let difference = self.t.checked_sub(other_ns)?; Some(Instant { - t: t as c::LARGE_INTEGER, + t: difference, }) } } @@ -186,14 +177,59 @@ fn intervals2dur(intervals: u64) -> Duration { ((intervals % INTERVALS_PER_SEC) * 100) as u32) } -fn frequency() -> c::LARGE_INTEGER { - static mut FREQUENCY: c::LARGE_INTEGER = 0; - static ONCE: Once = Once::new(); +mod perf_counter { + use super::{NANOS_PER_SEC}; + use sync::Once; + use sys_common::mul_div_u64; + use sys::c; + use sys::cvt; - unsafe { - ONCE.call_once(|| { - cvt(c::QueryPerformanceFrequency(&mut FREQUENCY)).unwrap(); - }); - FREQUENCY + pub struct PerformanceCounterInstant { + ts: c::LARGE_INTEGER + } + impl PerformanceCounterInstant { + pub fn now() -> Self { + Self { + ts: query() + } + } + + // Per microsoft docs, the margin of error for cross-thread time comparisons + // using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency(). + // Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo + // /acquiring-high-resolution-time-stamps + pub fn epsilon_nanos() -> u32 { + let epsilon = NANOS_PER_SEC / (frequency() as u64); + // As noted elsewhere, subsecond nanos always fit in a u32 + epsilon as u32 + } + } + impl From for super::Instant { + fn from(other: PerformanceCounterInstant) -> Self { + let freq = frequency() as u64; + Self { + t: mul_div_u64(other.ts as u64, NANOS_PER_SEC, freq) + } + } + } + + fn frequency() -> c::LARGE_INTEGER { + static mut FREQUENCY: c::LARGE_INTEGER = 0; + static ONCE: Once = Once::new(); + + unsafe { + ONCE.call_once(|| { + cvt(c::QueryPerformanceFrequency(&mut FREQUENCY)).unwrap(); + }); + FREQUENCY + } + } + + fn query() -> c::LARGE_INTEGER { + let mut qpc_value: c::LARGE_INTEGER = 0; + cvt(unsafe { + c::QueryPerformanceCounter(&mut qpc_value) + }).unwrap(); + qpc_value } } diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 507ea395c6c..23924559fcc 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -610,6 +610,15 @@ mod tests { assert_eq!(a + year, a.checked_add(year).unwrap()); } + #[test] + fn instant_math_is_associative() { + let now = Instant::now(); + let offset = Duration::from_millis(5); + // Changing the order of instant math shouldn't change the results, + // especially when the expression reduces to X + identity. + assert_eq!((now + offset) - now, (now - now) + offset); + } + #[test] #[should_panic] fn instant_duration_panic() { From 0f566ec5751aebaf2261c267f1ff172ec43ab2e0 Mon Sep 17 00:00:00 2001 From: Alex Berghage Date: Sun, 20 Jan 2019 18:05:09 -0700 Subject: [PATCH 10/18] Move Instant backing type to Duration Per review comments, this commit switches out the backing type for Instant on windows to a Duration. Tests all pass, and the code's a lot simpler (plus it should be portable now, with the exception of the QueryPerformanceWhatever functions). --- src/libstd/sys/windows/time.rs | 36 +++++++++++++--------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index b0cdd0a7f3b..113affb737e 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -11,7 +11,7 @@ const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100; #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] pub struct Instant { - t: u64, + t: Duration, } #[derive(Copy, Clone)] @@ -49,34 +49,25 @@ impl Instant { pub fn sub_instant(&self, other: &Instant) -> Duration { // On windows there's a threshold below which we consider two timestamps // equivalent due to measurement error. For more details + doc link, - // check the docs on epsilon_nanos. - let epsilon_ns = - perf_counter::PerformanceCounterInstant::epsilon_nanos() as u64; - if other.t > self.t && other.t - self.t <= epsilon_ns { + // check the docs on epsilon. + let epsilon = + perf_counter::PerformanceCounterInstant::epsilon(); + if other.t > self.t && other.t - self.t <= epsilon { return Duration::new(0, 0) } - let diff = (self.t).checked_sub(other.t) - .expect("specified instant was later than self"); - Duration::new(diff / NANOS_PER_SEC, (diff % NANOS_PER_SEC) as u32) + self.t.checked_sub(other.t) + .expect("specified instant was later than self") } pub fn checked_add_duration(&self, other: &Duration) -> Option { - let sum = other.as_secs() - .checked_mul(NANOS_PER_SEC)? - .checked_add(other.subsec_nanos() as u64)? - .checked_add(self.t as u64)?; Some(Instant { - t: sum, + t: self.t.checked_add(*other)? }) } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - let other_ns = other.as_secs() - .checked_mul(NANOS_PER_SEC)? - .checked_add(other.subsec_nanos() as u64)?; - let difference = self.t.checked_sub(other_ns)?; Some(Instant { - t: difference, + t: self.t.checked_sub(*other)? }) } } @@ -183,6 +174,7 @@ mod perf_counter { use sys_common::mul_div_u64; use sys::c; use sys::cvt; + use time::Duration; pub struct PerformanceCounterInstant { ts: c::LARGE_INTEGER @@ -198,17 +190,17 @@ mod perf_counter { // using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency(). // Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo // /acquiring-high-resolution-time-stamps - pub fn epsilon_nanos() -> u32 { + pub fn epsilon() -> Duration { let epsilon = NANOS_PER_SEC / (frequency() as u64); - // As noted elsewhere, subsecond nanos always fit in a u32 - epsilon as u32 + Duration::from_nanos(epsilon) } } impl From for super::Instant { fn from(other: PerformanceCounterInstant) -> Self { let freq = frequency() as u64; + let instant_nsec = mul_div_u64(other.ts as u64, NANOS_PER_SEC, freq); Self { - t: mul_div_u64(other.ts as u64, NANOS_PER_SEC, freq) + t: Duration::from_nanos(instant_nsec) } } } From 41be93c2f694b6b8c493b255d2e77c0703135b14 Mon Sep 17 00:00:00 2001 From: Alex Berghage Date: Tue, 22 Jan 2019 19:31:55 -0700 Subject: [PATCH 11/18] Rebase and fix new instantiation fn --- src/libstd/sys/windows/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index 113affb737e..fe3766f25c8 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -43,7 +43,7 @@ impl Instant { } pub const fn zero() -> Instant { - Instant { t: 0 } + Instant { t: Duration::from_secs(0) } } pub fn sub_instant(&self, other: &Instant) -> Duration { From d4ee556126edb0d22b8774a4d85a842c443adf60 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 23 Jan 2019 11:34:02 +0100 Subject: [PATCH 12/18] Follow naming scheme for "frame" methods --- src/librustc_mir/interpret/eval_context.rs | 8 ++++---- src/librustc_mir/interpret/operand.rs | 2 +- src/librustc_mir/interpret/step.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index b2db0fea3d0..132b753eb9a 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -282,12 +282,12 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } } - pub fn monomorphize_in_frame + Subst<'tcx>>( + pub(super) fn monomorphize + Subst<'tcx>>( &self, t: T, ) -> EvalResult<'tcx, T> { match self.stack.last() { - Some(frame) => Ok(self.monomorphize(t, frame.instance.substs)), + Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)), None => if t.needs_subst() { err!(TooGeneric).into() } else { @@ -296,7 +296,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } } - pub fn monomorphize + Subst<'tcx>>( + fn monomorphize_with_substs + Subst<'tcx>>( &self, t: T, substs: &'tcx Substs<'tcx> @@ -315,7 +315,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc let cell = &frame.local_layouts[local]; if cell.get().is_none() { let local_ty = frame.mir.local_decls[local].ty; - let local_ty = self.monomorphize(local_ty, frame.instance.substs); + let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs); let layout = self.layout_of(local_ty)?; cell.set(Some(layout)); } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 8995d091aaa..8741571342f 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -508,7 +508,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> Constant(ref constant) => { let layout = from_known_layout(layout, || { - let ty = self.monomorphize_in_frame(mir_op.ty(self.mir(), *self.tcx))?; + let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx))?; self.layout_of(ty) })?; let op = self.const_value_to_op(*constant.literal)?; diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index f1b4e6a5055..25f3e4c1f77 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -248,7 +248,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } NullaryOp(mir::NullOp::SizeOf, ty) => { - let ty = self.monomorphize_in_frame(ty)?; + let ty = self.monomorphize(ty)?; let layout = self.layout_of(ty)?; assert!(!layout.is_unsized(), "SizeOf nullary MIR operator called for unsized type"); @@ -260,7 +260,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } Cast(kind, ref operand, cast_ty) => { - debug_assert_eq!(self.monomorphize_in_frame(cast_ty)?, dest.layout.ty); + debug_assert_eq!(self.monomorphize(cast_ty)?, dest.layout.ty); let src = self.eval_operand(operand, None)?; self.cast(src, kind, dest)?; } From 8db59d49f3364c26f424518d99631ca008b9b4f5 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Wed, 23 Jan 2019 18:40:40 +0530 Subject: [PATCH 13/18] Add os::fortanix_sgx::ffi module --- src/libstd/os/fortanix_sgx/mod.rs | 2 +- src/libstd/sys/sgx/ext/ffi.rs | 109 ++++++++++++++++++++++++++++++ src/libstd/sys/sgx/ext/mod.rs | 1 + 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 src/libstd/sys/sgx/ext/ffi.rs diff --git a/src/libstd/os/fortanix_sgx/mod.rs b/src/libstd/os/fortanix_sgx/mod.rs index 47c7b5dcbe6..810965fc1b8 100644 --- a/src/libstd/os/fortanix_sgx/mod.rs +++ b/src/libstd/os/fortanix_sgx/mod.rs @@ -56,4 +56,4 @@ pub mod mem { pub use sys::abi::mem::*; } -pub use sys::ext::{io, arch}; +pub use sys::ext::{io, arch, ffi}; diff --git a/src/libstd/sys/sgx/ext/ffi.rs b/src/libstd/sys/sgx/ext/ffi.rs new file mode 100644 index 00000000000..7b0ffea49ae --- /dev/null +++ b/src/libstd/sys/sgx/ext/ffi.rs @@ -0,0 +1,109 @@ +//! SGX-specific extension to the primitives in the `std::ffi` module + +#![unstable(feature = "sgx_platform", issue = "56975")] + +use ffi::{OsStr, OsString}; +use mem; +use sys::os_str::Buf; +use sys_common::{FromInner, IntoInner, AsInner}; + +/// SGX-specific extensions to [`OsString`]. +/// +/// [`OsString`]: ../../../../std/ffi/struct.OsString.html +#[unstable(feature = "sgx_platform", issue = "56975")] +pub trait OsStringExt { + /// Creates an [`OsString`] from a byte vector. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// use std::os::unix::ffi::OsStringExt; + /// + /// let bytes = b"foo".to_vec(); + /// let os_string = OsString::from_vec(bytes); + /// assert_eq!(os_string.to_str(), Some("foo")); + /// ``` + /// + /// [`OsString`]: ../../../ffi/struct.OsString.html + #[unstable(feature = "sgx_platform", issue = "56975")] + fn from_vec(vec: Vec) -> Self; + + /// Yields the underlying byte vector of this [`OsString`]. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// use std::os::unix::ffi::OsStringExt; + /// + /// let mut os_string = OsString::new(); + /// os_string.push("foo"); + /// let bytes = os_string.into_vec(); + /// assert_eq!(bytes, b"foo"); + /// ``` + /// + /// [`OsString`]: ../../../ffi/struct.OsString.html + #[unstable(feature = "sgx_platform", issue = "56975")] + fn into_vec(self) -> Vec; +} + +#[unstable(feature = "sgx_platform", issue = "56975")] +impl OsStringExt for OsString { + fn from_vec(vec: Vec) -> OsString { + FromInner::from_inner(Buf { inner: vec }) + } + fn into_vec(self) -> Vec { + self.into_inner().inner + } +} + +/// SGX-specific extensions to [`OsStr`]. +/// +/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html +#[unstable(feature = "sgx_platform", issue = "56975")] +pub trait OsStrExt { + #[unstable(feature = "sgx_platform", issue = "56975")] + /// Creates an [`OsStr`] from a byte slice. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// use std::os::unix::ffi::OsStrExt; + /// + /// let bytes = b"foo"; + /// let os_str = OsStr::from_bytes(bytes); + /// assert_eq!(os_str.to_str(), Some("foo")); + /// ``` + /// + /// [`OsStr`]: ../../../ffi/struct.OsStr.html + fn from_bytes(slice: &[u8]) -> &Self; + + /// Gets the underlying byte view of the [`OsStr`] slice. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// use std::os::unix::ffi::OsStrExt; + /// + /// let mut os_str = OsStr::new("foo"); + /// let bytes = os_str.as_bytes(); + /// assert_eq!(bytes, b"foo"); + /// ``` + /// + /// [`OsStr`]: ../../../ffi/struct.OsStr.html + #[unstable(feature = "sgx_platform", issue = "56975")] + fn as_bytes(&self) -> &[u8]; +} + +#[unstable(feature = "sgx_platform", issue = "56975")] +impl OsStrExt for OsStr { + fn from_bytes(slice: &[u8]) -> &OsStr { + unsafe { mem::transmute(slice) } + } + fn as_bytes(&self) -> &[u8] { + &self.as_inner().inner + } +} diff --git a/src/libstd/sys/sgx/ext/mod.rs b/src/libstd/sys/sgx/ext/mod.rs index 5489f6f5694..51b2659da83 100644 --- a/src/libstd/sys/sgx/ext/mod.rs +++ b/src/libstd/sys/sgx/ext/mod.rs @@ -2,3 +2,4 @@ pub mod arch; pub mod io; +pub mod ffi; From 0db2587a1c0f6492d595cd86b036789161adab31 Mon Sep 17 00:00:00 2001 From: Sergey Pepyakin Date: Wed, 23 Jan 2019 15:05:39 +0100 Subject: [PATCH 14/18] Don't export table by default in wasm --- src/librustc_codegen_ssa/back/linker.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index 06d4f940436..ad61f8f01d8 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -911,9 +911,6 @@ impl<'a> WasmLd<'a> { // For now we just never have an entry symbol cmd.arg("--no-entry"); - // Make the default table accessible - cmd.arg("--export-table"); - // Rust code should never have warnings, and warnings are often // indicative of bugs, let's prevent them. cmd.arg("--fatal-warnings"); From 31cd65f7120e209f7b29b205393156763409547a Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 23 Jan 2019 17:39:26 -0500 Subject: [PATCH 15/18] Fix std::future::from_generator documentation This function takes a generator and wraps it in a future, not vice-versa. --- src/libstd/future.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/future.rs b/src/libstd/future.rs index a7b9895177f..22900c3067b 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -11,7 +11,7 @@ use core::ops::{Drop, Generator, GeneratorState}; #[doc(inline)] pub use core::future::*; -/// Wrap a future in a generator. +/// Wrap a generator in a future. /// /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). From f14d007ee4f4b69cdb3880db49608b432bea8352 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 23 Jan 2019 16:42:23 +0100 Subject: [PATCH 16/18] Add suggestion for incorrect field syntax. This commit adds a suggestion when a `=` character is used when specifying the value of a field in a struct constructor incorrectly instead of a `:` character. --- src/libsyntax/parse/parser.rs | 18 ++++++++++++- src/test/ui/issues/issue-57684.fixed | 37 +++++++++++++++++++++++++++ src/test/ui/issues/issue-57684.rs | 37 +++++++++++++++++++++++++++ src/test/ui/issues/issue-57684.stderr | 18 +++++++++++++ 4 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-57684.fixed create mode 100644 src/test/ui/issues/issue-57684.rs create mode 100644 src/test/ui/issues/issue-57684.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 09ea0995253..b9c602550e3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2263,8 +2263,24 @@ impl<'a> Parser<'a> { let lo = self.span; // Check if a colon exists one ahead. This means we're parsing a fieldname. - let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) { + let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| { + t == &token::Colon || t == &token::Eq + }) { let fieldname = self.parse_field_name()?; + + // Check for an equals token. This means the source incorrectly attempts to + // initialize a field with an eq rather than a colon. + if self.token == token::Eq { + self.diagnostic() + .struct_span_err(self.span, "expected `:`, found `=`") + .span_suggestion_with_applicability( + fieldname.span.shrink_to_hi().to(self.span), + "replace equals symbol with a colon", + ":".to_string(), + Applicability::MachineApplicable, + ) + .emit(); + } self.bump(); // `:` (fieldname, self.parse_expr()?, false) } else { diff --git a/src/test/ui/issues/issue-57684.fixed b/src/test/ui/issues/issue-57684.fixed new file mode 100644 index 00000000000..4a432206d51 --- /dev/null +++ b/src/test/ui/issues/issue-57684.fixed @@ -0,0 +1,37 @@ +// run-rustfix + +#![allow(warnings)] + +// This test checks that the following error is emitted when a `=` character is used to initialize +// a struct field when a `:` is expected. +// +// ``` +// error: struct fields are initialized with a colon +// --> $DIR/issue-57684.rs:12:20 +// | +// LL | let _ = X { f1 = 5 }; +// | ^ help: replace equals symbol with a colon: `:` +// ``` + +struct X { + f1: i32, +} + +struct Y { + f1: i32, + f2: i32, + f3: i32, +} + +fn main() { + let _ = X { f1: 5 }; + //~^ ERROR expected `:`, found `=` + + let f3 = 3; + let _ = Y { + f1: 5, + //~^ ERROR expected `:`, found `=` + f2: 4, + f3, + }; +} diff --git a/src/test/ui/issues/issue-57684.rs b/src/test/ui/issues/issue-57684.rs new file mode 100644 index 00000000000..7a62785e32f --- /dev/null +++ b/src/test/ui/issues/issue-57684.rs @@ -0,0 +1,37 @@ +// run-rustfix + +#![allow(warnings)] + +// This test checks that the following error is emitted when a `=` character is used to initialize +// a struct field when a `:` is expected. +// +// ``` +// error: struct fields are initialized with a colon +// --> $DIR/issue-57684.rs:12:20 +// | +// LL | let _ = X { f1 = 5 }; +// | ^ help: replace equals symbol with a colon: `:` +// ``` + +struct X { + f1: i32, +} + +struct Y { + f1: i32, + f2: i32, + f3: i32, +} + +fn main() { + let _ = X { f1 = 5 }; + //~^ ERROR expected `:`, found `=` + + let f3 = 3; + let _ = Y { + f1 = 5, + //~^ ERROR expected `:`, found `=` + f2: 4, + f3, + }; +} diff --git a/src/test/ui/issues/issue-57684.stderr b/src/test/ui/issues/issue-57684.stderr new file mode 100644 index 00000000000..514bbffde6b --- /dev/null +++ b/src/test/ui/issues/issue-57684.stderr @@ -0,0 +1,18 @@ +error: expected `:`, found `=` + --> $DIR/issue-57684.rs:27:20 + | +LL | let _ = X { f1 = 5 }; + | -^ + | | + | help: replace equals symbol with a colon: `:` + +error: expected `:`, found `=` + --> $DIR/issue-57684.rs:32:12 + | +LL | f1 = 5, + | -^ + | | + | help: replace equals symbol with a colon: `:` + +error: aborting due to 2 previous errors + From 14ce5364de3bf7d2da59fbe52360459c0f2c6ada Mon Sep 17 00:00:00 2001 From: Alex Berghage Date: Wed, 23 Jan 2019 21:36:38 -0700 Subject: [PATCH 17/18] Add a comment on the meaning of Instant t: Duration --- src/libstd/sys/windows/time.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index fe3766f25c8..8a8159af2f1 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -11,6 +11,8 @@ const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100; #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] pub struct Instant { + // This duration is relative to an arbitrary microsecond epoch + // from the winapi QueryPerformanceCounter function. t: Duration, } From b12aa4fb6e86be9c031cfc4e52ab934ba49897eb Mon Sep 17 00:00:00 2001 From: Jewoo Lee Date: Thu, 24 Jan 2019 13:38:46 +0900 Subject: [PATCH 18/18] Stabilize no_panic_pow --- src/libcore/num/mod.rs | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 41caa1788fb..423b800d585 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -847,13 +847,12 @@ overflow occurred. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64)); assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn checked_pow(self, mut exp: u32) -> Option { let mut base = self; @@ -966,7 +965,6 @@ saturating at the numeric bounds instead of overflowing. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "use std::", stringify!($SelfT), "; assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64); @@ -974,7 +972,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn saturating_pow(self, exp: u32) -> Self { match self.checked_pow(exp) { @@ -1297,13 +1295,12 @@ wrapping around at the boundary of the type. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81); assert_eq!(3i8.wrapping_pow(5), -13); assert_eq!(3i8.wrapping_pow(6), -39);", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn wrapping_pow(self, mut exp: u32) -> Self { let mut base = self; @@ -1669,12 +1666,11 @@ whether an overflow happened. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false)); assert_eq!(3i8.overflowing_pow(5), (-13, true));", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { let mut base = self; @@ -2789,11 +2785,10 @@ overflow occurred. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32)); assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn checked_pow(self, mut exp: u32) -> Option { let mut base = self; @@ -2893,14 +2888,13 @@ saturating at the numeric bounds instead of overflowing. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "use std::", stringify!($SelfT), "; assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64); assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn saturating_pow(self, exp: u32) -> Self { match self.checked_pow(exp) { @@ -3178,11 +3172,10 @@ wrapping around at the boundary of the type. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243); assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn wrapping_pow(self, mut exp: u32) -> Self { let mut base = self; @@ -3497,11 +3490,10 @@ whether an overflow happened. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false)); assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { let mut base = self;