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

Replace all const evaluation with miri

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

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

r? @eddyb

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

21
src/Cargo.lock generated
View file

@ -1858,20 +1858,6 @@ dependencies = [
"syntax_pos 0.0.0",
]
[[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",
]

View file

@ -64,7 +64,6 @@ for details on how to format and write long error codes.
[librustc](https://github.com/rust-lang/rust/blob/master/src/librustc/diagnostics.rs),
[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),

View file

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

View file

@ -427,6 +427,7 @@ impl<T: Ord> Ord for Reverse<T> {
/// }
/// }
/// ```
#[cfg_attr(not(stage0), lang = "ord")]
#[stable(feature = "rust1", since = "1.0.0")]
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> {

View file

@ -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;

View file

@ -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.

View file

@ -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());

View file

@ -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,

View file

@ -46,19 +46,19 @@ pub fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
/// a reference to the TyCtxt) and it holds a few caches for speeding up various
/// 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>)

View file

@ -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,

View file

@ -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,

View file

@ -35,11 +35,11 @@ impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator,
impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, kind });
impl_stable_hash_for!(struct mir::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 });

View file

@ -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

View file

@ -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,

View file

@ -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)]

View file

@ -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,

View file

@ -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,

View file

@ -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);

View file

@ -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,

View file

@ -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)
}

View file

@ -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

View file

@ -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,
};

View file

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

View file

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

View file

@ -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()),

View file

@ -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 {

View file

@ -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),

View file

@ -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 {

View file

@ -41,9 +41,9 @@ impl<'tcx> MonoItem<'tcx> {
}
}
impl<'tcx> HashStable<StableHashingContext<'tcx>> for MonoItem<'tcx> {
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
fn hash_stable<W: StableHasherResult>(&self,
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,

View file

@ -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);

View file

@ -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) {

View file

@ -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
}
}

View file

@ -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),

View file

@ -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")

View file

@ -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)))
}
}
}
}
}

View file

@ -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};

View file

@ -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 => {}
}
}
}

View file

@ -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 => {

View file

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

View file

@ -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> {

View file

@ -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
})))
}

View file

@ -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(),

View file

@ -154,12 +154,12 @@ impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> {
}
}
impl<'gcx, D> HashStable<StableHashingContext<'gcx>> for SimplifiedTypeGen<D>
impl<'a, 'gcx, D> HashStable<StableHashingContext<'a>> for SimplifiedTypeGen<D>
where D: Copy + Debug + Ord + Eq + Hash +
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 {

View file

@ -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);

View file

@ -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),

View file

@ -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),

View file

@ -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);

View file

@ -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()))
}
}

View file

@ -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

View file

@ -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 }
}

View file

@ -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
{

View file

@ -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> {

View file

@ -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),

View file

@ -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),
}
}

View file

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

View file

@ -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)
}

View file

@ -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());
}

View file

@ -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);

View file

@ -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) => {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -29,13 +29,7 @@ extern crate syntax;
extern crate serialize as rustc_serialize; // used by deriving
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};

View file

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

View file

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

View file

@ -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" }

View file

@ -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.

View file

@ -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| {

View file

@ -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" }

View file

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

View file

@ -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,
);

View file

@ -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())
}

View file

@ -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;

View file

@ -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)?;

View file

@ -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.

View file

@ -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 {

View file

@ -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" }

View file

@ -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

View file

@ -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 {

View file

@ -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)

View file

@ -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>,
},

View file

@ -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();

View file

@ -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)

View file

@ -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;

View file

@ -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(..) |

View file

@ -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

View file

@ -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)
}),
},

View file

@ -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
}),
});

View file

@ -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>>,

View file

@ -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 ..]);

View file

@ -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();
}
}
}

View file

@ -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(|_| ())
}

View file

@ -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))),
}
}

View file

@ -1,34 +1,49 @@
use rustc::hir;
use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError};
use rustc::mir;
use rustc::ty::{self, TyCtxt, Ty, Instance};
use rustc::ty::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,
}
}
})
}

View file

@ -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()
}

View file

@ -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> {

View file

@ -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

View file

@ -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