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:
commit
c90f68224b
251 changed files with 6657 additions and 7185 deletions
21
src/Cargo.lock
generated
21
src/Cargo.lock
generated
|
@ -1858,20 +1858,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "rustc_const_math"
|
||||
version = "0.0.0"
|
||||
|
@ -1914,7 +1900,6 @@ dependencies = [
|
|||
"rustc_allocator 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_borrowck 0.0.0",
|
||||
"rustc_const_eval 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_incremental 0.0.0",
|
||||
|
@ -1964,7 +1949,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc_const_eval 0.0.0",
|
||||
"rustc_mir 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
@ -2012,6 +1997,7 @@ dependencies = [
|
|||
name = "rustc_mir"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arena 0.0.0",
|
||||
"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)",
|
||||
"graphviz 0.0.0",
|
||||
|
@ -2020,7 +2006,6 @@ dependencies = [
|
|||
"rustc 0.0.0",
|
||||
"rustc_apfloat 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_const_eval 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
|
@ -2046,10 +2031,10 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc_const_eval 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_mir 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
|
|
@ -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),
|
||||
[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_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_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),
|
||||
|
|
|
@ -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];
|
||||
```
|
|
@ -427,6 +427,7 @@ impl<T: Ord> Ord for Reverse<T> {
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(not(stage0), lang = "ord")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Ord: Eq + PartialOrd<Self> {
|
||||
/// 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.lt(&y), true);
|
||||
/// ```
|
||||
#[lang = "ord"]
|
||||
#[cfg_attr(stage0, lang = "ord")]
|
||||
#[cfg_attr(not(stage0), lang = "partial_ord")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"]
|
||||
pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
||||
|
|
|
@ -60,15 +60,15 @@
|
|||
//! user of the `DepNode` API of having to know how to compute the expected
|
||||
//! fingerprint for a given set of node parameters.
|
||||
|
||||
use mir::interpret::{GlobalId};
|
||||
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
|
||||
use hir::map::DefPathHash;
|
||||
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::subst::Substs;
|
||||
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
|
||||
use ich::StableHashingContext;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use syntax_pos::symbol::InternedString;
|
||||
|
@ -518,7 +518,7 @@ define_dep_nodes!( <'tcx>
|
|||
[] TypeckTables(DefId),
|
||||
[] UsedTraitImports(DefId),
|
||||
[] HasTypeckTables(DefId),
|
||||
[] ConstEval { param_env: ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)> },
|
||||
[] ConstEval { param_env: ParamEnvAnd<'tcx, GlobalId<'tcx>> },
|
||||
[] CheckMatch(DefId),
|
||||
[] SymbolName(DefId),
|
||||
[] 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
|
||||
where T: HashStable<StableHashingContext<'gcx>> + fmt::Debug
|
||||
where T: HashStable<StableHashingContext<'a>> + fmt::Debug
|
||||
{
|
||||
default const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
|
||||
|
||||
|
|
|
@ -14,19 +14,6 @@
|
|||
// 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! {
|
||||
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##"
|
||||
Trait objects like `Box<Trait>` can only be constructed when certain
|
||||
requirements are satisfied by the trait in question.
|
||||
|
|
|
@ -220,7 +220,6 @@ impl serialize::UseSpecializedDecodable for DefId {}
|
|||
pub struct LocalDefId(DefIndex);
|
||||
|
||||
impl LocalDefId {
|
||||
|
||||
#[inline]
|
||||
pub fn from_def_id(def_id: DefId) -> LocalDefId {
|
||||
assert!(def_id.is_local());
|
||||
|
|
|
@ -529,7 +529,7 @@ struct HirItemLike<T> {
|
|||
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>>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
|
|
|
@ -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
|
||||
/// things (e.g. each DefId/DefPath is only hashed once).
|
||||
#[derive(Clone)]
|
||||
pub struct StableHashingContext<'gcx> {
|
||||
sess: &'gcx Session,
|
||||
definitions: &'gcx Definitions,
|
||||
cstore: &'gcx dyn CrateStore,
|
||||
body_resolver: BodyResolver<'gcx>,
|
||||
pub struct StableHashingContext<'a> {
|
||||
sess: &'a Session,
|
||||
definitions: &'a Definitions,
|
||||
cstore: &'a dyn CrateStore,
|
||||
body_resolver: BodyResolver<'a>,
|
||||
hash_spans: bool,
|
||||
hash_bodies: bool,
|
||||
node_id_hashing_mode: NodeIdHashingMode,
|
||||
|
||||
// Very often, we are hashing something that does not need the
|
||||
// CachingCodemapView, so we initialize it lazily.
|
||||
raw_codemap: &'gcx CodeMap,
|
||||
caching_codemap: Option<CachingCodemapView<'gcx>>,
|
||||
raw_codemap: &'a CodeMap,
|
||||
caching_codemap: Option<CachingCodemapView<'a>>,
|
||||
}
|
||||
|
||||
#[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.
|
||||
// Don't use it for anything else or you'll run the risk of
|
||||
// leaking data out of the tracking system.
|
||||
pub fn new(sess: &'gcx Session,
|
||||
krate: &'gcx hir::Crate,
|
||||
definitions: &'gcx Definitions,
|
||||
cstore: &'gcx dyn CrateStore)
|
||||
pub fn new(sess: &'a Session,
|
||||
krate: &'a hir::Crate,
|
||||
definitions: &'a Definitions,
|
||||
cstore: &'a dyn CrateStore)
|
||||
-> Self {
|
||||
let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans;
|
||||
|
||||
|
@ -106,7 +106,7 @@ impl<'gcx> StableHashingContext<'gcx> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sess(&self) -> &'gcx Session {
|
||||
pub fn sess(&self) -> &'a Session {
|
||||
self.sess
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ impl<'gcx> StableHashingContext<'gcx> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn codemap(&mut self) -> &mut CachingCodemapView<'gcx> {
|
||||
pub fn codemap(&mut self) -> &mut CachingCodemapView<'a> {
|
||||
match self.caching_codemap {
|
||||
Some(ref mut cm) => {
|
||||
cm
|
||||
|
@ -193,27 +193,27 @@ impl<'gcx> StableHashingContext<'gcx> {
|
|||
}
|
||||
|
||||
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 {
|
||||
(*self).create_stable_hashing_context()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'gcx> StableHashingContextProvider for StableHashingContext<'gcx> {
|
||||
type ContextType = StableHashingContext<'gcx>;
|
||||
impl<'a> StableHashingContextProvider for StableHashingContext<'a> {
|
||||
type ContextType = StableHashingContext<'a>;
|
||||
fn create_stable_hashing_context(&self) -> Self::ContextType {
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
if hcx.hash_bodies() {
|
||||
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]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
match hcx.node_id_hashing_mode {
|
||||
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);
|
||||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self,
|
||||
hcx: &StableHashingContext<'gcx>)
|
||||
hcx: &StableHashingContext<'a>)
|
||||
-> (DefPathHash, hir::ItemLocalId) {
|
||||
let def_path_hash = hcx.local_def_path_hash(self.owner);
|
||||
(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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
match hcx.node_id_hashing_mode {
|
||||
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);
|
||||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self,
|
||||
hcx: &StableHashingContext<'gcx>)
|
||||
hcx: &StableHashingContext<'a>)
|
||||
-> (DefPathHash, hir::ItemLocalId) {
|
||||
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
|
||||
// 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
|
||||
// span starts and ends in the same file, which is almost always the case.
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
const TAG_VALID_SPAN: u8 = 0;
|
||||
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>(
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
pub fn hash_stable_trait_impls<'a, 'gcx, W, R>(
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>,
|
||||
blanket_impls: &Vec<DefId>,
|
||||
non_blanket_impls: &HashMap<fast_reject::SimplifiedType, Vec<DefId>, R>)
|
||||
|
|
|
@ -16,33 +16,6 @@ impl_stable_hash_for!(struct ::rustc_const_math::ConstFloat {
|
|||
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 {
|
||||
NotInRange,
|
||||
CmpBetweenUnequalTypes,
|
||||
|
|
|
@ -21,46 +21,46 @@ use std::mem;
|
|||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for DefId {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for DefId {
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
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;
|
||||
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for LocalDefId {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for LocalDefId {
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
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;
|
||||
|
||||
#[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())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for CrateNum {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for CrateNum {
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
hcx.def_path_hash(DefId {
|
||||
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;
|
||||
|
||||
#[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 };
|
||||
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<'gcx> ToStableHashKey<StableHashingContext<'gcx>>
|
||||
impl<'a> ToStableHashKey<StableHashingContext<'a>>
|
||||
for hir::ItemLocalId {
|
||||
type KeyType = hir::ItemLocalId;
|
||||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self,
|
||||
_: &StableHashingContext<'gcx>)
|
||||
_: &StableHashingContext<'a>)
|
||||
-> hir::ItemLocalId {
|
||||
*self
|
||||
}
|
||||
|
@ -100,9 +100,9 @@ for hir::ItemLocalId {
|
|||
// want to pick up on a reference changing its target, so we hash the NodeIds
|
||||
// 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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::ItemId {
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::TraitItemId {
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::ImplItemId {
|
||||
node_id
|
||||
|
@ -271,9 +271,9 @@ impl_stable_hash_for!(struct hir::TypeBinding {
|
|||
span
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Ty {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for hir::Ty {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
hcx.while_hashing_hir_bodies(true, |hcx| {
|
||||
let hir::Ty {
|
||||
|
@ -339,9 +339,9 @@ impl_stable_hash_for!(enum hir::FunctionRetTy {
|
|||
Return(t)
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitRef {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitRef {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::TraitRef {
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::Block {
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::Pat {
|
||||
id: _,
|
||||
|
@ -527,9 +527,9 @@ impl_stable_hash_for!(enum hir::UnsafeSource {
|
|||
UserProvided
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Expr {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for hir::Expr {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
hcx.while_hashing_hir_bodies(true, |hcx| {
|
||||
let hir::Expr {
|
||||
|
@ -591,9 +591,9 @@ impl_stable_hash_for!(enum hir::LoopSource {
|
|||
ForLoop
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::MatchSource {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for hir::MatchSource {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use hir::MatchSource;
|
||||
|
||||
|
@ -647,9 +647,9 @@ impl_stable_hash_for!(enum hir::ScopeTarget {
|
|||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let ast::Ident {
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::TraitItem {
|
||||
id: _,
|
||||
|
@ -695,9 +695,9 @@ impl_stable_hash_for!(enum hir::TraitItemKind {
|
|||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::ImplItem {
|
||||
id: _,
|
||||
|
@ -729,9 +729,9 @@ impl_stable_hash_for!(enum hir::ImplItemKind {
|
|||
Type(t)
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Visibility {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for hir::Visibility {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
|
@ -771,9 +771,9 @@ impl_stable_hash_for!(enum hir::ImplPolarity {
|
|||
Negative
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Mod {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for hir::Mod {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::Mod {
|
||||
inner,
|
||||
|
@ -826,9 +826,9 @@ impl_stable_hash_for!(enum hir::VariantData {
|
|||
Unit(id)
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Item {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for hir::Item {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::Item {
|
||||
name,
|
||||
|
@ -885,10 +885,10 @@ impl_stable_hash_for!(struct hir::ImplItemRef {
|
|||
defaultness
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a> HashStable<StableHashingContext<'a>>
|
||||
for hir::AssociatedItemKind {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
|
@ -930,9 +930,9 @@ impl_stable_hash_for!(struct hir::Arg {
|
|||
hir_id
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Body {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for hir::Body {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::Body {
|
||||
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);
|
||||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self,
|
||||
hcx: &StableHashingContext<'gcx>)
|
||||
hcx: &StableHashingContext<'a>)
|
||||
-> (DefPathHash, hir::ItemLocalId) {
|
||||
let hir::BodyId { node_id } = *self;
|
||||
node_id.to_stable_hash_key(hcx)
|
||||
|
@ -966,9 +966,9 @@ impl_stable_hash_for!(struct hir::InlineAsmOutput {
|
|||
is_indirect
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::GlobalAsm {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for hir::GlobalAsm {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::GlobalAsm {
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::InlineAsm {
|
||||
asm,
|
||||
|
@ -1062,22 +1062,22 @@ impl_stable_hash_for!(enum hir::Constness {
|
|||
NotConst
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a> HashStable<StableHashingContext<'a>>
|
||||
for hir::def_id::DefIndex {
|
||||
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
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 {
|
||||
type KeyType = DefPathHash;
|
||||
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
@ -1090,10 +1090,10 @@ impl_stable_hash_for!(struct hir::def::Export {
|
|||
is_import
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a> HashStable<StableHashingContext<'a>>
|
||||
for ::middle::lang_items::LangItem {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
_: &mut StableHashingContext<'gcx>,
|
||||
_: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
::std::hash::Hash::hash(self, hasher);
|
||||
}
|
||||
|
@ -1104,10 +1104,10 @@ impl_stable_hash_for!(struct ::middle::lang_items::LanguageItems {
|
|||
missing
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a> HashStable<StableHashingContext<'a>>
|
||||
for hir::TraitCandidate {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
|
||||
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)>);
|
||||
|
||||
fn to_stable_hash_key(&self,
|
||||
hcx: &StableHashingContext<'gcx>)
|
||||
hcx: &StableHashingContext<'a>)
|
||||
-> Self::KeyType {
|
||||
let hir::TraitCandidate {
|
||||
def_id,
|
||||
|
|
|
@ -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::UnsafetyCheckResult { violations, unsafe_blocks });
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a> HashStable<StableHashingContext<'a>>
|
||||
for mir::BorrowKind {
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
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 {
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
@ -79,12 +79,12 @@ impl_stable_hash_for!(struct mir::Terminator<'tcx> {
|
|||
source_info
|
||||
});
|
||||
|
||||
impl<'gcx, T> HashStable<StableHashingContext<'gcx>> for mir::ClearCrossCrate<T>
|
||||
where T: HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>> for mir::ClearCrossCrate<T>
|
||||
where T: HashStable<StableHashingContext<'a>>
|
||||
{
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
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]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
self.index().hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::BasicBlock {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for mir::BasicBlock {
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
self.index().hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Field {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for mir::Field {
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
self.index().hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a> HashStable<StableHashingContext<'a>>
|
||||
for mir::VisibilityScope {
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
self.index().hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Promoted {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for mir::Promoted {
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
self.index().hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for mir::TerminatorKind<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
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> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
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<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for mir::StatementKind<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
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>
|
||||
where T: HashStable<StableHashingContext<'gcx>>
|
||||
where T: HashStable<StableHashingContext<'a>>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>)
|
||||
{
|
||||
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<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Place<'gcx> {
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Place<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
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>
|
||||
where B: HashStable<StableHashingContext<'gcx>>,
|
||||
V: HashStable<StableHashingContext<'gcx>>,
|
||||
T: HashStable<StableHashingContext<'gcx>>
|
||||
where B: HashStable<StableHashingContext<'a>>,
|
||||
V: HashStable<StableHashingContext<'a>>,
|
||||
T: HashStable<StableHashingContext<'a>>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let mir::Projection {
|
||||
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>
|
||||
where V: HashStable<StableHashingContext<'gcx>>,
|
||||
T: HashStable<StableHashingContext<'gcx>>
|
||||
where V: HashStable<StableHashingContext<'a>>,
|
||||
T: HashStable<StableHashingContext<'a>>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
|
@ -382,9 +382,9 @@ impl_stable_hash_for!(struct mir::VisibilityScopeInfo {
|
|||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
||||
|
@ -479,10 +479,10 @@ impl_stable_hash_for!(enum mir::CastKind {
|
|||
Unsize
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for mir::AggregateKind<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
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<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Literal<'gcx> {
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Literal<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
|
@ -570,9 +570,9 @@ impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement<'tcx> {
|
|||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
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 });
|
||||
|
|
|
@ -29,42 +29,42 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey,
|
|||
StableHasher, StableHasherResult};
|
||||
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for InternedString {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for InternedString {
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let s: &str = &**self;
|
||||
s.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for InternedString {
|
||||
impl<'a> ToStableHashKey<StableHashingContext<'a>> for InternedString {
|
||||
type KeyType = InternedString;
|
||||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self,
|
||||
_: &StableHashingContext<'gcx>)
|
||||
_: &StableHashingContext<'a>)
|
||||
-> InternedString {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Name {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for ast::Name {
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
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;
|
||||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self,
|
||||
_: &StableHashingContext<'gcx>)
|
||||
_: &StableHashingContext<'a>)
|
||||
-> InternedString {
|
||||
self.as_str()
|
||||
}
|
||||
|
@ -111,10 +111,10 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
|
|||
rustc_const_unstable
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a> HashStable<StableHashingContext<'a>>
|
||||
for ::syntax::attr::StabilityLevel {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
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::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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
if self.len() == 0 {
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
// Make sure that these have been filtered out.
|
||||
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 {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
|
@ -242,10 +242,10 @@ for tokenstream::TokenTree {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a> HashStable<StableHashingContext<'a>>
|
||||
for tokenstream::TokenStream {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
for sub_tt in self.trees() {
|
||||
sub_tt.hash_stable(hcx, hasher);
|
||||
|
@ -253,9 +253,11 @@ for tokenstream::TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
fn hash_token<'gcx, W: StableHasherResult>(token: &token::Token,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
fn hash_token<'a, 'gcx, W: StableHasherResult>(
|
||||
token: &token::Token,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>,
|
||||
) {
|
||||
mem::discriminant(token).hash_stable(hcx, hasher);
|
||||
match *token {
|
||||
token::Token::Eq |
|
||||
|
@ -383,9 +385,9 @@ impl_stable_hash_for!(enum ::syntax_pos::FileName {
|
|||
Custom(s)
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for FileMap {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for FileMap {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let FileMap {
|
||||
name: _, // We hash the smaller name_hash instead of this
|
||||
|
|
|
@ -21,12 +21,13 @@ use std::mem;
|
|||
use middle::region;
|
||||
use traits;
|
||||
use ty;
|
||||
use mir;
|
||||
|
||||
impl<'gcx, T> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>>
|
||||
for &'gcx ty::Slice<T>
|
||||
where T: HashStable<StableHashingContext<'gcx>> {
|
||||
where T: HashStable<StableHashingContext<'a>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
thread_local! {
|
||||
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> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
self.unpack().hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for ty::subst::UnpackedKind<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
match self {
|
||||
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 {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
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]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
self.index().hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for ty::adjustment::AutoBorrow<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
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> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
|
@ -196,10 +197,10 @@ impl_stable_hash_for!(enum ty::BorrowKind {
|
|||
MutBorrow
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for ty::UpvarCapture<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
|
@ -223,11 +224,11 @@ impl_stable_hash_for!(struct ty::FnSig<'tcx> {
|
|||
abi
|
||||
});
|
||||
|
||||
impl<'gcx, T> HashStable<StableHashingContext<'gcx>> for ty::Binder<T>
|
||||
where T: HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>> for ty::Binder<T>
|
||||
where T: HashStable<StableHashingContext<'a>>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let ty::Binder(ref inner) = *self;
|
||||
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::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>
|
||||
where A: HashStable<StableHashingContext<'gcx>>,
|
||||
B: HashStable<StableHashingContext<'gcx>>,
|
||||
where A: HashStable<StableHashingContext<'a>>,
|
||||
B: HashStable<StableHashingContext<'a>>,
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let ty::OutlivesPredicate(ref a, ref b) = *self;
|
||||
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<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Predicate<'gcx> {
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::Predicate<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
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,
|
||||
_: &mut StableHashingContext<'gcx>,
|
||||
_: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
std_hash::Hash::hash(self, hasher);
|
||||
}
|
||||
|
@ -331,69 +332,102 @@ impl_stable_hash_for!(struct ty::FieldDef {
|
|||
vis
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for ::middle::const_val::ConstVal<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use middle::const_val::ConstVal::*;
|
||||
use middle::const_val::ConstAggregate::*;
|
||||
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
||||
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) => {
|
||||
def_id.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> {
|
||||
data
|
||||
impl_stable_hash_for!(enum mir::interpret::Value {
|
||||
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> {
|
||||
|
@ -406,26 +440,22 @@ impl_stable_hash_for!(struct ::middle::const_val::ConstEvalErr<'tcx> {
|
|||
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> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use middle::const_val::ErrKind::*;
|
||||
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
||||
match *self {
|
||||
CannotCast |
|
||||
MissingStructField |
|
||||
NonConstPath |
|
||||
ExpectedConstTuple |
|
||||
ExpectedConstStruct |
|
||||
IndexedNonVec |
|
||||
IndexNotUsize |
|
||||
MiscBinaryOp |
|
||||
MiscCatchAll |
|
||||
IndexOpFeatureGated |
|
||||
TypeckError |
|
||||
CheckMatchError => {
|
||||
// nothing to do
|
||||
|
@ -443,9 +473,10 @@ for ::middle::const_val::ErrKind<'gcx> {
|
|||
LayoutError(ref layout_error) => {
|
||||
layout_error.hash_stable(hcx, hasher);
|
||||
}
|
||||
ErroneousReferencedConstant(ref const_val) => {
|
||||
const_val.hash_stable(hcx, hasher);
|
||||
}
|
||||
Miri(ref err, ref trace) => {
|
||||
err.hash_stable(hcx, hasher);
|
||||
trace.hash_stable(hcx, hasher);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -459,6 +490,167 @@ impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> {
|
|||
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 {
|
||||
Covariant,
|
||||
Invariant,
|
||||
|
@ -470,9 +662,9 @@ impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized {
|
|||
Struct(index)
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Generics {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for ty::Generics {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let ty::Generics {
|
||||
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 {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let ty::RegionParameterDef {
|
||||
name,
|
||||
|
@ -527,12 +719,12 @@ impl_stable_hash_for!(struct ty::TypeParameterDef {
|
|||
synthetic
|
||||
});
|
||||
|
||||
impl<'gcx, T> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>>
|
||||
for ::middle::resolve_lifetime::Set1<T>
|
||||
where T: HashStable<StableHashingContext<'gcx>>
|
||||
where T: HashStable<StableHashingContext<'a>>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
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!(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;
|
||||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self, _: &StableHashingContext<'gcx>) -> region::Scope {
|
||||
fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> region::Scope {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
@ -613,11 +805,11 @@ impl_stable_hash_for!(enum ty::BoundRegion {
|
|||
BrEnv
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for ty::TypeVariants<'gcx>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use ty::TypeVariants::*;
|
||||
|
||||
|
@ -714,11 +906,11 @@ impl_stable_hash_for!(struct ty::TypeAndMut<'tcx> {
|
|||
mutbl
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for ty::ExistentialPredicate<'gcx>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
|
@ -751,9 +943,9 @@ impl_stable_hash_for!(struct ty::Instance<'tcx> {
|
|||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
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 } => {
|
||||
call_once.hash_stable(hcx, hasher);
|
||||
}
|
||||
ty::InstanceDef::DropGlue(def_id, t) => {
|
||||
ty::InstanceDef::DropGlue(def_id, ty) => {
|
||||
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);
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let ty::TraitDef {
|
||||
// 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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let ty::CrateVariancesMap {
|
||||
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>
|
||||
where T: HashStable<StableHashingContext<'gcx>>
|
||||
where T: HashStable<StableHashingContext<'a>>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
self.borrow().hash_stable(hcx, hasher);
|
||||
}
|
||||
|
@ -881,10 +1073,10 @@ impl_stable_hash_for!(enum ::middle::privacy::AccessLevel {
|
|||
Public
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a> HashStable<StableHashingContext<'a>>
|
||||
for ::middle::privacy::AccessLevels {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
|
||||
let ::middle::privacy::AccessLevels {
|
||||
|
@ -911,10 +1103,10 @@ impl_stable_hash_for!(tuple_struct ::middle::reachable::ReachableSet {
|
|||
reachable_set
|
||||
});
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
|
||||
for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use traits::Vtable::*;
|
||||
|
||||
|
@ -933,10 +1125,10 @@ for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableImplData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
|
||||
for traits::VtableImplData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableImplData {
|
||||
impl_def_id,
|
||||
|
@ -949,10 +1141,10 @@ for traits::VtableImplData<'gcx, N> where N: HashStable<StableHashingContext<'gc
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableAutoImplData<N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
|
||||
for traits::VtableAutoImplData<N> where N: HashStable<StableHashingContext<'a>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableAutoImplData {
|
||||
trait_def_id,
|
||||
|
@ -963,10 +1155,10 @@ for traits::VtableAutoImplData<N> where N: HashStable<StableHashingContext<'gcx>
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableObjectData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
|
||||
for traits::VtableObjectData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableObjectData {
|
||||
upcast_trait_ref,
|
||||
|
@ -979,10 +1171,10 @@ for traits::VtableObjectData<'gcx, N> where N: HashStable<StableHashingContext<'
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableBuiltinData<N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
|
||||
for traits::VtableBuiltinData<N> where N: HashStable<StableHashingContext<'a>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableBuiltinData {
|
||||
ref nested,
|
||||
|
@ -991,10 +1183,10 @@ for traits::VtableBuiltinData<N> where N: HashStable<StableHashingContext<'gcx>>
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableClosureData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
|
||||
for traits::VtableClosureData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableClosureData {
|
||||
closure_def_id,
|
||||
|
@ -1007,10 +1199,10 @@ for traits::VtableClosureData<'gcx, N> where N: HashStable<StableHashingContext<
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableFnPointerData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
|
||||
for traits::VtableFnPointerData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableFnPointerData {
|
||||
fn_ty,
|
||||
|
@ -1021,10 +1213,10 @@ for traits::VtableFnPointerData<'gcx, N> where N: HashStable<StableHashingContex
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
|
||||
for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableGeneratorData {
|
||||
closure_def_id,
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#![feature(core_intrinsics)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(dyn_trait)]
|
||||
#![feature(entry_or_default)]
|
||||
#![feature(from_ref)]
|
||||
#![feature(fs_read_write)]
|
||||
#![feature(i128)]
|
||||
|
|
|
@ -20,6 +20,12 @@ use session::Session;
|
|||
use session::config::Epoch;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
declare_lint! {
|
||||
pub EXCEEDING_BITSHIFTS,
|
||||
Deny,
|
||||
"shift exceeds the type's number of bits"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub CONST_ERR,
|
||||
Warn,
|
||||
|
@ -263,6 +269,12 @@ declare_lint! {
|
|||
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
|
||||
/// which are used by other parts of the compiler.
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -271,6 +283,8 @@ pub struct HardwiredLints;
|
|||
impl LintPass for HardwiredLints {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(
|
||||
ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
|
||||
EXCEEDING_BITSHIFTS,
|
||||
UNUSED_IMPORTS,
|
||||
UNUSED_EXTERN_CRATES,
|
||||
UNUSED_QUALIFICATIONS,
|
||||
|
|
|
@ -394,10 +394,10 @@ impl LintLevelMap {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for LintLevelMap {
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let LintLevelMap {
|
||||
ref sets,
|
||||
|
|
|
@ -73,10 +73,10 @@ macro_rules! __impl_stable_hash_field {
|
|||
#[macro_export]
|
||||
macro_rules! impl_stable_hash_for {
|
||||
(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]
|
||||
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>) {
|
||||
use $enum_name::*;
|
||||
::std::mem::discriminant(self).hash_stable(__ctx, __hasher);
|
||||
|
@ -92,10 +92,10 @@ macro_rules! impl_stable_hash_for {
|
|||
}
|
||||
};
|
||||
(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]
|
||||
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>) {
|
||||
let $struct_name {
|
||||
$(ref $field),*
|
||||
|
@ -106,10 +106,10 @@ macro_rules! impl_stable_hash_for {
|
|||
}
|
||||
};
|
||||
(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]
|
||||
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>) {
|
||||
let $struct_name (
|
||||
$(ref $field),*
|
||||
|
@ -125,11 +125,11 @@ macro_rules! impl_stable_hash_for {
|
|||
macro_rules! impl_stable_hash_for_spanned {
|
||||
($T:path) => (
|
||||
|
||||
impl<'tcx> HashStable<StableHashingContext<'tcx>> for ::syntax::codemap::Spanned<$T>
|
||||
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ::syntax::codemap::Spanned<$T>
|
||||
{
|
||||
#[inline]
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'tcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
self.node.hash_stable(hcx, hasher);
|
||||
self.span.hash_stable(hcx, hasher);
|
||||
|
|
|
@ -20,9 +20,9 @@ pub struct BorrowCheckResult {
|
|||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let BorrowCheckResult {
|
||||
ref used_mut_nodes,
|
||||
|
|
|
@ -8,72 +8,43 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub use rustc_const_math::ConstInt;
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use ty::{self, TyCtxt, layout};
|
||||
use ty::subst::Substs;
|
||||
use rustc_const_math::*;
|
||||
use mir::interpret::{Value, PrimVal};
|
||||
use errors::DiagnosticBuilder;
|
||||
|
||||
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 std::borrow::Cow;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
|
||||
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>),
|
||||
}
|
||||
|
||||
#[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")
|
||||
}
|
||||
Value(Value),
|
||||
}
|
||||
|
||||
impl<'tcx> ConstVal<'tcx> {
|
||||
pub fn to_const_int(&self) -> Option<ConstInt> {
|
||||
pub fn to_raw_bits(&self) -> Option<u128> {
|
||||
match *self {
|
||||
ConstVal::Integral(i) => Some(i),
|
||||
ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)),
|
||||
ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)),
|
||||
_ => None
|
||||
ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
|
||||
Some(b)
|
||||
},
|
||||
_ => 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)]
|
||||
pub struct ConstEvalErr<'tcx> {
|
||||
pub span: Span,
|
||||
pub kind: ErrKind<'tcx>,
|
||||
pub kind: Rc<ErrKind<'tcx>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ErrKind<'tcx> {
|
||||
CannotCast,
|
||||
MissingStructField,
|
||||
|
||||
NonConstPath,
|
||||
UnimplementedConstVal(&'static str),
|
||||
ExpectedConstTuple,
|
||||
ExpectedConstStruct,
|
||||
IndexedNonVec,
|
||||
IndexNotUsize,
|
||||
IndexOutOfBounds { len: u64, index: u64 },
|
||||
|
||||
MiscBinaryOp,
|
||||
MiscCatchAll,
|
||||
|
||||
IndexOpFeatureGated,
|
||||
Math(ConstMathErr),
|
||||
LayoutError(layout::LayoutError<'tcx>),
|
||||
|
||||
ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
|
||||
|
||||
TypeckError,
|
||||
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> {
|
||||
|
@ -120,21 +86,23 @@ impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ConstEvalErrDescription<'a> {
|
||||
pub enum ConstEvalErrDescription<'a, 'tcx: 'a> {
|
||||
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
|
||||
pub fn into_oneline(self) -> Cow<'a, str> {
|
||||
match self {
|
||||
ConstEvalErrDescription::Simple(simple) => simple,
|
||||
ConstEvalErrDescription::Backtrace(miri, _) => format!("{}", miri).into_cow(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
|
||||
pub fn description(&self) -> ConstEvalErrDescription {
|
||||
pub fn description(&'a self) -> ConstEvalErrDescription<'a, 'tcx> {
|
||||
use self::ErrKind::*;
|
||||
use self::ConstEvalErrDescription::*;
|
||||
|
||||
|
@ -145,31 +113,21 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
match self.kind {
|
||||
CannotCast => simple!("can't cast this type"),
|
||||
MissingStructField => simple!("nonexistent struct field"),
|
||||
match *self.kind {
|
||||
NonConstPath => simple!("non-constant path in constant expression"),
|
||||
UnimplementedConstVal(what) =>
|
||||
simple!("unimplemented constant expression: {}", what),
|
||||
ExpectedConstTuple => simple!("expected constant tuple"),
|
||||
ExpectedConstStruct => simple!("expected constant struct"),
|
||||
IndexedNonVec => simple!("indexing is only supported for arrays"),
|
||||
IndexNotUsize => simple!("indices must be of type `usize`"),
|
||||
IndexOutOfBounds { len, index } => {
|
||||
simple!("index out of bounds: the len is {} but the index is {}",
|
||||
len, index)
|
||||
}
|
||||
|
||||
MiscBinaryOp => simple!("bad operands for binary"),
|
||||
MiscCatchAll => simple!("unsupported constant expr"),
|
||||
IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
|
||||
Math(ref err) => Simple(err.description().into_cow()),
|
||||
LayoutError(ref err) => Simple(err.to_string().into_cow()),
|
||||
|
||||
ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
|
||||
|
||||
TypeckError => simple!("type-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)
|
||||
-> DiagnosticBuilder<'gcx>
|
||||
{
|
||||
let mut err = self;
|
||||
while let &ConstEvalErr {
|
||||
kind: ErrKind::ErroneousReferencedConstant(box ref i_err), ..
|
||||
} = err {
|
||||
err = i_err;
|
||||
}
|
||||
|
||||
let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
|
||||
err.note(tcx, primary_span, primary_kind, &mut diag);
|
||||
let mut diag = struct_error(tcx, self.span, "constant evaluation error");
|
||||
self.note(tcx, primary_span, primary_kind, &mut diag);
|
||||
diag
|
||||
}
|
||||
|
||||
|
@ -201,6 +152,12 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
|
|||
ConstEvalErrDescription::Simple(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) {
|
||||
|
@ -214,10 +171,25 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
|
|||
primary_span: Span,
|
||||
primary_kind: &str)
|
||||
{
|
||||
match self.kind {
|
||||
match *self.kind {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -280,6 +280,7 @@ language_item_table! {
|
|||
GeneratorTraitLangItem, "generator", gen_trait;
|
||||
|
||||
EqTraitLangItem, "eq", eq_trait;
|
||||
PartialOrdTraitLangItem, "partial_ord", partial_ord_trait;
|
||||
OrdTraitLangItem, "ord", ord_trait;
|
||||
|
||||
// A number of panic-related lang items. The `panic` item corresponds to
|
||||
|
|
|
@ -913,8 +913,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
|
||||
// Always promote `[T; 0]` (even when e.g. borrowed mutably).
|
||||
let promotable = match expr_ty.sty {
|
||||
ty::TyArray(_, len) if
|
||||
len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) => true,
|
||||
ty::TyArray(_, len) if len.val.to_raw_bits() == Some(0) => true,
|
||||
_ => promotable,
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let ScopeTree {
|
||||
root_body,
|
||||
|
|
|
@ -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,
|
||||
_: &mut StableHashingContext<'gcx>,
|
||||
_: &mut StableHashingContext<'a>,
|
||||
_: &mut StableHasher<W>) {
|
||||
// do nothing
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use rustc_const_math::ConstMathErr;
|
|||
use syntax::codemap::Span;
|
||||
use backtrace::Backtrace;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EvalError<'tcx> {
|
||||
pub kind: EvalErrorKind<'tcx>,
|
||||
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> {
|
||||
/// This variant is used by machines to signal their own errors that do not
|
||||
/// match an existing variant
|
||||
MachineError(Box<dyn Error>),
|
||||
MachineError(String),
|
||||
FunctionPointerTyMismatch(FnSig<'tcx>, FnSig<'tcx>),
|
||||
NoMirFor(String),
|
||||
UnterminatedCString(MemoryPointer),
|
||||
|
@ -65,11 +65,6 @@ pub enum EvalErrorKind<'tcx> {
|
|||
Intrinsic(String),
|
||||
OverflowingMath,
|
||||
InvalidChar(u128),
|
||||
OutOfMemory {
|
||||
allocation_size: u64,
|
||||
memory_size: u64,
|
||||
memory_usage: u64,
|
||||
},
|
||||
ExecutionTimeLimitReached,
|
||||
StackFrameLimitReached,
|
||||
OutOfTls,
|
||||
|
@ -124,6 +119,9 @@ pub enum EvalErrorKind<'tcx> {
|
|||
UnimplementedTraitSelection,
|
||||
/// Abort in case type errors are reached
|
||||
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>>;
|
||||
|
@ -132,7 +130,7 @@ impl<'tcx> Error for EvalError<'tcx> {
|
|||
fn description(&self) -> &str {
|
||||
use self::EvalErrorKind::*;
|
||||
match self.kind {
|
||||
MachineError(ref inner) => inner.description(),
|
||||
MachineError(ref inner) => inner,
|
||||
FunctionPointerTyMismatch(..) =>
|
||||
"tried to call a function through a function pointer of a different type",
|
||||
InvalidMemoryAccess =>
|
||||
|
@ -190,10 +188,8 @@ impl<'tcx> Error for EvalError<'tcx> {
|
|||
"mir not found",
|
||||
InvalidChar(..) =>
|
||||
"tried to interpret an invalid 32-bit value as a char",
|
||||
OutOfMemory{..} =>
|
||||
"could not allocate more memory",
|
||||
ExecutionTimeLimitReached =>
|
||||
"reached the configured maximum execution time",
|
||||
"the expression was too complex to be evaluated or resulted in an infinite loop",
|
||||
StackFrameLimitReached =>
|
||||
"reached the configured maximum number of stack frames",
|
||||
OutOfTls =>
|
||||
|
@ -245,14 +241,8 @@ impl<'tcx> Error for EvalError<'tcx> {
|
|||
"there were unresolved type arguments during trait selection",
|
||||
TypeckError =>
|
||||
"encountered constants with type errors, stopping evaluation",
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&dyn Error> {
|
||||
use self::EvalErrorKind::*;
|
||||
match self.kind {
|
||||
MachineError(ref inner) => Some(&**inner),
|
||||
_ => None,
|
||||
ReferencedConstant =>
|
||||
"referenced constant has errors",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -294,15 +284,12 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
|
|||
write!(f, "tried to reallocate memory from {} to {}", old, new),
|
||||
DeallocatedWrongMemoryKind(ref old, ref new) =>
|
||||
write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
|
||||
Math(span, ref err) =>
|
||||
write!(f, "{:?} at {:?}", err, span),
|
||||
Math(_, ref err) =>
|
||||
write!(f, "{}", err.description()),
|
||||
Intrinsic(ref err) =>
|
||||
write!(f, "{}", err),
|
||||
InvalidChar(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 } =>
|
||||
write!(f, "tried to access memory with alignment {}, but alignment {} is required",
|
||||
has, required),
|
||||
|
@ -313,7 +300,7 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
|
|||
PathNotFound(ref path) =>
|
||||
write!(f, "Cannot find path {:?}", path),
|
||||
MachineError(ref inner) =>
|
||||
write!(f, "machine error: {}", inner),
|
||||
write!(f, "{}", inner),
|
||||
IncorrectAllocationInformation(size, size2, align, align2) =>
|
||||
write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size, align, size2, align2),
|
||||
_ => write!(f, "{}", self.description()),
|
||||
|
|
|
@ -10,7 +10,7 @@ mod value;
|
|||
|
||||
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::fmt;
|
||||
|
@ -19,6 +19,7 @@ use ty;
|
|||
use ty::layout::{self, Align, HasDataLayout};
|
||||
use middle::region;
|
||||
use std::iter;
|
||||
use syntax::ast::Mutability;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Lock {
|
||||
|
@ -41,7 +42,7 @@ pub enum AccessKind {
|
|||
}
|
||||
|
||||
/// 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> {
|
||||
/// For a constant or static, the `Instance` of the item itself.
|
||||
/// 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 {}
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
|
||||
pub struct MemoryPointer {
|
||||
pub alloc_id: AllocId,
|
||||
pub offset: u64,
|
||||
|
@ -148,13 +149,16 @@ impl<'tcx> MemoryPointer {
|
|||
#[derive(Copy, Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)]
|
||||
pub struct AllocId(pub u64);
|
||||
|
||||
impl ::rustc_serialize::UseSpecializedEncodable for AllocId {}
|
||||
impl ::rustc_serialize::UseSpecializedDecodable for AllocId {}
|
||||
|
||||
impl fmt::Display for AllocId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Hash)]
|
||||
#[derive(Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct Allocation {
|
||||
/// The actual bytes of the allocation.
|
||||
/// Note that the bytes of a pointer represent the offset of the pointer
|
||||
|
@ -166,6 +170,10 @@ pub struct Allocation {
|
|||
pub undef_mask: UndefMask,
|
||||
/// The alignment of the allocation to detect unaligned reads.
|
||||
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 {
|
||||
|
@ -177,6 +185,7 @@ impl Allocation {
|
|||
relocations: BTreeMap::new(),
|
||||
undef_mask,
|
||||
align: Align::from_bytes(1, 1).unwrap(),
|
||||
runtime_mutability: Mutability::Immutable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,12 +197,14 @@ impl Allocation {
|
|||
type Block = u64;
|
||||
const BLOCK_SIZE: u64 = 64;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct UndefMask {
|
||||
blocks: Vec<Block>,
|
||||
len: u64,
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len});
|
||||
|
||||
impl UndefMask {
|
||||
pub fn new(size: u64) -> Self {
|
||||
let mut m = UndefMask {
|
||||
|
|
|
@ -1,24 +1,9 @@
|
|||
#![allow(unknown_lints)]
|
||||
|
||||
use ty::layout::{Align, HasDataLayout};
|
||||
use ty;
|
||||
|
||||
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.
|
||||
///
|
||||
|
@ -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
|
||||
/// 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.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
|
||||
pub enum Value {
|
||||
ByRef(Pointer, Align),
|
||||
ByVal(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.
|
||||
/// 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.
|
||||
|
@ -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
|
||||
/// the representation of pointers. Also all the sites that convert between primvals and pointers
|
||||
/// are explicit now (and rare!)
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
|
||||
pub struct Pointer {
|
||||
primval: PrimVal,
|
||||
pub primval: PrimVal,
|
||||
}
|
||||
|
||||
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
|
||||
/// 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.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
|
||||
pub enum PrimVal {
|
||||
/// The raw bytes of a simple value.
|
||||
Bytes(u128),
|
||||
|
@ -172,10 +166,6 @@ impl<'tcx> PrimVal {
|
|||
PrimVal::Bytes(n as u128)
|
||||
}
|
||||
|
||||
pub fn from_float(f: ConstFloat) -> Self {
|
||||
PrimVal::Bytes(f.bits)
|
||||
}
|
||||
|
||||
pub fn from_bool(b: bool) -> Self {
|
||||
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> {
|
||||
match self.to_bytes()? {
|
||||
0 => Ok(false),
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
use graphviz::IntoCow;
|
||||
use middle::const_val::ConstVal;
|
||||
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::indexed_vec::{IndexVec, Idx};
|
||||
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_id::DefId;
|
||||
use mir::visit::MirVisitable;
|
||||
use mir::interpret::{Value, PrimVal};
|
||||
use ty::subst::{Subst, Substs};
|
||||
use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior};
|
||||
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||
use ty::TypeAndMut;
|
||||
use util::ppaux;
|
||||
use std::slice;
|
||||
use hir::{self, InlineAsm};
|
||||
use std::ascii;
|
||||
use std::borrow::{Cow};
|
||||
use std::cell::Ref;
|
||||
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
|
||||
/// 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
|
||||
/// for the otherwise branch, so targets.len() == values.len() + 1
|
||||
|
@ -858,7 +859,7 @@ impl<'tcx> Terminator<'tcx> {
|
|||
impl<'tcx> TerminatorKind<'tcx> {
|
||||
pub fn if_<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'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 {
|
||||
discr: cond,
|
||||
switch_ty: tcx.types.bool,
|
||||
|
@ -1144,12 +1145,16 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
match *self {
|
||||
Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
|
||||
Goto { .. } => vec!["".into()],
|
||||
SwitchInt { ref values, .. } => {
|
||||
SwitchInt { ref values, switch_ty, .. } => {
|
||||
values.iter()
|
||||
.map(|const_val| {
|
||||
let mut buf = String::new();
|
||||
fmt_const_val(&mut buf, &ConstVal::Integral(*const_val)).unwrap();
|
||||
buf.into()
|
||||
.map(|&u| {
|
||||
let mut s = String::new();
|
||||
print_miri_value(
|
||||
Value::ByVal(PrimVal::Bytes(u)),
|
||||
switch_ty,
|
||||
&mut s,
|
||||
).unwrap();
|
||||
s.into()
|
||||
})
|
||||
.chain(iter::once(String::from("otherwise").into()))
|
||||
.collect()
|
||||
|
@ -1533,7 +1538,8 @@ impl<'tcx> Operand<'tcx> {
|
|||
ty,
|
||||
literal: Literal::Value {
|
||||
value: tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Function(def_id, substs),
|
||||
// ZST function type
|
||||
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
|
||||
ty
|
||||
})
|
||||
},
|
||||
|
@ -1557,7 +1563,7 @@ pub enum Rvalue<'tcx> {
|
|||
Use(Operand<'tcx>),
|
||||
|
||||
/// [x; 32]
|
||||
Repeat(Operand<'tcx>, ConstUsize),
|
||||
Repeat(Operand<'tcx>, u64),
|
||||
|
||||
/// &x or &mut x
|
||||
Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
|
||||
|
@ -1853,7 +1859,7 @@ impl<'tcx> Debug for Literal<'tcx> {
|
|||
match *self {
|
||||
Value { value } => {
|
||||
write!(fmt, "const ")?;
|
||||
fmt_const_val(fmt, &value.val)
|
||||
fmt_const_val(fmt, value)
|
||||
}
|
||||
Promoted { 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.
|
||||
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::*;
|
||||
match *const_val {
|
||||
Float(f) => write!(fmt, "{:?}", f),
|
||||
Integral(n) => write!(fmt, "{}", n),
|
||||
Str(s) => write!(fmt, "{:?}", s),
|
||||
ByteStr(bytes) => {
|
||||
let escaped: String = bytes.data
|
||||
.iter()
|
||||
.flat_map(|&ch| ascii::escape_default(ch).map(|c| c as char))
|
||||
.collect();
|
||||
write!(fmt, "b\"{}\"", escaped)
|
||||
}
|
||||
Bool(b) => write!(fmt, "{:?}", b),
|
||||
Char(c) => write!(fmt, "{:?}", c),
|
||||
Variant(def_id) |
|
||||
Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
|
||||
Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val),
|
||||
Unevaluated(..) => write!(fmt, "{:?}", const_val)
|
||||
match const_val.val {
|
||||
Unevaluated(..) => write!(fmt, "{:?}", const_val),
|
||||
Value(val) => print_miri_value(val, const_val.ty, fmt),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Result {
|
||||
use ty::TypeVariants::*;
|
||||
use rustc_const_math::ConstFloat;
|
||||
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(bits)), &TyFloat(fty)) =>
|
||||
write!(f, "{}", ConstFloat { bits, ty: fty }),
|
||||
(Value::ByVal(PrimVal::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui),
|
||||
(Value::ByVal(PrimVal::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i),
|
||||
(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> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
Constant {
|
||||
|
|
|
@ -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,
|
||||
hcx: &mut StableHashingContext<'tcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
::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,
|
||||
hcx: &mut StableHashingContext<'tcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let CodegenUnit {
|
||||
ref items,
|
||||
|
|
|
@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
|
|||
PlaceTy::Ty {
|
||||
ty: match ty.sty {
|
||||
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);
|
||||
tcx.mk_array(inner, len)
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
match *self {
|
||||
Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
|
||||
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) => {
|
||||
let place_ty = place.ty(local_decls, tcx).to_ty(tcx);
|
||||
|
|
|
@ -12,7 +12,6 @@ use hir::def_id::DefId;
|
|||
use ty::subst::Substs;
|
||||
use ty::{ClosureSubsts, Region, Ty, GeneratorInterior};
|
||||
use mir::*;
|
||||
use rustc_const_math::ConstUsize;
|
||||
use syntax_pos::Span;
|
||||
|
||||
// # The MIR Visitor
|
||||
|
@ -243,18 +242,6 @@ macro_rules! make_mir_visitor {
|
|||
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,
|
||||
local: Local,
|
||||
local_decl: & $($mutability)* LocalDecl<'tcx>) {
|
||||
|
@ -426,13 +413,10 @@ macro_rules! make_mir_visitor {
|
|||
|
||||
TerminatorKind::SwitchInt { ref $($mutability)* discr,
|
||||
ref $($mutability)* switch_ty,
|
||||
ref values,
|
||||
values: _,
|
||||
ref targets } => {
|
||||
self.visit_operand(discr, 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 {
|
||||
self.visit_branch(block, target);
|
||||
}
|
||||
|
@ -538,10 +522,8 @@ macro_rules! make_mir_visitor {
|
|||
self.visit_operand(operand, location);
|
||||
}
|
||||
|
||||
Rvalue::Repeat(ref $($mutability)* value,
|
||||
ref $($mutability)* length) => {
|
||||
Rvalue::Repeat(ref $($mutability)* value, _) => {
|
||||
self.visit_operand(value, location);
|
||||
self.visit_const_usize(length, location);
|
||||
}
|
||||
|
||||
Rvalue::Ref(ref $($mutability)* r, bk, ref $($mutability)* path) => {
|
||||
|
@ -798,12 +780,6 @@ macro_rules! make_mir_visitor {
|
|||
_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
|
||||
|
||||
fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Location) {
|
||||
|
|
|
@ -179,10 +179,10 @@ impl_stable_hash_for!(enum self::OutputType {
|
|||
DepInfo
|
||||
});
|
||||
|
||||
impl<'tcx> ToStableHashKey<StableHashingContext<'tcx>> for OutputType {
|
||||
impl<'a, 'tcx> ToStableHashKey<StableHashingContext<'a>> for OutputType {
|
||||
type KeyType = OutputType;
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self, _: &StableHashingContext<'tcx>) -> Self::KeyType {
|
||||
fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> Self::KeyType {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,6 +103,11 @@ pub struct Session {
|
|||
/// The maximum length of types during monomorphization.
|
||||
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
|
||||
/// dependency if it didn't already find one, and this tracks what was
|
||||
/// injected.
|
||||
|
@ -1004,6 +1009,8 @@ pub fn build_session_(sopts: config::Options,
|
|||
features: RefCell::new(None),
|
||||
recursion_limit: Cell::new(64),
|
||||
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)),
|
||||
injected_allocator: Cell::new(None),
|
||||
allocator_kind: Cell::new(None),
|
||||
|
|
|
@ -32,7 +32,6 @@ use hir;
|
|||
use hir::def_id::DefId;
|
||||
use infer::{self, InferCtxt};
|
||||
use infer::type_variable::TypeVariableOrigin;
|
||||
use middle::const_val;
|
||||
use std::fmt;
|
||||
use syntax::ast;
|
||||
use session::DiagnosticMessageId;
|
||||
|
@ -776,7 +775,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
ConstEvalFailure(ref err) => {
|
||||
if let const_val::ErrKind::TypeckError = err.kind {
|
||||
if let ::middle::const_val::ErrKind::TypeckError = *err.kind {
|
||||
return;
|
||||
}
|
||||
err.struct_error(self.tcx, span, "constant expression")
|
||||
|
|
|
@ -9,12 +9,14 @@
|
|||
// except according to those terms.
|
||||
|
||||
use infer::{RegionObligation, InferCtxt};
|
||||
use mir::interpret::GlobalId;
|
||||
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
|
||||
use ty::error::ExpectedFound;
|
||||
use rustc_data_structures::obligation_forest::{ObligationForest, Error};
|
||||
use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
|
||||
use std::marker::PhantomData;
|
||||
use hir::def_id::DefId;
|
||||
use middle::const_val::{ConstEvalErr, ErrKind};
|
||||
|
||||
use super::CodeAmbiguity;
|
||||
use super::CodeProjectionError;
|
||||
|
@ -514,17 +516,35 @@ fn process_predicate<'a, 'gcx, 'tcx>(
|
|||
}
|
||||
Some(param_env) => {
|
||||
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 => {
|
||||
pending_obligation.stalled_on = substs.types().collect();
|
||||
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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ pub use self::ObligationCauseCode::*;
|
|||
use hir;
|
||||
use hir::def_id::DefId;
|
||||
use infer::outlives::env::OutlivesEnvironment;
|
||||
use middle::const_val::ConstEvalErr;
|
||||
use middle::region;
|
||||
use middle::const_val::ConstEvalErr;
|
||||
use ty::subst::Substs;
|
||||
use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, ToPredicate};
|
||||
use ty::error::{ExpectedFound, TypeError};
|
||||
|
|
|
@ -29,6 +29,7 @@ use hir::def_id::DefId;
|
|||
use infer::{InferCtxt, InferOk};
|
||||
use infer::type_variable::TypeVariableOrigin;
|
||||
use middle::const_val::ConstVal;
|
||||
use mir::interpret::{GlobalId};
|
||||
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
|
||||
use syntax::symbol::Symbol;
|
||||
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> {
|
||||
if let ConstVal::Unevaluated(def_id, substs) = constant.val {
|
||||
if substs.needs_infer() {
|
||||
let identity_substs = Substs::identity_for_item(self.tcx(), def_id);
|
||||
let data = self.param_env.and((def_id, identity_substs));
|
||||
match self.tcx().lift_to_global(&data) {
|
||||
Some(data) => {
|
||||
match self.tcx().const_eval(data) {
|
||||
let tcx = self.selcx.tcx().global_tcx();
|
||||
if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) {
|
||||
if substs.needs_infer() {
|
||||
let identity_substs = Substs::identity_for_item(tcx, def_id);
|
||||
let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs);
|
||||
if let Some(instance) = instance {
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: None
|
||||
};
|
||||
match tcx.const_eval(param_env.and(cid)) {
|
||||
Ok(evaluated) => {
|
||||
let evaluated = evaluated.subst(self.tcx(), substs);
|
||||
return self.fold_const(evaluated);
|
||||
|
@ -413,18 +419,20 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
|
|||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
} else {
|
||||
let data = self.param_env.and((def_id, substs));
|
||||
match self.tcx().lift_to_global(&data) {
|
||||
Some(data) => {
|
||||
match self.tcx().const_eval(data) {
|
||||
Ok(evaluated) => return self.fold_const(evaluated),
|
||||
Err(_) => {}
|
||||
} else {
|
||||
if let Some(substs) = self.tcx().lift_to_global(&substs) {
|
||||
let instance = ty::Instance::resolve(tcx, 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(evaluated) => return self.fold_const(evaluated),
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
|
|||
use ty::fast_reject;
|
||||
use ty::relate::TypeRelation;
|
||||
use middle::lang_items;
|
||||
use mir::interpret::{GlobalId};
|
||||
|
||||
use rustc_data_structures::bitvec::BitVector;
|
||||
use std::iter;
|
||||
|
@ -732,11 +733,26 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
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)) => {
|
||||
match self.tcx().const_eval(param_env.and((def_id, substs))) {
|
||||
Ok(_) => EvaluatedToOk,
|
||||
Err(_) => EvaluatedToErr
|
||||
let instance = ty::Instance::resolve(
|
||||
tcx.global_tcx(),
|
||||
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 => {
|
||||
|
|
|
@ -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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let Children {
|
||||
ref nonblanket_impls,
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
// persisting to incr. comp. caches.
|
||||
|
||||
use hir::def_id::{DefId, CrateNum};
|
||||
use middle::const_val::ByteArray;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_serialize::{Decodable, Decoder, Encoder, Encodable, opaque};
|
||||
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)))?)
|
||||
}
|
||||
|
||||
#[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]
|
||||
pub fn decode_const<'a, 'tcx, D>(decoder: &mut D)
|
||||
-> Result<&'tcx ty::Const<'tcx>, D::Error>
|
||||
|
@ -278,7 +266,6 @@ macro_rules! implement_ty_decoder {
|
|||
use $crate::ty::codec::*;
|
||||
use $crate::ty::subst::Substs;
|
||||
use $crate::hir::def_id::{CrateNum};
|
||||
use $crate::middle::const_val::ByteArray;
|
||||
use rustc_serialize::{Decoder, SpecializedDecoder};
|
||||
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>>
|
||||
for $DecoderName<$($typaram),*> {
|
||||
fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
|
||||
|
|
|
@ -30,7 +30,8 @@ use middle::cstore::EncodedMetadata;
|
|||
use middle::lang_items;
|
||||
use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
|
||||
use middle::stability;
|
||||
use mir::{Mir, interpret};
|
||||
use mir::{self, Mir, interpret};
|
||||
use mir::interpret::{Value, PrimVal};
|
||||
use ty::subst::{Kind, Substs};
|
||||
use ty::ReprOptions;
|
||||
use ty::Instance;
|
||||
|
@ -53,7 +54,6 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
|
|||
StableHasher, StableHasherResult,
|
||||
StableVec};
|
||||
use arena::{TypedArena, DroplessArena};
|
||||
use rustc_const_math::{ConstInt, ConstUsize};
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let ty::TypeckTables {
|
||||
local_id_root,
|
||||
|
@ -868,7 +868,7 @@ pub struct GlobalCtxt<'tcx> {
|
|||
|
||||
stability_interner: RefCell<FxHashSet<&'tcx attr::Stability>>,
|
||||
|
||||
pub interpret_interner: RefCell<InterpretInterner<'tcx>>,
|
||||
pub interpret_interner: InterpretInterner<'tcx>,
|
||||
|
||||
layout_interner: RefCell<FxHashSet<&'tcx LayoutDetails>>,
|
||||
|
||||
|
@ -892,6 +892,11 @@ pub struct GlobalCtxt<'tcx> {
|
|||
/// Everything needed to efficiently work with interned allocations
|
||||
#[derive(Debug, Default)]
|
||||
pub struct InterpretInterner<'tcx> {
|
||||
inner: RefCell<InterpretInternerInner<'tcx>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct InterpretInternerInner<'tcx> {
|
||||
/// Stores the value of constants (and deduplicates the actual memory)
|
||||
allocs: FxHashSet<&'tcx interpret::Allocation>,
|
||||
|
||||
|
@ -905,12 +910,18 @@ pub struct InterpretInterner<'tcx> {
|
|||
/// Allows obtaining const allocs via a unique identifier
|
||||
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.
|
||||
/// Always incremented, never gets smaller.
|
||||
next_id: interpret::AllocId,
|
||||
|
||||
/// Allows checking whether a constant already has an allocation
|
||||
alloc_cache: FxHashMap<interpret::GlobalId<'tcx>, interpret::AllocId>,
|
||||
/// Allows checking whether a static already has an allocation
|
||||
///
|
||||
/// 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
|
||||
/// allocations for string and bytestring literals.
|
||||
|
@ -918,14 +929,15 @@ pub struct InterpretInterner<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> InterpretInterner<'tcx> {
|
||||
pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> interpret::AllocId {
|
||||
if let Some(&alloc_id) = self.function_cache.get(&instance) {
|
||||
pub fn create_fn_alloc(&self, instance: Instance<'tcx>) -> interpret::AllocId {
|
||||
if let Some(&alloc_id) = self.inner.borrow().function_cache.get(&instance) {
|
||||
return alloc_id;
|
||||
}
|
||||
let id = self.reserve();
|
||||
debug!("creating fn ptr: {}", id);
|
||||
self.functions.insert(id, instance);
|
||||
self.function_cache.insert(instance, id);
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
inner.functions.insert(id, instance);
|
||||
inner.function_cache.insert(instance, id);
|
||||
id
|
||||
}
|
||||
|
||||
|
@ -933,39 +945,48 @@ impl<'tcx> InterpretInterner<'tcx> {
|
|||
&self,
|
||||
id: interpret::AllocId,
|
||||
) -> Option<Instance<'tcx>> {
|
||||
self.functions.get(&id).cloned()
|
||||
self.inner.borrow().functions.get(&id).cloned()
|
||||
}
|
||||
|
||||
pub fn get_alloc(
|
||||
&self,
|
||||
id: interpret::AllocId,
|
||||
) -> Option<&'tcx interpret::Allocation> {
|
||||
self.alloc_by_id.get(&id).cloned()
|
||||
self.inner.borrow().alloc_by_id.get(&id).cloned()
|
||||
}
|
||||
|
||||
pub fn get_cached(
|
||||
&self,
|
||||
global_id: interpret::GlobalId<'tcx>,
|
||||
static_id: DefId,
|
||||
) -> Option<interpret::AllocId> {
|
||||
self.alloc_cache.get(&global_id).cloned()
|
||||
self.inner.borrow().alloc_cache.get(&static_id).cloned()
|
||||
}
|
||||
|
||||
pub fn cache(
|
||||
&mut self,
|
||||
global_id: interpret::GlobalId<'tcx>,
|
||||
ptr: interpret::AllocId,
|
||||
&self,
|
||||
static_id: DefId,
|
||||
alloc_id: interpret::AllocId,
|
||||
) {
|
||||
if let Some(old) = self.alloc_cache.insert(global_id, ptr) {
|
||||
bug!("tried to cache {:?}, but was already existing as {:#?}", global_id, old);
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
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(
|
||||
&mut self,
|
||||
&self,
|
||||
id: interpret::AllocId,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -973,10 +994,11 @@ impl<'tcx> InterpretInterner<'tcx> {
|
|||
/// obtains a new allocation ID that can be referenced but does not
|
||||
/// yet have an allocation backing it.
|
||||
pub fn reserve(
|
||||
&mut self,
|
||||
&self,
|
||||
) -> interpret::AllocId {
|
||||
let next = self.next_id;
|
||||
self.next_id.0 = self.next_id.0
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let next = inner.next_id;
|
||||
inner.next_id.0 = inner.next_id.0
|
||||
.checked_add(1)
|
||||
.expect("You overflowed a u64 by incrementing by 1... \
|
||||
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,
|
||||
alloc: 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;
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
interned
|
||||
|
@ -1070,20 +1092,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
/// Allocates a byte or string literal for `mir::interpret`
|
||||
pub fn allocate_cached(self, bytes: &[u8]) -> interpret::AllocId {
|
||||
// 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;
|
||||
}
|
||||
// create an allocation that just contains these bytes
|
||||
let alloc = interpret::Allocation::from_bytes(bytes);
|
||||
let alloc = self.intern_const_alloc(alloc);
|
||||
|
||||
let mut int = self.interpret_interner.borrow_mut();
|
||||
// the next unique id
|
||||
let id = int.reserve();
|
||||
let id = self.interpret_interner.reserve();
|
||||
// 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
|
||||
int.literal_alloc_cache.insert(bytes.to_owned(), id);
|
||||
self.interpret_interner.inner.borrow_mut().literal_alloc_cache.insert(bytes.to_owned(), id);
|
||||
id
|
||||
}
|
||||
|
||||
|
@ -1248,6 +1270,40 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
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>> {
|
||||
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)
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
StableHashingContext::new(self.sess,
|
||||
|
@ -1731,7 +1787,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
|||
println!("Substs interner: #{}", self.interners.substs.borrow().len());
|
||||
println!("Region interner: #{}", self.interners.region.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());
|
||||
}
|
||||
}
|
||||
|
@ -2043,13 +2099,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, '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 {
|
||||
val: ConstVal::Integral(ConstInt::Usize(n)),
|
||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.into()))),
|
||||
ty: self.types.usize
|
||||
})))
|
||||
}
|
||||
|
|
|
@ -9,17 +9,13 @@
|
|||
// except according to those terms.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use middle::const_val::ConstVal;
|
||||
use ty::{self, BoundRegion, Region, Ty, TyCtxt};
|
||||
|
||||
use std::fmt;
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
use errors::DiagnosticBuilder;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use rustc_const_math::ConstInt;
|
||||
|
||||
use hir;
|
||||
|
||||
#[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::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)),
|
||||
ty::TyArray(_, n) => {
|
||||
if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
|
||||
format!("array of {} elements", n)
|
||||
} else {
|
||||
"array".to_string()
|
||||
match n.val.to_raw_bits() {
|
||||
Some(n) => format!("array of {} elements", n),
|
||||
None => "array".to_string(),
|
||||
}
|
||||
}
|
||||
ty::TySlice(_) => "slice".to_string(),
|
||||
|
|
|
@ -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 +
|
||||
HashStable<StableHashingContext<'gcx>>,
|
||||
HashStable<StableHashingContext<'a>>,
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::const_val::{ConstVal, ConstAggregate};
|
||||
use middle::const_val::ConstVal;
|
||||
use ty::subst::Substs;
|
||||
use ty::{self, Ty, TypeFlags, TypeFoldable};
|
||||
|
||||
|
@ -218,30 +218,7 @@ impl FlagComputation {
|
|||
fn add_const(&mut self, constant: &ty::Const) {
|
||||
self.add_ty(constant.ty);
|
||||
match constant.val {
|
||||
ConstVal::Integral(_) |
|
||||
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::Value(_) => {}
|
||||
ConstVal::Unevaluated(_, substs) => {
|
||||
self.add_flags(TypeFlags::HAS_PROJECTION);
|
||||
self.add_substs(substs);
|
||||
|
|
|
@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
|||
}))
|
||||
},
|
||||
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
|
||||
// the type of its elements is uninhabited.
|
||||
Some(n) if n != 0 => ty.uninhabited_from(visited, tcx),
|
||||
|
|
|
@ -17,13 +17,13 @@ use util::ppaux;
|
|||
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct Instance<'tcx> {
|
||||
pub def: InstanceDef<'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> {
|
||||
Item(DefId),
|
||||
Intrinsic(DefId),
|
||||
|
|
|
@ -342,7 +342,7 @@ impl AddAssign for Size {
|
|||
/// 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
|
||||
/// 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 {
|
||||
abi: u8,
|
||||
pref: u8,
|
||||
|
@ -794,6 +794,17 @@ impl Abi {
|
|||
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)]
|
||||
|
@ -1237,7 +1248,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
|
|||
}
|
||||
|
||||
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)
|
||||
.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) {
|
||||
continue;
|
||||
}
|
||||
let x = discr.to_u128_unchecked() as i128;
|
||||
let x = discr.val as i128;
|
||||
if x < min { min = 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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use ty::layout::Variants::*;
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use ty::layout::FieldPlacement::*;
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use ty::layout::Abi::*;
|
||||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let Scalar { value, valid_range: RangeInclusive { start, end } } = *self;
|
||||
value.hash_stable(hcx, hasher);
|
||||
|
@ -2498,10 +2509,10 @@ impl_stable_hash_for!(struct ::ty::layout::Size {
|
|||
raw
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for LayoutError<'gcx>
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for LayoutError<'gcx>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use ty::layout::LayoutError::*;
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
|
|
@ -10,9 +10,10 @@
|
|||
|
||||
use dep_graph::SerializedDepNodeIndex;
|
||||
use hir::def_id::{CrateNum, DefId, DefIndex};
|
||||
use mir::interpret::{GlobalId};
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::maps::queries;
|
||||
use ty::subst::Substs;
|
||||
use ty::maps::queries;
|
||||
|
||||
use std::hash::Hash;
|
||||
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> {
|
||||
fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) -> String {
|
||||
format!("const-evaluating `{}`", tcx.item_path_str(key.value.0))
|
||||
fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> String {
|
||||
format!("const-evaluating `{}`", tcx.item_path_str(key.value.instance.def.def_id()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex};
|
|||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::subst::Substs;
|
||||
use ty::fast_reject::SimplifiedType;
|
||||
use mir;
|
||||
|
||||
use std::fmt::Debug;
|
||||
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 {
|
||||
fn map_crate(&self) -> CrateNum {
|
||||
*self
|
||||
|
|
|
@ -16,7 +16,6 @@ use hir::{self, TraitCandidate, ItemLocalId, TransFnAttrs};
|
|||
use hir::svh::Svh;
|
||||
use lint;
|
||||
use middle::borrowck::BorrowCheckResult;
|
||||
use middle::const_val;
|
||||
use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary,
|
||||
ExternBodyNestedBodies};
|
||||
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::lang_items::{LanguageItems, LangItem};
|
||||
use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol};
|
||||
use middle::const_val::EvalResult;
|
||||
use mir::mono::{CodegenUnit, Stats};
|
||||
use mir;
|
||||
use mir::interpret::{GlobalId};
|
||||
use session::{CompileResult, CrateDisambiguator};
|
||||
use session::config::OutputFilenames;
|
||||
use traits::Vtable;
|
||||
|
@ -210,8 +211,8 @@ define_maps! { <'tcx>
|
|||
|
||||
/// Results of evaluating const items or constants embedded in
|
||||
/// other items (such as enum variant explicit discriminants).
|
||||
[] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
|
||||
-> const_val::EvalResult<'tcx>,
|
||||
[] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
|
||||
-> EvalResult<'tcx>,
|
||||
|
||||
[] fn check_match: CheckMatch(DefId)
|
||||
-> Result<(), ErrorReported>,
|
||||
|
@ -450,7 +451,7 @@ fn typeck_item_bodies_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
|
|||
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::ConstEval { param_env }
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId,
|
|||
RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE};
|
||||
use hir::map::definitions::DefPathHash;
|
||||
use ich::{CachingCodemapView, Fingerprint};
|
||||
use mir;
|
||||
use mir::{self, interpret};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
|
@ -187,6 +187,7 @@ impl<'sess> OnDiskCache<'sess> {
|
|||
type_shorthands: FxHashMap(),
|
||||
predicate_shorthands: FxHashMap(),
|
||||
expn_info_shorthands: FxHashMap(),
|
||||
interpret_alloc_shorthands: FxHashMap(),
|
||||
codemap: CachingCodemapView::new(tcx.sess.codemap()),
|
||||
file_to_file_index,
|
||||
};
|
||||
|
@ -362,6 +363,7 @@ impl<'sess> OnDiskCache<'sess> {
|
|||
file_index_to_file: &self.file_index_to_file,
|
||||
file_index_to_stable_id: &self.file_index_to_stable_id,
|
||||
synthetic_expansion_infos: &self.synthetic_expansion_infos,
|
||||
interpret_alloc_cache: FxHashMap::default(),
|
||||
};
|
||||
|
||||
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>>,
|
||||
file_index_to_file: &'x RefCell<FxHashMap<FileMapIndex, Lrc<FileMap>>>,
|
||||
file_index_to_stable_id: &'x FxHashMap<FileMapIndex, StableFilemapId>,
|
||||
interpret_alloc_cache: FxHashMap<usize, interpret::AllocId>,
|
||||
}
|
||||
|
||||
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> );
|
||||
|
||||
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> {
|
||||
fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
|
||||
let tag: u8 = Decodable::decode(self)?;
|
||||
|
@ -703,6 +750,7 @@ struct CacheEncoder<'enc, 'a, 'tcx, E>
|
|||
type_shorthands: FxHashMap<ty::Ty<'tcx>, usize>,
|
||||
predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
|
||||
expn_info_shorthands: FxHashMap<Mark, AbsoluteBytePos>,
|
||||
interpret_alloc_shorthands: FxHashMap<interpret::AllocId, usize>,
|
||||
codemap: CachingCodemapView<'tcx>,
|
||||
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>
|
||||
where E: 'enc + ty_codec::TyEncoder
|
||||
{
|
||||
|
|
|
@ -26,12 +26,13 @@ use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangIte
|
|||
use middle::privacy::AccessLevels;
|
||||
use middle::resolve_lifetime::ObjectLifetimeDefault;
|
||||
use mir::Mir;
|
||||
use mir::interpret::{GlobalId, Value, PrimVal};
|
||||
use mir::GeneratorLayout;
|
||||
use session::CrateDisambiguator;
|
||||
use traits;
|
||||
use ty;
|
||||
use ty::subst::{Subst, Substs};
|
||||
use ty::util::IntTypeExt;
|
||||
use ty::util::{IntTypeExt, Discr};
|
||||
use ty::walk::TypeWalker;
|
||||
use util::common::ErrorReported;
|
||||
use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
|
||||
|
@ -52,7 +53,6 @@ use syntax::attr;
|
|||
use syntax::ext::hygiene::{Mark, SyntaxContext};
|
||||
use syntax::symbol::{Symbol, InternedString};
|
||||
use syntax_pos::{DUMMY_SP, Span};
|
||||
use rustc_const_math::ConstInt;
|
||||
|
||||
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
|
||||
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::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};
|
||||
|
||||
|
@ -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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let ty::TyS {
|
||||
ref sty,
|
||||
|
@ -1439,11 +1439,11 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx, T> HashStable<StableHashingContext<'gcx>> for ParamEnvAnd<'gcx, T>
|
||||
where T: HashStable<StableHashingContext<'gcx>>
|
||||
impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>> for ParamEnvAnd<'gcx, T>
|
||||
where T: HashStable<StableHashingContext<'a>>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let ParamEnvAnd {
|
||||
ref param_env,
|
||||
|
@ -1544,9 +1544,9 @@ impl<'tcx> serialize::UseSpecializedEncodable 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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
thread_local! {
|
||||
static CACHE: RefCell<FxHashMap<usize, Fingerprint>> =
|
||||
|
@ -1824,27 +1824,79 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
|
||||
-> impl Iterator<Item=ConstInt> + 'a {
|
||||
pub fn eval_explicit_discr(
|
||||
&self,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
expr_did: DefId,
|
||||
) -> Option<Discr<'tcx>> {
|
||||
let param_env = ParamEnv::empty(traits::Reveal::UserFacing);
|
||||
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 mut prev_discr = None::<ConstInt>;
|
||||
let mut prev_discr = None::<Discr<'tcx>>;
|
||||
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 {
|
||||
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
|
||||
match tcx.const_eval(param_env.and((expr_did, substs))) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
if let Some(new_discr) = self.eval_explicit_discr(tcx, expr_did) {
|
||||
discr = new_discr;
|
||||
}
|
||||
}
|
||||
prev_discr = Some(discr);
|
||||
|
@ -1861,8 +1913,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
|||
pub fn discriminant_for_variant(&self,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
variant_index: usize)
|
||||
-> ConstInt {
|
||||
let param_env = ParamEnv::empty(traits::Reveal::UserFacing);
|
||||
-> Discr<'tcx> {
|
||||
let repr_type = self.repr.discr_type();
|
||||
let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx());
|
||||
let mut explicit_index = variant_index;
|
||||
|
@ -1873,18 +1924,12 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
|||
explicit_index -= distance;
|
||||
}
|
||||
ty::VariantDiscr::Explicit(expr_did) => {
|
||||
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
|
||||
match tcx.const_eval(param_env.and((expr_did, substs))) {
|
||||
Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => {
|
||||
explicit_value = v;
|
||||
match self.eval_explicit_discr(tcx, expr_did) {
|
||||
Some(discr) => {
|
||||
explicit_value = discr;
|
||||
break;
|
||||
}
|
||||
err => {
|
||||
if !expr_did.is_local() {
|
||||
span_bug!(tcx.def_span(expr_did),
|
||||
"variant discriminant evaluation succeeded \
|
||||
in its crate but failed locally: {:?}", err);
|
||||
}
|
||||
},
|
||||
None => {
|
||||
if explicit_index == 0 {
|
||||
break;
|
||||
}
|
||||
|
@ -1894,18 +1939,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
|||
}
|
||||
}
|
||||
}
|
||||
let discr = explicit_value.to_u128_unchecked()
|
||||
.wrapping_add((variant_index - explicit_index) as u128);
|
||||
match repr_type {
|
||||
attr::UnsignedInt(ty) => {
|
||||
ConstInt::new_unsigned_truncating(discr, ty,
|
||||
tcx.sess.target.usize_ty)
|
||||
}
|
||||
attr::SignedInt(ty) => {
|
||||
ConstInt::new_signed_truncating(discr as i128, ty,
|
||||
tcx.sess.target.isize_ty)
|
||||
}
|
||||
}
|
||||
explicit_value.checked_add(tcx, (variant_index - explicit_index) as u128).0
|
||||
}
|
||||
|
||||
pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> {
|
||||
|
|
|
@ -20,6 +20,7 @@ use ty::subst::{UnpackedKind, Substs};
|
|||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use ty::fold::{TypeVisitor, TypeFolder};
|
||||
use ty::error::{ExpectedFound, TypeError};
|
||||
use mir::interpret::{GlobalId, Value, PrimVal};
|
||||
use util::common::ErrorReported;
|
||||
use std::rc::Rc;
|
||||
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);
|
||||
let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
|
||||
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) => {
|
||||
// FIXME(eddyb) get the right param_env.
|
||||
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
|
||||
match tcx.lift_to_global(&substs) {
|
||||
Some(substs) => {
|
||||
match tcx.const_eval(param_env.and((def_id, substs))) {
|
||||
Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => {
|
||||
return Ok(x.to_u64().unwrap());
|
||||
let instance = ty::Instance::resolve(
|
||||
tcx.global_tcx(),
|
||||
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 => {}
|
||||
}
|
||||
tcx.sess.delay_span_bug(tcx.def_span(def_id),
|
||||
|
|
|
@ -13,11 +13,12 @@
|
|||
//! hand, though we've recently added some macros (e.g.,
|
||||
//! `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::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
use mir::interpret;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -56,6 +57,7 @@ CopyImpls! {
|
|||
::syntax::abi::Abi,
|
||||
::hir::def_id::DefId,
|
||||
::mir::Local,
|
||||
::mir::Promoted,
|
||||
::traits::Reveal,
|
||||
::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> {
|
||||
type Lifted = ConstEvalErr<'tcx>;
|
||||
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 {
|
||||
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> {
|
||||
type Lifted = const_val::ErrKind<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
use middle::const_val::ErrKind::*;
|
||||
|
||||
Some(match *self {
|
||||
CannotCast => CannotCast,
|
||||
MissingStructField => MissingStructField,
|
||||
NonConstPath => NonConstPath,
|
||||
UnimplementedConstVal(s) => UnimplementedConstVal(s),
|
||||
ExpectedConstTuple => ExpectedConstTuple,
|
||||
ExpectedConstStruct => ExpectedConstStruct,
|
||||
IndexedNonVec => IndexedNonVec,
|
||||
IndexNotUsize => IndexNotUsize,
|
||||
IndexOutOfBounds { len, index } => IndexOutOfBounds { len, index },
|
||||
MiscBinaryOp => MiscBinaryOp,
|
||||
MiscCatchAll => MiscCatchAll,
|
||||
IndexOpFeatureGated => IndexOpFeatureGated,
|
||||
Math(ref e) => Math(e.clone()),
|
||||
|
||||
LayoutError(ref e) => {
|
||||
return tcx.lift(e).map(LayoutError)
|
||||
}
|
||||
ErroneousReferencedConstant(ref e) => {
|
||||
return tcx.lift(e).map(ErroneousReferencedConstant)
|
||||
}
|
||||
|
||||
TypeckError => TypeckError,
|
||||
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.
|
||||
//
|
||||
|
@ -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> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
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> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
match *self {
|
||||
ConstVal::Integral(i) => ConstVal::Integral(i),
|
||||
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::Value(v) => ConstVal::Value(v),
|
||||
ConstVal::Unevaluated(def_id, substs) => {
|
||||
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 {
|
||||
match *self {
|
||||
ConstVal::Integral(_) |
|
||||
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::Value(_) => false,
|
||||
ConstVal::Unevaluated(_, substs) => substs.visit_with(visitor),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let TraitImpls {
|
||||
ref blanket_impls,
|
||||
|
|
|
@ -22,58 +22,96 @@ use ty::fold::TypeVisitor;
|
|||
use ty::subst::{Subst, UnpackedKind};
|
||||
use ty::maps::TyCtxtAt;
|
||||
use ty::TypeVariants::*;
|
||||
use ty::layout::Integer;
|
||||
use util::common::ErrorReported;
|
||||
use middle::lang_items;
|
||||
use mir::interpret::{Value, PrimVal};
|
||||
|
||||
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
|
||||
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
|
||||
HashStable};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use std::cmp;
|
||||
use std::{cmp, fmt};
|
||||
use std::hash::Hash;
|
||||
use std::intrinsics;
|
||||
use syntax::ast::{self, Name};
|
||||
use syntax::attr::{self, SignedInt, UnsignedInt};
|
||||
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 {
|
||||
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>)
|
||||
-> Option<Disr>;
|
||||
fn assert_ty_matches(&self, val: Disr);
|
||||
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!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Discr<'tcx>>)
|
||||
-> Option<Discr<'tcx>>;
|
||||
fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Discr<'tcx>;
|
||||
}
|
||||
|
||||
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 {
|
||||
typed_literal!(tcx, *self, 0)
|
||||
}
|
||||
|
||||
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 initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Discr<'tcx> {
|
||||
Discr {
|
||||
val: 0,
|
||||
ty: self.to_ty(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
|
||||
-> Option<Disr> {
|
||||
fn disr_incr<'a, 'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
val: Option<Discr<'tcx>>,
|
||||
) -> Option<Discr<'tcx>> {
|
||||
if let Some(val) = val {
|
||||
self.assert_ty_matches(val);
|
||||
(val + typed_literal!(tcx, *self, 1)).ok()
|
||||
assert_eq!(self.to_ty(tcx), val.ty);
|
||||
let (new, oflo) = val.checked_add(tcx, 1);
|
||||
if oflo {
|
||||
None
|
||||
} else {
|
||||
Some(new)
|
||||
}
|
||||
} else {
|
||||
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 {
|
||||
match self.sess.target.usize_ty {
|
||||
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 {
|
||||
/// Return whether the node pointed to by def_id is a static item, and its mutability
|
||||
pub fn is_static(&self, def_id: DefId) -> Option<hir::Mutability> {
|
||||
if let Some(node) = self.hir.get_if_local(def_id) {
|
||||
match node {
|
||||
Node::NodeItem(&hir::Item {
|
||||
node: hir::ItemStatic(_, hir::MutMutable, _), ..
|
||||
}) => true,
|
||||
node: hir::ItemStatic(_, mutbl, _), ..
|
||||
}) => Some(mutbl),
|
||||
Node::NodeForeignItem(&hir::ForeignItem {
|
||||
node: hir::ForeignItemStatic(_, mutbl), ..
|
||||
}) => mutbl,
|
||||
_ => false
|
||||
node: hir::ForeignItemStatic(_, is_mutbl), ..
|
||||
}) =>
|
||||
Some(if is_mutbl {
|
||||
hir::Mutability::MutMutable
|
||||
} else {
|
||||
hir::Mutability::MutImmutable
|
||||
}),
|
||||
_ => None
|
||||
}
|
||||
} else {
|
||||
match self.describe_def(def_id) {
|
||||
Some(Def::Static(_, mutbl)) => mutbl,
|
||||
_ => false
|
||||
Some(Def::Static(_, is_mutbl)) =>
|
||||
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) => {
|
||||
self.hash_discriminant_u8(&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),
|
||||
_ => bug!("arrays should not have {:?} as length", n)
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
//! An iterator over the type substructure.
|
||||
//! 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 rustc_data_structures::small_vec::SmallVec;
|
||||
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>) {
|
||||
match constant.val {
|
||||
ConstVal::Integral(_) |
|
||||
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::Value(_) => {}
|
||||
ConstVal::Unevaluated(_, substs) => {
|
||||
stack.extend(substs.types().rev());
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use middle::const_val::{ConstVal, ConstAggregate};
|
||||
use middle::const_val::ConstVal;
|
||||
use infer::InferCtxt;
|
||||
use ty::subst::Substs;
|
||||
use traits;
|
||||
|
@ -217,28 +217,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
|
|||
fn compute_const(&mut self, constant: &'tcx ty::Const<'tcx>) {
|
||||
self.require_sized(constant.ty, traits::ConstSized);
|
||||
match constant.val {
|
||||
ConstVal::Integral(_) |
|
||||
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::Value(_) => {}
|
||||
ConstVal::Unevaluated(def_id, substs) => {
|
||||
let obligations = self.nominal_obligations(def_id, substs);
|
||||
self.out.extend(obligations);
|
||||
|
|
|
@ -21,12 +21,12 @@ use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, Ty
|
|||
use ty::{TyDynamic, TyInt, TyUint, TyInfer};
|
||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use util::nodemap::FxHashSet;
|
||||
use mir::interpret::{Value, PrimVal};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::fmt;
|
||||
use std::usize;
|
||||
|
||||
use rustc_const_math::ConstInt;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use syntax::abi::Abi;
|
||||
use syntax::ast::CRATE_NODE_ID;
|
||||
|
@ -1165,7 +1165,7 @@ define_print! {
|
|||
TyArray(ty, sz) => {
|
||||
print!(f, cx, write("["), print(ty), write("; "))?;
|
||||
match sz.val {
|
||||
ConstVal::Integral(ConstInt::Usize(sz)) => {
|
||||
ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => {
|
||||
write!(f, "{}", sz)?;
|
||||
}
|
||||
ConstVal::Unevaluated(_def_id, substs) => {
|
||||
|
|
|
@ -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" }
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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))),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,13 +29,7 @@ extern crate syntax;
|
|||
extern crate serialize as rustc_serialize; // used by deriving
|
||||
|
||||
mod float;
|
||||
mod int;
|
||||
mod usize;
|
||||
mod isize;
|
||||
mod err;
|
||||
|
||||
pub use float::*;
|
||||
pub use int::*;
|
||||
pub use usize::*;
|
||||
pub use isize::*;
|
||||
pub use err::{ConstMathErr, Op};
|
||||
|
|
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,) {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
ctx: &mut CTX,
|
||||
|
|
|
@ -17,7 +17,6 @@ rustc = { path = "../librustc" }
|
|||
rustc_allocator = { path = "../librustc_allocator" }
|
||||
rustc_back = { path = "../librustc_back" }
|
||||
rustc_borrowck = { path = "../librustc_borrowck" }
|
||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
rustc_incremental = { path = "../librustc_incremental" }
|
||||
|
|
|
@ -36,8 +36,7 @@ use rustc_typeck as typeck;
|
|||
use rustc_privacy;
|
||||
use rustc_plugin::registry::Registry;
|
||||
use rustc_plugin as plugin;
|
||||
use rustc_passes::{self, ast_validation, loops, consts, hir_stats};
|
||||
use rustc_const_eval::{self, check_match};
|
||||
use rustc_passes::{self, ast_validation, loops, rvalue_promotion, hir_stats};
|
||||
use super::Compilation;
|
||||
|
||||
use serialize::json;
|
||||
|
@ -942,7 +941,6 @@ pub fn default_provide(providers: &mut ty::maps::Providers) {
|
|||
ty::provide(providers);
|
||||
traits::provide(providers);
|
||||
reachable::provide(providers);
|
||||
rustc_const_eval::provide(providers);
|
||||
rustc_passes::provide(providers);
|
||||
middle::region::provide(providers);
|
||||
cstore::provide(providers);
|
||||
|
@ -1038,8 +1036,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate,
|
|||
}
|
||||
|
||||
time(time_passes,
|
||||
"const checking",
|
||||
|| consts::check_crate(tcx));
|
||||
"rvalue promotion",
|
||||
|| rvalue_promotion::check_crate(tcx));
|
||||
|
||||
analysis.access_levels =
|
||||
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,
|
||||
"match checking",
|
||||
|| check_match::check_crate(tcx));
|
||||
|| mir::matchck_crate(tcx));
|
||||
|
||||
// this must run before MIR dump, because
|
||||
// "not all control paths return a value" is reported here.
|
||||
|
|
|
@ -35,7 +35,6 @@ extern crate rustc;
|
|||
extern crate rustc_allocator;
|
||||
extern crate rustc_back;
|
||||
extern crate rustc_borrowck;
|
||||
extern crate rustc_const_eval;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_errors as errors;
|
||||
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
|
||||
// all_errors.extend_from_slice(get_trans(sess).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_passes::DIAGNOSTICS);
|
||||
all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS);
|
||||
|
@ -1576,8 +1574,14 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
|
|||
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();
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
init_rustc_env_logger();
|
||||
let result = run(|| {
|
||||
let args = env::args_os().enumerate()
|
||||
.map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| {
|
||||
|
|
|
@ -12,6 +12,6 @@ test = false
|
|||
[dependencies]
|
||||
log = "0.4"
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
||||
rustc_mir = { path = "../librustc_mir"}
|
||||
syntax = { path = "../libsyntax" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
|
|
|
@ -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! {
|
||||
pub UNUSED_DOC_COMMENT,
|
||||
Warn,
|
||||
|
|
|
@ -39,11 +39,10 @@ extern crate syntax;
|
|||
extern crate rustc;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate rustc_const_eval;
|
||||
extern crate rustc_mir;
|
||||
extern crate syntax_pos;
|
||||
|
||||
use rustc::lint;
|
||||
use rustc::middle;
|
||||
use rustc::session;
|
||||
use rustc::util;
|
||||
|
||||
|
@ -107,7 +106,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
|||
UnusedParens,
|
||||
UnusedImportBraces,
|
||||
AnonymousParameters,
|
||||
IllegalFloatLiteralPattern,
|
||||
UnusedDocComment,
|
||||
);
|
||||
|
||||
|
|
|
@ -14,8 +14,6 @@ use rustc::hir::map as hir_map;
|
|||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
|
||||
use rustc::ty::layout::{self, LayoutOf};
|
||||
use middle::const_val::ConstVal;
|
||||
use rustc_const_eval::ConstContext;
|
||||
use util::nodemap::FxHashSet;
|
||||
use lint::{LateContext, LintContext, LintArray};
|
||||
use lint::{LintPass, LateLintPass};
|
||||
|
@ -23,7 +21,7 @@ use lint::{LintPass, LateLintPass};
|
|||
use std::cmp;
|
||||
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_pos::Span;
|
||||
use syntax::codemap;
|
||||
|
@ -42,12 +40,6 @@ declare_lint! {
|
|||
"literal out of range for its type"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
EXCEEDING_BITSHIFTS,
|
||||
Deny,
|
||||
"shift exceeds the type's number of bits"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
VARIANT_SIZE_DIFFERENCES,
|
||||
Allow,
|
||||
|
@ -69,8 +61,7 @@ impl TypeLimits {
|
|||
impl LintPass for TypeLimits {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(UNUSED_COMPARISONS,
|
||||
OVERFLOWING_LITERALS,
|
||||
EXCEEDING_BITSHIFTS)
|
||||
OVERFLOWING_LITERALS)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,49 +80,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
|||
e.span,
|
||||
"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) => {
|
||||
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,
|
||||
binop: hir::BinOp,
|
||||
l: &hir::Expr,
|
||||
|
@ -439,12 +365,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
|||
) {
|
||||
let (t, actually) = match ty {
|
||||
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);
|
||||
(format!("{:?}", t), actually.to_string())
|
||||
}
|
||||
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);
|
||||
(format!("{:?}", t), actually.to_string())
|
||||
}
|
||||
|
|
|
@ -664,6 +664,16 @@ extern "C" {
|
|||
pub fn LLVMConstShl(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
|
||||
pub fn LLVMConstLShr(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 LLVMConstZExt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
|
||||
pub fn LLVMConstUIToFP(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
|
||||
|
|
|
@ -21,14 +21,15 @@ use rustc::middle::cstore::{LinkagePreference, ExternConstBody,
|
|||
use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
|
||||
use rustc::hir::def::{self, Def, CtorKind};
|
||||
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::middle::lang_items;
|
||||
use rustc::mir;
|
||||
use rustc::mir::{self, interpret};
|
||||
use rustc::session::Session;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::codec::TyDecoder;
|
||||
use rustc::mir::Mir;
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
|
||||
use std::cell::Ref;
|
||||
use std::collections::BTreeMap;
|
||||
|
@ -54,6 +55,9 @@ pub struct DecodeContext<'a, 'tcx: 'a> {
|
|||
last_filemap_index: usize,
|
||||
|
||||
lazy_state: LazyState,
|
||||
|
||||
// interpreter allocation cache
|
||||
interpret_alloc_cache: FxHashMap<usize, interpret::AllocId>,
|
||||
}
|
||||
|
||||
/// Abstract over the various ways one can create metadata decoders.
|
||||
|
@ -72,6 +76,7 @@ pub trait Metadata<'a, 'tcx>: Copy {
|
|||
tcx,
|
||||
last_filemap_index: 0,
|
||||
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> {
|
||||
fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
|
||||
let tag = u8::decode(self)?;
|
||||
|
|
|
@ -16,14 +16,14 @@ use schema::*;
|
|||
use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary,
|
||||
EncodedMetadata};
|
||||
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::ich::Fingerprint;
|
||||
use rustc::middle::dependency_format::Linkage;
|
||||
use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel,
|
||||
metadata_symbol_name};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::mir;
|
||||
use rustc::mir::{self, interpret};
|
||||
use rustc::traits::specialization_graph;
|
||||
use rustc::ty::{self, Ty, TyCtxt, ReprOptions, SymbolName};
|
||||
use rustc::ty::codec::{self as ty_codec, TyEncoder};
|
||||
|
@ -59,6 +59,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> {
|
|||
lazy_state: LazyState,
|
||||
type_shorthands: FxHashMap<Ty<'tcx>, usize>,
|
||||
predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
|
||||
interpret_alloc_shorthands: FxHashMap<interpret::AllocId, usize>,
|
||||
|
||||
// This is used to speed up Span encoding.
|
||||
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> {
|
||||
fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> {
|
||||
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> {
|
||||
fn specialized_encode(&mut self,
|
||||
predicates: &ty::GenericPredicates<'tcx>)
|
||||
|
@ -1117,7 +1154,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
|||
_ => None,
|
||||
},
|
||||
mir: match item.node {
|
||||
hir::ItemStatic(..) if self.tcx.sess.opts.debugging_opts.always_encode_mir => {
|
||||
hir::ItemStatic(..) => {
|
||||
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(),
|
||||
predicate_shorthands: Default::default(),
|
||||
filemap_cache: tcx.sess.codemap().files()[0].clone(),
|
||||
interpret_alloc_shorthands: Default::default(),
|
||||
};
|
||||
|
||||
// Encode the rustc version string in a predictable location.
|
||||
|
|
|
@ -227,9 +227,9 @@ pub struct TraitImpls {
|
|||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let TraitImpls {
|
||||
trait_id: (krate, def_index),
|
||||
|
@ -310,9 +310,9 @@ pub enum EntryKind<'tcx> {
|
|||
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,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
|
|
|
@ -9,13 +9,13 @@ path = "lib.rs"
|
|||
crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
arena = { path = "../libarena" }
|
||||
bitflags = "1.0"
|
||||
graphviz = { path = "../libgraphviz" }
|
||||
log = "0.4"
|
||||
log_settings = "0.1.1"
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_back = { path = "../librustc_back" }
|
||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
||||
rustc_const_math = { path = "../librustc_const_math" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
|
|
|
@ -1635,11 +1635,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
Mutability::Mut => Ok(()),
|
||||
}
|
||||
}
|
||||
Place::Static(ref static_) => if !self.tcx.is_static_mut(static_.def_id) {
|
||||
Err(place)
|
||||
} else {
|
||||
Ok(())
|
||||
},
|
||||
Place::Static(ref static_) =>
|
||||
if self.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
|
||||
Err(place)
|
||||
} else {
|
||||
Ok(())
|
||||
},
|
||||
Place::Projection(ref proj) => {
|
||||
match proj.elem {
|
||||
ProjectionElem::Deref => {
|
||||
|
@ -1792,7 +1793,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
if static1.def_id != static2.def_id {
|
||||
debug!("place_element_conflict: DISJOINT-STATIC");
|
||||
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.
|
||||
debug!("place_element_conflict: IGNORE-STATIC-MUT");
|
||||
Overlap::Disjoint
|
||||
|
|
|
@ -24,7 +24,6 @@ use rustc::traits::{self, FulfillmentContext};
|
|||
use rustc::ty::error::TypeError;
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::tcx::PlaceTy;
|
||||
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
|
||||
// would be lost if we just look at the normalized
|
||||
// value.
|
||||
if let ConstVal::Function(def_id, ..) = value.val {
|
||||
if let ty::TyFnDef(def_id, substs) = value.ty.sty {
|
||||
let tcx = self.tcx();
|
||||
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
|
||||
// don't have a handy function for that, so for
|
||||
// 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 =
|
||||
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 {
|
||||
ty: match base_ty.sty {
|
||||
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);
|
||||
if let Some(rest_size) = size.checked_sub(min_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 {
|
||||
match operand {
|
||||
&Operand::Constant(box Constant {
|
||||
literal:
|
||||
Literal::Value {
|
||||
value:
|
||||
&ty::Const {
|
||||
val: ConstVal::Function(def_id, _),
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
..
|
||||
}) => Some(def_id) == self.tcx().lang_items().box_free_fn(),
|
||||
match *operand {
|
||||
Operand::Constant(ref c) => match c.ty.sty {
|
||||
ty::TyFnDef(ty_def_id, _) => {
|
||||
Some(ty_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)
|
||||
}
|
||||
|
||||
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 trait_ref = ty::TraitRef {
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
|
||||
//! See docs in build/expr/mod.rs
|
||||
|
||||
use std;
|
||||
|
||||
use rustc_const_math::{ConstMathErr, Op};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
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::expr::category::{Category, RvalueFunc};
|
||||
use hair::*;
|
||||
use rustc_const_math::{ConstInt, ConstIsize};
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::middle::region;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::mir::*;
|
||||
use syntax::ast;
|
||||
use rustc::mir::interpret::{Value, PrimVal};
|
||||
use syntax_pos::Span;
|
||||
|
||||
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,
|
||||
literal: Literal::Value {
|
||||
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
|
||||
}),
|
||||
},
|
||||
|
@ -384,31 +381,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
|
||||
// Helper to get a `-1` value of the appropriate type
|
||||
fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||
let literal = match ty.sty {
|
||||
ty::TyInt(ity) => {
|
||||
let val = match ity {
|
||||
ast::IntTy::I8 => ConstInt::I8(-1),
|
||||
ast::IntTy::I16 => ConstInt::I16(-1),
|
||||
ast::IntTy::I32 => ConstInt::I32(-1),
|
||||
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)
|
||||
}
|
||||
let bits = self.hir.integer_bit_width(ty);
|
||||
let n = (!0u128) >> (128 - bits);
|
||||
let literal = Literal::Value {
|
||||
value: self.hir.tcx().mk_const(ty::Const {
|
||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
|
||||
ty
|
||||
})
|
||||
};
|
||||
|
||||
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
|
||||
fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||
let literal = match ty.sty {
|
||||
ty::TyInt(ity) => {
|
||||
let val = match ity {
|
||||
ast::IntTy::I8 => ConstInt::I8(i8::min_value()),
|
||||
ast::IntTy::I16 => ConstInt::I16(i16::min_value()),
|
||||
ast::IntTy::I32 => ConstInt::I32(i32::min_value()),
|
||||
ast::IntTy::I64 => ConstInt::I64(i64::min_value()),
|
||||
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)
|
||||
}
|
||||
assert!(ty.is_signed());
|
||||
let bits = self.hir.integer_bit_width(ty);
|
||||
let n = 1 << (bits - 1);
|
||||
let literal = Literal::Value {
|
||||
value: self.hir.tcx().mk_const(ty::Const {
|
||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
|
||||
ty
|
||||
})
|
||||
};
|
||||
|
||||
self.literal_operand(span, ty, literal)
|
||||
|
|
|
@ -354,7 +354,7 @@ enum TestKind<'tcx> {
|
|||
// test the branches of enum
|
||||
SwitchInt {
|
||||
switch_ty: Ty<'tcx>,
|
||||
options: Vec<&'tcx ty::Const<'tcx>>,
|
||||
options: Vec<u128>,
|
||||
indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
|
||||
},
|
||||
|
||||
|
|
|
@ -20,11 +20,10 @@ use build::matches::{Candidate, MatchPair, Test, TestKind};
|
|||
use hair::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::bitvec::BitVector;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::util::IntTypeExt;
|
||||
use rustc::mir::*;
|
||||
use rustc::hir::RangeEnd;
|
||||
use rustc::hir::{RangeEnd, Mutability};
|
||||
use syntax_pos::Span;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
|
@ -112,7 +111,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
test_place: &Place<'tcx>,
|
||||
candidate: &Candidate<'pat, 'tcx>,
|
||||
switch_ty: Ty<'tcx>,
|
||||
options: &mut Vec<&'tcx ty::Const<'tcx>>,
|
||||
options: &mut Vec<u128>,
|
||||
indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>)
|
||||
-> bool
|
||||
{
|
||||
|
@ -128,7 +127,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
|
||||
indices.entry(value)
|
||||
.or_insert_with(|| {
|
||||
options.push(value);
|
||||
options.push(value.val.to_raw_bits().expect("switching on int"));
|
||||
options.len() - 1
|
||||
});
|
||||
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.
|
||||
pub fn perform_test(&mut self,
|
||||
block: BasicBlock,
|
||||
|
@ -231,7 +197,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let tcx = self.hir.tcx();
|
||||
for (idx, discr) in adt_def.discriminants(tcx).enumerate() {
|
||||
target_blocks.place_back() <- if variants.contains(idx) {
|
||||
values.push(discr);
|
||||
values.push(discr.val);
|
||||
*(targets.place_back() <- self.cfg.start_new_block())
|
||||
} else {
|
||||
if otherwise_block.is_none() {
|
||||
|
@ -266,9 +232,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
assert!(options.len() > 0 && options.len() <= 2);
|
||||
let (true_bb, false_bb) = (self.cfg.start_new_block(),
|
||||
self.cfg.start_new_block());
|
||||
let ret = match options[0].val {
|
||||
ConstVal::Bool(true) => vec![true_bb, false_bb],
|
||||
ConstVal::Bool(false) => vec![false_bb, true_bb],
|
||||
let ret = match options[0] {
|
||||
1 => vec![true_bb, false_bb],
|
||||
0 => vec![false_bb, true_bb],
|
||||
v => span_bug!(test.span, "expected boolean value but got {:?}", v)
|
||||
};
|
||||
(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())
|
||||
.chain(Some(otherwise))
|
||||
.collect();
|
||||
let values: Vec<_> = options.iter().map(|v|
|
||||
v.val.to_const_int().expect("switching on integral")
|
||||
).collect();
|
||||
(targets.clone(), TerminatorKind::SwitchInt {
|
||||
discr: Operand::Copy(place.clone()),
|
||||
switch_ty,
|
||||
values: From::from(values),
|
||||
values: options.clone().into(),
|
||||
targets,
|
||||
})
|
||||
};
|
||||
|
@ -296,41 +259,88 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
ret
|
||||
}
|
||||
|
||||
TestKind::Eq { value, ty } => {
|
||||
let tcx = self.hir.tcx();
|
||||
TestKind::Eq { value, mut ty } => {
|
||||
let mut val = Operand::Copy(place.clone());
|
||||
|
||||
// If we're using b"..." as a pattern, we need to insert an
|
||||
// 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 (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 mut expect = self.literal_operand(test.span, ty, Literal::Value {
|
||||
value
|
||||
});
|
||||
// Use PartialEq::eq instead of BinOp::Eq
|
||||
// (the binop can only handle primitives)
|
||||
let fail = self.cfg.start_new_block();
|
||||
let ty = expect.ty(&self.local_decls, tcx);
|
||||
if let ty::TyRef(_, mt) = ty.sty {
|
||||
assert!(ty.is_slice());
|
||||
if !ty.is_scalar() {
|
||||
// If we're using b"..." as a pattern, we need to insert an
|
||||
// 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 ty = mt.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 eq_result = self.temp(bool_ty, test.span);
|
||||
let eq_block = self.cfg.start_new_block();
|
||||
|
|
|
@ -13,12 +13,11 @@
|
|||
|
||||
use build::Builder;
|
||||
|
||||
use rustc_const_math::{ConstInt, ConstUsize, ConstIsize};
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::mir::interpret::{Value, PrimVal};
|
||||
|
||||
use rustc::mir::*;
|
||||
use syntax::ast;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
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
|
||||
// bool, char and integers.
|
||||
pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||
let literal = match ty.sty {
|
||||
ty::TyBool => {
|
||||
self.hir.false_literal()
|
||||
}
|
||||
ty::TyChar => {
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
match ty.sty {
|
||||
ty::TyBool |
|
||||
ty::TyChar |
|
||||
ty::TyUint(_) |
|
||||
ty::TyInt(_) => {}
|
||||
_ => {
|
||||
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)
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
use build;
|
||||
use hair::cx::Cx;
|
||||
use hair::LintLevel;
|
||||
use hair::{LintLevel, BindingMode, PatternKind};
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::{DefId, LocalDefId};
|
||||
use rustc::middle::region;
|
||||
|
@ -21,7 +21,6 @@ use rustc::ty::{self, Ty, TyCtxt};
|
|||
use rustc::ty::subst::Substs;
|
||||
use rustc::util::nodemap::NodeMap;
|
||||
use rustc_back::PanicStrategy;
|
||||
use rustc_const_eval::pattern::{BindingMode, PatternKind};
|
||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
use shim;
|
||||
use std::mem;
|
||||
|
|
|
@ -783,7 +783,7 @@ fn is_unsafe_place<'a, 'gcx: 'tcx, 'tcx: 'a>(
|
|||
|
||||
match *place {
|
||||
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) => {
|
||||
match proj.elem {
|
||||
ProjectionElem::Field(..) |
|
||||
|
|
|
@ -12,6 +12,541 @@
|
|||
|
||||
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##"
|
||||
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
|
||||
|
@ -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##"
|
||||
Closures cannot mutate immutable captured variables.
|
||||
|
||||
|
@ -1771,6 +2324,9 @@ b.resume();
|
|||
}
|
||||
|
||||
register_diagnostics! {
|
||||
// E0298, // cannot compare constants
|
||||
// E0299, // mismatched types between arms
|
||||
// E0471, // constant evaluation error (in pattern)
|
||||
// E0385, // {} in an aliasable location
|
||||
E0493, // destructors cannot be evaluated at compile-time
|
||||
E0524, // two closures require unique access to `..` at the same time
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
|
||||
use hair::*;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_const_math::ConstInt;
|
||||
use hair::cx::Cx;
|
||||
use hair::cx::block;
|
||||
use hair::cx::to_ref::ToRef;
|
||||
use rustc::hir::def::{Def, CtorKind};
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::mir::interpret::{GlobalId, Value, PrimVal};
|
||||
use rustc::ty::{self, AdtKind, VariantDef, Ty};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
|
||||
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() }
|
||||
}
|
||||
Adjust::Deref(Some(deref)) => {
|
||||
let call = deref.method_call(cx.tcx, expr.ty);
|
||||
let call = deref.method_call(cx.tcx(), expr.ty);
|
||||
|
||||
expr = Expr {
|
||||
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) => {
|
||||
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) {
|
||||
overloaded_operator(cx, expr, vec![arg.to_ref()])
|
||||
} else {
|
||||
// FIXME runtime-overflow
|
||||
if let hir::ExprLit(_) = arg.node {
|
||||
ExprKind::Literal { literal: cx.const_eval_literal(expr) }
|
||||
if let hir::ExprLit(ref lit) = arg.node {
|
||||
ExprKind::Literal {
|
||||
literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true),
|
||||
}
|
||||
} else {
|
||||
ExprKind::Unary {
|
||||
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 def_id = cx.tcx.hir.body_owner_def_id(count);
|
||||
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))) {
|
||||
Ok(&ty::Const { val: ConstVal::Integral(ConstInt::Usize(u)), .. }) => u,
|
||||
Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
|
||||
Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
|
||||
let instance = ty::Instance::resolve(
|
||||
cx.tcx.global_tcx(),
|
||||
cx.param_env,
|
||||
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 {
|
||||
|
@ -634,8 +649,8 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
span: expr.span,
|
||||
kind: ExprKind::Literal {
|
||||
literal: Literal::Value {
|
||||
value: cx.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Function(def_id, substs),
|
||||
value: cx.tcx().mk_const(ty::Const {
|
||||
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
|
||||
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);
|
||||
match def {
|
||||
// A regular function, constructor function or a constant.
|
||||
Def::Fn(def_id) |
|
||||
Def::Method(def_id) |
|
||||
Def::StructCtor(def_id, CtorKind::Fn) |
|
||||
Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal {
|
||||
Def::Fn(_) |
|
||||
Def::Method(_) |
|
||||
Def::StructCtor(_, CtorKind::Fn) |
|
||||
Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
|
||||
literal: Literal::Value {
|
||||
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)
|
||||
}),
|
||||
},
|
||||
|
|
|
@ -16,22 +16,22 @@
|
|||
|
||||
use hair::*;
|
||||
|
||||
use rustc::middle::const_val::{ConstEvalErr, ConstVal};
|
||||
use rustc_const_eval::ConstContext;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc::hir::map::blocks::FnLikeNode;
|
||||
use rustc::middle::region;
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::{self, Ty, TyCtxt, layout};
|
||||
use rustc::ty::subst::Substs;
|
||||
use syntax::ast;
|
||||
use syntax::ast::{self, LitKind};
|
||||
use syntax::attr;
|
||||
use syntax::symbol::Symbol;
|
||||
use rustc::hir;
|
||||
use rustc_const_math::{ConstInt, ConstUsize};
|
||||
use rustc_const_math::ConstFloat;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc::mir::interpret::{Value, PrimVal};
|
||||
|
||||
#[derive(Clone)]
|
||||
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> {
|
||||
match ConstUsize::new(value, self.tcx.sess.target.usize_ty) {
|
||||
Ok(val) => {
|
||||
Literal::Value {
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Integral(ConstInt::Usize(val)),
|
||||
ty: self.tcx.types.usize
|
||||
})
|
||||
}
|
||||
}
|
||||
Err(_) => bug!("usize literal out of range for target"),
|
||||
Literal::Value {
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))),
|
||||
ty: self.tcx.types.usize
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +134,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
|||
pub fn true_literal(&mut self) -> Literal<'tcx> {
|
||||
Literal::Value {
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Bool(true),
|
||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))),
|
||||
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> {
|
||||
Literal::Value {
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Bool(false),
|
||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
|
||||
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 const_cx = ConstContext::new(tcx,
|
||||
self.param_env.and(self.identity_substs),
|
||||
self.tables());
|
||||
match const_cx.eval(tcx.hir.expect_expr(e.id)) {
|
||||
Ok(value) => Literal::Value { value },
|
||||
Err(s) => self.fatal_const_eval_err(&s, e.span, "expression")
|
||||
|
||||
let parse_float = |num: &str, fty| -> ConstFloat {
|
||||
ConstFloat::from_str(num, fty).unwrap_or_else(|_| {
|
||||
// FIXME(#31407) this is only necessary because float parsing is buggy
|
||||
tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)");
|
||||
})
|
||||
};
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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,
|
||||
trait_def_id: DefId,
|
||||
method_name: &str,
|
||||
|
@ -203,7 +271,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
|||
return (method_ty,
|
||||
Literal::Value {
|
||||
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
|
||||
}),
|
||||
});
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
//! unit-tested and separated from the Rust source and compiler data
|
||||
//! structures.
|
||||
|
||||
use rustc_const_math::ConstUsize;
|
||||
use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp};
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::region;
|
||||
|
@ -27,7 +26,8 @@ use self::cx::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)]
|
||||
pub enum LintLevel {
|
||||
|
@ -246,7 +246,7 @@ pub enum ExprKind<'tcx> {
|
|||
},
|
||||
Repeat {
|
||||
value: ExprRef<'tcx>,
|
||||
count: ConstUsize,
|
||||
count: u64,
|
||||
},
|
||||
Array {
|
||||
fields: Vec<ExprRef<'tcx>>,
|
||||
|
|
|
@ -13,21 +13,19 @@ use self::Usefulness::*;
|
|||
use self::WitnessPreference::*;
|
||||
|
||||
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::indexed_vec::Idx;
|
||||
|
||||
use pattern::{FieldPattern, Pattern, PatternKind};
|
||||
use pattern::{PatternFoldable, PatternFolder};
|
||||
use super::{FieldPattern, Pattern, PatternKind};
|
||||
use super::{PatternFoldable, PatternFolder, compare_const_vals};
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::RangeEnd;
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
|
||||
use rustc::mir::Field;
|
||||
use rustc::mir::interpret::{Value, PrimVal};
|
||||
use rustc::util::common::ErrorReported;
|
||||
|
||||
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(|| {
|
||||
match pat.kind {
|
||||
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 {
|
||||
ty: tcx.types.u8,
|
||||
span: pat.span,
|
||||
kind: box PatternKind::Constant {
|
||||
value: tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Integral(ConstInt::U8(b)),
|
||||
ty: tcx.types.u8
|
||||
})
|
||||
}
|
||||
})).collect()
|
||||
match b {
|
||||
Value::ByVal(PrimVal::Ptr(ptr)) => {
|
||||
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);
|
||||
let alloc = tcx
|
||||
.interpret_interner
|
||||
.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)
|
||||
}
|
||||
|
@ -422,13 +440,13 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
|||
ty::TyBool => {
|
||||
[true, false].iter().map(|&b| {
|
||||
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
|
||||
}))
|
||||
}).collect()
|
||||
}
|
||||
ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => {
|
||||
let len = len.val.to_const_int().unwrap().to_u64().unwrap();
|
||||
ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => {
|
||||
let len = len.val.unwrap_u64();
|
||||
if len != 0 && cx.is_uninhabited(sub_ty) {
|
||||
vec![]
|
||||
} 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>(
|
||||
_cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
patterns: I) -> u64
|
||||
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 {
|
||||
match *row.kind {
|
||||
PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => {
|
||||
max_fixed_len = cmp::max(max_fixed_len, b.data.len() as u64);
|
||||
PatternKind::Constant {
|
||||
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 } => {
|
||||
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)
|
||||
-> Usefulness<'tcx> {
|
||||
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
|
||||
// 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])))
|
||||
};
|
||||
|
||||
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) {
|
||||
debug!("is_useful - expanding constructors: {:?}", constructors);
|
||||
debug!("is_useful - expanding constructors: {:#?}", constructors);
|
||||
constructors.into_iter().map(|c|
|
||||
is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
|
||||
).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| {
|
||||
pat_constructors(cx, row[0], pcx).unwrap_or(vec![])
|
||||
}).collect();
|
||||
debug!("used_ctors = {:?}", used_ctors);
|
||||
debug!("used_ctors = {:#?}", used_ctors);
|
||||
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| {
|
||||
!used_ctors.contains(*c)
|
||||
}).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);
|
||||
let is_declared_nonexhaustive =
|
||||
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);
|
||||
|
||||
// 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>,
|
||||
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 wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| {
|
||||
Pattern {
|
||||
|
@ -821,7 +854,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
|
|||
Some(vec![ConstantRange(lo, hi, end)]),
|
||||
PatternKind::Array { .. } => match pcx.ty.sty {
|
||||
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)
|
||||
},
|
||||
|
@ -842,7 +875,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
|
|||
/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
|
||||
/// A struct pattern's arity is the number of fields it contains, etc.
|
||||
fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
|
||||
debug!("constructor_arity({:?}, {:?})", ctor, ty);
|
||||
debug!("constructor_arity({:#?}, {:?})", ctor, ty);
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref fs, _) => fs.len() as u64,
|
||||
ty::TySlice(..) | ty::TyArray(..) => match *ctor {
|
||||
|
@ -866,7 +899,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
|||
ctor: &Constructor,
|
||||
ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
|
||||
{
|
||||
debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty);
|
||||
debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(),
|
||||
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,
|
||||
prefix: &[Pattern],
|
||||
slice: &Option<Pattern>,
|
||||
suffix: &[Pattern])
|
||||
-> Result<bool, ErrorReported> {
|
||||
let data = match *ctor {
|
||||
ConstantValue(&ty::Const { val: ConstVal::ByteStr(b), .. }) => b.data,
|
||||
let data: &[u8] = match *ctor {
|
||||
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!()
|
||||
};
|
||||
|
||||
|
@ -923,11 +970,12 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
|
|||
{
|
||||
match pat.kind {
|
||||
box PatternKind::Constant { value } => match value.val {
|
||||
ConstVal::Integral(ConstInt::U8(u)) => {
|
||||
if u != *ch {
|
||||
ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
|
||||
assert_eq!(b as u8 as u128, b);
|
||||
if b as u8 != *ch {
|
||||
return Ok(false);
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => span_bug!(pat.span, "bad const u8 {:?}", value)
|
||||
},
|
||||
_ => {}
|
||||
|
@ -937,31 +985,41 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
|
|||
Ok(true)
|
||||
}
|
||||
|
||||
fn constructor_covered_by_range(tcx: TyCtxt, span: Span,
|
||||
ctor: &Constructor,
|
||||
fn constructor_covered_by_range(ctor: &Constructor,
|
||||
from: &ConstVal, to: &ConstVal,
|
||||
end: RangeEnd)
|
||||
end: RangeEnd,
|
||||
ty: Ty)
|
||||
-> Result<bool, ErrorReported> {
|
||||
let cmp_from = |c_from| Ok(compare_const_vals(tcx, span, c_from, from)? != Ordering::Less);
|
||||
let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to);
|
||||
trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty);
|
||||
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 {
|
||||
ConstantValue(value) => {
|
||||
let to = cmp_to(&value.val)?;
|
||||
let to = some_or_ok!(cmp_to(&value.val));
|
||||
let end = (to == Ordering::Less) ||
|
||||
(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) => {
|
||||
let to = cmp_to(&to.val)?;
|
||||
let to = some_or_ok!(cmp_to(&to.val));
|
||||
let end = (to == Ordering::Less) ||
|
||||
(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) => {
|
||||
let to = cmp_to(&to.val)?;
|
||||
let to = some_or_ok!(cmp_to(&to.val));
|
||||
let end = (to == Ordering::Less) ||
|
||||
(end == RangeEnd::Excluded && to == Ordering::Equal);
|
||||
Ok(cmp_from(&from.val)? && end)
|
||||
Ok(some_or_ok!(cmp_from(&from.val)) && end)
|
||||
}
|
||||
Single => Ok(true),
|
||||
_ => bug!(),
|
||||
|
@ -979,7 +1037,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
|
|||
result[subpat.field.index()] = &subpat.pattern;
|
||||
}
|
||||
|
||||
debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, wild_patterns, result);
|
||||
debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result);
|
||||
result
|
||||
}
|
||||
|
||||
|
@ -994,7 +1052,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
|
|||
fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
||||
cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
r: &[&'p Pattern<'tcx>],
|
||||
constructor: &Constructor,
|
||||
constructor: &Constructor<'tcx>,
|
||||
wild_patterns: &[&'p Pattern<'tcx>])
|
||||
-> Option<Vec<&'p Pattern<'tcx>>>
|
||||
{
|
||||
|
@ -1024,8 +1082,19 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
|||
PatternKind::Constant { value } => {
|
||||
match *constructor {
|
||||
Slice(..) => match value.val {
|
||||
ConstVal::ByteStr(b) => {
|
||||
if wild_patterns.len() == b.data.len() {
|
||||
ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => {
|
||||
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))
|
||||
} else {
|
||||
None
|
||||
|
@ -1036,7 +1105,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
|||
},
|
||||
_ => {
|
||||
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(false) => None,
|
||||
|
@ -1048,7 +1118,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
|||
|
||||
PatternKind::Range { lo, hi, ref end } => {
|
||||
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(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.extend_from_slice(&r[1 ..]);
|
|
@ -8,11 +8,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
|
||||
use _match::Usefulness::*;
|
||||
use _match::WitnessPreference::*;
|
||||
use super::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
|
||||
use super::_match::Usefulness::*;
|
||||
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::{LoanCause, MutateMode};
|
||||
|
@ -138,8 +138,18 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
PatternError::AssociatedConstInPattern(span) => {
|
||||
self.span_e0158(span, "associated consts cannot be referenced in patterns")
|
||||
}
|
||||
PatternError::ConstEval(ref err) => {
|
||||
err.report(self.tcx, pat_span, "pattern");
|
||||
PatternError::FloatBug => {
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,10 +8,19 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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::interpret::{GlobalId, Value, PrimVal};
|
||||
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
|
||||
use rustc::ty::subst::{Substs, Kind};
|
||||
use rustc::hir::{self, PatKind, RangeEnd};
|
||||
|
@ -19,17 +28,20 @@ use rustc::hir::def::{Def, CtorKind};
|
|||
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_const_math::ConstFloat;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use syntax::ast;
|
||||
use syntax::ptr::P;
|
||||
use syntax_pos::Span;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PatternError<'tcx> {
|
||||
pub enum PatternError {
|
||||
AssociatedConstInPattern(Span),
|
||||
StaticInPattern(Span),
|
||||
ConstEval(ConstEvalErr<'tcx>),
|
||||
FloatBug,
|
||||
NonConstPath(Span),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -110,21 +122,26 @@ pub enum PatternKind<'tcx> {
|
|||
},
|
||||
}
|
||||
|
||||
fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *value {
|
||||
ConstVal::Float(ref x) => write!(f, "{}", x),
|
||||
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(_) |
|
||||
fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match value.val {
|
||||
ConstVal::Value(v) => print_miri_value(v, value.ty, f),
|
||||
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> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self.kind {
|
||||
|
@ -232,15 +249,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
|||
write!(f, "{}", subpattern)
|
||||
}
|
||||
PatternKind::Constant { value } => {
|
||||
print_const_val(&value.val, f)
|
||||
print_const_val(value, f)
|
||||
}
|
||||
PatternKind::Range { lo, hi, end } => {
|
||||
print_const_val(&lo.val, f)?;
|
||||
print_const_val(lo, f)?;
|
||||
match end {
|
||||
RangeEnd::Included => 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::Array { ref prefix, ref slice, ref suffix } => {
|
||||
|
@ -272,7 +289,7 @@ pub struct PatternContext<'a, 'tcx: 'a> {
|
|||
pub param_env: ty::ParamEnv<'tcx>,
|
||||
pub tables: &'a ty::TypeckTables<'tcx>,
|
||||
pub substs: &'tcx Substs<'tcx>,
|
||||
pub errors: Vec<PatternError<'tcx>>,
|
||||
pub errors: Vec<PatternError>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Pattern<'tcx> {
|
||||
|
@ -350,18 +367,53 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
|
||||
PatKind::Lit(ref value) => self.lower_lit(value),
|
||||
|
||||
PatKind::Range(ref lo, ref hi, end) => {
|
||||
match (self.lower_lit(lo), self.lower_lit(hi)) {
|
||||
PatKind::Range(ref lo_expr, ref hi_expr, end) => {
|
||||
match (self.lower_lit(lo_expr), self.lower_lit(hi_expr)) {
|
||||
(PatternKind::Constant { value: lo },
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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, _) |
|
||||
|
@ -471,7 +523,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
pattern: self.lower_pattern(field),
|
||||
})
|
||||
.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, _) => {
|
||||
|
@ -503,7 +555,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
})
|
||||
.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) => {
|
||||
// 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);
|
||||
PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
|
||||
}
|
||||
|
@ -594,6 +646,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
fn lower_variant_or_leaf(
|
||||
&mut self,
|
||||
def: Def,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
subpatterns: Vec<FieldPattern<'tcx>>)
|
||||
-> PatternKind<'tcx>
|
||||
|
@ -624,14 +677,19 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
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,
|
||||
qpath: &hir::QPath,
|
||||
id: hir::HirId,
|
||||
pat_id: ast::NodeId,
|
||||
span: Span)
|
||||
-> Pattern<'tcx> {
|
||||
let ty = self.tables.node_id_to_type(id);
|
||||
|
@ -643,23 +701,27 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
let kind = match def {
|
||||
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
|
||||
let substs = self.tables.node_substs(id);
|
||||
match eval::lookup_const_by_id(self.tcx, self.param_env.and((def_id, substs))) {
|
||||
Some((def_id, substs)) => {
|
||||
// Enter the inlined constant's tables&substs temporarily.
|
||||
let old_tables = self.tables;
|
||||
let old_substs = self.substs;
|
||||
self.tables = self.tcx.typeck_tables_of(def_id);
|
||||
self.substs = substs;
|
||||
let body = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
|
||||
self.tcx.hir.body(self.tcx.hir.body_owned_by(id))
|
||||
} else {
|
||||
self.tcx.extern_const_body(def_id).body
|
||||
match ty::Instance::resolve(
|
||||
self.tcx,
|
||||
self.param_env,
|
||||
def_id,
|
||||
substs,
|
||||
) {
|
||||
Some(instance) => {
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: None,
|
||||
};
|
||||
let pat = self.lower_const_expr(&body.value, pat_id, span);
|
||||
self.tables = old_tables;
|
||||
self.substs = old_substs;
|
||||
return pat;
|
||||
}
|
||||
match self.tcx.at(span).const_eval(self.param_env.and(cid)) {
|
||||
Ok(value) => {
|
||||
return self.const_to_pat(instance, value, id, span)
|
||||
},
|
||||
Err(err) => {
|
||||
err.report(self.tcx, span, "pattern");
|
||||
PatternKind::Wild
|
||||
},
|
||||
}
|
||||
},
|
||||
None => {
|
||||
self.errors.push(if is_associated_const {
|
||||
PatternError::AssociatedConstInPattern(span)
|
||||
|
@ -667,10 +729,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
PatternError::StaticInPattern(span)
|
||||
});
|
||||
PatternKind::Wild
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
_ => self.lower_variant_or_leaf(def, ty, vec![]),
|
||||
_ => self.lower_variant_or_leaf(def, span, ty, vec![]),
|
||||
};
|
||||
|
||||
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> {
|
||||
let const_cx = eval::ConstContext::new(self.tcx,
|
||||
self.param_env.and(self.substs),
|
||||
self.tables);
|
||||
match const_cx.eval(expr) {
|
||||
Ok(value) => {
|
||||
if let ConstVal::Variant(def_id) = value.val {
|
||||
let ty = self.tables.expr_ty(expr);
|
||||
self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![])
|
||||
} else {
|
||||
PatternKind::Constant { value }
|
||||
match expr.node {
|
||||
hir::ExprLit(ref lit) => {
|
||||
let ty = self.tables.expr_ty(expr);
|
||||
match lit_to_const(&lit.node, self.tcx, ty, false) {
|
||||
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
|
||||
},
|
||||
}
|
||||
},
|
||||
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) => {
|
||||
self.errors.push(PatternError::ConstEval(e));
|
||||
PatternKind::Wild
|
||||
}
|
||||
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_const_expr(&mut self,
|
||||
expr: &'tcx hir::Expr,
|
||||
pat_id: ast::NodeId,
|
||||
span: Span)
|
||||
-> Pattern<'tcx> {
|
||||
let pat_ty = self.tables.expr_ty(expr);
|
||||
debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
|
||||
match pat_ty.sty {
|
||||
/// Converts an evaluated constant to a pattern (if possible).
|
||||
/// This means aggregate values (like structs and enums) are converted
|
||||
/// to a pattern that matches the value (as if you'd compare via eq).
|
||||
fn const_to_pat(
|
||||
&self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
cv: &'tcx ty::Const<'tcx>,
|
||||
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(_) => {
|
||||
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() => {
|
||||
// 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");
|
||||
PatternKind::Wild
|
||||
}
|
||||
ty::TyAdt(adt_def, _) => {
|
||||
if !self.tcx.has_attr(adt_def.did, "structural_match") {
|
||||
let msg = format!("to use a constant of type `{}` in a pattern, \
|
||||
`{}` 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.sess.span_err(span, &msg);
|
||||
}
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
let kind = match expr.node {
|
||||
hir::ExprTup(ref exprs) => {
|
||||
PatternKind::Leaf {
|
||||
subpatterns: exprs.iter().enumerate().map(|(i, expr)| {
|
||||
FieldPattern {
|
||||
field: Field::new(i),
|
||||
pattern: self.lower_const_expr(expr, pat_id, span)
|
||||
ty::TyAdt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => {
|
||||
let msg = format!("to use a constant of type `{}` in a pattern, \
|
||||
`{}` 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.sess.span_err(span, &msg);
|
||||
PatternKind::Wild
|
||||
},
|
||||
ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
|
||||
match cv.val {
|
||||
ConstVal::Value(val) => {
|
||||
let discr = const_discr(
|
||||
self.tcx, self.param_env, instance, val, cv.ty
|
||||
).unwrap();
|
||||
let variant_index = adt_def
|
||||
.discriminants(self.tcx)
|
||||
.position(|var| var.val == discr)
|
||||
.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),
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprCall(ref callee, ref args) => {
|
||||
let qpath = match callee.node {
|
||||
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::TyTuple(fields, _) => {
|
||||
PatternKind::Leaf {
|
||||
subpatterns: adt_subpatterns(fields.len(), None),
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
ty::TyArray(_, n) => {
|
||||
PatternKind::Array {
|
||||
prefix: pats,
|
||||
prefix: (0..n.val.unwrap_u64())
|
||||
.map(|i| adt_subpattern(i as usize, None))
|
||||
.collect(),
|
||||
slice: None,
|
||||
suffix: vec![]
|
||||
suffix: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprPath(ref qpath) => {
|
||||
return self.lower_path(qpath, expr.hir_id, pat_id, span);
|
||||
}
|
||||
|
||||
_ => self.lower_lit(expr)
|
||||
_ => {
|
||||
PatternKind::Constant {
|
||||
value: cv,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Pattern {
|
||||
span,
|
||||
ty: pat_ty,
|
||||
ty: cv.ty,
|
||||
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(|_| ())
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
use rustc::ty::Ty;
|
||||
use rustc::ty::layout::LayoutOf;
|
||||
use syntax::ast::{FloatTy, IntTy, UintTy};
|
||||
|
||||
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::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(
|
||||
&self,
|
||||
val: PrimVal,
|
||||
src_ty: Ty<'tcx>,
|
||||
dest_ty: Ty<'tcx>,
|
||||
) -> EvalResult<'tcx, PrimVal> {
|
||||
use rustc::ty::TypeVariants::*;
|
||||
trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
|
||||
let src_kind = self.ty_to_primval_kind(src_ty)?;
|
||||
|
||||
match val {
|
||||
PrimVal::Undef => Ok(PrimVal::Undef),
|
||||
PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
|
||||
val @ PrimVal::Bytes(_) => {
|
||||
use rustc::mir::interpret::PrimValKind::*;
|
||||
match src_kind {
|
||||
F32 => self.cast_from_float(val.to_f32()?, 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)
|
||||
}
|
||||
PrimVal::Bytes(b) => {
|
||||
match src_ty.sty {
|
||||
TyFloat(fty) => self.cast_from_float(b, fty, dest_ty),
|
||||
_ => self.cast_from_int(b, src_ty, dest_ty),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
&self,
|
||||
v: u128,
|
||||
ty: Ty<'tcx>,
|
||||
negative: bool,
|
||||
src_ty: Ty<'tcx>,
|
||||
dest_ty: Ty<'tcx>,
|
||||
) -> 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::*;
|
||||
match ty.sty {
|
||||
// Casts to bool are not permitted by rustc, no need to handle them here.
|
||||
TyInt(ty) => Ok(PrimVal::Bytes(self.int_to_int(v as i128, ty))),
|
||||
TyUint(ty) => Ok(PrimVal::Bytes(self.int_to_uint(v, ty))),
|
||||
match dest_ty.sty {
|
||||
TyInt(_) | TyUint(_) => {
|
||||
let v = self.truncate(v, dest_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)),
|
||||
|
||||
TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
|
||||
TyChar => err!(InvalidChar(v)),
|
||||
|
||||
// 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::*;
|
||||
match ty.sty {
|
||||
use rustc_apfloat::FloatConvert;
|
||||
match dest_ty.sty {
|
||||
// float -> uint
|
||||
TyUint(t) => {
|
||||
let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
|
||||
match val.ty {
|
||||
FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(val.bits).to_u128(width).value)),
|
||||
FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(val.bits).to_u128(width).value)),
|
||||
match fty {
|
||||
FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(bits).to_u128(width).value)),
|
||||
FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(bits).to_u128(width).value)),
|
||||
}
|
||||
},
|
||||
|
||||
// float -> int
|
||||
TyInt(t) => {
|
||||
let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
|
||||
match val.ty {
|
||||
FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(val.bits).to_i128(width).value)),
|
||||
FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(val.bits).to_i128(width).value)),
|
||||
match fty {
|
||||
FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(bits).to_i128(width).value)),
|
||||
FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(bits).to_i128(width).value)),
|
||||
}
|
||||
},
|
||||
|
||||
TyFloat(fty) => Ok(PrimVal::from_float(val.convert(fty))),
|
||||
_ => err!(Unimplemented(format!("float to {:?} cast", ty))),
|
||||
// f64 -> f32
|
||||
TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
|
||||
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))),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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::layout::{self, LayoutOf};
|
||||
use rustc::ty::subst::Substs;
|
||||
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 rustc::ty::subst::Subst;
|
||||
|
||||
use syntax::ast::Mutability;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal};
|
||||
use super::{Place, EvalContext, StackPopCleanup, ValTy};
|
||||
|
||||
use rustc_const_math::ConstInt;
|
||||
use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal, AllocId};
|
||||
use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory};
|
||||
|
||||
use std::fmt;
|
||||
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>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
instance: Instance<'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);
|
||||
let limits = super::ResourceLimits::default();
|
||||
let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ());
|
||||
let span = tcx.def_span(instance.def_id());
|
||||
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
|
||||
let mir = ecx.load_mir(instance.def)?;
|
||||
// insert a stack frame so any queries have the correct substs
|
||||
ecx.push_stack_frame(
|
||||
|
@ -41,99 +56,115 @@ pub fn mk_eval_cx<'a, 'tcx>(
|
|||
Ok(ecx)
|
||||
}
|
||||
|
||||
pub fn eval_body<'a, 'tcx>(
|
||||
pub fn eval_body_with_mir<'a, 'mir, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
cid: GlobalId<'tcx>,
|
||||
mir: &'mir mir::Mir<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> EvalResult<'tcx, (Pointer, Ty<'tcx>)> {
|
||||
debug!("eval_body: {:?}, {:?}", instance, param_env);
|
||||
let limits = super::ResourceLimits::default();
|
||||
let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ());
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: None,
|
||||
};
|
||||
|
||||
if ecx.tcx.has_attr(instance.def_id(), "linkage") {
|
||||
return Err(ConstEvalError::NotConst("extern global".to_string()).into());
|
||||
) -> Option<(Value, Pointer, Ty<'tcx>)> {
|
||||
let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env);
|
||||
match res {
|
||||
Ok(val) => Some(val),
|
||||
Err(mut err) => {
|
||||
ecx.report(&mut err, true, None);
|
||||
None
|
||||
}
|
||||
}
|
||||
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>,
|
||||
cid: GlobalId<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
) -> EvalResult<'tcx, ConstInt> {
|
||||
let ptr_ty = eval_body(tcx, instance, param_env);
|
||||
let (ptr, ty) = ptr_ty?;
|
||||
let ecx = mk_eval_cx(tcx, instance, param_env)?;
|
||||
let prim = match ecx.try_read_value(ptr, ecx.layout_of(ty)?.align, ty)? {
|
||||
Some(Value::ByVal(prim)) => prim.to_bytes()?,
|
||||
_ => 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(),
|
||||
)
|
||||
) -> Option<(Value, Pointer, Ty<'tcx>)> {
|
||||
let (res, ecx) = eval_body_and_ecx(tcx, cid, None, param_env);
|
||||
match res {
|
||||
Ok(val) => Some(val),
|
||||
Err(mut err) => {
|
||||
ecx.report(&mut err, true, None);
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
|
||||
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
|
||||
)
|
||||
}
|
||||
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 MemoryKinds = !;
|
||||
fn eval_fn_call<'a>(
|
||||
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
destination: Option<(Place, mir::BasicBlock)>,
|
||||
_args: &[ValTy<'tcx>],
|
||||
args: &[ValTy<'tcx>],
|
||||
span: Span,
|
||||
_sig: ty::FnSig<'tcx>,
|
||||
sig: ty::FnSig<'tcx>,
|
||||
) -> EvalResult<'tcx, bool> {
|
||||
debug!("eval_fn_call: {:?}", instance);
|
||||
if !ecx.tcx.is_const_fn(instance.def_id()) {
|
||||
return Err(
|
||||
ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(),
|
||||
);
|
||||
let def_id = instance.def_id();
|
||||
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) {
|
||||
Ok(mir) => mir,
|
||||
Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => {
|
||||
// some simple things like `malloc` might get accepted in the future
|
||||
return Err(
|
||||
ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
|
||||
.into(),
|
||||
);
|
||||
Err(err) => {
|
||||
if let EvalErrorKind::NoMirFor(ref path) = err.kind {
|
||||
return Err(
|
||||
ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
Err(other) => return Err(other),
|
||||
};
|
||||
let (return_place, return_to_block) = match destination {
|
||||
Some((place, block)) => (place, StackPopCleanup::Goto(block)),
|
||||
|
@ -219,7 +265,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
|
|||
|
||||
|
||||
fn call_intrinsic<'a>(
|
||||
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
_args: &[ValTy<'tcx>],
|
||||
dest: Place,
|
||||
|
@ -261,7 +307,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
|
|||
}
|
||||
|
||||
fn try_ptr_op<'a>(
|
||||
_ecx: &EvalContext<'a, 'tcx, Self>,
|
||||
_ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
_bin_op: mir::BinOp,
|
||||
left: PrimVal,
|
||||
_left_ty: Ty<'tcx>,
|
||||
|
@ -277,12 +323,29 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
|
|||
}
|
||||
}
|
||||
|
||||
fn mark_static_initialized(m: !) -> EvalResult<'tcx> {
|
||||
m
|
||||
fn mark_static_initialized<'a>(
|
||||
_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>(
|
||||
_ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
_ty: Ty<'tcx>,
|
||||
_dest: Place,
|
||||
) -> EvalResult<'tcx> {
|
||||
|
@ -292,7 +355,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
|
|||
}
|
||||
|
||||
fn global_item_with_linkage<'a>(
|
||||
_ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
_instance: ty::Instance<'tcx>,
|
||||
_mutability: Mutability,
|
||||
) -> 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>(
|
||||
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> {
|
||||
trace!("const eval: {:?}", key);
|
||||
let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, key) {
|
||||
resolved
|
||||
} else {
|
||||
return Err(ConstEvalErr {
|
||||
span: tcx.def_span(key.value.0),
|
||||
kind: TypeckError
|
||||
});
|
||||
};
|
||||
let cid = key.value;
|
||||
let def_id = cid.instance.def.def_id();
|
||||
|
||||
let tables = tcx.typeck_tables_of(def_id);
|
||||
let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
|
||||
let body_id = tcx.hir.body_owned_by(id);
|
||||
if tcx.is_foreign_item(def_id) {
|
||||
let id = tcx.interpret_interner.get_cached(def_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
|
||||
if tcx.check_match(def_id).is_err() {
|
||||
return Err(ConstEvalErr {
|
||||
span: tcx.def_span(key.value.0),
|
||||
kind: CheckMatchError,
|
||||
kind: Rc::new(CheckMatchError),
|
||||
span,
|
||||
});
|
||||
}
|
||||
|
||||
tcx.mir_const_qualif(def_id);
|
||||
tcx.hir.body(body_id)
|
||||
} else {
|
||||
tcx.extern_const_body(def_id).body
|
||||
if let hir::BodyOwnerKind::Const = tcx.hir.body_owner_kind(id) {
|
||||
tcx.mir_const_qualif(def_id);
|
||||
}
|
||||
|
||||
// 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
|
||||
// it will fail horribly
|
||||
if tables.tainted_by_errors {
|
||||
return Err(ConstEvalErr { span: body.value.span, kind: TypeckError })
|
||||
}
|
||||
|
||||
trace!("running old const eval");
|
||||
let old_result = ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value);
|
||||
trace!("old const eval produced {:?}", old_result);
|
||||
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)
|
||||
}
|
||||
let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
|
||||
res.map(|(miri_value, _, miri_ty)| {
|
||||
tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Value(miri_value),
|
||||
ty: miri_ty,
|
||||
})
|
||||
}).map_err(|mut err| {
|
||||
if tcx.is_static(def_id).is_some() {
|
||||
ecx.report(&mut err, true, None);
|
||||
}
|
||||
} else {
|
||||
old_result
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
let (trace, span) = ecx.generate_stacktrace(None);
|
||||
let err = ErrKind::Miri(err, trace);
|
||||
ConstEvalErr {
|
||||
kind: err.into(),
|
||||
span,
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,14 +3,15 @@ use std::fmt::Write;
|
|||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::map::definitions::DefPathData;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::middle::const_val::{ConstVal, ErrKind};
|
||||
use rustc::mir;
|
||||
use rustc::traits::Reveal;
|
||||
use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout};
|
||||
use rustc::ty::subst::{Subst, Substs};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::maps::TyCtxtAt;
|
||||
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 rustc::mir::interpret::{
|
||||
GlobalId, Value, Pointer, PrimVal, PrimValKind,
|
||||
|
@ -18,41 +19,41 @@ use rustc::mir::interpret::{
|
|||
};
|
||||
|
||||
use super::{Place, PlaceExtra, Memory,
|
||||
HasMemory, MemoryKind, operator,
|
||||
HasMemory, MemoryKind,
|
||||
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.
|
||||
pub machine: M,
|
||||
|
||||
/// 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.
|
||||
pub param_env: ty::ParamEnv<'tcx>,
|
||||
|
||||
/// The virtual memory system.
|
||||
pub memory: Memory<'a, 'tcx, M>,
|
||||
pub memory: Memory<'a, 'mir, 'tcx, M>,
|
||||
|
||||
/// The virtual call stack.
|
||||
pub(crate) stack: Vec<Frame<'tcx>>,
|
||||
pub(crate) stack: Vec<Frame<'mir, 'tcx>>,
|
||||
|
||||
/// The maximum number of stack frames allowed
|
||||
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.
|
||||
/// Remove once halting problem is solved.
|
||||
pub(crate) steps_remaining: u64,
|
||||
pub(crate) steps_remaining: usize,
|
||||
}
|
||||
|
||||
/// A stack frame.
|
||||
pub struct Frame<'tcx> {
|
||||
pub struct Frame<'mir, 'tcx: 'mir> {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Function and callsite information
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// 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
|
||||
pub instance: ty::Instance<'tcx>,
|
||||
|
@ -102,23 +103,6 @@ pub enum StackPopCleanup {
|
|||
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)]
|
||||
pub struct TyAndPacked<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
|
@ -131,6 +115,15 @@ pub struct ValTy<'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> {
|
||||
type Target = 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]
|
||||
fn data_layout(&self) -> &layout::TargetDataLayout {
|
||||
&self.tcx.data_layout
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> HasDataLayout
|
||||
for &'c &'b mut EvalContext<'a, 'tcx, M> {
|
||||
impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout
|
||||
for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
|
||||
#[inline]
|
||||
fn data_layout(&self) -> &layout::TargetDataLayout {
|
||||
&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]
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
|
||||
self.tcx
|
||||
*self.tcx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> layout::HasTyCtxt<'tcx>
|
||||
for &'c &'b mut EvalContext<'a, 'tcx, M> {
|
||||
impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx>
|
||||
for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
|
||||
#[inline]
|
||||
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>>;
|
||||
|
||||
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>>
|
||||
for &'c &'b mut EvalContext<'a, 'tcx, M> {
|
||||
impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf<Ty<'tcx>>
|
||||
for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
|
||||
type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
|
||||
|
||||
#[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(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
limits: ResourceLimits,
|
||||
machine: M,
|
||||
memory_data: M::MemoryData,
|
||||
) -> Self {
|
||||
|
@ -199,10 +191,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
machine,
|
||||
tcx,
|
||||
param_env,
|
||||
memory: Memory::new(tcx, limits.memory_size, memory_data),
|
||||
memory: Memory::new(tcx, memory_data),
|
||||
stack: Vec::new(),
|
||||
stack_limit: limits.stack_limit,
|
||||
steps_remaining: limits.step_limit,
|
||||
stack_limit: tcx.sess.const_eval_stack_frame_limit.get(),
|
||||
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))
|
||||
}
|
||||
|
||||
pub fn memory(&self) -> &Memory<'a, 'tcx, M> {
|
||||
pub fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
|
||||
&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
|
||||
}
|
||||
|
||||
pub fn stack(&self) -> &[Frame<'tcx>] {
|
||||
pub fn stack(&self) -> &[Frame<'mir, 'tcx>] {
|
||||
&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> {
|
||||
use rustc::middle::const_val::ConstVal::*;
|
||||
|
||||
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) => {
|
||||
pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
|
||||
match *const_val {
|
||||
ConstVal::Unevaluated(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,
|
||||
promoted: None,
|
||||
}, self.layout_of(ty)?));
|
||||
}, ty)
|
||||
}
|
||||
|
||||
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))
|
||||
ConstVal::Value(val) => Ok(val),
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
self.tcx,
|
||||
*self.tcx,
|
||||
self.param_env,
|
||||
def_id,
|
||||
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 {
|
||||
ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env)
|
||||
ty.is_sized(self.tcx, self.param_env)
|
||||
}
|
||||
|
||||
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
|
||||
// let's simply get rid of them
|
||||
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);
|
||||
substituted
|
||||
}
|
||||
|
@ -402,14 +375,14 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
span: codemap::Span,
|
||||
mir: &'tcx mir::Mir<'tcx>,
|
||||
mir: &'mir mir::Mir<'tcx>,
|
||||
return_place: Place,
|
||||
return_to_block: StackPopCleanup,
|
||||
) -> EvalResult<'tcx> {
|
||||
::log_settings::settings().indentation += 1;
|
||||
|
||||
/// 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::*;
|
||||
|
||||
let mut set = HashSet::new();
|
||||
|
@ -477,7 +450,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
StackPopCleanup::MarkStatic(mutable) => {
|
||||
if let Place::Ptr { ptr, .. } = frame.return_place {
|
||||
// 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,
|
||||
mutable,
|
||||
)?
|
||||
|
@ -563,16 +536,16 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
|
||||
UnaryOp(un_op, ref 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(
|
||||
dest,
|
||||
operator::unary_op(un_op, val, kind)?,
|
||||
val,
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
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 {
|
||||
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, _) => {
|
||||
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!(
|
||||
"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 \
|
||||
const arguments");
|
||||
}
|
||||
let instance = self.resolve(def_id, substs)?;
|
||||
let fn_ptr = self.memory.create_fn_alloc(instance);
|
||||
let instance: EvalResult<'tcx, _> = ty::Instance::resolve(
|
||||
*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 {
|
||||
value: Value::ByVal(PrimVal::Ptr(fn_ptr)),
|
||||
ty: dest_ty,
|
||||
|
@ -748,7 +726,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
ty::TyClosure(def_id, substs) => {
|
||||
let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs);
|
||||
let instance = ty::Instance::resolve_closure(
|
||||
self.tcx,
|
||||
*self.tcx,
|
||||
def_id,
|
||||
substs,
|
||||
ty::ClosureKind::FnOnce,
|
||||
|
@ -771,9 +749,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
let place = self.eval_place(place)?;
|
||||
let discr_val = self.read_discriminant_value(place, ty)?;
|
||||
if let ty::TyAdt(adt_def, _) = ty.sty {
|
||||
trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(self.tcx).collect::<Vec<_>>());
|
||||
if adt_def.discriminants(self.tcx).all(|v| {
|
||||
discr_val != v.to_u128_unchecked()
|
||||
trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(*self.tcx).collect::<Vec<_>>());
|
||||
if adt_def.discriminants(*self.tcx).all(|v| {
|
||||
discr_val != v.val
|
||||
})
|
||||
{
|
||||
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>> {
|
||||
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 {
|
||||
// FIXME: do some more logic on `move` to invalidate the old location
|
||||
Copy(ref place) |
|
||||
|
@ -841,7 +819,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
self.read_global_as_value(GlobalId {
|
||||
instance: self.frame().instance,
|
||||
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 { .. } => {
|
||||
let discr_val = dest_ty.ty_adt_def().unwrap()
|
||||
.discriminant_for_variant(self.tcx, variant_index)
|
||||
.to_u128_unchecked();
|
||||
.discriminant_for_variant(*self.tcx, variant_index)
|
||||
.val;
|
||||
|
||||
let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?;
|
||||
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(())
|
||||
}
|
||||
|
||||
pub fn read_global_as_value(&self, gid: GlobalId, layout: TyLayout) -> Value {
|
||||
let alloc = self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached");
|
||||
Value::ByRef(MemoryPointer::new(alloc, 0).into(), layout.align)
|
||||
pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
|
||||
if gid.promoted.is_none() {
|
||||
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> {
|
||||
|
@ -1121,20 +1128,22 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
dest_align: Align,
|
||||
dest_ty: Ty<'tcx>,
|
||||
) -> EvalResult<'tcx> {
|
||||
trace!("write_value_to_ptr: {:#?}", value);
|
||||
let layout = self.layout_of(dest_ty)?;
|
||||
trace!("write_value_to_ptr: {:#?}, {}, {:#?}", value, dest_ty, layout);
|
||||
match value {
|
||||
Value::ByRef(ptr, align) => {
|
||||
self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size.bytes(), false)
|
||||
}
|
||||
Value::ByVal(primval) => {
|
||||
match layout.abi {
|
||||
layout::Abi::Scalar(_) => {}
|
||||
_ if primval.is_undef() => {}
|
||||
let signed = match layout.abi {
|
||||
layout::Abi::Scalar(ref scal) => match scal.value {
|
||||
layout::Primitive::Int(_, signed) => signed,
|
||||
_ => false,
|
||||
},
|
||||
_ if primval.is_undef() => false,
|
||||
_ => 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(), false)
|
||||
};
|
||||
self.memory.write_primval(dest.to_ptr()?, dest_align, primval, layout.size.bytes(), signed)
|
||||
}
|
||||
Value::ByValPair(a_val, b_val) => {
|
||||
let ptr = dest.to_ptr()?;
|
||||
|
@ -1247,7 +1256,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
pointee_ty: Ty<'tcx>,
|
||||
) -> EvalResult<'tcx, Value> {
|
||||
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) {
|
||||
Ok(p.to_value())
|
||||
} else {
|
||||
|
@ -1255,11 +1264,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
let extra = ptr.offset(ptr_size, self)?;
|
||||
match self.tcx.struct_tail(pointee_ty).sty {
|
||||
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(
|
||||
p.to_value_with_len(self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_bytes()? as u64),
|
||||
),
|
||||
ty::TySlice(..) | ty::TyStr => {
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
@ -1271,7 +1284,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
let ptr = ptr.to_ptr()?;
|
||||
let val = match ty.sty {
|
||||
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 {
|
||||
PrimVal::Bytes(0) => false,
|
||||
PrimVal::Bytes(1) => true,
|
||||
|
@ -1281,7 +1294,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
PrimVal::from_bool(val)
|
||||
}
|
||||
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) {
|
||||
Some(ch) => PrimVal::from_char(ch),
|
||||
None => return err!(InvalidChar(c as u128)),
|
||||
|
@ -1298,7 +1311,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
I128 => 16,
|
||||
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) => {
|
||||
|
@ -1311,17 +1324,17 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
U128 => 16,
|
||||
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) => {
|
||||
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) => {
|
||||
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::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 {
|
||||
let mut signed = false;
|
||||
if let layout::Int(_, s) = scalar.value {
|
||||
signed = s;
|
||||
}
|
||||
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 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
@ -1348,15 +1357,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
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")
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
pub(super) fn mir(&self) -> &'tcx mir::Mir<'tcx> {
|
||||
pub(super) fn mir(&self) -> &'mir mir::Mir<'tcx> {
|
||||
self.frame().mir
|
||||
}
|
||||
|
||||
|
@ -1385,7 +1394,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
let ptr = self.into_ptr(src)?;
|
||||
// u64 cast is from usize to u64, which is always good
|
||||
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,
|
||||
};
|
||||
self.write_value(valty, dest)
|
||||
|
@ -1402,7 +1411,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
}
|
||||
(_, &ty::TyDynamic(ref data, _)) => {
|
||||
let trait_ref = data.principal().unwrap().with_self_ty(
|
||||
self.tcx,
|
||||
*self.tcx,
|
||||
src_pointee_ty,
|
||||
);
|
||||
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();
|
||||
|
||||
match self.stack[frame].get_local(local) {
|
||||
Err(EvalError { kind: EvalErrorKind::DeadLocal, .. }) => {
|
||||
write!(msg, " is dead").unwrap();
|
||||
}
|
||||
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)) => {
|
||||
match ptr.into_inner_primval() {
|
||||
|
@ -1566,7 +1576,40 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
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 {
|
||||
let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
|
||||
backtrace.resolve();
|
||||
|
@ -1599,29 +1642,60 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
}
|
||||
if let Some(frame) = self.stack().last() {
|
||||
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
|
||||
} else {
|
||||
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());
|
||||
for &Frame { instance, span, .. } in self.stack().iter().rev() {
|
||||
if self.tcx.def_key(instance.def_id()).disambiguated_data.data ==
|
||||
DefPathData::ClosureExpr
|
||||
{
|
||||
err.span_note(span, "inside call to closure");
|
||||
continue;
|
||||
}
|
||||
err.span_note(span, &format!("inside call to {}", instance));
|
||||
let (frames, span) = self.generate_stacktrace(explicit_span);
|
||||
err.span_label(span, e.to_string());
|
||||
for FrameInfo { span, location } in frames {
|
||||
err.span_note(span, &format!("inside call to `{}`", location));
|
||||
}
|
||||
err.emit();
|
||||
} else {
|
||||
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> {
|
||||
// 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())
|
||||
|
@ -1655,14 +1729,3 @@ impl<'tcx> Frame<'tcx> {
|
|||
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()
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//! This separation exists to ensure that no fancy miri features like
|
||||
//! 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 rustc::mir;
|
||||
|
@ -12,7 +12,7 @@ use syntax::ast::Mutability;
|
|||
|
||||
/// Methods of this trait signifies a point where CTFE evaluation would fail
|
||||
/// 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
|
||||
type MemoryData;
|
||||
|
||||
|
@ -26,7 +26,7 @@ pub trait Machine<'tcx>: Sized {
|
|||
///
|
||||
/// Returns Ok(false) if a new stack frame was pushed
|
||||
fn eval_fn_call<'a>(
|
||||
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
destination: Option<(Place, mir::BasicBlock)>,
|
||||
args: &[ValTy<'tcx>],
|
||||
|
@ -36,7 +36,7 @@ pub trait Machine<'tcx>: Sized {
|
|||
|
||||
/// directly process an intrinsic without pushing a stack frame.
|
||||
fn call_intrinsic<'a>(
|
||||
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[ValTy<'tcx>],
|
||||
dest: Place,
|
||||
|
@ -51,7 +51,7 @@ pub trait Machine<'tcx>: Sized {
|
|||
///
|
||||
/// Returns a (value, overflowed) pair if the operation succeeded
|
||||
fn try_ptr_op<'a>(
|
||||
ecx: &EvalContext<'a, 'tcx, Self>,
|
||||
ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
bin_op: mir::BinOp,
|
||||
left: PrimVal,
|
||||
left_ty: Ty<'tcx>,
|
||||
|
@ -60,26 +60,37 @@ pub trait Machine<'tcx>: Sized {
|
|||
) -> EvalResult<'tcx, Option<(PrimVal, bool)>>;
|
||||
|
||||
/// 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
|
||||
///
|
||||
/// Returns a pointer to the allocated memory
|
||||
fn box_alloc<'a>(
|
||||
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
ty: Ty<'tcx>,
|
||||
dest: Place,
|
||||
) -> EvalResult<'tcx>;
|
||||
|
||||
/// Called when trying to access a global declared with a `linkage` attribute
|
||||
fn global_item_with_linkage<'a>(
|
||||
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
mutability: Mutability,
|
||||
) -> EvalResult<'tcx>;
|
||||
|
||||
fn check_locks<'a>(
|
||||
_mem: &Memory<'a, 'tcx, Self>,
|
||||
_mem: &Memory<'a, 'mir, 'tcx, Self>,
|
||||
_ptr: MemoryPointer,
|
||||
_size: u64,
|
||||
_access: AccessKind,
|
||||
|
@ -88,12 +99,12 @@ pub trait Machine<'tcx>: Sized {
|
|||
}
|
||||
|
||||
fn add_lock<'a>(
|
||||
_mem: &mut Memory<'a, 'tcx, Self>,
|
||||
_mem: &mut Memory<'a, 'mir, 'tcx, Self>,
|
||||
_id: AllocId,
|
||||
) {}
|
||||
|
||||
fn free_lock<'a>(
|
||||
_mem: &mut Memory<'a, 'tcx, Self>,
|
||||
_mem: &mut Memory<'a, 'mir, 'tcx, Self>,
|
||||
_id: AllocId,
|
||||
_len: u64,
|
||||
) -> EvalResult<'tcx> {
|
||||
|
@ -101,14 +112,14 @@ pub trait Machine<'tcx>: Sized {
|
|||
}
|
||||
|
||||
fn end_region<'a>(
|
||||
_ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
_reg: Option<::rustc::middle::region::Scope>,
|
||||
) -> EvalResult<'tcx> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validation_op<'a>(
|
||||
_ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
_op: ::rustc::mir::ValidationOp,
|
||||
_operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>,
|
||||
) -> EvalResult<'tcx> {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian};
|
||||
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 syntax::ast::Mutability;
|
||||
|
||||
|
@ -19,8 +20,6 @@ use super::{EvalContext, Machine};
|
|||
pub enum MemoryKind<T> {
|
||||
/// Error if deallocated except during a stack pop
|
||||
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
|
||||
Machine(T),
|
||||
}
|
||||
|
@ -29,7 +28,7 @@ pub enum MemoryKind<T> {
|
|||
// 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
|
||||
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
|
||||
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.
|
||||
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> {
|
||||
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, max_memory: u64, data: M::MemoryData) -> Self {
|
||||
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
||||
pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self {
|
||||
Memory {
|
||||
data,
|
||||
alloc_kind: HashMap::new(),
|
||||
alloc_map: HashMap::new(),
|
||||
uninitialized_statics: HashMap::new(),
|
||||
tcx,
|
||||
memory_size: max_memory,
|
||||
memory_usage: 0,
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -93,22 +84,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
|||
align: Align,
|
||||
kind: Option<MemoryKind<M::MemoryKinds>>,
|
||||
) -> 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);
|
||||
let alloc = Allocation {
|
||||
bytes: vec![0; size as usize],
|
||||
relocations: BTreeMap::new(),
|
||||
undef_mask: UndefMask::new(size),
|
||||
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);
|
||||
match kind {
|
||||
Some(kind @ MemoryKind::Stack) |
|
||||
|
@ -119,7 +103,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
|||
None => {
|
||||
self.uninitialized_statics.insert(id, alloc);
|
||||
},
|
||||
Some(MemoryKind::MutableStatic) => bug!("don't allocate mutable statics directly")
|
||||
}
|
||||
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> {
|
||||
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),
|
||||
// Happens if the memory was interned into immutable memory
|
||||
None => Ok(()),
|
||||
|
@ -192,12 +171,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
|||
"uninitializedstatic".to_string(),
|
||||
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(
|
||||
"function".to_string(),
|
||||
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(
|
||||
"static".to_string(),
|
||||
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);
|
||||
|
||||
Ok(())
|
||||
|
@ -292,7 +270,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
|||
}
|
||||
|
||||
/// 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> {
|
||||
// normal alloc?
|
||||
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) {
|
||||
Some(alloc) => Ok(alloc),
|
||||
None => {
|
||||
let int = self.tcx.interpret_interner.borrow();
|
||||
// static alloc?
|
||||
int.get_alloc(id)
|
||||
self.tcx.interpret_interner.get_alloc(id)
|
||||
// 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()
|
||||
} else {
|
||||
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) {
|
||||
Some(alloc) => Ok(alloc),
|
||||
None => {
|
||||
let int = self.tcx.interpret_interner.borrow();
|
||||
// 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)
|
||||
} else if int.get_fn(id).is_some() {
|
||||
} else if self.tcx.interpret_interner.get_fn(id).is_some() {
|
||||
err!(DerefFunctionPointer)
|
||||
} else {
|
||||
err!(DanglingPointerDeref)
|
||||
|
@ -347,7 +323,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
|||
debug!("reading fn ptr: {}", ptr.alloc_id);
|
||||
self.tcx
|
||||
.interpret_interner
|
||||
.borrow()
|
||||
.get_fn(ptr.alloc_id)
|
||||
.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] {
|
||||
MemoryKind::Stack => " (stack)".to_owned(),
|
||||
MemoryKind::Machine(m) => format!(" ({:?})", m),
|
||||
MemoryKind::MutableStatic => " (static mut)".to_owned(),
|
||||
}),
|
||||
// uninitialized static alloc?
|
||||
None => match self.uninitialized_statics.get(&id) {
|
||||
Some(a) => (a, " (static in the process of initialization)".to_owned()),
|
||||
None => {
|
||||
let int = self.tcx.interpret_interner.borrow();
|
||||
// static alloc?
|
||||
match int.get_alloc(id) {
|
||||
match self.tcx.interpret_interner.get_alloc(id) {
|
||||
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);
|
||||
continue;
|
||||
continue;
|
||||
} else {
|
||||
trace!("{} (deallocated)", msg);
|
||||
continue;
|
||||
trace!("{} (deallocated)", msg);
|
||||
continue;
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
for i in 0..(alloc.bytes.len() as u64) {
|
||||
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 {
|
||||
trace!("### LEAK REPORT ###");
|
||||
let kinds = &self.alloc_kind;
|
||||
let leaks: Vec<_> = self.alloc_map
|
||||
.keys()
|
||||
.filter_map(|key| if kinds[key] != MemoryKind::MutableStatic {
|
||||
Some(*key)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
let n = leaks.len();
|
||||
self.dump_allocs(leaks);
|
||||
|
@ -457,7 +425,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
|||
}
|
||||
|
||||
/// 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(
|
||||
&self,
|
||||
ptr: MemoryPointer,
|
||||
|
@ -521,7 +489,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
|||
}
|
||||
|
||||
/// 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
|
||||
fn mark_inner_allocation_initialized(
|
||||
&mut self,
|
||||
|
@ -529,80 +497,47 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
|||
mutability: Mutability,
|
||||
) -> EvalResult<'tcx> {
|
||||
match self.alloc_kind.get(&alloc) {
|
||||
// do not go into immutable statics
|
||||
None |
|
||||
// or mutable statics
|
||||
Some(&MemoryKind::MutableStatic) => Ok(()),
|
||||
// do not go into statics
|
||||
None => Ok(()),
|
||||
// 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
|
||||
pub fn mark_static_initalized(
|
||||
pub fn mark_static_initialized(
|
||||
&mut self,
|
||||
alloc_id: AllocId,
|
||||
mutability: Mutability,
|
||||
) -> EvalResult<'tcx> {
|
||||
trace!(
|
||||
"mark_static_initalized {:?}, mutability: {:?}",
|
||||
"mark_static_initialized {:?}, mutability: {:?}",
|
||||
alloc_id,
|
||||
mutability
|
||||
);
|
||||
if mutability == Mutability::Immutable {
|
||||
let alloc = self.alloc_map.remove(&alloc_id);
|
||||
let kind = self.alloc_kind.remove(&alloc_id);
|
||||
assert_ne!(kind, Some(MemoryKind::MutableStatic));
|
||||
let uninit = self.uninitialized_statics.remove(&alloc_id);
|
||||
if let Some(alloc) = alloc.or(uninit) {
|
||||
let alloc = self.tcx.intern_const_alloc(alloc);
|
||||
self.tcx.interpret_interner.borrow_mut().intern_at_reserved(alloc_id, alloc);
|
||||
// recurse into inner allocations
|
||||
for &alloc in alloc.relocations.values() {
|
||||
self.mark_inner_allocation_initialized(alloc, mutability)?;
|
||||
}
|
||||
// The machine handled it
|
||||
if M::mark_static_initialized(self, alloc_id, mutability)? {
|
||||
return Ok(())
|
||||
}
|
||||
let alloc = self.alloc_map.remove(&alloc_id);
|
||||
match self.alloc_kind.remove(&alloc_id) {
|
||||
None => {},
|
||||
Some(MemoryKind::Machine(_)) => bug!("machine didn't handle machine alloc"),
|
||||
Some(MemoryKind::Stack) => {},
|
||||
}
|
||||
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(())
|
||||
}
|
||||
|
||||
|
@ -720,7 +655,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
|||
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
|
||||
let endianness = self.endianness();
|
||||
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());
|
||||
}
|
||||
// Now we do the actual reading
|
||||
let bytes = if signed {
|
||||
read_target_int(endianness, bytes).unwrap() as u128
|
||||
} else {
|
||||
read_target_uint(endianness, bytes).unwrap()
|
||||
};
|
||||
let bytes = read_target_uint(endianness, bytes).unwrap();
|
||||
// See if we got a pointer
|
||||
if size != self.pointer_size() {
|
||||
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))
|
||||
}
|
||||
|
||||
pub fn read_ptr_sized_unsigned(&self, ptr: MemoryPointer, ptr_align: Align) -> EvalResult<'tcx, PrimVal> {
|
||||
self.read_primval(ptr, ptr_align, self.pointer_size(), false)
|
||||
pub fn read_ptr_sized(&self, ptr: MemoryPointer, ptr_align: Align) -> EvalResult<'tcx, PrimVal> {
|
||||
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> {
|
||||
|
@ -764,19 +695,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
|||
val.offset as u128
|
||||
}
|
||||
|
||||
PrimVal::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::Bytes(bytes) => bytes,
|
||||
|
||||
PrimVal::Undef => {
|
||||
self.mark_definedness(PrimVal::Ptr(ptr).into(), size, false)?;
|
||||
|
@ -829,7 +748,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
|||
}
|
||||
|
||||
/// 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(
|
||||
&self,
|
||||
ptr: MemoryPointer,
|
||||
|
@ -883,7 +802,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
|||
}
|
||||
|
||||
/// 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.
|
||||
fn copy_undef_mask(
|
||||
&mut self,
|
||||
|
@ -944,7 +863,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
|||
// Methods to access integers in the target endianness
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn write_target_uint(
|
||||
pub fn write_target_uint(
|
||||
endianness: layout::Endian,
|
||||
mut target: &mut [u8],
|
||||
data: u128,
|
||||
|
@ -955,7 +874,8 @@ fn write_target_uint(
|
|||
layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
|
||||
}
|
||||
}
|
||||
fn write_target_int(
|
||||
|
||||
pub fn write_target_int(
|
||||
endianness: layout::Endian,
|
||||
mut target: &mut [u8],
|
||||
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 {
|
||||
layout::Endian::Little => source.read_uint128::<LittleEndian>(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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> {
|
||||
fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M>;
|
||||
fn memory(&self) -> &Memory<'a, 'tcx, M>;
|
||||
pub trait HasMemory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
|
||||
fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, '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,
|
||||
/// this may have to perform a load.
|
||||
|
@ -997,7 +910,7 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> {
|
|||
) -> EvalResult<'tcx, Pointer> {
|
||||
Ok(match value {
|
||||
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::ByValPair(ptr, _) => ptr,
|
||||
|
@ -1011,8 +924,8 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> {
|
|||
match value {
|
||||
Value::ByRef(ref_ptr, align) => {
|
||||
let mem = self.memory();
|
||||
let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?, align)?.into();
|
||||
let vtable = mem.read_ptr_sized_unsigned(
|
||||
let ptr = mem.read_ptr_sized(ref_ptr.to_ptr()?, align)?.into();
|
||||
let vtable = mem.read_ptr_sized(
|
||||
ref_ptr.offset(mem.pointer_size(), &mem.tcx.data_layout)?.to_ptr()?,
|
||||
align
|
||||
)?.to_ptr()?;
|
||||
|
@ -1033,8 +946,8 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> {
|
|||
match value {
|
||||
Value::ByRef(ref_ptr, align) => {
|
||||
let mem = self.memory();
|
||||
let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?, align)?.into();
|
||||
let len = mem.read_ptr_sized_unsigned(
|
||||
let ptr = mem.read_ptr_sized(ref_ptr.to_ptr()?, align)?.into();
|
||||
let len = mem.read_ptr_sized(
|
||||
ref_ptr.offset(mem.pointer_size(), &mem.tcx.data_layout)?.to_ptr()?,
|
||||
align
|
||||
)?.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]
|
||||
fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> {
|
||||
fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn memory(&self) -> &Memory<'a, 'tcx, M> {
|
||||
fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
|
||||
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]
|
||||
fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> {
|
||||
fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
|
||||
&mut self.memory
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn memory(&self) -> &Memory<'a, 'tcx, M> {
|
||||
fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
|
||||
&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]
|
||||
fn data_layout(&self) -> &TargetDataLayout {
|
||||
&self.tcx.data_layout
|
||||
|
|
|
@ -11,13 +11,23 @@ mod step;
|
|||
mod terminator;
|
||||
mod traits;
|
||||
|
||||
pub use self::eval_context::{EvalContext, Frame, ResourceLimits, StackPopCleanup,
|
||||
pub use self::eval_context::{EvalContext, Frame, StackPopCleanup,
|
||||
TyAndPacked, ValTy};
|
||||
|
||||
pub use self::place::{Place, PlaceExtra};
|
||||
|
||||
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::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
Loading…
Add table
Reference in a new issue