From 1dc4e417fa2a73d5ffa24428df6b7d4dbbf41f4a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 18 Jan 2019 11:40:53 +0100 Subject: [PATCH 01/16] Manually inline a function that was only used once --- src/librustc/ty/mod.rs | 10 ---------- src/librustc_mir/interpret/eval_context.rs | 10 +++++----- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 26b4735d926a5..2fdcb2681db0b 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2946,16 +2946,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Given the DefId of an item, returns its MIR, borrowed immutably. - /// Returns None if there is no MIR for the DefId - pub fn maybe_optimized_mir(self, did: DefId) -> Option<&'gcx Mir<'gcx>> { - if self.is_mir_available(did) { - Some(self.optimized_mir(did)) - } else { - None - } - } - /// Get the attributes of a definition. pub fn get_attrs(self, did: DefId) -> Attributes<'gcx> { if let Some(id) = self.hir().as_local_node_id(did) { diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 19362b6cfdb1c..90f7ba761ea1d 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -265,11 +265,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } trace!("load mir {:?}", instance); match instance { - ty::InstanceDef::Item(def_id) => { - self.tcx.maybe_optimized_mir(def_id).ok_or_else(|| - EvalErrorKind::NoMirFor(self.tcx.item_path_str(def_id)).into() - ) - } + ty::InstanceDef::Item(def_id) => if self.tcx.is_mir_available(did) { + Ok(self.tcx.optimized_mir(did)) + } else { + err!(NoMirFor(self.tcx.item_path_str(def_id))) + }, _ => Ok(self.tcx.instance_mir(instance)), } } From efda6816bd29beea2702c7c3f76a252a405e60ae Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 18 Jan 2019 13:31:05 +0100 Subject: [PATCH 02/16] Allow evaluating trivial drop glue in constants --- src/librustc_mir/const_eval.rs | 29 ++++++++++++++++------------- src/test/ui/consts/drop_none.rs | 13 +++++++++++++ 2 files changed, 29 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/consts/drop_none.rs diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index f5f4048167938..f6ecf7c9436a2 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -391,19 +391,22 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { debug!("eval_fn_call: {:?}", instance); - // Execution might have wandered off into other crates, so we cannot to a stability- - // sensitive check here. But we can at least rule out functions that are not const - // at all. - if !ecx.tcx.is_const_fn_raw(instance.def_id()) { - // Some functions we support even if they are non-const -- but avoid testing - // that for const fn! We certainly do *not* want to actually call the fn - // though, so be sure we return here. - return if ecx.hook_fn(instance, args, dest)? { - ecx.goto_block(ret)?; // fully evaluated and done - Ok(None) - } else { - err!(MachineError(format!("calling non-const function `{}`", instance))) - }; + // Only check non-glue functions + if let ty::InstanceDef::Item(def_id) = instance.def { + // Execution might have wandered off into other crates, so we cannot to a stability- + // sensitive check here. But we can at least rule out functions that are not const + // at all. + if !ecx.tcx.is_const_fn_raw(def_id) { + // Some functions we support even if they are non-const -- but avoid testing + // that for const fn! We certainly do *not* want to actually call the fn + // though, so be sure we return here. + return if ecx.hook_fn(instance, args, dest)? { + ecx.goto_block(ret)?; // fully evaluated and done + Ok(None) + } else { + err!(MachineError(format!("calling non-const function `{}`", instance))) + }; + } } // This is a const fn. Call it. Ok(Some(match ecx.load_mir(instance.def) { diff --git a/src/test/ui/consts/drop_none.rs b/src/test/ui/consts/drop_none.rs new file mode 100644 index 0000000000000..86a197ffb993e --- /dev/null +++ b/src/test/ui/consts/drop_none.rs @@ -0,0 +1,13 @@ +// compile-pass +#![allow(dead_code)] +struct A; +impl Drop for A { + fn drop(&mut self) {} +} + +const FOO: Option = None; + +const BAR: () = (FOO, ()).1; + + +fn main() {} From a59eabbc36d7b96bb9e42d9bc6691d28b62c4187 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 14 Jan 2019 17:54:00 +0100 Subject: [PATCH 03/16] 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 e6d6ef1d7a38b..56d4342e6e161 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 105856fecc729..25b0d1424ca47 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 188a112044298..9cc5c93de41d8 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 8991a90737c7e..cdaffe5d45673 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 03d6d3868c9f0..fba74514f044f 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 0000000000000..c785317778b3c --- /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/16] 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 190a381cf52a5..c3b71be8354da 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 b2d3328a73fe8..b2db0fea3d09a 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 b2648480f203c..8995d091aaab6 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 962e0b7a74201..f3a948a6ca3e7 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 2de8b3c1afdf3..f1b4e6a5055b6 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/16] 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 25b0d1424ca47..45c6c1b42496a 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 fba74514f044f..dc556a15cd855 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/16] 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 c785317778b3c..53c5782a4c70e 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 0000000000000..e6e04e2c46276 --- /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/16] 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 3d6096b07ce43..13ad05101e4b6 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/16] 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 d4d70d04f5b4e..1e396f1be0e04 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 d4ee556126edb0d22b8774a4d85a842c443adf60 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 23 Jan 2019 11:34:02 +0100 Subject: [PATCH 09/16] 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 b2db0fea3d09a..132b753eb9a62 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 8995d091aaab6..8741571342f83 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 f1b4e6a5055b6..25f3e4c1f771d 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 10/16] 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 47c7b5dcbe64a..810965fc1b85a 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 0000000000000..7b0ffea49ae7c --- /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 5489f6f56946e..51b2659da83e3 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 11/16] 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 06d4f940436da..ad61f8f01d8d4 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 b2dfd9680d9d59ce5dcc16118da1f3384ceb19ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 22 Dec 2018 18:59:03 +0100 Subject: [PATCH 12/16] Fix race condition when emitting stored diagnostics --- src/librustc/dep_graph/graph.rs | 84 ++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 21 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index a9e80ddf4ba2a..63857d6c9189a 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -1,4 +1,4 @@ -use errors::DiagnosticBuilder; +use errors::{Diagnostic, DiagnosticBuilder}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; @@ -9,6 +9,7 @@ use std::hash::Hash; use std::collections::hash_map::Entry; use ty::{self, TyCtxt}; use util::common::{ProfileQueriesMsg, profq_msg}; +use parking_lot::{Mutex, Condvar}; use ich::{StableHashingContext, StableHashingContextProvider, Fingerprint}; @@ -60,6 +61,12 @@ struct DepGraphData { colors: DepNodeColorMap, + /// A set of loaded diagnostics which has been emitted. + emitted_diagnostics: Mutex>, + + /// Used to wait for diagnostics to be emitted. + emitted_diagnostics_cond_var: Condvar, + /// When we load, there may be `.o` files, cached mir, or other such /// things available to us. If we find that they are not dirty, we /// load the path to the file storing those work-products here into @@ -83,6 +90,8 @@ impl DepGraph { previous_work_products: prev_work_products, dep_node_debug: Default::default(), current: Lock::new(CurrentDepGraph::new(prev_graph_node_count)), + emitted_diagnostics: Default::default(), + emitted_diagnostics_cond_var: Condvar::new(), previous: prev_graph, colors: DepNodeColorMap::new(prev_graph_node_count), loaded_from_cache: Default::default(), @@ -718,28 +727,18 @@ impl DepGraph { }; // ... emitting any stored diagnostic ... - if did_allocation { - // Only the thread which did the allocation emits the error messages - - // FIXME: Ensure that these are printed before returning for all threads. - // Currently threads where did_allocation = false can continue on - // and emit other diagnostics before these diagnostics are emitted. - // Such diagnostics should be emitted after these. - // See https://github.com/rust-lang/rust/issues/48685 - let diagnostics = tcx.queries.on_disk_cache - .load_diagnostics(tcx, prev_dep_node_index); - if diagnostics.len() > 0 { - let handle = tcx.sess.diagnostic(); + let diagnostics = tcx.queries.on_disk_cache + .load_diagnostics(tcx, prev_dep_node_index); - // Promote the previous diagnostics to the current session. - tcx.queries.on_disk_cache - .store_diagnostics(dep_node_index, diagnostics.clone().into()); - - for diagnostic in diagnostics { - DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit(); - } - } + if unlikely!(diagnostics.len() > 0) { + self.emit_diagnostics( + tcx, + data, + dep_node_index, + did_allocation, + diagnostics + ); } // ... and finally storing a "Green" entry in the color map. @@ -755,6 +754,49 @@ impl DepGraph { Some(dep_node_index) } + /// Atomically emits some loaded diagnotics assuming that this only gets called with + /// did_allocation set to true on one thread + #[cold] + #[inline(never)] + fn emit_diagnostics<'tcx>( + &self, + tcx: TyCtxt<'_, 'tcx, 'tcx>, + data: &DepGraphData, + dep_node_index: DepNodeIndex, + did_allocation: bool, + diagnostics: Vec, + ) { + if did_allocation || !cfg!(parallel_queries) { + // Only the thread which did the allocation emits the error messages + let handle = tcx.sess.diagnostic(); + + // Promote the previous diagnostics to the current session. + tcx.queries.on_disk_cache + .store_diagnostics(dep_node_index, diagnostics.clone().into()); + + for diagnostic in diagnostics { + DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit(); + } + + #[cfg(parallel_queries)] + { + // Mark the diagnostics and emitted and wake up waiters + data.emitted_diagnostics.lock().insert(dep_node_index); + data.emitted_diagnostics_cond_var.notify_all(); + } + } else { + // The other threads will wait for the diagnostics to be emitted + + let mut emitted_diagnostics = data.emitted_diagnostics.lock(); + loop { + if emitted_diagnostics.contains(&dep_node_index) { + break; + } + data.emitted_diagnostics_cond_var.wait(&mut emitted_diagnostics); + } + } + } + // Returns true if the given node has been marked as green during the // current compilation session. Used in various assertions pub fn is_green(&self, dep_node: &DepNode) -> bool { From 39aa89bab13119fc003748f8ca5ffec9233b13ba Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 23 Jan 2019 16:21:33 +0100 Subject: [PATCH 13/16] Add a compile-fail test for `Drop` in constants in the presence of `Option`s --- src/test/ui/static/static-drop-scope.rs | 8 ++++++++ src/test/ui/static/static-drop-scope.stderr | 14 +++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/test/ui/static/static-drop-scope.rs b/src/test/ui/static/static-drop-scope.rs index a11a9f020e0dc..e5a9f2a405644 100644 --- a/src/test/ui/static/static-drop-scope.rs +++ b/src/test/ui/static/static-drop-scope.rs @@ -28,4 +28,12 @@ const fn const_drop2(x: T) { //~^ ERROR destructors cannot be evaluated at compile-time } +const EARLY_DROP_C_OPTION: i32 = (Some(WithDtor), 0).1; +//~^ ERROR destructors cannot be evaluated at compile-time + +const HELPER: Option = Some(WithDtor); + +const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1; +//~^ ERROR destructors cannot be evaluated at compile-time + fn main () {} diff --git a/src/test/ui/static/static-drop-scope.stderr b/src/test/ui/static/static-drop-scope.stderr index 89b31d95a2a4e..3e3032eb4fb60 100644 --- a/src/test/ui/static/static-drop-scope.stderr +++ b/src/test/ui/static/static-drop-scope.stderr @@ -54,7 +54,19 @@ error[E0493]: destructors cannot be evaluated at compile-time LL | (x, ()).1 | ^^^^^^^ constant functions cannot evaluate destructors -error: aborting due to 8 previous errors +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:31:34 + | +LL | const EARLY_DROP_C_OPTION: i32 = (Some(WithDtor), 0).1; + | ^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:36:43 + | +LL | const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1; + | ^^^^^^^^^^^ constants cannot evaluate destructors + +error: aborting due to 10 previous errors Some errors occurred: E0493, E0597. For more information about an error, try `rustc --explain E0493`. From 31cd65f7120e209f7b29b205393156763409547a Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 23 Jan 2019 17:39:26 -0500 Subject: [PATCH 14/16] 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 a7b9895177fe5..22900c3067b11 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 15/16] 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 09ea099525326..b9c602550e333 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 0000000000000..4a432206d51e1 --- /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 0000000000000..7a62785e32f1c --- /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 0000000000000..514bbffde6b1e --- /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 b12aa4fb6e86be9c031cfc4e52ab934ba49897eb Mon Sep 17 00:00:00 2001 From: Jewoo Lee Date: Thu, 24 Jan 2019 13:38:46 +0900 Subject: [PATCH 16/16] 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 41caa1788fbb8..423b800d5852f 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;