Auto merge of #46882 - oli-obk:miri3, r=eddyb

Replace all const evaluation with miri

* error reporting in constants prints a stacktrace through all called const fns
* Trivial constant propagation and folding in MIR (always active, irrelevant of the optimization level)
* can now use floating constants in patterns (previously only floating point literals were allowed)
    * the future compat lint is still produced for both cases
* can index into constant arrays during const eval (previously feature gated)
* can create a constant union value with field `a` and read from field `b`
* can dereference references into constants
* can create references inside constants (`const X: &u32 = &22`)
* Tuple struct constructors can be used in constants
* regression in const eval errors spans (some of these need improvements in mir debug info)
* can cast floats to ints and vice versa (in constants, and even nan/inf constants)
* Mir dump prints false/true instead of 0u8/1u8
* `1i8 >> [8][0]` does not lint about exceeding bitshifts anymore.
    * Needs const propagation across projections
* `foo[I]` produces a const eval lint if `foo: [T; N]` and `N < I`
    * Essentially all builtin panics produce lints if they can be statically proven to trigger at runtime. This is on a best effort basis, so there might be some complex cases that don't trigger. (The runtime panic stays there, irrelevant of whether the lint is produced or not)
* can use `union`s to implement `transmute` for `Copy` types in constants without a feature gate. With all the greatness and nasal demons that come with this.
* can convert integers to `&'static T` in constants (useful for embedded)

fixes #34997 (stack overflow with many constants)
fixes #25574 (deref byte strings in patterns)
fixes #27918 (broken mir ICE)
fixes #46114 (ICE on struct constructors in patterns)
fixes #37448 (`SomeStruct { foo } as SomeStruct`)
fixes #43754 (`return` in const fn)
fixes #41898 (tuple struct constructors)
fixes #31364 (infinite recursion with const fn, fixed by miri's recursion limit)
closes #29947 (const indexing stabilization)
fixes #45044 (pattern matching repeat expressions)
fixes #47971 (ICE on const fn + references)
fixes #48081 (ICE on cyclic assoc const error)
fixes #48746 (nonhelpful error message with unions)

r? @eddyb

even though 1k loc are added in tests, this PR reduces the loc in this repository by 700
This commit is contained in:
bors 2018-03-08 08:52:23 +00:00
commit c90f68224b
251 changed files with 6657 additions and 7185 deletions

21
src/Cargo.lock generated
View file

@ -1858,20 +1858,6 @@ dependencies = [
"syntax_pos 0.0.0", "syntax_pos 0.0.0",
] ]
[[package]]
name = "rustc_const_eval"
version = "0.0.0"
dependencies = [
"arena 0.0.0",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc_const_math 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]] [[package]]
name = "rustc_const_math" name = "rustc_const_math"
version = "0.0.0" version = "0.0.0"
@ -1914,7 +1900,6 @@ dependencies = [
"rustc_allocator 0.0.0", "rustc_allocator 0.0.0",
"rustc_back 0.0.0", "rustc_back 0.0.0",
"rustc_borrowck 0.0.0", "rustc_borrowck 0.0.0",
"rustc_const_eval 0.0.0",
"rustc_data_structures 0.0.0", "rustc_data_structures 0.0.0",
"rustc_errors 0.0.0", "rustc_errors 0.0.0",
"rustc_incremental 0.0.0", "rustc_incremental 0.0.0",
@ -1964,7 +1949,7 @@ version = "0.0.0"
dependencies = [ dependencies = [
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0", "rustc 0.0.0",
"rustc_const_eval 0.0.0", "rustc_mir 0.0.0",
"syntax 0.0.0", "syntax 0.0.0",
"syntax_pos 0.0.0", "syntax_pos 0.0.0",
] ]
@ -2012,6 +1997,7 @@ dependencies = [
name = "rustc_mir" name = "rustc_mir"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"arena 0.0.0",
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0", "graphviz 0.0.0",
@ -2020,7 +2006,6 @@ dependencies = [
"rustc 0.0.0", "rustc 0.0.0",
"rustc_apfloat 0.0.0", "rustc_apfloat 0.0.0",
"rustc_back 0.0.0", "rustc_back 0.0.0",
"rustc_const_eval 0.0.0",
"rustc_const_math 0.0.0", "rustc_const_math 0.0.0",
"rustc_data_structures 0.0.0", "rustc_data_structures 0.0.0",
"rustc_errors 0.0.0", "rustc_errors 0.0.0",
@ -2046,10 +2031,10 @@ version = "0.0.0"
dependencies = [ dependencies = [
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0", "rustc 0.0.0",
"rustc_const_eval 0.0.0",
"rustc_const_math 0.0.0", "rustc_const_math 0.0.0",
"rustc_data_structures 0.0.0", "rustc_data_structures 0.0.0",
"rustc_errors 0.0.0", "rustc_errors 0.0.0",
"rustc_mir 0.0.0",
"syntax 0.0.0", "syntax 0.0.0",
"syntax_pos 0.0.0", "syntax_pos 0.0.0",
] ]

View file

@ -64,7 +64,6 @@ for details on how to format and write long error codes.
[librustc](https://github.com/rust-lang/rust/blob/master/src/librustc/diagnostics.rs), [librustc](https://github.com/rust-lang/rust/blob/master/src/librustc/diagnostics.rs),
[libsyntax](https://github.com/rust-lang/rust/blob/master/src/libsyntax/diagnostics.rs), [libsyntax](https://github.com/rust-lang/rust/blob/master/src/libsyntax/diagnostics.rs),
[librustc_borrowck](https://github.com/rust-lang/rust/blob/master/src/librustc_borrowck/diagnostics.rs), [librustc_borrowck](https://github.com/rust-lang/rust/blob/master/src/librustc_borrowck/diagnostics.rs),
[librustc_const_eval](https://github.com/rust-lang/rust/blob/master/src/librustc_const_eval/diagnostics.rs),
[librustc_metadata](https://github.com/rust-lang/rust/blob/master/src/librustc_metadata/diagnostics.rs), [librustc_metadata](https://github.com/rust-lang/rust/blob/master/src/librustc_metadata/diagnostics.rs),
[librustc_mir](https://github.com/rust-lang/rust/blob/master/src/librustc_mir/diagnostics.rs), [librustc_mir](https://github.com/rust-lang/rust/blob/master/src/librustc_mir/diagnostics.rs),
[librustc_passes](https://github.com/rust-lang/rust/blob/master/src/librustc_passes/diagnostics.rs), [librustc_passes](https://github.com/rust-lang/rust/blob/master/src/librustc_passes/diagnostics.rs),

View file

@ -1,19 +0,0 @@
# `const_indexing`
The tracking issue for this feature is: [#29947]
[#29947]: https://github.com/rust-lang/rust/issues/29947
------------------------
The `const_indexing` feature allows the constant evaluation of index operations
on constant arrays and repeat expressions.
## Examples
```rust
#![feature(const_indexing)]
const ARR: [usize; 5] = [1, 2, 3, 4, 5];
const ARR2: [usize; ARR[1]] = [42, 99];
```

View file

@ -427,6 +427,7 @@ impl<T: Ord> Ord for Reverse<T> {
/// } /// }
/// } /// }
/// ``` /// ```
#[cfg_attr(not(stage0), lang = "ord")]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub trait Ord: Eq + PartialOrd<Self> { pub trait Ord: Eq + PartialOrd<Self> {
/// This method returns an `Ordering` between `self` and `other`. /// This method returns an `Ordering` between `self` and `other`.
@ -596,7 +597,8 @@ impl PartialOrd for Ordering {
/// assert_eq!(x < y, true); /// assert_eq!(x < y, true);
/// assert_eq!(x.lt(&y), true); /// assert_eq!(x.lt(&y), true);
/// ``` /// ```
#[lang = "ord"] #[cfg_attr(stage0, lang = "ord")]
#[cfg_attr(not(stage0), lang = "partial_ord")]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"]
pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {

View file

@ -60,15 +60,15 @@
//! user of the `DepNode` API of having to know how to compute the expected //! user of the `DepNode` API of having to know how to compute the expected
//! fingerprint for a given set of node parameters. //! fingerprint for a given set of node parameters.
use mir::interpret::{GlobalId};
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
use hir::map::DefPathHash; use hir::map::DefPathHash;
use hir::{HirId, ItemLocalId}; use hir::{HirId, ItemLocalId};
use ich::Fingerprint; use ich::{Fingerprint, StableHashingContext};
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty}; use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
use ty::subst::Substs; use ty::subst::Substs;
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
use ich::StableHashingContext;
use std::fmt; use std::fmt;
use std::hash::Hash; use std::hash::Hash;
use syntax_pos::symbol::InternedString; use syntax_pos::symbol::InternedString;
@ -518,7 +518,7 @@ define_dep_nodes!( <'tcx>
[] TypeckTables(DefId), [] TypeckTables(DefId),
[] UsedTraitImports(DefId), [] UsedTraitImports(DefId),
[] HasTypeckTables(DefId), [] HasTypeckTables(DefId),
[] ConstEval { param_env: ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)> }, [] ConstEval { param_env: ParamEnvAnd<'tcx, GlobalId<'tcx>> },
[] CheckMatch(DefId), [] CheckMatch(DefId),
[] SymbolName(DefId), [] SymbolName(DefId),
[] InstanceSymbolName { instance: Instance<'tcx> }, [] InstanceSymbolName { instance: Instance<'tcx> },
@ -661,7 +661,7 @@ trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
} }
impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T
where T: HashStable<StableHashingContext<'gcx>> + fmt::Debug where T: HashStable<StableHashingContext<'a>> + fmt::Debug
{ {
default const CAN_RECONSTRUCT_QUERY_KEY: bool = false; default const CAN_RECONSTRUCT_QUERY_KEY: bool = false;

View file

@ -14,19 +14,6 @@
// Each message should start and end with a new line, and be wrapped to 80 characters. // Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. // In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! { register_long_diagnostics! {
E0020: r##"
This error indicates that an attempt was made to divide by zero (or take the
remainder of a zero divisor) in a static or constant expression. Erroneous
code example:
```compile_fail
#[deny(const_err)]
const X: i32 = 42 / 0;
// error: attempt to divide by zero in a constant expression
```
"##,
E0038: r##" E0038: r##"
Trait objects like `Box<Trait>` can only be constructed when certain Trait objects like `Box<Trait>` can only be constructed when certain
requirements are satisfied by the trait in question. requirements are satisfied by the trait in question.

View file

@ -220,7 +220,6 @@ impl serialize::UseSpecializedDecodable for DefId {}
pub struct LocalDefId(DefIndex); pub struct LocalDefId(DefIndex);
impl LocalDefId { impl LocalDefId {
#[inline] #[inline]
pub fn from_def_id(def_id: DefId) -> LocalDefId { pub fn from_def_id(def_id: DefId) -> LocalDefId {
assert!(def_id.is_local()); assert!(def_id.is_local());

View file

@ -529,7 +529,7 @@ struct HirItemLike<T> {
hash_bodies: bool, hash_bodies: bool,
} }
impl<'hir, T> HashStable<StableHashingContext<'hir>> for HirItemLike<T> impl<'a, 'hir, T> HashStable<StableHashingContext<'hir>> for HirItemLike<T>
where T: HashStable<StableHashingContext<'hir>> where T: HashStable<StableHashingContext<'hir>>
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,

View file

@ -46,19 +46,19 @@ pub fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
/// a reference to the TyCtxt) and it holds a few caches for speeding up various /// a reference to the TyCtxt) and it holds a few caches for speeding up various
/// things (e.g. each DefId/DefPath is only hashed once). /// things (e.g. each DefId/DefPath is only hashed once).
#[derive(Clone)] #[derive(Clone)]
pub struct StableHashingContext<'gcx> { pub struct StableHashingContext<'a> {
sess: &'gcx Session, sess: &'a Session,
definitions: &'gcx Definitions, definitions: &'a Definitions,
cstore: &'gcx dyn CrateStore, cstore: &'a dyn CrateStore,
body_resolver: BodyResolver<'gcx>, body_resolver: BodyResolver<'a>,
hash_spans: bool, hash_spans: bool,
hash_bodies: bool, hash_bodies: bool,
node_id_hashing_mode: NodeIdHashingMode, node_id_hashing_mode: NodeIdHashingMode,
// Very often, we are hashing something that does not need the // Very often, we are hashing something that does not need the
// CachingCodemapView, so we initialize it lazily. // CachingCodemapView, so we initialize it lazily.
raw_codemap: &'gcx CodeMap, raw_codemap: &'a CodeMap,
caching_codemap: Option<CachingCodemapView<'gcx>>, caching_codemap: Option<CachingCodemapView<'a>>,
} }
#[derive(PartialEq, Eq, Clone, Copy)] #[derive(PartialEq, Eq, Clone, Copy)]
@ -81,14 +81,14 @@ impl<'gcx> BodyResolver<'gcx> {
} }
} }
impl<'gcx> StableHashingContext<'gcx> { impl<'a> StableHashingContext<'a> {
// The `krate` here is only used for mapping BodyIds to Bodies. // The `krate` here is only used for mapping BodyIds to Bodies.
// Don't use it for anything else or you'll run the risk of // Don't use it for anything else or you'll run the risk of
// leaking data out of the tracking system. // leaking data out of the tracking system.
pub fn new(sess: &'gcx Session, pub fn new(sess: &'a Session,
krate: &'gcx hir::Crate, krate: &'a hir::Crate,
definitions: &'gcx Definitions, definitions: &'a Definitions,
cstore: &'gcx dyn CrateStore) cstore: &'a dyn CrateStore)
-> Self { -> Self {
let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans; let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans;
@ -106,7 +106,7 @@ impl<'gcx> StableHashingContext<'gcx> {
} }
#[inline] #[inline]
pub fn sess(&self) -> &'gcx Session { pub fn sess(&self) -> &'a Session {
self.sess self.sess
} }
@ -165,7 +165,7 @@ impl<'gcx> StableHashingContext<'gcx> {
} }
#[inline] #[inline]
pub fn codemap(&mut self) -> &mut CachingCodemapView<'gcx> { pub fn codemap(&mut self) -> &mut CachingCodemapView<'a> {
match self.caching_codemap { match self.caching_codemap {
Some(ref mut cm) => { Some(ref mut cm) => {
cm cm
@ -193,27 +193,27 @@ impl<'gcx> StableHashingContext<'gcx> {
} }
impl<'a, 'gcx, 'lcx> StableHashingContextProvider for TyCtxt<'a, 'gcx, 'lcx> { impl<'a, 'gcx, 'lcx> StableHashingContextProvider for TyCtxt<'a, 'gcx, 'lcx> {
type ContextType = StableHashingContext<'gcx>; type ContextType = StableHashingContext<'a>;
fn create_stable_hashing_context(&self) -> Self::ContextType { fn create_stable_hashing_context(&self) -> Self::ContextType {
(*self).create_stable_hashing_context() (*self).create_stable_hashing_context()
} }
} }
impl<'gcx> StableHashingContextProvider for StableHashingContext<'gcx> { impl<'a> StableHashingContextProvider for StableHashingContext<'a> {
type ContextType = StableHashingContext<'gcx>; type ContextType = StableHashingContext<'a>;
fn create_stable_hashing_context(&self) -> Self::ContextType { fn create_stable_hashing_context(&self) -> Self::ContextType {
self.clone() self.clone()
} }
} }
impl<'gcx> ::dep_graph::DepGraphSafe for StableHashingContext<'gcx> { impl<'a> ::dep_graph::DepGraphSafe for StableHashingContext<'a> {
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::BodyId { impl<'a> HashStable<StableHashingContext<'a>> for hir::BodyId {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
if hcx.hash_bodies() { if hcx.hash_bodies() {
hcx.body_resolver.body(*self).hash_stable(hcx, hasher); hcx.body_resolver.body(*self).hash_stable(hcx, hasher);
@ -221,10 +221,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::BodyId {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::HirId { impl<'a> HashStable<StableHashingContext<'a>> for hir::HirId {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
match hcx.node_id_hashing_mode { match hcx.node_id_hashing_mode {
NodeIdHashingMode::Ignore => { NodeIdHashingMode::Ignore => {
@ -243,21 +243,21 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::HirId {
} }
} }
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for hir::HirId { impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::HirId {
type KeyType = (DefPathHash, hir::ItemLocalId); type KeyType = (DefPathHash, hir::ItemLocalId);
#[inline] #[inline]
fn to_stable_hash_key(&self, fn to_stable_hash_key(&self,
hcx: &StableHashingContext<'gcx>) hcx: &StableHashingContext<'a>)
-> (DefPathHash, hir::ItemLocalId) { -> (DefPathHash, hir::ItemLocalId) {
let def_path_hash = hcx.local_def_path_hash(self.owner); let def_path_hash = hcx.local_def_path_hash(self.owner);
(def_path_hash, self.local_id) (def_path_hash, self.local_id)
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::NodeId { impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
match hcx.node_id_hashing_mode { match hcx.node_id_hashing_mode {
NodeIdHashingMode::Ignore => { NodeIdHashingMode::Ignore => {
@ -270,18 +270,18 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::NodeId {
} }
} }
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for ast::NodeId { impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::NodeId {
type KeyType = (DefPathHash, hir::ItemLocalId); type KeyType = (DefPathHash, hir::ItemLocalId);
#[inline] #[inline]
fn to_stable_hash_key(&self, fn to_stable_hash_key(&self,
hcx: &StableHashingContext<'gcx>) hcx: &StableHashingContext<'a>)
-> (DefPathHash, hir::ItemLocalId) { -> (DefPathHash, hir::ItemLocalId) {
hcx.definitions.node_to_hir_id(*self).to_stable_hash_key(hcx) hcx.definitions.node_to_hir_id(*self).to_stable_hash_key(hcx)
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for Span { impl<'a> HashStable<StableHashingContext<'a>> for Span {
// Hash a span in a stable way. We can't directly hash the span's BytePos // Hash a span in a stable way. We can't directly hash the span's BytePos
// fields (that would be similar to hashing pointers, since those are just // fields (that would be similar to hashing pointers, since those are just
@ -293,7 +293,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Span {
// Also, hashing filenames is expensive so we avoid doing it twice when the // Also, hashing filenames is expensive so we avoid doing it twice when the
// span starts and ends in the same file, which is almost always the case. // span starts and ends in the same file, which is almost always the case.
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
const TAG_VALID_SPAN: u8 = 0; const TAG_VALID_SPAN: u8 = 0;
const TAG_INVALID_SPAN: u8 = 1; const TAG_INVALID_SPAN: u8 = 1;
@ -373,8 +373,8 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Span {
} }
} }
pub fn hash_stable_trait_impls<'gcx, W, R>( pub fn hash_stable_trait_impls<'a, 'gcx, W, R>(
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>, hasher: &mut StableHasher<W>,
blanket_impls: &Vec<DefId>, blanket_impls: &Vec<DefId>,
non_blanket_impls: &HashMap<fast_reject::SimplifiedType, Vec<DefId>, R>) non_blanket_impls: &HashMap<fast_reject::SimplifiedType, Vec<DefId>, R>)

View file

@ -16,33 +16,6 @@ impl_stable_hash_for!(struct ::rustc_const_math::ConstFloat {
bits bits
}); });
impl_stable_hash_for!(enum ::rustc_const_math::ConstInt {
I8(val),
I16(val),
I32(val),
I64(val),
I128(val),
Isize(val),
U8(val),
U16(val),
U32(val),
U64(val),
U128(val),
Usize(val)
});
impl_stable_hash_for!(enum ::rustc_const_math::ConstIsize {
Is16(i16),
Is32(i32),
Is64(i64)
});
impl_stable_hash_for!(enum ::rustc_const_math::ConstUsize {
Us16(i16),
Us32(i32),
Us64(i64)
});
impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr { impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr {
NotInRange, NotInRange,
CmpBetweenUnequalTypes, CmpBetweenUnequalTypes,

View file

@ -21,46 +21,46 @@ use std::mem;
use syntax::ast; use syntax::ast;
use syntax::attr; use syntax::attr;
impl<'gcx> HashStable<StableHashingContext<'gcx>> for DefId { impl<'a> HashStable<StableHashingContext<'a>> for DefId {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
hcx.def_path_hash(*self).hash_stable(hcx, hasher); hcx.def_path_hash(*self).hash_stable(hcx, hasher);
} }
} }
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for DefId { impl<'a> ToStableHashKey<StableHashingContext<'a>> for DefId {
type KeyType = DefPathHash; type KeyType = DefPathHash;
#[inline] #[inline]
fn to_stable_hash_key(&self, hcx: &StableHashingContext<'gcx>) -> DefPathHash { fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
hcx.def_path_hash(*self) hcx.def_path_hash(*self)
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for LocalDefId { impl<'a> HashStable<StableHashingContext<'a>> for LocalDefId {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
hcx.def_path_hash(self.to_def_id()).hash_stable(hcx, hasher); hcx.def_path_hash(self.to_def_id()).hash_stable(hcx, hasher);
} }
} }
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for LocalDefId { impl<'a> ToStableHashKey<StableHashingContext<'a>> for LocalDefId {
type KeyType = DefPathHash; type KeyType = DefPathHash;
#[inline] #[inline]
fn to_stable_hash_key(&self, hcx: &StableHashingContext<'gcx>) -> DefPathHash { fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
hcx.def_path_hash(self.to_def_id()) hcx.def_path_hash(self.to_def_id())
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for CrateNum { impl<'a> HashStable<StableHashingContext<'a>> for CrateNum {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
hcx.def_path_hash(DefId { hcx.def_path_hash(DefId {
krate: *self, krate: *self,
@ -69,11 +69,11 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for CrateNum {
} }
} }
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for CrateNum { impl<'a> ToStableHashKey<StableHashingContext<'a>> for CrateNum {
type KeyType = DefPathHash; type KeyType = DefPathHash;
#[inline] #[inline]
fn to_stable_hash_key(&self, hcx: &StableHashingContext<'gcx>) -> DefPathHash { fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
def_id.to_stable_hash_key(hcx) def_id.to_stable_hash_key(hcx)
} }
@ -81,13 +81,13 @@ impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for CrateNum {
impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index }); impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index });
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> impl<'a> ToStableHashKey<StableHashingContext<'a>>
for hir::ItemLocalId { for hir::ItemLocalId {
type KeyType = hir::ItemLocalId; type KeyType = hir::ItemLocalId;
#[inline] #[inline]
fn to_stable_hash_key(&self, fn to_stable_hash_key(&self,
_: &StableHashingContext<'gcx>) _: &StableHashingContext<'a>)
-> hir::ItemLocalId { -> hir::ItemLocalId {
*self *self
} }
@ -100,9 +100,9 @@ for hir::ItemLocalId {
// want to pick up on a reference changing its target, so we hash the NodeIds // want to pick up on a reference changing its target, so we hash the NodeIds
// in "DefPath Mode". // in "DefPath Mode".
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ItemId { impl<'a> HashStable<StableHashingContext<'a>> for hir::ItemId {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let hir::ItemId { let hir::ItemId {
id id
@ -114,9 +114,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ItemId {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitItemId { impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitItemId {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let hir::TraitItemId { let hir::TraitItemId {
node_id node_id
@ -128,9 +128,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitItemId {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ImplItemId { impl<'a> HashStable<StableHashingContext<'a>> for hir::ImplItemId {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let hir::ImplItemId { let hir::ImplItemId {
node_id node_id
@ -271,9 +271,9 @@ impl_stable_hash_for!(struct hir::TypeBinding {
span span
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Ty { impl<'a> HashStable<StableHashingContext<'a>> for hir::Ty {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
hcx.while_hashing_hir_bodies(true, |hcx| { hcx.while_hashing_hir_bodies(true, |hcx| {
let hir::Ty { let hir::Ty {
@ -339,9 +339,9 @@ impl_stable_hash_for!(enum hir::FunctionRetTy {
Return(t) Return(t)
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitRef { impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitRef {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let hir::TraitRef { let hir::TraitRef {
ref path, ref path,
@ -376,9 +376,9 @@ impl_stable_hash_for!(struct hir::MacroDef {
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Block { impl<'a> HashStable<StableHashingContext<'a>> for hir::Block {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let hir::Block { let hir::Block {
ref stmts, ref stmts,
@ -400,9 +400,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Block {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Pat { impl<'a> HashStable<StableHashingContext<'a>> for hir::Pat {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let hir::Pat { let hir::Pat {
id: _, id: _,
@ -527,9 +527,9 @@ impl_stable_hash_for!(enum hir::UnsafeSource {
UserProvided UserProvided
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Expr { impl<'a> HashStable<StableHashingContext<'a>> for hir::Expr {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
hcx.while_hashing_hir_bodies(true, |hcx| { hcx.while_hashing_hir_bodies(true, |hcx| {
let hir::Expr { let hir::Expr {
@ -591,9 +591,9 @@ impl_stable_hash_for!(enum hir::LoopSource {
ForLoop ForLoop
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::MatchSource { impl<'a> HashStable<StableHashingContext<'a>> for hir::MatchSource {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use hir::MatchSource; use hir::MatchSource;
@ -647,9 +647,9 @@ impl_stable_hash_for!(enum hir::ScopeTarget {
Loop(loop_id_result) Loop(loop_id_result)
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Ident { impl<'a> HashStable<StableHashingContext<'a>> for ast::Ident {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let ast::Ident { let ast::Ident {
ref name, ref name,
@ -660,9 +660,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Ident {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitItem { impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitItem {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let hir::TraitItem { let hir::TraitItem {
id: _, id: _,
@ -695,9 +695,9 @@ impl_stable_hash_for!(enum hir::TraitItemKind {
Type(bounds, rhs) Type(bounds, rhs)
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ImplItem { impl<'a> HashStable<StableHashingContext<'a>> for hir::ImplItem {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let hir::ImplItem { let hir::ImplItem {
id: _, id: _,
@ -729,9 +729,9 @@ impl_stable_hash_for!(enum hir::ImplItemKind {
Type(t) Type(t)
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Visibility { impl<'a> HashStable<StableHashingContext<'a>> for hir::Visibility {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -750,9 +750,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Visibility {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Defaultness { impl<'a> HashStable<StableHashingContext<'a>> for hir::Defaultness {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -771,9 +771,9 @@ impl_stable_hash_for!(enum hir::ImplPolarity {
Negative Negative
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Mod { impl<'a> HashStable<StableHashingContext<'a>> for hir::Mod {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let hir::Mod { let hir::Mod {
inner, inner,
@ -826,9 +826,9 @@ impl_stable_hash_for!(enum hir::VariantData {
Unit(id) Unit(id)
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Item { impl<'a> HashStable<StableHashingContext<'a>> for hir::Item {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let hir::Item { let hir::Item {
name, name,
@ -885,10 +885,10 @@ impl_stable_hash_for!(struct hir::ImplItemRef {
defaultness defaultness
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a> HashStable<StableHashingContext<'a>>
for hir::AssociatedItemKind { for hir::AssociatedItemKind {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -930,9 +930,9 @@ impl_stable_hash_for!(struct hir::Arg {
hir_id hir_id
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Body { impl<'a> HashStable<StableHashingContext<'a>> for hir::Body {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let hir::Body { let hir::Body {
ref arguments, ref arguments,
@ -948,12 +948,12 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Body {
} }
} }
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for hir::BodyId { impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::BodyId {
type KeyType = (DefPathHash, hir::ItemLocalId); type KeyType = (DefPathHash, hir::ItemLocalId);
#[inline] #[inline]
fn to_stable_hash_key(&self, fn to_stable_hash_key(&self,
hcx: &StableHashingContext<'gcx>) hcx: &StableHashingContext<'a>)
-> (DefPathHash, hir::ItemLocalId) { -> (DefPathHash, hir::ItemLocalId) {
let hir::BodyId { node_id } = *self; let hir::BodyId { node_id } = *self;
node_id.to_stable_hash_key(hcx) node_id.to_stable_hash_key(hcx)
@ -966,9 +966,9 @@ impl_stable_hash_for!(struct hir::InlineAsmOutput {
is_indirect is_indirect
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::GlobalAsm { impl<'a> HashStable<StableHashingContext<'a>> for hir::GlobalAsm {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let hir::GlobalAsm { let hir::GlobalAsm {
asm, asm,
@ -979,9 +979,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::GlobalAsm {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::InlineAsm { impl<'a> HashStable<StableHashingContext<'a>> for hir::InlineAsm {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let hir::InlineAsm { let hir::InlineAsm {
asm, asm,
@ -1062,22 +1062,22 @@ impl_stable_hash_for!(enum hir::Constness {
NotConst NotConst
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a> HashStable<StableHashingContext<'a>>
for hir::def_id::DefIndex { for hir::def_id::DefIndex {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
hcx.local_def_path_hash(*self).hash_stable(hcx, hasher); hcx.local_def_path_hash(*self).hash_stable(hcx, hasher);
} }
} }
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> impl<'a> ToStableHashKey<StableHashingContext<'a>>
for hir::def_id::DefIndex { for hir::def_id::DefIndex {
type KeyType = DefPathHash; type KeyType = DefPathHash;
#[inline] #[inline]
fn to_stable_hash_key(&self, hcx: &StableHashingContext<'gcx>) -> DefPathHash { fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
hcx.local_def_path_hash(*self) hcx.local_def_path_hash(*self)
} }
} }
@ -1090,10 +1090,10 @@ impl_stable_hash_for!(struct hir::def::Export {
is_import is_import
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a> HashStable<StableHashingContext<'a>>
for ::middle::lang_items::LangItem { for ::middle::lang_items::LangItem {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
_: &mut StableHashingContext<'gcx>, _: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
::std::hash::Hash::hash(self, hasher); ::std::hash::Hash::hash(self, hasher);
} }
@ -1104,10 +1104,10 @@ impl_stable_hash_for!(struct ::middle::lang_items::LanguageItems {
missing missing
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a> HashStable<StableHashingContext<'a>>
for hir::TraitCandidate { for hir::TraitCandidate {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
let hir::TraitCandidate { let hir::TraitCandidate {
@ -1121,11 +1121,11 @@ for hir::TraitCandidate {
} }
} }
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for hir::TraitCandidate { impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
type KeyType = (DefPathHash, Option<(DefPathHash, hir::ItemLocalId)>); type KeyType = (DefPathHash, Option<(DefPathHash, hir::ItemLocalId)>);
fn to_stable_hash_key(&self, fn to_stable_hash_key(&self,
hcx: &StableHashingContext<'gcx>) hcx: &StableHashingContext<'a>)
-> Self::KeyType { -> Self::KeyType {
let hir::TraitCandidate { let hir::TraitCandidate {
def_id, def_id,

View file

@ -35,11 +35,11 @@ impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator,
impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, kind }); impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, kind });
impl_stable_hash_for!(struct mir::UnsafetyCheckResult { violations, unsafe_blocks }); impl_stable_hash_for!(struct mir::UnsafetyCheckResult { violations, unsafe_blocks });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a> HashStable<StableHashingContext<'a>>
for mir::BorrowKind { for mir::BorrowKind {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
@ -54,11 +54,11 @@ for mir::BorrowKind {
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a> HashStable<StableHashingContext<'a>>
for mir::UnsafetyViolationKind { for mir::UnsafetyViolationKind {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
@ -79,12 +79,12 @@ impl_stable_hash_for!(struct mir::Terminator<'tcx> {
source_info source_info
}); });
impl<'gcx, T> HashStable<StableHashingContext<'gcx>> for mir::ClearCrossCrate<T> impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>> for mir::ClearCrossCrate<T>
where T: HashStable<StableHashingContext<'gcx>> where T: HashStable<StableHashingContext<'a>>
{ {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -96,61 +96,61 @@ impl<'gcx, T> HashStable<StableHashingContext<'gcx>> for mir::ClearCrossCrate<T>
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Local { impl<'a> HashStable<StableHashingContext<'a>> for mir::Local {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
self.index().hash_stable(hcx, hasher); self.index().hash_stable(hcx, hasher);
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::BasicBlock { impl<'a> HashStable<StableHashingContext<'a>> for mir::BasicBlock {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
self.index().hash_stable(hcx, hasher); self.index().hash_stable(hcx, hasher);
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Field { impl<'a> HashStable<StableHashingContext<'a>> for mir::Field {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
self.index().hash_stable(hcx, hasher); self.index().hash_stable(hcx, hasher);
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a> HashStable<StableHashingContext<'a>>
for mir::VisibilityScope { for mir::VisibilityScope {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
self.index().hash_stable(hcx, hasher); self.index().hash_stable(hcx, hasher);
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Promoted { impl<'a> HashStable<StableHashingContext<'a>> for mir::Promoted {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
self.index().hash_stable(hcx, hasher); self.index().hash_stable(hcx, hasher);
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for mir::TerminatorKind<'gcx> { for mir::TerminatorKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
@ -227,10 +227,10 @@ for mir::TerminatorKind<'gcx> {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for mir::AssertMessage<'gcx> { for mir::AssertMessage<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
@ -250,10 +250,10 @@ for mir::AssertMessage<'gcx> {
impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind }); impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for mir::StatementKind<'gcx> { for mir::StatementKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
@ -287,12 +287,12 @@ for mir::StatementKind<'gcx> {
} }
} }
impl<'gcx, T> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>>
for mir::ValidationOperand<'gcx, T> for mir::ValidationOperand<'gcx, T>
where T: HashStable<StableHashingContext<'gcx>> where T: HashStable<StableHashingContext<'a>>
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) hasher: &mut StableHasher<W>)
{ {
self.place.hash_stable(hcx, hasher); self.place.hash_stable(hcx, hasher);
@ -304,9 +304,9 @@ impl<'gcx, T> HashStable<StableHashingContext<'gcx>>
impl_stable_hash_for!(enum mir::ValidationOp { Acquire, Release, Suspend(region_scope) }); impl_stable_hash_for!(enum mir::ValidationOp { Acquire, Release, Suspend(region_scope) });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Place<'gcx> { impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Place<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -323,14 +323,14 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Place<'gcx> {
} }
} }
impl<'gcx, B, V, T> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, B, V, T> HashStable<StableHashingContext<'a>>
for mir::Projection<'gcx, B, V, T> for mir::Projection<'gcx, B, V, T>
where B: HashStable<StableHashingContext<'gcx>>, where B: HashStable<StableHashingContext<'a>>,
V: HashStable<StableHashingContext<'gcx>>, V: HashStable<StableHashingContext<'a>>,
T: HashStable<StableHashingContext<'gcx>> T: HashStable<StableHashingContext<'a>>
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let mir::Projection { let mir::Projection {
ref base, ref base,
@ -342,13 +342,13 @@ for mir::Projection<'gcx, B, V, T>
} }
} }
impl<'gcx, V, T> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, V, T> HashStable<StableHashingContext<'a>>
for mir::ProjectionElem<'gcx, V, T> for mir::ProjectionElem<'gcx, V, T>
where V: HashStable<StableHashingContext<'gcx>>, where V: HashStable<StableHashingContext<'a>>,
T: HashStable<StableHashingContext<'gcx>> T: HashStable<StableHashingContext<'a>>
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -382,9 +382,9 @@ impl_stable_hash_for!(struct mir::VisibilityScopeInfo {
lint_root, safety lint_root, safety
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Safety { impl<'a> HashStable<StableHashingContext<'a>> for mir::Safety {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
@ -399,9 +399,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Safety {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Operand<'gcx> { impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Operand<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
@ -419,9 +419,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Operand<'gcx> {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Rvalue<'gcx> { impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Rvalue<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
@ -479,10 +479,10 @@ impl_stable_hash_for!(enum mir::CastKind {
Unsize Unsize
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for mir::AggregateKind<'gcx> { for mir::AggregateKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -541,9 +541,9 @@ impl_stable_hash_for!(enum mir::NullOp {
impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal }); impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Literal<'gcx> { impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Literal<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -570,9 +570,9 @@ impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement<'tcx> {
blame_span blame_span
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::ClosureOutlivesSubject<'gcx> { impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::ClosureOutlivesSubject<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -585,3 +585,5 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::ClosureOutlivesSubjec
} }
} }
} }
impl_stable_hash_for!(struct mir::interpret::GlobalId<'tcx> { instance, promoted });

View file

@ -29,42 +29,42 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey,
StableHasher, StableHasherResult}; StableHasher, StableHasherResult};
use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::accumulate_vec::AccumulateVec;
impl<'gcx> HashStable<StableHashingContext<'gcx>> for InternedString { impl<'a> HashStable<StableHashingContext<'a>> for InternedString {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let s: &str = &**self; let s: &str = &**self;
s.hash_stable(hcx, hasher); s.hash_stable(hcx, hasher);
} }
} }
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for InternedString { impl<'a> ToStableHashKey<StableHashingContext<'a>> for InternedString {
type KeyType = InternedString; type KeyType = InternedString;
#[inline] #[inline]
fn to_stable_hash_key(&self, fn to_stable_hash_key(&self,
_: &StableHashingContext<'gcx>) _: &StableHashingContext<'a>)
-> InternedString { -> InternedString {
self.clone() self.clone()
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Name { impl<'a> HashStable<StableHashingContext<'a>> for ast::Name {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
self.as_str().hash_stable(hcx, hasher); self.as_str().hash_stable(hcx, hasher);
} }
} }
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for ast::Name { impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::Name {
type KeyType = InternedString; type KeyType = InternedString;
#[inline] #[inline]
fn to_stable_hash_key(&self, fn to_stable_hash_key(&self,
_: &StableHashingContext<'gcx>) _: &StableHashingContext<'a>)
-> InternedString { -> InternedString {
self.as_str() self.as_str()
} }
@ -111,10 +111,10 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
rustc_const_unstable rustc_const_unstable
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a> HashStable<StableHashingContext<'a>>
for ::syntax::attr::StabilityLevel { for ::syntax::attr::StabilityLevel {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -166,9 +166,9 @@ impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, span, ident });
impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) }); impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) });
impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner }); impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for [ast::Attribute] { impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
if self.len() == 0 { if self.len() == 0 {
self.len().hash_stable(hcx, hasher); self.len().hash_stable(hcx, hasher);
@ -191,9 +191,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for [ast::Attribute] {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Attribute { impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
// Make sure that these have been filtered out. // Make sure that these have been filtered out.
debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true)); debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true));
@ -220,10 +220,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Attribute {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a> HashStable<StableHashingContext<'a>>
for tokenstream::TokenTree { for tokenstream::TokenTree {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -242,10 +242,10 @@ for tokenstream::TokenTree {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a> HashStable<StableHashingContext<'a>>
for tokenstream::TokenStream { for tokenstream::TokenStream {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
for sub_tt in self.trees() { for sub_tt in self.trees() {
sub_tt.hash_stable(hcx, hasher); sub_tt.hash_stable(hcx, hasher);
@ -253,9 +253,11 @@ for tokenstream::TokenStream {
} }
} }
fn hash_token<'gcx, W: StableHasherResult>(token: &token::Token, fn hash_token<'a, 'gcx, W: StableHasherResult>(
hcx: &mut StableHashingContext<'gcx>, token: &token::Token,
hasher: &mut StableHasher<W>) { hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>,
) {
mem::discriminant(token).hash_stable(hcx, hasher); mem::discriminant(token).hash_stable(hcx, hasher);
match *token { match *token {
token::Token::Eq | token::Token::Eq |
@ -383,9 +385,9 @@ impl_stable_hash_for!(enum ::syntax_pos::FileName {
Custom(s) Custom(s)
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for FileMap { impl<'a> HashStable<StableHashingContext<'a>> for FileMap {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let FileMap { let FileMap {
name: _, // We hash the smaller name_hash instead of this name: _, // We hash the smaller name_hash instead of this

View file

@ -21,12 +21,13 @@ use std::mem;
use middle::region; use middle::region;
use traits; use traits;
use ty; use ty;
use mir;
impl<'gcx, T> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>>
for &'gcx ty::Slice<T> for &'gcx ty::Slice<T>
where T: HashStable<StableHashingContext<'gcx>> { where T: HashStable<StableHashingContext<'a>> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
thread_local! { thread_local! {
static CACHE: RefCell<FxHashMap<(usize, usize), Fingerprint>> = static CACHE: RefCell<FxHashMap<(usize, usize), Fingerprint>> =
@ -51,19 +52,19 @@ for &'gcx ty::Slice<T>
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ty::subst::Kind<'gcx> { for ty::subst::Kind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
self.unpack().hash_stable(hcx, hasher); self.unpack().hash_stable(hcx, hasher);
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ty::subst::UnpackedKind<'gcx> { for ty::subst::UnpackedKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
match self { match self {
ty::subst::UnpackedKind::Lifetime(lt) => lt.hash_stable(hcx, hasher), ty::subst::UnpackedKind::Lifetime(lt) => lt.hash_stable(hcx, hasher),
@ -72,10 +73,10 @@ for ty::subst::UnpackedKind<'gcx> {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a> HashStable<StableHashingContext<'a>>
for ty::RegionKind { for ty::RegionKind {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -119,20 +120,20 @@ for ty::RegionKind {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::RegionVid { impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionVid {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
self.index().hash_stable(hcx, hasher); self.index().hash_stable(hcx, hasher);
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ty::adjustment::AutoBorrow<'gcx> { for ty::adjustment::AutoBorrow<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -147,10 +148,10 @@ for ty::adjustment::AutoBorrow<'gcx> {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ty::adjustment::Adjust<'gcx> { for ty::adjustment::Adjust<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -196,10 +197,10 @@ impl_stable_hash_for!(enum ty::BorrowKind {
MutBorrow MutBorrow
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ty::UpvarCapture<'gcx> { for ty::UpvarCapture<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -223,11 +224,11 @@ impl_stable_hash_for!(struct ty::FnSig<'tcx> {
abi abi
}); });
impl<'gcx, T> HashStable<StableHashingContext<'gcx>> for ty::Binder<T> impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>> for ty::Binder<T>
where T: HashStable<StableHashingContext<'gcx>> where T: HashStable<StableHashingContext<'a>>
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let ty::Binder(ref inner) = *self; let ty::Binder(ref inner) = *self;
inner.hash_stable(hcx, hasher); inner.hash_stable(hcx, hasher);
@ -246,13 +247,13 @@ impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs });
impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref }); impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref });
impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b }); impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b });
impl<'gcx, A, B> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, A, B> HashStable<StableHashingContext<'a>>
for ty::OutlivesPredicate<A, B> for ty::OutlivesPredicate<A, B>
where A: HashStable<StableHashingContext<'gcx>>, where A: HashStable<StableHashingContext<'a>>,
B: HashStable<StableHashingContext<'gcx>>, B: HashStable<StableHashingContext<'a>>,
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let ty::OutlivesPredicate(ref a, ref b) = *self; let ty::OutlivesPredicate(ref a, ref b) = *self;
a.hash_stable(hcx, hasher); a.hash_stable(hcx, hasher);
@ -264,9 +265,9 @@ impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty }
impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { substs, item_def_id }); impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { substs, item_def_id });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Predicate<'gcx> { impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::Predicate<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -304,9 +305,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Predicate<'gcx> {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::AdtFlags { impl<'a> HashStable<StableHashingContext<'a>> for ty::AdtFlags {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
_: &mut StableHashingContext<'gcx>, _: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
std_hash::Hash::hash(self, hasher); std_hash::Hash::hash(self, hasher);
} }
@ -331,69 +332,102 @@ impl_stable_hash_for!(struct ty::FieldDef {
vis vis
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ::middle::const_val::ConstVal<'gcx> { for ::middle::const_val::ConstVal<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use middle::const_val::ConstVal::*; use middle::const_val::ConstVal::*;
use middle::const_val::ConstAggregate::*;
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
Integral(ref value) => {
value.hash_stable(hcx, hasher);
}
Float(ref value) => {
value.hash_stable(hcx, hasher);
}
Str(ref value) => {
value.hash_stable(hcx, hasher);
}
ByteStr(ref value) => {
value.hash_stable(hcx, hasher);
}
Bool(value) => {
value.hash_stable(hcx, hasher);
}
Char(value) => {
value.hash_stable(hcx, hasher);
}
Variant(def_id) => {
def_id.hash_stable(hcx, hasher);
}
Function(def_id, substs) => {
def_id.hash_stable(hcx, hasher);
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
substs.hash_stable(hcx, hasher);
});
}
Aggregate(Struct(ref name_values)) => {
let mut values = name_values.to_vec();
values.sort_unstable_by_key(|&(ref name, _)| name.clone());
values.hash_stable(hcx, hasher);
}
Aggregate(Tuple(ref value)) => {
value.hash_stable(hcx, hasher);
}
Aggregate(Array(ref value)) => {
value.hash_stable(hcx, hasher);
}
Aggregate(Repeat(ref value, times)) => {
value.hash_stable(hcx, hasher);
times.hash_stable(hcx, hasher);
}
Unevaluated(def_id, substs) => { Unevaluated(def_id, substs) => {
def_id.hash_stable(hcx, hasher); def_id.hash_stable(hcx, hasher);
substs.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher);
} }
Value(ref value) => {
value.hash_stable(hcx, hasher);
}
} }
} }
} }
impl_stable_hash_for!(struct ::middle::const_val::ByteArray<'tcx> { impl_stable_hash_for!(enum mir::interpret::Value {
data ByVal(v),
ByValPair(a, b),
ByRef(ptr, align)
});
impl_stable_hash_for!(struct mir::interpret::MemoryPointer {
alloc_id,
offset
});
enum AllocDiscriminant {
Static,
Constant,
Function,
}
impl_stable_hash_for!(enum self::AllocDiscriminant {
Static,
Constant,
Function
});
impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId {
fn hash_stable<W: StableHasherResult>(
&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>,
) {
ty::tls::with_opt(|tcx| {
let tcx = tcx.expect("can't hash AllocIds during hir lowering");
if let Some(def_id) = tcx.interpret_interner.get_corresponding_static_def_id(*self) {
AllocDiscriminant::Static.hash_stable(hcx, hasher);
// statics are unique via their DefId
def_id.hash_stable(hcx, hasher);
} else if let Some(alloc) = tcx.interpret_interner.get_alloc(*self) {
// not a static, can't be recursive, hash the allocation
AllocDiscriminant::Constant.hash_stable(hcx, hasher);
alloc.hash_stable(hcx, hasher);
} else if let Some(inst) = tcx.interpret_interner.get_fn(*self) {
AllocDiscriminant::Function.hash_stable(hcx, hasher);
inst.hash_stable(hcx, hasher);
} else {
bug!("no allocation for {}", self);
}
});
}
}
impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::Allocation {
fn hash_stable<W: StableHasherResult>(
&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>,
) {
self.bytes.hash_stable(hcx, hasher);
for reloc in self.relocations.iter() {
reloc.hash_stable(hcx, hasher);
}
self.undef_mask.hash_stable(hcx, hasher);
self.align.hash_stable(hcx, hasher);
self.runtime_mutability.hash_stable(hcx, hasher);
}
}
impl_stable_hash_for!(enum ::syntax::ast::Mutability {
Immutable,
Mutable
});
impl_stable_hash_for!(struct mir::interpret::Pointer{primval});
impl_stable_hash_for!(enum mir::interpret::PrimVal {
Bytes(b),
Ptr(p),
Undef
}); });
impl_stable_hash_for!(struct ty::Const<'tcx> { impl_stable_hash_for!(struct ty::Const<'tcx> {
@ -406,26 +440,22 @@ impl_stable_hash_for!(struct ::middle::const_val::ConstEvalErr<'tcx> {
kind kind
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl_stable_hash_for!(struct ::middle::const_val::FrameInfo {
span,
location
});
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ::middle::const_val::ErrKind<'gcx> { for ::middle::const_val::ErrKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use middle::const_val::ErrKind::*; use middle::const_val::ErrKind::*;
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
CannotCast |
MissingStructField |
NonConstPath | NonConstPath |
ExpectedConstTuple |
ExpectedConstStruct |
IndexedNonVec |
IndexNotUsize |
MiscBinaryOp |
MiscCatchAll |
IndexOpFeatureGated |
TypeckError | TypeckError |
CheckMatchError => { CheckMatchError => {
// nothing to do // nothing to do
@ -443,9 +473,10 @@ for ::middle::const_val::ErrKind<'gcx> {
LayoutError(ref layout_error) => { LayoutError(ref layout_error) => {
layout_error.hash_stable(hcx, hasher); layout_error.hash_stable(hcx, hasher);
} }
ErroneousReferencedConstant(ref const_val) => { Miri(ref err, ref trace) => {
const_val.hash_stable(hcx, hasher); err.hash_stable(hcx, hasher);
} trace.hash_stable(hcx, hasher);
},
} }
} }
} }
@ -459,6 +490,167 @@ impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> {
predicates predicates
}); });
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ::mir::interpret::EvalError<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
use mir::interpret::EvalErrorKind::*;
mem::discriminant(&self.kind).hash_stable(hcx, hasher);
match self.kind {
DanglingPointerDeref |
DoubleFree |
InvalidMemoryAccess |
InvalidFunctionPointer |
InvalidBool |
InvalidDiscriminant |
InvalidNullPointerUsage |
ReadPointerAsBytes |
ReadBytesAsPointer |
InvalidPointerMath |
ReadUndefBytes |
DeadLocal |
ExecutionTimeLimitReached |
StackFrameLimitReached |
OutOfTls |
TlsOutOfBounds |
CalledClosureAsFunction |
VtableForArgumentlessMethod |
ModifiedConstantMemory |
AssumptionNotHeld |
InlineAsm |
ReallocateNonBasePtr |
DeallocateNonBasePtr |
HeapAllocZeroBytes |
Unreachable |
Panic |
ReadFromReturnPointer |
UnimplementedTraitSelection |
TypeckError |
DerefFunctionPointer |
ExecuteMemory |
ReferencedConstant |
OverflowingMath => {}
MachineError(ref err) => err.hash_stable(hcx, hasher),
FunctionPointerTyMismatch(a, b) => {
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher)
},
NoMirFor(ref s) => s.hash_stable(hcx, hasher),
UnterminatedCString(ptr) => ptr.hash_stable(hcx, hasher),
PointerOutOfBounds {
ptr,
access,
allocation_size,
} => {
ptr.hash_stable(hcx, hasher);
access.hash_stable(hcx, hasher);
allocation_size.hash_stable(hcx, hasher)
},
InvalidBoolOp(bop) => bop.hash_stable(hcx, hasher),
Unimplemented(ref s) => s.hash_stable(hcx, hasher),
ArrayIndexOutOfBounds(sp, a, b) => {
sp.hash_stable(hcx, hasher);
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher)
},
Math(sp, ref err) => {
sp.hash_stable(hcx, hasher);
err.hash_stable(hcx, hasher)
},
Intrinsic(ref s) => s.hash_stable(hcx, hasher),
InvalidChar(c) => c.hash_stable(hcx, hasher),
AbiViolation(ref s) => s.hash_stable(hcx, hasher),
AlignmentCheckFailed {
required,
has,
} => {
required.hash_stable(hcx, hasher);
has.hash_stable(hcx, hasher)
},
MemoryLockViolation {
ptr,
len,
frame,
access,
ref lock,
} => {
ptr.hash_stable(hcx, hasher);
len.hash_stable(hcx, hasher);
frame.hash_stable(hcx, hasher);
access.hash_stable(hcx, hasher);
lock.hash_stable(hcx, hasher)
},
MemoryAcquireConflict {
ptr,
len,
kind,
ref lock,
} => {
ptr.hash_stable(hcx, hasher);
len.hash_stable(hcx, hasher);
kind.hash_stable(hcx, hasher);
lock.hash_stable(hcx, hasher)
},
InvalidMemoryLockRelease {
ptr,
len,
frame,
ref lock,
} => {
ptr.hash_stable(hcx, hasher);
len.hash_stable(hcx, hasher);
frame.hash_stable(hcx, hasher);
lock.hash_stable(hcx, hasher)
},
DeallocatedLockedMemory {
ptr,
ref lock,
} => {
ptr.hash_stable(hcx, hasher);
lock.hash_stable(hcx, hasher)
},
ValidationFailure(ref s) => s.hash_stable(hcx, hasher),
TypeNotPrimitive(ty) => ty.hash_stable(hcx, hasher),
ReallocatedWrongMemoryKind(ref a, ref b) => {
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher)
},
DeallocatedWrongMemoryKind(ref a, ref b) => {
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher)
},
IncorrectAllocationInformation(a, b, c, d) => {
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher);
c.hash_stable(hcx, hasher);
d.hash_stable(hcx, hasher)
},
Layout(lay) => lay.hash_stable(hcx, hasher),
HeapAllocNonPowerOfTwoAlignment(n) => n.hash_stable(hcx, hasher),
PathNotFound(ref v) => v.hash_stable(hcx, hasher),
}
}
}
impl_stable_hash_for!(enum mir::interpret::Lock {
NoLock,
WriteLock(dl),
ReadLock(v)
});
impl_stable_hash_for!(struct mir::interpret::DynamicLifetime {
frame,
region
});
impl_stable_hash_for!(enum mir::interpret::AccessKind {
Read,
Write
});
impl_stable_hash_for!(enum ty::Variance { impl_stable_hash_for!(enum ty::Variance {
Covariant, Covariant,
Invariant, Invariant,
@ -470,9 +662,9 @@ impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized {
Struct(index) Struct(index)
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Generics { impl<'a> HashStable<StableHashingContext<'a>> for ty::Generics {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let ty::Generics { let ty::Generics {
parent, parent,
@ -498,10 +690,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Generics {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a> HashStable<StableHashingContext<'a>>
for ty::RegionParameterDef { for ty::RegionParameterDef {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let ty::RegionParameterDef { let ty::RegionParameterDef {
name, name,
@ -527,12 +719,12 @@ impl_stable_hash_for!(struct ty::TypeParameterDef {
synthetic synthetic
}); });
impl<'gcx, T> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>>
for ::middle::resolve_lifetime::Set1<T> for ::middle::resolve_lifetime::Set1<T>
where T: HashStable<StableHashingContext<'gcx>> where T: HashStable<StableHashingContext<'a>>
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use middle::resolve_lifetime::Set1; use middle::resolve_lifetime::Set1;
@ -583,11 +775,11 @@ impl_stable_hash_for!(enum ty::cast::CastKind {
impl_stable_hash_for!(tuple_struct ::middle::region::FirstStatementIndex { idx }); impl_stable_hash_for!(tuple_struct ::middle::region::FirstStatementIndex { idx });
impl_stable_hash_for!(struct ::middle::region::Scope { id, code }); impl_stable_hash_for!(struct ::middle::region::Scope { id, code });
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for region::Scope { impl<'a> ToStableHashKey<StableHashingContext<'a>> for region::Scope {
type KeyType = region::Scope; type KeyType = region::Scope;
#[inline] #[inline]
fn to_stable_hash_key(&self, _: &StableHashingContext<'gcx>) -> region::Scope { fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> region::Scope {
*self *self
} }
} }
@ -613,11 +805,11 @@ impl_stable_hash_for!(enum ty::BoundRegion {
BrEnv BrEnv
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ty::TypeVariants<'gcx> for ty::TypeVariants<'gcx>
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use ty::TypeVariants::*; use ty::TypeVariants::*;
@ -714,11 +906,11 @@ impl_stable_hash_for!(struct ty::TypeAndMut<'tcx> {
mutbl mutbl
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ty::ExistentialPredicate<'gcx> for ty::ExistentialPredicate<'gcx>
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
@ -751,9 +943,9 @@ impl_stable_hash_for!(struct ty::Instance<'tcx> {
substs substs
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::InstanceDef<'gcx> { impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::InstanceDef<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
@ -775,21 +967,21 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::InstanceDef<'gcx> {
ty::InstanceDef::ClosureOnceShim { call_once } => { ty::InstanceDef::ClosureOnceShim { call_once } => {
call_once.hash_stable(hcx, hasher); call_once.hash_stable(hcx, hasher);
} }
ty::InstanceDef::DropGlue(def_id, t) => { ty::InstanceDef::DropGlue(def_id, ty) => {
def_id.hash_stable(hcx, hasher); def_id.hash_stable(hcx, hasher);
t.hash_stable(hcx, hasher); ty.hash_stable(hcx, hasher);
} }
ty::InstanceDef::CloneShim(def_id, t) => { ty::InstanceDef::CloneShim(def_id, ty) => {
def_id.hash_stable(hcx, hasher); def_id.hash_stable(hcx, hasher);
t.hash_stable(hcx, hasher); ty.hash_stable(hcx, hasher);
} }
} }
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::TraitDef { impl<'a> HashStable<StableHashingContext<'a>> for ty::TraitDef {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let ty::TraitDef { let ty::TraitDef {
// We already have the def_path_hash below, no need to hash it twice // We already have the def_path_hash below, no need to hash it twice
@ -817,9 +1009,9 @@ impl_stable_hash_for!(struct ty::DtorckConstraint<'tcx> {
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::CrateVariancesMap { impl<'a> HashStable<StableHashingContext<'a>> for ty::CrateVariancesMap {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let ty::CrateVariancesMap { let ty::CrateVariancesMap {
ref variances, ref variances,
@ -853,12 +1045,12 @@ impl_stable_hash_for!(enum ty::AssociatedItemContainer {
}); });
impl<'gcx, T> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>>
for ty::steal::Steal<T> for ty::steal::Steal<T>
where T: HashStable<StableHashingContext<'gcx>> where T: HashStable<StableHashingContext<'a>>
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
self.borrow().hash_stable(hcx, hasher); self.borrow().hash_stable(hcx, hasher);
} }
@ -881,10 +1073,10 @@ impl_stable_hash_for!(enum ::middle::privacy::AccessLevel {
Public Public
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> impl<'a> HashStable<StableHashingContext<'a>>
for ::middle::privacy::AccessLevels { for ::middle::privacy::AccessLevels {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
let ::middle::privacy::AccessLevels { let ::middle::privacy::AccessLevels {
@ -911,10 +1103,10 @@ impl_stable_hash_for!(tuple_struct ::middle::reachable::ReachableSet {
reachable_set reachable_set
}); });
impl<'gcx, N> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> { for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use traits::Vtable::*; use traits::Vtable::*;
@ -933,10 +1125,10 @@ for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
} }
} }
impl<'gcx, N> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
for traits::VtableImplData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> { for traits::VtableImplData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let traits::VtableImplData { let traits::VtableImplData {
impl_def_id, impl_def_id,
@ -949,10 +1141,10 @@ for traits::VtableImplData<'gcx, N> where N: HashStable<StableHashingContext<'gc
} }
} }
impl<'gcx, N> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
for traits::VtableAutoImplData<N> where N: HashStable<StableHashingContext<'gcx>> { for traits::VtableAutoImplData<N> where N: HashStable<StableHashingContext<'a>> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let traits::VtableAutoImplData { let traits::VtableAutoImplData {
trait_def_id, trait_def_id,
@ -963,10 +1155,10 @@ for traits::VtableAutoImplData<N> where N: HashStable<StableHashingContext<'gcx>
} }
} }
impl<'gcx, N> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
for traits::VtableObjectData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> { for traits::VtableObjectData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let traits::VtableObjectData { let traits::VtableObjectData {
upcast_trait_ref, upcast_trait_ref,
@ -979,10 +1171,10 @@ for traits::VtableObjectData<'gcx, N> where N: HashStable<StableHashingContext<'
} }
} }
impl<'gcx, N> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
for traits::VtableBuiltinData<N> where N: HashStable<StableHashingContext<'gcx>> { for traits::VtableBuiltinData<N> where N: HashStable<StableHashingContext<'a>> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let traits::VtableBuiltinData { let traits::VtableBuiltinData {
ref nested, ref nested,
@ -991,10 +1183,10 @@ for traits::VtableBuiltinData<N> where N: HashStable<StableHashingContext<'gcx>>
} }
} }
impl<'gcx, N> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
for traits::VtableClosureData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> { for traits::VtableClosureData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let traits::VtableClosureData { let traits::VtableClosureData {
closure_def_id, closure_def_id,
@ -1007,10 +1199,10 @@ for traits::VtableClosureData<'gcx, N> where N: HashStable<StableHashingContext<
} }
} }
impl<'gcx, N> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
for traits::VtableFnPointerData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> { for traits::VtableFnPointerData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let traits::VtableFnPointerData { let traits::VtableFnPointerData {
fn_ty, fn_ty,
@ -1021,10 +1213,10 @@ for traits::VtableFnPointerData<'gcx, N> where N: HashStable<StableHashingContex
} }
} }
impl<'gcx, N> HashStable<StableHashingContext<'gcx>> impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> { for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let traits::VtableGeneratorData { let traits::VtableGeneratorData {
closure_def_id, closure_def_id,

View file

@ -49,6 +49,7 @@
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(drain_filter)] #![feature(drain_filter)]
#![feature(dyn_trait)] #![feature(dyn_trait)]
#![feature(entry_or_default)]
#![feature(from_ref)] #![feature(from_ref)]
#![feature(fs_read_write)] #![feature(fs_read_write)]
#![feature(i128)] #![feature(i128)]

View file

@ -20,6 +20,12 @@ use session::Session;
use session::config::Epoch; use session::config::Epoch;
use syntax::codemap::Span; use syntax::codemap::Span;
declare_lint! {
pub EXCEEDING_BITSHIFTS,
Deny,
"shift exceeds the type's number of bits"
}
declare_lint! { declare_lint! {
pub CONST_ERR, pub CONST_ERR,
Warn, Warn,
@ -263,6 +269,12 @@ declare_lint! {
Epoch::Epoch2018 Epoch::Epoch2018
} }
declare_lint! {
pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
Warn,
"floating-point literals cannot be used in patterns"
}
/// Does nothing as a lint pass, but registers some `Lint`s /// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler. /// which are used by other parts of the compiler.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -271,6 +283,8 @@ pub struct HardwiredLints;
impl LintPass for HardwiredLints { impl LintPass for HardwiredLints {
fn get_lints(&self) -> LintArray { fn get_lints(&self) -> LintArray {
lint_array!( lint_array!(
ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
EXCEEDING_BITSHIFTS,
UNUSED_IMPORTS, UNUSED_IMPORTS,
UNUSED_EXTERN_CRATES, UNUSED_EXTERN_CRATES,
UNUSED_QUALIFICATIONS, UNUSED_QUALIFICATIONS,

View file

@ -394,10 +394,10 @@ impl LintLevelMap {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for LintLevelMap { impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let LintLevelMap { let LintLevelMap {
ref sets, ref sets,

View file

@ -73,10 +73,10 @@ macro_rules! __impl_stable_hash_field {
#[macro_export] #[macro_export]
macro_rules! impl_stable_hash_for { macro_rules! impl_stable_hash_for {
(enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => { (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => {
impl<'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'tcx>> for $enum_name { impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $enum_name {
#[inline] #[inline]
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self, fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
__ctx: &mut $crate::ich::StableHashingContext<'tcx>, __ctx: &mut $crate::ich::StableHashingContext<'a>,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) { __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
use $enum_name::*; use $enum_name::*;
::std::mem::discriminant(self).hash_stable(__ctx, __hasher); ::std::mem::discriminant(self).hash_stable(__ctx, __hasher);
@ -92,10 +92,10 @@ macro_rules! impl_stable_hash_for {
} }
}; };
(struct $struct_name:path { $($field:ident),* }) => { (struct $struct_name:path { $($field:ident),* }) => {
impl<'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'tcx>> for $struct_name { impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name {
#[inline] #[inline]
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self, fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
__ctx: &mut $crate::ich::StableHashingContext<'tcx>, __ctx: &mut $crate::ich::StableHashingContext<'a>,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) { __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
let $struct_name { let $struct_name {
$(ref $field),* $(ref $field),*
@ -106,10 +106,10 @@ macro_rules! impl_stable_hash_for {
} }
}; };
(tuple_struct $struct_name:path { $($field:ident),* }) => { (tuple_struct $struct_name:path { $($field:ident),* }) => {
impl<'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'tcx>> for $struct_name { impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name {
#[inline] #[inline]
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self, fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
__ctx: &mut $crate::ich::StableHashingContext<'tcx>, __ctx: &mut $crate::ich::StableHashingContext<'a>,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) { __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
let $struct_name ( let $struct_name (
$(ref $field),* $(ref $field),*
@ -125,11 +125,11 @@ macro_rules! impl_stable_hash_for {
macro_rules! impl_stable_hash_for_spanned { macro_rules! impl_stable_hash_for_spanned {
($T:path) => ( ($T:path) => (
impl<'tcx> HashStable<StableHashingContext<'tcx>> for ::syntax::codemap::Spanned<$T> impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ::syntax::codemap::Spanned<$T>
{ {
#[inline] #[inline]
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'tcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
self.node.hash_stable(hcx, hasher); self.node.hash_stable(hcx, hasher);
self.span.hash_stable(hcx, hasher); self.span.hash_stable(hcx, hasher);

View file

@ -20,9 +20,9 @@ pub struct BorrowCheckResult {
pub used_mut_nodes: FxHashSet<HirId>, pub used_mut_nodes: FxHashSet<HirId>,
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for BorrowCheckResult { impl<'a> HashStable<StableHashingContext<'a>> for BorrowCheckResult {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let BorrowCheckResult { let BorrowCheckResult {
ref used_mut_nodes, ref used_mut_nodes,

View file

@ -8,72 +8,43 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
pub use rustc_const_math::ConstInt;
use hir::def_id::DefId; use hir::def_id::DefId;
use ty::{self, TyCtxt, layout}; use ty::{self, TyCtxt, layout};
use ty::subst::Substs; use ty::subst::Substs;
use rustc_const_math::*; use rustc_const_math::*;
use mir::interpret::{Value, PrimVal};
use errors::DiagnosticBuilder;
use graphviz::IntoCow; use graphviz::IntoCow;
use errors::DiagnosticBuilder;
use serialize::{self, Encodable, Encoder, Decodable, Decoder};
use syntax::symbol::InternedString;
use syntax::ast;
use syntax_pos::Span; use syntax_pos::Span;
use std::borrow::Cow; use std::borrow::Cow;
use std::rc::Rc;
pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>; pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>;
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
pub enum ConstVal<'tcx> { pub enum ConstVal<'tcx> {
Integral(ConstInt),
Float(ConstFloat),
Str(InternedString),
ByteStr(ByteArray<'tcx>),
Bool(bool),
Char(char),
Variant(DefId),
Function(DefId, &'tcx Substs<'tcx>),
Aggregate(ConstAggregate<'tcx>),
Unevaluated(DefId, &'tcx Substs<'tcx>), Unevaluated(DefId, &'tcx Substs<'tcx>),
} Value(Value),
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)]
pub struct ByteArray<'tcx> {
pub data: &'tcx [u8],
}
impl<'tcx> serialize::UseSpecializedDecodable for ByteArray<'tcx> {}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum ConstAggregate<'tcx> {
Struct(&'tcx [(ast::Name, &'tcx ty::Const<'tcx>)]),
Tuple(&'tcx [&'tcx ty::Const<'tcx>]),
Array(&'tcx [&'tcx ty::Const<'tcx>]),
Repeat(&'tcx ty::Const<'tcx>, u64),
}
impl<'tcx> Encodable for ConstAggregate<'tcx> {
fn encode<S: Encoder>(&self, _: &mut S) -> Result<(), S::Error> {
bug!("should never encode ConstAggregate::{:?}", self)
}
}
impl<'tcx> Decodable for ConstAggregate<'tcx> {
fn decode<D: Decoder>(_: &mut D) -> Result<Self, D::Error> {
bug!("should never decode ConstAggregate")
}
} }
impl<'tcx> ConstVal<'tcx> { impl<'tcx> ConstVal<'tcx> {
pub fn to_const_int(&self) -> Option<ConstInt> { pub fn to_raw_bits(&self) -> Option<u128> {
match *self { match *self {
ConstVal::Integral(i) => Some(i), ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)), Some(b)
ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)), },
_ => None _ => None,
}
}
pub fn unwrap_u64(&self) -> u64 {
match self.to_raw_bits() {
Some(val) => {
assert_eq!(val as u64 as u128, val);
val as u64
},
None => bug!("expected constant u64, got {:#?}", self),
} }
} }
} }
@ -81,33 +52,28 @@ impl<'tcx> ConstVal<'tcx> {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ConstEvalErr<'tcx> { pub struct ConstEvalErr<'tcx> {
pub span: Span, pub span: Span,
pub kind: ErrKind<'tcx>, pub kind: Rc<ErrKind<'tcx>>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum ErrKind<'tcx> { pub enum ErrKind<'tcx> {
CannotCast,
MissingStructField,
NonConstPath, NonConstPath,
UnimplementedConstVal(&'static str), UnimplementedConstVal(&'static str),
ExpectedConstTuple,
ExpectedConstStruct,
IndexedNonVec,
IndexNotUsize,
IndexOutOfBounds { len: u64, index: u64 }, IndexOutOfBounds { len: u64, index: u64 },
MiscBinaryOp,
MiscCatchAll,
IndexOpFeatureGated,
Math(ConstMathErr), Math(ConstMathErr),
LayoutError(layout::LayoutError<'tcx>), LayoutError(layout::LayoutError<'tcx>),
ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
TypeckError, TypeckError,
CheckMatchError, CheckMatchError,
Miri(::mir::interpret::EvalError<'tcx>, Vec<FrameInfo>),
}
#[derive(Clone, Debug)]
pub struct FrameInfo {
pub span: Span,
pub location: String,
} }
impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> { impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
@ -120,21 +86,23 @@ impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum ConstEvalErrDescription<'a> { pub enum ConstEvalErrDescription<'a, 'tcx: 'a> {
Simple(Cow<'a, str>), Simple(Cow<'a, str>),
Backtrace(&'a ::mir::interpret::EvalError<'tcx>, &'a [FrameInfo]),
} }
impl<'a> ConstEvalErrDescription<'a> { impl<'a, 'tcx> ConstEvalErrDescription<'a, 'tcx> {
/// Return a one-line description of the error, for lints and such /// Return a one-line description of the error, for lints and such
pub fn into_oneline(self) -> Cow<'a, str> { pub fn into_oneline(self) -> Cow<'a, str> {
match self { match self {
ConstEvalErrDescription::Simple(simple) => simple, ConstEvalErrDescription::Simple(simple) => simple,
ConstEvalErrDescription::Backtrace(miri, _) => format!("{}", miri).into_cow(),
} }
} }
} }
impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
pub fn description(&self) -> ConstEvalErrDescription { pub fn description(&'a self) -> ConstEvalErrDescription<'a, 'tcx> {
use self::ErrKind::*; use self::ErrKind::*;
use self::ConstEvalErrDescription::*; use self::ConstEvalErrDescription::*;
@ -145,31 +113,21 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
}) })
} }
match self.kind { match *self.kind {
CannotCast => simple!("can't cast this type"),
MissingStructField => simple!("nonexistent struct field"),
NonConstPath => simple!("non-constant path in constant expression"), NonConstPath => simple!("non-constant path in constant expression"),
UnimplementedConstVal(what) => UnimplementedConstVal(what) =>
simple!("unimplemented constant expression: {}", 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 } => { IndexOutOfBounds { len, index } => {
simple!("index out of bounds: the len is {} but the index is {}", simple!("index out of bounds: the len is {} but the index is {}",
len, index) 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()), Math(ref err) => Simple(err.description().into_cow()),
LayoutError(ref err) => Simple(err.to_string().into_cow()), LayoutError(ref err) => Simple(err.to_string().into_cow()),
ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
TypeckError => simple!("type-checking failed"), TypeckError => simple!("type-checking failed"),
CheckMatchError => simple!("match-checking failed"), CheckMatchError => simple!("match-checking failed"),
Miri(ref err, ref trace) => Backtrace(err, trace),
} }
} }
@ -179,15 +137,8 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
primary_kind: &str) primary_kind: &str)
-> DiagnosticBuilder<'gcx> -> DiagnosticBuilder<'gcx>
{ {
let mut err = self; let mut diag = struct_error(tcx, self.span, "constant evaluation error");
while let &ConstEvalErr { self.note(tcx, primary_span, primary_kind, &mut diag);
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 diag
} }
@ -201,6 +152,12 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
ConstEvalErrDescription::Simple(message) => { ConstEvalErrDescription::Simple(message) => {
diag.span_label(self.span, message); diag.span_label(self.span, message);
} }
ConstEvalErrDescription::Backtrace(miri, frames) => {
diag.span_label(self.span, format!("{}", miri));
for frame in frames {
diag.span_label(frame.span, format!("inside call to `{}`", frame.location));
}
}
} }
if !primary_span.contains(self.span) { if !primary_span.contains(self.span) {
@ -214,10 +171,25 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
primary_span: Span, primary_span: Span,
primary_kind: &str) primary_kind: &str)
{ {
match self.kind { match *self.kind {
ErrKind::TypeckError | ErrKind::CheckMatchError => return, ErrKind::TypeckError | ErrKind::CheckMatchError => return,
ErrKind::Miri(ref miri, _) => {
match miri.kind {
::mir::interpret::EvalErrorKind::TypeckError |
::mir::interpret::EvalErrorKind::Layout(_) => return,
_ => {},
}
}
_ => {} _ => {}
} }
self.struct_error(tcx, primary_span, primary_kind).emit(); self.struct_error(tcx, primary_span, primary_kind).emit();
} }
} }
pub fn struct_error<'a, 'gcx, 'tcx>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
span: Span,
msg: &str,
) -> DiagnosticBuilder<'gcx> {
struct_span_err!(tcx.sess, span, E0080, "{}", msg)
}

View file

@ -280,6 +280,7 @@ language_item_table! {
GeneratorTraitLangItem, "generator", gen_trait; GeneratorTraitLangItem, "generator", gen_trait;
EqTraitLangItem, "eq", eq_trait; EqTraitLangItem, "eq", eq_trait;
PartialOrdTraitLangItem, "partial_ord", partial_ord_trait;
OrdTraitLangItem, "ord", ord_trait; OrdTraitLangItem, "ord", ord_trait;
// A number of panic-related lang items. The `panic` item corresponds to // A number of panic-related lang items. The `panic` item corresponds to

View file

@ -913,8 +913,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
// Always promote `[T; 0]` (even when e.g. borrowed mutably). // Always promote `[T; 0]` (even when e.g. borrowed mutably).
let promotable = match expr_ty.sty { let promotable = match expr_ty.sty {
ty::TyArray(_, len) if ty::TyArray(_, len) if len.val.to_raw_bits() == Some(0) => true,
len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) => true,
_ => promotable, _ => promotable,
}; };

View file

@ -1488,9 +1488,9 @@ pub fn provide(providers: &mut Providers) {
}; };
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ScopeTree { impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let ScopeTree { let ScopeTree {
root_body, root_body,

View file

@ -35,9 +35,9 @@ impl serialize::Decodable for Cache {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for Cache { impl<'a> HashStable<StableHashingContext<'a>> for Cache {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
_: &mut StableHashingContext<'gcx>, _: &mut StableHashingContext<'a>,
_: &mut StableHasher<W>) { _: &mut StableHasher<W>) {
// do nothing // do nothing
} }

View file

@ -12,7 +12,7 @@ use rustc_const_math::ConstMathErr;
use syntax::codemap::Span; use syntax::codemap::Span;
use backtrace::Backtrace; use backtrace::Backtrace;
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct EvalError<'tcx> { pub struct EvalError<'tcx> {
pub kind: EvalErrorKind<'tcx>, pub kind: EvalErrorKind<'tcx>,
pub backtrace: Option<Backtrace>, pub backtrace: Option<Backtrace>,
@ -31,11 +31,11 @@ impl<'tcx> From<EvalErrorKind<'tcx>> for EvalError<'tcx> {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum EvalErrorKind<'tcx> { pub enum EvalErrorKind<'tcx> {
/// This variant is used by machines to signal their own errors that do not /// This variant is used by machines to signal their own errors that do not
/// match an existing variant /// match an existing variant
MachineError(Box<dyn Error>), MachineError(String),
FunctionPointerTyMismatch(FnSig<'tcx>, FnSig<'tcx>), FunctionPointerTyMismatch(FnSig<'tcx>, FnSig<'tcx>),
NoMirFor(String), NoMirFor(String),
UnterminatedCString(MemoryPointer), UnterminatedCString(MemoryPointer),
@ -65,11 +65,6 @@ pub enum EvalErrorKind<'tcx> {
Intrinsic(String), Intrinsic(String),
OverflowingMath, OverflowingMath,
InvalidChar(u128), InvalidChar(u128),
OutOfMemory {
allocation_size: u64,
memory_size: u64,
memory_usage: u64,
},
ExecutionTimeLimitReached, ExecutionTimeLimitReached,
StackFrameLimitReached, StackFrameLimitReached,
OutOfTls, OutOfTls,
@ -124,6 +119,9 @@ pub enum EvalErrorKind<'tcx> {
UnimplementedTraitSelection, UnimplementedTraitSelection,
/// Abort in case type errors are reached /// Abort in case type errors are reached
TypeckError, TypeckError,
/// Cannot compute this constant because it depends on another one
/// which already produced an error
ReferencedConstant,
} }
pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>; pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;
@ -132,7 +130,7 @@ impl<'tcx> Error for EvalError<'tcx> {
fn description(&self) -> &str { fn description(&self) -> &str {
use self::EvalErrorKind::*; use self::EvalErrorKind::*;
match self.kind { match self.kind {
MachineError(ref inner) => inner.description(), MachineError(ref inner) => inner,
FunctionPointerTyMismatch(..) => FunctionPointerTyMismatch(..) =>
"tried to call a function through a function pointer of a different type", "tried to call a function through a function pointer of a different type",
InvalidMemoryAccess => InvalidMemoryAccess =>
@ -190,10 +188,8 @@ impl<'tcx> Error for EvalError<'tcx> {
"mir not found", "mir not found",
InvalidChar(..) => InvalidChar(..) =>
"tried to interpret an invalid 32-bit value as a char", "tried to interpret an invalid 32-bit value as a char",
OutOfMemory{..} =>
"could not allocate more memory",
ExecutionTimeLimitReached => ExecutionTimeLimitReached =>
"reached the configured maximum execution time", "the expression was too complex to be evaluated or resulted in an infinite loop",
StackFrameLimitReached => StackFrameLimitReached =>
"reached the configured maximum number of stack frames", "reached the configured maximum number of stack frames",
OutOfTls => OutOfTls =>
@ -245,14 +241,8 @@ impl<'tcx> Error for EvalError<'tcx> {
"there were unresolved type arguments during trait selection", "there were unresolved type arguments during trait selection",
TypeckError => TypeckError =>
"encountered constants with type errors, stopping evaluation", "encountered constants with type errors, stopping evaluation",
} ReferencedConstant =>
} "referenced constant has errors",
fn cause(&self) -> Option<&dyn Error> {
use self::EvalErrorKind::*;
match self.kind {
MachineError(ref inner) => Some(&**inner),
_ => None,
} }
} }
} }
@ -294,15 +284,12 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
write!(f, "tried to reallocate memory from {} to {}", old, new), write!(f, "tried to reallocate memory from {} to {}", old, new),
DeallocatedWrongMemoryKind(ref old, ref new) => DeallocatedWrongMemoryKind(ref old, ref new) =>
write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new), write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
Math(span, ref err) => Math(_, ref err) =>
write!(f, "{:?} at {:?}", err, span), write!(f, "{}", err.description()),
Intrinsic(ref err) => Intrinsic(ref err) =>
write!(f, "{}", err), write!(f, "{}", err),
InvalidChar(c) => InvalidChar(c) =>
write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c), write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
OutOfMemory { allocation_size, memory_size, memory_usage } =>
write!(f, "tried to allocate {} more bytes, but only {} bytes are free of the {} byte memory",
allocation_size, memory_size - memory_usage, memory_size),
AlignmentCheckFailed { required, has } => AlignmentCheckFailed { required, has } =>
write!(f, "tried to access memory with alignment {}, but alignment {} is required", write!(f, "tried to access memory with alignment {}, but alignment {} is required",
has, required), has, required),
@ -313,7 +300,7 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
PathNotFound(ref path) => PathNotFound(ref path) =>
write!(f, "Cannot find path {:?}", path), write!(f, "Cannot find path {:?}", path),
MachineError(ref inner) => MachineError(ref inner) =>
write!(f, "machine error: {}", inner), write!(f, "{}", inner),
IncorrectAllocationInformation(size, size2, align, align2) => IncorrectAllocationInformation(size, size2, align, align2) =>
write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size, align, size2, align2), write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size, align, size2, align2),
_ => write!(f, "{}", self.description()), _ => write!(f, "{}", self.description()),

View file

@ -10,7 +10,7 @@ mod value;
pub use self::error::{EvalError, EvalResult, EvalErrorKind}; pub use self::error::{EvalError, EvalResult, EvalErrorKind};
pub use self::value::{PrimVal, PrimValKind, Value, Pointer, bytes_to_f32, bytes_to_f64}; pub use self::value::{PrimVal, PrimValKind, Value, Pointer};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt; use std::fmt;
@ -19,6 +19,7 @@ use ty;
use ty::layout::{self, Align, HasDataLayout}; use ty::layout::{self, Align, HasDataLayout};
use middle::region; use middle::region;
use std::iter; use std::iter;
use syntax::ast::Mutability;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Lock { pub enum Lock {
@ -41,7 +42,7 @@ pub enum AccessKind {
} }
/// Uniquely identifies a specific constant or static. /// Uniquely identifies a specific constant or static.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub struct GlobalId<'tcx> { pub struct GlobalId<'tcx> {
/// For a constant or static, the `Instance` of the item itself. /// For a constant or static, the `Instance` of the item itself.
/// For a promoted global, the `Instance` of the function they belong to. /// For a promoted global, the `Instance` of the function they belong to.
@ -101,7 +102,7 @@ pub trait PointerArithmetic: layout::HasDataLayout {
impl<T: layout::HasDataLayout> PointerArithmetic for T {} impl<T: layout::HasDataLayout> PointerArithmetic for T {}
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
pub struct MemoryPointer { pub struct MemoryPointer {
pub alloc_id: AllocId, pub alloc_id: AllocId,
pub offset: u64, pub offset: u64,
@ -148,13 +149,16 @@ impl<'tcx> MemoryPointer {
#[derive(Copy, Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)] #[derive(Copy, Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)]
pub struct AllocId(pub u64); pub struct AllocId(pub u64);
impl ::rustc_serialize::UseSpecializedEncodable for AllocId {}
impl ::rustc_serialize::UseSpecializedDecodable for AllocId {}
impl fmt::Display for AllocId { impl fmt::Display for AllocId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0) write!(f, "{}", self.0)
} }
} }
#[derive(Debug, Eq, PartialEq, Hash)] #[derive(Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub struct Allocation { pub struct Allocation {
/// The actual bytes of the allocation. /// The actual bytes of the allocation.
/// Note that the bytes of a pointer represent the offset of the pointer /// Note that the bytes of a pointer represent the offset of the pointer
@ -166,6 +170,10 @@ pub struct Allocation {
pub undef_mask: UndefMask, pub undef_mask: UndefMask,
/// The alignment of the allocation to detect unaligned reads. /// The alignment of the allocation to detect unaligned reads.
pub align: Align, pub align: Align,
/// Whether the allocation (of a static) should be put into mutable memory when translating
///
/// Only happens for `static mut` or `static` with interior mutability
pub runtime_mutability: Mutability,
} }
impl Allocation { impl Allocation {
@ -177,6 +185,7 @@ impl Allocation {
relocations: BTreeMap::new(), relocations: BTreeMap::new(),
undef_mask, undef_mask,
align: Align::from_bytes(1, 1).unwrap(), align: Align::from_bytes(1, 1).unwrap(),
runtime_mutability: Mutability::Immutable,
} }
} }
} }
@ -188,12 +197,14 @@ impl Allocation {
type Block = u64; type Block = u64;
const BLOCK_SIZE: u64 = 64; const BLOCK_SIZE: u64 = 64;
#[derive(Clone, Debug, Eq, PartialEq, Hash)] #[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub struct UndefMask { pub struct UndefMask {
blocks: Vec<Block>, blocks: Vec<Block>,
len: u64, len: u64,
} }
impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len});
impl UndefMask { impl UndefMask {
pub fn new(size: u64) -> Self { pub fn new(size: u64) -> Self {
let mut m = UndefMask { let mut m = UndefMask {

View file

@ -1,24 +1,9 @@
#![allow(unknown_lints)] #![allow(unknown_lints)]
use ty::layout::{Align, HasDataLayout}; use ty::layout::{Align, HasDataLayout};
use ty;
use super::{EvalResult, MemoryPointer, PointerArithmetic}; use super::{EvalResult, MemoryPointer, PointerArithmetic};
use syntax::ast::FloatTy;
use rustc_const_math::ConstFloat;
pub fn bytes_to_f32(bits: u128) -> ConstFloat {
ConstFloat {
bits,
ty: FloatTy::F32,
}
}
pub fn bytes_to_f64(bits: u128) -> ConstFloat {
ConstFloat {
bits,
ty: FloatTy::F64,
}
}
/// A `Value` represents a single self-contained Rust value. /// A `Value` represents a single self-contained Rust value.
/// ///
@ -29,13 +14,22 @@ pub fn bytes_to_f64(bits: u128) -> ConstFloat {
/// For optimization of a few very common cases, there is also a representation for a pair of /// For optimization of a few very common cases, there is also a representation for a pair of
/// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary /// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary
/// operations and fat pointers. This idea was taken from rustc's trans. /// operations and fat pointers. This idea was taken from rustc's trans.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
pub enum Value { pub enum Value {
ByRef(Pointer, Align), ByRef(Pointer, Align),
ByVal(PrimVal), ByVal(PrimVal),
ByValPair(PrimVal, PrimVal), ByValPair(PrimVal, PrimVal),
} }
impl<'tcx> ty::TypeFoldable<'tcx> for Value {
fn super_fold_with<'gcx: 'tcx, F: ty::fold::TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self {
*self
}
fn super_visit_with<V: ty::fold::TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
false
}
}
/// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally. /// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally.
/// This type clears up a few APIs where having a `PrimVal` argument for something that is /// This type clears up a few APIs where having a `PrimVal` argument for something that is
/// potentially an integer pointer or a pointer to an allocation was unclear. /// potentially an integer pointer or a pointer to an allocation was unclear.
@ -43,9 +37,9 @@ pub enum Value {
/// I (@oli-obk) believe it is less easy to mix up generic primvals and primvals that are just /// I (@oli-obk) believe it is less easy to mix up generic primvals and primvals that are just
/// the representation of pointers. Also all the sites that convert between primvals and pointers /// the representation of pointers. Also all the sites that convert between primvals and pointers
/// are explicit now (and rare!) /// are explicit now (and rare!)
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
pub struct Pointer { pub struct Pointer {
primval: PrimVal, pub primval: PrimVal,
} }
impl<'tcx> Pointer { impl<'tcx> Pointer {
@ -138,7 +132,7 @@ impl ::std::convert::From<MemoryPointer> for Pointer {
/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
/// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes /// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes
/// of a simple value, a pointer into another `Allocation`, or be undefined. /// of a simple value, a pointer into another `Allocation`, or be undefined.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
pub enum PrimVal { pub enum PrimVal {
/// The raw bytes of a simple value. /// The raw bytes of a simple value.
Bytes(u128), Bytes(u128),
@ -172,10 +166,6 @@ impl<'tcx> PrimVal {
PrimVal::Bytes(n as u128) PrimVal::Bytes(n as u128)
} }
pub fn from_float(f: ConstFloat) -> Self {
PrimVal::Bytes(f.bits)
}
pub fn from_bool(b: bool) -> Self { pub fn from_bool(b: bool) -> Self {
PrimVal::Bytes(b as u128) PrimVal::Bytes(b as u128)
} }
@ -250,14 +240,6 @@ impl<'tcx> PrimVal {
}) })
} }
pub fn to_f32(self) -> EvalResult<'tcx, ConstFloat> {
self.to_bytes().map(bytes_to_f32)
}
pub fn to_f64(self) -> EvalResult<'tcx, ConstFloat> {
self.to_bytes().map(bytes_to_f64)
}
pub fn to_bool(self) -> EvalResult<'tcx, bool> { pub fn to_bool(self) -> EvalResult<'tcx, bool> {
match self.to_bytes()? { match self.to_bytes()? {
0 => Ok(false), 0 => Ok(false),

View file

@ -15,7 +15,7 @@
use graphviz::IntoCow; use graphviz::IntoCow;
use middle::const_val::ConstVal; use middle::const_val::ConstVal;
use middle::region; use middle::region;
use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr}; use rustc_const_math::ConstMathErr;
use rustc_data_structures::sync::{Lrc}; use rustc_data_structures::sync::{Lrc};
use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators}; use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators};
@ -25,13 +25,14 @@ use rustc_serialize as serialize;
use hir::def::CtorKind; use hir::def::CtorKind;
use hir::def_id::DefId; use hir::def_id::DefId;
use mir::visit::MirVisitable; use mir::visit::MirVisitable;
use mir::interpret::{Value, PrimVal};
use ty::subst::{Subst, Substs}; use ty::subst::{Subst, Substs};
use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior}; use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use ty::TypeAndMut;
use util::ppaux; use util::ppaux;
use std::slice; use std::slice;
use hir::{self, InlineAsm}; use hir::{self, InlineAsm};
use std::ascii;
use std::borrow::{Cow}; use std::borrow::{Cow};
use std::cell::Ref; use std::cell::Ref;
use std::fmt::{self, Debug, Formatter, Write}; use std::fmt::{self, Debug, Formatter, Write};
@ -707,7 +708,7 @@ pub enum TerminatorKind<'tcx> {
/// Possible values. The locations to branch to in each case /// Possible values. The locations to branch to in each case
/// are found in the corresponding indices from the `targets` vector. /// are found in the corresponding indices from the `targets` vector.
values: Cow<'tcx, [ConstInt]>, values: Cow<'tcx, [u128]>,
/// Possible branch sites. The last element of this vector is used /// Possible branch sites. The last element of this vector is used
/// for the otherwise branch, so targets.len() == values.len() + 1 /// for the otherwise branch, so targets.len() == values.len() + 1
@ -858,7 +859,7 @@ impl<'tcx> Terminator<'tcx> {
impl<'tcx> TerminatorKind<'tcx> { impl<'tcx> TerminatorKind<'tcx> {
pub fn if_<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>, pub fn if_<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>,
t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> { t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)]; static BOOL_SWITCH_FALSE: &'static [u128] = &[0];
TerminatorKind::SwitchInt { TerminatorKind::SwitchInt {
discr: cond, discr: cond,
switch_ty: tcx.types.bool, switch_ty: tcx.types.bool,
@ -1144,12 +1145,16 @@ impl<'tcx> TerminatorKind<'tcx> {
match *self { match *self {
Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
Goto { .. } => vec!["".into()], Goto { .. } => vec!["".into()],
SwitchInt { ref values, .. } => { SwitchInt { ref values, switch_ty, .. } => {
values.iter() values.iter()
.map(|const_val| { .map(|&u| {
let mut buf = String::new(); let mut s = String::new();
fmt_const_val(&mut buf, &ConstVal::Integral(*const_val)).unwrap(); print_miri_value(
buf.into() Value::ByVal(PrimVal::Bytes(u)),
switch_ty,
&mut s,
).unwrap();
s.into()
}) })
.chain(iter::once(String::from("otherwise").into())) .chain(iter::once(String::from("otherwise").into()))
.collect() .collect()
@ -1533,7 +1538,8 @@ impl<'tcx> Operand<'tcx> {
ty, ty,
literal: Literal::Value { literal: Literal::Value {
value: tcx.mk_const(ty::Const { value: tcx.mk_const(ty::Const {
val: ConstVal::Function(def_id, substs), // ZST function type
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
ty ty
}) })
}, },
@ -1557,7 +1563,7 @@ pub enum Rvalue<'tcx> {
Use(Operand<'tcx>), Use(Operand<'tcx>),
/// [x; 32] /// [x; 32]
Repeat(Operand<'tcx>, ConstUsize), Repeat(Operand<'tcx>, u64),
/// &x or &mut x /// &x or &mut x
Ref(Region<'tcx>, BorrowKind, Place<'tcx>), Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
@ -1853,7 +1859,7 @@ impl<'tcx> Debug for Literal<'tcx> {
match *self { match *self {
Value { value } => { Value { value } => {
write!(fmt, "const ")?; write!(fmt, "const ")?;
fmt_const_val(fmt, &value.val) fmt_const_val(fmt, value)
} }
Promoted { index } => { Promoted { index } => {
write!(fmt, "{:?}", index) write!(fmt, "{:?}", index)
@ -1863,25 +1869,47 @@ impl<'tcx> Debug for Literal<'tcx> {
} }
/// Write a `ConstVal` in a way closer to the original source code than the `Debug` output. /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
use middle::const_val::ConstVal::*; use middle::const_val::ConstVal::*;
match *const_val { match const_val.val {
Float(f) => write!(fmt, "{:?}", f), Unevaluated(..) => write!(fmt, "{:?}", const_val),
Integral(n) => write!(fmt, "{}", n), Value(val) => print_miri_value(val, const_val.ty, fmt),
Str(s) => write!(fmt, "{:?}", s), }
ByteStr(bytes) => { }
let escaped: String = bytes.data
.iter() pub fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Result {
.flat_map(|&ch| ascii::escape_default(ch).map(|c| c as char)) use ty::TypeVariants::*;
.collect(); use rustc_const_math::ConstFloat;
write!(fmt, "b\"{}\"", escaped) match (value, &ty.sty) {
} (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
Bool(b) => write!(fmt, "{:?}", b), (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
Char(c) => write!(fmt, "{:?}", c), (Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(fty)) =>
Variant(def_id) | write!(f, "{}", ConstFloat { bits, ty: fty }),
Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), (Value::ByVal(PrimVal::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui),
Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val), (Value::ByVal(PrimVal::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i),
Unevaluated(..) => write!(fmt, "{:?}", const_val) (Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
(Value::ByVal(PrimVal::Undef), &TyFnDef(did, _)) =>
write!(f, "{}", item_path_str(did)),
(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len)), &TyRef(_, TypeAndMut {
ty: &ty::TyS { sty: TyStr, .. }, ..
})) => {
ty::tls::with(|tcx| {
let alloc = tcx
.interpret_interner
.get_alloc(ptr.alloc_id);
if let Some(alloc) = alloc {
assert_eq!(len as usize as u128, len);
let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)];
let s = ::std::str::from_utf8(slice)
.expect("non utf8 str from miri");
write!(f, "{:?}", s)
} else {
write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len)
}
})
},
_ => write!(f, "{:?}:{}", value, ty),
} }
} }
@ -2467,6 +2495,15 @@ impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<'tcx, B, V, T>
} }
} }
impl<'tcx> TypeFoldable<'tcx> for Field {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self {
*self
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
false
}
}
impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
Constant { Constant {

View file

@ -41,9 +41,9 @@ impl<'tcx> MonoItem<'tcx> {
} }
} }
impl<'tcx> HashStable<StableHashingContext<'tcx>> for MonoItem<'tcx> { impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'tcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
::std::mem::discriminant(self).hash_stable(hcx, hasher); ::std::mem::discriminant(self).hash_stable(hcx, hasher);
@ -171,9 +171,9 @@ impl<'tcx> CodegenUnit<'tcx> {
} }
} }
impl<'tcx> HashStable<StableHashingContext<'tcx>> for CodegenUnit<'tcx> { impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'tcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let CodegenUnit { let CodegenUnit {
ref items, ref items,

View file

@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
PlaceTy::Ty { PlaceTy::Ty {
ty: match ty.sty { ty: match ty.sty {
ty::TyArray(inner, size) => { ty::TyArray(inner, size) => {
let size = size.val.to_const_int().unwrap().to_u64().unwrap(); let size = size.val.unwrap_u64();
let len = size - (from as u64) - (to as u64); let len = size - (from as u64) - (to as u64);
tcx.mk_array(inner, len) tcx.mk_array(inner, len)
} }
@ -149,7 +149,7 @@ impl<'tcx> Rvalue<'tcx> {
match *self { match *self {
Rvalue::Use(ref operand) => operand.ty(local_decls, tcx), Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
Rvalue::Repeat(ref operand, count) => { Rvalue::Repeat(ref operand, count) => {
tcx.mk_array_const_usize(operand.ty(local_decls, tcx), count) tcx.mk_array(operand.ty(local_decls, tcx), count)
} }
Rvalue::Ref(reg, bk, ref place) => { Rvalue::Ref(reg, bk, ref place) => {
let place_ty = place.ty(local_decls, tcx).to_ty(tcx); let place_ty = place.ty(local_decls, tcx).to_ty(tcx);

View file

@ -12,7 +12,6 @@ use hir::def_id::DefId;
use ty::subst::Substs; use ty::subst::Substs;
use ty::{ClosureSubsts, Region, Ty, GeneratorInterior}; use ty::{ClosureSubsts, Region, Ty, GeneratorInterior};
use mir::*; use mir::*;
use rustc_const_math::ConstUsize;
use syntax_pos::Span; use syntax_pos::Span;
// # The MIR Visitor // # The MIR Visitor
@ -243,18 +242,6 @@ macro_rules! make_mir_visitor {
self.super_generator_interior(interior); self.super_generator_interior(interior);
} }
fn visit_const_int(&mut self,
const_int: &ConstInt,
_: Location) {
self.super_const_int(const_int);
}
fn visit_const_usize(&mut self,
const_usize: & $($mutability)* ConstUsize,
_: Location) {
self.super_const_usize(const_usize);
}
fn visit_local_decl(&mut self, fn visit_local_decl(&mut self,
local: Local, local: Local,
local_decl: & $($mutability)* LocalDecl<'tcx>) { local_decl: & $($mutability)* LocalDecl<'tcx>) {
@ -426,13 +413,10 @@ macro_rules! make_mir_visitor {
TerminatorKind::SwitchInt { ref $($mutability)* discr, TerminatorKind::SwitchInt { ref $($mutability)* discr,
ref $($mutability)* switch_ty, ref $($mutability)* switch_ty,
ref values, values: _,
ref targets } => { ref targets } => {
self.visit_operand(discr, source_location); self.visit_operand(discr, source_location);
self.visit_ty(switch_ty, TyContext::Location(source_location)); self.visit_ty(switch_ty, TyContext::Location(source_location));
for value in &values[..] {
self.visit_const_int(value, source_location);
}
for &target in targets { for &target in targets {
self.visit_branch(block, target); self.visit_branch(block, target);
} }
@ -538,10 +522,8 @@ macro_rules! make_mir_visitor {
self.visit_operand(operand, location); self.visit_operand(operand, location);
} }
Rvalue::Repeat(ref $($mutability)* value, Rvalue::Repeat(ref $($mutability)* value, _) => {
ref $($mutability)* length) => {
self.visit_operand(value, location); self.visit_operand(value, location);
self.visit_const_usize(length, location);
} }
Rvalue::Ref(ref $($mutability)* r, bk, ref $($mutability)* path) => { Rvalue::Ref(ref $($mutability)* r, bk, ref $($mutability)* path) => {
@ -798,12 +780,6 @@ macro_rules! make_mir_visitor {
_substs: & $($mutability)* ClosureSubsts<'tcx>) { _substs: & $($mutability)* ClosureSubsts<'tcx>) {
} }
fn super_const_int(&mut self, _const_int: &ConstInt) {
}
fn super_const_usize(&mut self, _const_usize: & $($mutability)* ConstUsize) {
}
// Convenience methods // Convenience methods
fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Location) { fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Location) {

View file

@ -179,10 +179,10 @@ impl_stable_hash_for!(enum self::OutputType {
DepInfo DepInfo
}); });
impl<'tcx> ToStableHashKey<StableHashingContext<'tcx>> for OutputType { impl<'a, 'tcx> ToStableHashKey<StableHashingContext<'a>> for OutputType {
type KeyType = OutputType; type KeyType = OutputType;
#[inline] #[inline]
fn to_stable_hash_key(&self, _: &StableHashingContext<'tcx>) -> Self::KeyType { fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> Self::KeyType {
*self *self
} }
} }

View file

@ -103,6 +103,11 @@ pub struct Session {
/// The maximum length of types during monomorphization. /// The maximum length of types during monomorphization.
pub type_length_limit: Cell<usize>, pub type_length_limit: Cell<usize>,
/// The maximum number of stackframes allowed in const eval
pub const_eval_stack_frame_limit: Cell<usize>,
/// The maximum number miri steps per constant
pub const_eval_step_limit: Cell<usize>,
/// The metadata::creader module may inject an allocator/panic_runtime /// The metadata::creader module may inject an allocator/panic_runtime
/// dependency if it didn't already find one, and this tracks what was /// dependency if it didn't already find one, and this tracks what was
/// injected. /// injected.
@ -1004,6 +1009,8 @@ pub fn build_session_(sopts: config::Options,
features: RefCell::new(None), features: RefCell::new(None),
recursion_limit: Cell::new(64), recursion_limit: Cell::new(64),
type_length_limit: Cell::new(1048576), type_length_limit: Cell::new(1048576),
const_eval_stack_frame_limit: Cell::new(100),
const_eval_step_limit: Cell::new(1_000_000),
next_node_id: Cell::new(NodeId::new(1)), next_node_id: Cell::new(NodeId::new(1)),
injected_allocator: Cell::new(None), injected_allocator: Cell::new(None),
allocator_kind: Cell::new(None), allocator_kind: Cell::new(None),

View file

@ -32,7 +32,6 @@ use hir;
use hir::def_id::DefId; use hir::def_id::DefId;
use infer::{self, InferCtxt}; use infer::{self, InferCtxt};
use infer::type_variable::TypeVariableOrigin; use infer::type_variable::TypeVariableOrigin;
use middle::const_val;
use std::fmt; use std::fmt;
use syntax::ast; use syntax::ast;
use session::DiagnosticMessageId; use session::DiagnosticMessageId;
@ -776,7 +775,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
} }
ConstEvalFailure(ref err) => { ConstEvalFailure(ref err) => {
if let const_val::ErrKind::TypeckError = err.kind { if let ::middle::const_val::ErrKind::TypeckError = *err.kind {
return; return;
} }
err.struct_error(self.tcx, span, "constant expression") err.struct_error(self.tcx, span, "constant expression")

View file

@ -9,12 +9,14 @@
// except according to those terms. // except according to those terms.
use infer::{RegionObligation, InferCtxt}; use infer::{RegionObligation, InferCtxt};
use mir::interpret::GlobalId;
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate}; use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
use ty::error::ExpectedFound; use ty::error::ExpectedFound;
use rustc_data_structures::obligation_forest::{ObligationForest, Error}; use rustc_data_structures::obligation_forest::{ObligationForest, Error};
use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor}; use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
use std::marker::PhantomData; use std::marker::PhantomData;
use hir::def_id::DefId; use hir::def_id::DefId;
use middle::const_val::{ConstEvalErr, ErrKind};
use super::CodeAmbiguity; use super::CodeAmbiguity;
use super::CodeProjectionError; use super::CodeProjectionError;
@ -514,17 +516,35 @@ fn process_predicate<'a, 'gcx, 'tcx>(
} }
Some(param_env) => { Some(param_env) => {
match selcx.tcx().lift_to_global(&substs) { match selcx.tcx().lift_to_global(&substs) {
Some(substs) => {
let instance = ty::Instance::resolve(
selcx.tcx().global_tcx(),
param_env,
def_id,
substs,
);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None,
};
match selcx.tcx().at(obligation.cause.span)
.const_eval(param_env.and(cid)) {
Ok(_) => Ok(Some(vec![])),
Err(err) => Err(CodeSelectionError(ConstEvalFailure(err)))
}
} else {
Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr {
span: obligation.cause.span,
kind: ErrKind::UnimplementedConstVal("could not resolve")
.into(),
})))
}
},
None => { None => {
pending_obligation.stalled_on = substs.types().collect(); pending_obligation.stalled_on = substs.types().collect();
Ok(None) Ok(None)
} }
Some(substs) => {
match selcx.tcx().at(obligation.cause.span)
.const_eval(param_env.and((def_id, substs))) {
Ok(_) => Ok(Some(vec![])),
Err(e) => Err(CodeSelectionError(ConstEvalFailure(e)))
}
}
} }
} }
} }

View file

@ -20,8 +20,8 @@ pub use self::ObligationCauseCode::*;
use hir; use hir;
use hir::def_id::DefId; use hir::def_id::DefId;
use infer::outlives::env::OutlivesEnvironment; use infer::outlives::env::OutlivesEnvironment;
use middle::const_val::ConstEvalErr;
use middle::region; use middle::region;
use middle::const_val::ConstEvalErr;
use ty::subst::Substs; use ty::subst::Substs;
use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, ToPredicate}; use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, ToPredicate};
use ty::error::{ExpectedFound, TypeError}; use ty::error::{ExpectedFound, TypeError};

View file

@ -29,6 +29,7 @@ use hir::def_id::DefId;
use infer::{InferCtxt, InferOk}; use infer::{InferCtxt, InferOk};
use infer::type_variable::TypeVariableOrigin; use infer::type_variable::TypeVariableOrigin;
use middle::const_val::ConstVal; use middle::const_val::ConstVal;
use mir::interpret::{GlobalId};
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
use syntax::symbol::Symbol; use syntax::symbol::Symbol;
use ty::subst::{Subst, Substs}; use ty::subst::{Subst, Substs};
@ -400,12 +401,17 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if let ConstVal::Unevaluated(def_id, substs) = constant.val { if let ConstVal::Unevaluated(def_id, substs) = constant.val {
if substs.needs_infer() { let tcx = self.selcx.tcx().global_tcx();
let identity_substs = Substs::identity_for_item(self.tcx(), def_id); if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) {
let data = self.param_env.and((def_id, identity_substs)); if substs.needs_infer() {
match self.tcx().lift_to_global(&data) { let identity_substs = Substs::identity_for_item(tcx, def_id);
Some(data) => { let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs);
match self.tcx().const_eval(data) { if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None
};
match tcx.const_eval(param_env.and(cid)) {
Ok(evaluated) => { Ok(evaluated) => {
let evaluated = evaluated.subst(self.tcx(), substs); let evaluated = evaluated.subst(self.tcx(), substs);
return self.fold_const(evaluated); return self.fold_const(evaluated);
@ -413,18 +419,20 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
Err(_) => {} Err(_) => {}
} }
} }
None => {} } else {
} if let Some(substs) = self.tcx().lift_to_global(&substs) {
} else { let instance = ty::Instance::resolve(tcx, param_env, def_id, substs);
let data = self.param_env.and((def_id, substs)); if let Some(instance) = instance {
match self.tcx().lift_to_global(&data) { let cid = GlobalId {
Some(data) => { instance,
match self.tcx().const_eval(data) { promoted: None
Ok(evaluated) => return self.fold_const(evaluated), };
Err(_) => {} match tcx.const_eval(param_env.and(cid)) {
Ok(evaluated) => return self.fold_const(evaluated),
Err(_) => {}
}
} }
} }
None => {}
} }
} }
} }

View file

@ -42,6 +42,7 @@ use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use ty::fast_reject; use ty::fast_reject;
use ty::relate::TypeRelation; use ty::relate::TypeRelation;
use middle::lang_items; use middle::lang_items;
use mir::interpret::{GlobalId};
use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::bitvec::BitVector;
use std::iter; use std::iter;
@ -732,11 +733,26 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
} }
ty::Predicate::ConstEvaluatable(def_id, substs) => { ty::Predicate::ConstEvaluatable(def_id, substs) => {
match self.tcx().lift_to_global(&(obligation.param_env, substs)) { let tcx = self.tcx();
match tcx.lift_to_global(&(obligation.param_env, substs)) {
Some((param_env, substs)) => { Some((param_env, substs)) => {
match self.tcx().const_eval(param_env.and((def_id, substs))) { let instance = ty::Instance::resolve(
Ok(_) => EvaluatedToOk, tcx.global_tcx(),
Err(_) => EvaluatedToErr param_env,
def_id,
substs,
);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None
};
match self.tcx().const_eval(param_env.and(cid)) {
Ok(_) => EvaluatedToOk,
Err(_) => EvaluatedToErr
}
} else {
EvaluatedToErr
} }
} }
None => { None => {

View file

@ -391,9 +391,9 @@ pub fn ancestors(tcx: TyCtxt,
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for Children { impl<'a> HashStable<StableHashingContext<'a>> for Children {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let Children { let Children {
ref nonblanket_impls, ref nonblanket_impls,

View file

@ -17,7 +17,6 @@
// persisting to incr. comp. caches. // persisting to incr. comp. caches.
use hir::def_id::{DefId, CrateNum}; use hir::def_id::{DefId, CrateNum};
use middle::const_val::ByteArray;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_serialize::{Decodable, Decoder, Encoder, Encodable, opaque}; use rustc_serialize::{Decodable, Decoder, Encoder, Encodable, opaque};
use std::hash::Hash; use std::hash::Hash;
@ -240,17 +239,6 @@ pub fn decode_existential_predicate_slice<'a, 'tcx, D>(decoder: &mut D)
.mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?) .mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?)
} }
#[inline]
pub fn decode_byte_array<'a, 'tcx, D>(decoder: &mut D)
-> Result<ByteArray<'tcx>, D::Error>
where D: TyDecoder<'a, 'tcx>,
'tcx: 'a,
{
Ok(ByteArray {
data: decoder.tcx().alloc_byte_array(&Vec::decode(decoder)?)
})
}
#[inline] #[inline]
pub fn decode_const<'a, 'tcx, D>(decoder: &mut D) pub fn decode_const<'a, 'tcx, D>(decoder: &mut D)
-> Result<&'tcx ty::Const<'tcx>, D::Error> -> Result<&'tcx ty::Const<'tcx>, D::Error>
@ -278,7 +266,6 @@ macro_rules! implement_ty_decoder {
use $crate::ty::codec::*; use $crate::ty::codec::*;
use $crate::ty::subst::Substs; use $crate::ty::subst::Substs;
use $crate::hir::def_id::{CrateNum}; use $crate::hir::def_id::{CrateNum};
use $crate::middle::const_val::ByteArray;
use rustc_serialize::{Decoder, SpecializedDecoder}; use rustc_serialize::{Decoder, SpecializedDecoder};
use std::borrow::Cow; use std::borrow::Cow;
@ -377,13 +364,6 @@ macro_rules! implement_ty_decoder {
} }
} }
impl<$($typaram),*> SpecializedDecoder<ByteArray<'tcx>>
for $DecoderName<$($typaram),*> {
fn specialized_decode(&mut self) -> Result<ByteArray<'tcx>, Self::Error> {
decode_byte_array(self)
}
}
impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::Const<'tcx>> impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::Const<'tcx>>
for $DecoderName<$($typaram),*> { for $DecoderName<$($typaram),*> {
fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {

View file

@ -30,7 +30,8 @@ use middle::cstore::EncodedMetadata;
use middle::lang_items; use middle::lang_items;
use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use middle::stability; use middle::stability;
use mir::{Mir, interpret}; use mir::{self, Mir, interpret};
use mir::interpret::{Value, PrimVal};
use ty::subst::{Kind, Substs}; use ty::subst::{Kind, Substs};
use ty::ReprOptions; use ty::ReprOptions;
use ty::Instance; use ty::Instance;
@ -53,7 +54,6 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
StableHasher, StableHasherResult, StableHasher, StableHasherResult,
StableVec}; StableVec};
use arena::{TypedArena, DroplessArena}; use arena::{TypedArena, DroplessArena};
use rustc_const_math::{ConstInt, ConstUsize};
use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use std::any::Any; use std::any::Any;
@ -675,9 +675,9 @@ impl<'tcx> TypeckTables<'tcx> {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> { impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let ty::TypeckTables { let ty::TypeckTables {
local_id_root, local_id_root,
@ -868,7 +868,7 @@ pub struct GlobalCtxt<'tcx> {
stability_interner: RefCell<FxHashSet<&'tcx attr::Stability>>, stability_interner: RefCell<FxHashSet<&'tcx attr::Stability>>,
pub interpret_interner: RefCell<InterpretInterner<'tcx>>, pub interpret_interner: InterpretInterner<'tcx>,
layout_interner: RefCell<FxHashSet<&'tcx LayoutDetails>>, layout_interner: RefCell<FxHashSet<&'tcx LayoutDetails>>,
@ -892,6 +892,11 @@ pub struct GlobalCtxt<'tcx> {
/// Everything needed to efficiently work with interned allocations /// Everything needed to efficiently work with interned allocations
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct InterpretInterner<'tcx> { pub struct InterpretInterner<'tcx> {
inner: RefCell<InterpretInternerInner<'tcx>>,
}
#[derive(Debug, Default)]
struct InterpretInternerInner<'tcx> {
/// Stores the value of constants (and deduplicates the actual memory) /// Stores the value of constants (and deduplicates the actual memory)
allocs: FxHashSet<&'tcx interpret::Allocation>, allocs: FxHashSet<&'tcx interpret::Allocation>,
@ -905,12 +910,18 @@ pub struct InterpretInterner<'tcx> {
/// Allows obtaining const allocs via a unique identifier /// Allows obtaining const allocs via a unique identifier
alloc_by_id: FxHashMap<interpret::AllocId, &'tcx interpret::Allocation>, alloc_by_id: FxHashMap<interpret::AllocId, &'tcx interpret::Allocation>,
/// Reverse map of `alloc_cache`
global_cache: FxHashMap<interpret::AllocId, DefId>,
/// The AllocId to assign to the next new regular allocation. /// The AllocId to assign to the next new regular allocation.
/// Always incremented, never gets smaller. /// Always incremented, never gets smaller.
next_id: interpret::AllocId, next_id: interpret::AllocId,
/// Allows checking whether a constant already has an allocation /// Allows checking whether a static already has an allocation
alloc_cache: FxHashMap<interpret::GlobalId<'tcx>, interpret::AllocId>, ///
/// This is only important for detecting statics referring to themselves
// FIXME(oli-obk) move it to the EvalContext?
alloc_cache: FxHashMap<DefId, interpret::AllocId>,
/// A cache for basic byte allocations keyed by their contents. This is used to deduplicate /// A cache for basic byte allocations keyed by their contents. This is used to deduplicate
/// allocations for string and bytestring literals. /// allocations for string and bytestring literals.
@ -918,14 +929,15 @@ pub struct InterpretInterner<'tcx> {
} }
impl<'tcx> InterpretInterner<'tcx> { impl<'tcx> InterpretInterner<'tcx> {
pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> interpret::AllocId { pub fn create_fn_alloc(&self, instance: Instance<'tcx>) -> interpret::AllocId {
if let Some(&alloc_id) = self.function_cache.get(&instance) { if let Some(&alloc_id) = self.inner.borrow().function_cache.get(&instance) {
return alloc_id; return alloc_id;
} }
let id = self.reserve(); let id = self.reserve();
debug!("creating fn ptr: {}", id); debug!("creating fn ptr: {}", id);
self.functions.insert(id, instance); let mut inner = self.inner.borrow_mut();
self.function_cache.insert(instance, id); inner.functions.insert(id, instance);
inner.function_cache.insert(instance, id);
id id
} }
@ -933,39 +945,48 @@ impl<'tcx> InterpretInterner<'tcx> {
&self, &self,
id: interpret::AllocId, id: interpret::AllocId,
) -> Option<Instance<'tcx>> { ) -> Option<Instance<'tcx>> {
self.functions.get(&id).cloned() self.inner.borrow().functions.get(&id).cloned()
} }
pub fn get_alloc( pub fn get_alloc(
&self, &self,
id: interpret::AllocId, id: interpret::AllocId,
) -> Option<&'tcx interpret::Allocation> { ) -> Option<&'tcx interpret::Allocation> {
self.alloc_by_id.get(&id).cloned() self.inner.borrow().alloc_by_id.get(&id).cloned()
} }
pub fn get_cached( pub fn get_cached(
&self, &self,
global_id: interpret::GlobalId<'tcx>, static_id: DefId,
) -> Option<interpret::AllocId> { ) -> Option<interpret::AllocId> {
self.alloc_cache.get(&global_id).cloned() self.inner.borrow().alloc_cache.get(&static_id).cloned()
} }
pub fn cache( pub fn cache(
&mut self, &self,
global_id: interpret::GlobalId<'tcx>, static_id: DefId,
ptr: interpret::AllocId, alloc_id: interpret::AllocId,
) { ) {
if let Some(old) = self.alloc_cache.insert(global_id, ptr) { let mut inner = self.inner.borrow_mut();
bug!("tried to cache {:?}, but was already existing as {:#?}", global_id, old); inner.global_cache.insert(alloc_id, static_id);
if let Some(old) = inner.alloc_cache.insert(static_id, alloc_id) {
bug!("tried to cache {:?}, but was already existing as {:#?}", static_id, old);
} }
} }
pub fn get_corresponding_static_def_id(
&self,
ptr: interpret::AllocId,
) -> Option<DefId> {
self.inner.borrow().global_cache.get(&ptr).cloned()
}
pub fn intern_at_reserved( pub fn intern_at_reserved(
&mut self, &self,
id: interpret::AllocId, id: interpret::AllocId,
alloc: &'tcx interpret::Allocation, alloc: &'tcx interpret::Allocation,
) { ) {
if let Some(old) = self.alloc_by_id.insert(id, alloc) { if let Some(old) = self.inner.borrow_mut().alloc_by_id.insert(id, alloc) {
bug!("tried to intern allocation at {}, but was already existing as {:#?}", id, old); bug!("tried to intern allocation at {}, but was already existing as {:#?}", id, old);
} }
} }
@ -973,10 +994,11 @@ impl<'tcx> InterpretInterner<'tcx> {
/// obtains a new allocation ID that can be referenced but does not /// obtains a new allocation ID that can be referenced but does not
/// yet have an allocation backing it. /// yet have an allocation backing it.
pub fn reserve( pub fn reserve(
&mut self, &self,
) -> interpret::AllocId { ) -> interpret::AllocId {
let next = self.next_id; let mut inner = self.inner.borrow_mut();
self.next_id.0 = self.next_id.0 let next = inner.next_id;
inner.next_id.0 = inner.next_id.0
.checked_add(1) .checked_add(1)
.expect("You overflowed a u64 by incrementing by 1... \ .expect("You overflowed a u64 by incrementing by 1... \
You've just earned yourself a free drink if we ever meet. \ You've just earned yourself a free drink if we ever meet. \
@ -1056,12 +1078,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self, self,
alloc: interpret::Allocation, alloc: interpret::Allocation,
) -> &'gcx interpret::Allocation { ) -> &'gcx interpret::Allocation {
if let Some(alloc) = self.interpret_interner.borrow().allocs.get(&alloc) { if let Some(alloc) = self.interpret_interner.inner.borrow().allocs.get(&alloc) {
return alloc; return alloc;
} }
let interned = self.global_arenas.const_allocs.alloc(alloc); let interned = self.global_arenas.const_allocs.alloc(alloc);
if let Some(prev) = self.interpret_interner.borrow_mut().allocs.replace(interned) { if let Some(prev) = self.interpret_interner.inner.borrow_mut().allocs.replace(interned) {
bug!("Tried to overwrite interned Allocation: {:#?}", prev) bug!("Tried to overwrite interned Allocation: {:#?}", prev)
} }
interned interned
@ -1070,20 +1092,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// Allocates a byte or string literal for `mir::interpret` /// Allocates a byte or string literal for `mir::interpret`
pub fn allocate_cached(self, bytes: &[u8]) -> interpret::AllocId { pub fn allocate_cached(self, bytes: &[u8]) -> interpret::AllocId {
// check whether we already allocated this literal or a constant with the same memory // check whether we already allocated this literal or a constant with the same memory
if let Some(&alloc_id) = self.interpret_interner.borrow().literal_alloc_cache.get(bytes) { if let Some(&alloc_id) = self.interpret_interner.inner.borrow()
.literal_alloc_cache.get(bytes) {
return alloc_id; return alloc_id;
} }
// create an allocation that just contains these bytes // create an allocation that just contains these bytes
let alloc = interpret::Allocation::from_bytes(bytes); let alloc = interpret::Allocation::from_bytes(bytes);
let alloc = self.intern_const_alloc(alloc); let alloc = self.intern_const_alloc(alloc);
let mut int = self.interpret_interner.borrow_mut();
// the next unique id // the next unique id
let id = int.reserve(); let id = self.interpret_interner.reserve();
// make the allocation identifiable // make the allocation identifiable
int.alloc_by_id.insert(id, alloc); self.interpret_interner.inner.borrow_mut().alloc_by_id.insert(id, alloc);
// cache it for the future // cache it for the future
int.literal_alloc_cache.insert(bytes.to_owned(), id); self.interpret_interner.inner.borrow_mut().literal_alloc_cache.insert(bytes.to_owned(), id);
id id
} }
@ -1248,6 +1270,40 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.get_lang_items(LOCAL_CRATE) self.get_lang_items(LOCAL_CRATE)
} }
/// Due to missing llvm support for lowering 128 bit math to software emulation
/// (on some targets), the lowering can be done in MIR.
///
/// This function only exists until said support is implemented.
pub fn is_binop_lang_item(&self, def_id: DefId) -> Option<(mir::BinOp, bool)> {
let items = self.lang_items();
let def_id = Some(def_id);
if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
else { None }
}
pub fn stability(self) -> Lrc<stability::Index<'tcx>> { pub fn stability(self) -> Lrc<stability::Index<'tcx>> {
self.stability_index(LOCAL_CRATE) self.stability_index(LOCAL_CRATE)
} }
@ -1321,7 +1377,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.cstore.crate_data_as_rc_any(cnum) self.cstore.crate_data_as_rc_any(cnum)
} }
pub fn create_stable_hashing_context(self) -> StableHashingContext<'gcx> { pub fn create_stable_hashing_context(self) -> StableHashingContext<'a> {
let krate = self.dep_graph.with_ignore(|| self.gcx.hir.krate()); let krate = self.dep_graph.with_ignore(|| self.gcx.hir.krate());
StableHashingContext::new(self.sess, StableHashingContext::new(self.sess,
@ -1731,7 +1787,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
println!("Substs interner: #{}", self.interners.substs.borrow().len()); println!("Substs interner: #{}", self.interners.substs.borrow().len());
println!("Region interner: #{}", self.interners.region.borrow().len()); println!("Region interner: #{}", self.interners.region.borrow().len());
println!("Stability interner: #{}", self.stability_interner.borrow().len()); println!("Stability interner: #{}", self.stability_interner.borrow().len());
println!("Interpret interner: #{}", self.interpret_interner.borrow().allocs.len()); println!("Interpret interner: #{}", self.interpret_interner.inner.borrow().allocs.len());
println!("Layout interner: #{}", self.layout_interner.borrow().len()); println!("Layout interner: #{}", self.layout_interner.borrow().len());
} }
} }
@ -2043,13 +2099,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
} }
pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
let n = ConstUsize::new(n, self.sess.target.usize_ty).unwrap();
self.mk_array_const_usize(ty, n)
}
pub fn mk_array_const_usize(self, ty: Ty<'tcx>, n: ConstUsize) -> Ty<'tcx> {
self.mk_ty(TyArray(ty, self.mk_const(ty::Const { self.mk_ty(TyArray(ty, self.mk_const(ty::Const {
val: ConstVal::Integral(ConstInt::Usize(n)), val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.into()))),
ty: self.types.usize ty: self.types.usize
}))) })))
} }

View file

@ -9,17 +9,13 @@
// except according to those terms. // except according to those terms.
use hir::def_id::DefId; use hir::def_id::DefId;
use middle::const_val::ConstVal;
use ty::{self, BoundRegion, Region, Ty, TyCtxt}; use ty::{self, BoundRegion, Region, Ty, TyCtxt};
use std::fmt; use std::fmt;
use syntax::abi; use syntax::abi;
use syntax::ast; use syntax::ast;
use errors::DiagnosticBuilder; use errors::DiagnosticBuilder;
use syntax_pos::Span; use syntax_pos::Span;
use rustc_const_math::ConstInt;
use hir; use hir;
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -186,10 +182,9 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)), ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)),
ty::TyArray(_, n) => { ty::TyArray(_, n) => {
if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { match n.val.to_raw_bits() {
format!("array of {} elements", n) Some(n) => format!("array of {} elements", n),
} else { None => "array".to_string(),
"array".to_string()
} }
} }
ty::TySlice(_) => "slice".to_string(), ty::TySlice(_) => "slice".to_string(),

View file

@ -154,12 +154,12 @@ impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> {
} }
} }
impl<'gcx, D> HashStable<StableHashingContext<'gcx>> for SimplifiedTypeGen<D> impl<'a, 'gcx, D> HashStable<StableHashingContext<'a>> for SimplifiedTypeGen<D>
where D: Copy + Debug + Ord + Eq + Hash + where D: Copy + Debug + Ord + Eq + Hash +
HashStable<StableHashingContext<'gcx>>, HashStable<StableHashingContext<'a>>,
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use middle::const_val::{ConstVal, ConstAggregate}; use middle::const_val::ConstVal;
use ty::subst::Substs; use ty::subst::Substs;
use ty::{self, Ty, TypeFlags, TypeFoldable}; use ty::{self, Ty, TypeFlags, TypeFoldable};
@ -218,30 +218,7 @@ impl FlagComputation {
fn add_const(&mut self, constant: &ty::Const) { fn add_const(&mut self, constant: &ty::Const) {
self.add_ty(constant.ty); self.add_ty(constant.ty);
match constant.val { match constant.val {
ConstVal::Integral(_) | ConstVal::Value(_) => {}
ConstVal::Float(_) |
ConstVal::Str(_) |
ConstVal::ByteStr(_) |
ConstVal::Bool(_) |
ConstVal::Char(_) |
ConstVal::Variant(_) => {}
ConstVal::Function(_, substs) => {
self.add_substs(substs);
}
ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
for &(_, v) in fields {
self.add_const(v);
}
}
ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
for v in fields {
self.add_const(v);
}
}
ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
self.add_const(v);
}
ConstVal::Unevaluated(_, substs) => { ConstVal::Unevaluated(_, substs) => {
self.add_flags(TypeFlags::HAS_PROJECTION); self.add_flags(TypeFlags::HAS_PROJECTION);
self.add_substs(substs); self.add_substs(substs);

View file

@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
})) }))
}, },
TyArray(ty, len) => { TyArray(ty, len) => {
match len.val.to_const_int().and_then(|i| i.to_u64()) { match len.val.to_raw_bits() {
// If the array is definitely non-empty, it's uninhabited if // If the array is definitely non-empty, it's uninhabited if
// the type of its elements is uninhabited. // the type of its elements is uninhabited.
Some(n) if n != 0 => ty.uninhabited_from(visited, tcx), Some(n) if n != 0 => ty.uninhabited_from(visited, tcx),

View file

@ -17,13 +17,13 @@ use util::ppaux;
use std::fmt; use std::fmt;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct Instance<'tcx> { pub struct Instance<'tcx> {
pub def: InstanceDef<'tcx>, pub def: InstanceDef<'tcx>,
pub substs: &'tcx Substs<'tcx>, pub substs: &'tcx Substs<'tcx>,
} }
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum InstanceDef<'tcx> { pub enum InstanceDef<'tcx> {
Item(DefId), Item(DefId),
Intrinsic(DefId), Intrinsic(DefId),

View file

@ -342,7 +342,7 @@ impl AddAssign for Size {
/// Each field is a power of two, giving the alignment a maximum /// Each field is a power of two, giving the alignment a maximum
/// value of 2<sup>(2<sup>8</sup> - 1)</sup>, which is limited by LLVM to a i32, with /// value of 2<sup>(2<sup>8</sup> - 1)</sup>, which is limited by LLVM to a i32, with
/// a maximum capacity of 2<sup>31</sup> - 1 or 2147483647. /// a maximum capacity of 2<sup>31</sup> - 1 or 2147483647.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct Align { pub struct Align {
abi: u8, abi: u8,
pref: u8, pref: u8,
@ -794,6 +794,17 @@ impl Abi {
Abi::Aggregate { sized } => !sized Abi::Aggregate { sized } => !sized
} }
} }
/// Returns true if this is a single signed integer scalar
pub fn is_signed(&self) -> bool {
match *self {
Abi::Scalar(ref scal) => match scal.value {
Primitive::Int(_, signed) => signed,
_ => false,
},
_ => false,
}
}
} }
#[derive(PartialEq, Eq, Hash, Debug)] #[derive(PartialEq, Eq, Hash, Debug)]
@ -1237,7 +1248,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
} }
let element = self.layout_of(element)?; let element = self.layout_of(element)?;
let count = count.val.to_const_int().unwrap().to_u64().unwrap(); let count = count.val.unwrap_u64();
let size = element.size.checked_mul(count, dl) let size = element.size.checked_mul(count, dl)
.ok_or(LayoutError::SizeOverflow(ty))?; .ok_or(LayoutError::SizeOverflow(ty))?;
@ -1537,7 +1548,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
if variants[i].iter().any(|f| f.abi == Abi::Uninhabited) { if variants[i].iter().any(|f| f.abi == Abi::Uninhabited) {
continue; continue;
} }
let x = discr.to_u128_unchecked() as i128; let x = discr.val as i128;
if x < min { min = x; } if x < min { min = x; }
if x > max { max = x; } if x > max { max = x; }
} }
@ -2369,9 +2380,9 @@ impl<'a, 'tcx> TyLayout<'tcx> {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for Variants { impl<'a> HashStable<StableHashingContext<'a>> for Variants {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use ty::layout::Variants::*; use ty::layout::Variants::*;
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
@ -2405,9 +2416,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Variants {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for FieldPlacement { impl<'a> HashStable<StableHashingContext<'a>> for FieldPlacement {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use ty::layout::FieldPlacement::*; use ty::layout::FieldPlacement::*;
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
@ -2428,9 +2439,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for FieldPlacement {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi { impl<'a> HashStable<StableHashingContext<'a>> for Abi {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use ty::layout::Abi::*; use ty::layout::Abi::*;
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
@ -2455,9 +2466,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for Scalar { impl<'a> HashStable<StableHashingContext<'a>> for Scalar {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let Scalar { value, valid_range: RangeInclusive { start, end } } = *self; let Scalar { value, valid_range: RangeInclusive { start, end } } = *self;
value.hash_stable(hcx, hasher); value.hash_stable(hcx, hasher);
@ -2498,10 +2509,10 @@ impl_stable_hash_for!(struct ::ty::layout::Size {
raw raw
}); });
impl<'gcx> HashStable<StableHashingContext<'gcx>> for LayoutError<'gcx> impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for LayoutError<'gcx>
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use ty::layout::LayoutError::*; use ty::layout::LayoutError::*;
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);

View file

@ -10,9 +10,10 @@
use dep_graph::SerializedDepNodeIndex; use dep_graph::SerializedDepNodeIndex;
use hir::def_id::{CrateNum, DefId, DefIndex}; use hir::def_id::{CrateNum, DefId, DefIndex};
use mir::interpret::{GlobalId};
use ty::{self, Ty, TyCtxt}; use ty::{self, Ty, TyCtxt};
use ty::maps::queries;
use ty::subst::Substs; use ty::subst::Substs;
use ty::maps::queries;
use std::hash::Hash; use std::hash::Hash;
use syntax_pos::symbol::InternedString; use syntax_pos::symbol::InternedString;
@ -152,8 +153,8 @@ impl<'tcx> QueryDescription<'tcx> for queries::reachable_set<'tcx> {
} }
impl<'tcx> QueryDescription<'tcx> for queries::const_eval<'tcx> { impl<'tcx> QueryDescription<'tcx> for queries::const_eval<'tcx> {
fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) -> String { fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> String {
format!("const-evaluating `{}`", tcx.item_path_str(key.value.0)) format!("const-evaluating `{}`", tcx.item_path_str(key.value.instance.def.def_id()))
} }
} }

View file

@ -14,6 +14,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex};
use ty::{self, Ty, TyCtxt}; use ty::{self, Ty, TyCtxt};
use ty::subst::Substs; use ty::subst::Substs;
use ty::fast_reject::SimplifiedType; use ty::fast_reject::SimplifiedType;
use mir;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::Hash; use std::hash::Hash;
@ -52,6 +53,16 @@ impl<'tcx> Key for ty::Instance<'tcx> {
} }
} }
impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
fn map_crate(&self) -> CrateNum {
self.instance.map_crate()
}
fn default_span(&self, tcx: TyCtxt) -> Span {
self.instance.default_span(tcx)
}
}
impl Key for CrateNum { impl Key for CrateNum {
fn map_crate(&self) -> CrateNum { fn map_crate(&self) -> CrateNum {
*self *self

View file

@ -16,7 +16,6 @@ use hir::{self, TraitCandidate, ItemLocalId, TransFnAttrs};
use hir::svh::Svh; use hir::svh::Svh;
use lint; use lint;
use middle::borrowck::BorrowCheckResult; use middle::borrowck::BorrowCheckResult;
use middle::const_val;
use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary,
ExternBodyNestedBodies}; ExternBodyNestedBodies};
use middle::cstore::{NativeLibraryKind, DepKind, CrateSource, ExternConstBody}; use middle::cstore::{NativeLibraryKind, DepKind, CrateSource, ExternConstBody};
@ -27,8 +26,10 @@ use middle::resolve_lifetime::{ResolveLifetimes, Region, ObjectLifetimeDefault};
use middle::stability::{self, DeprecationEntry}; use middle::stability::{self, DeprecationEntry};
use middle::lang_items::{LanguageItems, LangItem}; use middle::lang_items::{LanguageItems, LangItem};
use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol}; use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol};
use middle::const_val::EvalResult;
use mir::mono::{CodegenUnit, Stats}; use mir::mono::{CodegenUnit, Stats};
use mir; use mir;
use mir::interpret::{GlobalId};
use session::{CompileResult, CrateDisambiguator}; use session::{CompileResult, CrateDisambiguator};
use session::config::OutputFilenames; use session::config::OutputFilenames;
use traits::Vtable; use traits::Vtable;
@ -210,8 +211,8 @@ define_maps! { <'tcx>
/// Results of evaluating const items or constants embedded in /// Results of evaluating const items or constants embedded in
/// other items (such as enum variant explicit discriminants). /// other items (such as enum variant explicit discriminants).
[] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
-> const_val::EvalResult<'tcx>, -> EvalResult<'tcx>,
[] fn check_match: CheckMatch(DefId) [] fn check_match: CheckMatch(DefId)
-> Result<(), ErrorReported>, -> Result<(), ErrorReported>,
@ -450,7 +451,7 @@ fn typeck_item_bodies_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
DepConstructor::TypeckBodiesKrate DepConstructor::TypeckBodiesKrate
} }
fn const_eval_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) fn const_eval_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
-> DepConstructor<'tcx> { -> DepConstructor<'tcx> {
DepConstructor::ConstEval { param_env } DepConstructor::ConstEval { param_env }
} }

View file

@ -15,7 +15,7 @@ use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId,
RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE}; RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE};
use hir::map::definitions::DefPathHash; use hir::map::definitions::DefPathHash;
use ich::{CachingCodemapView, Fingerprint}; use ich::{CachingCodemapView, Fingerprint};
use mir; use mir::{self, interpret};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@ -187,6 +187,7 @@ impl<'sess> OnDiskCache<'sess> {
type_shorthands: FxHashMap(), type_shorthands: FxHashMap(),
predicate_shorthands: FxHashMap(), predicate_shorthands: FxHashMap(),
expn_info_shorthands: FxHashMap(), expn_info_shorthands: FxHashMap(),
interpret_alloc_shorthands: FxHashMap(),
codemap: CachingCodemapView::new(tcx.sess.codemap()), codemap: CachingCodemapView::new(tcx.sess.codemap()),
file_to_file_index, file_to_file_index,
}; };
@ -362,6 +363,7 @@ impl<'sess> OnDiskCache<'sess> {
file_index_to_file: &self.file_index_to_file, file_index_to_file: &self.file_index_to_file,
file_index_to_stable_id: &self.file_index_to_stable_id, file_index_to_stable_id: &self.file_index_to_stable_id,
synthetic_expansion_infos: &self.synthetic_expansion_infos, synthetic_expansion_infos: &self.synthetic_expansion_infos,
interpret_alloc_cache: FxHashMap::default(),
}; };
match decode_tagged(&mut decoder, dep_node_index) { match decode_tagged(&mut decoder, dep_node_index) {
@ -423,6 +425,7 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> {
synthetic_expansion_infos: &'x RefCell<FxHashMap<AbsoluteBytePos, SyntaxContext>>, synthetic_expansion_infos: &'x RefCell<FxHashMap<AbsoluteBytePos, SyntaxContext>>,
file_index_to_file: &'x RefCell<FxHashMap<FileMapIndex, Lrc<FileMap>>>, file_index_to_file: &'x RefCell<FxHashMap<FileMapIndex, Lrc<FileMap>>>,
file_index_to_stable_id: &'x FxHashMap<FileMapIndex, StableFilemapId>, file_index_to_stable_id: &'x FxHashMap<FileMapIndex, StableFilemapId>,
interpret_alloc_cache: FxHashMap<usize, interpret::AllocId>,
} }
impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> {
@ -542,6 +545,50 @@ impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx,
implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> ); implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> );
impl<'a, 'tcx, 'x> SpecializedDecoder<interpret::AllocId> for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<interpret::AllocId, Self::Error> {
const MAX1: usize = usize::max_value() - 1;
let tcx = self.tcx;
let pos = TyDecoder::position(self);
match usize::decode(self)? {
::std::usize::MAX => {
let alloc_id = tcx.interpret_interner.reserve();
trace!("creating alloc id {:?} at {}", alloc_id, pos);
// insert early to allow recursive allocs
self.interpret_alloc_cache.insert(pos, alloc_id);
let allocation = interpret::Allocation::decode(self)?;
trace!("decoded alloc {:?} {:#?}", alloc_id, allocation);
let allocation = self.tcx.intern_const_alloc(allocation);
tcx.interpret_interner.intern_at_reserved(alloc_id, allocation);
if let Some(glob) = Option::<DefId>::decode(self)? {
tcx.interpret_interner.cache(glob, alloc_id);
}
Ok(alloc_id)
},
MAX1 => {
trace!("creating fn alloc id at {}", pos);
let instance = ty::Instance::decode(self)?;
trace!("decoded fn alloc instance: {:?}", instance);
let id = tcx.interpret_interner.create_fn_alloc(instance);
trace!("created fn alloc id: {:?}", id);
self.interpret_alloc_cache.insert(pos, id);
Ok(id)
},
shorthand => {
trace!("loading shorthand {}", shorthand);
if let Some(&alloc_id) = self.interpret_alloc_cache.get(&shorthand) {
return Ok(alloc_id);
}
trace!("shorthand {} not cached, loading entire allocation", shorthand);
// need to load allocation
self.with_position(shorthand, |this| interpret::AllocId::decode(this))
},
}
}
}
impl<'a, 'tcx, 'x> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx, 'x> { impl<'a, 'tcx, 'x> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<Span, Self::Error> { fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
let tag: u8 = Decodable::decode(self)?; let tag: u8 = Decodable::decode(self)?;
@ -703,6 +750,7 @@ struct CacheEncoder<'enc, 'a, 'tcx, E>
type_shorthands: FxHashMap<ty::Ty<'tcx>, usize>, type_shorthands: FxHashMap<ty::Ty<'tcx>, usize>,
predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>, predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
expn_info_shorthands: FxHashMap<Mark, AbsoluteBytePos>, expn_info_shorthands: FxHashMap<Mark, AbsoluteBytePos>,
interpret_alloc_shorthands: FxHashMap<interpret::AllocId, usize>,
codemap: CachingCodemapView<'tcx>, codemap: CachingCodemapView<'tcx>,
file_to_file_index: FxHashMap<*const FileMap, FileMapIndex>, file_to_file_index: FxHashMap<*const FileMap, FileMapIndex>,
} }
@ -735,6 +783,37 @@ impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E>
} }
} }
impl<'enc, 'a, 'tcx, E> SpecializedEncoder<interpret::AllocId> for CacheEncoder<'enc, 'a, 'tcx, E>
where E: 'enc + ty_codec::TyEncoder
{
fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
trace!("encoding {:?} at {}", alloc_id, self.position());
if let Some(shorthand) = self.interpret_alloc_shorthands.get(alloc_id).cloned() {
trace!("encoding {:?} as shorthand to {}", alloc_id, shorthand);
return shorthand.encode(self);
}
let start = self.position();
// cache the allocation shorthand now, because the allocation itself might recursively
// point to itself.
self.interpret_alloc_shorthands.insert(*alloc_id, start);
if let Some(alloc) = self.tcx.interpret_interner.get_alloc(*alloc_id) {
trace!("encoding {:?} with {:#?}", alloc_id, alloc);
usize::max_value().encode(self)?;
alloc.encode(self)?;
self.tcx.interpret_interner
.get_corresponding_static_def_id(*alloc_id)
.encode(self)?;
} else if let Some(fn_instance) = self.tcx.interpret_interner.get_fn(*alloc_id) {
trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
(usize::max_value() - 1).encode(self)?;
fn_instance.encode(self)?;
} else {
bug!("alloc id without corresponding allocation: {}", alloc_id);
}
Ok(())
}
}
impl<'enc, 'a, 'tcx, E> SpecializedEncoder<Span> for CacheEncoder<'enc, 'a, 'tcx, E> impl<'enc, 'a, 'tcx, E> SpecializedEncoder<Span> for CacheEncoder<'enc, 'a, 'tcx, E>
where E: 'enc + ty_codec::TyEncoder where E: 'enc + ty_codec::TyEncoder
{ {

View file

@ -26,12 +26,13 @@ use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangIte
use middle::privacy::AccessLevels; use middle::privacy::AccessLevels;
use middle::resolve_lifetime::ObjectLifetimeDefault; use middle::resolve_lifetime::ObjectLifetimeDefault;
use mir::Mir; use mir::Mir;
use mir::interpret::{GlobalId, Value, PrimVal};
use mir::GeneratorLayout; use mir::GeneratorLayout;
use session::CrateDisambiguator; use session::CrateDisambiguator;
use traits; use traits;
use ty; use ty;
use ty::subst::{Subst, Substs}; use ty::subst::{Subst, Substs};
use ty::util::IntTypeExt; use ty::util::{IntTypeExt, Discr};
use ty::walk::TypeWalker; use ty::walk::TypeWalker;
use util::common::ErrorReported; use util::common::ErrorReported;
use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
@ -52,7 +53,6 @@ use syntax::attr;
use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::symbol::{Symbol, InternedString}; use syntax::symbol::{Symbol, InternedString};
use syntax_pos::{DUMMY_SP, Span}; use syntax_pos::{DUMMY_SP, Span};
use rustc_const_math::ConstInt;
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
@ -79,7 +79,7 @@ pub use self::binding::BindingMode;
pub use self::binding::BindingMode::*; pub use self::binding::BindingMode::*;
pub use self::context::{TyCtxt, GlobalArenas, AllArenas, tls, keep_local}; pub use self::context::{TyCtxt, GlobalArenas, AllArenas, tls, keep_local};
pub use self::context::{Lift, TypeckTables}; pub use self::context::{Lift, TypeckTables, InterpretInterner};
pub use self::instance::{Instance, InstanceDef}; pub use self::instance::{Instance, InstanceDef};
@ -528,9 +528,9 @@ impl<'tcx> TyS<'tcx> {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::TyS<'gcx> { impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::TyS<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let ty::TyS { let ty::TyS {
ref sty, ref sty,
@ -1439,11 +1439,11 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> {
} }
} }
impl<'gcx, T> HashStable<StableHashingContext<'gcx>> for ParamEnvAnd<'gcx, T> impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>> for ParamEnvAnd<'gcx, T>
where T: HashStable<StableHashingContext<'gcx>> where T: HashStable<StableHashingContext<'a>>
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let ParamEnvAnd { let ParamEnvAnd {
ref param_env, ref param_env,
@ -1544,9 +1544,9 @@ impl<'tcx> serialize::UseSpecializedEncodable for &'tcx AdtDef {
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {} impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {}
impl<'gcx> HashStable<StableHashingContext<'gcx>> for AdtDef { impl<'a> HashStable<StableHashingContext<'a>> for AdtDef {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
thread_local! { thread_local! {
static CACHE: RefCell<FxHashMap<usize, Fingerprint>> = static CACHE: RefCell<FxHashMap<usize, Fingerprint>> =
@ -1824,27 +1824,79 @@ impl<'a, 'gcx, 'tcx> AdtDef {
} }
#[inline] #[inline]
pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) pub fn eval_explicit_discr(
-> impl Iterator<Item=ConstInt> + 'a { &self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
expr_did: DefId,
) -> Option<Discr<'tcx>> {
let param_env = ParamEnv::empty(traits::Reveal::UserFacing); let param_env = ParamEnv::empty(traits::Reveal::UserFacing);
let repr_type = self.repr.discr_type(); let repr_type = self.repr.discr_type();
let bit_size = layout::Integer::from_attr(tcx, repr_type).size().bits();
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
let instance = ty::Instance::new(expr_did, substs);
let cid = GlobalId {
instance,
promoted: None
};
match tcx.const_eval(param_env.and(cid)) {
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
..
}) => {
trace!("discriminants: {} ({:?})", b, repr_type);
let ty = repr_type.to_ty(tcx);
if repr_type.is_signed() {
let val = b as i128;
// sign extend to i128
let amt = 128 - bit_size;
let val = (val << amt) >> amt;
Some(Discr {
val: val as u128,
ty,
})
} else {
Some(Discr {
val: b,
ty,
})
}
},
Ok(&ty::Const {
val: ConstVal::Value(other),
..
}) => {
info!("invalid enum discriminant: {:#?}", other);
::middle::const_val::struct_error(
tcx,
tcx.def_span(expr_did),
"constant evaluation of enum discriminant resulted in non-integer",
).emit();
None
}
Err(err) => {
err.report(tcx, tcx.def_span(expr_did), "enum discriminant");
if !expr_did.is_local() {
span_bug!(tcx.def_span(expr_did),
"variant discriminant evaluation succeeded \
in its crate but failed locally");
}
None
}
_ => span_bug!(tcx.def_span(expr_did), "const eval "),
}
}
#[inline]
pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
-> impl Iterator<Item=Discr<'tcx>> + 'a {
let repr_type = self.repr.discr_type();
let initial = repr_type.initial_discriminant(tcx.global_tcx()); let initial = repr_type.initial_discriminant(tcx.global_tcx());
let mut prev_discr = None::<ConstInt>; let mut prev_discr = None::<Discr<'tcx>>;
self.variants.iter().map(move |v| { self.variants.iter().map(move |v| {
let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr()); let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
if let VariantDiscr::Explicit(expr_did) = v.discr { if let VariantDiscr::Explicit(expr_did) = v.discr {
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did); if let Some(new_discr) = self.eval_explicit_discr(tcx, expr_did) {
match tcx.const_eval(param_env.and((expr_did, substs))) { discr = new_discr;
Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => {
discr = v;
}
err => {
if !expr_did.is_local() {
span_bug!(tcx.def_span(expr_did),
"variant discriminant evaluation succeeded \
in its crate but failed locally: {:?}", err);
}
}
} }
} }
prev_discr = Some(discr); prev_discr = Some(discr);
@ -1861,8 +1913,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
pub fn discriminant_for_variant(&self, pub fn discriminant_for_variant(&self,
tcx: TyCtxt<'a, 'gcx, 'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>,
variant_index: usize) variant_index: usize)
-> ConstInt { -> Discr<'tcx> {
let param_env = ParamEnv::empty(traits::Reveal::UserFacing);
let repr_type = self.repr.discr_type(); let repr_type = self.repr.discr_type();
let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx()); let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx());
let mut explicit_index = variant_index; let mut explicit_index = variant_index;
@ -1873,18 +1924,12 @@ impl<'a, 'gcx, 'tcx> AdtDef {
explicit_index -= distance; explicit_index -= distance;
} }
ty::VariantDiscr::Explicit(expr_did) => { ty::VariantDiscr::Explicit(expr_did) => {
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did); match self.eval_explicit_discr(tcx, expr_did) {
match tcx.const_eval(param_env.and((expr_did, substs))) { Some(discr) => {
Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => { explicit_value = discr;
explicit_value = v;
break; break;
} },
err => { None => {
if !expr_did.is_local() {
span_bug!(tcx.def_span(expr_did),
"variant discriminant evaluation succeeded \
in its crate but failed locally: {:?}", err);
}
if explicit_index == 0 { if explicit_index == 0 {
break; break;
} }
@ -1894,18 +1939,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
} }
} }
} }
let discr = explicit_value.to_u128_unchecked() explicit_value.checked_add(tcx, (variant_index - explicit_index) as u128).0
.wrapping_add((variant_index - explicit_index) as u128);
match repr_type {
attr::UnsignedInt(ty) => {
ConstInt::new_unsigned_truncating(discr, ty,
tcx.sess.target.usize_ty)
}
attr::SignedInt(ty) => {
ConstInt::new_signed_truncating(discr as i128, ty,
tcx.sess.target.isize_ty)
}
}
} }
pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> { pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> {

View file

@ -20,6 +20,7 @@ use ty::subst::{UnpackedKind, Substs};
use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::fold::{TypeVisitor, TypeFolder}; use ty::fold::{TypeVisitor, TypeFolder};
use ty::error::{ExpectedFound, TypeError}; use ty::error::{ExpectedFound, TypeError};
use mir::interpret::{GlobalId, Value, PrimVal};
use util::common::ErrorReported; use util::common::ErrorReported;
use std::rc::Rc; use std::rc::Rc;
use std::iter; use std::iter;
@ -482,19 +483,35 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
assert_eq!(sz_b.ty, tcx.types.usize); assert_eq!(sz_b.ty, tcx.types.usize);
let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> { let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
match x.val { match x.val {
ConstVal::Integral(x) => Ok(x.to_u64().unwrap()), ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()),
ConstVal::Unevaluated(def_id, substs) => { ConstVal::Unevaluated(def_id, substs) => {
// FIXME(eddyb) get the right param_env. // FIXME(eddyb) get the right param_env.
let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
match tcx.lift_to_global(&substs) { match tcx.lift_to_global(&substs) {
Some(substs) => { Some(substs) => {
match tcx.const_eval(param_env.and((def_id, substs))) { let instance = ty::Instance::resolve(
Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => { tcx.global_tcx(),
return Ok(x.to_u64().unwrap()); param_env,
def_id,
substs,
);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None
};
match tcx.const_eval(param_env.and(cid)) {
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
..
}) => {
assert_eq!(b as u64 as u128, b);
return Ok(b as u64);
}
_ => {}
} }
_ => {}
} }
} },
None => {} None => {}
} }
tcx.sess.delay_span_bug(tcx.def_span(def_id), tcx.sess.delay_span_bug(tcx.def_span(def_id),

View file

@ -13,11 +13,12 @@
//! hand, though we've recently added some macros (e.g., //! hand, though we've recently added some macros (e.g.,
//! `BraceStructLiftImpl!`) to help with the tedium. //! `BraceStructLiftImpl!`) to help with the tedium.
use middle::const_val::{self, ConstVal, ConstAggregate, ConstEvalErr}; use middle::const_val::{self, ConstVal, ConstEvalErr};
use ty::{self, Lift, Ty, TyCtxt}; use ty::{self, Lift, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::accumulate_vec::AccumulateVec;
use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use mir::interpret;
use std::rc::Rc; use std::rc::Rc;
@ -56,6 +57,7 @@ CopyImpls! {
::syntax::abi::Abi, ::syntax::abi::Abi,
::hir::def_id::DefId, ::hir::def_id::DefId,
::mir::Local, ::mir::Local,
::mir::Promoted,
::traits::Reveal, ::traits::Reveal,
::syntax_pos::Span, ::syntax_pos::Span,
} }
@ -576,44 +578,139 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> { impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> {
type Lifted = ConstEvalErr<'tcx>; type Lifted = ConstEvalErr<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.kind).map(|kind| { tcx.lift(&*self.kind).map(|kind| {
ConstEvalErr { ConstEvalErr {
span: self.span, span: self.span,
kind, kind: Rc::new(kind),
} }
}) })
} }
} }
impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
type Lifted = interpret::EvalError<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
use ::mir::interpret::EvalErrorKind::*;
let kind = match self.kind {
MachineError(ref err) => MachineError(err.clone()),
FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch(
tcx.lift(&a)?,
tcx.lift(&b)?,
),
NoMirFor(ref s) => NoMirFor(s.clone()),
UnterminatedCString(ptr) => UnterminatedCString(ptr),
DanglingPointerDeref => DanglingPointerDeref,
DoubleFree => DoubleFree,
InvalidMemoryAccess => InvalidMemoryAccess,
InvalidFunctionPointer => InvalidFunctionPointer,
InvalidBool => InvalidBool,
InvalidDiscriminant => InvalidDiscriminant,
PointerOutOfBounds {
ptr,
access,
allocation_size,
} => PointerOutOfBounds { ptr, access, allocation_size },
InvalidNullPointerUsage => InvalidNullPointerUsage,
ReadPointerAsBytes => ReadPointerAsBytes,
ReadBytesAsPointer => ReadBytesAsPointer,
InvalidPointerMath => InvalidPointerMath,
ReadUndefBytes => ReadUndefBytes,
DeadLocal => DeadLocal,
InvalidBoolOp(bop) => InvalidBoolOp(bop),
Unimplemented(ref s) => Unimplemented(s.clone()),
DerefFunctionPointer => DerefFunctionPointer,
ExecuteMemory => ExecuteMemory,
ArrayIndexOutOfBounds(sp, a, b) => ArrayIndexOutOfBounds(sp, a, b),
Math(sp, ref err) => Math(sp, err.clone()),
Intrinsic(ref s) => Intrinsic(s.clone()),
OverflowingMath => OverflowingMath,
InvalidChar(c) => InvalidChar(c),
ExecutionTimeLimitReached => ExecutionTimeLimitReached,
StackFrameLimitReached => StackFrameLimitReached,
OutOfTls => OutOfTls,
TlsOutOfBounds => TlsOutOfBounds,
AbiViolation(ref s) => AbiViolation(s.clone()),
AlignmentCheckFailed {
required,
has,
} => AlignmentCheckFailed { required, has },
MemoryLockViolation {
ptr,
len,
frame,
access,
ref lock,
} => MemoryLockViolation { ptr, len, frame, access, lock: lock.clone() },
MemoryAcquireConflict {
ptr,
len,
kind,
ref lock,
} => MemoryAcquireConflict { ptr, len, kind, lock: lock.clone() },
InvalidMemoryLockRelease {
ptr,
len,
frame,
ref lock,
} => InvalidMemoryLockRelease { ptr, len, frame, lock: lock.clone() },
DeallocatedLockedMemory {
ptr,
ref lock,
} => DeallocatedLockedMemory { ptr, lock: lock.clone() },
ValidationFailure(ref s) => ValidationFailure(s.clone()),
CalledClosureAsFunction => CalledClosureAsFunction,
VtableForArgumentlessMethod => VtableForArgumentlessMethod,
ModifiedConstantMemory => ModifiedConstantMemory,
AssumptionNotHeld => AssumptionNotHeld,
InlineAsm => InlineAsm,
TypeNotPrimitive(ty) => TypeNotPrimitive(tcx.lift(&ty)?),
ReallocatedWrongMemoryKind(ref a, ref b) => {
ReallocatedWrongMemoryKind(a.clone(), b.clone())
},
DeallocatedWrongMemoryKind(ref a, ref b) => {
DeallocatedWrongMemoryKind(a.clone(), b.clone())
},
ReallocateNonBasePtr => ReallocateNonBasePtr,
DeallocateNonBasePtr => DeallocateNonBasePtr,
IncorrectAllocationInformation(a, b, c, d) => {
IncorrectAllocationInformation(a, b, c, d)
},
Layout(lay) => Layout(tcx.lift(&lay)?),
HeapAllocZeroBytes => HeapAllocZeroBytes,
HeapAllocNonPowerOfTwoAlignment(n) => HeapAllocNonPowerOfTwoAlignment(n),
Unreachable => Unreachable,
Panic => Panic,
ReadFromReturnPointer => ReadFromReturnPointer,
PathNotFound(ref v) => PathNotFound(v.clone()),
UnimplementedTraitSelection => UnimplementedTraitSelection,
TypeckError => TypeckError,
ReferencedConstant => ReferencedConstant,
};
Some(interpret::EvalError {
kind: kind,
backtrace: self.backtrace.clone(),
})
}
}
impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> { impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> {
type Lifted = const_val::ErrKind<'tcx>; type Lifted = const_val::ErrKind<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
use middle::const_val::ErrKind::*; use middle::const_val::ErrKind::*;
Some(match *self { Some(match *self {
CannotCast => CannotCast,
MissingStructField => MissingStructField,
NonConstPath => NonConstPath, NonConstPath => NonConstPath,
UnimplementedConstVal(s) => UnimplementedConstVal(s), UnimplementedConstVal(s) => UnimplementedConstVal(s),
ExpectedConstTuple => ExpectedConstTuple,
ExpectedConstStruct => ExpectedConstStruct,
IndexedNonVec => IndexedNonVec,
IndexNotUsize => IndexNotUsize,
IndexOutOfBounds { len, index } => IndexOutOfBounds { len, index }, IndexOutOfBounds { len, index } => IndexOutOfBounds { len, index },
MiscBinaryOp => MiscBinaryOp,
MiscCatchAll => MiscCatchAll,
IndexOpFeatureGated => IndexOpFeatureGated,
Math(ref e) => Math(e.clone()), Math(ref e) => Math(e.clone()),
LayoutError(ref e) => { LayoutError(ref e) => {
return tcx.lift(e).map(LayoutError) return tcx.lift(e).map(LayoutError)
} }
ErroneousReferencedConstant(ref e) => {
return tcx.lift(e).map(ErroneousReferencedConstant)
}
TypeckError => TypeckError, TypeckError => TypeckError,
CheckMatchError => CheckMatchError, CheckMatchError => CheckMatchError,
Miri(ref e, ref frames) => return tcx.lift(e).map(|e| Miri(e, frames.clone())),
}) })
} }
} }
@ -632,6 +729,42 @@ impl<'a, 'tcx> Lift<'tcx> for ty::layout::LayoutError<'a> {
} }
} }
impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
type Lifted = ty::InstanceDef<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
match *self {
ty::InstanceDef::Item(def_id) =>
Some(ty::InstanceDef::Item(def_id)),
ty::InstanceDef::Intrinsic(def_id) =>
Some(ty::InstanceDef::Intrinsic(def_id)),
ty::InstanceDef::FnPtrShim(def_id, ref ty) =>
Some(ty::InstanceDef::FnPtrShim(def_id, tcx.lift(ty)?)),
ty::InstanceDef::Virtual(def_id, n) =>
Some(ty::InstanceDef::Virtual(def_id, n)),
ty::InstanceDef::ClosureOnceShim { call_once } =>
Some(ty::InstanceDef::ClosureOnceShim { call_once }),
ty::InstanceDef::DropGlue(def_id, ref ty) =>
Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?)),
ty::InstanceDef::CloneShim(def_id, ref ty) =>
Some(ty::InstanceDef::CloneShim(def_id, tcx.lift(ty)?)),
}
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for ty::Instance<'a> {
type Lifted = ty::Instance<'tcx>;
def, substs
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for interpret::GlobalId<'a> {
type Lifted = interpret::GlobalId<'tcx>;
instance, promoted
}
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// TypeFoldable implementations. // TypeFoldable implementations.
// //
@ -778,6 +911,74 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<Ty<'tcx>> {
} }
} }
impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
use ty::InstanceDef::*;
Self {
substs: self.substs.fold_with(folder),
def: match self.def {
Item(did) => Item(did.fold_with(folder)),
Intrinsic(did) => Intrinsic(did.fold_with(folder)),
FnPtrShim(did, ty) => FnPtrShim(
did.fold_with(folder),
ty.fold_with(folder),
),
Virtual(did, i) => Virtual(
did.fold_with(folder),
i,
),
ClosureOnceShim { call_once } => ClosureOnceShim {
call_once: call_once.fold_with(folder),
},
DropGlue(did, ty) => DropGlue(
did.fold_with(folder),
ty.fold_with(folder),
),
CloneShim(did, ty) => CloneShim(
did.fold_with(folder),
ty.fold_with(folder),
),
},
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
use ty::InstanceDef::*;
self.substs.visit_with(visitor) ||
match self.def {
Item(did) => did.visit_with(visitor),
Intrinsic(did) => did.visit_with(visitor),
FnPtrShim(did, ty) => {
did.visit_with(visitor) ||
ty.visit_with(visitor)
},
Virtual(did, _) => did.visit_with(visitor),
ClosureOnceShim { call_once } => call_once.visit_with(visitor),
DropGlue(did, ty) => {
did.visit_with(visitor) ||
ty.visit_with(visitor)
},
CloneShim(did, ty) => {
did.visit_with(visitor) ||
ty.visit_with(visitor)
},
}
}
}
impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
Self {
instance: self.instance.fold_with(folder),
promoted: self.promoted
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.instance.visit_with(visitor)
}
}
impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
let sty = match self.sty { let sty = match self.sty {
@ -1243,53 +1444,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self { match *self {
ConstVal::Integral(i) => ConstVal::Integral(i), ConstVal::Value(v) => ConstVal::Value(v),
ConstVal::Float(f) => ConstVal::Float(f),
ConstVal::Str(s) => ConstVal::Str(s),
ConstVal::ByteStr(b) => ConstVal::ByteStr(b),
ConstVal::Bool(b) => ConstVal::Bool(b),
ConstVal::Char(c) => ConstVal::Char(c),
ConstVal::Variant(def_id) => ConstVal::Variant(def_id),
ConstVal::Function(def_id, substs) => {
ConstVal::Function(def_id, substs.fold_with(folder))
}
ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
let new_fields: Vec<_> = fields.iter().map(|&(name, v)| {
(name, v.fold_with(folder))
}).collect();
let fields = if new_fields == fields {
fields
} else {
folder.tcx().alloc_name_const_slice(&new_fields)
};
ConstVal::Aggregate(ConstAggregate::Struct(fields))
}
ConstVal::Aggregate(ConstAggregate::Tuple(fields)) => {
let new_fields: Vec<_> = fields.iter().map(|v| {
v.fold_with(folder)
}).collect();
let fields = if new_fields == fields {
fields
} else {
folder.tcx().alloc_const_slice(&new_fields)
};
ConstVal::Aggregate(ConstAggregate::Tuple(fields))
}
ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
let new_fields: Vec<_> = fields.iter().map(|v| {
v.fold_with(folder)
}).collect();
let fields = if new_fields == fields {
fields
} else {
folder.tcx().alloc_const_slice(&new_fields)
};
ConstVal::Aggregate(ConstAggregate::Array(fields))
}
ConstVal::Aggregate(ConstAggregate::Repeat(v, count)) => {
let v = v.fold_with(folder);
ConstVal::Aggregate(ConstAggregate::Repeat(v, count))
}
ConstVal::Unevaluated(def_id, substs) => { ConstVal::Unevaluated(def_id, substs) => {
ConstVal::Unevaluated(def_id, substs.fold_with(folder)) ConstVal::Unevaluated(def_id, substs.fold_with(folder))
} }
@ -1298,24 +1453,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> {
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self { match *self {
ConstVal::Integral(_) | ConstVal::Value(_) => false,
ConstVal::Float(_) |
ConstVal::Str(_) |
ConstVal::ByteStr(_) |
ConstVal::Bool(_) |
ConstVal::Char(_) |
ConstVal::Variant(_) => false,
ConstVal::Function(_, substs) => substs.visit_with(visitor),
ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
fields.iter().any(|&(_, v)| v.visit_with(visitor))
}
ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
fields.iter().any(|v| v.visit_with(visitor))
}
ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
v.visit_with(visitor)
}
ConstVal::Unevaluated(_, substs) => substs.visit_with(visitor), ConstVal::Unevaluated(_, substs) => substs.visit_with(visitor),
} }
} }

View file

@ -186,9 +186,9 @@ pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}) })
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for TraitImpls { impl<'a> HashStable<StableHashingContext<'a>> for TraitImpls {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let TraitImpls { let TraitImpls {
ref blanket_impls, ref blanket_impls,

View file

@ -22,58 +22,96 @@ use ty::fold::TypeVisitor;
use ty::subst::{Subst, UnpackedKind}; use ty::subst::{Subst, UnpackedKind};
use ty::maps::TyCtxtAt; use ty::maps::TyCtxtAt;
use ty::TypeVariants::*; use ty::TypeVariants::*;
use ty::layout::Integer;
use util::common::ErrorReported; use util::common::ErrorReported;
use middle::lang_items; use middle::lang_items;
use mir::interpret::{Value, PrimVal};
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
HashStable}; HashStable};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use std::cmp; use std::{cmp, fmt};
use std::hash::Hash; use std::hash::Hash;
use std::intrinsics; use std::intrinsics;
use syntax::ast::{self, Name}; use syntax::ast::{self, Name};
use syntax::attr::{self, SignedInt, UnsignedInt}; use syntax::attr::{self, SignedInt, UnsignedInt};
use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::{Span, DUMMY_SP};
type Disr = ConstInt; #[derive(Copy, Clone, Debug)]
pub struct Discr<'tcx> {
pub val: u128,
pub ty: Ty<'tcx>
}
impl<'tcx> fmt::Display for Discr<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
if self.ty.is_signed() {
write!(fmt, "{}", self.val as i128)
} else {
write!(fmt, "{}", self.val)
}
}
}
impl<'tcx> Discr<'tcx> {
/// Adds 1 to the value and wraps around if the maximum for the type is reached
pub fn wrap_incr<'a, 'gcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
self.checked_add(tcx, 1).0
}
pub fn checked_add<'a, 'gcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, n: u128) -> (Self, bool) {
let (int, signed) = match self.ty.sty {
TyInt(ity) => (Integer::from_attr(tcx, SignedInt(ity)), true),
TyUint(uty) => (Integer::from_attr(tcx, UnsignedInt(uty)), false),
_ => bug!("non integer discriminant"),
};
if signed {
let (min, max) = match int {
Integer::I8 => (i8::min_value() as i128, i8::max_value() as i128),
Integer::I16 => (i16::min_value() as i128, i16::max_value() as i128),
Integer::I32 => (i32::min_value() as i128, i32::max_value() as i128),
Integer::I64 => (i64::min_value() as i128, i64::max_value() as i128),
Integer::I128 => (i128::min_value(), i128::max_value()),
};
let val = self.val as i128;
let n = n as i128;
let oflo = val > max - n;
let val = if oflo {
min + (n - (max - val) - 1)
} else {
val + n
};
(Self {
val: val as u128,
ty: self.ty,
}, oflo)
} else {
let (min, max) = match int {
Integer::I8 => (u8::min_value() as u128, u8::max_value() as u128),
Integer::I16 => (u16::min_value() as u128, u16::max_value() as u128),
Integer::I32 => (u32::min_value() as u128, u32::max_value() as u128),
Integer::I64 => (u64::min_value() as u128, u64::max_value() as u128),
Integer::I128 => (u128::min_value(), u128::max_value()),
};
let val = self.val;
let oflo = val > max - n;
let val = if oflo {
min + (n - (max - val) - 1)
} else {
val + n
};
(Self {
val: val,
ty: self.ty,
}, oflo)
}
}
}
pub trait IntTypeExt { pub trait IntTypeExt {
fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>; fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>) fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Discr<'tcx>>)
-> Option<Disr>; -> Option<Discr<'tcx>>;
fn assert_ty_matches(&self, val: Disr); fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Discr<'tcx>;
fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
}
macro_rules! typed_literal {
($tcx:expr, $ty:expr, $lit:expr) => {
match $ty {
SignedInt(ast::IntTy::I8) => ConstInt::I8($lit),
SignedInt(ast::IntTy::I16) => ConstInt::I16($lit),
SignedInt(ast::IntTy::I32) => ConstInt::I32($lit),
SignedInt(ast::IntTy::I64) => ConstInt::I64($lit),
SignedInt(ast::IntTy::I128) => ConstInt::I128($lit),
SignedInt(ast::IntTy::Isize) => match $tcx.sess.target.isize_ty {
ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16($lit)),
ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32($lit)),
ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64($lit)),
_ => bug!(),
},
UnsignedInt(ast::UintTy::U8) => ConstInt::U8($lit),
UnsignedInt(ast::UintTy::U16) => ConstInt::U16($lit),
UnsignedInt(ast::UintTy::U32) => ConstInt::U32($lit),
UnsignedInt(ast::UintTy::U64) => ConstInt::U64($lit),
UnsignedInt(ast::UintTy::U128) => ConstInt::U128($lit),
UnsignedInt(ast::UintTy::Usize) => match $tcx.sess.target.usize_ty {
ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16($lit)),
ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32($lit)),
ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64($lit)),
_ => bug!(),
},
}
}
} }
impl IntTypeExt for attr::IntType { impl IntTypeExt for attr::IntType {
@ -94,33 +132,26 @@ impl IntTypeExt for attr::IntType {
} }
} }
fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr { fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Discr<'tcx> {
typed_literal!(tcx, *self, 0) Discr {
} val: 0,
ty: self.to_ty(tcx)
fn assert_ty_matches(&self, val: Disr) {
match (*self, val) {
(SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {},
(SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {},
(SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {},
(SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {},
(SignedInt(ast::IntTy::I128), ConstInt::I128(_)) => {},
(SignedInt(ast::IntTy::Isize), ConstInt::Isize(_)) => {},
(UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {},
(UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {},
(UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {},
(UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {},
(UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) => {},
(UnsignedInt(ast::UintTy::Usize), ConstInt::Usize(_)) => {},
_ => bug!("disr type mismatch: {:?} vs {:?}", self, val),
} }
} }
fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>) fn disr_incr<'a, 'tcx>(
-> Option<Disr> { &self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
val: Option<Discr<'tcx>>,
) -> Option<Discr<'tcx>> {
if let Some(val) = val { if let Some(val) = val {
self.assert_ty_matches(val); assert_eq!(self.to_ty(tcx), val.ty);
(val + typed_literal!(tcx, *self, 1)).ok() let (new, oflo) = val.checked_add(tcx, 1);
if oflo {
None
} else {
Some(new)
}
} else { } else {
Some(self.initial_discriminant(tcx)) Some(self.initial_discriminant(tcx))
} }
@ -681,31 +712,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}) })
} }
pub fn const_usize(&self, val: u16) -> ConstInt { /// Return whether the node pointed to by def_id is a static item, and its mutability
match self.sess.target.usize_ty { pub fn is_static(&self, def_id: DefId) -> Option<hir::Mutability> {
ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(val as u16)),
ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(val as u32)),
ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(val as u64)),
_ => bug!(),
}
}
/// Check if the node pointed to by def_id is a mutable static item
pub fn is_static_mut(&self, def_id: DefId) -> bool {
if let Some(node) = self.hir.get_if_local(def_id) { if let Some(node) = self.hir.get_if_local(def_id) {
match node { match node {
Node::NodeItem(&hir::Item { Node::NodeItem(&hir::Item {
node: hir::ItemStatic(_, hir::MutMutable, _), .. node: hir::ItemStatic(_, mutbl, _), ..
}) => true, }) => Some(mutbl),
Node::NodeForeignItem(&hir::ForeignItem { Node::NodeForeignItem(&hir::ForeignItem {
node: hir::ForeignItemStatic(_, mutbl), .. node: hir::ForeignItemStatic(_, is_mutbl), ..
}) => mutbl, }) =>
_ => false Some(if is_mutbl {
hir::Mutability::MutMutable
} else {
hir::Mutability::MutImmutable
}),
_ => None
} }
} else { } else {
match self.describe_def(def_id) { match self.describe_def(def_id) {
Some(Def::Static(_, mutbl)) => mutbl, Some(Def::Static(_, is_mutbl)) =>
_ => false Some(if is_mutbl {
hir::Mutability::MutMutable
} else {
hir::Mutability::MutImmutable
}),
_ => None
} }
} }
} }
@ -764,7 +796,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
TyArray(_, n) => { TyArray(_, n) => {
self.hash_discriminant_u8(&n.val); self.hash_discriminant_u8(&n.val);
match n.val { match n.val {
ConstVal::Integral(x) => self.hash(x.to_u64().unwrap()), ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b),
ConstVal::Unevaluated(def_id, _) => self.def_id(def_id), ConstVal::Unevaluated(def_id, _) => self.def_id(def_id),
_ => bug!("arrays should not have {:?} as length", n) _ => bug!("arrays should not have {:?} as length", n)
} }

View file

@ -11,7 +11,7 @@
//! An iterator over the type substructure. //! An iterator over the type substructure.
//! WARNING: this does not keep track of the region depth. //! WARNING: this does not keep track of the region depth.
use middle::const_val::{ConstVal, ConstAggregate}; use middle::const_val::ConstVal;
use ty::{self, Ty}; use ty::{self, Ty};
use rustc_data_structures::small_vec::SmallVec; use rustc_data_structures::small_vec::SmallVec;
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
@ -140,30 +140,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const<'tcx>) { fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const<'tcx>) {
match constant.val { match constant.val {
ConstVal::Integral(_) | ConstVal::Value(_) => {}
ConstVal::Float(_) |
ConstVal::Str(_) |
ConstVal::ByteStr(_) |
ConstVal::Bool(_) |
ConstVal::Char(_) |
ConstVal::Variant(_) => {}
ConstVal::Function(_, substs) => {
stack.extend(substs.types().rev());
}
ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
for &(_, v) in fields.iter().rev() {
push_const(stack, v);
}
}
ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
for v in fields.iter().rev() {
push_const(stack, v);
}
}
ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
push_const(stack, v);
}
ConstVal::Unevaluated(_, substs) => { ConstVal::Unevaluated(_, substs) => {
stack.extend(substs.types().rev()); stack.extend(substs.types().rev());
} }

View file

@ -9,7 +9,7 @@
// except according to those terms. // except according to those terms.
use hir::def_id::DefId; use hir::def_id::DefId;
use middle::const_val::{ConstVal, ConstAggregate}; use middle::const_val::ConstVal;
use infer::InferCtxt; use infer::InferCtxt;
use ty::subst::Substs; use ty::subst::Substs;
use traits; use traits;
@ -217,28 +217,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
fn compute_const(&mut self, constant: &'tcx ty::Const<'tcx>) { fn compute_const(&mut self, constant: &'tcx ty::Const<'tcx>) {
self.require_sized(constant.ty, traits::ConstSized); self.require_sized(constant.ty, traits::ConstSized);
match constant.val { match constant.val {
ConstVal::Integral(_) | ConstVal::Value(_) => {}
ConstVal::Float(_) |
ConstVal::Str(_) |
ConstVal::ByteStr(_) |
ConstVal::Bool(_) |
ConstVal::Char(_) |
ConstVal::Variant(_) |
ConstVal::Function(..) => {}
ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
for &(_, v) in fields {
self.compute_const(v);
}
}
ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
for v in fields {
self.compute_const(v);
}
}
ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
self.compute_const(v);
}
ConstVal::Unevaluated(def_id, substs) => { ConstVal::Unevaluated(def_id, substs) => {
let obligations = self.nominal_obligations(def_id, substs); let obligations = self.nominal_obligations(def_id, substs);
self.out.extend(obligations); self.out.extend(obligations);

View file

@ -21,12 +21,12 @@ use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, Ty
use ty::{TyDynamic, TyInt, TyUint, TyInfer}; use ty::{TyDynamic, TyInt, TyUint, TyInfer};
use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::{self, Ty, TyCtxt, TypeFoldable};
use util::nodemap::FxHashSet; use util::nodemap::FxHashSet;
use mir::interpret::{Value, PrimVal};
use std::cell::Cell; use std::cell::Cell;
use std::fmt; use std::fmt;
use std::usize; use std::usize;
use rustc_const_math::ConstInt;
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
use syntax::abi::Abi; use syntax::abi::Abi;
use syntax::ast::CRATE_NODE_ID; use syntax::ast::CRATE_NODE_ID;
@ -1165,7 +1165,7 @@ define_print! {
TyArray(ty, sz) => { TyArray(ty, sz) => {
print!(f, cx, write("["), print(ty), write("; "))?; print!(f, cx, write("["), print(ty), write("; "))?;
match sz.val { match sz.val {
ConstVal::Integral(ConstInt::Usize(sz)) => { ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => {
write!(f, "{}", sz)?; write!(f, "{}", sz)?;
} }
ConstVal::Unevaluated(_def_id, substs) => { ConstVal::Unevaluated(_def_id, substs) => {

View file

@ -1,19 +0,0 @@
[package]
authors = ["The Rust Project Developers"]
name = "rustc_const_eval"
version = "0.0.0"
[lib]
name = "rustc_const_eval"
path = "lib.rs"
crate-type = ["dylib"]
[dependencies]
arena = { path = "../libarena" }
log = "0.4"
rustc = { path = "../librustc" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }

View file

@ -1,571 +0,0 @@
// Copyright 2014 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(non_snake_case)]
// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {
E0001: r##"
#### Note: this error code is no longer emitted by the compiler.
This error suggests that the expression arm corresponding to the noted pattern
will never be reached as for all possible values of the expression being
matched, one of the preceding patterns will match.
This means that perhaps some of the preceding patterns are too general, this
one is too specific or the ordering is incorrect.
For example, the following `match` block has too many arms:
```
match Some(0) {
Some(bar) => {/* ... */}
x => {/* ... */} // This handles the `None` case
_ => {/* ... */} // All possible cases have already been handled
}
```
`match` blocks have their patterns matched in order, so, for example, putting
a wildcard arm above a more specific arm will make the latter arm irrelevant.
Ensure the ordering of the match arm is correct and remove any superfluous
arms.
"##,
E0002: r##"
#### Note: this error code is no longer emitted by the compiler.
This error indicates that an empty match expression is invalid because the type
it is matching on is non-empty (there exist values of this type). In safe code
it is impossible to create an instance of an empty type, so empty match
expressions are almost never desired. This error is typically fixed by adding
one or more cases to the match expression.
An example of an empty type is `enum Empty { }`. So, the following will work:
```
enum Empty {}
fn foo(x: Empty) {
match x {
// empty
}
}
```
However, this won't:
```compile_fail
fn foo(x: Option<String>) {
match x {
// empty
}
}
```
"##,
E0003: r##"
#### Note: this error code is no longer emitted by the compiler.
Not-a-Number (NaN) values cannot be compared for equality and hence can never
match the input to a match expression. So, the following will not compile:
```compile_fail
const NAN: f32 = 0.0 / 0.0;
let number = 0.1f32;
match number {
NAN => { /* ... */ },
_ => {}
}
```
To match against NaN values, you should instead use the `is_nan()` method in a
guard, like so:
```
let number = 0.1f32;
match number {
x if x.is_nan() => { /* ... */ }
_ => {}
}
```
"##,
E0004: r##"
This error indicates that the compiler cannot guarantee a matching pattern for
one or more possible inputs to a match expression. Guaranteed matches are
required in order to assign values to match expressions, or alternatively,
determine the flow of execution. Erroneous code example:
```compile_fail,E0004
enum Terminator {
HastaLaVistaBaby,
TalkToMyHand,
}
let x = Terminator::HastaLaVistaBaby;
match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered
Terminator::TalkToMyHand => {}
}
```
If you encounter this error you must alter your patterns so that every possible
value of the input type is matched. For types with a small number of variants
(like enums) you should probably cover all cases explicitly. Alternatively, the
underscore `_` wildcard pattern can be added after all other patterns to match
"anything else". Example:
```
enum Terminator {
HastaLaVistaBaby,
TalkToMyHand,
}
let x = Terminator::HastaLaVistaBaby;
match x {
Terminator::TalkToMyHand => {}
Terminator::HastaLaVistaBaby => {}
}
// or:
match x {
Terminator::TalkToMyHand => {}
_ => {}
}
```
"##,
E0005: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee
that a name will be extracted in all cases. Erroneous code example:
```compile_fail,E0005
let x = Some(1);
let Some(y) = x;
// error: refutable pattern in local binding: `None` not covered
```
If you encounter this error you probably need to use a `match` or `if let` to
deal with the possibility of failure. Example:
```
let x = Some(1);
match x {
Some(y) => {
// do something
},
None => {}
}
// or:
if let Some(y) = x {
// do something
}
```
"##,
E0007: r##"
This error indicates that the bindings in a match arm would require a value to
be moved into more than one location, thus violating unique ownership. Code
like the following is invalid as it requires the entire `Option<String>` to be
moved into a variable called `op_string` while simultaneously requiring the
inner `String` to be moved into a variable called `s`.
```compile_fail,E0007
let x = Some("s".to_string());
match x {
op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings
None => {},
}
```
See also the error E0303.
"##,
E0008: r##"
Names bound in match arms retain their type in pattern guards. As such, if a
name is bound by move in a pattern, it should also be moved to wherever it is
referenced in the pattern guard code. Doing so however would prevent the name
from being available in the body of the match arm. Consider the following:
```compile_fail,E0008
match Some("hi".to_string()) {
Some(s) if s.len() == 0 => {}, // use s.
_ => {},
}
```
The variable `s` has type `String`, and its use in the guard is as a variable of
type `String`. The guard code effectively executes in a separate scope to the
body of the arm, so the value would be moved into this anonymous scope and
therefore becomes unavailable in the body of the arm.
The problem above can be solved by using the `ref` keyword.
```
match Some("hi".to_string()) {
Some(ref s) if s.len() == 0 => {},
_ => {},
}
```
Though this example seems innocuous and easy to solve, the problem becomes clear
when it encounters functions which consume the value:
```compile_fail,E0008
struct A{}
impl A {
fn consume(self) -> usize {
0
}
}
fn main() {
let a = Some(A{});
match a {
Some(y) if y.consume() > 0 => {}
_ => {}
}
}
```
In this situation, even the `ref` keyword cannot solve it, since borrowed
content cannot be moved. This problem cannot be solved generally. If the value
can be cloned, here is a not-so-specific solution:
```
#[derive(Clone)]
struct A{}
impl A {
fn consume(self) -> usize {
0
}
}
fn main() {
let a = Some(A{});
match a{
Some(ref y) if y.clone().consume() > 0 => {}
_ => {}
}
}
```
If the value will be consumed in the pattern guard, using its clone will not
move its ownership, so the code works.
"##,
E0009: r##"
In a pattern, all values that don't implement the `Copy` trait have to be bound
the same way. The goal here is to avoid binding simultaneously by-move and
by-ref.
This limitation may be removed in a future version of Rust.
Erroneous code example:
```compile_fail,E0009
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the
// same pattern
None => panic!()
}
```
You have two solutions:
Solution #1: Bind the pattern's values the same way.
```
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((ref y, ref z)) => {},
// or Some((y, z)) => {}
None => panic!()
}
```
Solution #2: Implement the `Copy` trait for the `X` structure.
However, please keep in mind that the first solution should be preferred.
```
#[derive(Clone, Copy)]
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((y, ref z)) => {},
None => panic!()
}
```
"##,
E0158: r##"
`const` and `static` mean different things. A `const` is a compile-time
constant, an alias for a literal value. This property means you can match it
directly within a pattern.
The `static` keyword, on the other hand, guarantees a fixed location in memory.
This does not always mean that the value is constant. For example, a global
mutex can be declared `static` as well.
If you want to match against a `static`, consider using a guard instead:
```
static FORTY_TWO: i32 = 42;
match Some(42) {
Some(x) if x == FORTY_TWO => {}
_ => {}
}
```
"##,
E0162: r##"
An if-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding instead. For instance:
```compile_fail,E0162
struct Irrefutable(i32);
let irr = Irrefutable(0);
// This fails to compile because the match is irrefutable.
if let Irrefutable(x) = irr {
// This body will always be executed.
// ...
}
```
Try this instead:
```
struct Irrefutable(i32);
let irr = Irrefutable(0);
let Irrefutable(x) = irr;
println!("{}", x);
```
"##,
E0165: r##"
A while-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding inside a `loop` instead. For instance:
```compile_fail,E0165
struct Irrefutable(i32);
let irr = Irrefutable(0);
// This fails to compile because the match is irrefutable.
while let Irrefutable(x) = irr {
// ...
}
```
Try this instead:
```no_run
struct Irrefutable(i32);
let irr = Irrefutable(0);
loop {
let Irrefutable(x) = irr;
// ...
}
```
"##,
E0170: r##"
Enum variants are qualified by default. For example, given this type:
```
enum Method {
GET,
POST,
}
```
You would match it using:
```
enum Method {
GET,
POST,
}
let m = Method::GET;
match m {
Method::GET => {},
Method::POST => {},
}
```
If you don't qualify the names, the code will bind new variables named "GET" and
"POST" instead. This behavior is likely not what you want, so `rustc` warns when
that happens.
Qualified names are good practice, and most code works well with them. But if
you prefer them unqualified, you can import the variants into scope:
```
use Method::*;
enum Method { GET, POST }
# fn main() {}
```
If you want others to be able to import variants from your module directly, use
`pub use`:
```
pub use Method::*;
pub enum Method { GET, POST }
# fn main() {}
```
"##,
E0297: r##"
#### Note: this error code is no longer emitted by the compiler.
Patterns used to bind names must be irrefutable. That is, they must guarantee
that a name will be extracted in all cases. Instead of pattern matching the
loop variable, consider using a `match` or `if let` inside the loop body. For
instance:
```compile_fail,E0005
let xs : Vec<Option<i32>> = vec![Some(1), None];
// This fails because `None` is not covered.
for Some(x) in xs {
// ...
}
```
Match inside the loop instead:
```
let xs : Vec<Option<i32>> = vec![Some(1), None];
for item in xs {
match item {
Some(x) => {},
None => {},
}
}
```
Or use `if let`:
```
let xs : Vec<Option<i32>> = vec![Some(1), None];
for item in xs {
if let Some(x) = item {
// ...
}
}
```
"##,
E0301: r##"
Mutable borrows are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if mutable
borrows were allowed:
```compile_fail,E0301
match Some(()) {
None => { },
option if option.take().is_none() => {
/* impossible, option is `Some` */
},
Some(_) => { } // When the previous match failed, the option became `None`.
}
```
"##,
E0302: r##"
Assignments are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if assignments
were allowed:
```compile_fail,E0302
match Some(()) {
None => { },
option if { option = None; false } => { },
Some(_) => { } // When the previous match failed, the option became `None`.
}
```
"##,
E0303: r##"
In certain cases it is possible for sub-bindings to violate memory safety.
Updates to the borrow checker in a future version of Rust may remove this
restriction, but for now patterns must be rewritten without sub-bindings.
Before:
```compile_fail,E0303
match Some("hi".to_string()) {
ref op_string_ref @ Some(s) => {},
None => {},
}
```
After:
```
match Some("hi".to_string()) {
Some(ref s) => {
let op_string_ref = &Some(s);
// ...
},
None => {},
}
```
The `op_string_ref` binding has type `&Option<&String>` in both cases.
See also https://github.com/rust-lang/rust/issues/14587
"##,
}
register_diagnostics! {
// E0298, // cannot compare constants
// E0299, // mismatched types between arms
// E0471, // constant evaluation error (in pattern)
}

View file

@ -1,687 +0,0 @@
// Copyright 2012-2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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::middle::const_val::ConstAggregate::*;
use rustc::middle::const_val::ErrKind::*;
use rustc::middle::const_val::{ByteArray, ConstVal, ConstEvalErr, EvalResult, ErrKind};
use rustc::hir::map::blocks::FnLikeNode;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::util::IntTypeExt;
use rustc::ty::subst::{Substs, Subst};
use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
use syntax::abi::Abi;
use syntax::ast;
use syntax::attr;
use rustc::hir::{self, Expr};
use syntax_pos::Span;
use std::cmp::Ordering;
use rustc_const_math::*;
macro_rules! signal {
($e:expr, $exn:expr) => {
return Err(ConstEvalErr { span: $e.span, kind: $exn })
}
}
macro_rules! math {
($e:expr, $op:expr) => {
match $op {
Ok(val) => val,
Err(e) => signal!($e, ErrKind::from(e)),
}
}
}
/// * `DefId` is the id of the constant.
/// * `Substs` is the monomorphized substitutions for the expression.
pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
-> Option<(DefId, &'tcx Substs<'tcx>)> {
ty::Instance::resolve(
tcx,
key.param_env,
key.value.0,
key.value.1,
).map(|instance| (instance.def_id(), instance.substs))
}
pub struct ConstContext<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
param_env: ty::ParamEnv<'tcx>,
substs: &'tcx Substs<'tcx>,
fn_args: Option<NodeMap<&'tcx ty::Const<'tcx>>>
}
impl<'a, 'tcx> ConstContext<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
tables: &'a ty::TypeckTables<'tcx>)
-> Self {
ConstContext {
tcx,
param_env: param_env_and_substs.param_env,
tables,
substs: param_env_and_substs.value,
fn_args: None
}
}
/// Evaluate a constant expression in a context where the expression isn't
/// guaranteed to be evaluable.
pub fn eval(&self, e: &'tcx Expr) -> EvalResult<'tcx> {
if self.tables.tainted_by_errors {
signal!(e, TypeckError);
}
eval_const_expr_partial(self, e)
}
}
type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
e: &'tcx Expr) -> EvalResult<'tcx> {
trace!("eval_const_expr_partial: {:?}", e);
let tcx = cx.tcx;
let ty = cx.tables.expr_ty(e).subst(tcx, cx.substs);
let mk_const = |val| tcx.mk_const(ty::Const { val, ty });
let result = match e.node {
hir::ExprUnary(hir::UnNeg, ref inner) => {
// unary neg literals already got their sign during creation
if let hir::ExprLit(ref lit) = inner.node {
use syntax::ast::*;
use syntax::ast::LitIntType::*;
const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128;
const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128;
const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
const I128_OVERFLOW: u128 = i128::min_value() as u128;
let negated = match (&lit.node, &ty.sty) {
(&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
(&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
Some(I8(i8::min_value()))
},
(&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
(&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
Some(I16(i16::min_value()))
},
(&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
(&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
Some(I32(i32::min_value()))
},
(&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
(&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
Some(I64(i64::min_value()))
},
(&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
(&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
Some(I128(i128::min_value()))
},
(&LitKind::Int(n, _), &ty::TyInt(IntTy::Isize)) |
(&LitKind::Int(n, Signed(IntTy::Isize)), _) => {
match tcx.sess.target.isize_ty {
IntTy::I16 => if n == I16_OVERFLOW {
Some(Isize(Is16(i16::min_value())))
} else {
None
},
IntTy::I32 => if n == I32_OVERFLOW {
Some(Isize(Is32(i32::min_value())))
} else {
None
},
IntTy::I64 => if n == I64_OVERFLOW {
Some(Isize(Is64(i64::min_value())))
} else {
None
},
_ => span_bug!(e.span, "typeck error")
}
},
_ => None
};
if let Some(i) = negated {
return Ok(mk_const(Integral(i)));
}
}
mk_const(match cx.eval(inner)?.val {
Float(f) => Float(-f),
Integral(i) => Integral(math!(e, -i)),
_ => signal!(e, TypeckError)
})
}
hir::ExprUnary(hir::UnNot, ref inner) => {
mk_const(match cx.eval(inner)?.val {
Integral(i) => Integral(math!(e, !i)),
Bool(b) => Bool(!b),
_ => signal!(e, TypeckError)
})
}
hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
hir::ExprBinary(op, ref a, ref b) => {
// technically, if we don't have type hints, but integral eval
// gives us a type through a type-suffix, cast or const def type
// we need to re-eval the other value of the BinOp if it was
// not inferred
mk_const(match (cx.eval(a)?.val, cx.eval(b)?.val) {
(Float(a), Float(b)) => {
use std::cmp::Ordering::*;
match op.node {
hir::BiAdd => Float(math!(e, a + b)),
hir::BiSub => Float(math!(e, a - b)),
hir::BiMul => Float(math!(e, a * b)),
hir::BiDiv => Float(math!(e, a / b)),
hir::BiRem => Float(math!(e, a % b)),
hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
_ => span_bug!(e.span, "typeck error"),
}
}
(Integral(a), Integral(b)) => {
use std::cmp::Ordering::*;
match op.node {
hir::BiAdd => Integral(math!(e, a + b)),
hir::BiSub => Integral(math!(e, a - b)),
hir::BiMul => Integral(math!(e, a * b)),
hir::BiDiv => Integral(math!(e, a / b)),
hir::BiRem => Integral(math!(e, a % b)),
hir::BiBitAnd => Integral(math!(e, a & b)),
hir::BiBitOr => Integral(math!(e, a | b)),
hir::BiBitXor => Integral(math!(e, a ^ b)),
hir::BiShl => Integral(math!(e, a << b)),
hir::BiShr => Integral(math!(e, a >> b)),
hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
_ => span_bug!(e.span, "typeck error"),
}
}
(Bool(a), Bool(b)) => {
Bool(match op.node {
hir::BiAnd => a && b,
hir::BiOr => a || b,
hir::BiBitXor => a ^ b,
hir::BiBitAnd => a & b,
hir::BiBitOr => a | b,
hir::BiEq => a == b,
hir::BiNe => a != b,
hir::BiLt => a < b,
hir::BiLe => a <= b,
hir::BiGe => a >= b,
hir::BiGt => a > b,
_ => span_bug!(e.span, "typeck error"),
})
}
(Char(a), Char(b)) => {
Bool(match op.node {
hir::BiEq => a == b,
hir::BiNe => a != b,
hir::BiLt => a < b,
hir::BiLe => a <= b,
hir::BiGe => a >= b,
hir::BiGt => a > b,
_ => span_bug!(e.span, "typeck error"),
})
}
_ => signal!(e, MiscBinaryOp),
})
}
hir::ExprCast(ref base, _) => {
let base_val = cx.eval(base)?;
let base_ty = cx.tables.expr_ty(base).subst(tcx, cx.substs);
if ty == base_ty {
base_val
} else {
match cast_const(tcx, base_val.val, ty) {
Ok(val) => mk_const(val),
Err(kind) => signal!(e, kind),
}
}
}
hir::ExprPath(ref qpath) => {
let substs = cx.tables.node_substs(e.hir_id).subst(tcx, cx.substs);
match cx.tables.qpath_def(qpath, e.hir_id) {
Def::Const(def_id) |
Def::AssociatedConst(def_id) => {
let substs = tcx.normalize_associated_type_in_env(&substs, cx.param_env);
match tcx.at(e.span).const_eval(cx.param_env.and((def_id, substs))) {
Ok(val) => val,
Err(ConstEvalErr { kind: TypeckError, .. }) => {
signal!(e, TypeckError);
}
Err(err) => {
debug!("bad reference: {:?}, {:?}", err.description(), err.span);
signal!(e, ErroneousReferencedConstant(box err))
},
}
},
Def::VariantCtor(variant_def, CtorKind::Const) => {
mk_const(Variant(variant_def))
}
Def::VariantCtor(_, CtorKind::Fn) => {
signal!(e, UnimplementedConstVal("enum variants"));
}
Def::StructCtor(_, CtorKind::Const) => {
mk_const(Aggregate(Struct(&[])))
}
Def::StructCtor(_, CtorKind::Fn) => {
signal!(e, UnimplementedConstVal("tuple struct constructors"))
}
Def::Local(id) => {
debug!("Def::Local({:?}): {:?}", id, cx.fn_args);
if let Some(&val) = cx.fn_args.as_ref().and_then(|args| args.get(&id)) {
val
} else {
signal!(e, NonConstPath);
}
},
Def::Method(id) | Def::Fn(id) => mk_const(Function(id, substs)),
Def::Err => span_bug!(e.span, "typeck error"),
_ => signal!(e, NonConstPath),
}
}
hir::ExprCall(ref callee, ref args) => {
let (def_id, substs) = match cx.eval(callee)?.val {
Function(def_id, substs) => (def_id, substs),
_ => signal!(e, TypeckError),
};
if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic {
let layout_of = |ty: Ty<'tcx>| {
let ty = tcx.erase_regions(&ty);
tcx.at(e.span).layout_of(cx.param_env.and(ty)).map_err(|err| {
ConstEvalErr { span: e.span, kind: LayoutError(err) }
})
};
match &tcx.item_name(def_id)[..] {
"size_of" => {
let size = layout_of(substs.type_at(0))?.size.bytes();
return Ok(mk_const(Integral(Usize(ConstUsize::new(size,
tcx.sess.target.usize_ty).unwrap()))));
}
"min_align_of" => {
let align = layout_of(substs.type_at(0))?.align.abi();
return Ok(mk_const(Integral(Usize(ConstUsize::new(align,
tcx.sess.target.usize_ty).unwrap()))));
}
"type_id" => {
let type_id = tcx.type_id_hash(substs.type_at(0));
return Ok(mk_const(Integral(U64(type_id))));
}
_ => signal!(e, TypeckError)
}
}
let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
if fn_like.constness() == hir::Constness::Const {
tcx.hir.body(fn_like.body())
} else {
signal!(e, TypeckError)
}
} else {
signal!(e, TypeckError)
}
} else {
if tcx.is_const_fn(def_id) {
tcx.extern_const_body(def_id).body
} else {
signal!(e, TypeckError)
}
};
let arg_ids = body.arguments.iter().map(|arg| match arg.pat.node {
hir::PatKind::Binding(_, canonical_id, _, _) => Some(canonical_id),
_ => None
}).collect::<Vec<_>>();
assert_eq!(arg_ids.len(), args.len());
let mut call_args = NodeMap();
for (arg, arg_expr) in arg_ids.into_iter().zip(args.iter()) {
let arg_val = cx.eval(arg_expr)?;
debug!("const call arg: {:?}", arg);
if let Some(id) = arg {
assert!(call_args.insert(id, arg_val).is_none());
}
}
debug!("const call({:?})", call_args);
let callee_cx = ConstContext {
tcx,
param_env: cx.param_env,
tables: tcx.typeck_tables_of(def_id),
substs,
fn_args: Some(call_args)
};
callee_cx.eval(&body.value)?
},
hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty) {
Ok(val) => mk_const(val),
Err(err) => signal!(e, err),
},
hir::ExprBlock(ref block) => {
match block.expr {
Some(ref expr) => cx.eval(expr)?,
None => mk_const(Aggregate(Tuple(&[]))),
}
}
hir::ExprType(ref e, _) => cx.eval(e)?,
hir::ExprTup(ref fields) => {
let values = fields.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
mk_const(Aggregate(Tuple(tcx.alloc_const_slice(&values))))
}
hir::ExprStruct(_, ref fields, _) => {
mk_const(Aggregate(Struct(tcx.alloc_name_const_slice(&fields.iter().map(|f| {
cx.eval(&f.expr).map(|v| (f.name.node, v))
}).collect::<Result<Vec<_>, _>>()?))))
}
hir::ExprIndex(ref arr, ref idx) => {
if !tcx.features().const_indexing {
signal!(e, IndexOpFeatureGated);
}
let arr = cx.eval(arr)?;
let idx = match cx.eval(idx)?.val {
Integral(Usize(i)) => i.as_u64(),
_ => signal!(idx, IndexNotUsize),
};
assert_eq!(idx as usize as u64, idx);
match arr.val {
Aggregate(Array(v)) => {
if let Some(&elem) = v.get(idx as usize) {
elem
} else {
let n = v.len() as u64;
signal!(e, IndexOutOfBounds { len: n, index: idx })
}
}
Aggregate(Repeat(.., n)) if idx >= n => {
signal!(e, IndexOutOfBounds { len: n, index: idx })
}
Aggregate(Repeat(elem, _)) => elem,
ByteStr(b) if idx >= b.data.len() as u64 => {
signal!(e, IndexOutOfBounds { len: b.data.len() as u64, index: idx })
}
ByteStr(b) => {
mk_const(Integral(U8(b.data[idx as usize])))
},
_ => signal!(e, IndexedNonVec),
}
}
hir::ExprArray(ref v) => {
let values = v.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
mk_const(Aggregate(Array(tcx.alloc_const_slice(&values))))
}
hir::ExprRepeat(ref elem, _) => {
let n = match ty.sty {
ty::TyArray(_, n) => n.val.to_const_int().unwrap().to_u64().unwrap(),
_ => span_bug!(e.span, "typeck error")
};
mk_const(Aggregate(Repeat(cx.eval(elem)?, n)))
},
hir::ExprTupField(ref base, index) => {
if let Aggregate(Tuple(fields)) = cx.eval(base)?.val {
fields[index.node]
} else {
signal!(base, ExpectedConstTuple);
}
}
hir::ExprField(ref base, field_name) => {
if let Aggregate(Struct(fields)) = cx.eval(base)?.val {
if let Some(&(_, f)) = fields.iter().find(|&&(name, _)| name == field_name.node) {
f
} else {
signal!(e, MissingStructField);
}
} else {
signal!(base, ExpectedConstStruct);
}
}
hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")),
_ => signal!(e, MiscCatchAll)
};
Ok(result)
}
fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
val: ConstInt,
ty: Ty<'tcx>)
-> CastResult<'tcx> {
let v = val.to_u128_unchecked();
match ty.sty {
ty::TyBool if v == 0 => Ok(Bool(false)),
ty::TyBool if v == 1 => Ok(Bool(true)),
ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i128 as i8))),
ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i128 as i16))),
ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i128 as i32))),
ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))),
ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))),
ty::TyInt(ast::IntTy::Isize) => {
Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.isize_ty))))
},
ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))),
ty::TyUint(ast::UintTy::Usize) => {
Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.usize_ty))))
},
ty::TyFloat(fty) => {
if let Some(i) = val.to_u128() {
Ok(Float(ConstFloat::from_u128(i, fty)))
} else {
// The value must be negative, go through signed integers.
let i = val.to_u128_unchecked() as i128;
Ok(Float(ConstFloat::from_i128(i, fty)))
}
}
ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
ty::TyChar => match val {
U8(u) => Ok(Char(u as char)),
_ => bug!(),
},
_ => Err(CannotCast),
}
}
fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
val: ConstFloat,
ty: Ty<'tcx>) -> CastResult<'tcx> {
let int_width = |ty| {
ty::layout::Integer::from_attr(tcx, ty).size().bits() as usize
};
match ty.sty {
ty::TyInt(ity) => {
if let Some(i) = val.to_i128(int_width(attr::SignedInt(ity))) {
cast_const_int(tcx, I128(i), ty)
} else {
Err(CannotCast)
}
}
ty::TyUint(uty) => {
if let Some(i) = val.to_u128(int_width(attr::UnsignedInt(uty))) {
cast_const_int(tcx, U128(i), ty)
} else {
Err(CannotCast)
}
}
ty::TyFloat(fty) => Ok(Float(val.convert(fty))),
_ => Err(CannotCast),
}
}
fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
val: ConstVal<'tcx>,
ty: Ty<'tcx>)
-> CastResult<'tcx> {
match val {
Integral(i) => cast_const_int(tcx, i, ty),
Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
Float(f) => cast_const_float(tcx, f, ty),
Char(c) => cast_const_int(tcx, U32(c as u32), ty),
Variant(v) => {
let adt = tcx.adt_def(tcx.parent_def_id(v).unwrap());
let idx = adt.variant_index_with_id(v);
cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty)
}
Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
ByteStr(b) => match ty.sty {
ty::TyRawPtr(_) => {
Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
},
ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
ty::TyArray(ty, n) => {
let n = n.val.to_const_int().unwrap().to_u64().unwrap();
if ty == tcx.types.u8 && n == b.data.len() as u64 {
Ok(val)
} else {
Err(CannotCast)
}
}
ty::TySlice(_) => {
Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
},
_ => Err(CannotCast),
},
_ => Err(CannotCast),
},
Str(s) => match ty.sty {
ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")),
ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
ty::TyStr => Ok(Str(s)),
_ => Err(CannotCast),
},
_ => Err(CannotCast),
},
_ => Err(CannotCast),
}
}
fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mut ty: Ty<'tcx>)
-> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
use syntax::ast::*;
use syntax::ast::LitIntType::*;
if let ty::TyAdt(adt, _) = ty.sty {
if adt.is_enum() {
ty = adt.repr.discr_type().to_ty(tcx)
}
}
match *lit {
LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
LitKind::ByteStr(ref data) => Ok(ByteStr(ByteArray { data })),
LitKind::Byte(n) => Ok(Integral(U8(n))),
LitKind::Int(n, hint) => {
match (&ty.sty, hint) {
(&ty::TyInt(ity), _) |
(_, Signed(ity)) => {
Ok(Integral(ConstInt::new_signed_truncating(n as i128,
ity, tcx.sess.target.isize_ty)))
}
(&ty::TyUint(uty), _) |
(_, Unsigned(uty)) => {
Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
uty, tcx.sess.target.usize_ty)))
}
_ => bug!()
}
}
LitKind::Float(n, fty) => {
parse_float(&n.as_str(), fty).map(Float)
}
LitKind::FloatUnsuffixed(n) => {
let fty = match ty.sty {
ty::TyFloat(fty) => fty,
_ => bug!()
};
parse_float(&n.as_str(), fty).map(Float)
}
LitKind::Bool(b) => Ok(Bool(b)),
LitKind::Char(c) => Ok(Char(c)),
}
}
fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
-> Result<ConstFloat, ErrKind<'tcx>> {
ConstFloat::from_str(num, fty).map_err(|_| {
// FIXME(#31407) this is only necessary because float parsing is buggy
UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
})
}
pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
-> Result<Ordering, ErrorReported>
{
let result = match (a, b) {
(&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
(&Float(a), &Float(b)) => a.try_cmp(b).ok(),
(&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
(&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
(&ByteStr(a), &ByteStr(b)) => Some(a.data.cmp(b.data)),
(&Char(a), &Char(b)) => Some(a.cmp(&b)),
_ => None,
};
match result {
Some(result) => Ok(result),
None => {
// FIXME: can this ever be reached?
tcx.sess.delay_span_bug(span,
&format!("type mismatch comparing {:?} and {:?}", a, b));
Err(ErrorReported)
}
}
}
impl<'a, 'tcx> ConstContext<'a, 'tcx> {
pub fn compare_lit_exprs(&self,
span: Span,
a: &'tcx Expr,
b: &'tcx Expr) -> Result<Ordering, ErrorReported> {
let tcx = self.tcx;
let a = match self.eval(a) {
Ok(a) => a,
Err(e) => {
e.report(tcx, a.span, "expression");
return Err(ErrorReported);
}
};
let b = match self.eval(b) {
Ok(b) => b,
Err(e) => {
e.report(tcx, b.span, "expression");
return Err(ErrorReported);
}
};
compare_const_vals(tcx, span, &a.val, &b.val)
}
}

View file

@ -1,590 +0,0 @@
// Copyright 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cmp::Ordering;
use syntax::attr::IntType;
use syntax::ast::{IntTy, UintTy};
use super::isize::*;
use super::usize::*;
use super::err::*;
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
pub enum ConstInt {
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
Isize(ConstIsize),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
Usize(ConstUsize),
}
pub use self::ConstInt::*;
macro_rules! bounds {
($ct: ty, $($t:ident $min:ident $max:ident)*) => {
$(
pub const $min: $ct = $t::min_value() as $ct;
pub const $max: $ct = $t::max_value() as $ct;
)*
};
($ct: ty: $min_val: expr, $($t:ident $min:ident $max:ident)*) => {
$(
pub const $min: $ct = $min_val;
pub const $max: $ct = $t::max_value() as $ct;
)*
}
}
mod ubounds {
#![allow(dead_code)]
bounds!{u128: 0,
i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX
u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX u128 U128MIN U128MAX
// do not add constants for isize/usize, because these are guaranteed to be wrong for
// arbitrary host/target combinations
}
}
mod ibounds {
#![allow(dead_code)]
bounds!(i128, u64 U64MIN U64MAX);
pub const U128MIN: i128 = 0;
pub const U128MAX: i128 = i128::max_value();
bounds!{i128,
i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX
u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX
// do not add constants for isize/usize, because these are guaranteed to be wrong for
// arbitrary host/target combinations
}
}
impl ConstInt {
/// Creates a new unsigned ConstInt with matching type while also checking that overflow does
/// not happen.
pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt> {
match ty {
UintTy::U8 if val <= ubounds::U8MAX => Some(U8(val as u8)),
UintTy::U16 if val <= ubounds::U16MAX => Some(U16(val as u16)),
UintTy::U32 if val <= ubounds::U32MAX => Some(U32(val as u32)),
UintTy::U64 if val <= ubounds::U64MAX => Some(U64(val as u64)),
UintTy::Usize if val <= ubounds::U64MAX => ConstUsize::new(val as u64, usize_ty).ok()
.map(Usize),
UintTy::U128 => Some(U128(val)),
_ => None
}
}
/// Creates a new signed ConstInt with matching type while also checking that overflow does
/// not happen.
pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option<ConstInt> {
match ty {
IntTy::I8 if val <= ibounds::I8MAX => Some(I8(val as i8)),
IntTy::I16 if val <= ibounds::I16MAX => Some(I16(val as i16)),
IntTy::I32 if val <= ibounds::I32MAX => Some(I32(val as i32)),
IntTy::I64 if val <= ibounds::I64MAX => Some(I64(val as i64)),
IntTy::Isize if val <= ibounds::I64MAX => ConstIsize::new(val as i64, isize_ty).ok()
.map(Isize),
IntTy::I128 => Some(I128(val)),
_ => None
}
}
/// Creates a new unsigned ConstInt with matching type.
pub fn new_unsigned_truncating(val: u128, ty: UintTy, usize_ty: UintTy) -> ConstInt {
match ty {
UintTy::U8 => U8(val as u8),
UintTy::U16 => U16(val as u16),
UintTy::U32 => U32(val as u32),
UintTy::U64 => U64(val as u64),
UintTy::Usize => Usize(ConstUsize::new_truncating(val, usize_ty)),
UintTy::U128 => U128(val)
}
}
/// Creates a new signed ConstInt with matching type.
pub fn new_signed_truncating(val: i128, ty: IntTy, isize_ty: IntTy) -> ConstInt {
match ty {
IntTy::I8 => I8(val as i8),
IntTy::I16 => I16(val as i16),
IntTy::I32 => I32(val as i32),
IntTy::I64 => I64(val as i64),
IntTy::Isize => Isize(ConstIsize::new_truncating(val, isize_ty)),
IntTy::I128 => I128(val)
}
}
/// Description of the type, not the value
pub fn description(&self) -> &'static str {
match *self {
I8(_) => "i8",
I16(_) => "i16",
I32(_) => "i32",
I64(_) => "i64",
I128(_) => "i128",
Isize(_) => "isize",
U8(_) => "u8",
U16(_) => "u16",
U32(_) => "u32",
U64(_) => "u64",
U128(_) => "u128",
Usize(_) => "usize",
}
}
/// Erases the type and returns a u128.
/// This is not the same as `-5i8 as u128` but as `-5i8 as i128 as u128`
pub fn to_u128_unchecked(self) -> u128 {
match self {
I8(i) => i as i128 as u128,
I16(i) => i as i128 as u128,
I32(i) => i as i128 as u128,
I64(i) => i as i128 as u128,
I128(i) => i as i128 as u128,
Isize(Is16(i)) => i as i128 as u128,
Isize(Is32(i)) => i as i128 as u128,
Isize(Is64(i)) => i as i128 as u128,
U8(i) => i as u128,
U16(i) => i as u128,
U32(i) => i as u128,
U64(i) => i as u128,
U128(i) => i as u128,
Usize(Us16(i)) => i as u128,
Usize(Us32(i)) => i as u128,
Usize(Us64(i)) => i as u128,
}
}
/// Converts the value to a `u32` if it's in the range 0...std::u32::MAX
pub fn to_u32(&self) -> Option<u32> {
self.to_u128().and_then(|v| if v <= u32::max_value() as u128 {
Some(v as u32)
} else {
None
})
}
/// Converts the value to a `u64` if it's in the range 0...std::u64::MAX
pub fn to_u64(&self) -> Option<u64> {
self.to_u128().and_then(|v| if v <= u64::max_value() as u128 {
Some(v as u64)
} else {
None
})
}
/// Converts the value to a `u128` if it's in the range 0...std::u128::MAX
pub fn to_u128(&self) -> Option<u128> {
match *self {
I8(v) if v >= 0 => Some(v as u128),
I16(v) if v >= 0 => Some(v as u128),
I32(v) if v >= 0 => Some(v as u128),
I64(v) if v >= 0 => Some(v as u128),
I128(v) if v >= 0 => Some(v as u128),
Isize(Is16(v)) if v >= 0 => Some(v as u128),
Isize(Is32(v)) if v >= 0 => Some(v as u128),
Isize(Is64(v)) if v >= 0 => Some(v as u128),
U8(v) => Some(v as u128),
U16(v) => Some(v as u128),
U32(v) => Some(v as u128),
U64(v) => Some(v as u128),
U128(v) => Some(v as u128),
Usize(Us16(v)) => Some(v as u128),
Usize(Us32(v)) => Some(v as u128),
Usize(Us64(v)) => Some(v as u128),
_ => None,
}
}
pub fn is_negative(&self) -> bool {
match *self {
I8(v) => v < 0,
I16(v) => v < 0,
I32(v) => v < 0,
I64(v) => v < 0,
I128(v) => v < 0,
Isize(Is16(v)) => v < 0,
Isize(Is32(v)) => v < 0,
Isize(Is64(v)) => v < 0,
_ => false,
}
}
/// Compares the values if they are of the same type
pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> {
match (self, rhs) {
(I8(a), I8(b)) => Ok(a.cmp(&b)),
(I16(a), I16(b)) => Ok(a.cmp(&b)),
(I32(a), I32(b)) => Ok(a.cmp(&b)),
(I64(a), I64(b)) => Ok(a.cmp(&b)),
(I128(a), I128(b)) => Ok(a.cmp(&b)),
(Isize(Is16(a)), Isize(Is16(b))) => Ok(a.cmp(&b)),
(Isize(Is32(a)), Isize(Is32(b))) => Ok(a.cmp(&b)),
(Isize(Is64(a)), Isize(Is64(b))) => Ok(a.cmp(&b)),
(U8(a), U8(b)) => Ok(a.cmp(&b)),
(U16(a), U16(b)) => Ok(a.cmp(&b)),
(U32(a), U32(b)) => Ok(a.cmp(&b)),
(U64(a), U64(b)) => Ok(a.cmp(&b)),
(U128(a), U128(b)) => Ok(a.cmp(&b)),
(Usize(Us16(a)), Usize(Us16(b))) => Ok(a.cmp(&b)),
(Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)),
(Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)),
_ => Err(CmpBetweenUnequalTypes),
}
}
/// Adds 1 to the value and wraps around if the maximum for the type is reached
pub fn wrap_incr(self) -> Self {
macro_rules! add1 {
($e:expr) => { ($e).wrapping_add(1) }
}
match self {
ConstInt::I8(i) => ConstInt::I8(add1!(i)),
ConstInt::I16(i) => ConstInt::I16(add1!(i)),
ConstInt::I32(i) => ConstInt::I32(add1!(i)),
ConstInt::I64(i) => ConstInt::I64(add1!(i)),
ConstInt::I128(i) => ConstInt::I128(add1!(i)),
ConstInt::Isize(ConstIsize::Is16(i)) => ConstInt::Isize(ConstIsize::Is16(add1!(i))),
ConstInt::Isize(ConstIsize::Is32(i)) => ConstInt::Isize(ConstIsize::Is32(add1!(i))),
ConstInt::Isize(ConstIsize::Is64(i)) => ConstInt::Isize(ConstIsize::Is64(add1!(i))),
ConstInt::U8(i) => ConstInt::U8(add1!(i)),
ConstInt::U16(i) => ConstInt::U16(add1!(i)),
ConstInt::U32(i) => ConstInt::U32(add1!(i)),
ConstInt::U64(i) => ConstInt::U64(add1!(i)),
ConstInt::U128(i) => ConstInt::U128(add1!(i)),
ConstInt::Usize(ConstUsize::Us16(i)) => ConstInt::Usize(ConstUsize::Us16(add1!(i))),
ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))),
ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))),
}
}
pub fn int_type(self) -> IntType {
match self {
ConstInt::I8(_) => IntType::SignedInt(IntTy::I8),
ConstInt::I16(_) => IntType::SignedInt(IntTy::I16),
ConstInt::I32(_) => IntType::SignedInt(IntTy::I32),
ConstInt::I64(_) => IntType::SignedInt(IntTy::I64),
ConstInt::I128(_) => IntType::SignedInt(IntTy::I128),
ConstInt::Isize(_) => IntType::SignedInt(IntTy::Isize),
ConstInt::U8(_) => IntType::UnsignedInt(UintTy::U8),
ConstInt::U16(_) => IntType::UnsignedInt(UintTy::U16),
ConstInt::U32(_) => IntType::UnsignedInt(UintTy::U32),
ConstInt::U64(_) => IntType::UnsignedInt(UintTy::U64),
ConstInt::U128(_) => IntType::UnsignedInt(UintTy::U128),
ConstInt::Usize(_) => IntType::UnsignedInt(UintTy::Usize),
}
}
}
impl ::std::cmp::PartialOrd for ConstInt {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.try_cmp(*other).ok()
}
}
impl ::std::cmp::Ord for ConstInt {
fn cmp(&self, other: &Self) -> Ordering {
self.try_cmp(*other).unwrap()
}
}
impl ::std::fmt::Display for ConstInt {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
match *self {
I8(i) => write!(fmt, "{}i8", i),
I16(i) => write!(fmt, "{}i16", i),
I32(i) => write!(fmt, "{}i32", i),
I64(i) => write!(fmt, "{}i64", i),
I128(i) => write!(fmt, "{}i128", i),
Isize(i) => write!(fmt, "{}isize", i),
U8(i) => write!(fmt, "{}u8", i),
U16(i) => write!(fmt, "{}u16", i),
U32(i) => write!(fmt, "{}u32", i),
U64(i) => write!(fmt, "{}u64", i),
U128(i) => write!(fmt, "{}u128", i),
Usize(i) => write!(fmt, "{}usize", i),
}
}
}
macro_rules! overflowing {
($e:expr, $err:expr) => {{
if $e.1 {
return Err(Overflow($err));
} else {
$e.0
}
}}
}
macro_rules! impl_binop {
($op:ident, $func:ident, $checked_func:ident) => {
impl ::std::ops::$op for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
match (self, rhs) {
(I8(a), I8(b)) => a.$checked_func(b).map(I8),
(I16(a), I16(b)) => a.$checked_func(b).map(I16),
(I32(a), I32(b)) => a.$checked_func(b).map(I32),
(I64(a), I64(b)) => a.$checked_func(b).map(I64),
(I128(a), I128(b)) => a.$checked_func(b).map(I128),
(Isize(Is16(a)), Isize(Is16(b))) => a.$checked_func(b).map(Is16).map(Isize),
(Isize(Is32(a)), Isize(Is32(b))) => a.$checked_func(b).map(Is32).map(Isize),
(Isize(Is64(a)), Isize(Is64(b))) => a.$checked_func(b).map(Is64).map(Isize),
(U8(a), U8(b)) => a.$checked_func(b).map(U8),
(U16(a), U16(b)) => a.$checked_func(b).map(U16),
(U32(a), U32(b)) => a.$checked_func(b).map(U32),
(U64(a), U64(b)) => a.$checked_func(b).map(U64),
(U128(a), U128(b)) => a.$checked_func(b).map(U128),
(Usize(Us16(a)), Usize(Us16(b))) => a.$checked_func(b).map(Us16).map(Usize),
(Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize),
(Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize),
_ => return Err(UnequalTypes(Op::$op)),
}.ok_or(Overflow(Op::$op))
}
}
}
}
macro_rules! derive_binop {
($op:ident, $func:ident) => {
impl ::std::ops::$op for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
match (self, rhs) {
(I8(a), I8(b)) => Ok(I8(a.$func(b))),
(I16(a), I16(b)) => Ok(I16(a.$func(b))),
(I32(a), I32(b)) => Ok(I32(a.$func(b))),
(I64(a), I64(b)) => Ok(I64(a.$func(b))),
(I128(a), I128(b)) => Ok(I128(a.$func(b))),
(Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a.$func(b)))),
(Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a.$func(b)))),
(Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a.$func(b)))),
(U8(a), U8(b)) => Ok(U8(a.$func(b))),
(U16(a), U16(b)) => Ok(U16(a.$func(b))),
(U32(a), U32(b)) => Ok(U32(a.$func(b))),
(U64(a), U64(b)) => Ok(U64(a.$func(b))),
(U128(a), U128(b)) => Ok(U128(a.$func(b))),
(Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a.$func(b)))),
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))),
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))),
_ => Err(UnequalTypes(Op::$op)),
}
}
}
}
}
impl_binop!(Add, add, checked_add);
impl_binop!(Sub, sub, checked_sub);
impl_binop!(Mul, mul, checked_mul);
derive_binop!(BitAnd, bitand);
derive_binop!(BitOr, bitor);
derive_binop!(BitXor, bitxor);
const I128_MIN: i128 = ::std::i128::MIN;
fn check_division(
lhs: ConstInt,
rhs: ConstInt,
op: Op,
zerr: ConstMathErr,
) -> Result<(), ConstMathErr> {
match (lhs, rhs) {
(I8(_), I8(0)) => Err(zerr),
(I16(_), I16(0)) => Err(zerr),
(I32(_), I32(0)) => Err(zerr),
(I64(_), I64(0)) => Err(zerr),
(I128(_), I128(0)) => Err(zerr),
(Isize(_), Isize(Is16(0))) => Err(zerr),
(Isize(_), Isize(Is32(0))) => Err(zerr),
(Isize(_), Isize(Is64(0))) => Err(zerr),
(U8(_), U8(0)) => Err(zerr),
(U16(_), U16(0)) => Err(zerr),
(U32(_), U32(0)) => Err(zerr),
(U64(_), U64(0)) => Err(zerr),
(U128(_), U128(0)) => Err(zerr),
(Usize(_), Usize(Us16(0))) => Err(zerr),
(Usize(_), Usize(Us32(0))) => Err(zerr),
(Usize(_), Usize(Us64(0))) => Err(zerr),
(I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)),
(I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)),
(I32(::std::i32::MIN), I32(-1)) => Err(Overflow(op)),
(I64(::std::i64::MIN), I64(-1)) => Err(Overflow(op)),
(I128(I128_MIN), I128(-1)) => Err(Overflow(op)),
(Isize(Is16(::std::i16::MIN)), Isize(Is16(-1))) => Err(Overflow(op)),
(Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)),
(Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)),
_ => Ok(()),
}
}
impl ::std::ops::Div for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
let (lhs, rhs) = (self, rhs);
check_division(lhs, rhs, Op::Div, DivisionByZero)?;
match (lhs, rhs) {
(I8(a), I8(b)) => Ok(I8(a/b)),
(I16(a), I16(b)) => Ok(I16(a/b)),
(I32(a), I32(b)) => Ok(I32(a/b)),
(I64(a), I64(b)) => Ok(I64(a/b)),
(I128(a), I128(b)) => Ok(I128(a/b)),
(Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a/b))),
(Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))),
(Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))),
(U8(a), U8(b)) => Ok(U8(a/b)),
(U16(a), U16(b)) => Ok(U16(a/b)),
(U32(a), U32(b)) => Ok(U32(a/b)),
(U64(a), U64(b)) => Ok(U64(a/b)),
(U128(a), U128(b)) => Ok(U128(a/b)),
(Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a/b))),
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))),
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))),
_ => Err(UnequalTypes(Op::Div)),
}
}
}
impl ::std::ops::Rem for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
let (lhs, rhs) = (self, rhs);
// should INT_MIN%-1 be zero or an error?
check_division(lhs, rhs, Op::Rem, RemainderByZero)?;
match (lhs, rhs) {
(I8(a), I8(b)) => Ok(I8(a%b)),
(I16(a), I16(b)) => Ok(I16(a%b)),
(I32(a), I32(b)) => Ok(I32(a%b)),
(I64(a), I64(b)) => Ok(I64(a%b)),
(I128(a), I128(b)) => Ok(I128(a%b)),
(Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a%b))),
(Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))),
(Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))),
(U8(a), U8(b)) => Ok(U8(a%b)),
(U16(a), U16(b)) => Ok(U16(a%b)),
(U32(a), U32(b)) => Ok(U32(a%b)),
(U64(a), U64(b)) => Ok(U64(a%b)),
(U128(a), U128(b)) => Ok(U128(a%b)),
(Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a%b))),
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))),
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))),
_ => Err(UnequalTypes(Op::Rem)),
}
}
}
impl ::std::ops::Shl<ConstInt> for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn shl(self, rhs: Self) -> Result<Self, ConstMathErr> {
let b = rhs.to_u32().ok_or(ShiftNegative)?;
match self {
I8(a) => Ok(I8(overflowing!(a.overflowing_shl(b), Op::Shl))),
I16(a) => Ok(I16(overflowing!(a.overflowing_shl(b), Op::Shl))),
I32(a) => Ok(I32(overflowing!(a.overflowing_shl(b), Op::Shl))),
I64(a) => Ok(I64(overflowing!(a.overflowing_shl(b), Op::Shl))),
I128(a) => Ok(I128(overflowing!(a.overflowing_shl(b), Op::Shl))),
Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_shl(b), Op::Shl)))),
Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
U8(a) => Ok(U8(overflowing!(a.overflowing_shl(b), Op::Shl))),
U16(a) => Ok(U16(overflowing!(a.overflowing_shl(b), Op::Shl))),
U32(a) => Ok(U32(overflowing!(a.overflowing_shl(b), Op::Shl))),
U64(a) => Ok(U64(overflowing!(a.overflowing_shl(b), Op::Shl))),
U128(a) => Ok(U128(overflowing!(a.overflowing_shl(b), Op::Shl))),
Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shl(b), Op::Shl)))),
Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
}
}
}
impl ::std::ops::Shr<ConstInt> for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn shr(self, rhs: Self) -> Result<Self, ConstMathErr> {
let b = rhs.to_u32().ok_or(ShiftNegative)?;
match self {
I8(a) => Ok(I8(overflowing!(a.overflowing_shr(b), Op::Shr))),
I16(a) => Ok(I16(overflowing!(a.overflowing_shr(b), Op::Shr))),
I32(a) => Ok(I32(overflowing!(a.overflowing_shr(b), Op::Shr))),
I64(a) => Ok(I64(overflowing!(a.overflowing_shr(b), Op::Shr))),
I128(a) => Ok(I128(overflowing!(a.overflowing_shr(b), Op::Shr))),
Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_shr(b), Op::Shr)))),
Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
U8(a) => Ok(U8(overflowing!(a.overflowing_shr(b), Op::Shr))),
U16(a) => Ok(U16(overflowing!(a.overflowing_shr(b), Op::Shr))),
U32(a) => Ok(U32(overflowing!(a.overflowing_shr(b), Op::Shr))),
U64(a) => Ok(U64(overflowing!(a.overflowing_shr(b), Op::Shr))),
U128(a) => Ok(U128(overflowing!(a.overflowing_shr(b), Op::Shr))),
Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shr(b), Op::Shr)))),
Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
}
}
}
impl ::std::ops::Neg for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn neg(self) -> Result<Self, ConstMathErr> {
match self {
I8(a) => Ok(I8(overflowing!(a.overflowing_neg(), Op::Neg))),
I16(a) => Ok(I16(overflowing!(a.overflowing_neg(), Op::Neg))),
I32(a) => Ok(I32(overflowing!(a.overflowing_neg(), Op::Neg))),
I64(a) => Ok(I64(overflowing!(a.overflowing_neg(), Op::Neg))),
I128(a) => Ok(I128(overflowing!(a.overflowing_neg(), Op::Neg))),
Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_neg(), Op::Neg)))),
Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_neg(), Op::Neg)))),
Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_neg(), Op::Neg)))),
a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) |
a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a),
U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation),
}
}
}
impl ::std::ops::Not for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn not(self) -> Result<Self, ConstMathErr> {
match self {
I8(a) => Ok(I8(!a)),
I16(a) => Ok(I16(!a)),
I32(a) => Ok(I32(!a)),
I64(a) => Ok(I64(!a)),
I128(a) => Ok(I128(!a)),
Isize(Is16(a)) => Ok(Isize(Is16(!a))),
Isize(Is32(a)) => Ok(Isize(Is32(!a))),
Isize(Is64(a)) => Ok(Isize(Is64(!a))),
U8(a) => Ok(U8(!a)),
U16(a) => Ok(U16(!a)),
U32(a) => Ok(U32(!a)),
U64(a) => Ok(U64(!a)),
U128(a) => Ok(U128(!a)),
Usize(Us16(a)) => Ok(Usize(Us16(!a))),
Usize(Us32(a)) => Ok(Usize(Us32(!a))),
Usize(Us64(a)) => Ok(Usize(Us64(!a))),
}
}
}

View file

@ -1,56 +0,0 @@
// Copyright 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use syntax::ast;
use super::err::*;
/// Depending on the target only one variant is ever used in a compilation.
/// Anything else is an error. This invariant is checked at several locations
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
pub enum ConstIsize {
Is16(i16),
Is32(i32),
Is64(i64),
}
pub use self::ConstIsize::*;
impl ::std::fmt::Display for ConstIsize {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
write!(fmt, "{}", self.as_i64())
}
}
impl ConstIsize {
pub fn as_i64(self) -> i64 {
match self {
Is16(i) => i as i64,
Is32(i) => i as i64,
Is64(i) => i,
}
}
pub fn new(i: i64, isize_ty: ast::IntTy) -> Result<Self, ConstMathErr> {
match isize_ty {
ast::IntTy::I16 if i as i16 as i64 == i => Ok(Is16(i as i16)),
ast::IntTy::I16 => Err(LitOutOfRange(ast::IntTy::Isize)),
ast::IntTy::I32 if i as i32 as i64 == i => Ok(Is32(i as i32)),
ast::IntTy::I32 => Err(LitOutOfRange(ast::IntTy::Isize)),
ast::IntTy::I64 => Ok(Is64(i)),
_ => unreachable!(),
}
}
pub fn new_truncating(i: i128, isize_ty: ast::IntTy) -> Self {
match isize_ty {
ast::IntTy::I16 => Is16(i as i16),
ast::IntTy::I32 => Is32(i as i32),
ast::IntTy::I64 => Is64(i as i64),
_ => unreachable!(),
}
}
}

View file

@ -29,13 +29,7 @@ extern crate syntax;
extern crate serialize as rustc_serialize; // used by deriving extern crate serialize as rustc_serialize; // used by deriving
mod float; mod float;
mod int;
mod usize;
mod isize;
mod err; mod err;
pub use float::*; pub use float::*;
pub use int::*;
pub use usize::*;
pub use isize::*;
pub use err::{ConstMathErr, Op}; pub use err::{ConstMathErr, Op};

View file

@ -1,56 +0,0 @@
// Copyright 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use syntax::ast;
use super::err::*;
/// Depending on the target only one variant is ever used in a compilation.
/// Anything else is an error. This invariant is checked at several locations
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
pub enum ConstUsize {
Us16(u16),
Us32(u32),
Us64(u64),
}
pub use self::ConstUsize::*;
impl ::std::fmt::Display for ConstUsize {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
write!(fmt, "{}", self.as_u64())
}
}
impl ConstUsize {
pub fn as_u64(self) -> u64 {
match self {
Us16(i) => i as u64,
Us32(i) => i as u64,
Us64(i) => i,
}
}
pub fn new(i: u64, usize_ty: ast::UintTy) -> Result<Self, ConstMathErr> {
match usize_ty {
ast::UintTy::U16 if i as u16 as u64 == i => Ok(Us16(i as u16)),
ast::UintTy::U16 => Err(ULitOutOfRange(ast::UintTy::Usize)),
ast::UintTy::U32 if i as u32 as u64 == i => Ok(Us32(i as u32)),
ast::UintTy::U32 => Err(ULitOutOfRange(ast::UintTy::Usize)),
ast::UintTy::U64 => Ok(Us64(i)),
_ => unreachable!(),
}
}
pub fn new_truncating(i: u128, usize_ty: ast::UintTy) -> Self {
match usize_ty {
ast::UintTy::U16 => Us16(i as u16),
ast::UintTy::U32 => Us32(i as u32),
ast::UintTy::U64 => Us64(i as u64),
_ => unreachable!(),
}
}
}

View file

@ -259,6 +259,14 @@ impl<CTX> HashStable<CTX> for f64 {
} }
} }
impl<CTX> HashStable<CTX> for ::std::cmp::Ordering {
fn hash_stable<W: StableHasherResult>(&self,
ctx: &mut CTX,
hasher: &mut StableHasher<W>) {
(*self as i8).hash_stable(ctx, hasher);
}
}
impl<T1: HashStable<CTX>, CTX> HashStable<CTX> for (T1,) { impl<T1: HashStable<CTX>, CTX> HashStable<CTX> for (T1,) {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
ctx: &mut CTX, ctx: &mut CTX,

View file

@ -17,7 +17,6 @@ rustc = { path = "../librustc" }
rustc_allocator = { path = "../librustc_allocator" } rustc_allocator = { path = "../librustc_allocator" }
rustc_back = { path = "../librustc_back" } rustc_back = { path = "../librustc_back" }
rustc_borrowck = { path = "../librustc_borrowck" } rustc_borrowck = { path = "../librustc_borrowck" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_data_structures = { path = "../librustc_data_structures" } rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" } rustc_errors = { path = "../librustc_errors" }
rustc_incremental = { path = "../librustc_incremental" } rustc_incremental = { path = "../librustc_incremental" }

View file

@ -36,8 +36,7 @@ use rustc_typeck as typeck;
use rustc_privacy; use rustc_privacy;
use rustc_plugin::registry::Registry; use rustc_plugin::registry::Registry;
use rustc_plugin as plugin; use rustc_plugin as plugin;
use rustc_passes::{self, ast_validation, loops, consts, hir_stats}; use rustc_passes::{self, ast_validation, loops, rvalue_promotion, hir_stats};
use rustc_const_eval::{self, check_match};
use super::Compilation; use super::Compilation;
use serialize::json; use serialize::json;
@ -942,7 +941,6 @@ pub fn default_provide(providers: &mut ty::maps::Providers) {
ty::provide(providers); ty::provide(providers);
traits::provide(providers); traits::provide(providers);
reachable::provide(providers); reachable::provide(providers);
rustc_const_eval::provide(providers);
rustc_passes::provide(providers); rustc_passes::provide(providers);
middle::region::provide(providers); middle::region::provide(providers);
cstore::provide(providers); cstore::provide(providers);
@ -1038,8 +1036,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate,
} }
time(time_passes, time(time_passes,
"const checking", "rvalue promotion",
|| consts::check_crate(tcx)); || rvalue_promotion::check_crate(tcx));
analysis.access_levels = analysis.access_levels =
time(time_passes, "privacy checking", || rustc_privacy::check_crate(tcx)); time(time_passes, "privacy checking", || rustc_privacy::check_crate(tcx));
@ -1050,7 +1048,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate,
time(time_passes, time(time_passes,
"match checking", "match checking",
|| check_match::check_crate(tcx)); || mir::matchck_crate(tcx));
// this must run before MIR dump, because // this must run before MIR dump, because
// "not all control paths return a value" is reported here. // "not all control paths return a value" is reported here.

View file

@ -35,7 +35,6 @@ extern crate rustc;
extern crate rustc_allocator; extern crate rustc_allocator;
extern crate rustc_back; extern crate rustc_back;
extern crate rustc_borrowck; extern crate rustc_borrowck;
extern crate rustc_const_eval;
extern crate rustc_data_structures; extern crate rustc_data_structures;
extern crate rustc_errors as errors; extern crate rustc_errors as errors;
extern crate rustc_passes; extern crate rustc_passes;
@ -1566,7 +1565,6 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
// FIXME: need to figure out a way to get these back in here // FIXME: need to figure out a way to get these back in here
// all_errors.extend_from_slice(get_trans(sess).diagnostics()); // all_errors.extend_from_slice(get_trans(sess).diagnostics());
all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS);
@ -1576,8 +1574,14 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
Registry::new(&all_errors) Registry::new(&all_errors)
} }
pub fn main() { /// This allows tools to enable rust logging without having to magically match rustc's
/// log crate version
pub fn init_rustc_env_logger() {
env_logger::init(); env_logger::init();
}
pub fn main() {
init_rustc_env_logger();
let result = run(|| { let result = run(|| {
let args = env::args_os().enumerate() let args = env::args_os().enumerate()
.map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| { .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| {

View file

@ -12,6 +12,6 @@ test = false
[dependencies] [dependencies]
log = "0.4" log = "0.4"
rustc = { path = "../librustc" } rustc = { path = "../librustc" }
rustc_const_eval = { path = "../librustc_const_eval" } rustc_mir = { path = "../librustc_mir"}
syntax = { path = "../libsyntax" } syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" } syntax_pos = { path = "../libsyntax_pos" }

View file

@ -682,78 +682,6 @@ impl EarlyLintPass for DeprecatedAttr {
} }
} }
declare_lint! {
pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
Warn,
"floating-point literals cannot be used in patterns"
}
/// Checks for floating point literals in patterns.
#[derive(Clone)]
pub struct IllegalFloatLiteralPattern;
impl LintPass for IllegalFloatLiteralPattern {
fn get_lints(&self) -> LintArray {
lint_array!(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN)
}
}
fn fl_lit_check_expr(cx: &EarlyContext, expr: &ast::Expr) {
use self::ast::{ExprKind, LitKind};
match expr.node {
ExprKind::Lit(ref l) => {
match l.node {
LitKind::FloatUnsuffixed(..) |
LitKind::Float(..) => {
cx.span_lint(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
l.span,
"floating-point literals cannot be used in patterns");
},
_ => (),
}
}
// These may occur in patterns
// and can maybe contain float literals
ExprKind::Unary(_, ref f) => fl_lit_check_expr(cx, f),
// Other kinds of exprs can't occur in patterns so we don't have to check them
// (ast_validation will emit an error if they occur)
_ => (),
}
}
impl EarlyLintPass for IllegalFloatLiteralPattern {
fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat) {
use self::ast::PatKind;
pat.walk(&mut |p| {
match p.node {
// Wildcard patterns and paths are uninteresting for the lint
PatKind::Wild |
PatKind::Path(..) => (),
// The walk logic recurses inside these
PatKind::Ident(..) |
PatKind::Struct(..) |
PatKind::Tuple(..) |
PatKind::TupleStruct(..) |
PatKind::Ref(..) |
PatKind::Box(..) |
PatKind::Paren(..) |
PatKind::Slice(..) => (),
// Extract the expressions and check them
PatKind::Lit(ref e) => fl_lit_check_expr(cx, e),
PatKind::Range(ref st, ref en, _) => {
fl_lit_check_expr(cx, st);
fl_lit_check_expr(cx, en);
},
PatKind::Mac(_) => bug!("lint must run post-expansion"),
}
true
});
}
}
declare_lint! { declare_lint! {
pub UNUSED_DOC_COMMENT, pub UNUSED_DOC_COMMENT,
Warn, Warn,

View file

@ -39,11 +39,10 @@ extern crate syntax;
extern crate rustc; extern crate rustc;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate rustc_const_eval; extern crate rustc_mir;
extern crate syntax_pos; extern crate syntax_pos;
use rustc::lint; use rustc::lint;
use rustc::middle;
use rustc::session; use rustc::session;
use rustc::util; use rustc::util;
@ -107,7 +106,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
UnusedParens, UnusedParens,
UnusedImportBraces, UnusedImportBraces,
AnonymousParameters, AnonymousParameters,
IllegalFloatLiteralPattern,
UnusedDocComment, UnusedDocComment,
); );

View file

@ -14,8 +14,6 @@ use rustc::hir::map as hir_map;
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::{self, AdtKind, Ty, TyCtxt};
use rustc::ty::layout::{self, LayoutOf}; use rustc::ty::layout::{self, LayoutOf};
use middle::const_val::ConstVal;
use rustc_const_eval::ConstContext;
use util::nodemap::FxHashSet; use util::nodemap::FxHashSet;
use lint::{LateContext, LintContext, LintArray}; use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass}; use lint::{LintPass, LateLintPass};
@ -23,7 +21,7 @@ use lint::{LintPass, LateLintPass};
use std::cmp; use std::cmp;
use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
use syntax::ast; use syntax::{ast, attr};
use syntax::abi::Abi; use syntax::abi::Abi;
use syntax_pos::Span; use syntax_pos::Span;
use syntax::codemap; use syntax::codemap;
@ -42,12 +40,6 @@ declare_lint! {
"literal out of range for its type" "literal out of range for its type"
} }
declare_lint! {
EXCEEDING_BITSHIFTS,
Deny,
"shift exceeds the type's number of bits"
}
declare_lint! { declare_lint! {
VARIANT_SIZE_DIFFERENCES, VARIANT_SIZE_DIFFERENCES,
Allow, Allow,
@ -69,8 +61,7 @@ impl TypeLimits {
impl LintPass for TypeLimits { impl LintPass for TypeLimits {
fn get_lints(&self) -> LintArray { fn get_lints(&self) -> LintArray {
lint_array!(UNUSED_COMPARISONS, lint_array!(UNUSED_COMPARISONS,
OVERFLOWING_LITERALS, OVERFLOWING_LITERALS)
EXCEEDING_BITSHIFTS)
} }
} }
@ -89,49 +80,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
e.span, e.span,
"comparison is useless due to type limits"); "comparison is useless due to type limits");
} }
if binop.node.is_shift() {
let opt_ty_bits = match cx.tables.node_id_to_type(l.hir_id).sty {
ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.isize_ty)),
ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.usize_ty)),
_ => None,
};
if let Some(bits) = opt_ty_bits {
let exceeding = if let hir::ExprLit(ref lit) = r.node {
if let ast::LitKind::Int(shift, _) = lit.node {
shift as u64 >= bits
} else {
false
}
} else {
// HACK(eddyb) This might be quite inefficient.
// This would be better left to MIR constant propagation,
// perhaps even at trans time (like is the case already
// when the value being shifted is *also* constant).
let parent_item = cx.tcx.hir.get_parent(e.id);
let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
let substs = Substs::identity_for_item(cx.tcx, parent_def_id);
let const_cx = ConstContext::new(cx.tcx,
cx.param_env.and(substs),
cx.tables);
match const_cx.eval(&r) {
Ok(&ty::Const { val: ConstVal::Integral(i), .. }) => {
i.is_negative() ||
i.to_u64()
.map(|i| i >= bits)
.unwrap_or(true)
}
_ => false,
}
};
if exceeding {
cx.span_lint(EXCEEDING_BITSHIFTS,
e.span,
"bitshift exceeds the type's number of bits");
}
};
}
} }
hir::ExprLit(ref lit) => { hir::ExprLit(ref lit) => {
match cx.tables.node_id_to_type(e.hir_id).sty { match cx.tables.node_id_to_type(e.hir_id).sty {
@ -290,28 +238,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
} }
} }
fn int_ty_bits(int_ty: ast::IntTy, isize_ty: ast::IntTy) -> u64 {
match int_ty {
ast::IntTy::Isize => int_ty_bits(isize_ty, isize_ty),
ast::IntTy::I8 => 8,
ast::IntTy::I16 => 16 as u64,
ast::IntTy::I32 => 32,
ast::IntTy::I64 => 64,
ast::IntTy::I128 => 128,
}
}
fn uint_ty_bits(uint_ty: ast::UintTy, usize_ty: ast::UintTy) -> u64 {
match uint_ty {
ast::UintTy::Usize => uint_ty_bits(usize_ty, usize_ty),
ast::UintTy::U8 => 8,
ast::UintTy::U16 => 16,
ast::UintTy::U32 => 32,
ast::UintTy::U64 => 64,
ast::UintTy::U128 => 128,
}
}
fn check_limits(cx: &LateContext, fn check_limits(cx: &LateContext,
binop: hir::BinOp, binop: hir::BinOp,
l: &hir::Expr, l: &hir::Expr,
@ -439,12 +365,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
) { ) {
let (t, actually) = match ty { let (t, actually) = match ty {
ty::TyInt(t) => { ty::TyInt(t) => {
let bits = int_ty_bits(t, cx.sess().target.isize_ty); let ity = attr::IntType::SignedInt(t);
let bits = layout::Integer::from_attr(cx.tcx, ity).size().bits();
let actually = (val << (128 - bits)) as i128 >> (128 - bits); let actually = (val << (128 - bits)) as i128 >> (128 - bits);
(format!("{:?}", t), actually.to_string()) (format!("{:?}", t), actually.to_string())
} }
ty::TyUint(t) => { ty::TyUint(t) => {
let bits = uint_ty_bits(t, cx.sess().target.usize_ty); let ity = attr::IntType::UnsignedInt(t);
let bits = layout::Integer::from_attr(cx.tcx, ity).size().bits();
let actually = (val << (128 - bits)) >> (128 - bits); let actually = (val << (128 - bits)) >> (128 - bits);
(format!("{:?}", t), actually.to_string()) (format!("{:?}", t), actually.to_string())
} }

View file

@ -664,6 +664,16 @@ extern "C" {
pub fn LLVMConstShl(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; pub fn LLVMConstShl(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
pub fn LLVMConstLShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; pub fn LLVMConstLShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
pub fn LLVMConstAShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; pub fn LLVMConstAShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
pub fn LLVMConstGEP(
ConstantVal: ValueRef,
ConstantIndices: *const ValueRef,
NumIndices: c_uint,
) -> ValueRef;
pub fn LLVMConstInBoundsGEP(
ConstantVal: ValueRef,
ConstantIndices: *const ValueRef,
NumIndices: c_uint,
) -> ValueRef;
pub fn LLVMConstTrunc(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; pub fn LLVMConstTrunc(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
pub fn LLVMConstZExt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; pub fn LLVMConstZExt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
pub fn LLVMConstUIToFP(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; pub fn LLVMConstUIToFP(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;

View file

@ -21,14 +21,15 @@ use rustc::middle::cstore::{LinkagePreference, ExternConstBody,
use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def::{self, Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, use rustc::hir::def_id::{CrateNum, DefId, DefIndex,
CRATE_DEF_INDEX, LOCAL_CRATE}; CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId};
use rustc::ich::Fingerprint; use rustc::ich::Fingerprint;
use rustc::middle::lang_items; use rustc::middle::lang_items;
use rustc::mir; use rustc::mir::{self, interpret};
use rustc::session::Session; use rustc::session::Session;
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::codec::TyDecoder; use rustc::ty::codec::TyDecoder;
use rustc::mir::Mir; use rustc::mir::Mir;
use rustc::util::nodemap::FxHashMap;
use std::cell::Ref; use std::cell::Ref;
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -54,6 +55,9 @@ pub struct DecodeContext<'a, 'tcx: 'a> {
last_filemap_index: usize, last_filemap_index: usize,
lazy_state: LazyState, lazy_state: LazyState,
// interpreter allocation cache
interpret_alloc_cache: FxHashMap<usize, interpret::AllocId>,
} }
/// Abstract over the various ways one can create metadata decoders. /// Abstract over the various ways one can create metadata decoders.
@ -72,6 +76,7 @@ pub trait Metadata<'a, 'tcx>: Copy {
tcx, tcx,
last_filemap_index: 0, last_filemap_index: 0,
lazy_state: LazyState::NoNode, lazy_state: LazyState::NoNode,
interpret_alloc_cache: FxHashMap::default(),
} }
} }
} }
@ -268,6 +273,58 @@ impl<'a, 'tcx> SpecializedDecoder<DefIndex> for DecodeContext<'a, 'tcx> {
} }
} }
impl<'a, 'tcx> SpecializedDecoder<LocalDefId> for DecodeContext<'a, 'tcx> {
#[inline]
fn specialized_decode(&mut self) -> Result<LocalDefId, Self::Error> {
self.specialized_decode().map(|i| LocalDefId::from_def_id(i))
}
}
impl<'a, 'tcx> SpecializedDecoder<interpret::AllocId> for DecodeContext<'a, 'tcx> {
fn specialized_decode(&mut self) -> Result<interpret::AllocId, Self::Error> {
const MAX1: usize = usize::max_value() - 1;
let tcx = self.tcx.unwrap();
let pos = self.position();
match usize::decode(self)? {
::std::usize::MAX => {
let alloc_id = tcx.interpret_interner.reserve();
trace!("creating alloc id {:?} at {}", alloc_id, pos);
// insert early to allow recursive allocs
self.interpret_alloc_cache.insert(pos, alloc_id);
let allocation = interpret::Allocation::decode(self)?;
trace!("decoded alloc {:?} {:#?}", alloc_id, allocation);
let allocation = self.tcx.unwrap().intern_const_alloc(allocation);
tcx.interpret_interner.intern_at_reserved(alloc_id, allocation);
if let Some(glob) = Option::<DefId>::decode(self)? {
tcx.interpret_interner.cache(glob, alloc_id);
}
Ok(alloc_id)
},
MAX1 => {
trace!("creating fn alloc id at {}", pos);
let instance = ty::Instance::decode(self)?;
trace!("decoded fn alloc instance: {:?}", instance);
let id = tcx.interpret_interner.create_fn_alloc(instance);
trace!("created fn alloc id: {:?}", id);
self.interpret_alloc_cache.insert(pos, id);
Ok(id)
},
shorthand => {
trace!("loading shorthand {}", shorthand);
if let Some(&alloc_id) = self.interpret_alloc_cache.get(&shorthand) {
return Ok(alloc_id);
}
trace!("shorthand {} not cached, loading entire allocation", shorthand);
// need to load allocation
self.with_position(shorthand, |this| interpret::AllocId::decode(this))
},
}
}
}
impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
fn specialized_decode(&mut self) -> Result<Span, Self::Error> { fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
let tag = u8::decode(self)?; let tag = u8::decode(self)?;

View file

@ -16,14 +16,14 @@ use schema::*;
use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary, use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary,
EncodedMetadata}; EncodedMetadata};
use rustc::hir::def::CtorKind; use rustc::hir::def::CtorKind;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LOCAL_CRATE}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LocalDefId, LOCAL_CRATE};
use rustc::hir::map::definitions::DefPathTable; use rustc::hir::map::definitions::DefPathTable;
use rustc::ich::Fingerprint; use rustc::ich::Fingerprint;
use rustc::middle::dependency_format::Linkage; use rustc::middle::dependency_format::Linkage;
use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel, use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel,
metadata_symbol_name}; metadata_symbol_name};
use rustc::middle::lang_items; use rustc::middle::lang_items;
use rustc::mir; use rustc::mir::{self, interpret};
use rustc::traits::specialization_graph; use rustc::traits::specialization_graph;
use rustc::ty::{self, Ty, TyCtxt, ReprOptions, SymbolName}; use rustc::ty::{self, Ty, TyCtxt, ReprOptions, SymbolName};
use rustc::ty::codec::{self as ty_codec, TyEncoder}; use rustc::ty::codec::{self as ty_codec, TyEncoder};
@ -59,6 +59,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> {
lazy_state: LazyState, lazy_state: LazyState,
type_shorthands: FxHashMap<Ty<'tcx>, usize>, type_shorthands: FxHashMap<Ty<'tcx>, usize>,
predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>, predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
interpret_alloc_shorthands: FxHashMap<interpret::AllocId, usize>,
// This is used to speed up Span encoding. // This is used to speed up Span encoding.
filemap_cache: Lrc<FileMap>, filemap_cache: Lrc<FileMap>,
@ -180,12 +181,48 @@ impl<'a, 'tcx> SpecializedEncoder<Span> for EncodeContext<'a, 'tcx> {
} }
} }
impl<'a, 'tcx> SpecializedEncoder<LocalDefId> for EncodeContext<'a, 'tcx> {
#[inline]
fn specialized_encode(&mut self, def_id: &LocalDefId) -> Result<(), Self::Error> {
self.specialized_encode(&def_id.to_def_id())
}
}
impl<'a, 'tcx> SpecializedEncoder<Ty<'tcx>> for EncodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedEncoder<Ty<'tcx>> for EncodeContext<'a, 'tcx> {
fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> { fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> {
ty_codec::encode_with_shorthand(self, ty, |ecx| &mut ecx.type_shorthands) ty_codec::encode_with_shorthand(self, ty, |ecx| &mut ecx.type_shorthands)
} }
} }
impl<'a, 'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'a, 'tcx> {
fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
trace!("encoding {:?} at {}", alloc_id, self.position());
if let Some(shorthand) = self.interpret_alloc_shorthands.get(alloc_id).cloned() {
trace!("encoding {:?} as shorthand to {}", alloc_id, shorthand);
return shorthand.encode(self);
}
let start = self.position();
// cache the allocation shorthand now, because the allocation itself might recursively
// point to itself.
self.interpret_alloc_shorthands.insert(*alloc_id, start);
if let Some(alloc) = self.tcx.interpret_interner.get_alloc(*alloc_id) {
trace!("encoding {:?} with {:#?}", alloc_id, alloc);
usize::max_value().encode(self)?;
alloc.encode(self)?;
self.tcx.interpret_interner
.get_corresponding_static_def_id(*alloc_id)
.encode(self)?;
} else if let Some(fn_instance) = self.tcx.interpret_interner.get_fn(*alloc_id) {
trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
(usize::max_value() - 1).encode(self)?;
fn_instance.encode(self)?;
} else {
bug!("alloc id without corresponding allocation: {}", alloc_id);
}
Ok(())
}
}
impl<'a, 'tcx> SpecializedEncoder<ty::GenericPredicates<'tcx>> for EncodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedEncoder<ty::GenericPredicates<'tcx>> for EncodeContext<'a, 'tcx> {
fn specialized_encode(&mut self, fn specialized_encode(&mut self,
predicates: &ty::GenericPredicates<'tcx>) predicates: &ty::GenericPredicates<'tcx>)
@ -1117,7 +1154,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
_ => None, _ => None,
}, },
mir: match item.node { mir: match item.node {
hir::ItemStatic(..) if self.tcx.sess.opts.debugging_opts.always_encode_mir => { hir::ItemStatic(..) => {
self.encode_optimized_mir(def_id) self.encode_optimized_mir(def_id)
} }
hir::ItemConst(..) => self.encode_optimized_mir(def_id), hir::ItemConst(..) => self.encode_optimized_mir(def_id),
@ -1699,6 +1736,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
type_shorthands: Default::default(), type_shorthands: Default::default(),
predicate_shorthands: Default::default(), predicate_shorthands: Default::default(),
filemap_cache: tcx.sess.codemap().files()[0].clone(), filemap_cache: tcx.sess.codemap().files()[0].clone(),
interpret_alloc_shorthands: Default::default(),
}; };
// Encode the rustc version string in a predictable location. // Encode the rustc version string in a predictable location.

View file

@ -227,9 +227,9 @@ pub struct TraitImpls {
pub impls: LazySeq<DefIndex>, pub impls: LazySeq<DefIndex>,
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for TraitImpls { impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TraitImpls {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
let TraitImpls { let TraitImpls {
trait_id: (krate, def_index), trait_id: (krate, def_index),
@ -310,9 +310,9 @@ pub enum EntryKind<'tcx> {
AssociatedConst(AssociatedContainer, u8), AssociatedConst(AssociatedContainer, u8),
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for EntryKind<'gcx> { impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for EntryKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {

View file

@ -9,13 +9,13 @@ path = "lib.rs"
crate-type = ["dylib"] crate-type = ["dylib"]
[dependencies] [dependencies]
arena = { path = "../libarena" }
bitflags = "1.0" bitflags = "1.0"
graphviz = { path = "../libgraphviz" } graphviz = { path = "../libgraphviz" }
log = "0.4" log = "0.4"
log_settings = "0.1.1" log_settings = "0.1.1"
rustc = { path = "../librustc" } rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" } rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_const_math = { path = "../librustc_const_math" } rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" } rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" } rustc_errors = { path = "../librustc_errors" }

View file

@ -1635,11 +1635,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Mutability::Mut => Ok(()), Mutability::Mut => Ok(()),
} }
} }
Place::Static(ref static_) => if !self.tcx.is_static_mut(static_.def_id) { Place::Static(ref static_) =>
Err(place) if self.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
} else { Err(place)
Ok(()) } else {
}, Ok(())
},
Place::Projection(ref proj) => { Place::Projection(ref proj) => {
match proj.elem { match proj.elem {
ProjectionElem::Deref => { ProjectionElem::Deref => {
@ -1792,7 +1793,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
if static1.def_id != static2.def_id { if static1.def_id != static2.def_id {
debug!("place_element_conflict: DISJOINT-STATIC"); debug!("place_element_conflict: DISJOINT-STATIC");
Overlap::Disjoint Overlap::Disjoint
} else if self.tcx.is_static_mut(static1.def_id) { } else if self.tcx.is_static(static1.def_id) == Some(hir::Mutability::MutMutable) {
// We ignore mutable statics - they can only be unsafe code. // We ignore mutable statics - they can only be unsafe code.
debug!("place_element_conflict: IGNORE-STATIC-MUT"); debug!("place_element_conflict: IGNORE-STATIC-MUT");
Overlap::Disjoint Overlap::Disjoint

View file

@ -24,7 +24,6 @@ use rustc::traits::{self, FulfillmentContext};
use rustc::ty::error::TypeError; use rustc::ty::error::TypeError;
use rustc::ty::fold::TypeFoldable; use rustc::ty::fold::TypeFoldable;
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
use rustc::middle::const_val::ConstVal;
use rustc::mir::*; use rustc::mir::*;
use rustc::mir::tcx::PlaceTy; use rustc::mir::tcx::PlaceTy;
use rustc::mir::visit::{PlaceContext, Visitor}; use rustc::mir::visit::{PlaceContext, Visitor};
@ -258,7 +257,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
// constraints on `'a` and `'b`. These constraints // constraints on `'a` and `'b`. These constraints
// would be lost if we just look at the normalized // would be lost if we just look at the normalized
// value. // value.
if let ConstVal::Function(def_id, ..) = value.val { if let ty::TyFnDef(def_id, substs) = value.ty.sty {
let tcx = self.tcx(); let tcx = self.tcx();
let type_checker = &mut self.cx; let type_checker = &mut self.cx;
@ -271,17 +270,6 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
// are transitioning to the miri-based system, we // are transitioning to the miri-based system, we
// don't have a handy function for that, so for // don't have a handy function for that, so for
// now we just ignore `value.val` regions. // now we just ignore `value.val` regions.
let substs = match value.ty.sty {
ty::TyFnDef(ty_def_id, substs) => {
assert_eq!(def_id, ty_def_id);
substs
}
_ => span_bug!(
self.last_span,
"unexpected type for constant function: {:?}",
value.ty
),
};
let instantiated_predicates = let instantiated_predicates =
tcx.predicates_of(def_id).instantiate(tcx, substs); tcx.predicates_of(def_id).instantiate(tcx, substs);
@ -436,7 +424,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
ProjectionElem::Subslice { from, to } => PlaceTy::Ty { ProjectionElem::Subslice { from, to } => PlaceTy::Ty {
ty: match base_ty.sty { ty: match base_ty.sty {
ty::TyArray(inner, size) => { ty::TyArray(inner, size) => {
let size = size.val.to_const_int().unwrap().to_u64().unwrap(); let size = size.val.unwrap_u64();
let min_size = (from as u64) + (to as u64); let min_size = (from as u64) + (to as u64);
if let Some(rest_size) = size.checked_sub(min_size) { if let Some(rest_size) = size.checked_sub(min_size) {
tcx.mk_array(inner, rest_size) tcx.mk_array(inner, rest_size)
@ -1013,19 +1001,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
} }
fn is_box_free(&self, operand: &Operand<'tcx>) -> bool { fn is_box_free(&self, operand: &Operand<'tcx>) -> bool {
match operand { match *operand {
&Operand::Constant(box Constant { Operand::Constant(ref c) => match c.ty.sty {
literal: ty::TyFnDef(ty_def_id, _) => {
Literal::Value { Some(ty_def_id) == self.tcx().lang_items().box_free_fn()
value: }
&ty::Const { _ => false,
val: ConstVal::Function(def_id, _), },
..
},
..
},
..
}) => Some(def_id) == self.tcx().lang_items().box_free_fn(),
_ => false, _ => false,
} }
} }
@ -1284,7 +1266,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
self.check_aggregate_rvalue(mir, rvalue, ak, ops, location) self.check_aggregate_rvalue(mir, rvalue, ak, ops, location)
} }
Rvalue::Repeat(operand, const_usize) => if const_usize.as_u64() > 1 { Rvalue::Repeat(operand, len) => if *len > 1 {
let operand_ty = operand.ty(mir, tcx); let operand_ty = operand.ty(mir, tcx);
let trait_ref = ty::TraitRef { let trait_ref = ty::TraitRef {

View file

@ -10,8 +10,6 @@
//! See docs in build/expr/mod.rs //! See docs in build/expr/mod.rs
use std;
use rustc_const_math::{ConstMathErr, Op}; use rustc_const_math::{ConstMathErr, Op};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
@ -19,12 +17,11 @@ use rustc_data_structures::indexed_vec::Idx;
use build::{BlockAnd, BlockAndExtension, Builder}; use build::{BlockAnd, BlockAndExtension, Builder};
use build::expr::category::{Category, RvalueFunc}; use build::expr::category::{Category, RvalueFunc};
use hair::*; use hair::*;
use rustc_const_math::{ConstInt, ConstIsize};
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc::middle::region; use rustc::middle::region;
use rustc::ty::{self, Ty}; use rustc::ty::{self, Ty};
use rustc::mir::*; use rustc::mir::*;
use syntax::ast; use rustc::mir::interpret::{Value, PrimVal};
use syntax_pos::Span; use syntax_pos::Span;
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@ -203,7 +200,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ty: this.hir.tcx().types.u32, ty: this.hir.tcx().types.u32,
literal: Literal::Value { literal: Literal::Value {
value: this.hir.tcx().mk_const(ty::Const { value: this.hir.tcx().mk_const(ty::Const {
val: ConstVal::Integral(ConstInt::U32(0)), val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
ty: this.hir.tcx().types.u32 ty: this.hir.tcx().types.u32
}), }),
}, },
@ -384,31 +381,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// Helper to get a `-1` value of the appropriate type // Helper to get a `-1` value of the appropriate type
fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
let literal = match ty.sty { let bits = self.hir.integer_bit_width(ty);
ty::TyInt(ity) => { let n = (!0u128) >> (128 - bits);
let val = match ity { let literal = Literal::Value {
ast::IntTy::I8 => ConstInt::I8(-1), value: self.hir.tcx().mk_const(ty::Const {
ast::IntTy::I16 => ConstInt::I16(-1), val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
ast::IntTy::I32 => ConstInt::I32(-1), ty
ast::IntTy::I64 => ConstInt::I64(-1), })
ast::IntTy::I128 => ConstInt::I128(-1),
ast::IntTy::Isize => {
let int_ty = self.hir.tcx().sess.target.isize_ty;
let val = ConstIsize::new(-1, int_ty).unwrap();
ConstInt::Isize(val)
}
};
Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Integral(val),
ty
})
}
}
_ => {
span_bug!(span, "Invalid type for neg_1_literal: `{:?}`", ty)
}
}; };
self.literal_operand(span, ty, literal) self.literal_operand(span, ty, literal)
@ -416,37 +395,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// Helper to get the minimum value of the appropriate type // Helper to get the minimum value of the appropriate type
fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
let literal = match ty.sty { assert!(ty.is_signed());
ty::TyInt(ity) => { let bits = self.hir.integer_bit_width(ty);
let val = match ity { let n = 1 << (bits - 1);
ast::IntTy::I8 => ConstInt::I8(i8::min_value()), let literal = Literal::Value {
ast::IntTy::I16 => ConstInt::I16(i16::min_value()), value: self.hir.tcx().mk_const(ty::Const {
ast::IntTy::I32 => ConstInt::I32(i32::min_value()), val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
ast::IntTy::I64 => ConstInt::I64(i64::min_value()), ty
ast::IntTy::I128 => ConstInt::I128(i128::min_value()), })
ast::IntTy::Isize => {
let int_ty = self.hir.tcx().sess.target.isize_ty;
let min = match int_ty {
ast::IntTy::I16 => std::i16::MIN as i64,
ast::IntTy::I32 => std::i32::MIN as i64,
ast::IntTy::I64 => std::i64::MIN,
_ => unreachable!()
};
let val = ConstIsize::new(min, int_ty).unwrap();
ConstInt::Isize(val)
}
};
Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Integral(val),
ty
})
}
}
_ => {
span_bug!(span, "Invalid type for minval_literal: `{:?}`", ty)
}
}; };
self.literal_operand(span, ty, literal) self.literal_operand(span, ty, literal)

View file

@ -354,7 +354,7 @@ enum TestKind<'tcx> {
// test the branches of enum // test the branches of enum
SwitchInt { SwitchInt {
switch_ty: Ty<'tcx>, switch_ty: Ty<'tcx>,
options: Vec<&'tcx ty::Const<'tcx>>, options: Vec<u128>,
indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>, indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
}, },

View file

@ -20,11 +20,10 @@ use build::matches::{Candidate, MatchPair, Test, TestKind};
use hair::*; use hair::*;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::bitvec::BitVector;
use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, Ty}; use rustc::ty::{self, Ty};
use rustc::ty::util::IntTypeExt; use rustc::ty::util::IntTypeExt;
use rustc::mir::*; use rustc::mir::*;
use rustc::hir::RangeEnd; use rustc::hir::{RangeEnd, Mutability};
use syntax_pos::Span; use syntax_pos::Span;
use std::cmp::Ordering; use std::cmp::Ordering;
@ -112,7 +111,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
test_place: &Place<'tcx>, test_place: &Place<'tcx>,
candidate: &Candidate<'pat, 'tcx>, candidate: &Candidate<'pat, 'tcx>,
switch_ty: Ty<'tcx>, switch_ty: Ty<'tcx>,
options: &mut Vec<&'tcx ty::Const<'tcx>>, options: &mut Vec<u128>,
indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>) indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>)
-> bool -> bool
{ {
@ -128,7 +127,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
indices.entry(value) indices.entry(value)
.or_insert_with(|| { .or_insert_with(|| {
options.push(value); options.push(value.val.to_raw_bits().expect("switching on int"));
options.len() - 1 options.len() - 1
}); });
true true
@ -174,39 +173,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
} }
} }
/// Convert a byte array or byte slice to a byte slice.
fn to_slice_operand(&mut self,
block: BasicBlock,
source_info: SourceInfo,
operand: Operand<'tcx>)
-> Operand<'tcx>
{
let tcx = self.hir.tcx();
let ty = operand.ty(&self.local_decls, tcx);
debug!("to_slice_operand({:?}, {:?}: {:?})", block, operand, ty);
match ty.sty {
ty::TyRef(region, mt) => match mt.ty.sty {
ty::TyArray(ety, _) => {
let ty = tcx.mk_imm_ref(region, tcx.mk_slice(ety));
let temp = self.temp(ty, source_info.span);
self.cfg.push_assign(block, source_info, &temp,
Rvalue::Cast(CastKind::Unsize, operand, ty));
Operand::Move(temp)
}
ty::TySlice(_) => operand,
_ => {
span_bug!(source_info.span,
"bad operand {:?}: {:?} to `to_slice_operand`", operand, ty)
}
}
_ => {
span_bug!(source_info.span,
"bad operand {:?}: {:?} to `to_slice_operand`", operand, ty)
}
}
}
/// Generates the code to perform a test. /// Generates the code to perform a test.
pub fn perform_test(&mut self, pub fn perform_test(&mut self,
block: BasicBlock, block: BasicBlock,
@ -231,7 +197,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let tcx = self.hir.tcx(); let tcx = self.hir.tcx();
for (idx, discr) in adt_def.discriminants(tcx).enumerate() { for (idx, discr) in adt_def.discriminants(tcx).enumerate() {
target_blocks.place_back() <- if variants.contains(idx) { target_blocks.place_back() <- if variants.contains(idx) {
values.push(discr); values.push(discr.val);
*(targets.place_back() <- self.cfg.start_new_block()) *(targets.place_back() <- self.cfg.start_new_block())
} else { } else {
if otherwise_block.is_none() { if otherwise_block.is_none() {
@ -266,9 +232,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
assert!(options.len() > 0 && options.len() <= 2); assert!(options.len() > 0 && options.len() <= 2);
let (true_bb, false_bb) = (self.cfg.start_new_block(), let (true_bb, false_bb) = (self.cfg.start_new_block(),
self.cfg.start_new_block()); self.cfg.start_new_block());
let ret = match options[0].val { let ret = match options[0] {
ConstVal::Bool(true) => vec![true_bb, false_bb], 1 => vec![true_bb, false_bb],
ConstVal::Bool(false) => vec![false_bb, true_bb], 0 => vec![false_bb, true_bb],
v => span_bug!(test.span, "expected boolean value but got {:?}", v) v => span_bug!(test.span, "expected boolean value but got {:?}", v)
}; };
(ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place.clone()), (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place.clone()),
@ -282,13 +248,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
.map(|_| self.cfg.start_new_block()) .map(|_| self.cfg.start_new_block())
.chain(Some(otherwise)) .chain(Some(otherwise))
.collect(); .collect();
let values: Vec<_> = options.iter().map(|v|
v.val.to_const_int().expect("switching on integral")
).collect();
(targets.clone(), TerminatorKind::SwitchInt { (targets.clone(), TerminatorKind::SwitchInt {
discr: Operand::Copy(place.clone()), discr: Operand::Copy(place.clone()),
switch_ty, switch_ty,
values: From::from(values), values: options.clone().into(),
targets, targets,
}) })
}; };
@ -296,41 +259,88 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ret ret
} }
TestKind::Eq { value, ty } => { TestKind::Eq { value, mut ty } => {
let tcx = self.hir.tcx();
let mut val = Operand::Copy(place.clone()); let mut val = Operand::Copy(place.clone());
let mut expect = self.literal_operand(test.span, ty, Literal::Value {
// If we're using b"..." as a pattern, we need to insert an value
// unsizing coercion, as the byte string has the type &[u8; N]. });
// // Use PartialEq::eq instead of BinOp::Eq
// We want to do this even when the scrutinee is a reference to an // (the binop can only handle primitives)
// array, so we can call `<[u8]>::eq` rather than having to find an
// `<[u8; N]>::eq`.
let (expect, val) = if let ConstVal::ByteStr(bytes) = value.val {
let array_ty = tcx.mk_array(tcx.types.u8, bytes.data.len() as u64);
let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty);
let array = self.literal_operand(test.span, array_ref, Literal::Value {
value
});
let val = self.to_slice_operand(block, source_info, val);
let slice = self.to_slice_operand(block, source_info, array);
(slice, val)
} else {
(self.literal_operand(test.span, ty, Literal::Value {
value
}), val)
};
// Use PartialEq::eq for &str and &[u8] slices, instead of BinOp::Eq.
let fail = self.cfg.start_new_block(); let fail = self.cfg.start_new_block();
let ty = expect.ty(&self.local_decls, tcx); if !ty.is_scalar() {
if let ty::TyRef(_, mt) = ty.sty { // If we're using b"..." as a pattern, we need to insert an
assert!(ty.is_slice()); // unsizing coercion, as the byte string has the type &[u8; N].
//
// We want to do this even when the scrutinee is a reference to an
// array, so we can call `<[u8]>::eq` rather than having to find an
// `<[u8; N]>::eq`.
let unsize = |ty: Ty<'tcx>| match ty.sty {
ty::TyRef(region, tam) => match tam.ty.sty {
ty::TyArray(inner_ty, n) => Some((region, inner_ty, n)),
_ => None,
},
_ => None,
};
let opt_ref_ty = unsize(ty);
let opt_ref_test_ty = unsize(value.ty);
let mut place = place.clone();
match (opt_ref_ty, opt_ref_test_ty) {
// nothing to do, neither is an array
(None, None) => {},
(Some((region, elem_ty, _)), _) |
(None, Some((region, elem_ty, _))) => {
let tcx = self.hir.tcx();
// make both a slice
ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty));
if opt_ref_ty.is_some() {
place = self.temp(ty, test.span);
self.cfg.push_assign(block, source_info, &place,
Rvalue::Cast(CastKind::Unsize, val, ty));
}
if opt_ref_test_ty.is_some() {
let array = self.literal_operand(
test.span,
value.ty,
Literal::Value {
value
},
);
let slice = self.temp(ty, test.span);
self.cfg.push_assign(block, source_info, &slice,
Rvalue::Cast(CastKind::Unsize, array, ty));
expect = Operand::Move(slice);
}
},
}
let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap(); let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap();
let ty = mt.ty;
let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]); let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]);
// take the argument by reference
let region_scope = self.topmost_scope();
let region = self.hir.tcx().mk_region(ty::ReScope(region_scope));
let tam = ty::TypeAndMut {
ty,
mutbl: Mutability::MutImmutable,
};
let ref_ty = self.hir.tcx().mk_ref(region, tam);
// let lhs_ref_place = &lhs;
let ref_rvalue = Rvalue::Ref(region, BorrowKind::Shared, place.clone());
let lhs_ref_place = self.temp(ref_ty, test.span);
self.cfg.push_assign(block, source_info, &lhs_ref_place, ref_rvalue);
let val = Operand::Move(lhs_ref_place);
// let rhs_place = rhs;
let rhs_place = self.temp(ty, test.span);
self.cfg.push_assign(block, source_info, &rhs_place, Rvalue::Use(expect));
// let rhs_ref_place = &rhs_place;
let ref_rvalue = Rvalue::Ref(region, BorrowKind::Shared, rhs_place);
let rhs_ref_place = self.temp(ref_ty, test.span);
self.cfg.push_assign(block, source_info, &rhs_ref_place, ref_rvalue);
let expect = Operand::Move(rhs_ref_place);
let bool_ty = self.hir.bool_ty(); let bool_ty = self.hir.bool_ty();
let eq_result = self.temp(bool_ty, test.span); let eq_result = self.temp(bool_ty, test.span);
let eq_block = self.cfg.start_new_block(); let eq_block = self.cfg.start_new_block();

View file

@ -13,12 +13,11 @@
use build::Builder; use build::Builder;
use rustc_const_math::{ConstInt, ConstUsize, ConstIsize};
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, Ty}; use rustc::ty::{self, Ty};
use rustc::mir::interpret::{Value, PrimVal};
use rustc::mir::*; use rustc::mir::*;
use syntax::ast;
use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::{Span, DUMMY_SP};
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@ -55,63 +54,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// Returns a zero literal operand for the appropriate type, works for // Returns a zero literal operand for the appropriate type, works for
// bool, char and integers. // bool, char and integers.
pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
let literal = match ty.sty { match ty.sty {
ty::TyBool => { ty::TyBool |
self.hir.false_literal() ty::TyChar |
} ty::TyUint(_) |
ty::TyChar => { ty::TyInt(_) => {}
Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Char('\0'),
ty
})
}
}
ty::TyUint(ity) => {
let val = match ity {
ast::UintTy::U8 => ConstInt::U8(0),
ast::UintTy::U16 => ConstInt::U16(0),
ast::UintTy::U32 => ConstInt::U32(0),
ast::UintTy::U64 => ConstInt::U64(0),
ast::UintTy::U128 => ConstInt::U128(0),
ast::UintTy::Usize => {
let uint_ty = self.hir.tcx().sess.target.usize_ty;
let val = ConstUsize::new(0, uint_ty).unwrap();
ConstInt::Usize(val)
}
};
Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Integral(val),
ty
})
}
}
ty::TyInt(ity) => {
let val = match ity {
ast::IntTy::I8 => ConstInt::I8(0),
ast::IntTy::I16 => ConstInt::I16(0),
ast::IntTy::I32 => ConstInt::I32(0),
ast::IntTy::I64 => ConstInt::I64(0),
ast::IntTy::I128 => ConstInt::I128(0),
ast::IntTy::Isize => {
let int_ty = self.hir.tcx().sess.target.isize_ty;
let val = ConstIsize::new(0, int_ty).unwrap();
ConstInt::Isize(val)
}
};
Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Integral(val),
ty
})
}
}
_ => { _ => {
span_bug!(span, "Invalid type for zero_literal: `{:?}`", ty) span_bug!(span, "Invalid type for zero_literal: `{:?}`", ty)
} }
}
let literal = Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
ty
})
}; };
self.literal_operand(span, ty, literal) self.literal_operand(span, ty, literal)

View file

@ -11,7 +11,7 @@
use build; use build;
use hair::cx::Cx; use hair::cx::Cx;
use hair::LintLevel; use hair::{LintLevel, BindingMode, PatternKind};
use rustc::hir; use rustc::hir;
use rustc::hir::def_id::{DefId, LocalDefId}; use rustc::hir::def_id::{DefId, LocalDefId};
use rustc::middle::region; use rustc::middle::region;
@ -21,7 +21,6 @@ use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
use rustc::util::nodemap::NodeMap; use rustc::util::nodemap::NodeMap;
use rustc_back::PanicStrategy; use rustc_back::PanicStrategy;
use rustc_const_eval::pattern::{BindingMode, PatternKind};
use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use shim; use shim;
use std::mem; use std::mem;

View file

@ -783,7 +783,7 @@ fn is_unsafe_place<'a, 'gcx: 'tcx, 'tcx: 'a>(
match *place { match *place {
Local(_) => false, Local(_) => false,
Static(ref static_) => tcx.is_static_mut(static_.def_id), Static(ref static_) => tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable),
Projection(ref proj) => { Projection(ref proj) => {
match proj.elem { match proj.elem {
ProjectionElem::Field(..) | ProjectionElem::Field(..) |

View file

@ -12,6 +12,541 @@
register_long_diagnostics! { register_long_diagnostics! {
E0001: r##"
#### Note: this error code is no longer emitted by the compiler.
This error suggests that the expression arm corresponding to the noted pattern
will never be reached as for all possible values of the expression being
matched, one of the preceding patterns will match.
This means that perhaps some of the preceding patterns are too general, this
one is too specific or the ordering is incorrect.
For example, the following `match` block has too many arms:
```
match Some(0) {
Some(bar) => {/* ... */}
x => {/* ... */} // This handles the `None` case
_ => {/* ... */} // All possible cases have already been handled
}
```
`match` blocks have their patterns matched in order, so, for example, putting
a wildcard arm above a more specific arm will make the latter arm irrelevant.
Ensure the ordering of the match arm is correct and remove any superfluous
arms.
"##,
E0002: r##"
#### Note: this error code is no longer emitted by the compiler.
This error indicates that an empty match expression is invalid because the type
it is matching on is non-empty (there exist values of this type). In safe code
it is impossible to create an instance of an empty type, so empty match
expressions are almost never desired. This error is typically fixed by adding
one or more cases to the match expression.
An example of an empty type is `enum Empty { }`. So, the following will work:
```
enum Empty {}
fn foo(x: Empty) {
match x {
// empty
}
}
```
However, this won't:
```compile_fail
fn foo(x: Option<String>) {
match x {
// empty
}
}
```
"##,
E0004: r##"
This error indicates that the compiler cannot guarantee a matching pattern for
one or more possible inputs to a match expression. Guaranteed matches are
required in order to assign values to match expressions, or alternatively,
determine the flow of execution. Erroneous code example:
```compile_fail,E0004
enum Terminator {
HastaLaVistaBaby,
TalkToMyHand,
}
let x = Terminator::HastaLaVistaBaby;
match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered
Terminator::TalkToMyHand => {}
}
```
If you encounter this error you must alter your patterns so that every possible
value of the input type is matched. For types with a small number of variants
(like enums) you should probably cover all cases explicitly. Alternatively, the
underscore `_` wildcard pattern can be added after all other patterns to match
"anything else". Example:
```
enum Terminator {
HastaLaVistaBaby,
TalkToMyHand,
}
let x = Terminator::HastaLaVistaBaby;
match x {
Terminator::TalkToMyHand => {}
Terminator::HastaLaVistaBaby => {}
}
// or:
match x {
Terminator::TalkToMyHand => {}
_ => {}
}
```
"##,
E0005: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee
that a name will be extracted in all cases. Erroneous code example:
```compile_fail,E0005
let x = Some(1);
let Some(y) = x;
// error: refutable pattern in local binding: `None` not covered
```
If you encounter this error you probably need to use a `match` or `if let` to
deal with the possibility of failure. Example:
```
let x = Some(1);
match x {
Some(y) => {
// do something
},
None => {}
}
// or:
if let Some(y) = x {
// do something
}
```
"##,
E0007: r##"
This error indicates that the bindings in a match arm would require a value to
be moved into more than one location, thus violating unique ownership. Code
like the following is invalid as it requires the entire `Option<String>` to be
moved into a variable called `op_string` while simultaneously requiring the
inner `String` to be moved into a variable called `s`.
```compile_fail,E0007
let x = Some("s".to_string());
match x {
op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings
None => {},
}
```
See also the error E0303.
"##,
E0008: r##"
Names bound in match arms retain their type in pattern guards. As such, if a
name is bound by move in a pattern, it should also be moved to wherever it is
referenced in the pattern guard code. Doing so however would prevent the name
from being available in the body of the match arm. Consider the following:
```compile_fail,E0008
match Some("hi".to_string()) {
Some(s) if s.len() == 0 => {}, // use s.
_ => {},
}
```
The variable `s` has type `String`, and its use in the guard is as a variable of
type `String`. The guard code effectively executes in a separate scope to the
body of the arm, so the value would be moved into this anonymous scope and
therefore becomes unavailable in the body of the arm.
The problem above can be solved by using the `ref` keyword.
```
match Some("hi".to_string()) {
Some(ref s) if s.len() == 0 => {},
_ => {},
}
```
Though this example seems innocuous and easy to solve, the problem becomes clear
when it encounters functions which consume the value:
```compile_fail,E0008
struct A{}
impl A {
fn consume(self) -> usize {
0
}
}
fn main() {
let a = Some(A{});
match a {
Some(y) if y.consume() > 0 => {}
_ => {}
}
}
```
In this situation, even the `ref` keyword cannot solve it, since borrowed
content cannot be moved. This problem cannot be solved generally. If the value
can be cloned, here is a not-so-specific solution:
```
#[derive(Clone)]
struct A{}
impl A {
fn consume(self) -> usize {
0
}
}
fn main() {
let a = Some(A{});
match a{
Some(ref y) if y.clone().consume() > 0 => {}
_ => {}
}
}
```
If the value will be consumed in the pattern guard, using its clone will not
move its ownership, so the code works.
"##,
E0009: r##"
In a pattern, all values that don't implement the `Copy` trait have to be bound
the same way. The goal here is to avoid binding simultaneously by-move and
by-ref.
This limitation may be removed in a future version of Rust.
Erroneous code example:
```compile_fail,E0009
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the
// same pattern
None => panic!()
}
```
You have two solutions:
Solution #1: Bind the pattern's values the same way.
```
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((ref y, ref z)) => {},
// or Some((y, z)) => {}
None => panic!()
}
```
Solution #2: Implement the `Copy` trait for the `X` structure.
However, please keep in mind that the first solution should be preferred.
```
#[derive(Clone, Copy)]
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((y, ref z)) => {},
None => panic!()
}
```
"##,
E0030: r##"
When matching against a range, the compiler verifies that the range is
non-empty. Range patterns include both end-points, so this is equivalent to
requiring the start of the range to be less than or equal to the end of the
range.
For example:
```compile_fail
match 5u32 {
// This range is ok, albeit pointless.
1 ... 1 => {}
// This range is empty, and the compiler can tell.
1000 ... 5 => {}
}
```
"##,
E0158: r##"
`const` and `static` mean different things. A `const` is a compile-time
constant, an alias for a literal value. This property means you can match it
directly within a pattern.
The `static` keyword, on the other hand, guarantees a fixed location in memory.
This does not always mean that the value is constant. For example, a global
mutex can be declared `static` as well.
If you want to match against a `static`, consider using a guard instead:
```
static FORTY_TWO: i32 = 42;
match Some(42) {
Some(x) if x == FORTY_TWO => {}
_ => {}
}
```
"##,
E0162: r##"
An if-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding instead. For instance:
```compile_fail,E0162
struct Irrefutable(i32);
let irr = Irrefutable(0);
// This fails to compile because the match is irrefutable.
if let Irrefutable(x) = irr {
// This body will always be executed.
// ...
}
```
Try this instead:
```
struct Irrefutable(i32);
let irr = Irrefutable(0);
let Irrefutable(x) = irr;
println!("{}", x);
```
"##,
E0165: r##"
A while-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding inside a `loop` instead. For instance:
```compile_fail,E0165
struct Irrefutable(i32);
let irr = Irrefutable(0);
// This fails to compile because the match is irrefutable.
while let Irrefutable(x) = irr {
// ...
}
```
Try this instead:
```no_run
struct Irrefutable(i32);
let irr = Irrefutable(0);
loop {
let Irrefutable(x) = irr;
// ...
}
```
"##,
E0170: r##"
Enum variants are qualified by default. For example, given this type:
```
enum Method {
GET,
POST,
}
```
You would match it using:
```
enum Method {
GET,
POST,
}
let m = Method::GET;
match m {
Method::GET => {},
Method::POST => {},
}
```
If you don't qualify the names, the code will bind new variables named "GET" and
"POST" instead. This behavior is likely not what you want, so `rustc` warns when
that happens.
Qualified names are good practice, and most code works well with them. But if
you prefer them unqualified, you can import the variants into scope:
```
use Method::*;
enum Method { GET, POST }
# fn main() {}
```
If you want others to be able to import variants from your module directly, use
`pub use`:
```
pub use Method::*;
pub enum Method { GET, POST }
# fn main() {}
```
"##,
E0297: r##"
#### Note: this error code is no longer emitted by the compiler.
Patterns used to bind names must be irrefutable. That is, they must guarantee
that a name will be extracted in all cases. Instead of pattern matching the
loop variable, consider using a `match` or `if let` inside the loop body. For
instance:
```compile_fail,E0005
let xs : Vec<Option<i32>> = vec![Some(1), None];
// This fails because `None` is not covered.
for Some(x) in xs {
// ...
}
```
Match inside the loop instead:
```
let xs : Vec<Option<i32>> = vec![Some(1), None];
for item in xs {
match item {
Some(x) => {},
None => {},
}
}
```
Or use `if let`:
```
let xs : Vec<Option<i32>> = vec![Some(1), None];
for item in xs {
if let Some(x) = item {
// ...
}
}
```
"##,
E0301: r##"
Mutable borrows are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if mutable
borrows were allowed:
```compile_fail,E0301
match Some(()) {
None => { },
option if option.take().is_none() => {
/* impossible, option is `Some` */
},
Some(_) => { } // When the previous match failed, the option became `None`.
}
```
"##,
E0302: r##"
Assignments are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if assignments
were allowed:
```compile_fail,E0302
match Some(()) {
None => { },
option if { option = None; false } => { },
Some(_) => { } // When the previous match failed, the option became `None`.
}
```
"##,
E0303: r##"
In certain cases it is possible for sub-bindings to violate memory safety.
Updates to the borrow checker in a future version of Rust may remove this
restriction, but for now patterns must be rewritten without sub-bindings.
Before:
```compile_fail,E0303
match Some("hi".to_string()) {
ref op_string_ref @ Some(s) => {},
None => {},
}
```
After:
```
match Some("hi".to_string()) {
Some(ref s) => {
let op_string_ref = &Some(s);
// ...
},
None => {},
}
```
The `op_string_ref` binding has type `&Option<&String>` in both cases.
See also https://github.com/rust-lang/rust/issues/14587
"##,
E0010: r##" E0010: r##"
The value of statics and constants must be known at compile time, and they live The value of statics and constants must be known at compile time, and they live
for the entire lifetime of a program. Creating a boxed value allocates memory on for the entire lifetime of a program. Creating a boxed value allocates memory on
@ -1613,6 +2148,24 @@ fn main() {
``` ```
"##, "##,
E0579: r##"
When matching against an exclusive range, the compiler verifies that the range
is non-empty. Exclusive range patterns include the start point but not the end
point, so this is equivalent to requiring the start of the range to be less
than the end of the range.
For example:
```compile_fail
match 5u32 {
// This range is ok, albeit pointless.
1 .. 2 => {}
// This range is empty, and the compiler can tell.
5 .. 5 => {}
}
```
"##,
E0595: r##" E0595: r##"
Closures cannot mutate immutable captured variables. Closures cannot mutate immutable captured variables.
@ -1771,6 +2324,9 @@ b.resume();
} }
register_diagnostics! { register_diagnostics! {
// E0298, // cannot compare constants
// E0299, // mismatched types between arms
// E0471, // constant evaluation error (in pattern)
// E0385, // {} in an aliasable location // E0385, // {} in an aliasable location
E0493, // destructors cannot be evaluated at compile-time E0493, // destructors cannot be evaluated at compile-time
E0524, // two closures require unique access to `..` at the same time E0524, // two closures require unique access to `..` at the same time

View file

@ -10,12 +10,12 @@
use hair::*; use hair::*;
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
use rustc_const_math::ConstInt;
use hair::cx::Cx; use hair::cx::Cx;
use hair::cx::block; use hair::cx::block;
use hair::cx::to_ref::ToRef; use hair::cx::to_ref::ToRef;
use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def::{Def, CtorKind};
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc::mir::interpret::{GlobalId, Value, PrimVal};
use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::{self, AdtKind, VariantDef, Ty};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
use rustc::ty::cast::CastKind as TyCastKind; use rustc::ty::cast::CastKind as TyCastKind;
@ -100,7 +100,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
ExprKind::Deref { arg: expr.to_ref() } ExprKind::Deref { arg: expr.to_ref() }
} }
Adjust::Deref(Some(deref)) => { Adjust::Deref(Some(deref)) => {
let call = deref.method_call(cx.tcx, expr.ty); let call = deref.method_call(cx.tcx(), expr.ty);
expr = Expr { expr = Expr {
temp_lifetime, temp_lifetime,
@ -314,7 +314,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
} }
} }
hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) }, hir::ExprLit(ref lit) => ExprKind::Literal {
literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false),
},
hir::ExprBinary(op, ref lhs, ref rhs) => { hir::ExprBinary(op, ref lhs, ref rhs) => {
if cx.tables().is_method_call(expr) { if cx.tables().is_method_call(expr) {
@ -400,9 +402,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
if cx.tables().is_method_call(expr) { if cx.tables().is_method_call(expr) {
overloaded_operator(cx, expr, vec![arg.to_ref()]) overloaded_operator(cx, expr, vec![arg.to_ref()])
} else { } else {
// FIXME runtime-overflow if let hir::ExprLit(ref lit) = arg.node {
if let hir::ExprLit(_) = arg.node { ExprKind::Literal {
ExprKind::Literal { literal: cx.const_eval_literal(expr) } literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true),
}
} else { } else {
ExprKind::Unary { ExprKind::Unary {
op: UnOp::Neg, op: UnOp::Neg,
@ -508,10 +511,22 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
let c = &cx.tcx.hir.body(count).value; let c = &cx.tcx.hir.body(count).value;
let def_id = cx.tcx.hir.body_owner_def_id(count); let def_id = cx.tcx.hir.body_owner_def_id(count);
let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id); let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id);
let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) { let instance = ty::Instance::resolve(
Ok(&ty::Const { val: ConstVal::Integral(ConstInt::Usize(u)), .. }) => u, cx.tcx.global_tcx(),
Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), cx.param_env,
Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") def_id,
substs,
).unwrap();
let global_id = GlobalId {
instance,
promoted: None
};
let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) {
Ok(cv) => cv.val.unwrap_u64(),
Err(e) => {
e.report(cx.tcx, cx.tcx.def_span(def_id), "array length");
0
},
}; };
ExprKind::Repeat { ExprKind::Repeat {
@ -634,8 +649,8 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
span: expr.span, span: expr.span,
kind: ExprKind::Literal { kind: ExprKind::Literal {
literal: Literal::Value { literal: Literal::Value {
value: cx.tcx.mk_const(ty::Const { value: cx.tcx().mk_const(ty::Const {
val: ConstVal::Function(def_id, substs), val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
ty ty
}), }),
}, },
@ -682,13 +697,13 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
let substs = cx.tables().node_substs(expr.hir_id); let substs = cx.tables().node_substs(expr.hir_id);
match def { match def {
// A regular function, constructor function or a constant. // A regular function, constructor function or a constant.
Def::Fn(def_id) | Def::Fn(_) |
Def::Method(def_id) | Def::Method(_) |
Def::StructCtor(def_id, CtorKind::Fn) | Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal { Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
literal: Literal::Value { literal: Literal::Value {
value: cx.tcx.mk_const(ty::Const { value: cx.tcx.mk_const(ty::Const {
val: ConstVal::Function(def_id, substs), val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
ty: cx.tables().node_id_to_type(expr.hir_id) ty: cx.tables().node_id_to_type(expr.hir_id)
}), }),
}, },

View file

@ -16,22 +16,22 @@
use hair::*; use hair::*;
use rustc::middle::const_val::{ConstEvalErr, ConstVal}; use rustc::middle::const_val::ConstVal;
use rustc_const_eval::ConstContext;
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::blocks::FnLikeNode;
use rustc::middle::region; use rustc::middle::region;
use rustc::infer::InferCtxt; use rustc::infer::InferCtxt;
use rustc::ty::subst::Subst; use rustc::ty::subst::Subst;
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt, layout};
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
use syntax::ast; use syntax::ast::{self, LitKind};
use syntax::attr; use syntax::attr;
use syntax::symbol::Symbol; use syntax::symbol::Symbol;
use rustc::hir; use rustc::hir;
use rustc_const_math::{ConstInt, ConstUsize}; use rustc_const_math::ConstFloat;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc::mir::interpret::{Value, PrimVal};
#[derive(Clone)] #[derive(Clone)]
pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
@ -115,16 +115,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
} }
pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> { pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
match ConstUsize::new(value, self.tcx.sess.target.usize_ty) { Literal::Value {
Ok(val) => { value: self.tcx.mk_const(ty::Const {
Literal::Value { val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))),
value: self.tcx.mk_const(ty::Const { ty: self.tcx.types.usize
val: ConstVal::Integral(ConstInt::Usize(val)), })
ty: self.tcx.types.usize
})
}
}
Err(_) => bug!("usize literal out of range for target"),
} }
} }
@ -139,7 +134,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
pub fn true_literal(&mut self) -> Literal<'tcx> { pub fn true_literal(&mut self) -> Literal<'tcx> {
Literal::Value { Literal::Value {
value: self.tcx.mk_const(ty::Const { value: self.tcx.mk_const(ty::Const {
val: ConstVal::Bool(true), val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))),
ty: self.tcx.types.bool ty: self.tcx.types.bool
}) })
} }
@ -148,20 +143,104 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
pub fn false_literal(&mut self) -> Literal<'tcx> { pub fn false_literal(&mut self) -> Literal<'tcx> {
Literal::Value { Literal::Value {
value: self.tcx.mk_const(ty::Const { value: self.tcx.mk_const(ty::Const {
val: ConstVal::Bool(false), val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
ty: self.tcx.types.bool ty: self.tcx.types.bool
}) })
} }
} }
pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> { pub fn integer_bit_width(
&self,
ty: Ty,
) -> u64 {
let ty = match ty.sty {
ty::TyInt(ity) => attr::IntType::SignedInt(ity),
ty::TyUint(uty) => attr::IntType::UnsignedInt(uty),
_ => bug!("{} is not an integer", ty),
};
layout::Integer::from_attr(self.tcx, ty).size().bits()
}
pub fn const_eval_literal(
&mut self,
lit: &'tcx ast::LitKind,
ty: Ty<'tcx>,
sp: Span,
neg: bool,
) -> Literal<'tcx> {
trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
let tcx = self.tcx.global_tcx(); let tcx = self.tcx.global_tcx();
let const_cx = ConstContext::new(tcx,
self.param_env.and(self.identity_substs), let parse_float = |num: &str, fty| -> ConstFloat {
self.tables()); ConstFloat::from_str(num, fty).unwrap_or_else(|_| {
match const_cx.eval(tcx.hir.expect_expr(e.id)) { // FIXME(#31407) this is only necessary because float parsing is buggy
Ok(value) => Literal::Value { value }, tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)");
Err(s) => self.fatal_const_eval_err(&s, e.span, "expression") })
};
let clamp = |n| {
let size = self.integer_bit_width(ty);
trace!("clamp {} with size {} and amt {}", n, size, 128 - size);
let amt = 128 - size;
let result = (n << amt) >> amt;
trace!("clamp result: {}", result);
result
};
use rustc::mir::interpret::*;
let lit = match *lit {
LitKind::Str(ref s, _) => {
let s = s.as_str();
let id = self.tcx.allocate_cached(s.as_bytes());
let ptr = MemoryPointer::new(id, 0);
Value::ByValPair(
PrimVal::Ptr(ptr),
PrimVal::from_u128(s.len() as u128),
)
},
LitKind::ByteStr(ref data) => {
let id = self.tcx.allocate_cached(data);
let ptr = MemoryPointer::new(id, 0);
Value::ByVal(PrimVal::Ptr(ptr))
},
LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
LitKind::Int(n, _) if neg => {
let n = n as i128;
let n = n.overflowing_neg().0;
let n = clamp(n as u128);
Value::ByVal(PrimVal::Bytes(n))
},
LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(clamp(n))),
LitKind::Float(n, fty) => {
let n = n.as_str();
let mut f = parse_float(&n, fty);
if neg {
f = -f;
}
let bits = f.bits;
Value::ByVal(PrimVal::Bytes(bits))
}
LitKind::FloatUnsuffixed(n) => {
let fty = match ty.sty {
ty::TyFloat(fty) => fty,
_ => bug!()
};
let n = n.as_str();
let mut f = parse_float(&n, fty);
if neg {
f = -f;
}
let bits = f.bits;
Value::ByVal(PrimVal::Bytes(bits))
}
LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
};
Literal::Value {
value: self.tcx.mk_const(ty::Const {
val: ConstVal::Value(lit),
ty,
}),
} }
} }
@ -177,17 +256,6 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
p) p)
} }
pub fn fatal_const_eval_err(&mut 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, pub fn trait_method(&mut self,
trait_def_id: DefId, trait_def_id: DefId,
method_name: &str, method_name: &str,
@ -203,7 +271,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
return (method_ty, return (method_ty,
Literal::Value { Literal::Value {
value: self.tcx.mk_const(ty::Const { value: self.tcx.mk_const(ty::Const {
val: ConstVal::Function(item.def_id, substs), // ZST function type
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
ty: method_ty ty: method_ty
}), }),
}); });

View file

@ -14,7 +14,6 @@
//! unit-tested and separated from the Rust source and compiler data //! unit-tested and separated from the Rust source and compiler data
//! structures. //! structures.
use rustc_const_math::ConstUsize;
use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp}; use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp};
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::middle::region; use rustc::middle::region;
@ -27,7 +26,8 @@ use self::cx::Cx;
pub mod cx; pub mod cx;
pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPattern}; pub mod pattern;
pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum LintLevel { pub enum LintLevel {
@ -246,7 +246,7 @@ pub enum ExprKind<'tcx> {
}, },
Repeat { Repeat {
value: ExprRef<'tcx>, value: ExprRef<'tcx>,
count: ConstUsize, count: u64,
}, },
Array { Array {
fields: Vec<ExprRef<'tcx>>, fields: Vec<ExprRef<'tcx>>,

View file

@ -13,21 +13,19 @@ use self::Usefulness::*;
use self::WitnessPreference::*; use self::WitnessPreference::*;
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use eval::{compare_const_vals};
use rustc_const_math::ConstInt;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
use pattern::{FieldPattern, Pattern, PatternKind}; use super::{FieldPattern, Pattern, PatternKind};
use pattern::{PatternFoldable, PatternFolder}; use super::{PatternFoldable, PatternFolder, compare_const_vals};
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::hir::RangeEnd; use rustc::hir::RangeEnd;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::mir::Field; use rustc::mir::Field;
use rustc::mir::interpret::{Value, PrimVal};
use rustc::util::common::ErrorReported; use rustc::util::common::ErrorReported;
use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::{Span, DUMMY_SP};
@ -182,18 +180,38 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
self.byte_array_map.entry(pat).or_insert_with(|| { self.byte_array_map.entry(pat).or_insert_with(|| {
match pat.kind { match pat.kind {
box PatternKind::Constant { box PatternKind::Constant {
value: &ty::Const { val: ConstVal::ByteStr(b), .. } value: &ty::Const { val: ConstVal::Value(b), ty }
} => { } => {
b.data.iter().map(|&b| &*pattern_arena.alloc(Pattern { match b {
ty: tcx.types.u8, Value::ByVal(PrimVal::Ptr(ptr)) => {
span: pat.span, let is_array_ptr = ty
kind: box PatternKind::Constant { .builtin_deref(true)
value: tcx.mk_const(ty::Const { .and_then(|t| t.ty.builtin_index())
val: ConstVal::Integral(ConstInt::U8(b)), .map_or(false, |t| t == tcx.types.u8);
ty: tcx.types.u8 assert!(is_array_ptr);
}) let alloc = tcx
} .interpret_interner
})).collect() .get_alloc(ptr.alloc_id)
.unwrap();
assert_eq!(ptr.offset, 0);
// FIXME: check length
alloc.bytes.iter().map(|b| {
&*pattern_arena.alloc(Pattern {
ty: tcx.types.u8,
span: pat.span,
kind: box PatternKind::Constant {
value: tcx.mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(
PrimVal::Bytes(*b as u128),
)),
ty: tcx.types.u8
})
}
})
}).collect()
},
_ => bug!("not a byte str: {:?}", b),
}
} }
_ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat) _ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat)
} }
@ -422,13 +440,13 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
ty::TyBool => { ty::TyBool => {
[true, false].iter().map(|&b| { [true, false].iter().map(|&b| {
ConstantValue(cx.tcx.mk_const(ty::Const { ConstantValue(cx.tcx.mk_const(ty::Const {
val: ConstVal::Bool(b), val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))),
ty: cx.tcx.types.bool ty: cx.tcx.types.bool
})) }))
}).collect() }).collect()
} }
ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => { ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => {
let len = len.val.to_const_int().unwrap().to_u64().unwrap(); let len = len.val.unwrap_u64();
if len != 0 && cx.is_uninhabited(sub_ty) { if len != 0 && cx.is_uninhabited(sub_ty) {
vec![] vec![]
} else { } else {
@ -461,7 +479,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
} }
fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
_cx: &mut MatchCheckCtxt<'a, 'tcx>, cx: &mut MatchCheckCtxt<'a, 'tcx>,
patterns: I) -> u64 patterns: I) -> u64
where I: Iterator<Item=&'p Pattern<'tcx>> where I: Iterator<Item=&'p Pattern<'tcx>>
{ {
@ -535,8 +553,23 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
for row in patterns { for row in patterns {
match *row.kind { match *row.kind {
PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => { PatternKind::Constant {
max_fixed_len = cmp::max(max_fixed_len, b.data.len() as u64); value: &ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))),
ty,
}
} => {
let is_array_ptr = ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == cx.tcx.types.u8);
if is_array_ptr {
let alloc = cx.tcx
.interpret_interner
.get_alloc(ptr.alloc_id)
.unwrap();
max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
}
} }
PatternKind::Slice { ref prefix, slice: None, ref suffix } => { PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
let fixed_len = prefix.len() as u64 + suffix.len() as u64; let fixed_len = prefix.len() as u64 + suffix.len() as u64;
@ -581,7 +614,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
witness: WitnessPreference) witness: WitnessPreference)
-> Usefulness<'tcx> { -> Usefulness<'tcx> {
let &Matrix(ref rows) = matrix; let &Matrix(ref rows) = matrix;
debug!("is_useful({:?}, {:?})", matrix, v); debug!("is_useful({:#?}, {:#?})", matrix, v);
// The base case. We are pattern-matching on () and the return value is // The base case. We are pattern-matching on () and the return value is
// based on whether our matrix has a row or not. // based on whether our matrix has a row or not.
@ -626,10 +659,10 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0]))) max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0])))
}; };
debug!("is_useful_expand_first_col: pcx={:?}, expanding {:?}", pcx, v[0]); debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]);
if let Some(constructors) = pat_constructors(cx, v[0], pcx) { if let Some(constructors) = pat_constructors(cx, v[0], pcx) {
debug!("is_useful - expanding constructors: {:?}", constructors); debug!("is_useful - expanding constructors: {:#?}", constructors);
constructors.into_iter().map(|c| constructors.into_iter().map(|c|
is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness) is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
).find(|result| result.is_useful()).unwrap_or(NotUseful) ).find(|result| result.is_useful()).unwrap_or(NotUseful)
@ -639,9 +672,9 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
let used_ctors: Vec<Constructor> = rows.iter().flat_map(|row| { let used_ctors: Vec<Constructor> = rows.iter().flat_map(|row| {
pat_constructors(cx, row[0], pcx).unwrap_or(vec![]) pat_constructors(cx, row[0], pcx).unwrap_or(vec![])
}).collect(); }).collect();
debug!("used_ctors = {:?}", used_ctors); debug!("used_ctors = {:#?}", used_ctors);
let all_ctors = all_constructors(cx, pcx); let all_ctors = all_constructors(cx, pcx);
debug!("all_ctors = {:?}", all_ctors); debug!("all_ctors = {:#?}", all_ctors);
let missing_ctors: Vec<Constructor> = all_ctors.iter().filter(|c| { let missing_ctors: Vec<Constructor> = all_ctors.iter().filter(|c| {
!used_ctors.contains(*c) !used_ctors.contains(*c)
}).cloned().collect(); }).cloned().collect();
@ -669,7 +702,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty); all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
let is_declared_nonexhaustive = let is_declared_nonexhaustive =
cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty); cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
debug!("missing_ctors={:?} is_privately_empty={:?} is_declared_nonexhaustive={:?}", debug!("missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
missing_ctors, is_privately_empty, is_declared_nonexhaustive); missing_ctors, is_privately_empty, is_declared_nonexhaustive);
// For privately empty and non-exhaustive enums, we work as if there were an "extra" // For privately empty and non-exhaustive enums, we work as if there were an "extra"
@ -769,7 +802,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
lty: Ty<'tcx>, lty: Ty<'tcx>,
witness: WitnessPreference) -> Usefulness<'tcx> witness: WitnessPreference) -> Usefulness<'tcx>
{ {
debug!("is_useful_specialized({:?}, {:?}, {:?})", v, ctor, lty); debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty); let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty);
let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| { let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| {
Pattern { Pattern {
@ -821,7 +854,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
Some(vec![ConstantRange(lo, hi, end)]), Some(vec![ConstantRange(lo, hi, end)]),
PatternKind::Array { .. } => match pcx.ty.sty { PatternKind::Array { .. } => match pcx.ty.sty {
ty::TyArray(_, length) => Some(vec![ ty::TyArray(_, length) => Some(vec![
Slice(length.val.to_const_int().unwrap().to_u64().unwrap()) Slice(length.val.unwrap_u64())
]), ]),
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty) _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
}, },
@ -842,7 +875,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3. /// 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. /// 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, ctor: &Constructor, ty: Ty) -> u64 {
debug!("constructor_arity({:?}, {:?})", ctor, ty); debug!("constructor_arity({:#?}, {:?})", ctor, ty);
match ty.sty { match ty.sty {
ty::TyTuple(ref fs, _) => fs.len() as u64, ty::TyTuple(ref fs, _) => fs.len() as u64,
ty::TySlice(..) | ty::TyArray(..) => match *ctor { ty::TySlice(..) | ty::TyArray(..) => match *ctor {
@ -866,7 +899,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
ctor: &Constructor, ctor: &Constructor,
ty: Ty<'tcx>) -> Vec<Ty<'tcx>> ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
{ {
debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty); debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
match ty.sty { match ty.sty {
ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(), ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(),
ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor { ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor {
@ -901,14 +934,28 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
} }
} }
fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
ctor: &Constructor, ctor: &Constructor,
prefix: &[Pattern], prefix: &[Pattern],
slice: &Option<Pattern>, slice: &Option<Pattern>,
suffix: &[Pattern]) suffix: &[Pattern])
-> Result<bool, ErrorReported> { -> Result<bool, ErrorReported> {
let data = match *ctor { let data: &[u8] = match *ctor {
ConstantValue(&ty::Const { val: ConstVal::ByteStr(b), .. }) => b.data, ConstantValue(&ty::Const { val: ConstVal::Value(
Value::ByVal(PrimVal::Ptr(ptr))
), ty }) => {
let is_array_ptr = ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == tcx.types.u8);
assert!(is_array_ptr);
tcx
.interpret_interner
.get_alloc(ptr.alloc_id)
.unwrap()
.bytes
.as_ref()
}
_ => bug!() _ => bug!()
}; };
@ -923,11 +970,12 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
{ {
match pat.kind { match pat.kind {
box PatternKind::Constant { value } => match value.val { box PatternKind::Constant { value } => match value.val {
ConstVal::Integral(ConstInt::U8(u)) => { ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
if u != *ch { assert_eq!(b as u8 as u128, b);
if b as u8 != *ch {
return Ok(false); return Ok(false);
} }
}, }
_ => span_bug!(pat.span, "bad const u8 {:?}", value) _ => span_bug!(pat.span, "bad const u8 {:?}", value)
}, },
_ => {} _ => {}
@ -937,31 +985,41 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
Ok(true) Ok(true)
} }
fn constructor_covered_by_range(tcx: TyCtxt, span: Span, fn constructor_covered_by_range(ctor: &Constructor,
ctor: &Constructor,
from: &ConstVal, to: &ConstVal, from: &ConstVal, to: &ConstVal,
end: RangeEnd) end: RangeEnd,
ty: Ty)
-> Result<bool, ErrorReported> { -> Result<bool, ErrorReported> {
let cmp_from = |c_from| Ok(compare_const_vals(tcx, span, c_from, from)? != Ordering::Less); trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty);
let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to); let cmp_from = |c_from| compare_const_vals(c_from, from, ty)
.map(|res| res != Ordering::Less);
let cmp_to = |c_to| compare_const_vals(c_to, to, ty);
macro_rules! some_or_ok {
($e:expr) => {
match $e {
Some(to) => to,
None => return Ok(false), // not char or int
}
};
}
match *ctor { match *ctor {
ConstantValue(value) => { ConstantValue(value) => {
let to = cmp_to(&value.val)?; let to = some_or_ok!(cmp_to(&value.val));
let end = (to == Ordering::Less) || let end = (to == Ordering::Less) ||
(end == RangeEnd::Included && to == Ordering::Equal); (end == RangeEnd::Included && to == Ordering::Equal);
Ok(cmp_from(&value.val)? && end) Ok(some_or_ok!(cmp_from(&value.val)) && end)
}, },
ConstantRange(from, to, RangeEnd::Included) => { ConstantRange(from, to, RangeEnd::Included) => {
let to = cmp_to(&to.val)?; let to = some_or_ok!(cmp_to(&to.val));
let end = (to == Ordering::Less) || let end = (to == Ordering::Less) ||
(end == RangeEnd::Included && to == Ordering::Equal); (end == RangeEnd::Included && to == Ordering::Equal);
Ok(cmp_from(&from.val)? && end) Ok(some_or_ok!(cmp_from(&from.val)) && end)
}, },
ConstantRange(from, to, RangeEnd::Excluded) => { ConstantRange(from, to, RangeEnd::Excluded) => {
let to = cmp_to(&to.val)?; let to = some_or_ok!(cmp_to(&to.val));
let end = (to == Ordering::Less) || let end = (to == Ordering::Less) ||
(end == RangeEnd::Excluded && to == Ordering::Equal); (end == RangeEnd::Excluded && to == Ordering::Equal);
Ok(cmp_from(&from.val)? && end) Ok(some_or_ok!(cmp_from(&from.val)) && end)
} }
Single => Ok(true), Single => Ok(true),
_ => bug!(), _ => bug!(),
@ -979,7 +1037,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
result[subpat.field.index()] = &subpat.pattern; result[subpat.field.index()] = &subpat.pattern;
} }
debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, wild_patterns, result); debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result);
result result
} }
@ -994,7 +1052,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
fn specialize<'p, 'a: 'p, 'tcx: 'a>( fn specialize<'p, 'a: 'p, 'tcx: 'a>(
cx: &mut MatchCheckCtxt<'a, 'tcx>, cx: &mut MatchCheckCtxt<'a, 'tcx>,
r: &[&'p Pattern<'tcx>], r: &[&'p Pattern<'tcx>],
constructor: &Constructor, constructor: &Constructor<'tcx>,
wild_patterns: &[&'p Pattern<'tcx>]) wild_patterns: &[&'p Pattern<'tcx>])
-> Option<Vec<&'p Pattern<'tcx>>> -> Option<Vec<&'p Pattern<'tcx>>>
{ {
@ -1024,8 +1082,19 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
PatternKind::Constant { value } => { PatternKind::Constant { value } => {
match *constructor { match *constructor {
Slice(..) => match value.val { Slice(..) => match value.val {
ConstVal::ByteStr(b) => { ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => {
if wild_patterns.len() == b.data.len() { let is_array_ptr = value.ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == cx.tcx.types.u8);
assert!(is_array_ptr);
let data_len = cx.tcx
.interpret_interner
.get_alloc(ptr.alloc_id)
.unwrap()
.bytes
.len();
if wild_patterns.len() == data_len {
Some(cx.lower_byte_str_pattern(pat)) Some(cx.lower_byte_str_pattern(pat))
} else { } else {
None None
@ -1036,7 +1105,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
}, },
_ => { _ => {
match constructor_covered_by_range( match constructor_covered_by_range(
cx.tcx, pat.span, constructor, &value.val, &value.val, RangeEnd::Included constructor, &value.val, &value.val, RangeEnd::Included,
value.ty,
) { ) {
Ok(true) => Some(vec![]), Ok(true) => Some(vec![]),
Ok(false) => None, Ok(false) => None,
@ -1048,7 +1118,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
PatternKind::Range { lo, hi, ref end } => { PatternKind::Range { lo, hi, ref end } => {
match constructor_covered_by_range( match constructor_covered_by_range(
cx.tcx, pat.span, constructor, &lo.val, &hi.val, end.clone() constructor, &lo.val, &hi.val, end.clone(), lo.ty,
) { ) {
Ok(true) => Some(vec![]), Ok(true) => Some(vec![]),
Ok(false) => None, Ok(false) => None,
@ -1092,7 +1162,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
} }
} }
}; };
debug!("specialize({:?}, {:?}) = {:?}", r[0], wild_patterns, head); debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head);
head.map(|mut head| { head.map(|mut head| {
head.extend_from_slice(&r[1 ..]); head.extend_from_slice(&r[1 ..]);

View file

@ -8,11 +8,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful}; use super::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
use _match::Usefulness::*; use super::_match::Usefulness::*;
use _match::WitnessPreference::*; use super::_match::WitnessPreference::*;
use pattern::{Pattern, PatternContext, PatternError, PatternKind}; use super::{Pattern, PatternContext, PatternError, PatternKind};
use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
use rustc::middle::expr_use_visitor::{LoanCause, MutateMode}; use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
@ -138,8 +138,18 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
PatternError::AssociatedConstInPattern(span) => { PatternError::AssociatedConstInPattern(span) => {
self.span_e0158(span, "associated consts cannot be referenced in patterns") self.span_e0158(span, "associated consts cannot be referenced in patterns")
} }
PatternError::ConstEval(ref err) => { PatternError::FloatBug => {
err.report(self.tcx, pat_span, "pattern"); // FIXME(#31407) this is only necessary because float parsing is buggy
::rustc::middle::const_val::struct_error(
self.tcx, pat_span,
"could not evaluate float literal (see issue #31407)",
).emit();
}
PatternError::NonConstPath(span) => {
::rustc::middle::const_val::struct_error(
self.tcx, span,
"runtime values cannot be referenced in patterns",
).emit();
} }
} }
} }

View file

@ -8,10 +8,19 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use eval; //! Code to validate patterns/matches
use rustc::middle::const_val::{ConstEvalErr, ConstVal}; mod _match;
mod check_match;
pub use self::check_match::check_crate;
pub(crate) use self::check_match::check_match;
use interpret::{const_val_field, const_discr};
use rustc::middle::const_val::ConstVal;
use rustc::mir::{Field, BorrowKind, Mutability}; use rustc::mir::{Field, BorrowKind, Mutability};
use rustc::mir::interpret::{GlobalId, Value, PrimVal};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
use rustc::ty::subst::{Substs, Kind}; use rustc::ty::subst::{Substs, Kind};
use rustc::hir::{self, PatKind, RangeEnd}; use rustc::hir::{self, PatKind, RangeEnd};
@ -19,17 +28,20 @@ use rustc::hir::def::{Def, CtorKind};
use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::hir::pat_util::EnumerateAndAdjustIterator;
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
use rustc_const_math::ConstFloat;
use std::cmp::Ordering;
use std::fmt; use std::fmt;
use syntax::ast; use syntax::ast;
use syntax::ptr::P; use syntax::ptr::P;
use syntax_pos::Span; use syntax_pos::Span;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum PatternError<'tcx> { pub enum PatternError {
AssociatedConstInPattern(Span), AssociatedConstInPattern(Span),
StaticInPattern(Span), StaticInPattern(Span),
ConstEval(ConstEvalErr<'tcx>), FloatBug,
NonConstPath(Span),
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -110,21 +122,26 @@ pub enum PatternKind<'tcx> {
}, },
} }
fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
match *value { match value.val {
ConstVal::Float(ref x) => write!(f, "{}", x), ConstVal::Value(v) => print_miri_value(v, value.ty, f),
ConstVal::Integral(ref i) => write!(f, "{}", i),
ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]),
ConstVal::ByteStr(b) => write!(f, "{:?}", b.data),
ConstVal::Bool(b) => write!(f, "{:?}", b),
ConstVal::Char(c) => write!(f, "{:?}", c),
ConstVal::Variant(_) |
ConstVal::Function(..) |
ConstVal::Aggregate(_) |
ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value) ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
} }
} }
fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result {
use rustc::ty::TypeVariants::*;
match (value, &ty.sty) {
(Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
(Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
(Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n),
(Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128),
(Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
_ => bug!("{:?}: {} not printable in a pattern", value, ty),
}
}
impl<'tcx> fmt::Display for Pattern<'tcx> { impl<'tcx> fmt::Display for Pattern<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.kind { match *self.kind {
@ -232,15 +249,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
write!(f, "{}", subpattern) write!(f, "{}", subpattern)
} }
PatternKind::Constant { value } => { PatternKind::Constant { value } => {
print_const_val(&value.val, f) print_const_val(value, f)
} }
PatternKind::Range { lo, hi, end } => { PatternKind::Range { lo, hi, end } => {
print_const_val(&lo.val, f)?; print_const_val(lo, f)?;
match end { match end {
RangeEnd::Included => write!(f, "...")?, RangeEnd::Included => write!(f, "...")?,
RangeEnd::Excluded => write!(f, "..")?, RangeEnd::Excluded => write!(f, "..")?,
} }
print_const_val(&hi.val, f) print_const_val(hi, f)
} }
PatternKind::Slice { ref prefix, ref slice, ref suffix } | PatternKind::Slice { ref prefix, ref slice, ref suffix } |
PatternKind::Array { ref prefix, ref slice, ref suffix } => { PatternKind::Array { ref prefix, ref slice, ref suffix } => {
@ -272,7 +289,7 @@ pub struct PatternContext<'a, 'tcx: 'a> {
pub param_env: ty::ParamEnv<'tcx>, pub param_env: ty::ParamEnv<'tcx>,
pub tables: &'a ty::TypeckTables<'tcx>, pub tables: &'a ty::TypeckTables<'tcx>,
pub substs: &'tcx Substs<'tcx>, pub substs: &'tcx Substs<'tcx>,
pub errors: Vec<PatternError<'tcx>>, pub errors: Vec<PatternError>,
} }
impl<'a, 'tcx> Pattern<'tcx> { impl<'a, 'tcx> Pattern<'tcx> {
@ -350,18 +367,53 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
PatKind::Lit(ref value) => self.lower_lit(value), PatKind::Lit(ref value) => self.lower_lit(value),
PatKind::Range(ref lo, ref hi, end) => { PatKind::Range(ref lo_expr, ref hi_expr, end) => {
match (self.lower_lit(lo), self.lower_lit(hi)) { match (self.lower_lit(lo_expr), self.lower_lit(hi_expr)) {
(PatternKind::Constant { value: lo }, (PatternKind::Constant { value: lo },
PatternKind::Constant { value: hi }) => { PatternKind::Constant { value: hi }) => {
PatternKind::Range { lo, hi, end } use std::cmp::Ordering;
match (end, compare_const_vals(&lo.val, &hi.val, ty).unwrap()) {
(RangeEnd::Excluded, Ordering::Less) =>
PatternKind::Range { lo, hi, end },
(RangeEnd::Excluded, _) => {
span_err!(
self.tcx.sess,
lo_expr.span,
E0579,
"lower range bound must be less than upper",
);
PatternKind::Wild
},
(RangeEnd::Included, Ordering::Greater) => {
let mut err = struct_span_err!(
self.tcx.sess,
lo_expr.span,
E0030,
"lower range bound must be less than or equal to upper"
);
err.span_label(
lo_expr.span,
"lower bound larger than upper bound",
);
if self.tcx.sess.teach(&err.get_code().unwrap()) {
err.note("When matching against a range, the compiler \
verifies that the range is non-empty. Range \
patterns include both end-points, so this is \
equivalent to requiring the start of the range \
to be less than or equal to the end of the range.");
}
err.emit();
PatternKind::Wild
},
(RangeEnd::Included, _) => PatternKind::Range { lo, hi, end },
}
} }
_ => PatternKind::Wild _ => PatternKind::Wild
} }
} }
PatKind::Path(ref qpath) => { PatKind::Path(ref qpath) => {
return self.lower_path(qpath, pat.hir_id, pat.id, pat.span); return self.lower_path(qpath, pat.hir_id, pat.span);
} }
PatKind::Ref(ref subpattern, _) | PatKind::Ref(ref subpattern, _) |
@ -471,7 +523,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
pattern: self.lower_pattern(field), pattern: self.lower_pattern(field),
}) })
.collect(); .collect();
self.lower_variant_or_leaf(def, ty, subpatterns) self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
} }
PatKind::Struct(ref qpath, ref fields, _) => { PatKind::Struct(ref qpath, ref fields, _) => {
@ -503,7 +555,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
}) })
.collect(); .collect();
self.lower_variant_or_leaf(def, ty, subpatterns) self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
} }
}; };
@ -580,7 +632,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
ty::TyArray(_, len) => { ty::TyArray(_, len) => {
// fixed-length array // fixed-length array
let len = len.val.to_const_int().unwrap().to_u64().unwrap(); let len = len.val.unwrap_u64();
assert!(len >= prefix.len() as u64 + suffix.len() as u64); assert!(len >= prefix.len() as u64 + suffix.len() as u64);
PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix } PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
} }
@ -594,6 +646,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
fn lower_variant_or_leaf( fn lower_variant_or_leaf(
&mut self, &mut self,
def: Def, def: Def,
span: Span,
ty: Ty<'tcx>, ty: Ty<'tcx>,
subpatterns: Vec<FieldPattern<'tcx>>) subpatterns: Vec<FieldPattern<'tcx>>)
-> PatternKind<'tcx> -> PatternKind<'tcx>
@ -624,14 +677,19 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
PatternKind::Leaf { subpatterns: subpatterns } PatternKind::Leaf { subpatterns: subpatterns }
} }
_ => bug!() _ => {
self.errors.push(PatternError::NonConstPath(span));
PatternKind::Wild
}
} }
} }
/// Takes a HIR Path. If the path is a constant, evaluates it and feeds
/// it to `const_to_pat`. Any other path (like enum variants without fields)
/// is converted to the corresponding pattern via `lower_variant_or_leaf`
fn lower_path(&mut self, fn lower_path(&mut self,
qpath: &hir::QPath, qpath: &hir::QPath,
id: hir::HirId, id: hir::HirId,
pat_id: ast::NodeId,
span: Span) span: Span)
-> Pattern<'tcx> { -> Pattern<'tcx> {
let ty = self.tables.node_id_to_type(id); let ty = self.tables.node_id_to_type(id);
@ -643,23 +701,27 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
let kind = match def { let kind = match def {
Def::Const(def_id) | Def::AssociatedConst(def_id) => { Def::Const(def_id) | Def::AssociatedConst(def_id) => {
let substs = self.tables.node_substs(id); let substs = self.tables.node_substs(id);
match eval::lookup_const_by_id(self.tcx, self.param_env.and((def_id, substs))) { match ty::Instance::resolve(
Some((def_id, substs)) => { self.tcx,
// Enter the inlined constant's tables&substs temporarily. self.param_env,
let old_tables = self.tables; def_id,
let old_substs = self.substs; substs,
self.tables = self.tcx.typeck_tables_of(def_id); ) {
self.substs = substs; Some(instance) => {
let body = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { let cid = GlobalId {
self.tcx.hir.body(self.tcx.hir.body_owned_by(id)) instance,
} else { promoted: None,
self.tcx.extern_const_body(def_id).body
}; };
let pat = self.lower_const_expr(&body.value, pat_id, span); match self.tcx.at(span).const_eval(self.param_env.and(cid)) {
self.tables = old_tables; Ok(value) => {
self.substs = old_substs; return self.const_to_pat(instance, value, id, span)
return pat; },
} Err(err) => {
err.report(self.tcx, span, "pattern");
PatternKind::Wild
},
}
},
None => { None => {
self.errors.push(if is_associated_const { self.errors.push(if is_associated_const {
PatternError::AssociatedConstInPattern(span) PatternError::AssociatedConstInPattern(span)
@ -667,10 +729,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
PatternError::StaticInPattern(span) PatternError::StaticInPattern(span)
}); });
PatternKind::Wild PatternKind::Wild
} },
} }
} }
_ => self.lower_variant_or_leaf(def, ty, vec![]), _ => self.lower_variant_or_leaf(def, span, ty, vec![]),
}; };
Pattern { Pattern {
@ -680,138 +742,167 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
} }
} }
/// Converts literals, paths and negation of literals to patterns.
/// The special case for negation exists to allow things like -128i8
/// which would overflow if we tried to evaluate 128i8 and then negate
/// afterwards.
fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> { fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
let const_cx = eval::ConstContext::new(self.tcx, match expr.node {
self.param_env.and(self.substs), hir::ExprLit(ref lit) => {
self.tables); let ty = self.tables.expr_ty(expr);
match const_cx.eval(expr) { match lit_to_const(&lit.node, self.tcx, ty, false) {
Ok(value) => { Ok(val) => {
if let ConstVal::Variant(def_id) = value.val { let instance = ty::Instance::new(
let ty = self.tables.expr_ty(expr); self.tables.local_id_root.expect("literal outside any scope"),
self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![]) self.substs,
} else { );
PatternKind::Constant { value } let cv = self.tcx.mk_const(ty::Const { val, ty });
*self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
},
Err(()) => {
self.errors.push(PatternError::FloatBug);
PatternKind::Wild
},
}
},
hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind,
hir::ExprUnary(hir::UnNeg, ref expr) => {
let ty = self.tables.expr_ty(expr);
let lit = match expr.node {
hir::ExprLit(ref lit) => lit,
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
};
match lit_to_const(&lit.node, self.tcx, ty, true) {
Ok(val) => {
let instance = ty::Instance::new(
self.tables.local_id_root.expect("literal outside any scope"),
self.substs,
);
let cv = self.tcx.mk_const(ty::Const { val, ty });
*self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
},
Err(()) => {
self.errors.push(PatternError::FloatBug);
PatternKind::Wild
},
} }
} }
Err(e) => { _ => span_bug!(expr.span, "not a literal: {:?}", expr),
self.errors.push(PatternError::ConstEval(e));
PatternKind::Wild
}
} }
} }
fn lower_const_expr(&mut self, /// Converts an evaluated constant to a pattern (if possible).
expr: &'tcx hir::Expr, /// This means aggregate values (like structs and enums) are converted
pat_id: ast::NodeId, /// to a pattern that matches the value (as if you'd compare via eq).
span: Span) fn const_to_pat(
-> Pattern<'tcx> { &self,
let pat_ty = self.tables.expr_ty(expr); instance: ty::Instance<'tcx>,
debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id); cv: &'tcx ty::Const<'tcx>,
match pat_ty.sty { id: hir::HirId,
span: Span,
) -> Pattern<'tcx> {
debug!("const_to_pat: cv={:#?}", cv);
let adt_subpattern = |i, variant_opt| {
let field = Field::new(i);
let val = match cv.val {
ConstVal::Value(miri) => const_val_field(
self.tcx, self.param_env, instance,
variant_opt, field, miri, cv.ty,
).unwrap(),
_ => bug!("{:#?} is not a valid adt", cv),
};
self.const_to_pat(instance, val, id, span)
};
let adt_subpatterns = |n, variant_opt| {
(0..n).map(|i| {
let field = Field::new(i);
FieldPattern {
field,
pattern: adt_subpattern(i, variant_opt),
}
}).collect::<Vec<_>>()
};
let kind = match cv.ty.sty {
ty::TyFloat(_) => { ty::TyFloat(_) => {
self.tcx.sess.span_err(span, "floating point constants cannot be used in patterns"); let id = self.tcx.hir.hir_to_node_id(id);
} self.tcx.lint_node(
::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
id,
span,
"floating-point types cannot be used in patterns",
);
PatternKind::Constant {
value: cv,
}
},
ty::TyAdt(adt_def, _) if adt_def.is_union() => { ty::TyAdt(adt_def, _) if adt_def.is_union() => {
// Matching on union fields is unsafe, we can't hide it in constants // Matching on union fields is unsafe, we can't hide it in constants
self.tcx.sess.span_err(span, "cannot use unions in constant patterns"); self.tcx.sess.span_err(span, "cannot use unions in constant patterns");
PatternKind::Wild
} }
ty::TyAdt(adt_def, _) => { ty::TyAdt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => {
if !self.tcx.has_attr(adt_def.did, "structural_match") { let msg = format!("to use a constant of type `{}` in a pattern, \
let msg = format!("to use a constant of type `{}` in a pattern, \ `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
`{}` must be annotated with `#[derive(PartialEq, Eq)]`", self.tcx.item_path_str(adt_def.did),
self.tcx.item_path_str(adt_def.did), self.tcx.item_path_str(adt_def.did));
self.tcx.item_path_str(adt_def.did)); self.tcx.sess.span_err(span, &msg);
self.tcx.sess.span_err(span, &msg); PatternKind::Wild
} },
} ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
_ => { } match cv.val {
} ConstVal::Value(val) => {
let kind = match expr.node { let discr = const_discr(
hir::ExprTup(ref exprs) => { self.tcx, self.param_env, instance, val, cv.ty
PatternKind::Leaf { ).unwrap();
subpatterns: exprs.iter().enumerate().map(|(i, expr)| { let variant_index = adt_def
FieldPattern { .discriminants(self.tcx)
field: Field::new(i), .position(|var| var.val == discr)
pattern: self.lower_const_expr(expr, pat_id, span) .unwrap();
let subpatterns = adt_subpatterns(
adt_def.variants[variant_index].fields.len(),
Some(variant_index),
);
PatternKind::Variant {
adt_def,
substs,
variant_index,
subpatterns,
} }
}).collect() },
ConstVal::Unevaluated(..) =>
span_bug!(span, "{:#?} is not a valid enum constant", cv),
}
},
ty::TyAdt(adt_def, _) => {
let struct_var = adt_def.non_enum_variant();
PatternKind::Leaf {
subpatterns: adt_subpatterns(struct_var.fields.len(), None),
} }
} }
ty::TyTuple(fields, _) => {
hir::ExprCall(ref callee, ref args) => { PatternKind::Leaf {
let qpath = match callee.node { subpatterns: adt_subpatterns(fields.len(), None),
hir::ExprPath(ref qpath) => qpath,
_ => bug!()
};
let ty = self.tables.node_id_to_type(callee.hir_id);
let def = self.tables.qpath_def(qpath, callee.hir_id);
match def {
Def::Fn(..) | Def::Method(..) => self.lower_lit(expr),
_ => {
let subpatterns = args.iter().enumerate().map(|(i, expr)| {
FieldPattern {
field: Field::new(i),
pattern: self.lower_const_expr(expr, pat_id, span)
}
}).collect();
self.lower_variant_or_leaf(def, ty, subpatterns)
}
} }
} }
ty::TyArray(_, n) => {
hir::ExprStruct(ref qpath, ref fields, None) => {
let def = self.tables.qpath_def(qpath, expr.hir_id);
let adt_def = match pat_ty.sty {
ty::TyAdt(adt_def, _) => adt_def,
_ => {
span_bug!(
expr.span,
"struct expr without ADT type");
}
};
let variant_def = adt_def.variant_of_def(def);
let subpatterns =
fields.iter()
.map(|field| {
let index = variant_def.index_of_field_named(field.name.node);
let index = index.unwrap_or_else(|| {
span_bug!(
expr.span,
"no field with name {:?}",
field.name);
});
FieldPattern {
field: Field::new(index),
pattern: self.lower_const_expr(&field.expr, pat_id, span),
}
})
.collect();
self.lower_variant_or_leaf(def, pat_ty, subpatterns)
}
hir::ExprArray(ref exprs) => {
let pats = exprs.iter()
.map(|expr| self.lower_const_expr(expr, pat_id, span))
.collect();
PatternKind::Array { PatternKind::Array {
prefix: pats, prefix: (0..n.val.unwrap_u64())
.map(|i| adt_subpattern(i as usize, None))
.collect(),
slice: None, slice: None,
suffix: vec![] suffix: Vec::new(),
} }
} }
_ => {
hir::ExprPath(ref qpath) => { PatternKind::Constant {
return self.lower_path(qpath, expr.hir_id, pat_id, span); value: cv,
} }
},
_ => self.lower_lit(expr)
}; };
Pattern { Pattern {
span, span,
ty: pat_ty, ty: cv.ty,
kind: Box::new(kind), kind: Box::new(kind),
} }
} }
@ -975,3 +1066,127 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
} }
} }
} }
pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option<Ordering> {
use rustc_const_math::ConstFloat;
trace!("compare_const_vals: {:?}, {:?}", a, b);
use rustc::mir::interpret::{Value, PrimVal};
match (a, b) {
(&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))),
&ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => {
match ty.sty {
ty::TyFloat(ty) => {
let l = ConstFloat {
bits: a,
ty,
};
let r = ConstFloat {
bits: b,
ty,
};
// FIXME(oli-obk): report cmp errors?
l.try_cmp(r).ok()
},
ty::TyInt(_) => Some((a as i128).cmp(&(b as i128))),
_ => Some(a.cmp(&b)),
}
},
_ if a == b => Some(Ordering::Equal),
_ => None,
}
}
fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'tcx>,
neg: bool)
-> Result<ConstVal<'tcx>, ()> {
use syntax::ast::*;
use rustc::mir::interpret::*;
let lit = match *lit {
LitKind::Str(ref s, _) => {
let s = s.as_str();
let id = tcx.allocate_cached(s.as_bytes());
let ptr = MemoryPointer::new(id, 0);
Value::ByValPair(
PrimVal::Ptr(ptr),
PrimVal::from_u128(s.len() as u128),
)
},
LitKind::ByteStr(ref data) => {
let id = tcx.allocate_cached(data);
let ptr = MemoryPointer::new(id, 0);
Value::ByVal(PrimVal::Ptr(ptr))
},
LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
LitKind::Int(n, _) => {
enum Int {
Signed(IntTy),
Unsigned(UintTy),
}
let ty = match ty.sty {
ty::TyInt(IntTy::Isize) => Int::Signed(tcx.sess.target.isize_ty),
ty::TyInt(other) => Int::Signed(other),
ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty),
ty::TyUint(other) => Int::Unsigned(other),
_ => bug!(),
};
let n = match ty {
// FIXME(oli-obk): are these casts correct?
Int::Signed(IntTy::I8) if neg =>
(n as i128 as i8).overflowing_neg().0 as i128 as u128,
Int::Signed(IntTy::I16) if neg =>
(n as i128 as i16).overflowing_neg().0 as i128 as u128,
Int::Signed(IntTy::I32) if neg =>
(n as i128 as i32).overflowing_neg().0 as i128 as u128,
Int::Signed(IntTy::I64) if neg =>
(n as i128 as i64).overflowing_neg().0 as i128 as u128,
Int::Signed(IntTy::I128) if neg =>
(n as i128).overflowing_neg().0 as u128,
Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128,
Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128,
Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128,
Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128,
Int::Signed(IntTy::I128) => n,
Int::Unsigned(UintTy::U8) => n as u8 as u128,
Int::Unsigned(UintTy::U16) => n as u16 as u128,
Int::Unsigned(UintTy::U32) => n as u32 as u128,
Int::Unsigned(UintTy::U64) => n as u64 as u128,
Int::Unsigned(UintTy::U128) => n,
_ => bug!(),
};
Value::ByVal(PrimVal::Bytes(n))
},
LitKind::Float(n, fty) => {
let n = n.as_str();
let mut f = parse_float(&n, fty)?;
if neg {
f = -f;
}
let bits = f.bits;
Value::ByVal(PrimVal::Bytes(bits))
}
LitKind::FloatUnsuffixed(n) => {
let fty = match ty.sty {
ty::TyFloat(fty) => fty,
_ => bug!()
};
let n = n.as_str();
let mut f = parse_float(&n, fty)?;
if neg {
f = -f;
}
let bits = f.bits;
Value::ByVal(PrimVal::Bytes(bits))
}
LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
};
Ok(ConstVal::Value(lit))
}
fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
-> Result<ConstFloat, ()> {
ConstFloat::from_str(num, fty).map_err(|_| ())
}

View file

@ -1,4 +1,5 @@
use rustc::ty::Ty; use rustc::ty::Ty;
use rustc::ty::layout::LayoutOf;
use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::ast::{FloatTy, IntTy, UintTy};
use rustc_const_math::ConstFloat; use rustc_const_math::ConstFloat;
@ -7,115 +8,95 @@ use rustc::mir::interpret::{PrimVal, EvalResult, MemoryPointer, PointerArithmeti
use rustc_apfloat::ieee::{Single, Double}; use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::Float; use rustc_apfloat::Float;
impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
pub(super) fn cast_primval( pub(super) fn cast_primval(
&self, &self,
val: PrimVal, val: PrimVal,
src_ty: Ty<'tcx>, src_ty: Ty<'tcx>,
dest_ty: Ty<'tcx>, dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx, PrimVal> { ) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty); trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
let src_kind = self.ty_to_primval_kind(src_ty)?;
match val { match val {
PrimVal::Undef => Ok(PrimVal::Undef), PrimVal::Undef => Ok(PrimVal::Undef),
PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty), PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
val @ PrimVal::Bytes(_) => { PrimVal::Bytes(b) => {
use rustc::mir::interpret::PrimValKind::*; match src_ty.sty {
match src_kind { TyFloat(fty) => self.cast_from_float(b, fty, dest_ty),
F32 => self.cast_from_float(val.to_f32()?, dest_ty), _ => self.cast_from_int(b, src_ty, dest_ty),
F64 => self.cast_from_float(val.to_f64()?, dest_ty),
I8 | I16 | I32 | I64 | I128 => {
self.cast_from_signed_int(val.to_i128()?, dest_ty)
}
Bool | Char | U8 | U16 | U32 | U64 | U128 | FnPtr | Ptr => {
self.cast_from_int(val.to_u128()?, dest_ty, false)
}
} }
} }
} }
} }
fn cast_from_signed_int(&self, val: i128, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
self.cast_from_int(val as u128, ty, val < 0)
}
fn int_to_int(&self, v: i128, ty: IntTy) -> u128 {
match ty {
IntTy::I8 => v as i8 as u128,
IntTy::I16 => v as i16 as u128,
IntTy::I32 => v as i32 as u128,
IntTy::I64 => v as i64 as u128,
IntTy::I128 => v as u128,
IntTy::Isize => {
let ty = self.tcx.sess.target.isize_ty;
self.int_to_int(v, ty)
}
}
}
fn int_to_uint(&self, v: u128, ty: UintTy) -> u128 {
match ty {
UintTy::U8 => v as u8 as u128,
UintTy::U16 => v as u16 as u128,
UintTy::U32 => v as u32 as u128,
UintTy::U64 => v as u64 as u128,
UintTy::U128 => v,
UintTy::Usize => {
let ty = self.tcx.sess.target.usize_ty;
self.int_to_uint(v, ty)
}
}
}
fn cast_from_int( fn cast_from_int(
&self, &self,
v: u128, v: u128,
ty: Ty<'tcx>, src_ty: Ty<'tcx>,
negative: bool, dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx, PrimVal> { ) -> EvalResult<'tcx, PrimVal> {
trace!("cast_from_int: {}, {}, {}", v, ty, negative); let signed = self.layout_of(src_ty)?.abi.is_signed();
let v = if signed {
self.sign_extend(v, src_ty)?
} else {
v
};
trace!("cast_from_int: {}, {}, {}", v, src_ty, dest_ty);
use rustc::ty::TypeVariants::*; use rustc::ty::TypeVariants::*;
match ty.sty { match dest_ty.sty {
// Casts to bool are not permitted by rustc, no need to handle them here. TyInt(_) | TyUint(_) => {
TyInt(ty) => Ok(PrimVal::Bytes(self.int_to_int(v as i128, ty))), let v = self.truncate(v, dest_ty)?;
TyUint(ty) => Ok(PrimVal::Bytes(self.int_to_uint(v, ty))), Ok(PrimVal::Bytes(v))
}
TyFloat(fty) if negative => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)), TyFloat(fty) if signed => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)),
TyFloat(fty) => Ok(PrimVal::Bytes(ConstFloat::from_u128(v, fty).bits)), TyFloat(fty) => Ok(PrimVal::Bytes(ConstFloat::from_u128(v, fty).bits)),
TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)), TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
TyChar => err!(InvalidChar(v)), TyChar => err!(InvalidChar(v)),
// No alignment check needed for raw pointers. But we have to truncate to target ptr size. // No alignment check needed for raw pointers. But we have to truncate to target ptr size.
TyRawPtr(_) => Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128)), TyRawPtr(_) => {
Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128))
},
_ => err!(Unimplemented(format!("int to {:?} cast", ty))), // Casts to bool are not permitted by rustc, no need to handle them here.
_ => err!(Unimplemented(format!("int to {:?} cast", dest_ty))),
} }
} }
fn cast_from_float(&self, val: ConstFloat, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> { fn cast_from_float(&self, bits: u128, fty: FloatTy, dest_ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*; use rustc::ty::TypeVariants::*;
match ty.sty { use rustc_apfloat::FloatConvert;
match dest_ty.sty {
// float -> uint
TyUint(t) => { TyUint(t) => {
let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8); let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
match val.ty { match fty {
FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(val.bits).to_u128(width).value)), FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(bits).to_u128(width).value)),
FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(val.bits).to_u128(width).value)), FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(bits).to_u128(width).value)),
} }
}, },
// float -> int
TyInt(t) => { TyInt(t) => {
let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8); let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
match val.ty { match fty {
FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(val.bits).to_i128(width).value)), FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(bits).to_i128(width).value)),
FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(val.bits).to_i128(width).value)), FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(bits).to_i128(width).value)),
} }
}, },
// f64 -> f32
TyFloat(fty) => Ok(PrimVal::from_float(val.convert(fty))), TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
_ => err!(Unimplemented(format!("float to {:?} cast", ty))), Ok(PrimVal::Bytes(Single::to_bits(Double::from_bits(bits).convert(&mut false).value)))
},
// f32 -> f64
TyFloat(FloatTy::F64) if fty == FloatTy::F32 => {
Ok(PrimVal::Bytes(Double::to_bits(Single::from_bits(bits).convert(&mut false).value)))
},
// identity cast
TyFloat(_) => Ok(PrimVal::Bytes(bits)),
_ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
} }
} }

View file

@ -1,34 +1,49 @@
use rustc::hir;
use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError};
use rustc::mir;
use rustc::ty::{self, TyCtxt, Ty, Instance}; use rustc::ty::{self, TyCtxt, Ty, Instance};
use rustc::ty::layout::{self, LayoutOf}; use rustc::ty::layout::{self, LayoutOf};
use rustc::ty::subst::Substs; use rustc::ty::subst::Subst;
use rustc::hir::def_id::DefId;
use rustc::mir;
use rustc::middle::const_val::ErrKind::{CheckMatchError, TypeckError};
use rustc::middle::const_val::{ConstEvalErr, ConstVal};
use rustc_const_eval::{lookup_const_by_id, ConstContext};
use rustc::mir::Field;
use rustc_data_structures::indexed_vec::Idx;
use syntax::ast::Mutability; use syntax::ast::Mutability;
use syntax::codemap::Span; use syntax::codemap::Span;
use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal}; use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal, AllocId};
use super::{Place, EvalContext, StackPopCleanup, ValTy}; use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory};
use rustc_const_math::ConstInt;
use std::fmt; use std::fmt;
use std::error::Error; use std::error::Error;
use std::rc::Rc;
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, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>> {
debug!("mk_borrowck_eval_cx: {:?}", instance);
let param_env = tcx.param_env(instance.def_id());
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
// insert a stack frame so any queries have the correct substs
ecx.push_stack_frame(
instance,
span,
mir,
Place::undef(),
StackPopCleanup::None,
)?;
Ok(ecx)
}
pub fn mk_eval_cx<'a, 'tcx>( pub fn mk_eval_cx<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance: Instance<'tcx>, instance: Instance<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
) -> EvalResult<'tcx, EvalContext<'a, 'tcx, CompileTimeEvaluator>> { ) -> EvalResult<'tcx, EvalContext<'a, 'tcx, 'tcx, CompileTimeEvaluator>> {
debug!("mk_eval_cx: {:?}, {:?}", instance, param_env); debug!("mk_eval_cx: {:?}, {:?}", instance, param_env);
let limits = super::ResourceLimits::default(); let span = tcx.def_span(instance.def_id());
let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
let mir = ecx.load_mir(instance.def)?; let mir = ecx.load_mir(instance.def)?;
// insert a stack frame so any queries have the correct substs // insert a stack frame so any queries have the correct substs
ecx.push_stack_frame( ecx.push_stack_frame(
@ -41,99 +56,115 @@ pub fn mk_eval_cx<'a, 'tcx>(
Ok(ecx) Ok(ecx)
} }
pub fn eval_body<'a, 'tcx>( pub fn eval_body_with_mir<'a, 'mir, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance: Instance<'tcx>, cid: GlobalId<'tcx>,
mir: &'mir mir::Mir<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
) -> EvalResult<'tcx, (Pointer, Ty<'tcx>)> { ) -> Option<(Value, Pointer, Ty<'tcx>)> {
debug!("eval_body: {:?}, {:?}", instance, param_env); let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env);
let limits = super::ResourceLimits::default(); match res {
let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); Ok(val) => Some(val),
let cid = GlobalId { Err(mut err) => {
instance, ecx.report(&mut err, true, None);
promoted: None, None
}; }
if ecx.tcx.has_attr(instance.def_id(), "linkage") {
return Err(ConstEvalError::NotConst("extern global".to_string()).into());
} }
let instance_ty = instance.ty(tcx);
if tcx.interpret_interner.borrow().get_cached(cid).is_none() {
let mir = ecx.load_mir(instance.def)?;
let layout = ecx.layout_of(instance_ty)?;
assert!(!layout.is_unsized());
let ptr = ecx.memory.allocate(
layout.size.bytes(),
layout.align,
None,
)?;
tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id);
let cleanup = StackPopCleanup::MarkStatic(Mutability::Immutable);
let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id()));
trace!("const_eval: pushing stack frame for global: {}", name);
ecx.push_stack_frame(
instance,
mir.span,
mir,
Place::from_ptr(ptr, layout.align),
cleanup.clone(),
)?;
while ecx.step()? {}
}
let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached");
Ok((MemoryPointer::new(alloc, 0).into(), instance_ty))
} }
pub fn eval_body_as_integer<'a, 'tcx>( pub fn eval_body<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
cid: GlobalId<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
instance: Instance<'tcx>, ) -> Option<(Value, Pointer, Ty<'tcx>)> {
) -> EvalResult<'tcx, ConstInt> { let (res, ecx) = eval_body_and_ecx(tcx, cid, None, param_env);
let ptr_ty = eval_body(tcx, instance, param_env); match res {
let (ptr, ty) = ptr_ty?; Ok(val) => Some(val),
let ecx = mk_eval_cx(tcx, instance, param_env)?; Err(mut err) => {
let prim = match ecx.try_read_value(ptr, ecx.layout_of(ty)?.align, ty)? { ecx.report(&mut err, true, None);
Some(Value::ByVal(prim)) => prim.to_bytes()?, None
_ => return err!(TypeNotPrimitive(ty)),
};
use syntax::ast::{IntTy, UintTy};
use rustc::ty::TypeVariants::*;
use rustc_const_math::{ConstIsize, ConstUsize};
Ok(match ty.sty {
TyInt(IntTy::I8) => ConstInt::I8(prim as i128 as i8),
TyInt(IntTy::I16) => ConstInt::I16(prim as i128 as i16),
TyInt(IntTy::I32) => ConstInt::I32(prim as i128 as i32),
TyInt(IntTy::I64) => ConstInt::I64(prim as i128 as i64),
TyInt(IntTy::I128) => ConstInt::I128(prim as i128),
TyInt(IntTy::Isize) => ConstInt::Isize(
ConstIsize::new(prim as i128 as i64, tcx.sess.target.isize_ty)
.expect("miri should already have errored"),
),
TyUint(UintTy::U8) => ConstInt::U8(prim as u8),
TyUint(UintTy::U16) => ConstInt::U16(prim as u16),
TyUint(UintTy::U32) => ConstInt::U32(prim as u32),
TyUint(UintTy::U64) => ConstInt::U64(prim as u64),
TyUint(UintTy::U128) => ConstInt::U128(prim),
TyUint(UintTy::Usize) => ConstInt::Usize(
ConstUsize::new(prim as u64, tcx.sess.target.usize_ty)
.expect("miri should already have errored"),
),
_ => {
return Err(
ConstEvalError::NeedsRfc(
"evaluating anything other than isize/usize during typeck".to_string(),
).into(),
)
} }
}) }
}
fn eval_body_and_ecx<'a, 'mir, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cid: GlobalId<'tcx>,
mir: Option<&'mir mir::Mir<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
debug!("eval_body: {:?}, {:?}", cid, param_env);
// we start out with the best span we have
// and try improving it down the road when more information is available
let span = tcx.def_span(cid.instance.def_id());
let mut span = mir.map(|mir| mir.span).unwrap_or(span);
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
let res = (|| {
let mut mir = match mir {
Some(mir) => mir,
None => ecx.load_mir(cid.instance.def)?,
};
if let Some(index) = cid.promoted {
mir = &mir.promoted[index];
}
span = mir.span;
let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
let alloc = tcx.interpret_interner.get_cached(cid.instance.def_id());
let alloc = match alloc {
Some(alloc) => {
assert!(cid.promoted.is_none());
assert!(param_env.caller_bounds.is_empty());
alloc
},
None => {
assert!(!layout.is_unsized());
let ptr = ecx.memory.allocate(
layout.size.bytes(),
layout.align,
None,
)?;
if tcx.is_static(cid.instance.def_id()).is_some() {
tcx.interpret_interner.cache(cid.instance.def_id(), ptr.alloc_id);
}
let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span);
let mutability = tcx.is_static(cid.instance.def_id());
let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable {
Mutability::Mutable
} else {
Mutability::Immutable
};
let cleanup = StackPopCleanup::MarkStatic(mutability);
let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id()));
let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p));
trace!("const_eval: pushing stack frame for global: {}{}", name, prom);
assert!(mir.arg_count == 0);
ecx.push_stack_frame(
cid.instance,
mir.span,
mir,
Place::from_ptr(ptr, layout.align),
cleanup,
)?;
while ecx.step()? {}
ptr.alloc_id
}
};
let ptr = MemoryPointer::new(alloc, 0).into();
let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
Some(val) => val,
_ => Value::ByRef(ptr, layout.align),
};
Ok((value, ptr, layout.ty))
})();
(res, ecx)
} }
pub struct CompileTimeEvaluator; pub struct CompileTimeEvaluator;
impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError { impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
fn into(self) -> EvalError<'tcx> { fn into(self) -> EvalError<'tcx> {
EvalErrorKind::MachineError(Box::new(self)).into() EvalErrorKind::MachineError(self.to_string()).into()
} }
} }
@ -154,7 +185,7 @@ impl fmt::Display for ConstEvalError {
msg msg
) )
} }
NotConst(ref msg) => write!(f, "Cannot evaluate within constants: \"{}\"", msg), NotConst(ref msg) => write!(f, "{}", msg),
} }
} }
} }
@ -173,33 +204,48 @@ impl Error for ConstEvalError {
} }
} }
impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
type MemoryData = (); type MemoryData = ();
type MemoryKinds = !; type MemoryKinds = !;
fn eval_fn_call<'a>( fn eval_fn_call<'a>(
ecx: &mut EvalContext<'a, 'tcx, Self>, ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>, instance: ty::Instance<'tcx>,
destination: Option<(Place, mir::BasicBlock)>, destination: Option<(Place, mir::BasicBlock)>,
_args: &[ValTy<'tcx>], args: &[ValTy<'tcx>],
span: Span, span: Span,
_sig: ty::FnSig<'tcx>, sig: ty::FnSig<'tcx>,
) -> EvalResult<'tcx, bool> { ) -> EvalResult<'tcx, bool> {
debug!("eval_fn_call: {:?}", instance); debug!("eval_fn_call: {:?}", instance);
if !ecx.tcx.is_const_fn(instance.def_id()) { if !ecx.tcx.is_const_fn(instance.def_id()) {
return Err( let def_id = instance.def_id();
ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(), let (op, oflo) = if let Some(op) = ecx.tcx.is_binop_lang_item(def_id) {
); op
} else {
return Err(
ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(),
);
};
let (dest, bb) = destination.expect("128 lowerings can't diverge");
let dest_ty = sig.output();
if oflo {
ecx.intrinsic_with_overflow(op, args[0], args[1], dest, dest_ty)?;
} else {
ecx.intrinsic_overflowing(op, args[0], args[1], dest, dest_ty)?;
}
ecx.goto_block(bb);
return Ok(true);
} }
let mir = match ecx.load_mir(instance.def) { let mir = match ecx.load_mir(instance.def) {
Ok(mir) => mir, Ok(mir) => mir,
Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { Err(err) => {
// some simple things like `malloc` might get accepted in the future if let EvalErrorKind::NoMirFor(ref path) = err.kind {
return Err( return Err(
ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
.into(), .into(),
); );
}
return Err(err);
} }
Err(other) => return Err(other),
}; };
let (return_place, return_to_block) = match destination { let (return_place, return_to_block) = match destination {
Some((place, block)) => (place, StackPopCleanup::Goto(block)), Some((place, block)) => (place, StackPopCleanup::Goto(block)),
@ -219,7 +265,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
fn call_intrinsic<'a>( fn call_intrinsic<'a>(
ecx: &mut EvalContext<'a, 'tcx, Self>, ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>, instance: ty::Instance<'tcx>,
_args: &[ValTy<'tcx>], _args: &[ValTy<'tcx>],
dest: Place, dest: Place,
@ -261,7 +307,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
} }
fn try_ptr_op<'a>( fn try_ptr_op<'a>(
_ecx: &EvalContext<'a, 'tcx, Self>, _ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
_bin_op: mir::BinOp, _bin_op: mir::BinOp,
left: PrimVal, left: PrimVal,
_left_ty: Ty<'tcx>, _left_ty: Ty<'tcx>,
@ -277,12 +323,29 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
} }
} }
fn mark_static_initialized(m: !) -> EvalResult<'tcx> { fn mark_static_initialized<'a>(
m _mem: &mut Memory<'a, 'mir, 'tcx, Self>,
_id: AllocId,
_mutability: Mutability,
) -> EvalResult<'tcx, bool> {
Ok(false)
}
fn init_static<'a>(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
cid: GlobalId<'tcx>,
) -> EvalResult<'tcx, AllocId> {
// ensure the static is computed
ecx.const_eval(cid)?;
Ok(ecx
.tcx
.interpret_interner
.get_cached(cid.instance.def_id())
.expect("uncached static"))
} }
fn box_alloc<'a>( fn box_alloc<'a>(
_ecx: &mut EvalContext<'a, 'tcx, Self>, _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
_ty: Ty<'tcx>, _ty: Ty<'tcx>,
_dest: Place, _dest: Place,
) -> EvalResult<'tcx> { ) -> EvalResult<'tcx> {
@ -292,7 +355,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
} }
fn global_item_with_linkage<'a>( fn global_item_with_linkage<'a>(
_ecx: &mut EvalContext<'a, 'tcx, Self>, _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
_instance: ty::Instance<'tcx>, _instance: ty::Instance<'tcx>,
_mutability: Mutability, _mutability: Mutability,
) -> EvalResult<'tcx> { ) -> EvalResult<'tcx> {
@ -302,275 +365,147 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
} }
} }
pub fn const_val_field<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
variant: Option<usize>,
field: mir::Field,
value: Value,
ty: Ty<'tcx>,
) -> ::rustc::middle::const_val::EvalResult<'tcx> {
trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
let result = (|| {
let (mut field, ty) = match value {
Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
Value::ByRef(ptr, align) => {
let place = Place::Ptr {
ptr,
align,
extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant),
};
let layout = ecx.layout_of(ty)?;
let (place, layout) = ecx.place_field(place, field, layout)?;
let (ptr, align) = place.to_ptr_align();
(Value::ByRef(ptr, align), layout.ty)
}
};
if let Value::ByRef(ptr, align) = field {
if let Some(val) = ecx.try_read_value(ptr, align, ty)? {
field = val;
}
}
Ok((field, ty))
})();
match result {
Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
val: ConstVal::Value(field),
ty,
})),
Err(err) => {
let (trace, span) = ecx.generate_stacktrace(None);
let err = ErrKind::Miri(err, trace);
Err(ConstEvalErr {
kind: err.into(),
span,
})
},
}
}
pub fn const_discr<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
value: Value,
ty: Ty<'tcx>,
) -> EvalResult<'tcx, u128> {
trace!("const_discr: {:?}, {:?}, {:?}", instance, value, ty);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
let (ptr, align) = match value {
Value::ByValPair(..) | Value::ByVal(_) => {
let layout = ecx.layout_of(ty)?;
use super::MemoryKind;
let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
let ptr: Pointer = ptr.into();
ecx.write_value_to_ptr(value, ptr, layout.align, ty)?;
(ptr, layout.align)
},
Value::ByRef(ptr, align) => (ptr, align),
};
let place = Place::from_primval_ptr(ptr, align);
ecx.read_discriminant_value(place, ty)
}
pub fn const_eval_provider<'a, 'tcx>( pub fn const_eval_provider<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc::middle::const_val::EvalResult<'tcx> { ) -> ::rustc::middle::const_val::EvalResult<'tcx> {
trace!("const eval: {:?}", key); trace!("const eval: {:?}", key);
let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, key) { let cid = key.value;
resolved let def_id = cid.instance.def.def_id();
} else {
return Err(ConstEvalErr {
span: tcx.def_span(key.value.0),
kind: TypeckError
});
};
let tables = tcx.typeck_tables_of(def_id); if tcx.is_foreign_item(def_id) {
let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { let id = tcx.interpret_interner.get_cached(def_id);
let body_id = tcx.hir.body_owned_by(id); let id = match id {
// FIXME: due to caches this shouldn't happen, add some assertions
Some(id) => id,
None => {
let id = tcx.interpret_interner.reserve();
tcx.interpret_interner.cache(def_id, id);
id
},
};
let ty = tcx.type_of(def_id);
let layout = tcx.layout_of(key.param_env.and(ty)).unwrap();
let ptr = MemoryPointer::new(id, 0);
return Ok(tcx.mk_const(ty::Const {
val: ConstVal::Value(Value::ByRef(ptr.into(), layout.align)),
ty,
}))
}
if let Some(id) = tcx.hir.as_local_node_id(def_id) {
let tables = tcx.typeck_tables_of(def_id);
let span = tcx.def_span(def_id);
// Do match-check before building MIR // Do match-check before building MIR
if tcx.check_match(def_id).is_err() { if tcx.check_match(def_id).is_err() {
return Err(ConstEvalErr { return Err(ConstEvalErr {
span: tcx.def_span(key.value.0), kind: Rc::new(CheckMatchError),
kind: CheckMatchError, span,
}); });
} }
tcx.mir_const_qualif(def_id); if let hir::BodyOwnerKind::Const = tcx.hir.body_owner_kind(id) {
tcx.hir.body(body_id) tcx.mir_const_qualif(def_id);
} else { }
tcx.extern_const_body(def_id).body
// Do not continue into miri if typeck errors occurred; it will fail horribly
if tables.tainted_by_errors {
return Err(ConstEvalErr {
kind: Rc::new(TypeckError),
span,
});
}
}; };
// do not continue into miri if typeck errors occurred let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
// it will fail horribly res.map(|(miri_value, _, miri_ty)| {
if tables.tainted_by_errors { tcx.mk_const(ty::Const {
return Err(ConstEvalErr { span: body.value.span, kind: TypeckError }) val: ConstVal::Value(miri_value),
} ty: miri_ty,
})
trace!("running old const eval"); }).map_err(|mut err| {
let old_result = ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value); if tcx.is_static(def_id).is_some() {
trace!("old const eval produced {:?}", old_result); ecx.report(&mut err, true, None);
if tcx.sess.opts.debugging_opts.miri {
let instance = ty::Instance::new(def_id, substs);
trace!("const eval instance: {:?}, {:?}", instance, key.param_env);
let miri_result = ::interpret::eval_body(tcx, instance, key.param_env);
match (miri_result, old_result) {
(Err(err), Ok(ok)) => {
trace!("miri failed, ctfe returned {:?}", ok);
tcx.sess.span_warn(
tcx.def_span(key.value.0),
"miri failed to eval, while ctfe succeeded",
);
let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
let () = unwrap_miri(&ecx, Err(err));
Ok(ok)
},
(_, Err(err)) => Err(err),
(Ok((miri_val, miri_ty)), Ok(ctfe)) => {
let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
let layout = ecx.layout_of(miri_ty).unwrap();
let miri_place = Place::from_primval_ptr(miri_val, layout.align);
check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val);
Ok(ctfe)
}
} }
} else { let (trace, span) = ecx.generate_stacktrace(None);
old_result let err = ErrKind::Miri(err, trace);
} ConstEvalErr {
} kind: err.into(),
span,
fn check_ctfe_against_miri<'a, 'tcx>(
ecx: &mut EvalContext<'a, 'tcx, CompileTimeEvaluator>,
miri_place: Place,
miri_ty: Ty<'tcx>,
ctfe: ConstVal<'tcx>,
) {
use rustc::middle::const_val::ConstAggregate::*;
use rustc_const_math::ConstFloat;
use rustc::ty::TypeVariants::*;
let miri_val = ValTy {
value: ecx.read_place(miri_place).unwrap(),
ty: miri_ty
};
match miri_ty.sty {
TyInt(int_ty) => {
let prim = get_prim(ecx, miri_val);
let c = ConstInt::new_signed_truncating(prim as i128,
int_ty,
ecx.tcx.sess.target.isize_ty);
let c = ConstVal::Integral(c);
assert_eq!(c, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", c, ctfe);
},
TyUint(uint_ty) => {
let prim = get_prim(ecx, miri_val);
let c = ConstInt::new_unsigned_truncating(prim,
uint_ty,
ecx.tcx.sess.target.usize_ty);
let c = ConstVal::Integral(c);
assert_eq!(c, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", c, ctfe);
},
TyFloat(ty) => {
let prim = get_prim(ecx, miri_val);
let f = ConstVal::Float(ConstFloat { bits: prim, ty });
assert_eq!(f, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", f, ctfe);
},
TyBool => {
let bits = get_prim(ecx, miri_val);
if bits > 1 {
bug!("miri evaluated to {}, but expected a bool {:?}", bits, ctfe);
}
let b = ConstVal::Bool(bits == 1);
assert_eq!(b, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", b, ctfe);
},
TyChar => {
let bits = get_prim(ecx, miri_val);
if let Some(cm) = ::std::char::from_u32(bits as u32) {
assert_eq!(
ConstVal::Char(cm), ctfe,
"miri evaluated to {:?}, but expected {:?}", cm, ctfe,
);
} else {
bug!("miri evaluated to {}, but expected a char {:?}", bits, ctfe);
}
},
TyStr => {
let value = ecx.follow_by_ref_value(miri_val.value, miri_val.ty);
if let Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) = value {
let bytes = ecx
.memory
.read_bytes(ptr.into(), len as u64)
.expect("bad miri memory for str");
if let Ok(s) = ::std::str::from_utf8(bytes) {
if let ConstVal::Str(s2) = ctfe {
assert_eq!(s, s2, "miri produced {:?}, but expected {:?}", s, s2);
} else {
bug!("miri produced {:?}, but expected {:?}", s, ctfe);
}
} else {
bug!(
"miri failed to produce valid utf8 {:?}, while ctfe produced {:?}",
bytes,
ctfe,
);
}
} else {
bug!("miri evaluated to {:?}, but expected a str {:?}", value, ctfe);
}
},
TyArray(elem_ty, n) => {
let n = n.val.to_const_int().unwrap().to_u64().unwrap();
let vec: Vec<(ConstVal, Ty<'tcx>)> = match ctfe {
ConstVal::ByteStr(arr) => arr.data.iter().map(|&b| {
(ConstVal::Integral(ConstInt::U8(b)), ecx.tcx.types.u8)
}).collect(),
ConstVal::Aggregate(Array(v)) => {
v.iter().map(|c| (c.val, c.ty)).collect()
},
ConstVal::Aggregate(Repeat(v, n)) => {
vec![(v.val, v.ty); n as usize]
},
_ => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe),
};
let layout = ecx.layout_of(miri_ty).unwrap();
for (i, elem) in vec.into_iter().enumerate() {
assert!((i as u64) < n);
let (field_place, _) =
ecx.place_field(miri_place, Field::new(i), layout).unwrap();
check_ctfe_against_miri(ecx, field_place, elem_ty, elem.0);
}
},
TyTuple(..) => {
let vec = match ctfe {
ConstVal::Aggregate(Tuple(v)) => v,
_ => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe),
};
let layout = ecx.layout_of(miri_ty).unwrap();
for (i, elem) in vec.into_iter().enumerate() {
let (field_place, _) =
ecx.place_field(miri_place, Field::new(i), layout).unwrap();
check_ctfe_against_miri(ecx, field_place, elem.ty, elem.val);
}
},
TyAdt(def, _) => {
let mut miri_place = miri_place;
let struct_variant = if def.is_enum() {
let discr = ecx.read_discriminant_value(miri_place, miri_ty).unwrap();
let variant = def.discriminants(ecx.tcx).position(|variant_discr| {
variant_discr.to_u128_unchecked() == discr
}).expect("miri produced invalid enum discriminant");
miri_place = ecx.place_downcast(miri_place, variant).unwrap();
&def.variants[variant]
} else {
def.non_enum_variant()
};
let vec = match ctfe {
ConstVal::Aggregate(Struct(v)) => v,
ConstVal::Variant(did) => {
assert_eq!(struct_variant.fields.len(), 0);
assert_eq!(did, struct_variant.did);
return;
},
ctfe => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe),
};
let layout = ecx.layout_of(miri_ty).unwrap();
for &(name, elem) in vec.into_iter() {
let field = struct_variant.fields.iter().position(|f| f.name == name).unwrap();
let (field_place, _) =
ecx.place_field(miri_place, Field::new(field), layout).unwrap();
check_ctfe_against_miri(ecx, field_place, elem.ty, elem.val);
}
},
TySlice(_) => bug!("miri produced a slice?"),
// not supported by ctfe
TyRawPtr(_) |
TyRef(..) => {}
TyDynamic(..) => bug!("miri produced a trait object"),
TyClosure(..) => bug!("miri produced a closure"),
TyGenerator(..) => bug!("miri produced a generator"),
TyGeneratorWitness(..) => bug!("miri produced a generator witness"),
TyNever => bug!("miri produced a value of the never type"),
TyProjection(_) => bug!("miri produced a projection"),
TyAnon(..) => bug!("miri produced an impl Trait type"),
TyParam(_) => bug!("miri produced an unmonomorphized type"),
TyInfer(_) => bug!("miri produced an uninferred type"),
TyError => bug!("miri produced a type error"),
TyForeign(_) => bug!("miri produced an extern type"),
// should be fine
TyFnDef(..) => {}
TyFnPtr(_) => {
let value = ecx.value_to_primval(miri_val);
let ptr = match value {
Ok(PrimVal::Ptr(ptr)) => ptr,
value => bug!("expected fn ptr, got {:?}", value),
};
let inst = ecx.memory.get_fn(ptr).unwrap();
match ctfe {
ConstVal::Function(did, substs) => {
let ctfe = ty::Instance::resolve(
ecx.tcx,
ecx.param_env,
did,
substs,
).unwrap();
assert_eq!(inst, ctfe, "expected fn ptr {:?}, but got {:?}", ctfe, inst);
},
_ => bug!("ctfe produced {:?}, but miri produced function {:?}", ctfe, inst),
}
},
}
}
fn get_prim<'a, 'tcx>(
ecx: &mut EvalContext<'a, 'tcx, CompileTimeEvaluator>,
val: ValTy<'tcx>,
) -> u128 {
let res = ecx.value_to_primval(val).and_then(|prim| prim.to_bytes());
unwrap_miri(ecx, res)
}
fn unwrap_miri<'a, 'tcx, T>(
ecx: &EvalContext<'a, 'tcx, CompileTimeEvaluator>,
res: Result<T, EvalError<'tcx>>,
) -> T {
match res {
Ok(val) => val,
Err(mut err) => {
ecx.report(&mut err);
ecx.tcx.sess.abort_if_errors();
bug!("{:#?}", err);
} }
} })
} }

View file

@ -3,14 +3,15 @@ use std::fmt::Write;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::hir::map::definitions::DefPathData; use rustc::hir::map::definitions::DefPathData;
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::{ConstVal, ErrKind};
use rustc::mir; use rustc::mir;
use rustc::traits::Reveal;
use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout}; use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout};
use rustc::ty::subst::{Subst, Substs}; use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::maps::TyCtxtAt;
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
use syntax::codemap::{self, DUMMY_SP}; use rustc::middle::const_val::FrameInfo;
use syntax::codemap::{self, Span};
use syntax::ast::Mutability; use syntax::ast::Mutability;
use rustc::mir::interpret::{ use rustc::mir::interpret::{
GlobalId, Value, Pointer, PrimVal, PrimValKind, GlobalId, Value, Pointer, PrimVal, PrimValKind,
@ -18,41 +19,41 @@ use rustc::mir::interpret::{
}; };
use super::{Place, PlaceExtra, Memory, use super::{Place, PlaceExtra, Memory,
HasMemory, MemoryKind, operator, HasMemory, MemoryKind,
Machine}; Machine};
pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> { pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
/// Stores the `Machine` instance. /// Stores the `Machine` instance.
pub machine: M, pub machine: M,
/// The results of the type checker, from rustc. /// The results of the type checker, from rustc.
pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
/// Bounds in scope for polymorphic evaluations. /// Bounds in scope for polymorphic evaluations.
pub param_env: ty::ParamEnv<'tcx>, pub param_env: ty::ParamEnv<'tcx>,
/// The virtual memory system. /// The virtual memory system.
pub memory: Memory<'a, 'tcx, M>, pub memory: Memory<'a, 'mir, 'tcx, M>,
/// The virtual call stack. /// The virtual call stack.
pub(crate) stack: Vec<Frame<'tcx>>, pub(crate) stack: Vec<Frame<'mir, 'tcx>>,
/// The maximum number of stack frames allowed /// The maximum number of stack frames allowed
pub(crate) stack_limit: usize, pub(crate) stack_limit: usize,
/// The maximum number of operations that may be executed. /// The maximum number of terminators that may be evaluated.
/// This prevents infinite loops and huge computations from freezing up const eval. /// This prevents infinite loops and huge computations from freezing up const eval.
/// Remove once halting problem is solved. /// Remove once halting problem is solved.
pub(crate) steps_remaining: u64, pub(crate) steps_remaining: usize,
} }
/// A stack frame. /// A stack frame.
pub struct Frame<'tcx> { pub struct Frame<'mir, 'tcx: 'mir> {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Function and callsite information // Function and callsite information
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// The MIR for the function called on this frame. /// The MIR for the function called on this frame.
pub mir: &'tcx mir::Mir<'tcx>, pub mir: &'mir mir::Mir<'tcx>,
/// The def_id and substs of the current function /// The def_id and substs of the current function
pub instance: ty::Instance<'tcx>, pub instance: ty::Instance<'tcx>,
@ -102,23 +103,6 @@ pub enum StackPopCleanup {
None, None,
} }
#[derive(Copy, Clone, Debug)]
pub struct ResourceLimits {
pub memory_size: u64,
pub step_limit: u64,
pub stack_limit: usize,
}
impl Default for ResourceLimits {
fn default() -> Self {
ResourceLimits {
memory_size: 100 * 1024 * 1024, // 100 MB
step_limit: 1_000_000,
stack_limit: 100,
}
}
}
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct TyAndPacked<'tcx> { pub struct TyAndPacked<'tcx> {
pub ty: Ty<'tcx>, pub ty: Ty<'tcx>,
@ -131,6 +115,15 @@ pub struct ValTy<'tcx> {
pub ty: Ty<'tcx>, pub ty: Ty<'tcx>,
} }
impl<'tcx> ValTy<'tcx> {
pub fn from(val: &ty::Const<'tcx>) -> Option<Self> {
match val.val {
ConstVal::Value(value) => Some(ValTy { value, ty: val.ty }),
ConstVal::Unevaluated { .. } => None,
}
}
}
impl<'tcx> ::std::ops::Deref for ValTy<'tcx> { impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
type Target = Value; type Target = Value;
fn deref(&self) -> &Value { fn deref(&self) -> &Value {
@ -138,37 +131,37 @@ impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
} }
} }
impl<'a, 'tcx, M: Machine<'tcx>> HasDataLayout for &'a EvalContext<'a, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a EvalContext<'a, 'mir, 'tcx, M> {
#[inline] #[inline]
fn data_layout(&self) -> &layout::TargetDataLayout { fn data_layout(&self) -> &layout::TargetDataLayout {
&self.tcx.data_layout &self.tcx.data_layout
} }
} }
impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> HasDataLayout impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout
for &'c &'b mut EvalContext<'a, 'tcx, M> { for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
#[inline] #[inline]
fn data_layout(&self) -> &layout::TargetDataLayout { fn data_layout(&self) -> &layout::TargetDataLayout {
&self.tcx.data_layout &self.tcx.data_layout
} }
} }
impl<'a, 'tcx, M: Machine<'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'mir, 'tcx, M> {
#[inline] #[inline]
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.tcx *self.tcx
} }
} }
impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> layout::HasTyCtxt<'tcx> impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx>
for &'c &'b mut EvalContext<'a, 'tcx, M> { for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
#[inline] #[inline]
fn tcx<'d>(&'d self) -> TyCtxt<'d, 'tcx, 'tcx> { fn tcx<'d>(&'d self) -> TyCtxt<'d, 'tcx, 'tcx> {
self.tcx *self.tcx
} }
} }
impl<'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalContext<'a, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalContext<'a, 'mir, 'tcx, M> {
type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>; type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
@ -177,8 +170,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalContext<'a, 'tcx
} }
} }
impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>> impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf<Ty<'tcx>>
for &'c &'b mut EvalContext<'a, 'tcx, M> { for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>; type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
#[inline] #[inline]
@ -187,11 +180,10 @@ impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>>
} }
} }
impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
pub fn new( pub fn new(
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
limits: ResourceLimits,
machine: M, machine: M,
memory_data: M::MemoryData, memory_data: M::MemoryData,
) -> Self { ) -> Self {
@ -199,10 +191,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
machine, machine,
tcx, tcx,
param_env, param_env,
memory: Memory::new(tcx, limits.memory_size, memory_data), memory: Memory::new(tcx, memory_data),
stack: Vec::new(), stack: Vec::new(),
stack_limit: limits.stack_limit, stack_limit: tcx.sess.const_eval_stack_frame_limit.get(),
steps_remaining: limits.step_limit, steps_remaining: tcx.sess.const_eval_step_limit.get(),
} }
} }
@ -214,15 +206,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
self.memory.allocate(size, layout.align, Some(MemoryKind::Stack)) self.memory.allocate(size, layout.align, Some(MemoryKind::Stack))
} }
pub fn memory(&self) -> &Memory<'a, 'tcx, M> { pub fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
&self.memory &self.memory
} }
pub fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> { pub fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
&mut self.memory &mut self.memory
} }
pub fn stack(&self) -> &[Frame<'tcx>] { pub fn stack(&self) -> &[Frame<'mir, 'tcx>] {
&self.stack &self.stack
} }
@ -240,45 +232,26 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
)) ))
} }
pub(super) fn const_to_value(&mut self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
use rustc::middle::const_val::ConstVal::*; match *const_val {
ConstVal::Unevaluated(def_id, substs) => {
let primval = match *const_val {
Integral(const_int) => PrimVal::Bytes(const_int.to_u128_unchecked()),
Float(val) => PrimVal::Bytes(val.bits),
Bool(b) => PrimVal::from_bool(b),
Char(c) => PrimVal::from_char(c),
Str(ref s) => return self.str_to_value(s),
ByteStr(ref bs) => {
let ptr = self.memory.allocate_cached(bs.data);
PrimVal::Ptr(ptr)
}
Unevaluated(def_id, substs) => {
let instance = self.resolve(def_id, substs)?; let instance = self.resolve(def_id, substs)?;
return Ok(self.read_global_as_value(GlobalId { self.read_global_as_value(GlobalId {
instance, instance,
promoted: None, promoted: None,
}, self.layout_of(ty)?)); }, ty)
} }
ConstVal::Value(val) => Ok(val),
Aggregate(..) | }
Variant(_) => bug!("should not have aggregate or variant constants in MIR"),
// function items are zero sized and thus have no readable value
Function(..) => PrimVal::Undef,
};
Ok(Value::ByVal(primval))
} }
pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, ty::Instance<'tcx>> { pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, ty::Instance<'tcx>> {
let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs); trace!("resolve: {:?}, {:#?}", def_id, substs);
trace!("substs: {:#?}", self.substs());
trace!("param_env: {:#?}", self.param_env);
let substs = self.tcx.trans_apply_param_substs_env(self.substs(), self.param_env, &substs);
ty::Instance::resolve( ty::Instance::resolve(
self.tcx, *self.tcx,
self.param_env, self.param_env,
def_id, def_id,
substs, substs,
@ -286,7 +259,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
} }
pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) ty.is_sized(self.tcx, self.param_env)
} }
pub fn load_mir( pub fn load_mir(
@ -313,7 +286,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
// miri doesn't care about lifetimes, and will choke on some crazy ones // miri doesn't care about lifetimes, and will choke on some crazy ones
// let's simply get rid of them // let's simply get rid of them
let without_lifetimes = self.tcx.erase_regions(&ty); let without_lifetimes = self.tcx.erase_regions(&ty);
let substituted = without_lifetimes.subst(self.tcx, substs); let substituted = without_lifetimes.subst(*self.tcx, substs);
let substituted = self.tcx.fully_normalize_monormophic_ty(&substituted); let substituted = self.tcx.fully_normalize_monormophic_ty(&substituted);
substituted substituted
} }
@ -402,14 +375,14 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
&mut self, &mut self,
instance: ty::Instance<'tcx>, instance: ty::Instance<'tcx>,
span: codemap::Span, span: codemap::Span,
mir: &'tcx mir::Mir<'tcx>, mir: &'mir mir::Mir<'tcx>,
return_place: Place, return_place: Place,
return_to_block: StackPopCleanup, return_to_block: StackPopCleanup,
) -> EvalResult<'tcx> { ) -> EvalResult<'tcx> {
::log_settings::settings().indentation += 1; ::log_settings::settings().indentation += 1;
/// Return the set of locals that have a storage annotation anywhere /// Return the set of locals that have a storage annotation anywhere
fn collect_storage_annotations<'tcx>(mir: &'tcx mir::Mir<'tcx>) -> HashSet<mir::Local> { fn collect_storage_annotations<'mir, 'tcx>(mir: &'mir mir::Mir<'tcx>) -> HashSet<mir::Local> {
use rustc::mir::StatementKind::*; use rustc::mir::StatementKind::*;
let mut set = HashSet::new(); let mut set = HashSet::new();
@ -477,7 +450,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
StackPopCleanup::MarkStatic(mutable) => { StackPopCleanup::MarkStatic(mutable) => {
if let Place::Ptr { ptr, .. } = frame.return_place { if let Place::Ptr { ptr, .. } = frame.return_place {
// FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
self.memory.mark_static_initalized( self.memory.mark_static_initialized(
ptr.to_ptr()?.alloc_id, ptr.to_ptr()?.alloc_id,
mutable, mutable,
)? )?
@ -563,16 +536,16 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
UnaryOp(un_op, ref operand) => { UnaryOp(un_op, ref operand) => {
let val = self.eval_operand_to_primval(operand)?; let val = self.eval_operand_to_primval(operand)?;
let kind = self.ty_to_primval_kind(dest_ty)?; let val = self.unary_op(un_op, val, dest_ty)?;
self.write_primval( self.write_primval(
dest, dest,
operator::unary_op(un_op, val, kind)?, val,
dest_ty, dest_ty,
)?; )?;
} }
Aggregate(ref kind, ref operands) => { Aggregate(ref kind, ref operands) => {
self.inc_step_counter_and_check_limit(operands.len() as u64)?; self.inc_step_counter_and_check_limit(operands.len())?;
let (dest, active_field_index) = match **kind { let (dest, active_field_index) = match **kind {
mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => { mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
@ -600,7 +573,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
Repeat(ref operand, _) => { Repeat(ref operand, _) => {
let (elem_ty, length) = match dest_ty.sty { let (elem_ty, length) = match dest_ty.sty {
ty::TyArray(elem_ty, n) => (elem_ty, n.val.to_const_int().unwrap().to_u64().unwrap()), ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()),
_ => { _ => {
bug!( bug!(
"tried to assign array-repeat to non-array type {:?}", "tried to assign array-repeat to non-array type {:?}",
@ -720,8 +693,13 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
bug!("reifying a fn ptr that requires \ bug!("reifying a fn ptr that requires \
const arguments"); const arguments");
} }
let instance = self.resolve(def_id, substs)?; let instance: EvalResult<'tcx, _> = ty::Instance::resolve(
let fn_ptr = self.memory.create_fn_alloc(instance); *self.tcx,
self.param_env,
def_id,
substs,
).ok_or(EvalErrorKind::TypeckError.into());
let fn_ptr = self.memory.create_fn_alloc(instance?);
let valty = ValTy { let valty = ValTy {
value: Value::ByVal(PrimVal::Ptr(fn_ptr)), value: Value::ByVal(PrimVal::Ptr(fn_ptr)),
ty: dest_ty, ty: dest_ty,
@ -748,7 +726,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
ty::TyClosure(def_id, substs) => { ty::TyClosure(def_id, substs) => {
let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs); let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs);
let instance = ty::Instance::resolve_closure( let instance = ty::Instance::resolve_closure(
self.tcx, *self.tcx,
def_id, def_id,
substs, substs,
ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce,
@ -771,9 +749,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
let place = self.eval_place(place)?; let place = self.eval_place(place)?;
let discr_val = self.read_discriminant_value(place, ty)?; let discr_val = self.read_discriminant_value(place, ty)?;
if let ty::TyAdt(adt_def, _) = ty.sty { if let ty::TyAdt(adt_def, _) = ty.sty {
trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(self.tcx).collect::<Vec<_>>()); trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(*self.tcx).collect::<Vec<_>>());
if adt_def.discriminants(self.tcx).all(|v| { if adt_def.discriminants(*self.tcx).all(|v| {
discr_val != v.to_u128_unchecked() discr_val != v.val
}) })
{ {
return err!(InvalidDiscriminant); return err!(InvalidDiscriminant);
@ -820,7 +798,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> { pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> {
use rustc::mir::Operand::*; use rustc::mir::Operand::*;
let ty = self.monomorphize(op.ty(self.mir(), self.tcx), self.substs()); let ty = self.monomorphize(op.ty(self.mir(), *self.tcx), self.substs());
match *op { match *op {
// FIXME: do some more logic on `move` to invalidate the old location // FIXME: do some more logic on `move` to invalidate the old location
Copy(ref place) | Copy(ref place) |
@ -841,7 +819,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
self.read_global_as_value(GlobalId { self.read_global_as_value(GlobalId {
instance: self.frame().instance, instance: self.frame().instance,
promoted: Some(index), promoted: Some(index),
}, self.layout_of(ty)?) }, ty)?
} }
}; };
@ -928,8 +906,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
} }
layout::Variants::Tagged { .. } => { layout::Variants::Tagged { .. } => {
let discr_val = dest_ty.ty_adt_def().unwrap() let discr_val = dest_ty.ty_adt_def().unwrap()
.discriminant_for_variant(self.tcx, variant_index) .discriminant_for_variant(*self.tcx, variant_index)
.to_u128_unchecked(); .val;
let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?; let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?;
self.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?; self.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?;
@ -953,9 +931,38 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
Ok(()) Ok(())
} }
pub fn read_global_as_value(&self, gid: GlobalId, layout: TyLayout) -> Value { pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
let alloc = self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached"); if gid.promoted.is_none() {
Value::ByRef(MemoryPointer::new(alloc, 0).into(), layout.align) let cached = self
.tcx
.interpret_interner
.get_cached(gid.instance.def_id());
if let Some(alloc_id) = cached {
let layout = self.layout_of(ty)?;
let ptr = MemoryPointer::new(alloc_id, 0);
return Ok(Value::ByRef(ptr.into(), layout.align))
}
}
let cv = self.const_eval(gid)?;
self.const_to_value(&cv.val, ty)
}
pub fn const_eval(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
let param_env = if self.tcx.is_static(gid.instance.def_id()).is_some() {
use rustc::traits;
ty::ParamEnv::empty(traits::Reveal::All)
} else {
self.param_env
};
self.tcx.const_eval(param_env.and(gid)).map_err(|err| match *err.kind {
ErrKind::Miri(ref err, _) => match err.kind {
EvalErrorKind::TypeckError |
EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(),
_ => EvalErrorKind::ReferencedConstant.into(),
},
ErrKind::TypeckError => EvalErrorKind::TypeckError.into(),
ref other => bug!("const eval returned {:?}", other),
})
} }
pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> { pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> {
@ -1121,20 +1128,22 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
dest_align: Align, dest_align: Align,
dest_ty: Ty<'tcx>, dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx> { ) -> EvalResult<'tcx> {
trace!("write_value_to_ptr: {:#?}", value);
let layout = self.layout_of(dest_ty)?; let layout = self.layout_of(dest_ty)?;
trace!("write_value_to_ptr: {:#?}, {}, {:#?}", value, dest_ty, layout);
match value { match value {
Value::ByRef(ptr, align) => { Value::ByRef(ptr, align) => {
self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size.bytes(), false) self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size.bytes(), false)
} }
Value::ByVal(primval) => { Value::ByVal(primval) => {
match layout.abi { let signed = match layout.abi {
layout::Abi::Scalar(_) => {} layout::Abi::Scalar(ref scal) => match scal.value {
_ if primval.is_undef() => {} layout::Primitive::Int(_, signed) => signed,
_ => false,
},
_ if primval.is_undef() => false,
_ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout) _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
} };
// TODO: Do we need signedness? self.memory.write_primval(dest.to_ptr()?, dest_align, primval, layout.size.bytes(), signed)
self.memory.write_primval(dest.to_ptr()?, dest_align, primval, layout.size.bytes(), false)
} }
Value::ByValPair(a_val, b_val) => { Value::ByValPair(a_val, b_val) => {
let ptr = dest.to_ptr()?; let ptr = dest.to_ptr()?;
@ -1247,7 +1256,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
pointee_ty: Ty<'tcx>, pointee_ty: Ty<'tcx>,
) -> EvalResult<'tcx, Value> { ) -> EvalResult<'tcx, Value> {
let ptr_size = self.memory.pointer_size(); let ptr_size = self.memory.pointer_size();
let p: Pointer = self.memory.read_ptr_sized_unsigned(ptr, ptr_align)?.into(); let p: Pointer = self.memory.read_ptr_sized(ptr, ptr_align)?.into();
if self.type_is_sized(pointee_ty) { if self.type_is_sized(pointee_ty) {
Ok(p.to_value()) Ok(p.to_value())
} else { } else {
@ -1255,11 +1264,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
let extra = ptr.offset(ptr_size, self)?; let extra = ptr.offset(ptr_size, self)?;
match self.tcx.struct_tail(pointee_ty).sty { match self.tcx.struct_tail(pointee_ty).sty {
ty::TyDynamic(..) => Ok(p.to_value_with_vtable( ty::TyDynamic(..) => Ok(p.to_value_with_vtable(
self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_ptr()?, self.memory.read_ptr_sized(extra, ptr_align)?.to_ptr()?,
)), )),
ty::TySlice(..) | ty::TyStr => Ok( ty::TySlice(..) | ty::TyStr => {
p.to_value_with_len(self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_bytes()? as u64), let len = self
), .memory
.read_ptr_sized(extra, ptr_align)?
.to_bytes()?;
Ok(p.to_value_with_len(len as u64))
},
_ => bug!("unsized primval ptr read from {:?}", pointee_ty), _ => bug!("unsized primval ptr read from {:?}", pointee_ty),
} }
} }
@ -1271,7 +1284,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
let ptr = ptr.to_ptr()?; let ptr = ptr.to_ptr()?;
let val = match ty.sty { let val = match ty.sty {
ty::TyBool => { ty::TyBool => {
let val = self.memory.read_primval(ptr, ptr_align, 1, false)?; let val = self.memory.read_primval(ptr, ptr_align, 1)?;
let val = match val { let val = match val {
PrimVal::Bytes(0) => false, PrimVal::Bytes(0) => false,
PrimVal::Bytes(1) => true, PrimVal::Bytes(1) => true,
@ -1281,7 +1294,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
PrimVal::from_bool(val) PrimVal::from_bool(val)
} }
ty::TyChar => { ty::TyChar => {
let c = self.memory.read_primval(ptr, ptr_align, 4, false)?.to_bytes()? as u32; let c = self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()? as u32;
match ::std::char::from_u32(c) { match ::std::char::from_u32(c) {
Some(ch) => PrimVal::from_char(ch), Some(ch) => PrimVal::from_char(ch),
None => return err!(InvalidChar(c as u128)), None => return err!(InvalidChar(c as u128)),
@ -1298,7 +1311,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
I128 => 16, I128 => 16,
Isize => self.memory.pointer_size(), Isize => self.memory.pointer_size(),
}; };
self.memory.read_primval(ptr, ptr_align, size, true)? self.memory.read_primval(ptr, ptr_align, size)?
} }
ty::TyUint(uint_ty) => { ty::TyUint(uint_ty) => {
@ -1311,17 +1324,17 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
U128 => 16, U128 => 16,
Usize => self.memory.pointer_size(), Usize => self.memory.pointer_size(),
}; };
self.memory.read_primval(ptr, ptr_align, size, false)? self.memory.read_primval(ptr, ptr_align, size)?
} }
ty::TyFloat(FloatTy::F32) => { ty::TyFloat(FloatTy::F32) => {
PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4, false)?.to_bytes()?) PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()?)
} }
ty::TyFloat(FloatTy::F64) => { ty::TyFloat(FloatTy::F64) => {
PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8, false)?.to_bytes()?) PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8)?.to_bytes()?)
} }
ty::TyFnPtr(_) => self.memory.read_ptr_sized_unsigned(ptr, ptr_align)?, ty::TyFnPtr(_) => self.memory.read_ptr_sized(ptr, ptr_align)?,
ty::TyRef(_, ref tam) | ty::TyRef(_, ref tam) |
ty::TyRawPtr(ref tam) => return self.read_ptr(ptr, ptr_align, tam.ty).map(Some), ty::TyRawPtr(ref tam) => return self.read_ptr(ptr, ptr_align, tam.ty).map(Some),
@ -1331,12 +1344,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
} }
if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi { if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi {
let mut signed = false;
if let layout::Int(_, s) = scalar.value {
signed = s;
}
let size = scalar.value.size(self).bytes(); let size = scalar.value.size(self).bytes();
self.memory.read_primval(ptr, ptr_align, size, signed)? self.memory.read_primval(ptr, ptr_align, size)?
} else { } else {
return Ok(None); return Ok(None);
} }
@ -1348,15 +1357,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
Ok(Some(Value::ByVal(val))) Ok(Some(Value::ByVal(val)))
} }
pub fn frame(&self) -> &Frame<'tcx> { pub fn frame(&self) -> &Frame<'mir, 'tcx> {
self.stack.last().expect("no call frames exist") self.stack.last().expect("no call frames exist")
} }
pub fn frame_mut(&mut self) -> &mut Frame<'tcx> { pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> {
self.stack.last_mut().expect("no call frames exist") self.stack.last_mut().expect("no call frames exist")
} }
pub(super) fn mir(&self) -> &'tcx mir::Mir<'tcx> { pub(super) fn mir(&self) -> &'mir mir::Mir<'tcx> {
self.frame().mir self.frame().mir
} }
@ -1385,7 +1394,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
let ptr = self.into_ptr(src)?; let ptr = self.into_ptr(src)?;
// u64 cast is from usize to u64, which is always good // u64 cast is from usize to u64, which is always good
let valty = ValTy { let valty = ValTy {
value: ptr.to_value_with_len(length.val.to_const_int().unwrap().to_u64().unwrap() ), value: ptr.to_value_with_len(length.val.unwrap_u64() ),
ty: dest_ty, ty: dest_ty,
}; };
self.write_value(valty, dest) self.write_value(valty, dest)
@ -1402,7 +1411,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
} }
(_, &ty::TyDynamic(ref data, _)) => { (_, &ty::TyDynamic(ref data, _)) => {
let trait_ref = data.principal().unwrap().with_self_ty( let trait_ref = data.principal().unwrap().with_self_ty(
self.tcx, *self.tcx,
src_pointee_ty, src_pointee_ty,
); );
let trait_ref = self.tcx.erase_regions(&trait_ref); let trait_ref = self.tcx.erase_regions(&trait_ref);
@ -1504,11 +1513,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
write!(msg, ":").unwrap(); write!(msg, ":").unwrap();
match self.stack[frame].get_local(local) { match self.stack[frame].get_local(local) {
Err(EvalError { kind: EvalErrorKind::DeadLocal, .. }) => {
write!(msg, " is dead").unwrap();
}
Err(err) => { Err(err) => {
panic!("Failed to access local: {:?}", err); if let EvalErrorKind::DeadLocal = err.kind {
write!(msg, " is dead").unwrap();
} else {
panic!("Failed to access local: {:?}", err);
}
} }
Ok(Value::ByRef(ptr, align)) => { Ok(Value::ByRef(ptr, align)) => {
match ptr.into_inner_primval() { match ptr.into_inner_primval() {
@ -1566,7 +1576,40 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
Ok(()) Ok(())
} }
pub fn report(&self, e: &mut EvalError) { pub fn generate_stacktrace(&self, explicit_span: Option<Span>) -> (Vec<FrameInfo>, Span) {
let mut last_span = None;
let mut frames = Vec::new();
// skip 1 because the last frame is just the environment of the constant
for &Frame { instance, span, .. } in self.stack().iter().skip(1).rev() {
// make sure we don't emit frames that are duplicates of the previous
if explicit_span == Some(span) {
last_span = Some(span);
continue;
}
if let Some(last) = last_span {
if last == span {
continue;
}
} else {
last_span = Some(span);
}
let location = if self.tcx.def_key(instance.def_id()).disambiguated_data.data == DefPathData::ClosureExpr {
"closure".to_owned()
} else {
instance.to_string()
};
frames.push(FrameInfo { span, location });
}
trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span);
(frames, self.tcx.span)
}
pub fn report(&self, e: &mut EvalError, as_err: bool, explicit_span: Option<Span>) {
match e.kind {
EvalErrorKind::Layout(_) |
EvalErrorKind::TypeckError => return,
_ => {},
}
if let Some(ref mut backtrace) = e.backtrace { if let Some(ref mut backtrace) = e.backtrace {
let mut trace_text = "\n\nAn error occurred in miri:\n".to_string(); let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
backtrace.resolve(); backtrace.resolve();
@ -1599,29 +1642,60 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
} }
if let Some(frame) = self.stack().last() { if let Some(frame) = self.stack().last() {
let block = &frame.mir.basic_blocks()[frame.block]; let block = &frame.mir.basic_blocks()[frame.block];
let span = if frame.stmt < block.statements.len() { let span = explicit_span.unwrap_or_else(|| if frame.stmt < block.statements.len() {
block.statements[frame.stmt].source_info.span block.statements[frame.stmt].source_info.span
} else { } else {
block.terminator().source_info.span block.terminator().source_info.span
});
trace!("reporting const eval failure at {:?}", span);
let mut err = if as_err {
::rustc::middle::const_val::struct_error(*self.tcx, span, "constant evaluation error")
} else {
let node_id = self
.stack()
.iter()
.rev()
.filter_map(|frame| self.tcx.hir.as_local_node_id(frame.instance.def_id()))
.next()
.expect("some part of a failing const eval must be local");
self.tcx.struct_span_lint_node(
::rustc::lint::builtin::CONST_ERR,
node_id,
span,
"constant evaluation error",
)
}; };
let mut err = self.tcx.sess.struct_span_err(span, &e.to_string()); let (frames, span) = self.generate_stacktrace(explicit_span);
for &Frame { instance, span, .. } in self.stack().iter().rev() { err.span_label(span, e.to_string());
if self.tcx.def_key(instance.def_id()).disambiguated_data.data == for FrameInfo { span, location } in frames {
DefPathData::ClosureExpr err.span_note(span, &format!("inside call to `{}`", location));
{
err.span_note(span, "inside call to closure");
continue;
}
err.span_note(span, &format!("inside call to {}", instance));
} }
err.emit(); err.emit();
} else { } else {
self.tcx.sess.err(&e.to_string()); self.tcx.sess.err(&e.to_string());
} }
} }
pub fn sign_extend(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
let layout = self.layout_of(ty)?;
let size = layout.size.bits();
assert!(layout.abi.is_signed());
// sign extend
let amt = 128 - size;
// shift the unsigned value to the left
// and back to the right as signed (essentially fills with FF on the left)
Ok((((value << amt) as i128) >> amt) as u128)
}
pub fn truncate(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
let size = self.layout_of(ty)?.size.bits();
let amt = 128 - size;
// truncate (shift left to drop out leftover values, shift right to fill with zeroes)
Ok((value << amt) >> amt)
}
} }
impl<'tcx> Frame<'tcx> { impl<'mir, 'tcx> Frame<'mir, 'tcx> {
pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> { pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> {
// Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0. // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
self.locals[local.index() - 1].ok_or(EvalErrorKind::DeadLocal.into()) self.locals[local.index() - 1].ok_or(EvalErrorKind::DeadLocal.into())
@ -1655,14 +1729,3 @@ impl<'tcx> Frame<'tcx> {
return Ok(old); return Ok(old);
} }
} }
// TODO(solson): Upstream these methods into rustc::ty::layout.
pub fn resolve_drop_in_place<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'tcx>,
) -> ty::Instance<'tcx> {
let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem);
let substs = tcx.intern_substs(&[ty.into()]);
ty::Instance::resolve(tcx, ty::ParamEnv::empty(Reveal::All), def_id, substs).unwrap()
}

View file

@ -2,7 +2,7 @@
//! This separation exists to ensure that no fancy miri features like //! This separation exists to ensure that no fancy miri features like
//! interpreting common C functions leak into CTFE. //! interpreting common C functions leak into CTFE.
use rustc::mir::interpret::{AllocId, EvalResult, PrimVal, MemoryPointer, AccessKind}; use rustc::mir::interpret::{AllocId, EvalResult, PrimVal, MemoryPointer, AccessKind, GlobalId};
use super::{EvalContext, Place, ValTy, Memory}; use super::{EvalContext, Place, ValTy, Memory};
use rustc::mir; use rustc::mir;
@ -12,7 +12,7 @@ use syntax::ast::Mutability;
/// Methods of this trait signifies a point where CTFE evaluation would fail /// Methods of this trait signifies a point where CTFE evaluation would fail
/// and some use case dependent behaviour can instead be applied /// and some use case dependent behaviour can instead be applied
pub trait Machine<'tcx>: Sized { pub trait Machine<'mir, 'tcx>: Sized {
/// Additional data that can be accessed via the Memory /// Additional data that can be accessed via the Memory
type MemoryData; type MemoryData;
@ -26,7 +26,7 @@ pub trait Machine<'tcx>: Sized {
/// ///
/// Returns Ok(false) if a new stack frame was pushed /// Returns Ok(false) if a new stack frame was pushed
fn eval_fn_call<'a>( fn eval_fn_call<'a>(
ecx: &mut EvalContext<'a, 'tcx, Self>, ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>, instance: ty::Instance<'tcx>,
destination: Option<(Place, mir::BasicBlock)>, destination: Option<(Place, mir::BasicBlock)>,
args: &[ValTy<'tcx>], args: &[ValTy<'tcx>],
@ -36,7 +36,7 @@ pub trait Machine<'tcx>: Sized {
/// directly process an intrinsic without pushing a stack frame. /// directly process an intrinsic without pushing a stack frame.
fn call_intrinsic<'a>( fn call_intrinsic<'a>(
ecx: &mut EvalContext<'a, 'tcx, Self>, ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>, instance: ty::Instance<'tcx>,
args: &[ValTy<'tcx>], args: &[ValTy<'tcx>],
dest: Place, dest: Place,
@ -51,7 +51,7 @@ pub trait Machine<'tcx>: Sized {
/// ///
/// Returns a (value, overflowed) pair if the operation succeeded /// Returns a (value, overflowed) pair if the operation succeeded
fn try_ptr_op<'a>( fn try_ptr_op<'a>(
ecx: &EvalContext<'a, 'tcx, Self>, ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
bin_op: mir::BinOp, bin_op: mir::BinOp,
left: PrimVal, left: PrimVal,
left_ty: Ty<'tcx>, left_ty: Ty<'tcx>,
@ -60,26 +60,37 @@ pub trait Machine<'tcx>: Sized {
) -> EvalResult<'tcx, Option<(PrimVal, bool)>>; ) -> EvalResult<'tcx, Option<(PrimVal, bool)>>;
/// Called when trying to mark machine defined `MemoryKinds` as static /// Called when trying to mark machine defined `MemoryKinds` as static
fn mark_static_initialized(m: Self::MemoryKinds) -> EvalResult<'tcx>; fn mark_static_initialized<'a>(
_mem: &mut Memory<'a, 'mir, 'tcx, Self>,
_id: AllocId,
_mutability: Mutability,
) -> EvalResult<'tcx, bool>;
/// Called when requiring a pointer to a static. Non const eval can
/// create a mutable memory location for `static mut`
fn init_static<'a>(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
cid: GlobalId<'tcx>,
) -> EvalResult<'tcx, AllocId>;
/// Heap allocations via the `box` keyword /// Heap allocations via the `box` keyword
/// ///
/// Returns a pointer to the allocated memory /// Returns a pointer to the allocated memory
fn box_alloc<'a>( fn box_alloc<'a>(
ecx: &mut EvalContext<'a, 'tcx, Self>, ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
dest: Place, dest: Place,
) -> EvalResult<'tcx>; ) -> EvalResult<'tcx>;
/// Called when trying to access a global declared with a `linkage` attribute /// Called when trying to access a global declared with a `linkage` attribute
fn global_item_with_linkage<'a>( fn global_item_with_linkage<'a>(
ecx: &mut EvalContext<'a, 'tcx, Self>, ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>, instance: ty::Instance<'tcx>,
mutability: Mutability, mutability: Mutability,
) -> EvalResult<'tcx>; ) -> EvalResult<'tcx>;
fn check_locks<'a>( fn check_locks<'a>(
_mem: &Memory<'a, 'tcx, Self>, _mem: &Memory<'a, 'mir, 'tcx, Self>,
_ptr: MemoryPointer, _ptr: MemoryPointer,
_size: u64, _size: u64,
_access: AccessKind, _access: AccessKind,
@ -88,12 +99,12 @@ pub trait Machine<'tcx>: Sized {
} }
fn add_lock<'a>( fn add_lock<'a>(
_mem: &mut Memory<'a, 'tcx, Self>, _mem: &mut Memory<'a, 'mir, 'tcx, Self>,
_id: AllocId, _id: AllocId,
) {} ) {}
fn free_lock<'a>( fn free_lock<'a>(
_mem: &mut Memory<'a, 'tcx, Self>, _mem: &mut Memory<'a, 'mir, 'tcx, Self>,
_id: AllocId, _id: AllocId,
_len: u64, _len: u64,
) -> EvalResult<'tcx> { ) -> EvalResult<'tcx> {
@ -101,14 +112,14 @@ pub trait Machine<'tcx>: Sized {
} }
fn end_region<'a>( fn end_region<'a>(
_ecx: &mut EvalContext<'a, 'tcx, Self>, _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
_reg: Option<::rustc::middle::region::Scope>, _reg: Option<::rustc::middle::region::Scope>,
) -> EvalResult<'tcx> { ) -> EvalResult<'tcx> {
Ok(()) Ok(())
} }
fn validation_op<'a>( fn validation_op<'a>(
_ecx: &mut EvalContext<'a, 'tcx, Self>, _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
_op: ::rustc::mir::ValidationOp, _op: ::rustc::mir::ValidationOp,
_operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, _operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>,
) -> EvalResult<'tcx> { ) -> EvalResult<'tcx> {

View file

@ -1,8 +1,9 @@
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian}; use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian};
use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque}; use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque};
use std::{ptr, mem, io}; use std::{ptr, io};
use rustc::ty::{Instance, TyCtxt}; use rustc::ty::Instance;
use rustc::ty::maps::TyCtxtAt;
use rustc::ty::layout::{self, Align, TargetDataLayout}; use rustc::ty::layout::{self, Align, TargetDataLayout};
use syntax::ast::Mutability; use syntax::ast::Mutability;
@ -19,8 +20,6 @@ use super::{EvalContext, Machine};
pub enum MemoryKind<T> { pub enum MemoryKind<T> {
/// Error if deallocated except during a stack pop /// Error if deallocated except during a stack pop
Stack, Stack,
/// A mutable Static. All the others are interned in the tcx
MutableStatic, // FIXME: move me into the machine, rustc const eval doesn't need them
/// Additional memory kinds a machine wishes to distinguish from the builtin ones /// Additional memory kinds a machine wishes to distinguish from the builtin ones
Machine(T), Machine(T),
} }
@ -29,7 +28,7 @@ pub enum MemoryKind<T> {
// Top-level interpreter memory // Top-level interpreter memory
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
pub struct Memory<'a, 'tcx: 'a, M: Machine<'tcx>> { pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
/// Additional data required by the Machine /// Additional data required by the Machine
pub data: M::MemoryData, pub data: M::MemoryData,
@ -44,28 +43,20 @@ pub struct Memory<'a, 'tcx: 'a, M: Machine<'tcx>> {
/// Stores statics while they are being processed, before they are interned and thus frozen /// Stores statics while they are being processed, before they are interned and thus frozen
uninitialized_statics: HashMap<AllocId, Allocation>, uninitialized_statics: HashMap<AllocId, Allocation>,
/// Number of virtual bytes allocated.
memory_usage: u64,
/// Maximum number of virtual bytes that may be allocated.
memory_size: u64,
/// The current stack frame. Used to check accesses against locks. /// The current stack frame. Used to check accesses against locks.
pub cur_frame: usize, pub cur_frame: usize,
pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
} }
impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, max_memory: u64, data: M::MemoryData) -> Self { pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self {
Memory { Memory {
data, data,
alloc_kind: HashMap::new(), alloc_kind: HashMap::new(),
alloc_map: HashMap::new(), alloc_map: HashMap::new(),
uninitialized_statics: HashMap::new(), uninitialized_statics: HashMap::new(),
tcx, tcx,
memory_size: max_memory,
memory_usage: 0,
cur_frame: usize::max_value(), cur_frame: usize::max_value(),
} }
} }
@ -77,7 +68,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
} }
pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> MemoryPointer { pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> MemoryPointer {
let id = self.tcx.interpret_interner.borrow_mut().create_fn_alloc(instance); let id = self.tcx.interpret_interner.create_fn_alloc(instance);
MemoryPointer::new(id, 0) MemoryPointer::new(id, 0)
} }
@ -93,22 +84,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
align: Align, align: Align,
kind: Option<MemoryKind<M::MemoryKinds>>, kind: Option<MemoryKind<M::MemoryKinds>>,
) -> EvalResult<'tcx, MemoryPointer> { ) -> EvalResult<'tcx, MemoryPointer> {
if self.memory_size - self.memory_usage < size {
return err!(OutOfMemory {
allocation_size: size,
memory_size: self.memory_size,
memory_usage: self.memory_usage,
});
}
self.memory_usage += size;
assert_eq!(size as usize as u64, size); assert_eq!(size as usize as u64, size);
let alloc = Allocation { let alloc = Allocation {
bytes: vec![0; size as usize], bytes: vec![0; size as usize],
relocations: BTreeMap::new(), relocations: BTreeMap::new(),
undef_mask: UndefMask::new(size), undef_mask: UndefMask::new(size),
align, align,
runtime_mutability: Mutability::Immutable,
}; };
let id = self.tcx.interpret_interner.borrow_mut().reserve(); let id = self.tcx.interpret_interner.reserve();
M::add_lock(self, id); M::add_lock(self, id);
match kind { match kind {
Some(kind @ MemoryKind::Stack) | Some(kind @ MemoryKind::Stack) |
@ -119,7 +103,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
None => { None => {
self.uninitialized_statics.insert(id, alloc); self.uninitialized_statics.insert(id, alloc);
}, },
Some(MemoryKind::MutableStatic) => bug!("don't allocate mutable statics directly")
} }
Ok(MemoryPointer::new(id, 0)) Ok(MemoryPointer::new(id, 0))
} }
@ -164,10 +147,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
pub fn deallocate_local(&mut self, ptr: MemoryPointer) -> EvalResult<'tcx> { pub fn deallocate_local(&mut self, ptr: MemoryPointer) -> EvalResult<'tcx> {
match self.alloc_kind.get(&ptr.alloc_id).cloned() { match self.alloc_kind.get(&ptr.alloc_id).cloned() {
// for a constant like `const FOO: &i32 = &1;` the local containing
// the `1` is referred to by the global. We transitively marked everything
// the global refers to as static itself, so we don't free it here
Some(MemoryKind::MutableStatic) => Ok(()),
Some(MemoryKind::Stack) => self.deallocate(ptr, None, MemoryKind::Stack), Some(MemoryKind::Stack) => self.deallocate(ptr, None, MemoryKind::Stack),
// Happens if the memory was interned into immutable memory // Happens if the memory was interned into immutable memory
None => Ok(()), None => Ok(()),
@ -192,12 +171,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
"uninitializedstatic".to_string(), "uninitializedstatic".to_string(),
format!("{:?}", kind), format!("{:?}", kind),
)) ))
} else if self.tcx.interpret_interner.borrow().get_fn(ptr.alloc_id).is_some() { } else if self.tcx.interpret_interner.get_fn(ptr.alloc_id).is_some() {
return err!(DeallocatedWrongMemoryKind( return err!(DeallocatedWrongMemoryKind(
"function".to_string(), "function".to_string(),
format!("{:?}", kind), format!("{:?}", kind),
)) ))
} else if self.tcx.interpret_interner.borrow().get_alloc(ptr.alloc_id).is_some() { } else if self.tcx.interpret_interner.get_alloc(ptr.alloc_id).is_some() {
return err!(DeallocatedWrongMemoryKind( return err!(DeallocatedWrongMemoryKind(
"static".to_string(), "static".to_string(),
format!("{:?}", kind), format!("{:?}", kind),
@ -228,7 +207,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
} }
} }
self.memory_usage -= alloc.bytes.len() as u64;
debug!("deallocated : {}", ptr.alloc_id); debug!("deallocated : {}", ptr.alloc_id);
Ok(()) Ok(())
@ -292,7 +270,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
} }
/// Allocation accessors /// Allocation accessors
impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> { pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
// normal alloc? // normal alloc?
match self.alloc_map.get(&id) { match self.alloc_map.get(&id) {
@ -301,11 +279,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
None => match self.uninitialized_statics.get(&id) { None => match self.uninitialized_statics.get(&id) {
Some(alloc) => Ok(alloc), Some(alloc) => Ok(alloc),
None => { None => {
let int = self.tcx.interpret_interner.borrow();
// static alloc? // static alloc?
int.get_alloc(id) self.tcx.interpret_interner.get_alloc(id)
// no alloc? produce an error // no alloc? produce an error
.ok_or_else(|| if int.get_fn(id).is_some() { .ok_or_else(|| if self.tcx.interpret_interner.get_fn(id).is_some() {
EvalErrorKind::DerefFunctionPointer.into() EvalErrorKind::DerefFunctionPointer.into()
} else { } else {
EvalErrorKind::DanglingPointerDeref.into() EvalErrorKind::DanglingPointerDeref.into()
@ -326,11 +303,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
None => match self.uninitialized_statics.get_mut(&id) { None => match self.uninitialized_statics.get_mut(&id) {
Some(alloc) => Ok(alloc), Some(alloc) => Ok(alloc),
None => { None => {
let int = self.tcx.interpret_interner.borrow();
// no alloc or immutable alloc? produce an error // no alloc or immutable alloc? produce an error
if int.get_alloc(id).is_some() { if self.tcx.interpret_interner.get_alloc(id).is_some() {
err!(ModifiedConstantMemory) err!(ModifiedConstantMemory)
} else if int.get_fn(id).is_some() { } else if self.tcx.interpret_interner.get_fn(id).is_some() {
err!(DerefFunctionPointer) err!(DerefFunctionPointer)
} else { } else {
err!(DanglingPointerDeref) err!(DanglingPointerDeref)
@ -347,7 +323,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
debug!("reading fn ptr: {}", ptr.alloc_id); debug!("reading fn ptr: {}", ptr.alloc_id);
self.tcx self.tcx
.interpret_interner .interpret_interner
.borrow()
.get_fn(ptr.alloc_id) .get_fn(ptr.alloc_id)
.ok_or(EvalErrorKind::ExecuteMemory.into()) .ok_or(EvalErrorKind::ExecuteMemory.into())
} }
@ -376,27 +351,25 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
Some(a) => (a, match self.alloc_kind[&id] { Some(a) => (a, match self.alloc_kind[&id] {
MemoryKind::Stack => " (stack)".to_owned(), MemoryKind::Stack => " (stack)".to_owned(),
MemoryKind::Machine(m) => format!(" ({:?})", m), MemoryKind::Machine(m) => format!(" ({:?})", m),
MemoryKind::MutableStatic => " (static mut)".to_owned(),
}), }),
// uninitialized static alloc? // uninitialized static alloc?
None => match self.uninitialized_statics.get(&id) { None => match self.uninitialized_statics.get(&id) {
Some(a) => (a, " (static in the process of initialization)".to_owned()), Some(a) => (a, " (static in the process of initialization)".to_owned()),
None => { None => {
let int = self.tcx.interpret_interner.borrow();
// static alloc? // static alloc?
match int.get_alloc(id) { match self.tcx.interpret_interner.get_alloc(id) {
Some(a) => (a, "(immutable)".to_owned()), Some(a) => (a, "(immutable)".to_owned()),
None => if let Some(func) = int.get_fn(id) { None => if let Some(func) = self.tcx.interpret_interner.get_fn(id) {
trace!("{} {}", msg, func); trace!("{} {}", msg, func);
continue; continue;
} else { } else {
trace!("{} (deallocated)", msg); trace!("{} (deallocated)", msg);
continue; continue;
}, },
} }
}, },
}, },
}; };
for i in 0..(alloc.bytes.len() as u64) { for i in 0..(alloc.bytes.len() as u64) {
if let Some(&target_id) = alloc.relocations.get(&i) { if let Some(&target_id) = alloc.relocations.get(&i) {
@ -441,14 +414,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
pub fn leak_report(&self) -> usize { pub fn leak_report(&self) -> usize {
trace!("### LEAK REPORT ###"); trace!("### LEAK REPORT ###");
let kinds = &self.alloc_kind;
let leaks: Vec<_> = self.alloc_map let leaks: Vec<_> = self.alloc_map
.keys() .keys()
.filter_map(|key| if kinds[key] != MemoryKind::MutableStatic { .cloned()
Some(*key)
} else {
None
})
.collect(); .collect();
let n = leaks.len(); let n = leaks.len();
self.dump_allocs(leaks); self.dump_allocs(leaks);
@ -457,7 +425,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
} }
/// Byte accessors /// Byte accessors
impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
fn get_bytes_unchecked( fn get_bytes_unchecked(
&self, &self,
ptr: MemoryPointer, ptr: MemoryPointer,
@ -521,7 +489,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
} }
/// Reading and writing /// Reading and writing
impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
/// mark an allocation pointed to by a static as static and initialized /// mark an allocation pointed to by a static as static and initialized
fn mark_inner_allocation_initialized( fn mark_inner_allocation_initialized(
&mut self, &mut self,
@ -529,80 +497,47 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
mutability: Mutability, mutability: Mutability,
) -> EvalResult<'tcx> { ) -> EvalResult<'tcx> {
match self.alloc_kind.get(&alloc) { match self.alloc_kind.get(&alloc) {
// do not go into immutable statics // do not go into statics
None | None => Ok(()),
// or mutable statics
Some(&MemoryKind::MutableStatic) => Ok(()),
// just locals and machine allocs // just locals and machine allocs
Some(_) => self.mark_static_initalized(alloc, mutability), Some(_) => self.mark_static_initialized(alloc, mutability),
} }
} }
/// mark an allocation as static and initialized, either mutable or not /// mark an allocation as static and initialized, either mutable or not
pub fn mark_static_initalized( pub fn mark_static_initialized(
&mut self, &mut self,
alloc_id: AllocId, alloc_id: AllocId,
mutability: Mutability, mutability: Mutability,
) -> EvalResult<'tcx> { ) -> EvalResult<'tcx> {
trace!( trace!(
"mark_static_initalized {:?}, mutability: {:?}", "mark_static_initialized {:?}, mutability: {:?}",
alloc_id, alloc_id,
mutability mutability
); );
if mutability == Mutability::Immutable { // The machine handled it
let alloc = self.alloc_map.remove(&alloc_id); if M::mark_static_initialized(self, alloc_id, mutability)? {
let kind = self.alloc_kind.remove(&alloc_id); return Ok(())
assert_ne!(kind, Some(MemoryKind::MutableStatic)); }
let uninit = self.uninitialized_statics.remove(&alloc_id); let alloc = self.alloc_map.remove(&alloc_id);
if let Some(alloc) = alloc.or(uninit) { match self.alloc_kind.remove(&alloc_id) {
let alloc = self.tcx.intern_const_alloc(alloc); None => {},
self.tcx.interpret_interner.borrow_mut().intern_at_reserved(alloc_id, alloc); Some(MemoryKind::Machine(_)) => bug!("machine didn't handle machine alloc"),
// recurse into inner allocations Some(MemoryKind::Stack) => {},
for &alloc in alloc.relocations.values() { }
self.mark_inner_allocation_initialized(alloc, mutability)?; let uninit = self.uninitialized_statics.remove(&alloc_id);
} if let Some(mut alloc) = alloc.or(uninit) {
// ensure llvm knows not to put this into immutable memroy
alloc.runtime_mutability = mutability;
let alloc = self.tcx.intern_const_alloc(alloc);
self.tcx.interpret_interner.intern_at_reserved(alloc_id, alloc);
// recurse into inner allocations
for &alloc in alloc.relocations.values() {
self.mark_inner_allocation_initialized(alloc, mutability)?;
} }
return Ok(()); } else {
bug!("no allocation found for {:?}", alloc_id);
} }
// We are marking the static as initialized, so move it out of the uninit map
if let Some(uninit) = self.uninitialized_statics.remove(&alloc_id) {
self.alloc_map.insert(alloc_id, uninit);
}
// do not use `self.get_mut(alloc_id)` here, because we might have already marked a
// sub-element or have circular pointers (e.g. `Rc`-cycles)
let relocations = match self.alloc_map.get_mut(&alloc_id) {
Some(&mut Allocation {
ref mut relocations,
..
}) => {
match self.alloc_kind.get(&alloc_id) {
// const eval results can refer to "locals".
// E.g. `const Foo: &u32 = &1;` refers to the temp local that stores the `1`
None |
Some(&MemoryKind::Stack) => {},
Some(&MemoryKind::Machine(m)) => M::mark_static_initialized(m)?,
Some(&MemoryKind::MutableStatic) => {
trace!("mark_static_initalized: skipping already initialized static referred to by static currently being initialized");
return Ok(());
},
}
// overwrite or insert
self.alloc_kind.insert(alloc_id, MemoryKind::MutableStatic);
// take out the relocations vector to free the borrow on self, so we can call
// mark recursively
mem::replace(relocations, Default::default())
}
None => return err!(DanglingPointerDeref),
};
// recurse into inner allocations
for &alloc in relocations.values() {
self.mark_inner_allocation_initialized(alloc, mutability)?;
}
// put back the relocations
self.alloc_map
.get_mut(&alloc_id)
.expect("checked above")
.relocations = relocations;
Ok(()) Ok(())
} }
@ -720,7 +655,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
Ok(()) Ok(())
} }
pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: u64, signed: bool) -> EvalResult<'tcx, PrimVal> { pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: u64) -> EvalResult<'tcx, PrimVal> {
self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer
let endianness = self.endianness(); let endianness = self.endianness();
let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?; let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?;
@ -730,11 +665,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
return Ok(PrimVal::Undef.into()); return Ok(PrimVal::Undef.into());
} }
// Now we do the actual reading // Now we do the actual reading
let bytes = if signed { let bytes = read_target_uint(endianness, bytes).unwrap();
read_target_int(endianness, bytes).unwrap() as u128
} else {
read_target_uint(endianness, bytes).unwrap()
};
// See if we got a pointer // See if we got a pointer
if size != self.pointer_size() { if size != self.pointer_size() {
if self.relocations(ptr, size)?.count() != 0 { if self.relocations(ptr, size)?.count() != 0 {
@ -751,8 +682,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
Ok(PrimVal::Bytes(bytes)) Ok(PrimVal::Bytes(bytes))
} }
pub fn read_ptr_sized_unsigned(&self, ptr: MemoryPointer, ptr_align: Align) -> EvalResult<'tcx, PrimVal> { pub fn read_ptr_sized(&self, ptr: MemoryPointer, ptr_align: Align) -> EvalResult<'tcx, PrimVal> {
self.read_primval(ptr, ptr_align, self.pointer_size(), false) self.read_primval(ptr, ptr_align, self.pointer_size())
} }
pub fn write_primval(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> { pub fn write_primval(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> {
@ -764,19 +695,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
val.offset as u128 val.offset as u128
} }
PrimVal::Bytes(bytes) => { PrimVal::Bytes(bytes) => bytes,
// We need to mask here, or the byteorder crate can die when given a u64 larger
// than fits in an integer of the requested size.
let mask = match size {
1 => !0u8 as u128,
2 => !0u16 as u128,
4 => !0u32 as u128,
8 => !0u64 as u128,
16 => !0,
n => bug!("unexpected PrimVal::Bytes size: {}", n),
};
bytes & mask
}
PrimVal::Undef => { PrimVal::Undef => {
self.mark_definedness(PrimVal::Ptr(ptr).into(), size, false)?; self.mark_definedness(PrimVal::Ptr(ptr).into(), size, false)?;
@ -829,7 +748,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
} }
/// Relocations /// Relocations
impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
fn relocations( fn relocations(
&self, &self,
ptr: MemoryPointer, ptr: MemoryPointer,
@ -883,7 +802,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
} }
/// Undefined bytes /// Undefined bytes
impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
// FIXME(solson): This is a very naive, slow version. // FIXME(solson): This is a very naive, slow version.
fn copy_undef_mask( fn copy_undef_mask(
&mut self, &mut self,
@ -944,7 +863,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
// Methods to access integers in the target endianness // Methods to access integers in the target endianness
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
fn write_target_uint( pub fn write_target_uint(
endianness: layout::Endian, endianness: layout::Endian,
mut target: &mut [u8], mut target: &mut [u8],
data: u128, data: u128,
@ -955,7 +874,8 @@ fn write_target_uint(
layout::Endian::Big => target.write_uint128::<BigEndian>(data, len), layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
} }
} }
fn write_target_int(
pub fn write_target_int(
endianness: layout::Endian, endianness: layout::Endian,
mut target: &mut [u8], mut target: &mut [u8],
data: i128, data: i128,
@ -967,27 +887,20 @@ fn write_target_int(
} }
} }
fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> { pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
match endianness { match endianness {
layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()), layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()), layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
} }
} }
fn read_target_int(endianness: layout::Endian, mut source: &[u8]) -> Result<i128, io::Error> {
match endianness {
layout::Endian::Little => source.read_int128::<LittleEndian>(source.len()),
layout::Endian::Big => source.read_int128::<BigEndian>(source.len()),
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Unaligned accesses // Unaligned accesses
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> { pub trait HasMemory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M>; fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M>;
fn memory(&self) -> &Memory<'a, 'tcx, M>; fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M>;
/// Convert the value into a pointer (or a pointer-sized integer). If the value is a ByRef, /// Convert the value into a pointer (or a pointer-sized integer). If the value is a ByRef,
/// this may have to perform a load. /// this may have to perform a load.
@ -997,7 +910,7 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> {
) -> EvalResult<'tcx, Pointer> { ) -> EvalResult<'tcx, Pointer> {
Ok(match value { Ok(match value {
Value::ByRef(ptr, align) => { Value::ByRef(ptr, align) => {
self.memory().read_ptr_sized_unsigned(ptr.to_ptr()?, align)? self.memory().read_ptr_sized(ptr.to_ptr()?, align)?
} }
Value::ByVal(ptr) | Value::ByVal(ptr) |
Value::ByValPair(ptr, _) => ptr, Value::ByValPair(ptr, _) => ptr,
@ -1011,8 +924,8 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> {
match value { match value {
Value::ByRef(ref_ptr, align) => { Value::ByRef(ref_ptr, align) => {
let mem = self.memory(); let mem = self.memory();
let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?, align)?.into(); let ptr = mem.read_ptr_sized(ref_ptr.to_ptr()?, align)?.into();
let vtable = mem.read_ptr_sized_unsigned( let vtable = mem.read_ptr_sized(
ref_ptr.offset(mem.pointer_size(), &mem.tcx.data_layout)?.to_ptr()?, ref_ptr.offset(mem.pointer_size(), &mem.tcx.data_layout)?.to_ptr()?,
align align
)?.to_ptr()?; )?.to_ptr()?;
@ -1033,8 +946,8 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> {
match value { match value {
Value::ByRef(ref_ptr, align) => { Value::ByRef(ref_ptr, align) => {
let mem = self.memory(); let mem = self.memory();
let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?, align)?.into(); let ptr = mem.read_ptr_sized(ref_ptr.to_ptr()?, align)?.into();
let len = mem.read_ptr_sized_unsigned( let len = mem.read_ptr_sized(
ref_ptr.offset(mem.pointer_size(), &mem.tcx.data_layout)?.to_ptr()?, ref_ptr.offset(mem.pointer_size(), &mem.tcx.data_layout)?.to_ptr()?,
align align
)?.to_bytes()? as u64; )?.to_bytes()? as u64;
@ -1051,31 +964,31 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> {
} }
} }
impl<'a, 'tcx, M: Machine<'tcx>> HasMemory<'a, 'tcx, M> for Memory<'a, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasMemory<'a, 'mir, 'tcx, M> for Memory<'a, 'mir, 'tcx, M> {
#[inline] #[inline]
fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> { fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
self self
} }
#[inline] #[inline]
fn memory(&self) -> &Memory<'a, 'tcx, M> { fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
self self
} }
} }
impl<'a, 'tcx, M: Machine<'tcx>> HasMemory<'a, 'tcx, M> for EvalContext<'a, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasMemory<'a, 'mir, 'tcx, M> for EvalContext<'a, 'mir, 'tcx, M> {
#[inline] #[inline]
fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> { fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
&mut self.memory &mut self.memory
} }
#[inline] #[inline]
fn memory(&self) -> &Memory<'a, 'tcx, M> { fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
&self.memory &self.memory
} }
} }
impl<'a, 'tcx, M: Machine<'tcx>> layout::HasDataLayout for &'a Memory<'a, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasDataLayout for &'a Memory<'a, 'mir, 'tcx, M> {
#[inline] #[inline]
fn data_layout(&self) -> &TargetDataLayout { fn data_layout(&self) -> &TargetDataLayout {
&self.tcx.data_layout &self.tcx.data_layout

View file

@ -11,13 +11,23 @@ mod step;
mod terminator; mod terminator;
mod traits; mod traits;
pub use self::eval_context::{EvalContext, Frame, ResourceLimits, StackPopCleanup, pub use self::eval_context::{EvalContext, Frame, StackPopCleanup,
TyAndPacked, ValTy}; TyAndPacked, ValTy};
pub use self::place::{Place, PlaceExtra}; pub use self::place::{Place, PlaceExtra};
pub use self::memory::{Memory, MemoryKind, HasMemory}; pub use self::memory::{Memory, MemoryKind, HasMemory};
pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider}; pub use self::const_eval::{
eval_body_with_mir,
mk_borrowck_eval_cx,
eval_body,
CompileTimeEvaluator,
const_eval_provider,
const_val_field,
const_discr,
};
pub use self::machine::Machine; pub use self::machine::Machine;
pub use self::memory::{write_target_uint, write_target_int, read_target_uint};

Some files were not shown because too many files have changed in this diff Show more