From 368d56010ae91a8b136c9eea5821ff3e5a7b79d3 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 12 Apr 2017 19:04:57 -0400 Subject: [PATCH 1/5] Rename compiler_barrier to compiler_fence This addresses concerns raised following the merge of #41092. Specifically: > The naming of these seems surprising: the multithreaded functions (and > both the single and multithreaded intrinsics themselves) are fences, > but this is a barrier. It's not incorrect, but the latter is both > inconsistent with the existing functions and slightly confusing with > another type in std (e.g., `Barrier`). `compiler_fence` carries the same semantic implication that this is a compiler-only operation, while being more in line with the fence/barrier concepts already in use in `std`. --- src/doc/unstable-book/src/SUMMARY.md | 2 +- ...ompiler-barriers.md => compiler-fences.md} | 20 +++++++++---------- src/libcore/sync/atomic.rs | 12 +++++------ 3 files changed, 17 insertions(+), 17 deletions(-) rename src/doc/unstable-book/src/{compiler-barriers.md => compiler-fences.md} (86%) diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 54e602a81db73..b0cb444beaf7d 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -38,7 +38,7 @@ - [collections](collections.md) - [collections_range](collections-range.md) - [command_envs](command-envs.md) -- [compiler_barriers](compiler-barriers.md) +- [compiler_fences](compiler-fences.md) - [compiler_builtins](compiler-builtins.md) - [compiler_builtins_lib](compiler-builtins-lib.md) - [concat_idents](concat-idents.md) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-fences.md similarity index 86% rename from src/doc/unstable-book/src/compiler-barriers.md rename to src/doc/unstable-book/src/compiler-fences.md index 827447f0bd510..b1e36ab13d5ae 100644 --- a/src/doc/unstable-book/src/compiler-barriers.md +++ b/src/doc/unstable-book/src/compiler-fences.md @@ -1,4 +1,4 @@ -# `compiler_barriers` +# `compiler_fences` The tracking issue for this feature is: [#41091] @@ -6,7 +6,7 @@ The tracking issue for this feature is: [#41091] ------------------------ -The `compiler_barriers` feature exposes the `compiler_barrier` function +The `compiler_fences` feature exposes the `compiler_fence` function in `std::sync::atomic`. This function is conceptually similar to C++'s `atomic_signal_fence`, which can currently only be accessed in nightly Rust using the `atomic_singlethreadfence_*` instrinsic functions in @@ -17,18 +17,18 @@ Rust using the `atomic_singlethreadfence_*` instrinsic functions in unsafe { asm!("" ::: "memory" : "volatile") }; ``` -A `compiler_barrier` restricts the kinds of memory re-ordering the +A `compiler_fence` restricts the kinds of memory re-ordering the compiler is allowed to do. Specifically, depending on the given ordering semantics, the compiler may be disallowed from moving reads or writes from before or after the call to the other side of the call to -`compiler_barrier`. Note that it does **not** prevent the *hardware* +`compiler_fence`. Note that it does **not** prevent the *hardware* from doing such re-ordering. This is not a problem in a single-threaded, execution context, but when other threads may modify memory at the same time, stronger synchronization primitives are required. ## Examples -`compiler_barrier` is generally only useful for preventing a thread from +`compiler_fence` is generally only useful for preventing a thread from racing *with itself*. That is, if a given thread is executing one piece of code, and is then interrupted, and starts executing code elsewhere (while still in the same thread, and conceptually still on the same @@ -37,7 +37,7 @@ handler is registered. In more low-level code, such situations can also arise when handling interrupts, when implementing green threads with pre-emption, etc. -To give a straightforward example of when a `compiler_barrier` is +To give a straightforward example of when a `compiler_fence` is necessary, consider the following example: ```rust @@ -67,14 +67,14 @@ remember that the compiler is free to swap the stores to after `IS_READY` is updated, then the signal handler will see `IS_READY=1`, but `IMPORTANT_VARIABLE=0`. -Using a `compiler_barrier`, we can remedy this situation: +Using a `compiler_fence`, we can remedy this situation: ```rust -#![feature(compiler_barriers)] +#![feature(compiler_fences)] # use std::sync::atomic::{AtomicBool, AtomicUsize}; # use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; # use std::sync::atomic::Ordering; -use std::sync::atomic::compiler_barrier; +use std::sync::atomic::compiler_fence; static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT; static IS_READY: AtomicBool = ATOMIC_BOOL_INIT; @@ -82,7 +82,7 @@ static IS_READY: AtomicBool = ATOMIC_BOOL_INIT; fn main() { IMPORTANT_VARIABLE.store(42, Ordering::Relaxed); // prevent earlier writes from being moved beyond this point - compiler_barrier(Ordering::Release); + compiler_fence(Ordering::Release); IS_READY.store(true, Ordering::Relaxed); } diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 0c70524ead246..fad58deecd4c0 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1591,11 +1591,11 @@ pub fn fence(order: Ordering) { } -/// A compiler memory barrier. +/// A compiler memory fence. /// -/// `compiler_barrier` does not emit any machine code, but prevents the compiler from re-ordering +/// `compiler_fence` does not emit any machine code, but prevents the compiler from re-ordering /// memory operations across this point. Which reorderings are disallowed is dictated by the given -/// [`Ordering`]. Note that `compiler_barrier` does *not* introduce inter-thread memory +/// [`Ordering`]. Note that `compiler_fence` does *not* introduce inter-thread memory /// synchronization; for that, a [`fence`] is needed. /// /// The re-ordering prevented by the different ordering semantics are: @@ -1617,15 +1617,15 @@ pub fn fence(order: Ordering) { /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed #[inline] -#[unstable(feature = "compiler_barriers", issue = "41091")] -pub fn compiler_barrier(order: Ordering) { +#[unstable(feature = "compiler_fences", issue = "41091")] +pub fn compiler_fence(order: Ordering) { unsafe { match order { Acquire => intrinsics::atomic_singlethreadfence_acq(), Release => intrinsics::atomic_singlethreadfence_rel(), AcqRel => intrinsics::atomic_singlethreadfence_acqrel(), SeqCst => intrinsics::atomic_singlethreadfence(), - Relaxed => panic!("there is no such thing as a relaxed barrier"), + Relaxed => panic!("there is no such thing as a relaxed compiler fence"), __Nonexhaustive => panic!("invalid memory ordering"), } } From 8854164d0cda3c90f6c3c774d8acf891599e4da3 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 13 Apr 2017 16:40:03 +0300 Subject: [PATCH 2/5] rustc_const_eval: move ConstEvalErr to the rustc crate. --- src/Cargo.lock | 2 - src/librustc/diagnostics.rs | 19 +++ src/librustc/middle/const_val.rs | 164 ++++++++++++++++++++++- src/librustc/ty/maps.rs | 4 +- src/librustc_const_eval/Cargo.toml | 1 - src/librustc_const_eval/check_match.rs | 32 ++--- src/librustc_const_eval/diagnostics.rs | 19 --- src/librustc_const_eval/eval.rs | 176 +------------------------ src/librustc_const_eval/lib.rs | 1 - src/librustc_const_eval/pattern.rs | 4 +- src/librustc_metadata/decoder.rs | 3 +- src/librustc_mir/hair/cx/expr.rs | 4 +- src/librustc_mir/hair/cx/mod.rs | 17 ++- src/librustc_passes/consts.rs | 9 +- src/librustc_trans/Cargo.toml | 1 - src/librustc_trans/consts.rs | 2 +- src/librustc_trans/lib.rs | 1 - src/librustc_trans/mir/block.rs | 5 +- src/librustc_trans/mir/constant.rs | 7 +- src/librustc_trans/trans_item.rs | 5 +- src/librustc_typeck/collect.rs | 21 ++- 21 files changed, 242 insertions(+), 255 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 1fa256197ce52..c4b5366d4a324 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -503,7 +503,6 @@ name = "rustc_const_eval" version = "0.0.0" dependencies = [ "arena 0.0.0", - "graphviz 0.0.0", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", @@ -731,7 +730,6 @@ dependencies = [ "rustc 0.0.0", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", - "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 5a0fbf8efb707..8a391f9cde3a3 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -327,6 +327,25 @@ struct ListNode { This works because `Box` is a pointer, so its size is well-known. "##, +E0080: r##" +This error indicates that the compiler was unable to sensibly evaluate an +constant expression that had to be evaluated. Attempting to divide by 0 +or causing integer overflow are two ways to induce this error. For example: + +```compile_fail,E0080 +enum Enum { + X = (1 << 500), + Y = (1 / 0) +} +``` + +Ensure that the expressions given can be evaluated as the desired integer type. +See the FFI section of the Reference for more information about using a custom +integer type: + +https://doc.rust-lang.org/reference.html#ffi-attributes +"##, + E0106: r##" This error indicates that a lifetime is missing from a type. If it is an error inside a function signature, the problem may be with failing to adhere to the diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index d81f89827d938..9315f7f58081a 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -8,17 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::symbol::InternedString; -use syntax::ast; -use std::rc::Rc; +use self::ConstVal::*; +pub use rustc_const_math::ConstInt; + use hir::def_id::DefId; +use ty::TyCtxt; use ty::subst::Substs; use rustc_const_math::*; -use self::ConstVal::*; -pub use rustc_const_math::ConstInt; +use graphviz::IntoCow; +use errors::DiagnosticBuilder; +use syntax::symbol::InternedString; +use syntax::ast; +use syntax_pos::Span; +use std::borrow::Cow; use std::collections::BTreeMap; +use std::rc::Rc; + +pub type EvalResult<'tcx> = Result, ConstEvalErr<'tcx>>; #[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] pub enum ConstVal<'tcx> { @@ -61,3 +69,149 @@ impl<'tcx> ConstVal<'tcx> { } } } + +#[derive(Clone, Debug)] +pub struct ConstEvalErr<'tcx> { + pub span: Span, + pub kind: ErrKind<'tcx>, +} + +#[derive(Clone, Debug)] +pub enum ErrKind<'tcx> { + CannotCast, + MissingStructField, + NegateOn(ConstVal<'tcx>), + NotOn(ConstVal<'tcx>), + CallOn(ConstVal<'tcx>), + + NonConstPath, + UnimplementedConstVal(&'static str), + ExpectedConstTuple, + ExpectedConstStruct, + IndexedNonVec, + IndexNotUsize, + IndexOutOfBounds { len: u64, index: u64 }, + + MiscBinaryOp, + MiscCatchAll, + + IndexOpFeatureGated, + Math(ConstMathErr), + + ErroneousReferencedConstant(Box>), + + TypeckError +} + +impl<'tcx> From for ErrKind<'tcx> { + fn from(err: ConstMathErr) -> ErrKind<'tcx> { + match err { + ConstMathErr::UnsignedNegation => ErrKind::TypeckError, + _ => ErrKind::Math(err) + } + } +} + +#[derive(Clone, Debug)] +pub enum ConstEvalErrDescription<'a> { + Simple(Cow<'a, str>), +} + +impl<'a> ConstEvalErrDescription<'a> { + /// Return a one-line description of the error, for lints and such + pub fn into_oneline(self) -> Cow<'a, str> { + match self { + ConstEvalErrDescription::Simple(simple) => simple, + } + } +} + +impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { + pub fn description(&self) -> ConstEvalErrDescription { + use self::ErrKind::*; + use self::ConstEvalErrDescription::*; + + macro_rules! simple { + ($msg:expr) => ({ Simple($msg.into_cow()) }); + ($fmt:expr, $($arg:tt)+) => ({ + Simple(format!($fmt, $($arg)+).into_cow()) + }) + } + + match self.kind { + CannotCast => simple!("can't cast this type"), + NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), + NotOn(ref const_val) => simple!("not on {}", const_val.description()), + CallOn(ref const_val) => simple!("call on {}", const_val.description()), + + MissingStructField => simple!("nonexistent struct field"), + NonConstPath => simple!("non-constant path in constant expression"), + UnimplementedConstVal(what) => + simple!("unimplemented constant expression: {}", what), + ExpectedConstTuple => simple!("expected constant tuple"), + ExpectedConstStruct => simple!("expected constant struct"), + IndexedNonVec => simple!("indexing is only supported for arrays"), + IndexNotUsize => simple!("indices must be of type `usize`"), + IndexOutOfBounds { len, index } => { + simple!("index out of bounds: the len is {} but the index is {}", + len, index) + } + + MiscBinaryOp => simple!("bad operands for binary"), + MiscCatchAll => simple!("unsupported constant expr"), + IndexOpFeatureGated => simple!("the index operation on const values is unstable"), + Math(ref err) => Simple(err.description().into_cow()), + + ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), + + TypeckError => simple!("type-checking failed"), + } + } + + pub fn struct_error(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + primary_span: Span, + primary_kind: &str) + -> DiagnosticBuilder<'gcx> + { + let mut err = self; + while let &ConstEvalErr { + kind: ErrKind::ErroneousReferencedConstant(box ref i_err), .. + } = err { + err = i_err; + } + + let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error"); + err.note(tcx, primary_span, primary_kind, &mut diag); + diag + } + + pub fn note(&self, + _tcx: TyCtxt<'a, 'gcx, 'tcx>, + primary_span: Span, + primary_kind: &str, + diag: &mut DiagnosticBuilder) + { + match self.description() { + ConstEvalErrDescription::Simple(message) => { + diag.span_label(self.span, &message); + } + } + + if !primary_span.contains(self.span) { + diag.span_note(primary_span, + &format!("for {} here", primary_kind)); + } + } + + pub fn report(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + primary_span: Span, + primary_kind: &str) + { + if let ErrKind::TypeckError = self.kind { + return; + } + self.struct_error(tcx, primary_span, primary_kind).emit(); + } +} diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 868ccad8a3a90..e9eb5e97582bf 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -10,7 +10,7 @@ use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use middle::const_val::ConstVal; +use middle::const_val; use middle::privacy::AccessLevels; use mir; use session::CompileResult; @@ -443,7 +443,7 @@ define_maps! { <'tcx> /// Results of evaluating monomorphic constants embedded in /// other items, such as enum variant explicit discriminants. - pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result, ()>, + pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> const_val::EvalResult<'tcx>, /// Performs the privacy check and computes "access levels". pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc, diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 907410f74dca4..bbc6148082494 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -17,5 +17,4 @@ rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } -graphviz = { path = "../libgraphviz" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 9d55281d019d9..f1ab6a00aa2ef 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -14,8 +14,6 @@ use _match::WitnessPreference::*; use pattern::{Pattern, PatternContext, PatternError, PatternKind}; -use eval::report_const_eval_err; - use rustc::dep_graph::DepNode; use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; @@ -108,27 +106,29 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { - fn check_patterns(&self, has_guard: bool, pats: &[P]) { - check_legality_of_move_bindings(self, has_guard, pats); - for pat in pats { - check_legality_of_bindings_in_at_patterns(self, pat); - } - } - - fn report_inlining_errors(&self, patcx: PatternContext, pat_span: Span) { - for error in patcx.errors { - match error { +impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { + fn report_inlining_errors(&self, pat_span: Span) { + for error in &self.errors { + match *error { PatternError::StaticInPattern(span) => { span_err!(self.tcx.sess, span, E0158, "statics cannot be referenced in patterns"); } - PatternError::ConstEval(err) => { - report_const_eval_err(self.tcx, &err, pat_span, "pattern"); + PatternError::ConstEval(ref err) => { + err.report(self.tcx, pat_span, "pattern"); } } } } +} + +impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { + fn check_patterns(&self, has_guard: bool, pats: &[P]) { + check_legality_of_move_bindings(self, has_guard, pats); + for pat in pats { + check_legality_of_bindings_in_at_patterns(self, pat); + } + } fn check_match( &self, @@ -161,7 +161,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { let mut patcx = PatternContext::new(self.tcx, self.tables); let pattern = expand_pattern(cx, patcx.lower_pattern(&pat)); if !patcx.errors.is_empty() { - self.report_inlining_errors(patcx, pat.span); + patcx.report_inlining_errors(pat.span); have_errors = true; } (pattern, &**pat) diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index 60eef8dd3bc5f..04fc3e68c8ccd 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -557,25 +557,6 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases. See also https://github.com/rust-lang/rust/issues/14587 "##, -E0080: r##" -This error indicates that the compiler was unable to sensibly evaluate an -constant expression that had to be evaluated. Attempting to divide by 0 -or causing integer overflow are two ways to induce this error. For example: - -```compile_fail,E0080 -enum Enum { - X = (1 << 500), - Y = (1 / 0) -} -``` - -Ensure that the expressions given can be evaluated as the desired integer type. -See the FFI section of the Reference for more information about using a custom -integer type: - -https://doc.rust-lang.org/reference.html#ffi-attributes -"##, - } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 54f5cff16ed6c..b928bae620b6c 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -9,8 +9,8 @@ // except according to those terms. use rustc::middle::const_val::ConstVal::*; -use rustc::middle::const_val::ConstVal; -use self::ErrKind::*; +use rustc::middle::const_val::ErrKind::*; +use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind}; use rustc::hir::map as hir_map; use rustc::hir::map::blocks::FnLikeNode; @@ -24,16 +24,13 @@ use rustc::traits::Reveal; use rustc::util::common::ErrorReported; use rustc::util::nodemap::DefIdMap; -use graphviz::IntoCow; use syntax::ast; use rustc::hir::{self, Expr}; use syntax_pos::{Span, DUMMY_SP}; -use std::borrow::Cow; use std::cmp::Ordering; use rustc_const_math::*; -use rustc_errors::DiagnosticBuilder; macro_rules! signal { ($e:expr, $exn:expr) => { @@ -158,66 +155,6 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) } } -fn build_const_eval_err<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - err: &ConstEvalErr, - primary_span: Span, - primary_kind: &str) - -> DiagnosticBuilder<'tcx> -{ - let mut err = err; - while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err { - err = i_err; - } - - let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error"); - note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag); - diag -} - -pub fn report_const_eval_err<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - err: &ConstEvalErr, - primary_span: Span, - primary_kind: &str) -{ - if let TypeckError = err.kind { - return; - } - build_const_eval_err(tcx, err, primary_span, primary_kind).emit(); -} - -pub fn fatal_const_eval_err<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - err: &ConstEvalErr, - primary_span: Span, - primary_kind: &str) - -> ! -{ - report_const_eval_err(tcx, err, primary_span, primary_kind); - tcx.sess.abort_if_errors(); - unreachable!() -} - -pub fn note_const_eval_err<'a, 'tcx>( - _tcx: TyCtxt<'a, 'tcx, 'tcx>, - err: &ConstEvalErr, - primary_span: Span, - primary_kind: &str, - diag: &mut DiagnosticBuilder) -{ - match err.description() { - ConstEvalErrDescription::Simple(message) => { - diag.span_label(err.span, &message); - } - } - - if !primary_span.contains(err.span) { - diag.span_note(primary_span, - &format!("for {} here", primary_kind)); - } -} - pub struct ConstContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>, @@ -251,107 +188,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { } } -#[derive(Clone, Debug)] -pub struct ConstEvalErr<'tcx> { - pub span: Span, - pub kind: ErrKind<'tcx>, -} - -#[derive(Clone, Debug)] -pub enum ErrKind<'tcx> { - CannotCast, - MissingStructField, - NegateOn(ConstVal<'tcx>), - NotOn(ConstVal<'tcx>), - CallOn(ConstVal<'tcx>), - - NonConstPath, - UnimplementedConstVal(&'static str), - ExpectedConstTuple, - ExpectedConstStruct, - IndexedNonVec, - IndexNotUsize, - IndexOutOfBounds { len: u64, index: u64 }, - - MiscBinaryOp, - MiscCatchAll, - - IndexOpFeatureGated, - Math(ConstMathErr), - - ErroneousReferencedConstant(Box>), - - TypeckError -} - -impl<'tcx> From for ErrKind<'tcx> { - fn from(err: ConstMathErr) -> ErrKind<'tcx> { - match err { - ConstMathErr::UnsignedNegation => TypeckError, - _ => Math(err) - } - } -} - -#[derive(Clone, Debug)] -pub enum ConstEvalErrDescription<'a> { - Simple(Cow<'a, str>), -} - -impl<'a> ConstEvalErrDescription<'a> { - /// Return a one-line description of the error, for lints and such - pub fn into_oneline(self) -> Cow<'a, str> { - match self { - ConstEvalErrDescription::Simple(simple) => simple, - } - } -} - -impl<'tcx> ConstEvalErr<'tcx> { - pub fn description(&self) -> ConstEvalErrDescription { - use self::ErrKind::*; - use self::ConstEvalErrDescription::*; - - macro_rules! simple { - ($msg:expr) => ({ Simple($msg.into_cow()) }); - ($fmt:expr, $($arg:tt)+) => ({ - Simple(format!($fmt, $($arg)+).into_cow()) - }) - } - - match self.kind { - CannotCast => simple!("can't cast this type"), - NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), - NotOn(ref const_val) => simple!("not on {}", const_val.description()), - CallOn(ref const_val) => simple!("call on {}", const_val.description()), - - MissingStructField => simple!("nonexistent struct field"), - NonConstPath => simple!("non-constant path in constant expression"), - UnimplementedConstVal(what) => - simple!("unimplemented constant expression: {}", what), - ExpectedConstTuple => simple!("expected constant tuple"), - ExpectedConstStruct => simple!("expected constant struct"), - IndexedNonVec => simple!("indexing is only supported for arrays"), - IndexNotUsize => simple!("indices must be of type `usize`"), - IndexOutOfBounds { len, index } => { - simple!("index out of bounds: the len is {} but the index is {}", - len, index) - } - - MiscBinaryOp => simple!("bad operands for binary"), - MiscCatchAll => simple!("unsupported constant expr"), - IndexOpFeatureGated => simple!("the index operation on const values is unstable"), - Math(ref err) => Simple(err.description().into_cow()), - - ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), - - TypeckError => simple!("type-checking failed"), - } - } -} - -pub type EvalResult<'tcx> = Result, ConstEvalErr<'tcx>>; -pub type CastResult<'tcx> = Result, ErrKind<'tcx>>; +type CastResult<'tcx> = Result, ErrKind<'tcx>>; fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, e: &Expr) -> EvalResult<'tcx> { @@ -947,14 +784,14 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { let a = match self.eval(a) { Ok(a) => a, Err(e) => { - report_const_eval_err(tcx, &e, a.span, "expression"); + e.report(tcx, a.span, "expression"); return Err(ErrorReported); } }; let b = match self.eval(b) { Ok(b) => b, Err(e) => { - report_const_eval_err(tcx, &e, b.span, "expression"); + e.report(tcx, b.span, "expression"); return Err(ErrorReported); } }; @@ -979,8 +816,7 @@ pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(_) | Err(ConstEvalErr { kind: TypeckError, .. }) => Err(ErrorReported), Err(err) => { - let mut diag = build_const_eval_err( - tcx, &err, count_expr.span, reason); + let mut diag = err.struct_error(tcx, count_expr.span, reason); if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node { if let Def::Local(..) = path.def { diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 4434a901f9412..fa3161a860498 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -40,7 +40,6 @@ extern crate rustc_back; extern crate rustc_const_math; extern crate rustc_data_structures; extern crate rustc_errors; -extern crate graphviz; extern crate syntax_pos; // NB: This module needs to be declared first so diagnostics are diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index bd67dd2e6b25d..f20fa27dc2251 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -11,7 +11,7 @@ use eval; use rustc::lint; -use rustc::middle::const_val::ConstVal; +use rustc::middle::const_val::{ConstEvalErr, ConstVal}; use rustc::mir::{Field, BorrowKind, Mutability}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, TypeVariants, Region}; use rustc::ty::subst::{Substs, Kind}; @@ -29,7 +29,7 @@ use syntax_pos::Span; #[derive(Clone, Debug)] pub enum PatternError<'tcx> { StaticInPattern(Span), - ConstEval(eval::ConstEvalErr<'tcx>), + ConstEval(ConstEvalErr<'tcx>), } #[derive(Copy, Clone, Debug)] diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3498be9dfdf32..d2512ff602a84 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -524,7 +524,8 @@ impl<'a, 'tcx> CrateMetadata { }; if let ty::VariantDiscr::Explicit(def_id) = data.discr { - let result = data.evaluated_discr.map_or(Err(()), Ok); + // The original crate wouldn't have compiled if this is missing. + let result = Ok(data.evaluated_discr.unwrap()); tcx.maps.monomorphic_const_eval.borrow_mut().insert(def_id, result); } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index d9b8d04ad386f..595748c8c6fdc 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -17,7 +17,7 @@ use hair::cx::to_ref::ToRef; use rustc::hir::map; use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; -use rustc_const_eval::{ConstContext, fatal_const_eval_err}; +use rustc_const_eval::ConstContext; use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; @@ -597,7 +597,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let count = match ConstContext::new(tcx, count).eval(c) { Ok(ConstVal::Integral(ConstInt::Usize(u))) => u, Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), - Err(s) => fatal_const_eval_err(tcx, &s, c.span, "expression") + Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") }; ExprKind::Repeat { diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 3eef5d83b8ba0..5f9fb8e1b120f 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -17,8 +17,8 @@ use hair::*; use rustc::mir::transform::MirSource; -use rustc::middle::const_val::ConstVal; -use rustc_const_eval::{ConstContext, fatal_const_eval_err}; +use rustc::middle::const_val::{ConstEvalErr, ConstVal}; +use rustc_const_eval::ConstContext; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::DefId; use rustc::hir::map::blocks::FnLikeNode; @@ -115,10 +115,21 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let tcx = self.tcx.global_tcx(); match ConstContext::with_tables(tcx, self.tables()).eval(e) { Ok(value) => Literal::Value { value: value }, - Err(s) => fatal_const_eval_err(tcx, &s, e.span, "expression") + Err(s) => self.fatal_const_eval_err(&s, e.span, "expression") } } + pub fn fatal_const_eval_err(&self, + err: &ConstEvalErr<'tcx>, + primary_span: Span, + primary_kind: &str) + -> ! + { + err.report(self.tcx, primary_span, primary_kind); + self.tcx.sess.abort_if_errors(); + unreachable!() + } + pub fn trait_method(&mut self, trait_def_id: DefId, method_name: &str, diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 930a13e36bdca..44d3026d80c3e 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -26,10 +26,11 @@ use rustc::dep_graph::DepNode; use rustc::ty::cast::CastKind; -use rustc_const_eval::{ConstEvalErr, ConstContext}; -use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math}; -use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath}; -use rustc_const_eval::ErrKind::{TypeckError}; +use rustc_const_eval::ConstContext; +use rustc::middle::const_val::ConstEvalErr; +use rustc::middle::const_val::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll}; +use rustc::middle::const_val::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath}; +use rustc::middle::const_val::ErrKind::{TypeckError, Math}; use rustc_const_math::{ConstMathErr, Op}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 07dcb2fc29dc6..af477f5a15217 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -15,7 +15,6 @@ log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } -rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 6b6fa538dc03b..7a53a03344fcb 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -13,9 +13,9 @@ use back::symbol_names; use llvm; use llvm::{SetUnnamedAddr}; use llvm::{ValueRef, True}; -use rustc_const_eval::ConstEvalErr; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; +use rustc::middle::const_val::ConstEvalErr; use {debuginfo, machine}; use base; use trans_item::TransItem; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index abda358bc4f87..c5383fceb8787 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -51,7 +51,6 @@ extern crate rustc_incremental; pub extern crate rustc_llvm as llvm; extern crate rustc_platform_intrinsics as intrinsics; extern crate rustc_const_math; -extern crate rustc_const_eval; #[macro_use] #[no_link] extern crate rustc_bitflags; diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index caec4789eddce..0976859e27f44 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -9,9 +9,8 @@ // except according to those terms. use llvm::{self, ValueRef, BasicBlockRef}; -use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err}; use rustc::middle::lang_items; -use rustc::middle::const_val::ConstInt; +use rustc::middle::const_val::{ConstEvalErr, ConstInt, ErrKind}; use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::{self, LayoutTyper}; use rustc::mir; @@ -363,7 +362,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let err = ConstEvalErr{ span: span, kind: err }; let mut diag = bcx.tcx().sess.struct_span_warn( span, "this expression will panic at run-time"); - note_const_eval_err(bcx.tcx(), &err, span, "expression", &mut diag); + err.note(bcx.tcx(), span, "expression", &mut diag); diag.emit(); } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 4d5b691c86ebb..37d2b1952f494 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -9,8 +9,7 @@ // except according to those terms. use llvm::{self, ValueRef}; -use rustc::middle::const_val::ConstVal; -use rustc_const_eval::{ErrKind, ConstEvalErr, report_const_eval_err}; +use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind}; use rustc_const_math::ConstInt::*; use rustc_const_math::ConstFloat::*; use rustc_const_math::{ConstInt, ConstMathErr}; @@ -327,8 +326,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } }; - let err = ConstEvalErr{ span: span, kind: err }; - report_const_eval_err(tcx, &err, span, "expression"); + let err = ConstEvalErr { span: span, kind: err }; + err.report(tcx, span, "expression"); failure = Err(err); } target diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index f5556bb8382f6..4d908f3c94fa5 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -28,7 +28,6 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst::Substs; -use rustc_const_eval::fatal_const_eval_err; use syntax::ast::{self, NodeId}; use syntax::attr; use type_of; @@ -82,9 +81,7 @@ impl<'a, 'tcx> TransItem<'tcx> { match consts::trans_static(&ccx, m, item.id, &item.attrs) { Ok(_) => { /* Cool, everything's alright. */ }, Err(err) => { - // FIXME: shouldn't this be a `span_err`? - fatal_const_eval_err( - ccx.tcx(), &err, item.span, "static"); + err.report(ccx.tcx(), item.span, "static"); } }; } else { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 649353d52f6aa..4c7979ea3765c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -59,7 +59,7 @@ use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use middle::resolve_lifetime as rl; -use rustc_const_eval::{ConstContext, report_const_eval_err}; +use rustc_const_eval::ConstContext; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ReprOptions}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; @@ -587,17 +587,6 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.item_predicates(def_id); } -fn evaluate_disr_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - body: hir::BodyId) - -> Result, ()> { - let e = &tcx.hir.body(body).value; - ConstContext::new(tcx, body).eval(e).map_err(|err| { - // enum variant evaluation happens before the global constant check - // so we need to report the real error - report_const_eval_err(tcx, &err, e.span, "enum discriminant"); - }) -} - fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, variants: &[hir::Variant]) { @@ -612,9 +601,15 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, prev_discr = Some(if let Some(e) = variant.node.disr_expr { let expr_did = tcx.hir.local_def_id(e.node_id); let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || { - evaluate_disr_expr(tcx, e) + ConstContext::new(tcx, e).eval(&tcx.hir.body(e).value) }); + // enum variant evaluation happens before the global constant check + // so we need to report the real error + if let Err(ref err) = result { + err.report(tcx, variant.span, "enum discriminant"); + } + match result { Ok(ConstVal::Integral(x)) => Some(x), _ => None From 63064ec190fef7947c3eabfcdfeaeb293c9a91dd Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 14 Apr 2017 19:00:08 +0300 Subject: [PATCH 3/5] rustc: expose monomorphic const_eval through on-demand. --- src/Cargo.lock | 2 -- src/librustc/middle/const_val.rs | 37 +++++++++++++++++++++++- src/librustc_const_eval/eval.rs | 49 ++++++++++---------------------- src/librustc_driver/driver.rs | 3 +- src/librustc_mir/hair/cx/expr.rs | 5 ++-- src/librustc_typeck/Cargo.toml | 1 - src/librustc_typeck/astconv.rs | 4 +-- src/librustc_typeck/check/mod.rs | 4 +-- src/librustc_typeck/collect.rs | 6 +--- src/librustc_typeck/lib.rs | 1 - src/librustdoc/Cargo.toml | 1 - src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/lib.rs | 1 - 13 files changed, 61 insertions(+), 55 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index c4b5366d4a324..62b853480394f 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -760,7 +760,6 @@ dependencies = [ "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", - "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -781,7 +780,6 @@ dependencies = [ "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", - "rustc_const_eval 0.0.0", "rustc_data_structures 0.0.0", "rustc_driver 0.0.0", "rustc_errors 0.0.0", diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 9315f7f58081a..b4c5af9401944 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -11,9 +11,12 @@ use self::ConstVal::*; pub use rustc_const_math::ConstInt; +use hir; +use hir::def::Def; use hir::def_id::DefId; -use ty::TyCtxt; +use ty::{self, TyCtxt}; use ty::subst::Substs; +use util::common::ErrorReported; use rustc_const_math::*; use graphviz::IntoCow; @@ -215,3 +218,35 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { self.struct_error(tcx, primary_span, primary_kind).emit(); } } + +/// Returns the value of the length-valued expression +pub fn eval_length(tcx: TyCtxt, + count: hir::BodyId, + reason: &str) + -> Result +{ + let count_expr = &tcx.hir.body(count).value; + let count_def_id = tcx.hir.body_owner_def_id(count); + match ty::queries::monomorphic_const_eval::get(tcx, count_expr.span, count_def_id) { + Ok(Integral(Usize(count))) => { + let val = count.as_u64(tcx.sess.target.uint_type); + assert_eq!(val as usize as u64, val); + Ok(val as usize) + }, + Ok(_) | + Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported), + Err(err) => { + let mut diag = err.struct_error(tcx, count_expr.span, reason); + + if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node { + if let Def::Local(..) = path.def { + diag.note(&format!("`{}` is a variable", + tcx.hir.node_to_pretty_string(count_expr.id))); + } + } + + diag.emit(); + Err(ErrorReported) + } + } +} diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index b928bae620b6c..bf8085be31c44 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -18,6 +18,7 @@ use rustc::traits; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; use rustc::ty::subst::{Substs, Subst}; use rustc::traits::Reveal; @@ -163,12 +164,6 @@ pub struct ConstContext<'a, 'tcx: 'a> { } impl<'a, 'tcx> ConstContext<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self { - let def_id = tcx.hir.body_owner_def_id(body); - ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); - ConstContext::with_tables(tcx, tcx.item_tables(def_id)) - } - pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self { ConstContext { tcx: tcx, @@ -799,34 +794,20 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { } } +pub fn provide(providers: &mut Providers) { + *providers = Providers { + monomorphic_const_eval, + ..*providers + }; +} -/// Returns the value of the length-valued expression -pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - count: hir::BodyId, - reason: &str) - -> Result -{ - let count_expr = &tcx.hir.body(count).value; - match ConstContext::new(tcx, count).eval(count_expr) { - Ok(Integral(Usize(count))) => { - let val = count.as_u64(tcx.sess.target.uint_type); - assert_eq!(val as usize as u64, val); - Ok(val as usize) - }, - Ok(_) | - Err(ConstEvalErr { kind: TypeckError, .. }) => Err(ErrorReported), - Err(err) => { - let mut diag = err.struct_error(tcx, count_expr.span, reason); - - if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node { - if let Def::Local(..) = path.def { - diag.note(&format!("`{}` is a variable", - tcx.hir.node_to_pretty_string(count_expr.id))); - } - } +fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> EvalResult<'tcx> { + ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); + let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id)); - diag.emit(); - Err(ErrorReported) - } - } + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let body = tcx.hir.body_owned_by(id); + cx.eval(&tcx.hir.body(body).value) } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 48d9719e76c4d..c856ea505ffe8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -37,7 +37,7 @@ use rustc_plugin::registry::Registry; use rustc_plugin as plugin; use rustc_passes::{ast_validation, no_asm, loops, consts, static_recursion, hir_stats, mir_stats}; -use rustc_const_eval::check_match; +use rustc_const_eval::{self, check_match}; use super::Compilation; use serialize::json; @@ -895,6 +895,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, typeck::provide(&mut local_providers); ty::provide(&mut local_providers); reachable::provide(&mut local_providers); + rustc_const_eval::provide(&mut local_providers); let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 595748c8c6fdc..b7de50efe3442 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -17,7 +17,6 @@ use hair::cx::to_ref::ToRef; use rustc::hir::map; use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; -use rustc_const_eval::ConstContext; use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; @@ -592,9 +591,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // Now comes the rote stuff: hir::ExprRepeat(ref v, count) => { - let tcx = cx.tcx.global_tcx(); let c = &cx.tcx.hir.body(count).value; - let count = match ConstContext::new(tcx, count).eval(c) { + let def_id = cx.tcx.hir.body_owner_def_id(count); + let count = match ty::queries::monomorphic_const_eval::get(cx.tcx, c.span, def_id) { Ok(ConstVal::Integral(ConstInt::Usize(u))) => u, Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 07998aa4a30ea..194d37dcb81c2 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -16,7 +16,6 @@ arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } -rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 66c4a81a5c0f2..9426d601dfcce 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -12,7 +12,7 @@ //! representation. The main routine here is `ast_ty_to_ty()`: each use //! is parameterized by an instance of `AstConv`. -use rustc_const_eval::eval_length; +use rustc::middle::const_val::eval_length; use rustc_data_structures::accumulate_vec::AccumulateVec; use hir; use hir::def::Def; @@ -1208,7 +1208,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0 } hir::TyArray(ref ty, length) => { - if let Ok(length) = eval_length(tcx.global_tcx(), length, "array length") { + if let Ok(length) = eval_length(tcx, length, "array length") { tcx.mk_array(self.ast_ty_to_ty(&ty), length) } else { self.tcx().types.err diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5e7325275b819..d2c9fd119d72b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -126,7 +126,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::{self, PatKind}; use rustc::middle::lang_items; use rustc_back::slice; -use rustc_const_eval::eval_length; +use rustc::middle::const_val::eval_length; use rustc_const_math::ConstInt; mod assoc; @@ -3634,7 +3634,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.mk_array(element_ty, args.len()) } hir::ExprRepeat(ref element, count) => { - let count = eval_length(self.tcx.global_tcx(), count, "repeat count") + let count = eval_length(self.tcx, count, "repeat count") .unwrap_or(0); let uty = match expected { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4c7979ea3765c..73e3de0cc76dd 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -59,14 +59,12 @@ use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use middle::resolve_lifetime as rl; -use rustc_const_eval::ConstContext; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ReprOptions}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; use rustc::dep_graph::DepNode; -use util::common::MemoizationMap; use util::nodemap::{NodeMap, FxHashMap}; use rustc_const_math::ConstInt; @@ -600,9 +598,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr()); prev_discr = Some(if let Some(e) = variant.node.disr_expr { let expr_did = tcx.hir.local_def_id(e.node_id); - let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || { - ConstContext::new(tcx, e).eval(&tcx.hir.body(e).value) - }); + let result = ty::queries::monomorphic_const_eval::get(tcx, variant.span, expr_did); // enum variant evaluation happens before the global constant check // so we need to report the real error diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 12db76bf91c34..e9d52c5eb98d9 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -94,7 +94,6 @@ extern crate fmt_macros; extern crate rustc_platform_intrinsics as intrinsics; extern crate rustc_back; extern crate rustc_const_math; -extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors as errors; diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 52f5d99838dc7..e81acf7bdba82 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -14,7 +14,6 @@ env_logger = { version = "0.4", default-features = false } log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } -rustc_const_eval = { path = "../librustc_const_eval" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_driver = { path = "../librustc_driver" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3d233463bba3a..47e1d0b7edb2a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1715,7 +1715,7 @@ impl Clean for hir::Ty { } TySlice(ref ty) => Vector(box ty.clean(cx)), TyArray(ref ty, length) => { - use rustc_const_eval::eval_length; + use rustc::middle::const_val::eval_length; let n = eval_length(cx.tcx, length, "array length").unwrap(); FixedVector(box ty.clean(cx), n.to_string()) }, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 447d60018d912..d5b997001bb9d 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -33,7 +33,6 @@ extern crate getopts; extern crate env_logger; extern crate libc; extern crate rustc; -extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_trans; extern crate rustc_driver; From 6dc21b71cfd8e5246e7953cf64ea5ee6a19ceb3d Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 15 Apr 2017 04:14:44 +0300 Subject: [PATCH 4/5] rustc: use monomorphic const_eval for cross-crate enum discriminants. --- src/librustc/ty/mod.rs | 47 ++++++++++- src/librustc_const_eval/eval.rs | 11 ++- src/librustc_driver/driver.rs | 2 + .../persist/dirty_clean.rs | 11 +++ src/librustc_metadata/decoder.rs | 24 ++---- src/librustc_metadata/encoder.rs | 46 +++++++++-- src/librustc_metadata/schema.rs | 13 ++- src/librustc_trans/adt.rs | 20 ++--- src/librustc_trans/disr.rs | 82 ------------------- src/librustc_trans/lib.rs | 2 - src/librustc_trans/mir/constant.rs | 13 +-- src/librustc_trans/mir/rvalue.rs | 6 +- src/librustc_trans/mir/statement.rs | 3 +- src/test/incremental/hashes/enum_defs.rs | 8 +- 14 files changed, 139 insertions(+), 149 deletions(-) delete mode 100644 src/librustc_trans/disr.rs diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 09eacb40aef7e..0b5434f50e830 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1660,7 +1660,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.variants.iter().map(move |v| { let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr()); if let VariantDiscr::Explicit(expr_did) = v.discr { - match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] { + match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) { Ok(ConstVal::Integral(v)) => { discr = v; } @@ -1673,6 +1673,51 @@ impl<'a, 'gcx, 'tcx> AdtDef { }) } + /// Compute the discriminant value used by a specific variant. + /// Unlike `discriminants`, this is (amortized) constant-time, + /// only doing at most one query for evaluating an explicit + /// discriminant (the last one before the requested variant), + /// assuming there are no constant-evaluation errors there. + pub fn discriminant_for_variant(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + variant_index: usize) + -> ConstInt { + let repr_type = self.repr.discr_type(); + let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx()); + let mut explicit_index = variant_index; + loop { + match self.variants[explicit_index].discr { + ty::VariantDiscr::Relative(0) => break, + ty::VariantDiscr::Relative(distance) => { + explicit_index -= distance; + } + ty::VariantDiscr::Explicit(expr_did) => { + match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) { + Ok(ConstVal::Integral(v)) => { + explicit_value = v; + break; + } + _ => { + explicit_index -= 1; + } + } + } + } + } + let discr = explicit_value.to_u128_unchecked() + .wrapping_add((variant_index - explicit_index) as u128); + match repr_type { + attr::UnsignedInt(ty) => { + ConstInt::new_unsigned_truncating(discr, ty, + tcx.sess.target.uint_type) + } + attr::SignedInt(ty) => { + ConstInt::new_signed_truncating(discr as i128, ty, + tcx.sess.target.int_type) + } + } + } + pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { queries::adt_destructor::get(tcx, DUMMY_SP, self.did) } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index bf8085be31c44..9c5a669bef0d9 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -804,10 +804,13 @@ pub fn provide(providers: &mut Providers) { fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> EvalResult<'tcx> { - ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id)); - let id = tcx.hir.as_local_node_id(def_id).unwrap(); - let body = tcx.hir.body_owned_by(id); - cx.eval(&tcx.hir.body(body).value) + let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { + ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); + tcx.hir.body(tcx.hir.body_owned_by(id)) + } else { + tcx.sess.cstore.maybe_get_item_body(tcx, def_id).unwrap() + }; + cx.eval(&body.value) } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c856ea505ffe8..7632b40ab4f9e 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -900,6 +900,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); ty::provide_extern(&mut extern_providers); + // FIXME(eddyb) get rid of this once we replace const_eval with miri. + rustc_const_eval::provide(&mut extern_providers); TyCtxt::create_and_enter(sess, local_providers, diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index af5c1f05bd1fc..b73b3e161f9b5 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -266,6 +266,17 @@ impl<'a, 'tcx, 'm> intravisit::Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, ' intravisit::walk_item(self, item); } + fn visit_variant(&mut self, + variant: &'tcx hir::Variant, + generics: &'tcx hir::Generics, + parent_id: ast::NodeId) { + if let Some(e) = variant.node.disr_expr { + self.check_item(e.node_id, variant.span); + } + + intravisit::walk_variant(self, variant, generics, parent_id); + } + fn visit_variant_data(&mut self, variant_data: &'tcx hir::VariantData, _: ast::Name, diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d2512ff602a84..fac6079529e30 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -511,11 +511,7 @@ impl<'a, 'tcx> CrateMetadata { def } - fn get_variant(&self, - item: &Entry<'tcx>, - index: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> (ty::VariantDef, Option) { + fn get_variant(&self, item: &Entry, index: DefIndex) -> ty::VariantDef { let data = match item.kind { EntryKind::Variant(data) | EntryKind::Struct(data, _) | @@ -523,13 +519,7 @@ impl<'a, 'tcx> CrateMetadata { _ => bug!(), }; - if let ty::VariantDiscr::Explicit(def_id) = data.discr { - // The original crate wouldn't have compiled if this is missing. - let result = Ok(data.evaluated_discr.unwrap()); - tcx.maps.monomorphic_const_eval.borrow_mut().insert(def_id, result); - } - - (ty::VariantDef { + ty::VariantDef { did: self.local_def_id(data.struct_ctor.unwrap_or(index)), name: self.item_name(index), fields: item.children.decode(self).map(|index| { @@ -542,7 +532,7 @@ impl<'a, 'tcx> CrateMetadata { }).collect(), discr: data.discr, ctor_kind: data.ctor_kind, - }, data.struct_ctor) + } } pub fn get_adt_def(&self, @@ -561,15 +551,11 @@ impl<'a, 'tcx> CrateMetadata { item.children .decode(self) .map(|index| { - let (variant, struct_ctor) = - self.get_variant(&self.entry(index), index, tcx); - assert_eq!(struct_ctor, None); - variant + self.get_variant(&self.entry(index), index) }) .collect() } else { - let (variant, _struct_ctor) = self.get_variant(&item, item_id, tcx); - vec![variant] + vec![self.get_variant(&item, item_id)] }; let (kind, repr) = match item.kind { EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr), diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 0e204695e8f22..ce9f0a73fe2b8 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -269,12 +269,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let data = VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - evaluated_discr: match variant.discr { - ty::VariantDiscr::Explicit(def_id) => { - ty::queries::monomorphic_const_eval::get(tcx, DUMMY_SP, def_id).ok() - } - ty::VariantDiscr::Relative(_) => None - }, struct_ctor: None, }; @@ -408,7 +402,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let data = VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - evaluated_discr: None, struct_ctor: Some(def_id.index), }; @@ -697,7 +690,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { EntryKind::Struct(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - evaluated_discr: None, struct_ctor: struct_ctor, }), repr_options) } @@ -708,7 +700,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { EntryKind::Union(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - evaluated_discr: None, struct_ctor: None, }), repr_options) } @@ -1037,6 +1028,17 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { EntryBuilder::encode_info_for_foreign_item, (def_id, ni)); } + fn visit_variant(&mut self, + v: &'tcx hir::Variant, + g: &'tcx hir::Generics, + id: ast::NodeId) { + intravisit::walk_variant(self, v, g, id); + + if let Some(discr) = v.node.disr_expr { + let def_id = self.index.tcx.hir.body_owner_def_id(discr); + self.index.record(def_id, EntryBuilder::encode_info_for_embedded_const, def_id); + } + } fn visit_generics(&mut self, generics: &'tcx hir::Generics) { intravisit::walk_generics(self, generics); self.index.encode_info_for_generics(generics); @@ -1160,6 +1162,32 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } } + fn encode_info_for_embedded_const(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_embedded_const({:?})", def_id); + let tcx = self.tcx; + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let body = tcx.hir.body_owned_by(id); + + Entry { + kind: EntryKind::Const(ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id)), + visibility: self.lazy(&ty::Visibility::Public), + span: self.lazy(&tcx.def_span(def_id)), + attributes: LazySeq::empty(), + children: LazySeq::empty(), + stability: None, + deprecation: None, + + ty: Some(self.encode_item_type(def_id)), + inherent_impls: LazySeq::empty(), + variances: LazySeq::empty(), + generics: Some(self.encode_generics(def_id)), + predicates: Some(self.encode_predicates(def_id)), + + ast: Some(self.encode_body(body)), + mir: self.encode_mir(def_id), + } + } + fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { // NOTE: This must use lazy_seq_from_slice(), not lazy_seq() because // we really on the HashStable specialization for [Attribute] diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 6cd35f1335ed7..2f2e0e125aea5 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -15,7 +15,6 @@ use rustc::hir; use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId}; use rustc::ich::StableHashingContext; -use rustc::middle::const_val::ConstVal; use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary}; use rustc::middle::lang_items; use rustc::mir; @@ -271,9 +270,9 @@ pub enum EntryKind<'tcx> { Type, Enum(ReprOptions), Field, - Variant(Lazy>), - Struct(Lazy>, ReprOptions), - Union(Lazy>, ReprOptions), + Variant(Lazy), + Struct(Lazy, ReprOptions), + Union(Lazy, ReprOptions), Fn(Lazy), ForeignFn(Lazy), Mod(Lazy), @@ -374,20 +373,18 @@ pub struct FnData { impl_stable_hash_for!(struct FnData { constness, arg_names }); #[derive(RustcEncodable, RustcDecodable)] -pub struct VariantData<'tcx> { +pub struct VariantData { pub ctor_kind: CtorKind, pub discr: ty::VariantDiscr, - pub evaluated_discr: Option>, /// If this is a struct's only variant, this /// is the index of the "struct ctor" item. pub struct_ctor: Option, } -impl_stable_hash_for!(struct VariantData<'tcx> { +impl_stable_hash_for!(struct VariantData { ctor_kind, discr, - evaluated_discr, struct_ctor }); diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 0fe180253b5b8..87ca410dece0d 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -41,8 +41,6 @@ //! used unboxed and any field can have pointers (including mutable) //! taken to it, implementing them for Rust seems difficult. -use super::Disr; - use std; use llvm::{ValueRef, True, IntEQ, IntNE}; @@ -347,31 +345,31 @@ fn load_discr(bcx: &Builder, ity: layout::Integer, ptr: ValueRef, /// Set the discriminant for a new value of the given case of the given /// representation. -pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: Disr) { +pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: u64) { let l = bcx.ccx.layout_of(t); match *l { layout::CEnum{ discr, min, max, .. } => { - assert_discr_in_range(Disr(min), Disr(max), to); - bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true), + assert_discr_in_range(min, max, to); + bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true), val, None); } layout::General{ discr, .. } => { - bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true), + bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true), bcx.struct_gep(val, 0), None); } layout::Univariant { .. } | layout::UntaggedUnion { .. } | layout::Vector { .. } => { - assert_eq!(to, Disr(0)); + assert_eq!(to, 0); } layout::RawNullablePointer { nndiscr, .. } => { - if to.0 != nndiscr { + if to != nndiscr { let llptrty = val_ty(val).element_type(); bcx.store(C_null(llptrty), val, None); } } layout::StructWrappedNullablePointer { nndiscr, ref discrfield, ref nonnull, .. } => { - if to.0 != nndiscr { + if to != nndiscr { if target_sets_discr_via_memset(bcx) { // Issue #34427: As workaround for LLVM bug on // ARM, use memset of 0 on whole struct rather @@ -397,7 +395,7 @@ fn target_sets_discr_via_memset<'a, 'tcx>(bcx: &Builder<'a, 'tcx>) -> bool { bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64" } -pub fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) { +pub fn assert_discr_in_range(min: D, max: D, discr: D) { if min <= max { assert!(min <= discr && discr <= max) } else { @@ -415,7 +413,7 @@ fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a } /// (Not to be confused with `common::const_get_elt`, which operates on /// raw LLVM-level structs and arrays.) pub fn const_get_field<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, - val: ValueRef, _discr: Disr, + val: ValueRef, ix: usize) -> ValueRef { let l = ccx.layout_of(t); match *l { diff --git a/src/librustc_trans/disr.rs b/src/librustc_trans/disr.rs deleted file mode 100644 index a940faac83877..0000000000000 --- a/src/librustc_trans/disr.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc::middle::const_val::ConstVal; -use rustc::ty::{self, TyCtxt}; -use rustc_const_math::ConstInt; - -#[derive(Debug, Eq, PartialEq, Copy, Clone)] -pub struct Disr(pub u64); - -impl Disr { - pub fn for_variant(tcx: TyCtxt, - def: &ty::AdtDef, - variant_index: usize) -> Self { - let mut explicit_index = variant_index; - let mut explicit_value = Disr(0); - loop { - match def.variants[explicit_index].discr { - ty::VariantDiscr::Relative(0) => break, - ty::VariantDiscr::Relative(distance) => { - explicit_index -= distance; - } - ty::VariantDiscr::Explicit(expr_did) => { - match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] { - Ok(ConstVal::Integral(v)) => { - explicit_value = Disr::from(v); - break; - } - _ => { - explicit_index -= 1; - } - } - } - } - } - let distance = variant_index - explicit_index; - explicit_value.wrapping_add(Disr::from(distance)) - } - - pub fn wrapping_add(self, other: Self) -> Self { - Disr(self.0.wrapping_add(other.0)) - } -} - -impl ::std::ops::BitAnd for Disr { - type Output = Disr; - fn bitand(self, other: Self) -> Self { - Disr(self.0 & other.0) - } -} - -impl From for Disr { - fn from(i: ConstInt) -> Disr { - // FIXME: what if discr has 128 bit discr? - Disr(i.to_u128_unchecked() as u64) - } -} - -impl From for Disr { - fn from(i: usize) -> Disr { - Disr(i as u64) - } -} - -impl PartialOrd for Disr { - fn partial_cmp(&self, other: &Disr) -> Option<::std::cmp::Ordering> { - self.0.partial_cmp(&other.0) - } -} - -impl Ord for Disr { - fn cmp(&self, other: &Disr) -> ::std::cmp::Ordering { - self.0.cmp(&other.0) - } -} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index c5383fceb8787..be214a0f6143c 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -67,7 +67,6 @@ pub use rustc::lint; pub use rustc::util; pub use base::trans_crate; -pub use disr::Disr; pub mod back { pub use rustc::hir::svh; @@ -118,7 +117,6 @@ mod consts; mod context; mod debuginfo; mod declare; -mod disr; mod glue; mod intrinsic; mod machine; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 37d2b1952f494..8bce0cf85c08b 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -22,7 +22,7 @@ use rustc::ty::layout::{self, LayoutTyper}; use rustc::ty::cast::{CastTy, IntTy}; use rustc::ty::subst::{Kind, Substs, Subst}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use {abi, adt, base, Disr, machine}; +use {abi, adt, base, machine}; use callee; use builder::Builder; use common::{self, CrateContext, const_get_elt, val_ty}; @@ -428,7 +428,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } mir::ProjectionElem::Field(ref field, _) => { let llprojected = adt::const_get_field(self.ccx, tr_base.ty, base.llval, - Disr(0), field.index()); + field.index()); let llextra = if is_sized { ptr::null_mut() } else { @@ -987,13 +987,14 @@ fn trans_const<'a, 'tcx>( layout::CEnum { discr: d, min, max, .. } => { let discr = match *kind { mir::AggregateKind::Adt(adt_def, _, _, _) => { - Disr::for_variant(ccx.tcx(), adt_def, variant_index) + adt_def.discriminant_for_variant(ccx.tcx(), variant_index) + .to_u128_unchecked() as u64 }, - _ => Disr(0), + _ => 0, }; assert_eq!(vals.len(), 0); - adt::assert_discr_in_range(Disr(min), Disr(max), discr); - C_integral(Type::from_integer(ccx, d), discr.0, true) + adt::assert_discr_in_range(min, max, discr); + C_integral(Type::from_integer(ccx, d), discr, true) } layout::General { discr: d, ref variants, .. } => { let variant = &variants[variant_index]; diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index aa41720d717a7..98e9008f829f6 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -28,7 +28,6 @@ use type_::Type; use type_of; use tvec; use value::Value; -use Disr; use super::MirContext; use super::constant::const_scalar_checked_binop; @@ -107,9 +106,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::Rvalue::Aggregate(ref kind, ref operands) => { match *kind { mir::AggregateKind::Adt(adt_def, variant_index, substs, active_field_index) => { - let disr = Disr::for_variant(bcx.tcx(), adt_def, variant_index); + let discr = adt_def.discriminant_for_variant(bcx.tcx(), variant_index) + .to_u128_unchecked() as u64; let dest_ty = dest.ty.to_ty(bcx.tcx()); - adt::trans_set_discr(&bcx, dest_ty, dest.llval, disr); + adt::trans_set_discr(&bcx, dest_ty, dest.llval, discr); for (i, operand) in operands.iter().enumerate() { let op = self.trans_operand(&bcx, operand); // Do not generate stores and GEPis for zero-sized fields. diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs index 29a0648c8f8f8..52c2afca4748b 100644 --- a/src/librustc_trans/mir/statement.rs +++ b/src/librustc_trans/mir/statement.rs @@ -18,7 +18,6 @@ use builder::Builder; use super::MirContext; use super::LocalRef; use super::super::adt; -use super::super::disr::Disr; impl<'a, 'tcx> MirContext<'a, 'tcx> { pub fn trans_statement(&mut self, @@ -65,7 +64,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { adt::trans_set_discr(&bcx, ty, lvalue_transed.llval, - Disr::from(variant_index)); + variant_index as u64); bcx } mir::StatementKind::StorageLive(ref lvalue) => { diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs index 37c6ef58f5e56..0f734683b60e5 100644 --- a/src/test/incremental/hashes/enum_defs.rs +++ b/src/test/incremental/hashes/enum_defs.rs @@ -27,6 +27,7 @@ #![allow(warnings)] #![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] #![crate_type="rlib"] @@ -125,9 +126,12 @@ enum EnumChangeValueCStyleVariant0 { enum EnumChangeValueCStyleVariant0 { Variant1, - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - Variant2 = 22, + Variant2 = + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + 22, } #[cfg(cfail1)] From 1528cbefdb2c0c9fff37174d337c63617d6cb9fd Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Mon, 17 Apr 2017 17:49:35 +0100 Subject: [PATCH 5/5] Remove non-breaking spaces --- src/etc/natvis/libcollections.natvis | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/etc/natvis/libcollections.natvis b/src/etc/natvis/libcollections.natvis index 821c52361f868..e7e93be98695a 100644 --- a/src/etc/natvis/libcollections.natvis +++ b/src/etc/natvis/libcollections.natvis @@ -1,16 +1,16 @@ -    {{ size={len} }} -     + {{ size={len} }} + len buf.cap len buf.ptr.pointer.__0 -     -   + + {{ size={tail <= head ? head - tail : buf.cap - tail + head} }}