CFG_CONFIGURE_ARGS="$@"
-case "${CFG_SRC_DIR}" in
+case "${CFG_SRC_DIR}" in
*\ * )
err "The path to the rust source directory contains spaces, which is not supported"
;;
CFG_DISABLE_JEMALLOC=1
fi
+if [ $CFG_OSTYPE = pc-windows-gnu ]
+then
+ # FIXME(#31030) - there's not a great reason to disable jemalloc here
+ step_msg "on Windows, disabling jemalloc"
+ CFG_DISABLE_JEMALLOC=1
+fi
+
# OS X 10.9, gcc is actually clang. This can cause some confusion in the build
# system, so if we find that gcc is clang, we should just use clang directly.
if [ $CFG_OSTYPE = apple-darwin -a -z "$CFG_ENABLE_CLANG" ]
if [ -n "$CFG_OSX_CLANG_VERSION" ]
then
case $CFG_OSX_CLANG_VERSION in
- (7.0*)
+ (7.0* | 7.1* | 7.2*)
step_msg "found ok version of APPLE CLANG: $CFG_OSX_CLANG_VERSION"
;;
(*)
DEPS_rustc_lint := rustc log syntax
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
DEPS_rustc_metadata := rustc rustc_front syntax rbml
-DEPS_rustc_passes := syntax rustc core
+DEPS_rustc_passes := syntax rustc core rustc_front
DEPS_rustc_mir := rustc rustc_front syntax
DEPS_rustc_resolve := arena rustc rustc_front log syntax
DEPS_rustc_platform_intrinsics := rustc rustc_llvm
######################################################################
# The version number
-CFG_RELEASE_NUM=1.7.0
+CFG_RELEASE_NUM=1.8.0
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
# NB Make sure it starts with a dot to conform to semver pre-release
fn get_mut(&mut self) -> &mut T; // elided
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
-fn args<T:ToCStr>(&mut self, args: &[T]) -> &mut Command; // elided
-fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command; // expanded
+fn args<T: ToCStr>(&mut self, args: &[T]) -> &mut Command; // elided
+fn args<'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command; // expanded
fn new(buf: &mut [u8]) -> BufWriter; // elided
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a>; // expanded
```text
const char *state = "reticulating splines";
-int state = get_log_state();
-if (state > 0) {
- printf("log(%d): %s\n", state, state);
+{
+ int state = get_log_state();
+ if (state > 0) {
+ printf("log(%d): %s\n", state, state);
+ }
}
```
fn get_mut(&mut self) -> &mut T; // elided
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
-fn args<T:ToCStr>(&mut self, args: &[T]) -> &mut Command // elided
-fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
+fn args<T: ToCStr>(&mut self, args: &[T]) -> &mut Command // elided
+fn args<'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
fn new(buf: &mut [u8]) -> BufWriter; // elided
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded
-Subproject commit f84e30927284b0c500ed3eaf09e8e159da20ddaf
+Subproject commit e24a1a025a1f214e40eedafe3b9c7b1d69937922
_ptr: Shared<ArcInner<T>>,
}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "arc_weak", since = "1.4.0")]
unsafe impl<T: ?Sized + Sync + Send> Send for Weak<T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "arc_weak", since = "1.4.0")]
unsafe impl<T: ?Sized + Sync + Send> Sync for Weak<T> {}
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "arc_weak", since = "1.4.0")]
impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(Weak)")
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "arc_weak", since = "1.4.0")]
impl<T: ?Sized> Drop for Weak<T> {
/// Drops the `Weak<T>`.
///
_ptr: Shared<RcBox<T>>,
}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "rc_weak", since = "1.4.0")]
impl<T: ?Sized> !marker::Send for Weak<T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "rc_weak", since = "1.4.0")]
impl<T: ?Sized> !marker::Sync for Weak<T> {}
#[unstable(feature = "coerce_unsized", issue = "27732")]
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "rc_weak", since = "1.4.0")]
impl<T: ?Sized> Drop for Weak<T> {
/// Drops the `Weak<T>`.
///
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "rc_weak", since = "1.4.0")]
impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(Weak)")
}
self.node.as_leaf_mut().len -= 1;
+ left_node.as_leaf_mut().len += right_len as u16 + 1;
+
if self.node.height > 1 {
ptr::copy_nonoverlapping(
right_node.cast_unchecked().as_internal().edges.as_ptr(),
);
}
- left_node.as_leaf_mut().len += right_len as u16 + 1;
-
Handle::new_edge(self.node, self.idx)
}
}
use core::cmp::Ordering::{self, Less, Greater, Equal};
use core::fmt::Debug;
use core::fmt;
-use core::iter::{Peekable, Map, FromIterator};
+use core::iter::{Peekable, FromIterator};
use core::ops::{BitOr, BitAnd, BitXor, Sub};
use borrow::Borrow;
/// An owning iterator over a BTreeSet's items.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<T> {
- iter: Map<::btree_map::IntoIter<T, ()>, fn((T, ())) -> T>,
+ iter: ::btree_map::IntoIter<T, ()>,
}
/// An iterator over a sub-range of BTreeSet's items.
pub struct Range<'a, T: 'a> {
- iter: Map<::btree_map::Range<'a, T, ()>, fn((&'a T, &'a ())) -> &'a T>,
+ iter: ::btree_map::Range<'a, T, ()>,
}
/// A lazy iterator producing elements in the set difference (in-order).
-> Range<'a, T>
where T: Borrow<Min> + Borrow<Max>
{
- fn first<A, B>((a, _): (A, B)) -> A {
- a
- }
- let first: fn((&'a T, &'a ())) -> &'a T = first; // coerce to fn pointer
-
- Range { iter: self.map.range(min, max).map(first) }
+ Range { iter: self.map.range(min, max) }
}
}
/// assert_eq!(v, [1, 2, 3, 4]);
/// ```
fn into_iter(self) -> IntoIter<T> {
- fn first<A, B>((a, _): (A, B)) -> A {
- a
- }
- let first: fn((T, ())) -> T = first; // coerce to fn pointer
-
- IntoIter { iter: self.map.into_iter().map(first) }
+ IntoIter { iter: self.map.into_iter() }
}
}
type Item = T;
fn next(&mut self) -> Option<T> {
- self.iter.next()
+ self.iter.next().map(|(k, _)| k)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> DoubleEndedIterator for IntoIter<T> {
fn next_back(&mut self) -> Option<T> {
- self.iter.next_back()
+ self.iter.next_back().map(|(k, _)| k)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
- self.iter.next()
+ self.iter.next().map(|(k, _)| k)
}
}
impl<'a, T> DoubleEndedIterator for Range<'a, T> {
fn next_back(&mut self) -> Option<&'a T> {
- self.iter.next_back()
+ self.iter.next_back().map(|(k, _)| k)
}
}
//! The fill character is provided normally in conjunction with the `width`
//! parameter. This indicates that if the value being formatted is smaller than
//! `width` some extra characters will be printed around it. The extra
-//! characters are specified by `fill`, and the alignment can be one of two
-//! options:
+//! characters are specified by `fill`, and the alignment can be one of the
+//! following options:
//!
//! * `<` - the argument is left-aligned in `width` columns
//! * `^` - the argument is center-aligned in `width` columns
/// # Safety
///
/// Callers of this function are responsible that three preconditions are
- /// satisifed:
+ /// satisfied:
///
/// * `begin` must come before `end`.
/// * `begin` and `end` must be byte positions within the string slice.
/// # Safety
///
/// Callers of this function are responsible that three preconditions are
- /// satisifed:
+ /// satisfied:
///
/// * `begin` must come before `end`.
/// * `begin` and `end` must be byte positions within the string slice.
}
}
}
-
- #[test]
- fn test_zst_push() {
- const N: usize = 8;
-
- // Zero sized type
- struct Zst;
-
- // Test that for all possible sequences of push_front / push_back,
- // we end up with a deque of the correct size
-
- for len in 0..N {
- let mut tester = VecDeque::with_capacity(len);
- assert_eq!(tester.len(), 0);
- assert!(tester.capacity() >= len);
- for case in 0..(1 << len) {
- assert_eq!(tester.len(), 0);
- for bit in 0..len {
- if case & (1 << bit) != 0 {
- tester.push_front(Zst);
- } else {
- tester.push_back(Zst);
- }
- }
- assert_eq!(tester.len(), len);
- assert_eq!(tester.iter().count(), len);
- tester.clear();
- }
- }
- }
}
assert_eq!(s.iter().next(), None);
}
+
+#[test]
+fn test_variance() {
+ use std::collections::btree_set::{IntoIter, Iter, Range};
+
+ fn set<'new>(v: BTreeSet<&'static str>) -> BTreeSet<&'new str> { v }
+ fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { v }
+ fn into_iter<'new>(v: IntoIter<&'static str>) -> IntoIter<&'new str> { v }
+ fn range<'a, 'new>(v: Range<'a, &'static str>) -> Range<'a, &'new str> { v }
+}
/// use std::marker::PhantomData;
///
/// # #[allow(dead_code)]
-/// struct Slice<'a, T:'a> {
+/// struct Slice<'a, T: 'a> {
/// start: *const T,
/// end: *const T,
/// phantom: PhantomData<&'a T>
/// use std::any::Any;
///
/// # #[allow(dead_code)]
-/// fn foo<T:Reflect+'static>(x: &T) {
+/// fn foo<T: Reflect + 'static>(x: &T) {
/// let any: &Any = x;
/// if any.is::<u32>() { println!("u32"); }
/// }
/// ```
///
-/// Without the declaration `T:Reflect`, `foo` would not type check
+/// Without the declaration `T: Reflect`, `foo` would not type check
/// (note: as a matter of style, it would be preferable to write
-/// `T:Any`, because `T:Any` implies `T:Reflect` and `T:'static`, but
+/// `T: Any`, because `T: Any` implies `T: Reflect` and `T: 'static`, but
/// we use `Reflect` here to show how it works). The `Reflect` bound
/// thus serves to alert `foo`'s caller to the fact that `foo` may
-/// behave differently depending on whether `T=u32` or not. In
+/// behave differently depending on whether `T = u32` or not. In
/// particular, thanks to the `Reflect` bound, callers know that a
/// function declared like `fn bar<T>(...)` will always act in
/// precisely the same way no matter what type `T` is supplied,
intrinsics::mul_with_overflow }
}
-// `Int` + `UnsignedInt` implemented for signed integers
+// `Int` + `UnsignedInt` implemented for unsigned integers
macro_rules! uint_impl {
($ActualT:ty, $BITS:expr,
$ctpop:path,
/// Basic usage:
///
/// ```
- /// assert_eq!((-127i8).checked_sub(1), Some(-128));
- /// assert_eq!((-128i8).checked_sub(1), None);
+ /// assert_eq!(1u8.checked_sub(1), Some(0));
+ /// assert_eq!(0u8.checked_sub(1), None);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
/// Basic usage:
///
/// ```
- /// assert_eq!((-127i8).checked_div(-1), Some(127));
- /// assert_eq!((-128i8).checked_div(-1), None);
- /// assert_eq!((1i8).checked_div(0), None);
+ /// assert_eq!(128u8.checked_div(2), Some(64));
+ /// assert_eq!(1u8.checked_div(0), None);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
/// Basic usage:
///
/// ```
- /// assert_eq!(100i8.saturating_add(1), 101);
- /// assert_eq!(100i8.saturating_add(127), 127);
+ /// assert_eq!(100u8.saturating_add(1), 101);
+ /// assert_eq!(200u8.saturating_add(127), 255);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn saturating_add(self, other: Self) -> Self {
match self.checked_add(other) {
- Some(x) => x,
- None if other >= Self::zero() => Self::max_value(),
- None => Self::min_value(),
+ Some(x) => x,
+ None => Self::max_value(),
}
}
/// Basic usage:
///
/// ```
- /// assert_eq!(100i8.saturating_sub(127), -27);
- /// assert_eq!((-100i8).saturating_sub(127), -128);
+ /// assert_eq!(100u8.saturating_sub(27), 73);
+ /// assert_eq!(13u8.saturating_sub(127), 0);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn saturating_sub(self, other: Self) -> Self {
match self.checked_sub(other) {
- Some(x) => x,
- None if other >= Self::zero() => Self::min_value(),
- None => Self::max_value(),
+ Some(x) => x,
+ None => Self::min_value(),
}
}
/// Basic usage:
///
/// ```
- /// assert_eq!(100i8.wrapping_add(27), 127);
- /// assert_eq!(100i8.wrapping_add(127), -29);
+ /// assert_eq!(200u8.wrapping_add(55), 255);
+ /// assert_eq!(200u8.wrapping_add(155), 99);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
/// Basic usage:
///
/// ```
- /// assert_eq!(0i8.wrapping_sub(127), -127);
- /// assert_eq!((-2i8).wrapping_sub(127), 127);
+ /// assert_eq!(100u8.wrapping_sub(100), 0);
+ /// assert_eq!(100u8.wrapping_sub(155), 201);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
/// Basic usage:
///
/// ```
- /// assert_eq!(10i8.wrapping_mul(12), 120);
- /// assert_eq!(11i8.wrapping_mul(12), -124);
+ /// assert_eq!(10u8.wrapping_mul(12), 120);
+ /// assert_eq!(25u8.wrapping_mul(12), 44);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
}
}
- /// Wrapping (modular) division. Computes `self / other`,
- /// wrapping around at the boundary of the type.
- ///
- /// The only case where such wrapping can occur is when one
- /// divides `MIN / -1` on a signed type (where `MIN` is the
- /// negative minimal value for the type); this is equivalent
- /// to `-MIN`, a positive value that is too large to represent
- /// in the type. In such a case, this function returns `MIN`
- /// itself.
+ /// Wrapping (modular) division. Computes `self / other`.
+ /// Wrapped division on unsigned types is just normal division.
+ /// There's no way wrapping could ever happen.
+ /// This function exists, so that all operations
+ /// are accounted for in the wrapping operations.
///
/// # Examples
///
///
/// ```
/// assert_eq!(100u8.wrapping_div(10), 10);
- /// assert_eq!((-128i8).wrapping_div(-1), -128);
/// ```
#[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
pub fn wrapping_div(self, rhs: Self) -> Self {
- self.overflowing_div(rhs).0
+ self / rhs
}
- /// Wrapping (modular) remainder. Computes `self % other`,
- /// wrapping around at the boundary of the type.
- ///
- /// Such wrap-around never actually occurs mathematically;
- /// implementation artifacts make `x % y` invalid for `MIN /
- /// -1` on a signed type (where `MIN` is the negative
- /// minimal value). In such a case, this function returns `0`.
+ /// Wrapping (modular) remainder. Computes `self % other`.
+ /// Wrapped remainder calculation on unsigned types is
+ /// just the regular remainder calculation.
+ /// There's no way wrapping could ever happen.
+ /// This function exists, so that all operations
+ /// are accounted for in the wrapping operations.
///
/// # Examples
///
///
/// ```
/// assert_eq!(100i8.wrapping_rem(10), 0);
- /// assert_eq!((-128i8).wrapping_rem(-1), 0);
/// ```
#[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
pub fn wrapping_rem(self, rhs: Self) -> Self {
- self.overflowing_rem(rhs).0
+ self % rhs
}
/// Wrapping (modular) negation. Computes `-self`,
/// wrapping around at the boundary of the type.
///
- /// The only case where such wrapping can occur is when one
- /// negates `MIN` on a signed type (where `MIN` is the
- /// negative minimal value for the type); this is a positive
- /// value that is too large to represent in the type. In such
- /// a case, this function returns `MIN` itself.
+ /// Since unsigned types do not have negative equivalents
+ /// all applications of this function will wrap (except for `-0`).
+ /// For values smaller than the corresponding signed type's maximum
+ /// the result is the same as casting the corresponding signed value.
+ /// Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where
+ /// `MAX` is the corresponding signed type's maximum.
///
/// # Examples
///
/// Basic usage:
///
/// ```
- /// assert_eq!(100i8.wrapping_neg(), -100);
- /// assert_eq!((-128i8).wrapping_neg(), -128);
+ /// assert_eq!(100u8.wrapping_neg(), 156);
+ /// assert_eq!(0u8.wrapping_neg(), 0);
+ /// assert_eq!(180u8.wrapping_neg(), 76);
+ /// assert_eq!(180u8.wrapping_neg(), (127 + 1) - (180u8 - (127 + 1)));
/// ```
#[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
/// Basic usage:
///
/// ```
- /// assert_eq!(2i32.pow(4), 16);
+ /// assert_eq!(2u32.pow(4), 16);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Drop {
/// A method called when the value goes out of scope.
+ ///
+ /// When this method has been called, `self` has not yet been deallocated.
+ /// If it were, `self` would be a dangling reference.
+ ///
+ /// After this function is over, the memory of `self` will be deallocated.
+ ///
+ /// # Panics
+ ///
+ /// Given that a `panic!` will call `drop()` as it unwinds, any `panic!` in
+ /// a `drop()` implementation will likely abort.
#[stable(feature = "rust1", since = "1.0.0")]
fn drop(&mut self);
}
fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
assert!(self.len() == src.len(),
"destination and source slices have different lengths");
- for (dst, src) in self.iter_mut().zip(src) {
- dst.clone_from(src);
+ // NOTE: We need to explicitly slice them to the same length
+ // for bounds checking to be elided, and the optimizer will
+ // generate memcpy for simple cases (for example T = u8).
+ let len = self.len();
+ let src = &src[..len];
+ for i in 0..len {
+ self[i].clone_from(&src[i]);
}
}
}
// except according to those terms.
#[inline]
-pub fn write_to_vec(vec: &mut Vec<u8>, position: &mut usize, byte: u8)
-{
+pub fn write_to_vec(vec: &mut Vec<u8>, position: &mut usize, byte: u8) {
if *position == vec.len() {
vec.push(byte);
} else {
*position += 1;
}
-pub fn write_unsigned_leb128(out: &mut Vec<u8>,
- start_position: usize,
- mut value: u64)
- -> usize {
+pub fn write_unsigned_leb128(out: &mut Vec<u8>, start_position: usize, mut value: u64) -> usize {
let mut position = start_position;
- loop
- {
+ loop {
let mut byte = (value & 0x7F) as u8;
value >>= 7;
if value != 0 {
return position - start_position;
}
-pub fn read_unsigned_leb128(data: &[u8],
- start_position: usize)
- -> (u64, usize) {
+pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u64, usize) {
let mut result = 0;
let mut shift = 0;
let mut position = start_position;
}
-pub fn write_signed_leb128(out: &mut Vec<u8>,
- start_position: usize,
- mut value: i64) -> usize {
+pub fn write_signed_leb128(out: &mut Vec<u8>, start_position: usize, mut value: i64) -> usize {
let mut position = start_position;
loop {
let mut byte = (value as u8) & 0x7f;
value >>= 7;
- let more = !((((value == 0 ) && ((byte & 0x40) == 0)) ||
+ let more = !((((value == 0) && ((byte & 0x40) == 0)) ||
((value == -1) && ((byte & 0x40) != 0))));
if more {
byte |= 0x80; // Mark this byte to show that more bytes will follow.
return position - start_position;
}
-pub fn read_signed_leb128(data: &[u8],
- start_position: usize)
- -> (i64, usize) {
+pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i64, usize) {
let mut result = 0;
let mut shift = 0;
let mut position = start_position;
}
if (shift < 64) && ((byte & 0x40) != 0) {
- /* sign extend */
+ // sign extend
result |= -(1i64 << shift);
}
#[cfg(test)]
extern crate serialize as rustc_serialize; // Used by RustcEncodable
-#[macro_use] extern crate log;
+#[macro_use]
+extern crate log;
-#[cfg(test)] extern crate test;
+#[cfg(test)]
+extern crate test;
pub mod opaque;
pub mod leb128;
impl<'doc> Doc<'doc> {
pub fn new(data: &'doc [u8]) -> Doc<'doc> {
- Doc { data: data, start: 0, end: data.len() }
+ Doc {
+ data: data,
+ start: 0,
+ end: data.len(),
+ }
}
pub fn get<'a>(&'a self, tag: usize) -> Doc<'a> {
pub enum EbmlEncoderTag {
// tags 00..1f are reserved for auto-serialization.
// first NUM_IMPLICIT_TAGS tags are implicitly sized and lengths are not encoded.
-
- EsU8 = 0x00, // + 1 byte
- EsU16 = 0x01, // + 2 bytes
- EsU32 = 0x02, // + 4 bytes
- EsU64 = 0x03, // + 8 bytes
- EsI8 = 0x04, // + 1 byte
- EsI16 = 0x05, // + 2 bytes
- EsI32 = 0x06, // + 4 bytes
- EsI64 = 0x07, // + 8 bytes
- EsBool = 0x08, // + 1 byte
- EsChar = 0x09, // + 4 bytes
- EsF32 = 0x0a, // + 4 bytes
- EsF64 = 0x0b, // + 8 bytes
- EsSub8 = 0x0c, // + 1 byte
- EsSub32 = 0x0d, // + 4 bytes
+ EsU8 = 0x00, // + 1 byte
+ EsU16 = 0x01, // + 2 bytes
+ EsU32 = 0x02, // + 4 bytes
+ EsU64 = 0x03, // + 8 bytes
+ EsI8 = 0x04, // + 1 byte
+ EsI16 = 0x05, // + 2 bytes
+ EsI32 = 0x06, // + 4 bytes
+ EsI64 = 0x07, // + 8 bytes
+ EsBool = 0x08, // + 1 byte
+ EsChar = 0x09, // + 4 bytes
+ EsF32 = 0x0a, // + 4 bytes
+ EsF64 = 0x0b, // + 8 bytes
+ EsSub8 = 0x0c, // + 1 byte
+ EsSub32 = 0x0d, // + 4 bytes
// 0x0e and 0x0f are reserved
-
- EsStr = 0x10,
- EsEnum = 0x11, // encodes the variant id as the first EsSub*
- EsVec = 0x12, // encodes the # of elements as the first EsSub*
- EsVecElt = 0x13,
- EsMap = 0x14, // encodes the # of pairs as the first EsSub*
- EsMapKey = 0x15,
- EsMapVal = 0x16,
- EsOpaque = 0x17,
+ EsStr = 0x10,
+ EsEnum = 0x11, // encodes the variant id as the first EsSub*
+ EsVec = 0x12, // encodes the # of elements as the first EsSub*
+ EsVecElt = 0x13,
+ EsMap = 0x14, // encodes the # of pairs as the first EsSub*
+ EsMapKey = 0x15,
+ EsMapVal = 0x16,
+ EsOpaque = 0x17,
}
const NUM_TAGS: usize = 0x1000;
const NUM_IMPLICIT_TAGS: usize = 0x0e;
+#[cfg_attr(rustfmt, rustfmt_skip)]
static TAG_IMPLICIT_LEN: [i8; NUM_IMPLICIT_TAGS] = [
1, 2, 4, 8, // EsU*
1, 2, 4, 8, // ESI*
InvalidTag(usize),
Expected(String),
IoError(std::io::Error),
- ApplicationError(String)
+ ApplicationError(String),
}
impl fmt::Display for Error {
use serialize;
use super::opaque;
- use super::{ ApplicationError, EsVec, EsMap, EsEnum, EsSub8, EsSub32,
- EsVecElt, EsMapKey, EsU64, EsU32, EsU16, EsU8, EsI64,
- EsI32, EsI16, EsI8, EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal,
- EsOpaque, EbmlEncoderTag, Doc, TaggedDoc,
- Error, IntTooBig, InvalidTag, Expected, NUM_IMPLICIT_TAGS, TAG_IMPLICIT_LEN };
+ use super::{ApplicationError, EsVec, EsMap, EsEnum, EsSub8, EsSub32, EsVecElt, EsMapKey,
+ EsU64, EsU32, EsU16, EsU8, EsI64, EsI32, EsI16, EsI8, EsBool, EsF64, EsF32,
+ EsChar, EsStr, EsMapVal, EsOpaque, EbmlEncoderTag, Doc, TaggedDoc, Error,
+ IntTooBig, InvalidTag, Expected, NUM_IMPLICIT_TAGS, TAG_IMPLICIT_LEN};
pub type DecodeResult<T> = Result<T, Error>;
// rbml reading
#[derive(Copy, Clone)]
pub struct Res {
pub val: usize,
- pub next: usize
+ pub next: usize,
}
pub fn tag_at(data: &[u8], start: usize) -> DecodeResult<Res> {
let v = data[start] as usize;
if v < 0xf0 {
- Ok(Res { val: v, next: start + 1 })
+ Ok(Res {
+ val: v,
+ next: start + 1,
+ })
} else if v > 0xf0 {
- Ok(Res { val: ((v & 0xf) << 8) | data[start + 1] as usize, next: start + 2 })
+ Ok(Res {
+ val: ((v & 0xf) << 8) | data[start + 1] as usize,
+ next: start + 2,
+ })
} else {
// every tag starting with byte 0xf0 is an overlong form, which is prohibited.
Err(InvalidTag(v))
fn vuint_at_slow(data: &[u8], start: usize) -> DecodeResult<Res> {
let a = data[start];
if a & 0x80 != 0 {
- return Ok(Res {val: (a & 0x7f) as usize, next: start + 1});
+ return Ok(Res {
+ val: (a & 0x7f) as usize,
+ next: start + 1,
+ });
}
if a & 0x40 != 0 {
- return Ok(Res {val: ((a & 0x3f) as usize) << 8 |
- (data[start + 1] as usize),
- next: start + 2});
+ return Ok(Res {
+ val: ((a & 0x3f) as usize) << 8 | (data[start + 1] as usize),
+ next: start + 2,
+ });
}
if a & 0x20 != 0 {
- return Ok(Res {val: ((a & 0x1f) as usize) << 16 |
- (data[start + 1] as usize) << 8 |
- (data[start + 2] as usize),
- next: start + 3});
+ return Ok(Res {
+ val: ((a & 0x1f) as usize) << 16 | (data[start + 1] as usize) << 8 |
+ (data[start + 2] as usize),
+ next: start + 3,
+ });
}
if a & 0x10 != 0 {
- return Ok(Res {val: ((a & 0x0f) as usize) << 24 |
- (data[start + 1] as usize) << 16 |
- (data[start + 2] as usize) << 8 |
- (data[start + 3] as usize),
- next: start + 4});
+ return Ok(Res {
+ val: ((a & 0x0f) as usize) << 24 | (data[start + 1] as usize) << 16 |
+ (data[start + 2] as usize) << 8 |
+ (data[start + 3] as usize),
+ next: start + 4,
+ });
}
Err(IntTooBig(a as usize))
}
// most significant bit is set etc. we can replace up to three
// "and+branch" with a single table lookup which gives us a measured
// speedup of around 2x on x86_64.
- static SHIFT_MASK_TABLE: [(usize, u32); 16] = [
- (0, 0x0), (0, 0x0fffffff),
- (8, 0x1fffff), (8, 0x1fffff),
- (16, 0x3fff), (16, 0x3fff), (16, 0x3fff), (16, 0x3fff),
- (24, 0x7f), (24, 0x7f), (24, 0x7f), (24, 0x7f),
- (24, 0x7f), (24, 0x7f), (24, 0x7f), (24, 0x7f)
- ];
+ static SHIFT_MASK_TABLE: [(usize, u32); 16] = [(0, 0x0),
+ (0, 0x0fffffff),
+ (8, 0x1fffff),
+ (8, 0x1fffff),
+ (16, 0x3fff),
+ (16, 0x3fff),
+ (16, 0x3fff),
+ (16, 0x3fff),
+ (24, 0x7f),
+ (24, 0x7f),
+ (24, 0x7f),
+ (24, 0x7f),
+ (24, 0x7f),
+ (24, 0x7f),
+ (24, 0x7f),
+ (24, 0x7f)];
unsafe {
let ptr = data.as_ptr().offset(start as isize) as *const u32;
pub fn tag_len_at(data: &[u8], tag: Res) -> DecodeResult<Res> {
if tag.val < NUM_IMPLICIT_TAGS && TAG_IMPLICIT_LEN[tag.val] >= 0 {
- Ok(Res { val: TAG_IMPLICIT_LEN[tag.val] as usize, next: tag.next })
+ Ok(Res {
+ val: TAG_IMPLICIT_LEN[tag.val] as usize,
+ next: tag.next,
+ })
} else {
vuint_at(data, tag.next)
}
let end = elt_size.next + elt_size.val;
Ok(TaggedDoc {
tag: elt_tag.val,
- doc: Doc { data: data, start: elt_size.next, end: end }
+ doc: Doc {
+ data: data,
+ start: elt_size.next,
+ end: end,
+ },
})
}
let elt_size = try_or!(tag_len_at(d.data, elt_tag), None);
pos = elt_size.next + elt_size.val;
if elt_tag.val == tg {
- return Some(Doc { data: d.data, start: elt_size.next,
- end: pos });
+ return Some(Doc {
+ data: d.data,
+ start: elt_size.next,
+ end: pos,
+ });
}
}
None
}
pub fn docs<'a>(d: Doc<'a>) -> DocsIterator<'a> {
- DocsIterator {
- d: d
- }
+ DocsIterator { d: d }
}
pub struct DocsIterator<'a> {
}
}
- pub fn with_doc_data<T, F>(d: Doc, f: F) -> T where
- F: FnOnce(&[u8]) -> T,
+ pub fn with_doc_data<T, F>(d: Doc, f: F) -> T
+ where F: FnOnce(&[u8]) -> T
{
f(&d.data[d.start..d.end])
}
// of the page and segfault.
let mut b = [0; 8];
- b.clone_from_slice(&d.data[d.end-8..d.end]);
+ b.clone_from_slice(&d.data[d.end - 8..d.end]);
let data = unsafe { (*(b.as_ptr() as *const u64)).to_be() };
let len = d.end - d.start;
if len < 8 {
- data & ((1<<(len*8))-1)
+ data & ((1 << (len * 8)) - 1)
} else {
data
}
} else {
let mut result = 0;
for b in &d.data[d.start..d.end] {
- result = (result<<8) + (*b as u64);
+ result = (result << 8) + (*b as u64);
}
result
}
}
- #[inline] pub fn doc_as_u16(d: Doc) -> u16 { doc_as_u64(d) as u16 }
- #[inline] pub fn doc_as_u32(d: Doc) -> u32 { doc_as_u64(d) as u32 }
+ #[inline]
+ pub fn doc_as_u16(d: Doc) -> u16 {
+ doc_as_u64(d) as u16
+ }
+ #[inline]
+ pub fn doc_as_u32(d: Doc) -> u32 {
+ doc_as_u64(d) as u32
+ }
- #[inline] pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 }
- #[inline] pub fn doc_as_i16(d: Doc) -> i16 { doc_as_u16(d) as i16 }
- #[inline] pub fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 }
- #[inline] pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 }
+ #[inline]
+ pub fn doc_as_i8(d: Doc) -> i8 {
+ doc_as_u8(d) as i8
+ }
+ #[inline]
+ pub fn doc_as_i16(d: Doc) -> i16 {
+ doc_as_u16(d) as i16
+ }
+ #[inline]
+ pub fn doc_as_i32(d: Doc) -> i32 {
+ doc_as_u32(d) as i32
+ }
+ #[inline]
+ pub fn doc_as_i64(d: Doc) -> i64 {
+ doc_as_u64(d) as i64
+ }
pub struct Decoder<'a> {
parent: Doc<'a>,
pub fn new(d: Doc<'doc>) -> Decoder<'doc> {
Decoder {
parent: d,
- pos: d.start
+ pos: d.start,
}
}
fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> DecodeResult<Doc<'doc>> {
debug!(". next_doc(exp_tag={:?})", exp_tag);
if self.pos >= self.parent.end {
- return Err(Expected(format!("no more documents in \
- current node!")));
+ return Err(Expected(format!("no more documents in current node!")));
}
- let TaggedDoc { tag: r_tag, doc: r_doc } =
- try!(doc_at(self.parent.data, self.pos));
+ let TaggedDoc { tag: r_tag, doc: r_doc } = try!(doc_at(self.parent.data, self.pos));
debug!("self.parent={:?}-{:?} self.pos={:?} r_tag={:?} r_doc={:?}-{:?}",
self.parent.start,
self.parent.end,
r_doc.start,
r_doc.end);
if r_tag != (exp_tag as usize) {
- return Err(Expected(format!("expected EBML doc with tag {:?} but \
- found tag {:?}", exp_tag, r_tag)));
+ return Err(Expected(format!("expected EBML doc with tag {:?} but found tag {:?}",
+ exp_tag,
+ r_tag)));
}
if r_doc.end > self.parent.end {
- return Err(Expected(format!("invalid EBML, child extends to \
- {:#x}, parent to {:#x}",
- r_doc.end, self.parent.end)));
+ return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \
+ {:#x}",
+ r_doc.end,
+ self.parent.end)));
}
self.pos = r_doc.end;
Ok(r_doc)
}
- fn push_doc<T, F>(&mut self, exp_tag: EbmlEncoderTag, f: F) -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ fn push_doc<T, F>(&mut self, exp_tag: EbmlEncoderTag, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
{
let d = try!(self.next_doc(exp_tag));
let old_parent = self.parent;
return Ok(0);
}
- let TaggedDoc { tag: r_tag, doc: r_doc } =
- try!(doc_at(self.parent.data, self.pos));
+ let TaggedDoc { tag: r_tag, doc: r_doc } = try!(doc_at(self.parent.data, self.pos));
let r = if r_tag == (EsSub8 as usize) {
doc_as_u8(r_doc) as usize
} else if r_tag == (EsSub32 as usize) {
doc_as_u32(r_doc) as usize
} else {
- return Err(Expected(format!("expected EBML doc with tag {:?} or {:?} but \
- found tag {:?}", EsSub8, EsSub32, r_tag)));
+ return Err(Expected(format!("expected EBML doc with tag {:?} or {:?} but found \
+ tag {:?}",
+ EsSub8,
+ EsSub32,
+ r_tag)));
};
if r_doc.end > self.parent.end {
- return Err(Expected(format!("invalid EBML, child extends to \
- {:#x}, parent to {:#x}",
- r_doc.end, self.parent.end)));
+ return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \
+ {:#x}",
+ r_doc.end,
+ self.parent.end)));
}
self.pos = r_doc.end;
debug!("_next_sub result={:?}", r);
// all tags between them should be valid, in the order of u8, u16, u32 and u64.
fn _next_int(&mut self,
first_tag: EbmlEncoderTag,
- last_tag: EbmlEncoderTag) -> DecodeResult<u64> {
+ last_tag: EbmlEncoderTag)
+ -> DecodeResult<u64> {
if self.pos >= self.parent.end {
- return Err(Expected(format!("no more documents in \
- current node!")));
+ return Err(Expected(format!("no more documents in current node!")));
}
- let TaggedDoc { tag: r_tag, doc: r_doc } =
- try!(doc_at(self.parent.data, self.pos));
+ let TaggedDoc { tag: r_tag, doc: r_doc } = try!(doc_at(self.parent.data, self.pos));
let r = if first_tag as usize <= r_tag && r_tag <= last_tag as usize {
match r_tag - first_tag as usize {
0 => doc_as_u8(r_doc) as u64,
}
} else {
return Err(Expected(format!("expected EBML doc with tag {:?} through {:?} but \
- found tag {:?}", first_tag, last_tag, r_tag)));
+ found tag {:?}",
+ first_tag,
+ last_tag,
+ r_tag)));
};
if r_doc.end > self.parent.end {
- return Err(Expected(format!("invalid EBML, child extends to \
- {:#x}, parent to {:#x}",
- r_doc.end, self.parent.end)));
+ return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \
+ {:#x}",
+ r_doc.end,
+ self.parent.end)));
}
self.pos = r_doc.end;
debug!("_next_int({:?}, {:?}) result={:?}", first_tag, last_tag, r);
Ok(r)
}
- pub fn read_opaque<R, F>(&mut self, op: F) -> DecodeResult<R> where
- F: FnOnce(&mut opaque::Decoder, Doc) -> DecodeResult<R>,
+ pub fn read_opaque<R, F>(&mut self, op: F) -> DecodeResult<R>
+ where F: FnOnce(&mut opaque::Decoder, Doc) -> DecodeResult<R>
{
let doc = try!(self.next_doc(EsOpaque));
let result = {
- let mut opaque_decoder = opaque::Decoder::new(doc.data,
- doc.start);
+ let mut opaque_decoder = opaque::Decoder::new(doc.data, doc.start);
try!(op(&mut opaque_decoder, doc))
};
impl<'doc> serialize::Decoder for Decoder<'doc> {
type Error = Error;
- fn read_nil(&mut self) -> DecodeResult<()> { Ok(()) }
+ fn read_nil(&mut self) -> DecodeResult<()> {
+ Ok(())
+ }
- fn read_u64(&mut self) -> DecodeResult<u64> { self._next_int(EsU8, EsU64) }
- fn read_u32(&mut self) -> DecodeResult<u32> { Ok(try!(self._next_int(EsU8, EsU32)) as u32) }
- fn read_u16(&mut self) -> DecodeResult<u16> { Ok(try!(self._next_int(EsU8, EsU16)) as u16) }
- fn read_u8(&mut self) -> DecodeResult<u8> { Ok(doc_as_u8(try!(self.next_doc(EsU8)))) }
+ fn read_u64(&mut self) -> DecodeResult<u64> {
+ self._next_int(EsU8, EsU64)
+ }
+ fn read_u32(&mut self) -> DecodeResult<u32> {
+ Ok(try!(self._next_int(EsU8, EsU32)) as u32)
+ }
+ fn read_u16(&mut self) -> DecodeResult<u16> {
+ Ok(try!(self._next_int(EsU8, EsU16)) as u16)
+ }
+ fn read_u8(&mut self) -> DecodeResult<u8> {
+ Ok(doc_as_u8(try!(self.next_doc(EsU8))))
+ }
fn read_uint(&mut self) -> DecodeResult<usize> {
let v = try!(self._next_int(EsU8, EsU64));
if v > (::std::usize::MAX as u64) {
}
}
- fn read_i64(&mut self) -> DecodeResult<i64> { Ok(try!(self._next_int(EsI8, EsI64)) as i64) }
- fn read_i32(&mut self) -> DecodeResult<i32> { Ok(try!(self._next_int(EsI8, EsI32)) as i32) }
- fn read_i16(&mut self) -> DecodeResult<i16> { Ok(try!(self._next_int(EsI8, EsI16)) as i16) }
- fn read_i8(&mut self) -> DecodeResult<i8> { Ok(doc_as_u8(try!(self.next_doc(EsI8))) as i8) }
+ fn read_i64(&mut self) -> DecodeResult<i64> {
+ Ok(try!(self._next_int(EsI8, EsI64)) as i64)
+ }
+ fn read_i32(&mut self) -> DecodeResult<i32> {
+ Ok(try!(self._next_int(EsI8, EsI32)) as i32)
+ }
+ fn read_i16(&mut self) -> DecodeResult<i16> {
+ Ok(try!(self._next_int(EsI8, EsI16)) as i16)
+ }
+ fn read_i8(&mut self) -> DecodeResult<i8> {
+ Ok(doc_as_u8(try!(self.next_doc(EsI8))) as i8)
+ }
fn read_int(&mut self) -> DecodeResult<isize> {
let v = try!(self._next_int(EsI8, EsI64)) as i64;
if v > (isize::MAX as i64) || v < (isize::MIN as i64) {
}
// Compound types:
- fn read_enum<T, F>(&mut self, name: &str, f: F) -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ fn read_enum<T, F>(&mut self, name: &str, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
{
debug!("read_enum({})", name);
Ok(result)
}
- fn read_enum_variant<T, F>(&mut self, _: &[&str],
- mut f: F) -> DecodeResult<T>
- where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult<T>,
+ fn read_enum_variant<T, F>(&mut self, _: &[&str], mut f: F) -> DecodeResult<T>
+ where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult<T>
{
debug!("read_enum_variant()");
let idx = try!(self._next_sub());
f(self, idx)
}
- fn read_enum_variant_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ fn read_enum_variant_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
{
debug!("read_enum_variant_arg(idx={})", idx);
f(self)
}
- fn read_enum_struct_variant<T, F>(&mut self, _: &[&str],
- mut f: F) -> DecodeResult<T>
- where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult<T>,
+ fn read_enum_struct_variant<T, F>(&mut self, _: &[&str], mut f: F) -> DecodeResult<T>
+ where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult<T>
{
debug!("read_enum_struct_variant()");
let idx = try!(self._next_sub());
name: &str,
idx: usize,
f: F)
- -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
{
- debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx);
+ debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx);
f(self)
}
- fn read_struct<T, F>(&mut self, name: &str, _: usize, f: F) -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ fn read_struct<T, F>(&mut self, name: &str, _: usize, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
{
debug!("read_struct(name={})", name);
f(self)
}
- fn read_struct_field<T, F>(&mut self, name: &str, idx: usize, f: F) -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ fn read_struct_field<T, F>(&mut self, name: &str, idx: usize, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
{
debug!("read_struct_field(name={}, idx={})", name, idx);
f(self)
}
- fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
{
debug!("read_tuple()");
self.read_seq(move |d, len| {
if len == tuple_len {
f(d)
} else {
- Err(Expected(format!("Expected tuple of length `{}`, \
- found tuple of length `{}`", tuple_len, len)))
+ Err(Expected(format!("Expected tuple of length `{}`, found tuple of length \
+ `{}`",
+ tuple_len,
+ len)))
}
})
}
- fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
{
debug!("read_tuple_arg(idx={})", idx);
self.read_seq_elt(idx, f)
}
- fn read_tuple_struct<T, F>(&mut self, name: &str, len: usize, f: F) -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ fn read_tuple_struct<T, F>(&mut self, name: &str, len: usize, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
{
debug!("read_tuple_struct(name={})", name);
self.read_tuple(len, f)
}
- fn read_tuple_struct_arg<T, F>(&mut self,
- idx: usize,
- f: F)
- -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ fn read_tuple_struct_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
{
debug!("read_tuple_struct_arg(idx={})", idx);
self.read_tuple_arg(idx, f)
}
- fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T> where
- F: FnMut(&mut Decoder<'doc>, bool) -> DecodeResult<T>,
+ fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T>
+ where F: FnMut(&mut Decoder<'doc>, bool) -> DecodeResult<T>
{
debug!("read_option()");
self.read_enum("Option", move |this| {
match idx {
0 => f(this, false),
1 => f(this, true),
- _ => {
- Err(Expected(format!("Expected None or Some")))
- }
+ _ => Err(Expected(format!("Expected None or Some"))),
}
})
})
}
- fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult<T>,
+ fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult<T>
{
debug!("read_seq()");
self.push_doc(EsVec, move |d| {
})
}
- fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
{
debug!("read_seq_elt(idx={})", idx);
self.push_doc(EsVecElt, f)
}
- fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult<T>,
+ fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult<T>
{
debug!("read_map()");
self.push_doc(EsMap, move |d| {
})
}
- fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
{
debug!("read_map_elt_key(idx={})", idx);
self.push_doc(EsMapKey, f)
}
- fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> where
- F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
+ where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
{
debug!("read_map_elt_val(idx={})", idx);
self.push_doc(EsMapVal, f)
use std::io::{self, SeekFrom, Cursor};
use super::opaque;
- use super::{ EsVec, EsMap, EsEnum, EsSub8, EsSub32, EsVecElt, EsMapKey,
- EsU64, EsU32, EsU16, EsU8, EsI64, EsI32, EsI16, EsI8,
- EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal,
- EsOpaque, NUM_IMPLICIT_TAGS, NUM_TAGS };
+ use super::{EsVec, EsMap, EsEnum, EsSub8, EsSub32, EsVecElt, EsMapKey, EsU64, EsU32, EsU16,
+ EsU8, EsI64, EsI32, EsI16, EsI8, EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal,
+ EsOpaque, NUM_IMPLICIT_TAGS, NUM_TAGS};
use serialize;
} else if 0x100 <= n && n < NUM_TAGS {
w.write_all(&[0xf0 | (n >> 8) as u8, n as u8])
} else {
- Err(io::Error::new(io::ErrorKind::Other,
- &format!("invalid tag: {}", n)[..]))
+ Err(io::Error::new(io::ErrorKind::Other, &format!("invalid tag: {}", n)[..]))
}
}
match size {
1 => w.write_all(&[0x80 | (n as u8)]),
2 => w.write_all(&[0x40 | ((n >> 8) as u8), n as u8]),
- 3 => w.write_all(&[0x20 | ((n >> 16) as u8), (n >> 8) as u8,
- n as u8]),
- 4 => w.write_all(&[0x10 | ((n >> 24) as u8), (n >> 16) as u8,
- (n >> 8) as u8, n as u8]),
- _ => Err(io::Error::new(io::ErrorKind::Other,
- &format!("isize too big: {}", n)[..]))
+ 3 => w.write_all(&[0x20 | ((n >> 16) as u8), (n >> 8) as u8, n as u8]),
+ 4 => w.write_all(&[0x10 | ((n >> 24) as u8), (n >> 16) as u8, (n >> 8) as u8, n as u8]),
+ _ => Err(io::Error::new(io::ErrorKind::Other, &format!("isize too big: {}", n)[..])),
}
}
pub fn write_vuint<W: Write>(w: &mut W, n: usize) -> EncodeResult {
- if n < 0x7f { return write_sized_vuint(w, n, 1); }
- if n < 0x4000 { return write_sized_vuint(w, n, 2); }
- if n < 0x200000 { return write_sized_vuint(w, n, 3); }
- if n < 0x10000000 { return write_sized_vuint(w, n, 4); }
- Err(io::Error::new(io::ErrorKind::Other,
- &format!("isize too big: {}", n)[..]))
+ if n < 0x7f {
+ return write_sized_vuint(w, n, 1);
+ }
+ if n < 0x4000 {
+ return write_sized_vuint(w, n, 2);
+ }
+ if n < 0x200000 {
+ return write_sized_vuint(w, n, 3);
+ }
+ if n < 0x10000000 {
+ return write_sized_vuint(w, n, 4);
+ }
+ Err(io::Error::new(io::ErrorKind::Other, &format!("isize too big: {}", n)[..]))
}
impl<'a> Encoder<'a> {
pub fn new(w: &'a mut Cursor<Vec<u8>>) -> Encoder<'a> {
Encoder {
writer: w,
- size_positions: vec!(),
+ size_positions: vec![],
relax_limit: 0,
}
}
let mut buf = [0u8; RELAX_MAX_SIZE];
{
let last_size_pos = last_size_pos as usize;
- let data = &self.writer.get_ref()[last_size_pos+4..cur_pos as usize];
+ let data = &self.writer.get_ref()[last_size_pos + 4..cur_pos as usize];
buf[..size].clone_from_slice(data);
}
Ok(())
}
- pub fn wr_tag<F>(&mut self, tag_id: usize, blk: F) -> EncodeResult where
- F: FnOnce() -> EncodeResult,
+ pub fn wr_tag<F>(&mut self, tag_id: usize, blk: F) -> EncodeResult
+ where F: FnOnce() -> EncodeResult
{
try!(self.start_tag(tag_id));
try!(blk());
let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) };
// tagged integers are emitted in big-endian, with no
// leading zeros.
- let leading_zero_bytes = v.leading_zeros()/8;
+ let leading_zero_bytes = v.leading_zeros() / 8;
self.wr_tagged_bytes(tag_id, &bytes[leading_zero_bytes as usize..])
}
#[inline]
- pub fn wr_tagged_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult {
+ pub fn wr_tagged_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult {
self.wr_tagged_u64(tag_id, v as u64)
}
self.wr_tagged_raw_bytes(tag_id, &bytes)
}
- fn wr_tagged_raw_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult{
+ fn wr_tagged_raw_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult {
let bytes: [u8; 4] = unsafe { mem::transmute(v.to_be()) };
self.wr_tagged_raw_bytes(tag_id, &bytes)
}
self.wr_tagged_raw_u32(EsSub32 as usize, v as u32)
} else {
Err(io::Error::new(io::ErrorKind::Other,
- &format!("length or variant id too big: {}",
- v)[..]))
+ &format!("length or variant id too big: {}", v)[..]))
}
}
- pub fn emit_opaque<F>(&mut self, f: F) -> EncodeResult where
- F: FnOnce(&mut opaque::Encoder) -> EncodeResult,
+ pub fn emit_opaque<F>(&mut self, f: F) -> EncodeResult
+ where F: FnOnce(&mut opaque::Encoder) -> EncodeResult
{
try!(self.start_tag(EsOpaque as usize));
self.wr_tagged_str(EsStr as usize, v)
}
- fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
try!(self.start_tag(EsEnum as usize));
try!(f(self));
self.end_tag()
}
- fn emit_enum_variant<F>(&mut self,
- _: &str,
- v_id: usize,
- _: usize,
- f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_enum_variant<F>(&mut self, _: &str, v_id: usize, _: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
try!(self._emit_tagged_sub(v_id));
f(self)
}
- fn emit_enum_variant_arg<F>(&mut self, _: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_enum_variant_arg<F>(&mut self, _: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
f(self)
}
v_name: &str,
v_id: usize,
cnt: usize,
- f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ f: F)
+ -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_enum_variant(v_name, v_id, cnt, f)
}
- fn emit_enum_struct_variant_field<F>(&mut self,
- _: &str,
- idx: usize,
- f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_enum_struct_variant_field<F>(&mut self, _: &str, idx: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_enum_variant_arg(idx, f)
}
- fn emit_struct<F>(&mut self, _: &str, _len: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_struct<F>(&mut self, _: &str, _len: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
f(self)
}
- fn emit_struct_field<F>(&mut self, _name: &str, _: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_struct_field<F>(&mut self, _name: &str, _: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
f(self)
}
- fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_seq(len, f)
}
- fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_seq_elt(idx, f)
}
- fn emit_tuple_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_tuple_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_seq(len, f)
}
- fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_seq_elt(idx, f)
}
- fn emit_option<F>(&mut self, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_option<F>(&mut self, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_enum("Option", f)
}
fn emit_option_none(&mut self) -> EncodeResult {
self.emit_enum_variant("None", 0, 0, |_| Ok(()))
}
- fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_option_some<F>(&mut self, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_enum_variant("Some", 1, 1, f)
}
- fn emit_seq<F>(&mut self, len: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_seq<F>(&mut self, len: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
if len == 0 {
// empty vector optimization
self.end_tag()
}
- fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
try!(self.start_tag(EsVecElt as usize));
self.end_tag()
}
- fn emit_map<F>(&mut self, len: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_map<F>(&mut self, len: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
if len == 0 {
// empty map optimization
self.end_tag()
}
- fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
try!(self.start_tag(EsMapKey as usize));
self.end_tag()
}
- fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
try!(self.start_tag(EsMapVal as usize));
try!(f(self));
#[bench]
pub fn vuint_at_A_aligned(b: &mut Bencher) {
- let data = (0..4*100).map(|i| {
- match i % 2 {
- 0 => 0x80,
- _ => i as u8,
- }
- }).collect::<Vec<_>>();
+ let data = (0..4 * 100)
+ .map(|i| {
+ match i % 2 {
+ 0 => 0x80,
+ _ => i as u8,
+ }
+ })
+ .collect::<Vec<_>>();
let mut sum = 0;
b.iter(|| {
let mut i = 0;
#[bench]
pub fn vuint_at_A_unaligned(b: &mut Bencher) {
- let data = (0..4*100+1).map(|i| {
- match i % 2 {
- 1 => 0x80,
- _ => i as u8
- }
- }).collect::<Vec<_>>();
+ let data = (0..4 * 100 + 1)
+ .map(|i| {
+ match i % 2 {
+ 1 => 0x80,
+ _ => i as u8,
+ }
+ })
+ .collect::<Vec<_>>();
let mut sum = 0;
b.iter(|| {
let mut i = 1;
#[bench]
pub fn vuint_at_D_aligned(b: &mut Bencher) {
- let data = (0..4*100).map(|i| {
- match i % 4 {
- 0 => 0x10,
- 3 => i as u8,
- _ => 0
- }
- }).collect::<Vec<_>>();
+ let data = (0..4 * 100)
+ .map(|i| {
+ match i % 4 {
+ 0 => 0x10,
+ 3 => i as u8,
+ _ => 0,
+ }
+ })
+ .collect::<Vec<_>>();
let mut sum = 0;
b.iter(|| {
let mut i = 0;
#[bench]
pub fn vuint_at_D_unaligned(b: &mut Bencher) {
- let data = (0..4*100+1).map(|i| {
- match i % 4 {
- 1 => 0x10,
- 0 => i as u8,
- _ => 0
- }
- }).collect::<Vec<_>>();
+ let data = (0..4 * 100 + 1)
+ .map(|i| {
+ match i % 4 {
+ 1 => 0x10,
+ 0 => i as u8,
+ _ => 0,
+ }
+ })
+ .collect::<Vec<_>>();
let mut sum = 0;
b.iter(|| {
let mut i = 1;
use Error as DecodeError;
use writer::EncodeResult;
-use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128,
- write_unsigned_leb128};
+use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128};
use std::io::{self, Write};
use serialize;
-//=-----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
// Encoder
-//=-----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
pub struct Encoder<'a> {
pub cursor: &'a mut io::Cursor<Vec<u8>>,
impl<'a> Encoder<'a> {
pub fn new(cursor: &'a mut io::Cursor<Vec<u8>>) -> Encoder<'a> {
- Encoder {
- cursor: cursor
- }
+ Encoder { cursor: cursor }
}
}
}
fn emit_bool(&mut self, v: bool) -> EncodeResult {
- self.emit_u8(if v { 1 } else { 0 })
+ self.emit_u8(if v {
+ 1
+ } else {
+ 0
+ })
}
fn emit_f64(&mut self, v: f64) -> EncodeResult {
}
fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult
- where F: FnOnce(&mut Self) -> EncodeResult {
+ where F: FnOnce(&mut Self) -> EncodeResult
+ {
f(self)
}
_v_name: &str,
v_id: usize,
_len: usize,
- f: F) -> EncodeResult
+ f: F)
+ -> EncodeResult
where F: FnOnce(&mut Self) -> EncodeResult
{
try!(self.emit_uint(v_id));
f(self)
}
- fn emit_enum_variant_arg<F>(&mut self, _: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_enum_variant_arg<F>(&mut self, _: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
f(self)
}
fn emit_enum_struct_variant<F>(&mut self,
- v_name: &str,
- v_id: usize,
- cnt: usize,
- f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ v_name: &str,
+ v_id: usize,
+ cnt: usize,
+ f: F)
+ -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_enum_variant(v_name, v_id, cnt, f)
}
- fn emit_enum_struct_variant_field<F>(&mut self,
- _: &str,
- idx: usize,
- f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_enum_struct_variant_field<F>(&mut self, _: &str, idx: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_enum_variant_arg(idx, f)
}
- fn emit_struct<F>(&mut self, _: &str, _len: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_struct<F>(&mut self, _: &str, _len: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
f(self)
}
- fn emit_struct_field<F>(&mut self, _name: &str, _: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_struct_field<F>(&mut self, _name: &str, _: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
f(self)
}
- fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_seq(len, f)
}
- fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_seq_elt(idx, f)
}
- fn emit_tuple_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_tuple_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_seq(len, f)
}
- fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_seq_elt(idx, f)
}
- fn emit_option<F>(&mut self, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_option<F>(&mut self, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_enum("Option", f)
}
self.emit_enum_variant("None", 0, 0, |_| Ok(()))
}
- fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_option_some<F>(&mut self, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
self.emit_enum_variant("Some", 1, 1, f)
}
- fn emit_seq<F>(&mut self, len: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_seq<F>(&mut self, len: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
try!(self.emit_uint(len));
f(self)
}
- fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
f(self)
}
- fn emit_map<F>(&mut self, len: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_map<F>(&mut self, len: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
try!(self.emit_uint(len));
f(self)
}
- fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
f(self)
}
- fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult
+ where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
{
f(self)
}
}
pub fn from_rbml<'b: 'c, 'c>(rbml: &'c mut ::writer::Encoder<'b>) -> Encoder<'c> {
- Encoder {
- cursor: rbml.writer
- }
+ Encoder { cursor: rbml.writer }
}
}
-//=-----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
// Decoder
-//=-----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
pub struct Decoder<'a> {
pub data: &'a [u8],
pub fn new(data: &'a [u8], position: usize) -> Decoder<'a> {
Decoder {
data: data,
- position: position
+ position: position,
}
}
fn read_i8(&mut self) -> Result<i8, Self::Error> {
let as_u8 = self.data[self.position];
self.position += 1;
- unsafe {
- Ok(::std::mem::transmute(as_u8))
- }
+ unsafe { Ok(::std::mem::transmute(as_u8)) }
}
fn read_int(&mut self) -> Result<isize, Self::Error> {
fn read_str(&mut self) -> Result<String, Self::Error> {
let len = try!(self.read_uint());
- let s = ::std::str::from_utf8(&self.data[self.position .. self.position + len]).unwrap();
+ let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap();
self.position += len;
Ok(s.to_string())
}
- fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>,
+ fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
{
f(self)
}
- fn read_enum_variant<T, F>(&mut self,
- _: &[&str],
- mut f: F)
- -> Result<T, Self::Error>
- where F: FnMut(&mut Decoder<'a>, usize) -> Result<T, Self::Error>,
+ fn read_enum_variant<T, F>(&mut self, _: &[&str], mut f: F) -> Result<T, Self::Error>
+ where F: FnMut(&mut Decoder<'a>, usize) -> Result<T, Self::Error>
{
let disr = try!(self.read_uint());
f(self, disr)
}
- fn read_enum_variant_arg<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>,
+ fn read_enum_variant_arg<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
{
f(self)
}
- fn read_enum_struct_variant<T, F>(&mut self,
- _: &[&str],
- mut f: F) -> Result<T, Self::Error>
- where F: FnMut(&mut Decoder<'a>, usize) -> Result<T, Self::Error>,
+ fn read_enum_struct_variant<T, F>(&mut self, _: &[&str], mut f: F) -> Result<T, Self::Error>
+ where F: FnMut(&mut Decoder<'a>, usize) -> Result<T, Self::Error>
{
let disr = try!(self.read_uint());
f(self, disr)
_name: &str,
_idx: usize,
f: F)
- -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>,
+ -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
{
f(self)
}
- fn read_struct<T, F>(&mut self, _name: &str, _: usize, f: F) -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>,
+ fn read_struct<T, F>(&mut self, _name: &str, _: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
{
f(self)
}
- fn read_struct_field<T, F>(&mut self,
- _name: &str,
- _idx: usize, f: F)
- -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>,
+ fn read_struct_field<T, F>(&mut self, _name: &str, _idx: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
{
f(self)
}
- fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>,
+ fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
{
self.read_seq(move |d, len| {
if len == tuple_len {
f(d)
} else {
let err = format!("Invalid tuple length. Expected {}, found {}",
- tuple_len,
- len);
+ tuple_len,
+ len);
Err(DecodeError::Expected(err))
}
})
}
- fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>,
+ fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
{
self.read_seq_elt(idx, f)
}
- fn read_tuple_struct<T, F>(&mut self,
- _name: &str,
- len: usize, f: F)
- -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>,
+ fn read_tuple_struct<T, F>(&mut self, _name: &str, len: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
{
self.read_tuple(len, f)
}
- fn read_tuple_struct_arg<T, F>(&mut self,
- idx: usize,
- f: F)
- -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>,
+ fn read_tuple_struct_arg<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
{
self.read_tuple_arg(idx, f)
}
- fn read_option<T, F>(&mut self, mut f: F) -> Result<T, Self::Error> where
- F: FnMut(&mut Decoder<'a>, bool) -> Result<T, Self::Error>,
+ fn read_option<T, F>(&mut self, mut f: F) -> Result<T, Self::Error>
+ where F: FnMut(&mut Decoder<'a>, bool) -> Result<T, Self::Error>
{
self.read_enum("Option", move |this| {
this.read_enum_variant(&["None", "Some"], move |this, idx| {
})
}
- fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>, usize) -> Result<T, Self::Error>,
+ fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>, usize) -> Result<T, Self::Error>
{
let len = try!(self.read_uint());
f(self, len)
}
- fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>,
+ fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
{
f(self)
}
- fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>, usize) -> Result<T, Self::Error>,
+ fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>, usize) -> Result<T, Self::Error>
{
let len = try!(self.read_uint());
f(self, len)
}
- fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>,
+ fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
{
f(self)
}
- fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error> where
- F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>,
+ fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
{
f(self)
}
#[cfg(test)]
mod tests {
use serialize::{Encodable, Decodable};
- use std::io::{Cursor};
+ use std::io::Cursor;
use std::fmt::Debug;
use super::{Encoder, Decoder};
}
- fn check_round_trip<T: Encodable+Decodable+PartialEq+Debug>(values: Vec<T>) {
+ fn check_round_trip<T: Encodable + Decodable + PartialEq + Debug>(values: Vec<T>) {
let mut cursor = Cursor::new(Vec::new());
for value in &values {
#[test]
fn test_u8() {
let mut vec = vec![];
- for i in ::std::u8::MIN .. ::std::u8::MAX {
+ for i in ::std::u8::MIN..::std::u8::MAX {
vec.push(i);
}
check_round_trip(vec);
#[test]
fn test_u16() {
- for i in ::std::u16::MIN .. ::std::u16::MAX {
+ for i in ::std::u16::MIN..::std::u16::MAX {
check_round_trip(vec![1, 2, 3, i, i, i]);
}
}
#[test]
fn test_i8() {
let mut vec = vec![];
- for i in ::std::i8::MIN .. ::std::i8::MAX {
+ for i in ::std::i8::MIN..::std::i8::MAX {
vec.push(i);
}
check_round_trip(vec);
#[test]
fn test_i16() {
- for i in ::std::i16::MIN .. ::std::i16::MAX {
+ for i in ::std::i16::MIN..::std::i16::MAX {
check_round_trip(vec![-1, 2, -3, i, i, i, 2]);
}
}
#[test]
fn test_f32() {
let mut vec = vec![];
- for i in -100 .. 100 {
- vec.push( (i as f32) / 3.0 );
+ for i in -100..100 {
+ vec.push((i as f32) / 3.0);
}
check_round_trip(vec);
}
#[test]
fn test_f64() {
let mut vec = vec![];
- for i in -100 .. 100 {
- vec.push( (i as f64) / 3.0 );
+ for i in -100..100 {
+ vec.push((i as f64) / 3.0);
}
check_round_trip(vec);
}
#[test]
fn test_string() {
- let vec = vec![
- "abcbuÖeiovÄnameÜavmpßvmea€µsbpnvapeapmaebn".to_string(),
- "abcbuÖganeiovÄnameÜavmpßvmea€µsbpnvapeapmaebn".to_string(),
- "abcbuÖganeiovÄnameÜavmpßvmea€µsbpapmaebn".to_string(),
- "abcbuÖganeiovÄnameÜavmpßvmeabpnvapeapmaebn".to_string(),
- "abcbuÖganeiÄnameÜavmpßvmea€µsbpnvapeapmaebn".to_string(),
- "abcbuÖganeiovÄnameÜavmpßvmea€µsbpmaebn".to_string(),
- "abcbuÖganeiovÄnameÜavmpßvmea€µnvapeapmaebn".to_string()];
+ let vec = vec!["abcbuÖeiovÄnameÜavmpßvmea€µsbpnvapeapmaebn".to_string(),
+ "abcbuÖganeiovÄnameÜavmpßvmea€µsbpnvapeapmaebn".to_string(),
+ "abcbuÖganeiovÄnameÜavmpßvmea€µsbpapmaebn".to_string(),
+ "abcbuÖganeiovÄnameÜavmpßvmeabpnvapeapmaebn".to_string(),
+ "abcbuÖganeiÄnameÜavmpßvmea€µsbpnvapeapmaebn".to_string(),
+ "abcbuÖganeiovÄnameÜavmpßvmea€µsbpmaebn".to_string(),
+ "abcbuÖganeiovÄnameÜavmpßvmea€µnvapeapmaebn".to_string()];
check_round_trip(vec);
}
#[test]
fn test_struct() {
check_round_trip(vec![Struct {
- a: (),
- b: 10,
- c: 11,
- d: 12,
- e: 13,
- f: 14,
-
- g: 15,
- h: 16,
- i: 17,
- j: 18,
- k: 19,
-
- l: 'x',
- m: "abc".to_string(),
- n: 20.5,
- o: 21.5,
- p: false,
- q: None,
- }]);
+ a: (),
+ b: 10,
+ c: 11,
+ d: 12,
+ e: 13,
+ f: 14,
+
+ g: 15,
+ h: 16,
+ i: 17,
+ j: 18,
+ k: 19,
+
+ l: 'x',
+ m: "abc".to_string(),
+ n: 20.5,
+ o: 21.5,
+ p: false,
+ q: None,
+ }]);
check_round_trip(vec![Struct {
- a: (),
- b: 101,
- c: 111,
- d: 121,
- e: 131,
- f: 141,
-
- g: -15,
- h: -16,
- i: -17,
- j: -18,
- k: -19,
-
- l: 'y',
- m: "def".to_string(),
- n: -20.5,
- o: -21.5,
- p: true,
- q: Some(1234567),
- }]);
+ a: (),
+ b: 101,
+ c: 111,
+ d: 121,
+ e: 131,
+ f: 141,
+
+ g: -15,
+ h: -16,
+ i: -17,
+ j: -18,
+ k: -19,
+
+ l: 'y',
+ m: "def".to_string(),
+ n: -20.5,
+ o: -21.5,
+ p: true,
+ q: Some(1234567),
+ }]);
}
#[derive(PartialEq, Clone, Debug, RustcEncodable, RustcDecodable)]
enum Enum {
Variant1,
Variant2(usize, f32),
- Variant3 { a: i32, b: char, c: bool }
+ Variant3 {
+ a: i32,
+ b: char,
+ c: bool,
+ },
}
#[test]
fn test_enum() {
check_round_trip(vec![Enum::Variant1,
Enum::Variant2(1, 2.5),
- Enum::Variant3 { a: 3, b: 'b', c: false },
- Enum::Variant3 { a: -4, b: 'f', c: true }]);
+ Enum::Variant3 {
+ a: 3,
+ b: 'b',
+ c: false,
+ },
+ Enum::Variant3 {
+ a: -4,
+ b: 'f',
+ c: true,
+ }]);
}
#[test]
fn test_sequence() {
let mut vec = vec![];
- for i in -100i64 .. 100i64 {
- vec.push(i*100000);
+ for i in -100i64..100i64 {
+ vec.push(i * 100000);
}
check_round_trip(vec![vec]);
fn test_hash_map() {
use std::collections::HashMap;
let mut map = HashMap::new();
- for i in -100i64 .. 100i64 {
- map.insert(i*100000, i*10000);
+ for i in -100i64..100i64 {
+ map.insert(i * 100000, i * 10000);
}
check_round_trip(vec![map]);
```
"##,
-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
-the heap at runtime, and therefore cannot be done at compile time. Erroneous
-code example:
-
-```
-#![feature(box_syntax)]
-
-const CON : Box<i32> = box 0;
-```
-"##,
-
-E0011: r##"
-Initializers for constants and statics are evaluated at compile time.
-User-defined operators rely on user-defined functions, which cannot be evaluated
-at compile time.
-
-Bad example:
-
-```
-use std::ops::Index;
-
-struct Foo { a: u8 }
-
-impl Index<u8> for Foo {
- type Output = u8;
-
- fn index<'a>(&'a self, idx: u8) -> &'a u8 { &self.a }
-}
-
-const a: Foo = Foo { a: 0u8 };
-const b: u8 = a[0]; // Index trait is defined by the user, bad!
-```
-
-Only operators on builtin types are allowed.
-
-Example:
-
-```
-const a: &'static [i32] = &[1, 2, 3];
-const b: i32 = a[0]; // Good!
-```
-"##,
-
-E0013: r##"
-Static and const variables can refer to other const variables. But a const
-variable cannot refer to a static variable. For example, `Y` cannot refer to `X`
-here:
-
-```
-static X: i32 = 42;
-const Y: i32 = X;
-```
-
-To fix this, the value can be extracted as a const and then used:
-
-```
-const A: i32 = 42;
-static X: i32 = A;
-const Y: i32 = A;
-```
-"##,
-
-E0014: r##"
-Constants can only be initialized by a constant value or, in a future
-version of Rust, a call to a const function. This error indicates the use
-of a path (like a::b, or x) denoting something other than one of these
-allowed items. Example:
-
-```
-const FOO: i32 = { let x = 0; x }; // 'x' isn't a constant nor a function!
-```
-
-To avoid it, you have to replace the non-constant value:
-
-```
-const FOO: i32 = { const X : i32 = 0; X };
-// or even:
-const FOO: i32 = { 0 }; // but brackets are useless here
-```
-"##,
-
-// FIXME(#24111) Change the language here when const fn stabilizes
-E0015: r##"
-The only functions that can be called in static or constant expressions are
-`const` functions, and struct/enum constructors. `const` functions are only
-available on a nightly compiler. Rust currently does not support more general
-compile-time function execution.
-
-```
-const FOO: Option<u8> = Some(1); // enum constructor
-struct Bar {x: u8}
-const BAR: Bar = Bar {x: 1}; // struct constructor
-```
-
-See [RFC 911] for more details on the design of `const fn`s.
-
-[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
-"##,
-
-E0017: r##"
-References in statics and constants may only refer to immutable values. Example:
-
-```
-static X: i32 = 1;
-const C: i32 = 2;
-
-// these three are not allowed:
-const CR: &'static mut i32 = &mut C;
-static STATIC_REF: &'static mut i32 = &mut X;
-static CONST_REF: &'static mut i32 = &mut C;
-```
-
-Statics are shared everywhere, and if they refer to mutable data one might
-violate memory safety since holding multiple mutable references to shared data
-is not allowed.
-
-If you really want global mutable state, try using `static mut` or a global
-`UnsafeCell`.
-"##,
-
-E0018: r##"
-The value of static and const variables must be known at compile time. You
-can't cast a pointer as an integer because we can't know what value the
-address will take.
-
-However, pointers to other constants' addresses are allowed in constants,
-example:
-
-```
-const X: u32 = 50;
-const Y: *const u32 = &X;
-```
-
-Therefore, casting one of these non-constant pointers to an integer results
-in a non-constant integer which lead to this error. Example:
-
-```
-const X: u32 = 1;
-const Y: usize = &X as *const u32 as usize;
-println!("{}", Y);
-```
-"##,
-
-E0019: r##"
-A function call isn't allowed in the const's initialization expression
-because the expression's value must be known at compile-time. Example of
-erroneous code:
-
-```
-enum Test {
- V1
-}
-
-impl Test {
- fn test(&self) -> i32 {
- 12
- }
-}
-
-fn main() {
- const FOO: Test = Test::V1;
-
- const A: i32 = FOO.test(); // You can't call Test::func() here !
-}
-```
-
-Remember: you can't use a function call inside a const's initialization
-expression! However, you can totally use it anywhere else:
-
-```
-fn main() {
- const FOO: Test = Test::V1;
-
- FOO.func(); // here is good
- let x = FOO.func(); // or even here!
-}
-```
-"##,
-
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
```
"##,
-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:
-
-```
-match 5u32 {
- // This range is ok, albeit pointless.
- 1 ... 1 => ...
- // This range is empty, and the compiler can tell.
- 1000 ... 5 => ...
-}
-```
-"##,
-
E0038: r####"
Trait objects like `Box<Trait>` can only be constructed when certain
requirements are satisfied by the trait in question.
```
"##,
-E0161: r##"
-In Rust, you can only move a value when its size is known at compile time.
-
-To work around this restriction, consider "hiding" the value behind a reference:
-either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
-it around as usual.
-"##,
-
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
```
"##,
-E0265: r##"
-This error indicates that a static or constant references itself.
-All statics and constants need to resolve to a value in an acyclic manner.
-
-For example, neither of the following can be sensibly compiled:
-
-```
-const X: u32 = X;
-```
-
-```
-const X: u32 = Y;
-const Y: u32 = X;
-```
-"##,
-
-E0267: r##"
-This error indicates the use of a loop keyword (`break` or `continue`) inside a
-closure but outside of any loop. Erroneous code example:
-
-```
-let w = || { break; }; // error: `break` inside of a closure
-```
-
-`break` and `continue` keywords can be used as normal inside closures as long as
-they are also contained within a loop. To halt the execution of a closure you
-should instead use a return statement. Example:
-
-```
-let w = || {
- for _ in 0..10 {
- break;
- }
-};
-
-w();
-```
-"##,
-
-E0268: r##"
-This error indicates the use of a loop keyword (`break` or `continue`) outside
-of a loop. Without a loop to break out of or continue in, no sensible action can
-be taken. Erroneous code example:
-
-```
-fn some_func() {
- break; // error: `break` outside of loop
-}
-```
-
-Please verify that you are using `break` and `continue` only in loops. Example:
-
-```
-fn some_func() {
- for _ in 0..10 {
- break; // ok!
- }
-}
-```
-"##,
-
E0269: r##"
Functions must eventually return a value of their return type. For example, in
the following function
```
"##,
-E0378: r##"
-Method calls that aren't calls to inherent `const` methods are disallowed
-in statics, constants, and constant functions.
-
-For example:
-
-```
-const BAZ: i32 = Foo(25).bar(); // error, `bar` isn't `const`
-
-struct Foo(i32);
-
-impl Foo {
- const fn foo(&self) -> i32 {
- self.bar() // error, `bar` isn't `const`
- }
-
- fn bar(&self) -> i32 { self.0 }
-}
-```
-
-For more information about `const fn`'s, see [RFC 911].
-
-[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
-"##,
-
-E0394: r##"
-From [RFC 246]:
-
- > It is invalid for a static to reference another static by value. It is
- > required that all references be borrowed.
-
-[RFC 246]: https://github.com/rust-lang/rfcs/pull/246
-"##,
-
-E0395: r##"
-The value assigned to a constant expression must be known at compile time,
-which is not the case when comparing raw pointers. Erroneous code example:
-
-```
-static foo: i32 = 42;
-static bar: i32 = 43;
-
-static baz: bool = { (&foo as *const i32) == (&bar as *const i32) };
-// error: raw pointers cannot be compared in statics!
-```
-
-Please check that the result of the comparison can be determined at compile time
-or isn't assigned to a constant expression. Example:
-
-```
-static foo: i32 = 42;
-static bar: i32 = 43;
-
-let baz: bool = { (&foo as *const i32) == (&bar as *const i32) };
-// baz isn't a constant expression so it's ok
-```
-"##,
-
-E0396: r##"
-The value assigned to a constant expression must be known at compile time,
-which is not the case when dereferencing raw pointers. Erroneous code
-example:
-
-```
-const foo: i32 = 42;
-const baz: *const i32 = (&foo as *const i32);
-
-const deref: i32 = *baz;
-// error: raw pointers cannot be dereferenced in constants
-```
-
-To fix this error, please do not assign this value to a constant expression.
-Example:
-
-```
-const foo: i32 = 42;
-const baz: *const i32 = (&foo as *const i32);
-
-unsafe { let deref: i32 = *baz; }
-// baz isn't a constant expression so it's ok
-```
-
-You'll also note that this assignment must be done in an unsafe block!
-"##,
-
-E0397: r##"
-It is not allowed for a mutable static to allocate or have destructors. For
-example:
-
-```
-// error: mutable statics are not allowed to have boxes
-static mut FOO: Option<Box<usize>> = None;
-
-// error: mutable statics are not allowed to have destructors
-static mut BAR: Option<Vec<i32>> = None;
-```
-"##,
-
E0398: r##"
In Rust 1.3, the default object lifetime bounds are expected to
change, as described in RFC #1156 [1]. You are getting a warning
[1]: https://github.com/rust-lang/rfcs/pull/1156
"##,
-E0400: r##"
-A user-defined dereference was attempted in an invalid context. Erroneous
-code example:
-
-```
-use std::ops::Deref;
-
-struct A;
-
-impl Deref for A {
- type Target = str;
-
- fn deref(&self)-> &str { "foo" }
-}
-
-const S: &'static str = &A;
-// error: user-defined dereference operators are not allowed in constants
-
-fn main() {
- let foo = S;
-}
-```
-
-You cannot directly use a dereference operation whilst initializing a constant
-or a static. To fix this error, restructure your code to avoid this dereference,
-perhaps moving it inline:
-
-```
-use std::ops::Deref;
-
-struct A;
-
-impl Deref for A {
- type Target = str;
-
- fn deref(&self)-> &str { "foo" }
-}
-
-fn main() {
- let foo : &str = &A;
-}
-```
-"##,
-
E0452: r##"
An invalid lint attribute has been given. Erroneous code example:
```
"##,
-E0492: r##"
-A borrow of a constant containing interior mutability was attempted. Erroneous
-code example:
-
-```
-use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
-
-const A: AtomicUsize = ATOMIC_USIZE_INIT;
-static B: &'static AtomicUsize = &A;
-// error: cannot borrow a constant which contains interior mutability, create a
-// static instead
-```
-
-A `const` represents a constant value that should never change. If one takes
-a `&` reference to the constant, then one is taking a pointer to some memory
-location containing the value. Normally this is perfectly fine: most values
-can't be changed via a shared `&` pointer, but interior mutability would allow
-it. That is, a constant value could be mutated. On the other hand, a `static` is
-explicitly a single memory location, which can be mutated at will.
-
-So, in order to solve this error, either use statics which are `Sync`:
-
-```
-use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
-
-static A: AtomicUsize = ATOMIC_USIZE_INIT;
-static B: &'static AtomicUsize = &A; // ok!
-```
-
-You can also have this error while using a cell type:
-
-```
-#![feature(const_fn)]
-
-use std::cell::Cell;
-
-const A: Cell<usize> = Cell::new(1);
-const B: &'static Cell<usize> = &A;
-// error: cannot borrow a constant which contains interior mutability, create
-// a static instead
-
-// or:
-struct C { a: Cell<usize> }
-
-const D: C = C { a: Cell::new(1) };
-const E: &'static Cell<usize> = &D.a; // error
-
-// or:
-const F: &'static C = &D; // error
-```
-
-This is because cell types do operations that are not thread-safe. Due to this,
-they don't implement Sync and thus can't be placed in statics. In this
-case, `StaticMutex` would work just fine, but it isn't stable yet:
-https://doc.rust-lang.org/nightly/std/sync/struct.StaticMutex.html
-
-However, if you still wish to use these types, you can achieve this by an unsafe
-wrapper:
-
-```
-#![feature(const_fn)]
-
-use std::cell::Cell;
-use std::marker::Sync;
-
-struct NotThreadSafe<T> {
- value: Cell<T>,
-}
-
-unsafe impl<T> Sync for NotThreadSafe<T> {}
-
-static A: NotThreadSafe<usize> = NotThreadSafe { value : Cell::new(1) };
-static B: &'static NotThreadSafe<usize> = &A; // ok!
-```
-
-Remember this solution is unsafe! You will have to ensure that accesses to the
-cell are synchronized.
-"##,
-
-E0493: r##"
-A type with a destructor was assigned to an invalid type of variable. Erroneous
-code example:
-
-```
-struct Foo {
- a: u32
-}
-
-impl Drop for Foo {
- fn drop(&mut self) {}
-}
-
-const F : Foo = Foo { a : 0 };
-// error: constants are not allowed to have destructors
-static S : Foo = Foo { a : 0 };
-// error: statics are not allowed to have destructors
-```
-
-To solve this issue, please use a type which does allow the usage of type with
-destructors.
-"##,
-
-E0494: r##"
-A reference of an interior static was assigned to another const/static.
-Erroneous code example:
-
-```
-struct Foo {
- a: u32
-}
-
-static S : Foo = Foo { a : 0 };
-static A : &'static u32 = &S.a;
-// error: cannot refer to the interior of another static, use a
-// constant instead
-```
-
-The "base" variable has to be a const if you want another static/const variable
-to refer to one of its fields. Example:
-
-```
-struct Foo {
- a: u32
-}
-
-const S : Foo = Foo { a : 0 };
-static A : &'static u32 = &S.a; // ok!
-```
-"##,
-
E0496: r##"
A lifetime name is shadowing another lifetime name. Erroneous code example:
pub mod astconv_util;
pub mod expr_use_visitor; // STAGE0: increase glitch immunity
pub mod cfg;
- pub mod check_const;
- pub mod check_static_recursion;
- pub mod check_loop;
pub mod check_match;
- pub mod check_rvalues;
pub mod const_eval;
+ pub mod const_qualif;
pub mod cstore;
pub mod dataflow;
pub mod dead;
* Almost certainly this could (and should) be refactored out of existence.
*/
-use middle::def;
+use middle::def::Def;
use middle::ty::{self, Ty};
use syntax::codemap::Span;
}
Some(d) => d.full_def()
};
- if let def::DefPrimTy(nty) = def {
+ if let Def::PrimTy(nty) = def {
Some(prim_ty_to_ty(tcx, &path.segments, nty))
} else {
None
use rustc_data_structures::graph;
use middle::cfg::*;
-use middle::def;
+use middle::def::Def;
use middle::pat_util;
use middle::ty;
use syntax::ast;
}
match self.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
- Some(def::DefLabel(loop_id)) => {
+ Some(Def::Label(loop_id)) => {
for l in &self.loop_scopes {
if l.loop_id == loop_id {
return *l;
+++ /dev/null
-// Copyright 2012-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.
-
-// Verifies that the types and values of const and static items
-// are safe. The rules enforced by this module are:
-//
-// - For each *mutable* static item, it checks that its **type**:
-// - doesn't have a destructor
-// - doesn't own a box
-//
-// - For each *immutable* static item, it checks that its **value**:
-// - doesn't own a box
-// - doesn't contain a struct literal or a call to an enum variant / struct constructor where
-// - the type of the struct/enum has a dtor
-//
-// Rules Enforced Elsewhere:
-// - It's not possible to take the address of a static item with unsafe interior. This is enforced
-// by borrowck::gather_loans
-
-use dep_graph::DepNode;
-use middle::ty::cast::{CastKind};
-use middle::const_eval::{self, ConstEvalErr};
-use middle::const_eval::ErrKind::IndexOpFeatureGated;
-use middle::const_eval::EvalHint::ExprTypeChecked;
-use middle::def;
-use middle::def_id::DefId;
-use middle::expr_use_visitor as euv;
-use middle::infer;
-use middle::mem_categorization as mc;
-use middle::mem_categorization::Categorization;
-use middle::traits;
-use middle::ty::{self, Ty};
-use util::nodemap::NodeMap;
-
-use rustc_front::hir;
-use syntax::ast;
-use syntax::codemap::Span;
-use syntax::feature_gate::UnstableFeatures;
-use rustc_front::intravisit::{self, FnKind, Visitor};
-
-use std::collections::hash_map::Entry;
-use std::cmp::Ordering;
-
-// Const qualification, from partial to completely promotable.
-bitflags! {
- #[derive(RustcEncodable, RustcDecodable)]
- flags ConstQualif: u8 {
- // Inner mutability (can not be placed behind a reference) or behind
- // &mut in a non-global expression. Can be copied from static memory.
- const MUTABLE_MEM = 1 << 0,
- // Constant value with a type that implements Drop. Can be copied
- // from static memory, similar to MUTABLE_MEM.
- const NEEDS_DROP = 1 << 1,
- // Even if the value can be placed in static memory, copying it from
- // there is more expensive than in-place instantiation, and/or it may
- // be too large. This applies to [T; N] and everything containing it.
- // N.B.: references need to clear this flag to not end up on the stack.
- const PREFER_IN_PLACE = 1 << 2,
- // May use more than 0 bytes of memory, doesn't impact the constness
- // directly, but is not allowed to be borrowed mutably in a constant.
- const NON_ZERO_SIZED = 1 << 3,
- // Actually borrowed, has to always be in static memory. Does not
- // propagate, and requires the expression to behave like a 'static
- // lvalue. The set of expressions with this flag is the minimum
- // that have to be promoted.
- const HAS_STATIC_BORROWS = 1 << 4,
- // Invalid const for miscellaneous reasons (e.g. not implemented).
- const NOT_CONST = 1 << 5,
-
- // Borrowing the expression won't produce &'static T if any of these
- // bits are set, though the value could be copied from static memory
- // if `NOT_CONST` isn't set.
- const NON_STATIC_BORROWS = ConstQualif::MUTABLE_MEM.bits |
- ConstQualif::NEEDS_DROP.bits |
- ConstQualif::NOT_CONST.bits
- }
-}
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-enum Mode {
- Const,
- ConstFn,
- Static,
- StaticMut,
-
- // An expression that occurs outside of any constant context
- // (i.e. `const`, `static`, array lengths, etc.). The value
- // can be variable at runtime, but will be promotable to
- // static memory if we can prove it is actually constant.
- Var,
-}
-
-struct CheckCrateVisitor<'a, 'tcx: 'a> {
- tcx: &'a ty::ctxt<'tcx>,
- mode: Mode,
- qualif: ConstQualif,
- rvalue_borrows: NodeMap<hir::Mutability>
-}
-
-impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
- fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R where
- F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>) -> R,
- {
- let (old_mode, old_qualif) = (self.mode, self.qualif);
- self.mode = mode;
- self.qualif = ConstQualif::empty();
- let r = f(self);
- self.mode = old_mode;
- self.qualif = old_qualif;
- r
- }
-
- fn with_euv<'b, F, R>(&'b mut self, item_id: Option<ast::NodeId>, f: F) -> R where
- F: for<'t> FnOnce(&mut euv::ExprUseVisitor<'b, 't, 'b, 'tcx>) -> R,
- {
- let param_env = match item_id {
- Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
- None => self.tcx.empty_parameter_environment()
- };
-
- let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env));
-
- f(&mut euv::ExprUseVisitor::new(self, &infcx))
- }
-
- fn global_expr(&mut self, mode: Mode, expr: &hir::Expr) -> ConstQualif {
- assert!(mode != Mode::Var);
- match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) {
- Entry::Occupied(entry) => return *entry.get(),
- Entry::Vacant(entry) => {
- // Prevent infinite recursion on re-entry.
- entry.insert(ConstQualif::empty());
- }
- }
- self.with_mode(mode, |this| {
- this.with_euv(None, |euv| euv.consume_expr(expr));
- this.visit_expr(expr);
- this.qualif
- })
- }
-
- fn fn_like(&mut self,
- fk: FnKind,
- fd: &hir::FnDecl,
- b: &hir::Block,
- s: Span,
- fn_id: ast::NodeId)
- -> ConstQualif {
- match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) {
- Entry::Occupied(entry) => return *entry.get(),
- Entry::Vacant(entry) => {
- // Prevent infinite recursion on re-entry.
- entry.insert(ConstQualif::empty());
- }
- }
-
- let mode = match fk {
- FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _) => {
- Mode::ConstFn
- }
- FnKind::Method(_, m, _) => {
- if m.constness == hir::Constness::Const {
- Mode::ConstFn
- } else {
- Mode::Var
- }
- }
- _ => Mode::Var
- };
-
- let qualif = self.with_mode(mode, |this| {
- this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
- intravisit::walk_fn(this, fk, fd, b, s);
- this.qualif
- });
-
- // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
- // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
- let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
-
- self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
- qualif
- }
-
- fn add_qualif(&mut self, qualif: ConstQualif) {
- self.qualif = self.qualif | qualif;
- }
-
- /// Returns true if the call is to a const fn or method.
- fn handle_const_fn_call(&mut self,
- expr: &hir::Expr,
- def_id: DefId,
- ret_ty: Ty<'tcx>)
- -> bool {
- if let Some(fn_like) = const_eval::lookup_const_fn_by_id(self.tcx, def_id) {
- if
- // we are in a static/const initializer
- self.mode != Mode::Var &&
-
- // feature-gate is not enabled
- !self.tcx.sess.features.borrow().const_fn &&
-
- // this doesn't come from a macro that has #[allow_internal_unstable]
- !self.tcx.sess.codemap().span_allows_unstable(expr.span)
- {
- let mut err = self.tcx.sess.struct_span_err(
- expr.span,
- "const fns are an unstable feature");
- fileline_help!(
- &mut err,
- expr.span,
- "in Nightly builds, add `#![feature(const_fn)]` to the crate \
- attributes to enable");
- err.emit();
- }
-
- let qualif = self.fn_like(fn_like.kind(),
- fn_like.decl(),
- fn_like.body(),
- fn_like.span(),
- fn_like.id());
- self.add_qualif(qualif);
-
- if ret_ty.type_contents(self.tcx).interior_unsafe() {
- self.add_qualif(ConstQualif::MUTABLE_MEM);
- }
-
- true
- } else {
- false
- }
- }
-
- fn record_borrow(&mut self, id: ast::NodeId, mutbl: hir::Mutability) {
- match self.rvalue_borrows.entry(id) {
- Entry::Occupied(mut entry) => {
- // Merge the two borrows, taking the most demanding
- // one, mutability-wise.
- if mutbl == hir::MutMutable {
- entry.insert(mutbl);
- }
- }
- Entry::Vacant(entry) => {
- entry.insert(mutbl);
- }
- }
- }
-
- fn msg(&self) -> &'static str {
- match self.mode {
- Mode::Const => "constant",
- Mode::ConstFn => "constant function",
- Mode::StaticMut | Mode::Static => "static",
- Mode::Var => unreachable!(),
- }
- }
-
- fn check_static_mut_type(&self, e: &hir::Expr) {
- let node_ty = self.tcx.node_id_to_type(e.id);
- let tcontents = node_ty.type_contents(self.tcx);
-
- let suffix = if tcontents.has_dtor() {
- "destructors"
- } else if tcontents.owns_owned() {
- "boxes"
- } else {
- return
- };
-
- span_err!(self.tcx.sess, e.span, E0397,
- "mutable statics are not allowed to have {}", suffix);
- }
-
- fn check_static_type(&self, e: &hir::Expr) {
- let ty = self.tcx.node_id_to_type(e.id);
- let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
- let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
- let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();
- fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
- match fulfill_cx.select_all_or_error(&infcx) {
- Ok(()) => { },
- Err(ref errors) => {
- traits::report_fulfillment_errors(&infcx, errors);
- }
- }
- }
-}
-
-impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
- fn visit_item(&mut self, i: &hir::Item) {
- debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
- assert_eq!(self.mode, Mode::Var);
- match i.node {
- hir::ItemStatic(_, hir::MutImmutable, ref expr) => {
- self.check_static_type(&**expr);
- self.global_expr(Mode::Static, &**expr);
- }
- hir::ItemStatic(_, hir::MutMutable, ref expr) => {
- self.check_static_mut_type(&**expr);
- self.global_expr(Mode::StaticMut, &**expr);
- }
- hir::ItemConst(_, ref expr) => {
- self.global_expr(Mode::Const, &**expr);
- }
- hir::ItemEnum(ref enum_definition, _) => {
- for var in &enum_definition.variants {
- if let Some(ref ex) = var.node.disr_expr {
- self.global_expr(Mode::Const, &**ex);
- }
- }
- }
- _ => {
- intravisit::walk_item(self, i);
- }
- }
- }
-
- fn visit_trait_item(&mut self, t: &'v hir::TraitItem) {
- match t.node {
- hir::ConstTraitItem(_, ref default) => {
- if let Some(ref expr) = *default {
- self.global_expr(Mode::Const, &*expr);
- } else {
- intravisit::walk_trait_item(self, t);
- }
- }
- _ => self.with_mode(Mode::Var, |v| intravisit::walk_trait_item(v, t)),
- }
- }
-
- fn visit_impl_item(&mut self, i: &'v hir::ImplItem) {
- match i.node {
- hir::ImplItemKind::Const(_, ref expr) => {
- self.global_expr(Mode::Const, &*expr);
- }
- _ => self.with_mode(Mode::Var, |v| intravisit::walk_impl_item(v, i)),
- }
- }
-
- fn visit_fn(&mut self,
- fk: FnKind<'v>,
- fd: &'v hir::FnDecl,
- b: &'v hir::Block,
- s: Span,
- fn_id: ast::NodeId) {
- self.fn_like(fk, fd, b, s, fn_id);
- }
-
- fn visit_pat(&mut self, p: &hir::Pat) {
- match p.node {
- hir::PatLit(ref lit) => {
- self.global_expr(Mode::Const, &**lit);
- }
- hir::PatRange(ref start, ref end) => {
- self.global_expr(Mode::Const, &**start);
- self.global_expr(Mode::Const, &**end);
-
- match const_eval::compare_lit_exprs(self.tcx, start, end) {
- Some(Ordering::Less) |
- Some(Ordering::Equal) => {}
- Some(Ordering::Greater) => {
- span_err!(self.tcx.sess, start.span, E0030,
- "lower range bound must be less than or equal to upper");
- }
- None => {
- self.tcx.sess.delay_span_bug(start.span,
- "non-constant path in constant expr");
- }
- }
- }
- _ => intravisit::walk_pat(self, p)
- }
- }
-
- fn visit_block(&mut self, block: &hir::Block) {
- // Check all statements in the block
- for stmt in &block.stmts {
- match stmt.node {
- hir::StmtDecl(ref decl, _) => {
- match decl.node {
- hir::DeclLocal(_) => {},
- // Item statements are allowed
- hir::DeclItem(_) => continue
- }
- }
- hir::StmtExpr(_, _) => {},
- hir::StmtSemi(_, _) => {},
- }
- self.add_qualif(ConstQualif::NOT_CONST);
- // anything else should have been caught by check_const_fn
- assert_eq!(self.mode, Mode::Var);
- }
- intravisit::walk_block(self, block);
- }
-
- fn visit_expr(&mut self, ex: &hir::Expr) {
- let mut outer = self.qualif;
- self.qualif = ConstQualif::empty();
-
- let node_ty = self.tcx.node_id_to_type(ex.id);
- check_expr(self, ex, node_ty);
- check_adjustments(self, ex);
-
- // Special-case some expressions to avoid certain flags bubbling up.
- match ex.node {
- hir::ExprCall(ref callee, ref args) => {
- for arg in args {
- self.visit_expr(&**arg)
- }
-
- let inner = self.qualif;
- self.visit_expr(&**callee);
- // The callee's size doesn't count in the call.
- let added = self.qualif - inner;
- self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
- }
- hir::ExprRepeat(ref element, _) => {
- self.visit_expr(&**element);
- // The count is checked elsewhere (typeck).
- let count = match node_ty.sty {
- ty::TyArray(_, n) => n,
- _ => unreachable!()
- };
- // [element; 0] is always zero-sized.
- if count == 0 {
- self.qualif.remove(ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
- }
- }
- hir::ExprMatch(ref discr, ref arms, _) => {
- // Compute the most demanding borrow from all the arms'
- // patterns and set that on the discriminator.
- let mut borrow = None;
- for pat in arms.iter().flat_map(|arm| &arm.pats) {
- let pat_borrow = self.rvalue_borrows.remove(&pat.id);
- match (borrow, pat_borrow) {
- (None, _) | (_, Some(hir::MutMutable)) => {
- borrow = pat_borrow;
- }
- _ => {}
- }
- }
- if let Some(mutbl) = borrow {
- self.record_borrow(discr.id, mutbl);
- }
- intravisit::walk_expr(self, ex);
- }
- // Division by zero and overflow checking.
- hir::ExprBinary(op, _, _) => {
- intravisit::walk_expr(self, ex);
- let div_or_rem = op.node == hir::BiDiv || op.node == hir::BiRem;
- match node_ty.sty {
- ty::TyUint(_) | ty::TyInt(_) if div_or_rem => {
- if !self.qualif.intersects(ConstQualif::NOT_CONST) {
- match const_eval::eval_const_expr_partial(
- self.tcx, ex, ExprTypeChecked, None) {
- Ok(_) => {}
- Err(ConstEvalErr { kind: IndexOpFeatureGated, ..}) => {},
- Err(msg) => {
- self.tcx.sess.add_lint(::lint::builtin::CONST_ERR, ex.id,
- msg.span,
- msg.description().into_owned())
- }
- }
- }
- }
- _ => {}
- }
- }
- _ => intravisit::walk_expr(self, ex)
- }
-
- // Handle borrows on (or inside the autorefs of) this expression.
- match self.rvalue_borrows.remove(&ex.id) {
- Some(hir::MutImmutable) => {
- // Constants cannot be borrowed if they contain interior mutability as
- // it means that our "silent insertion of statics" could change
- // initializer values (very bad).
- // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
- // propagated from another error, so erroring again would be just noise.
- let tc = node_ty.type_contents(self.tcx);
- if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
- outer = outer | ConstQualif::NOT_CONST;
- if self.mode != Mode::Var {
- span_err!(self.tcx.sess, ex.span, E0492,
- "cannot borrow a constant which contains \
- interior mutability, create a static instead");
- }
- }
- // If the reference has to be 'static, avoid in-place initialization
- // as that will end up pointing to the stack instead.
- if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
- self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
- self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
- }
- }
- Some(hir::MutMutable) => {
- // `&mut expr` means expr could be mutated, unless it's zero-sized.
- if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) {
- if self.mode == Mode::Var {
- outer = outer | ConstQualif::NOT_CONST;
- self.add_qualif(ConstQualif::MUTABLE_MEM);
- } else {
- span_err!(self.tcx.sess, ex.span, E0017,
- "references in {}s may only refer \
- to immutable values", self.msg())
- }
- }
- if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
- self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
- }
- }
- None => {}
- }
- self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
- // Don't propagate certain flags.
- self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
- }
-}
-
-/// This function is used to enforce the constraints on
-/// const/static items. It walks through the *value*
-/// of the item walking down the expression and evaluating
-/// every nested expression. If the expression is not part
-/// of a const/static item, it is qualified for promotion
-/// instead of producing errors.
-fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
- e: &hir::Expr, node_ty: Ty<'tcx>) {
- match node_ty.sty {
- ty::TyStruct(def, _) |
- ty::TyEnum(def, _) if def.has_dtor() => {
- v.add_qualif(ConstQualif::NEEDS_DROP);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0493,
- "{}s are not allowed to have destructors",
- v.msg());
- }
- }
- _ => {}
- }
-
- let method_call = ty::MethodCall::expr(e.id);
- match e.node {
- hir::ExprUnary(..) |
- hir::ExprBinary(..) |
- hir::ExprIndex(..) if v.tcx.tables.borrow().method_map.contains_key(&method_call) => {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0011,
- "user-defined operators are not allowed in {}s", v.msg());
- }
- }
- hir::ExprBox(_) => {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0010,
- "allocations are not allowed in {}s", v.msg());
- }
- }
- hir::ExprUnary(op, ref inner) => {
- match v.tcx.node_id_to_type(inner.id).sty {
- ty::TyRawPtr(_) => {
- assert!(op == hir::UnDeref);
-
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0396,
- "raw pointers cannot be dereferenced in {}s", v.msg());
- }
- }
- _ => {}
- }
- }
- hir::ExprBinary(op, ref lhs, _) => {
- match v.tcx.node_id_to_type(lhs.id).sty {
- ty::TyRawPtr(_) => {
- assert!(op.node == hir::BiEq || op.node == hir::BiNe ||
- op.node == hir::BiLe || op.node == hir::BiLt ||
- op.node == hir::BiGe || op.node == hir::BiGt);
-
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0395,
- "raw pointers cannot be compared in {}s", v.msg());
- }
- }
- _ => {}
- }
- }
- hir::ExprCast(ref from, _) => {
- debug!("Checking const cast(id={})", from.id);
- match v.tcx.cast_kinds.borrow().get(&from.id) {
- None => v.tcx.sess.span_bug(e.span, "no kind for cast"),
- Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0018,
- "raw pointers cannot be cast to integers in {}s", v.msg());
- }
- }
- _ => {}
- }
- }
- hir::ExprPath(..) => {
- let def = v.tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
- match def {
- Some(def::DefVariant(_, _, _)) => {
- // Count the discriminator or function pointer.
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- }
- Some(def::DefStruct(_)) => {
- if let ty::TyBareFn(..) = node_ty.sty {
- // Count the function pointer.
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- }
- }
- Some(def::DefFn(..)) | Some(def::DefMethod(..)) => {
- // Count the function pointer.
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- }
- Some(def::DefStatic(..)) => {
- match v.mode {
- Mode::Static | Mode::StaticMut => {}
- Mode::Const | Mode::ConstFn => {
- span_err!(v.tcx.sess, e.span, E0013,
- "{}s cannot refer to other statics, insert \
- an intermediate constant instead", v.msg());
- }
- Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
- }
- }
- Some(def::DefConst(did)) |
- Some(def::DefAssociatedConst(did)) => {
- if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
- Some(e.id),
- None) {
- let inner = v.global_expr(Mode::Const, expr);
- v.add_qualif(inner);
- }
- }
- Some(def::DefLocal(..)) if v.mode == Mode::ConstFn => {
- // Sadly, we can't determine whether the types are zero-sized.
- v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
- }
- def => {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- debug!("(checking const) found bad def: {:?}", def);
- span_err!(v.tcx.sess, e.span, E0014,
- "paths in {}s may only refer to constants \
- or functions", v.msg());
- }
- }
- }
- }
- hir::ExprCall(ref callee, _) => {
- let mut callee = &**callee;
- loop {
- callee = match callee.node {
- hir::ExprBlock(ref block) => match block.expr {
- Some(ref tail) => &**tail,
- None => break
- },
- _ => break
- };
- }
- let def = v.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def());
- let is_const = match def {
- Some(def::DefStruct(..)) => true,
- Some(def::DefVariant(..)) => {
- // Count the discriminator.
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- true
- }
- Some(def::DefFn(did, _)) => {
- v.handle_const_fn_call(e, did, node_ty)
- }
- Some(def::DefMethod(did)) => {
- match v.tcx.impl_or_trait_item(did).container() {
- ty::ImplContainer(_) => {
- v.handle_const_fn_call(e, did, node_ty)
- }
- ty::TraitContainer(_) => false
- }
- }
- _ => false
- };
- if !is_const {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- // FIXME(#24111) Remove this check when const fn stabilizes
- let (msg, note) =
- if let UnstableFeatures::Disallow = v.tcx.sess.opts.unstable_features {
- (format!("function calls in {}s are limited to \
- struct and enum constructors",
- v.msg()),
- Some("a limited form of compile-time function \
- evaluation is available on a nightly \
- compiler via `const fn`"))
- } else {
- (format!("function calls in {}s are limited \
- to constant functions, \
- struct and enum constructors",
- v.msg()),
- None)
- };
- let mut err = struct_span_err!(v.tcx.sess, e.span, E0015, "{}", msg);
- if let Some(note) = note {
- err.span_note(e.span, note);
- }
- err.emit();
- }
- }
- }
- hir::ExprMethodCall(..) => {
- let method = v.tcx.tables.borrow().method_map[&method_call];
- let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() {
- ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
- ty::TraitContainer(_) => false
- };
- if !is_const {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0378,
- "method calls in {}s are limited to \
- constant inherent methods", v.msg());
- }
- }
- }
- hir::ExprStruct(..) => {
- let did = v.tcx.def_map.borrow().get(&e.id).map(|def| def.def_id());
- if did == v.tcx.lang_items.unsafe_cell_type() {
- v.add_qualif(ConstQualif::MUTABLE_MEM);
- }
- }
-
- hir::ExprLit(_) |
- hir::ExprAddrOf(..) => {
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- }
-
- hir::ExprRepeat(..) => {
- v.add_qualif(ConstQualif::PREFER_IN_PLACE);
- }
-
- hir::ExprClosure(..) => {
- // Paths in constant contexts cannot refer to local variables,
- // as there are none, and thus closures can't have upvars there.
- if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) {
- assert!(v.mode == Mode::Var,
- "global closures can't capture anything");
- v.add_qualif(ConstQualif::NOT_CONST);
- }
- }
-
- hir::ExprBlock(_) |
- hir::ExprIndex(..) |
- hir::ExprField(..) |
- hir::ExprTupField(..) |
- hir::ExprVec(_) |
- hir::ExprType(..) |
- hir::ExprTup(..) => {}
-
- // Conditional control flow (possible to implement).
- hir::ExprMatch(..) |
- hir::ExprIf(..) |
-
- // Loops (not very meaningful in constants).
- hir::ExprWhile(..) |
- hir::ExprLoop(..) |
-
- // More control flow (also not very meaningful).
- hir::ExprBreak(_) |
- hir::ExprAgain(_) |
- hir::ExprRet(_) |
-
- // Miscellaneous expressions that could be implemented.
- hir::ExprRange(..) |
-
- // Expressions with side-effects.
- hir::ExprAssign(..) |
- hir::ExprAssignOp(..) |
- hir::ExprInlineAsm(_) => {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0019,
- "{} contains unimplemented expression type", v.msg());
- }
- }
- }
-}
-
-/// Check the adjustments of an expression
-fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
- match v.tcx.tables.borrow().adjustments.get(&e.id) {
- None |
- Some(&ty::adjustment::AdjustReifyFnPointer) |
- Some(&ty::adjustment::AdjustUnsafeFnPointer) => {}
-
- Some(&ty::adjustment::AdjustDerefRef(
- ty::adjustment::AutoDerefRef { autoderefs, .. }
- )) => {
- if (0..autoderefs as u32).any(|autoderef| {
- v.tcx.is_overloaded_autoderef(e.id, autoderef)
- }) {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0400,
- "user-defined dereference operators are not allowed in {}s",
- v.msg());
- }
- }
- }
- }
-}
-
-pub fn check_crate(tcx: &ty::ctxt) {
- tcx.visit_all_items_in_krate(DepNode::CheckConst, &mut CheckCrateVisitor {
- tcx: tcx,
- mode: Mode::Var,
- qualif: ConstQualif::NOT_CONST,
- rvalue_borrows: NodeMap()
- });
- tcx.sess.abort_if_errors();
-}
-
-impl<'a, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'tcx> {
- fn consume(&mut self,
- _consume_id: ast::NodeId,
- consume_span: Span,
- cmt: mc::cmt,
- _mode: euv::ConsumeMode) {
- let mut cur = &cmt;
- loop {
- match cur.cat {
- Categorization::StaticItem => {
- if self.mode != Mode::Var {
- // statics cannot be consumed by value at any time, that would imply
- // that they're an initializer (what a const is for) or kept in sync
- // over time (not feasible), so deny it outright.
- span_err!(self.tcx.sess, consume_span, E0394,
- "cannot refer to other statics by value, use the \
- address-of operator or a constant instead");
- }
- break;
- }
- Categorization::Deref(ref cmt, _, _) |
- Categorization::Downcast(ref cmt, _) |
- Categorization::Interior(ref cmt, _) => cur = cmt,
-
- Categorization::Rvalue(..) |
- Categorization::Upvar(..) |
- Categorization::Local(..) => break
- }
- }
- }
- fn borrow(&mut self,
- borrow_id: ast::NodeId,
- borrow_span: Span,
- cmt: mc::cmt<'tcx>,
- _loan_region: ty::Region,
- bk: ty::BorrowKind,
- loan_cause: euv::LoanCause)
- {
- // Kind of hacky, but we allow Unsafe coercions in constants.
- // These occur when we convert a &T or *T to a *U, as well as
- // when making a thin pointer (e.g., `*T`) into a fat pointer
- // (e.g., `*Trait`).
- match loan_cause {
- euv::LoanCause::AutoUnsafe => {
- return;
- }
- _ => { }
- }
-
- let mut cur = &cmt;
- let mut is_interior = false;
- loop {
- match cur.cat {
- Categorization::Rvalue(..) => {
- if loan_cause == euv::MatchDiscriminant {
- // Ignore the dummy immutable borrow created by EUV.
- break;
- }
- let mutbl = bk.to_mutbl_lossy();
- if mutbl == hir::MutMutable && self.mode == Mode::StaticMut {
- // Mutable slices are the only `&mut` allowed in
- // globals, but only in `static mut`, nowhere else.
- // FIXME: This exception is really weird... there isn't
- // any fundamental reason to restrict this based on
- // type of the expression. `&mut [1]` has exactly the
- // same representation as &mut 1.
- match cmt.ty.sty {
- ty::TyArray(_, _) | ty::TySlice(_) => break,
- _ => {}
- }
- }
- self.record_borrow(borrow_id, mutbl);
- break;
- }
- Categorization::StaticItem => {
- if is_interior && self.mode != Mode::Var {
- // Borrowed statics can specifically *only* have their address taken,
- // not any number of other borrows such as borrowing fields, reading
- // elements of an array, etc.
- span_err!(self.tcx.sess, borrow_span, E0494,
- "cannot refer to the interior of another \
- static, use a constant instead");
- }
- break;
- }
- Categorization::Deref(ref cmt, _, _) |
- Categorization::Downcast(ref cmt, _) |
- Categorization::Interior(ref cmt, _) => {
- is_interior = true;
- cur = cmt;
- }
-
- Categorization::Upvar(..) |
- Categorization::Local(..) => break
- }
- }
- }
-
- fn decl_without_init(&mut self,
- _id: ast::NodeId,
- _span: Span) {}
- fn mutate(&mut self,
- _assignment_id: ast::NodeId,
- _assignment_span: Span,
- _assignee_cmt: mc::cmt,
- _mode: euv::MutateMode) {}
-
- fn matched_pat(&mut self,
- _: &hir::Pat,
- _: mc::cmt,
- _: euv::MatchMode) {}
-
- fn consume_pat(&mut self,
- _consume_pat: &hir::Pat,
- _cmt: mc::cmt,
- _mode: euv::ConsumeMode) {}
-}
+++ /dev/null
-// Copyright 2012-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.
-use self::Context::*;
-
-use session::Session;
-
-use syntax::codemap::Span;
-use rustc_front::intravisit::{self, Visitor};
-use rustc_front::hir;
-
-#[derive(Clone, Copy, PartialEq)]
-enum Context {
- Normal, Loop, Closure
-}
-
-#[derive(Copy, Clone)]
-struct CheckLoopVisitor<'a> {
- sess: &'a Session,
- cx: Context
-}
-
-pub fn check_crate(sess: &Session, krate: &hir::Crate) {
- krate.visit_all_items(&mut CheckLoopVisitor { sess: sess, cx: Normal });
-}
-
-impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
- fn visit_item(&mut self, i: &hir::Item) {
- self.with_context(Normal, |v| intravisit::walk_item(v, i));
- }
-
- fn visit_expr(&mut self, e: &hir::Expr) {
- match e.node {
- hir::ExprWhile(ref e, ref b, _) => {
- self.visit_expr(&**e);
- self.with_context(Loop, |v| v.visit_block(&**b));
- }
- hir::ExprLoop(ref b, _) => {
- self.with_context(Loop, |v| v.visit_block(&**b));
- }
- hir::ExprClosure(_, _, ref b) => {
- self.with_context(Closure, |v| v.visit_block(&**b));
- }
- hir::ExprBreak(_) => self.require_loop("break", e.span),
- hir::ExprAgain(_) => self.require_loop("continue", e.span),
- _ => intravisit::walk_expr(self, e)
- }
- }
-}
-
-impl<'a> CheckLoopVisitor<'a> {
- fn with_context<F>(&mut self, cx: Context, f: F) where
- F: FnOnce(&mut CheckLoopVisitor<'a>),
- {
- let old_cx = self.cx;
- self.cx = cx;
- f(self);
- self.cx = old_cx;
- }
-
- fn require_loop(&self, name: &str, span: Span) {
- match self.cx {
- Loop => {}
- Closure => {
- span_err!(self.sess, span, E0267,
- "`{}` inside of a closure", name);
- }
- Normal => {
- span_err!(self.sess, span, E0268,
- "`{}` outside of loop", name);
- }
- }
- }
-}
let pat_ty = cx.tcx.pat_ty(p);
if let ty::TyEnum(edef, _) = pat_ty.sty {
let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
- if let Some(DefLocal(..)) = def {
+ if let Some(Def::Local(..)) = def {
if edef.variants.iter().any(|variant|
variant.name == ident.node.unhygienic_name
&& variant.kind() == VariantKind::Unit
hir::PatIdent(..) | hir::PatEnum(..) | hir::PatQPath(..) => {
let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
match def {
- Some(DefAssociatedConst(did)) |
- Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did,
+ Some(Def::AssociatedConst(did)) |
+ Some(Def::Const(did)) => match lookup_const_by_id(self.tcx, did,
Some(pat.id), None) {
Some(const_expr) => {
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
match pat.node {
hir::PatIdent(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
- Some(DefStruct(_)) => vec!(Single),
- Some(DefVariant(_, id, _)) => vec!(Variant(id)),
+ Some(Def::Struct(..)) => vec!(Single),
+ Some(Def::Variant(_, id)) => vec!(Variant(id)),
_ => vec!()
},
hir::PatEnum(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
- Some(DefVariant(_, id, _)) => vec!(Variant(id)),
+ Some(Def::Variant(_, id)) => vec!(Variant(id)),
_ => vec!(Single)
},
hir::PatQPath(..) =>
been rewritten"),
hir::PatStruct(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
- Some(DefVariant(_, id, _)) => vec!(Variant(id)),
+ Some(Def::Variant(_, id)) => vec!(Variant(id)),
_ => vec!(Single)
},
hir::PatLit(ref expr) =>
hir::PatIdent(_, _, _) => {
let opt_def = cx.tcx.def_map.borrow().get(&pat_id).map(|d| d.full_def());
match opt_def {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
- Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
+ Some(Def::Variant(_, id)) => if *constructor == Variant(id) {
Some(vec!())
} else {
None
hir::PatEnum(_, ref args) => {
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
match def {
- DefConst(..) | DefAssociatedConst(..) =>
+ Def::Const(..) | Def::AssociatedConst(..) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
- DefVariant(_, id, _) if *constructor != Variant(id) => None,
- DefVariant(..) | DefStruct(..) => {
+ Def::Variant(_, id) if *constructor != Variant(id) => None,
+ Def::Variant(..) | Def::Struct(..) => {
Some(match args {
&Some(ref args) => args.iter().map(|p| &**p).collect(),
&None => vec![DUMMY_WILD_PAT; arity],
+++ /dev/null
-// 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.
-
-// Checks that all rvalues in a crate have statically known size. check_crate
-// is the public starting point.
-
-use dep_graph::DepNode;
-use middle::expr_use_visitor as euv;
-use middle::infer;
-use middle::mem_categorization as mc;
-use middle::ty::ParameterEnvironment;
-use middle::ty;
-
-use rustc_front::hir;
-use rustc_front::intravisit;
-use syntax::ast;
-use syntax::codemap::Span;
-
-pub fn check_crate(tcx: &ty::ctxt) {
- let mut rvcx = RvalueContext { tcx: tcx };
- tcx.visit_all_items_in_krate(DepNode::RvalueCheck, &mut rvcx);
-}
-
-struct RvalueContext<'a, 'tcx: 'a> {
- tcx: &'a ty::ctxt<'tcx>,
-}
-
-impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
- fn visit_fn(&mut self,
- fk: intravisit::FnKind<'v>,
- fd: &'v hir::FnDecl,
- b: &'v hir::Block,
- s: Span,
- fn_id: ast::NodeId) {
- {
- // FIXME (@jroesch) change this to be an inference context
- let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
- let infcx = infer::new_infer_ctxt(self.tcx,
- &self.tcx.tables,
- Some(param_env.clone()));
- let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: ¶m_env };
- let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
- euv.walk_fn(fd, b);
- }
- intravisit::walk_fn(self, fk, fd, b, s)
- }
-}
-
-struct RvalueContextDelegate<'a, 'tcx: 'a> {
- tcx: &'a ty::ctxt<'tcx>,
- param_env: &'a ty::ParameterEnvironment<'a,'tcx>,
-}
-
-impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
- fn consume(&mut self,
- _: ast::NodeId,
- span: Span,
- cmt: mc::cmt<'tcx>,
- _: euv::ConsumeMode) {
- debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty);
- if !cmt.ty.is_sized(self.param_env, span) {
- span_err!(self.tcx.sess, span, E0161,
- "cannot move a value of type {0}: the size of {0} cannot be statically determined",
- cmt.ty);
- }
- }
-
- fn matched_pat(&mut self,
- _matched_pat: &hir::Pat,
- _cmt: mc::cmt,
- _mode: euv::MatchMode) {}
-
- fn consume_pat(&mut self,
- _consume_pat: &hir::Pat,
- _cmt: mc::cmt,
- _mode: euv::ConsumeMode) {
- }
-
- fn borrow(&mut self,
- _borrow_id: ast::NodeId,
- _borrow_span: Span,
- _cmt: mc::cmt,
- _loan_region: ty::Region,
- _bk: ty::BorrowKind,
- _loan_cause: euv::LoanCause) {
- }
-
- fn decl_without_init(&mut self,
- _id: ast::NodeId,
- _span: Span) {
- }
-
- fn mutate(&mut self,
- _assignment_id: ast::NodeId,
- _assignment_span: Span,
- _assignee_cmt: mc::cmt,
- _mode: euv::MutateMode) {
- }
-}
+++ /dev/null
-// 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.
-
-// This compiler pass detects constants that refer to themselves
-// recursively.
-
-use front::map as ast_map;
-use session::Session;
-use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefVariant, DefMap};
-use util::nodemap::NodeMap;
-
-use syntax::{ast};
-use syntax::codemap::Span;
-use syntax::feature_gate::{GateIssue, emit_feature_err};
-use rustc_front::intravisit::{self, Visitor};
-use rustc_front::hir;
-
-use std::cell::RefCell;
-
-struct CheckCrateVisitor<'a, 'ast: 'a> {
- sess: &'a Session,
- def_map: &'a DefMap,
- ast_map: &'a ast_map::Map<'ast>,
- // `discriminant_map` is a cache that associates the `NodeId`s of local
- // variant definitions with the discriminant expression that applies to
- // each one. If the variant uses the default values (starting from `0`),
- // then `None` is stored.
- discriminant_map: RefCell<NodeMap<Option<&'ast hir::Expr>>>,
-}
-
-impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
- fn visit_item(&mut self, it: &'ast hir::Item) {
- match it.node {
- hir::ItemStatic(..) |
- hir::ItemConst(..) => {
- let mut recursion_visitor =
- CheckItemRecursionVisitor::new(self, &it.span);
- recursion_visitor.visit_item(it);
- },
- hir::ItemEnum(ref enum_def, ref generics) => {
- // We could process the whole enum, but handling the variants
- // with discriminant expressions one by one gives more specific,
- // less redundant output.
- for variant in &enum_def.variants {
- if let Some(_) = variant.node.disr_expr {
- let mut recursion_visitor =
- CheckItemRecursionVisitor::new(self, &variant.span);
- recursion_visitor.populate_enum_discriminants(enum_def);
- recursion_visitor.visit_variant(variant, generics, it.id);
- }
- }
- }
- _ => {}
- }
- intravisit::walk_item(self, it)
- }
-
- fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
- match ti.node {
- hir::ConstTraitItem(_, ref default) => {
- if let Some(_) = *default {
- let mut recursion_visitor =
- CheckItemRecursionVisitor::new(self, &ti.span);
- recursion_visitor.visit_trait_item(ti);
- }
- }
- _ => {}
- }
- intravisit::walk_trait_item(self, ti)
- }
-
- fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
- match ii.node {
- hir::ImplItemKind::Const(..) => {
- let mut recursion_visitor =
- CheckItemRecursionVisitor::new(self, &ii.span);
- recursion_visitor.visit_impl_item(ii);
- }
- _ => {}
- }
- intravisit::walk_impl_item(self, ii)
- }
-}
-
-pub fn check_crate<'ast>(sess: &Session,
- krate: &'ast hir::Crate,
- def_map: &DefMap,
- ast_map: &ast_map::Map<'ast>) {
- let mut visitor = CheckCrateVisitor {
- sess: sess,
- def_map: def_map,
- ast_map: ast_map,
- discriminant_map: RefCell::new(NodeMap()),
- };
- sess.abort_if_new_errors(|| {
- krate.visit_all_items(&mut visitor);
- });
-}
-
-struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
- root_span: &'a Span,
- sess: &'a Session,
- ast_map: &'a ast_map::Map<'ast>,
- def_map: &'a DefMap,
- discriminant_map: &'a RefCell<NodeMap<Option<&'ast hir::Expr>>>,
- idstack: Vec<ast::NodeId>,
-}
-
-impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
- fn new(v: &'a CheckCrateVisitor<'a, 'ast>, span: &'a Span)
- -> CheckItemRecursionVisitor<'a, 'ast> {
- CheckItemRecursionVisitor {
- root_span: span,
- sess: v.sess,
- ast_map: v.ast_map,
- def_map: v.def_map,
- discriminant_map: &v.discriminant_map,
- idstack: Vec::new(),
- }
- }
- fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F)
- where F: Fn(&mut Self) {
- if self.idstack.iter().any(|&x| x == id) {
- let any_static = self.idstack.iter().any(|&x| {
- if let ast_map::NodeItem(item) = self.ast_map.get(x) {
- if let hir::ItemStatic(..) = item.node {
- true
- } else {
- false
- }
- } else {
- false
- }
- });
- if any_static {
- if !self.sess.features.borrow().static_recursion {
- emit_feature_err(&self.sess.parse_sess.span_diagnostic,
- "static_recursion",
- *self.root_span, GateIssue::Language, "recursive static");
- }
- } else {
- span_err!(self.sess, *self.root_span, E0265, "recursive constant");
- }
- return;
- }
- self.idstack.push(id);
- f(self);
- self.idstack.pop();
- }
- // If a variant has an expression specifying its discriminant, then it needs
- // to be checked just like a static or constant. However, if there are more
- // variants with no explicitly specified discriminant, those variants will
- // increment the same expression to get their values.
- //
- // So for every variant, we need to track whether there is an expression
- // somewhere in the enum definition that controls its discriminant. We do
- // this by starting from the end and searching backward.
- fn populate_enum_discriminants(&self, enum_definition: &'ast hir::EnumDef) {
- // Get the map, and return if we already processed this enum or if it
- // has no variants.
- let mut discriminant_map = self.discriminant_map.borrow_mut();
- match enum_definition.variants.first() {
- None => { return; }
- Some(variant) if discriminant_map.contains_key(&variant.node.data.id()) => {
- return;
- }
- _ => {}
- }
-
- // Go through all the variants.
- let mut variant_stack: Vec<ast::NodeId> = Vec::new();
- for variant in enum_definition.variants.iter().rev() {
- variant_stack.push(variant.node.data.id());
- // When we find an expression, every variant currently on the stack
- // is affected by that expression.
- if let Some(ref expr) = variant.node.disr_expr {
- for id in &variant_stack {
- discriminant_map.insert(*id, Some(expr));
- }
- variant_stack.clear()
- }
- }
- // If we are at the top, that always starts at 0, so any variant on the
- // stack has a default value and does not need to be checked.
- for id in &variant_stack {
- discriminant_map.insert(*id, None);
- }
- }
-}
-
-impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
- fn visit_item(&mut self, it: &'ast hir::Item) {
- self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it));
- }
-
- fn visit_enum_def(&mut self, enum_definition: &'ast hir::EnumDef,
- generics: &'ast hir::Generics, item_id: ast::NodeId, _: Span) {
- self.populate_enum_discriminants(enum_definition);
- intravisit::walk_enum_def(self, enum_definition, generics, item_id);
- }
-
- fn visit_variant(&mut self, variant: &'ast hir::Variant,
- _: &'ast hir::Generics, _: ast::NodeId) {
- let variant_id = variant.node.data.id();
- let maybe_expr;
- if let Some(get_expr) = self.discriminant_map.borrow().get(&variant_id) {
- // This is necessary because we need to let the `discriminant_map`
- // borrow fall out of scope, so that we can reborrow farther down.
- maybe_expr = (*get_expr).clone();
- } else {
- self.sess.span_bug(variant.span,
- "`check_static_recursion` attempted to visit \
- variant with unknown discriminant")
- }
- // If `maybe_expr` is `None`, that's because no discriminant is
- // specified that affects this variant. Thus, no risk of recursion.
- if let Some(expr) = maybe_expr {
- self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr));
- }
- }
-
- fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
- self.with_item_id_pushed(ti.id, |v| intravisit::walk_trait_item(v, ti));
- }
-
- fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
- self.with_item_id_pushed(ii.id, |v| intravisit::walk_impl_item(v, ii));
- }
-
- fn visit_expr(&mut self, e: &'ast hir::Expr) {
- match e.node {
- hir::ExprPath(..) => {
- match self.def_map.get(&e.id).map(|d| d.base_def) {
- Some(DefStatic(def_id, _)) |
- Some(DefAssociatedConst(def_id)) |
- Some(DefConst(def_id)) => {
- if let Some(node_id) = self.ast_map.as_local_node_id(def_id) {
- match self.ast_map.get(node_id) {
- ast_map::NodeItem(item) =>
- self.visit_item(item),
- ast_map::NodeTraitItem(item) =>
- self.visit_trait_item(item),
- ast_map::NodeImplItem(item) =>
- self.visit_impl_item(item),
- ast_map::NodeForeignItem(_) => {},
- _ => {
- self.sess.span_bug(
- e.span,
- &format!("expected item, found {}",
- self.ast_map.node_to_string(node_id)));
- }
- }
- }
- }
- // For variants, we only want to check expressions that
- // affect the specific variant used, but we need to check
- // the whole enum definition to see what expression that
- // might be (if any).
- Some(DefVariant(enum_id, variant_id, false)) => {
- if let Some(enum_node_id) = self.ast_map.as_local_node_id(enum_id) {
- if let hir::ItemEnum(ref enum_def, ref generics) =
- self.ast_map.expect_item(enum_node_id).node
- {
- self.populate_enum_discriminants(enum_def);
- let enum_id = self.ast_map.as_local_node_id(enum_id).unwrap();
- let variant_id = self.ast_map.as_local_node_id(variant_id).unwrap();
- let variant = self.ast_map.expect_variant(variant_id);
- self.visit_variant(variant, generics, enum_id);
- } else {
- self.sess.span_bug(e.span,
- "`check_static_recursion` found \
- non-enum in DefVariant");
- }
- }
- }
- _ => ()
- }
- },
- _ => ()
- }
- intravisit::walk_expr(self, e);
- }
-}
use front::map as ast_map;
use front::map::blocks::FnLikeNode;
use middle::cstore::{self, CrateStore, InlinedItem};
-use middle::{def, infer, subst, traits};
+use middle::{infer, subst, traits};
+use middle::def::Def;
use middle::subst::Subst;
use middle::def_id::DefId;
use middle::pat_util::def_to_path;
entry.insert(def);
}
let path = match def.full_def() {
- def::DefStruct(def_id) => def_to_path(tcx, def_id),
- def::DefVariant(_, variant_did, _) => def_to_path(tcx, variant_did),
- def::DefFn(..) => return P(hir::Pat {
+ Def::Struct(def_id) => def_to_path(tcx, def_id),
+ Def::Variant(_, variant_did) => def_to_path(tcx, variant_did),
+ Def::Fn(..) => return P(hir::Pat {
id: expr.id,
node: hir::PatLit(P(expr.clone())),
span: span,
hir::ExprPath(_, ref path) => {
let opt_def = tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def());
match opt_def {
- Some(def::DefStruct(..)) =>
+ Some(Def::Struct(..)) =>
hir::PatStruct(path.clone(), hir::HirVec::new(), false),
- Some(def::DefVariant(..)) =>
+ Some(Def::Variant(..)) =>
hir::PatEnum(path.clone(), None),
- Some(def::DefConst(def_id)) |
- Some(def::DefAssociatedConst(def_id)) => {
+ Some(Def::Const(def_id)) |
+ Some(Def::AssociatedConst(def_id)) => {
let expr = lookup_const_by_id(tcx, def_id, Some(expr.id), None).unwrap();
return const_expr_to_pat(tcx, expr, span);
},
None
};
let (const_expr, const_ty) = match opt_def {
- Some(def::DefConst(def_id)) => {
+ Some(Def::Const(def_id)) => {
if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
match tcx.map.find(node_id) {
Some(ast_map::NodeItem(it)) => match it.node {
(lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
}
}
- Some(def::DefAssociatedConst(def_id)) => {
+ Some(Def::AssociatedConst(def_id)) => {
if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
match tcx.impl_or_trait_item(def_id).container() {
ty::TraitContainer(trait_id) => match tcx.map.find(node_id) {
(lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
}
}
- Some(def::DefVariant(enum_def, variant_def, _)) => {
+ Some(Def::Variant(enum_def, variant_def)) => {
(lookup_variant_by_id(tcx, enum_def, variant_def), None)
}
- Some(def::DefStruct(_)) => {
+ Some(Def::Struct(..)) => {
return Ok(ConstVal::Struct(e.id))
}
- Some(def::DefLocal(_, id)) => {
- debug!("DefLocal({:?}): {:?}", id, fn_args);
+ Some(Def::Local(_, id)) => {
+ debug!("Def::Local({:?}): {:?}", id, fn_args);
if let Some(val) = fn_args.and_then(|args| args.get(&id)) {
return Ok(val.clone());
} else {
(None, None)
}
},
- Some(def::DefMethod(id)) | Some(def::DefFn(id, _)) => return Ok(Function(id)),
+ Some(Def::Method(id)) | Some(Def::Fn(id)) => return Ok(Function(id)),
_ => (None, None)
};
let const_expr = match const_expr {
--- /dev/null
+// Copyright 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.
+
+// Const qualification, from partial to completely promotable.
+bitflags! {
+ #[derive(RustcEncodable, RustcDecodable)]
+ flags ConstQualif: u8 {
+ // Inner mutability (can not be placed behind a reference) or behind
+ // &mut in a non-global expression. Can be copied from static memory.
+ const MUTABLE_MEM = 1 << 0,
+ // Constant value with a type that implements Drop. Can be copied
+ // from static memory, similar to MUTABLE_MEM.
+ const NEEDS_DROP = 1 << 1,
+ // Even if the value can be placed in static memory, copying it from
+ // there is more expensive than in-place instantiation, and/or it may
+ // be too large. This applies to [T; N] and everything containing it.
+ // N.B.: references need to clear this flag to not end up on the stack.
+ const PREFER_IN_PLACE = 1 << 2,
+ // May use more than 0 bytes of memory, doesn't impact the constness
+ // directly, but is not allowed to be borrowed mutably in a constant.
+ const NON_ZERO_SIZED = 1 << 3,
+ // Actually borrowed, has to always be in static memory. Does not
+ // propagate, and requires the expression to behave like a 'static
+ // lvalue. The set of expressions with this flag is the minimum
+ // that have to be promoted.
+ const HAS_STATIC_BORROWS = 1 << 4,
+ // Invalid const for miscellaneous reasons (e.g. not implemented).
+ const NOT_CONST = 1 << 5,
+
+ // Borrowing the expression won't produce &'static T if any of these
+ // bits are set, though the value could be copied from static memory
+ // if `NOT_CONST` isn't set.
+ const NON_STATIC_BORROWS = ConstQualif::MUTABLE_MEM.bits |
+ ConstQualif::NEEDS_DROP.bits |
+ ConstQualif::NOT_CONST.bits
+ }
+}
use back::svh::Svh;
use front::map as hir_map;
-use middle::def;
+use middle::def::{self, Def};
use middle::lang_items;
-use middle::ty::{self, Ty};
+use middle::ty::{self, Ty, VariantKind};
use middle::def_id::{DefId, DefIndex};
use mir::repr::Mir;
use session::Session;
// Something that a name can resolve to.
#[derive(Copy, Clone, Debug)]
pub enum DefLike {
- DlDef(def::Def),
+ DlDef(Def),
DlImpl(DefId),
DlField
}
// resolve
fn def_path(&self, def: DefId) -> hir_map::DefPath;
+ fn variant_kind(&self, def_id: DefId) -> Option<VariantKind>;
+ fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>;
fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>;
fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>;
fn item_children(&self, did: DefId) -> Vec<ChildItem>;
// resolve
fn def_path(&self, def: DefId) -> hir_map::DefPath { unimplemented!() }
+ fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> { unimplemented!() }
+ fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>
+ { unimplemented!() }
fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>
{ unimplemented!() }
fn struct_field_names(&self, def: DefId) -> Vec<ast::Name> { unimplemented!() }
use rustc_front::hir;
use rustc_front::intravisit::{self, Visitor};
-use middle::{def, pat_util, privacy, ty};
+use middle::{pat_util, privacy, ty};
+use middle::def::Def;
use middle::def_id::{DefId};
use lint;
self.tcx.def_map.borrow().get(id).map(|def| {
match def.full_def() {
- def::DefConst(_) | def::DefAssociatedConst(..) => {
+ Def::Const(_) | Def::AssociatedConst(..) => {
self.check_def_id(def.def_id());
}
_ if self.ignore_non_const_paths => (),
- def::DefPrimTy(_) => (),
- def::DefSelfTy(..) => (),
- def::DefVariant(enum_id, variant_id, _) => {
+ Def::PrimTy(_) => (),
+ Def::SelfTy(..) => (),
+ Def::Variant(enum_id, variant_id) => {
self.check_def_id(enum_id);
if !self.ignore_variant_stack.contains(&variant_id) {
self.check_def_id(variant_id);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub use self::Def::*;
-
use middle::def_id::DefId;
use middle::privacy::LastPrivate;
use middle::subst::ParamSpace;
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Def {
- DefFn(DefId, bool /* is_ctor */),
- DefSelfTy(Option<DefId>, // trait id
+ Fn(DefId),
+ SelfTy(Option<DefId>, // trait id
Option<(ast::NodeId, ast::NodeId)>), // (impl id, self type id)
- DefMod(DefId),
- DefForeignMod(DefId),
- DefStatic(DefId, bool /* is_mutbl */),
- DefConst(DefId),
- DefAssociatedConst(DefId),
- DefLocal(DefId, // def id of variable
+ Mod(DefId),
+ ForeignMod(DefId),
+ Static(DefId, bool /* is_mutbl */),
+ Const(DefId),
+ AssociatedConst(DefId),
+ Local(DefId, // def id of variable
ast::NodeId), // node id of variable
- DefVariant(DefId /* enum */, DefId /* variant */, bool /* is_structure */),
- DefTy(DefId, bool /* is_enum */),
- DefAssociatedTy(DefId /* trait */, DefId),
- DefTrait(DefId),
- DefPrimTy(hir::PrimTy),
- DefTyParam(ParamSpace, u32, DefId, ast::Name),
- DefUpvar(DefId, // def id of closed over local
+ Variant(DefId /* enum */, DefId /* variant */),
+ Enum(DefId),
+ TyAlias(DefId),
+ AssociatedTy(DefId /* trait */, DefId),
+ Trait(DefId),
+ PrimTy(hir::PrimTy),
+ TyParam(ParamSpace, u32, DefId, ast::Name),
+ Upvar(DefId, // def id of closed over local
ast::NodeId, // node id of closed over local
usize, // index in the freevars list of the closure
ast::NodeId), // expr node that creates the closure
- /// Note that if it's a tuple struct's definition, the node id of the DefId
- /// may either refer to the item definition's id or the VariantData.ctor_id.
- ///
- /// The cases that I have encountered so far are (this is not exhaustive):
- /// - If it's a ty_path referring to some tuple struct, then DefMap maps
- /// it to a def whose id is the item definition's id.
- /// - If it's an ExprPath referring to some tuple struct, then DefMap maps
- /// it to a def whose id is the VariantData.ctor_id.
- DefStruct(DefId),
- DefLabel(ast::NodeId),
- DefMethod(DefId),
- DefErr,
+ // If Def::Struct lives in type namespace it denotes a struct item and its DefId refers
+ // to NodeId of the struct itself.
+ // If Def::Struct lives in value namespace (e.g. tuple struct, unit struct expressions)
+ // it denotes a constructor and its DefId refers to NodeId of the struct's constructor.
+ Struct(DefId),
+ Label(ast::NodeId),
+ Method(DefId),
+ Err,
}
/// The result of resolving a path.
impl Def {
pub fn var_id(&self) -> ast::NodeId {
match *self {
- DefLocal(_, id) |
- DefUpvar(_, id, _, _) => {
+ Def::Local(_, id) |
+ Def::Upvar(_, id, _, _) => {
id
}
- DefFn(..) | DefMod(..) | DefForeignMod(..) | DefStatic(..) |
- DefVariant(..) | DefTy(..) | DefAssociatedTy(..) |
- DefTyParam(..) | DefStruct(..) | DefTrait(..) |
- DefMethod(..) | DefConst(..) | DefAssociatedConst(..) |
- DefPrimTy(..) | DefLabel(..) | DefSelfTy(..) | DefErr => {
+ Def::Fn(..) | Def::Mod(..) | Def::ForeignMod(..) | Def::Static(..) |
+ Def::Variant(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
+ Def::TyParam(..) | Def::Struct(..) | Def::Trait(..) |
+ Def::Method(..) | Def::Const(..) | Def::AssociatedConst(..) |
+ Def::PrimTy(..) | Def::Label(..) | Def::SelfTy(..) | Def::Err => {
panic!("attempted .def_id() on invalid {:?}", self)
}
}
pub fn def_id(&self) -> DefId {
match *self {
- DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) |
- DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
- DefTyParam(_, _, id, _) | DefStruct(id) | DefTrait(id) |
- DefMethod(id) | DefConst(id) | DefAssociatedConst(id) |
- DefLocal(id, _) | DefUpvar(id, _, _, _) => {
+ Def::Fn(id) | Def::Mod(id) | Def::ForeignMod(id) | Def::Static(id, _) |
+ Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) |
+ Def::TyParam(_, _, id, _) | Def::Struct(id) | Def::Trait(id) |
+ Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) |
+ Def::Local(id, _) | Def::Upvar(id, _, _, _) => {
id
}
- DefLabel(..) |
- DefPrimTy(..) |
- DefSelfTy(..) |
- DefErr => {
+ Def::Label(..) |
+ Def::PrimTy(..) |
+ Def::SelfTy(..) |
+ Def::Err => {
panic!("attempted .def_id() on invalid def: {:?}", self)
}
}
pub fn variant_def_ids(&self) -> Option<(DefId, DefId)> {
match *self {
- DefVariant(enum_id, var_id, _) => {
+ Def::Variant(enum_id, var_id) => {
Some((enum_id, var_id))
}
_ => None
//! `unsafe`.
use self::RootUnsafeContext::*;
-use middle::def;
+use middle::def::Def;
use middle::ty::{self, Ty};
use middle::ty::MethodCall;
self.require_unsafe(expr.span, "use of inline assembly");
}
hir::ExprPath(..) => {
- if let def::DefStatic(_, true) = self.tcx.resolve_expr(expr) {
+ if let Def::Static(_, true) = self.tcx.resolve_expr(expr) {
self.require_unsafe(expr.span, "use of mutable static");
}
}
use self::TrackMatchMode::*;
use self::OverloadedCallType::*;
-use middle::{def, pat_util};
+use middle::pat_util;
+use middle::def::Def;
use middle::def_id::{DefId};
use middle::infer;
use middle::mem_categorization as mc;
// struct or enum pattern.
}
- Some(def::DefVariant(enum_did, variant_did, _is_struct)) => {
+ Some(Def::Variant(enum_did, variant_did)) => {
let downcast_cmt =
if tcx.lookup_adt_def(enum_did).is_univariant() {
cmt_pat
delegate.matched_pat(pat, downcast_cmt, match_mode);
}
- Some(def::DefStruct(..)) | Some(def::DefTy(_, false)) => {
+ Some(Def::Struct(..)) | Some(Def::TyAlias(..)) => {
// A struct (in either the value or type
// namespace; we encounter the former on
// e.g. patterns for unit structs).
delegate.matched_pat(pat, cmt_pat, match_mode);
}
- Some(def::DefConst(..)) |
- Some(def::DefAssociatedConst(..)) |
- Some(def::DefLocal(..)) => {
+ Some(Def::Const(..)) |
+ Some(Def::AssociatedConst(..)) |
+ Some(Def::Local(..)) => {
// This is a leaf (i.e. identifier binding
// or constant value to match); thus no
// `matched_pat` call.
}
- Some(def @ def::DefTy(_, true)) => {
- // An enum's type -- should never be in a
- // pattern.
-
- if !tcx.sess.has_errors() {
- let msg = format!("Pattern has unexpected type: {:?} and type {:?}",
- def,
- cmt_pat.ty);
- tcx.sess.span_bug(pat.span, &msg)
- }
- }
-
Some(def) => {
- // Remaining cases are e.g. DefFn, to
+ // An enum type should never be in a pattern.
+ // Remaining cases are e.g. Def::Fn, to
// which identifiers within patterns
// should not resolve. However, we do
// encouter this when using the
fn cat_captured_var(&mut self,
closure_id: ast::NodeId,
closure_span: Span,
- upvar_def: def::Def)
+ upvar_def: Def)
-> mc::McResult<mc::cmt<'tcx>> {
// Create the cmt for the variable being borrowed, from the
// caller's perspective
use rustc_front::print::pprust;
use middle::cstore::CrateStore;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::infer::{self, TypeOrigin};
use middle::region;
Some(d) => d.full_def()
};
match a_def {
- def::DefTy(did, _) | def::DefStruct(did) => {
+ Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
let generics = self.tcx.lookup_item_type(did).generics;
let expected =
}
_ => ()
}
-
}
hir::TyPtr(ref mut_ty) => {
// except according to those terms.
use dep_graph::DepNode;
-use middle::def::DefFn;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::subst::{Subst, Substs, EnumeratedItems};
use middle::ty::{TransmuteRestriction, ctxt, TyBareFn};
fn visit_expr(&mut self, expr: &hir::Expr) {
if let hir::ExprPath(..) = expr.node {
match self.tcx.resolve_expr(expr) {
- DefFn(did, _) if self.def_id_is_transmute(did) => {
+ Def::Fn(did) if self.def_id_is_transmute(did) => {
let typ = self.tcx.node_id_to_type(expr.id);
match typ.sty {
TyBareFn(_, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
hir::ExprPath(..) => {
let def = ir.tcx.def_map.borrow().get(&expr.id).unwrap().full_def();
debug!("expr {}: path that leads to {:?}", expr.id, def);
- if let DefLocal(..) = def {
+ if let Def::Local(..) = def {
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
}
intravisit::walk_expr(ir, expr);
let mut call_caps = Vec::new();
ir.tcx.with_freevars(expr.id, |freevars| {
for fv in freevars {
- if let DefLocal(_, rv) = fv.def {
+ if let Def::Local(_, rv) = fv.def {
let fv_ln = ir.add_live_node(FreeVarNode(fv.span));
call_caps.push(CaptureInfo {ln: fv_ln,
var_nid: rv});
// Refers to a labeled loop. Use the results of resolve
// to find with one
match self.ir.tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
- Some(DefLabel(loop_id)) => loop_id,
+ Some(Def::Label(loop_id)) => loop_id,
_ => self.ir.tcx.sess.span_bug(sp, "label on break/loop \
doesn't refer to a loop")
}
fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
-> LiveNode {
match self.ir.tcx.def_map.borrow().get(&expr.id).unwrap().full_def() {
- DefLocal(_, nid) => {
+ Def::Local(_, nid) => {
let ln = self.live_node(expr.id, expr.span);
if acc != 0 {
self.init_from_succ(ln, succ);
fn check_lvalue(&mut self, expr: &Expr) {
match expr.node {
hir::ExprPath(..) => {
- if let DefLocal(_, nid) = self.ir.tcx.def_map.borrow().get(&expr.id)
+ if let Def::Local(_, nid) = self.ir.tcx.def_map.borrow().get(&expr.id)
.unwrap()
.full_def() {
// Assignment to an immutable variable or argument: only legal
use middle::def_id::DefId;
use front::map as ast_map;
use middle::infer;
-use middle::check_const;
-use middle::def;
+use middle::const_qualif::ConstQualif;
+use middle::def::Def;
use middle::ty::adjustment;
use middle::ty::{self, Ty};
id: ast::NodeId,
span: Span,
expr_ty: Ty<'tcx>,
- def: def::Def)
+ def: Def)
-> McResult<cmt<'tcx>> {
debug!("cat_def: id={} expr={:?} def={:?}",
id, expr_ty, def);
match def {
- def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) |
- def::DefAssociatedConst(..) | def::DefFn(..) | def::DefMethod(..) => {
+ Def::Struct(..) | Def::Variant(..) | Def::Const(..) |
+ Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) => {
Ok(self.cat_rvalue_node(id, span, expr_ty))
}
- def::DefMod(_) | def::DefForeignMod(_) |
- def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
- def::DefTyParam(..) |
- def::DefLabel(_) | def::DefSelfTy(..) |
- def::DefAssociatedTy(..) => {
- Ok(Rc::new(cmt_ {
- id:id,
- span:span,
- cat:Categorization::StaticItem,
- mutbl: McImmutable,
- ty:expr_ty,
- note: NoteNone
- }))
+
+ Def::Mod(_) | Def::ForeignMod(_) |
+ Def::Trait(_) | Def::Enum(..) | Def::TyAlias(..) | Def::PrimTy(_) |
+ Def::TyParam(..) |
+ Def::Label(_) | Def::SelfTy(..) |
+ Def::AssociatedTy(..) => {
+ self.tcx().sess.span_bug(span, &format!("Unexpected definition in \
+ memory categorization: {:?}", def));
}
- def::DefStatic(_, mutbl) => {
+ Def::Static(_, mutbl) => {
Ok(Rc::new(cmt_ {
id:id,
span:span,
}))
}
- def::DefUpvar(_, var_id, _, fn_node_id) => {
+ Def::Upvar(_, var_id, _, fn_node_id) => {
let ty = try!(self.node_ty(fn_node_id));
match ty.sty {
ty::TyClosure(closure_id, _) => {
}
}
- def::DefLocal(_, vid) => {
+ Def::Local(_, vid) => {
Ok(Rc::new(cmt_ {
id: id,
span: span,
}))
}
- def::DefErr => panic!("DefErr in memory categorization")
+ Def::Err => panic!("Def::Err in memory categorization")
}
}
expr_ty: Ty<'tcx>)
-> cmt<'tcx> {
let qualif = self.tcx().const_qualif_map.borrow().get(&id).cloned()
- .unwrap_or(check_const::ConstQualif::NOT_CONST);
+ .unwrap_or(ConstQualif::NOT_CONST);
// Only promote `[T; 0]` before an RFC for rvalue promotions
// is accepted.
let qualif = match expr_ty.sty {
ty::TyArray(_, 0) => qualif,
- _ => check_const::ConstQualif::NOT_CONST
+ _ => ConstQualif::NOT_CONST
};
// Compute maximum lifetime of this rvalue. This is 'static if
// we can promote to a constant, otherwise equal to enclosing temp
// lifetime.
- let re = if qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS) {
+ let re = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.temporary_scope(id)
} else {
ty::ReStatic
(*op)(self, cmt.clone(), pat);
let opt_def = if let Some(path_res) = self.tcx().def_map.borrow().get(&pat.id) {
- if path_res.depth != 0 || path_res.base_def == def::DefErr {
+ if path_res.depth != 0 || path_res.base_def == Def::Err {
// Since patterns can be associated constants
// which are resolved during typeck, we might have
// some unresolved patterns reaching this stage
// alone) because struct patterns can refer to struct types or
// to struct variants within enums.
let cmt = match opt_def {
- Some(def::DefVariant(enum_did, variant_did, _))
+ Some(Def::Variant(enum_did, variant_did))
// univariant enums do not need downcasts
if !self.tcx().lookup_adt_def(enum_did).is_univariant() => {
self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did)
}
hir::PatEnum(_, Some(ref subpats)) => {
match opt_def {
- Some(def::DefVariant(..)) => {
+ Some(Def::Variant(..)) => {
// variant(x, y, z)
for (i, subpat) in subpats.iter().enumerate() {
let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
try!(self.cat_pattern_(subcmt, &**subpat, op));
}
}
- Some(def::DefStruct(..)) => {
+ Some(Def::Struct(..)) => {
for (i, subpat) in subpats.iter().enumerate() {
let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
let cmt_field =
try!(self.cat_pattern_(cmt_field, &**subpat, op));
}
}
- Some(def::DefConst(..)) | Some(def::DefAssociatedConst(..)) => {
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {
for subpat in subpats {
try!(self.cat_pattern_(cmt.clone(), &**subpat, op));
}
hir::PatIdent(_, _, None) |
hir::PatStruct(..) => {
match dm.get(&pat.id).map(|d| d.full_def()) {
- Some(DefVariant(..)) => true,
+ Some(Def::Variant(..)) => true,
_ => false
}
}
hir::PatIdent(_, _, None) |
hir::PatStruct(..) => {
match dm.get(&pat.id).map(|d| d.full_def()) {
- Some(DefVariant(..)) | Some(DefStruct(..)) => true,
+ Some(Def::Variant(..)) | Some(Def::Struct(..)) => true,
_ => false
}
}
match pat.node {
hir::PatIdent(_, _, None) | hir::PatEnum(..) | hir::PatQPath(..) => {
match dm.get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
_ => false
}
}
match dm.get(&pat.id)
.and_then(|d| if d.depth == 0 { Some(d.base_def) }
else { None } ) {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
_ => false
}
}
hir::PatIdent(_, _, None) |
hir::PatStruct(..) => {
match dm.get(&p.id) {
- Some(&PathResolution { base_def: DefVariant(_, id, _), .. }) => {
+ Some(&PathResolution { base_def: Def::Variant(_, id), .. }) => {
variants.push(id);
}
_ => ()
use dep_graph::DepNode;
use front::map as ast_map;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::ty;
use middle::privacy;
// If this path leads to a constant, then we need to
// recurse into the constant to continue finding
// items that are reachable.
- def::DefConst(..) | def::DefAssociatedConst(..) => {
+ Def::Const(..) | Def::AssociatedConst(..) => {
self.worklist.push(node_id);
}
//! region parameterized.
//!
//! Most of the documentation on regions can be found in
-//! `middle/typeck/infer/region_inference.rs`
+//! `middle/infer/region_inference/README.md`
use front::map as ast_map;
use session::Session;
use self::ScopeChain::*;
use session::Session;
-use middle::def::{self, DefMap};
+use middle::def::{Def, DefMap};
use middle::region;
use middle::subst;
use middle::ty;
// if this path references a trait, then this will resolve to
// a trait ref, which introduces a binding scope.
match self.def_map.get(&ty.id).map(|d| (d.base_def, d.depth)) {
- Some((def::DefTrait(..), 0)) => {
+ Some((Def::Trait(..), 0)) => {
self.with(LateScope(&[], self.scope), |_, this| {
this.visit_path(path, ty.id);
});
use session::Session;
use lint;
use middle::cstore::{CrateStore, LOCAL_CRATE};
-use middle::def;
+use middle::def::Def;
use middle::def_id::{CRATE_DEF_INDEX, DefId};
use middle::ty;
use middle::privacy::AccessLevels;
pub fn check_path(tcx: &ty::ctxt, path: &hir::Path, id: ast::NodeId,
cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option<Deprecation>)) {
match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
- Some(def::DefPrimTy(..)) => {}
- Some(def::DefSelfTy(..)) => {}
+ Some(Def::PrimTy(..)) => {}
+ Some(Def::SelfTy(..)) => {}
Some(def) => {
maybe_do_stability_check(tcx, def.def_id(), path.span, cb);
}
pub fn check_path_list_item(tcx: &ty::ctxt, item: &hir::PathListItem,
cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option<Deprecation>)) {
match tcx.def_map.borrow().get(&item.node.id()).map(|d| d.full_def()) {
- Some(def::DefPrimTy(..)) => {}
+ Some(Def::PrimTy(..)) => {}
Some(def) => {
maybe_do_stability_check(tcx, def.def_id(), item.span, cb);
}
repr_hint_cache: RefCell<DepTrackingMap<maps::ReprHints<'tcx>>>,
/// Maps Expr NodeId's to their constant qualification.
- pub const_qualif_map: RefCell<NodeMap<middle::check_const::ConstQualif>>,
+ pub const_qualif_map: RefCell<NodeMap<middle::const_qualif::ConstQualif>>,
/// Caches CoerceUnsized kinds for impls on custom types.
pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>,
use front::map::LinkedPath;
use middle;
use middle::cstore::{self, CrateStore, LOCAL_CRATE};
-use middle::def::{self, ExportMap};
+use middle::def::{self, Def, ExportMap};
use middle::def_id::DefId;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::region::{CodeExtent};
#[derive(Copy, Clone)]
pub struct ClosureUpvar<'tcx> {
- pub def: def::Def,
+ pub def: Def,
pub span: Span,
pub ty: Ty<'tcx>,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum AdtKind { Struct, Enum }
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum VariantKind { Struct, Tuple, Unit }
+impl VariantKind {
+ pub fn from_variant_data(vdata: &hir::VariantData) -> Self {
+ match *vdata {
+ hir::VariantData::Struct(..) => VariantKind::Struct,
+ hir::VariantData::Tuple(..) => VariantKind::Tuple,
+ hir::VariantData::Unit(..) => VariantKind::Unit,
+ }
+ }
+}
+
impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
fn new(tcx: &ctxt<'tcx>,
did: DefId,
.expect("variant_index_with_id: unknown variant")
}
- pub fn variant_of_def(&self, def: def::Def) -> &VariantDefData<'tcx, 'container> {
+ pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'tcx, 'container> {
match def {
- def::DefVariant(_, vid, _) => self.variant_with_id(vid),
- def::DefStruct(..) | def::DefTy(..) => self.struct_variant(),
+ Def::Variant(_, vid) => self.variant_with_id(vid),
+ Def::Struct(..) | Def::TyAlias(..) => self.struct_variant(),
_ => panic!("unexpected def {:?} in variant_of_def", def)
}
}
}
}
- pub fn resolve_expr(&self, expr: &hir::Expr) -> def::Def {
+ pub fn resolve_expr(&self, expr: &hir::Expr) -> Def {
match self.def_map.borrow().get(&expr.id) {
Some(def) => def.full_def(),
None => {
// rvalues.
match self.def_map.borrow().get(&expr.id) {
Some(&def::PathResolution {
- base_def: def::DefStatic(..), ..
+ base_def: Def::Static(..), ..
}) | Some(&def::PathResolution {
- base_def: def::DefUpvar(..), ..
+ base_def: Def::Upvar(..), ..
}) | Some(&def::PathResolution {
- base_def: def::DefLocal(..), ..
+ base_def: Def::Local(..), ..
}) => {
true
}
- Some(&def::PathResolution { base_def: def::DefErr, .. })=> true,
+ Some(&def::PathResolution { base_def: Def::Err, .. })=> true,
Some(..) => false,
None => self.sess.span_bug(expr.span, &format!(
"no def for path {}", expr.id))
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct Freevar {
/// The variable being accessed free.
- pub def: def::Def,
+ pub def: Def,
// First span where it is accessed (there can be multiple).
pub span: Span
pub fn target() -> Target {
let mut base = super::linux_base::opts();
+ base.cpu = "ppc64".to_string();
base.pre_link_args.push("-m64".to_string());
Target {
pub fn target() -> Target {
let mut base = super::linux_base::opts();
+ base.cpu = "ppc64le".to_string();
base.pre_link_args.push("-m64".to_string());
Target {
use rustc_plugin as plugin;
use rustc_front::hir;
use rustc_front::lowering::{lower_crate, LoweringContext};
+use rustc_passes::{no_asm, loops, consts, const_fn, rvalues, static_recursion};
use super::Compilation;
use serialize::json;
time(time_passes,
"checking for inline asm in case the target doesn't support it",
- || ::rustc_passes::no_asm::check_crate(sess, &krate));
+ || no_asm::check_crate(sess, &krate));
// One final feature gating of the true AST that gets compiled
// later, to make sure we've got everything (e.g. configuration
time(time_passes,
"const fn bodies and arguments",
- || ::rustc_passes::const_fn::check_crate(sess, &krate));
+ || const_fn::check_crate(sess, &krate));
if sess.opts.debugging_opts.input_stats {
println!("Post-expansion node count: {}", count_nodes(&krate));
time(time_passes,
"loop checking",
- || middle::check_loop::check_crate(sess, krate));
+ || loops::check_crate(sess, krate));
time(time_passes,
"static item recursion checking",
- || middle::check_static_recursion::check_crate(sess, krate, &def_map.borrow(), &hir_map));
+ || static_recursion::check_crate(sess, krate, &def_map.borrow(), &hir_map));
ty::ctxt::create_and_enter(sess,
arenas,
time(time_passes,
"const checking",
- || middle::check_const::check_crate(tcx));
+ || consts::check_crate(tcx));
let access_levels =
time(time_passes, "privacy checking", || {
time(time_passes,
"rvalue checking",
- || middle::check_rvalues::check_crate(tcx));
+ || rvalues::check_crate(tcx));
// Avoid overwhelming user with errors if type checking failed.
// I'm not sure how helpful this is, to be honest, but it avoids
cached_id: Cell<u32>,
// Keep track of gensym'ed idents.
gensym_cache: RefCell<HashMap<(NodeId, &'static str), hir::Ident>>,
- // A copy of cached_id, but is also set to an id while it is being cached.
+ // A copy of cached_id, but is also set to an id while a node is lowered for
+ // the first time.
gensym_key: Cell<u32>,
}
}
fn next_id(&self) -> NodeId {
- let cached = self.cached_id.get();
- if cached == 0 {
+ let cached_id = self.cached_id.get();
+ if cached_id == 0 {
return self.id_assigner.next_node_id();
}
- self.cached_id.set(cached + 1);
- cached
+ self.cached_id.set(cached_id + 1);
+ cached_id
}
fn str_to_ident(&self, s: &'static str) -> hir::Ident {
- let cached_id = self.gensym_key.get();
- if cached_id == 0 {
+ let gensym_key = self.gensym_key.get();
+ if gensym_key == 0 {
return hir::Ident::from_name(token::gensym(s));
}
- let cached = self.gensym_cache.borrow().contains_key(&(cached_id, s));
+ let cached = self.gensym_cache.borrow().contains_key(&(gensym_key, s));
if cached {
- self.gensym_cache.borrow()[&(cached_id, s)]
+ self.gensym_cache.borrow()[&(gensym_key, s)]
} else {
let result = hir::Ident::from_name(token::gensym(s));
- self.gensym_cache.borrow_mut().insert((cached_id, s), result);
+ self.gensym_cache.borrow_mut().insert((gensym_key, s), result);
result
}
}
}
+// Utility fn for setting and unsetting the cached id.
+fn cache_ids<'a, OP, R>(lctx: &LoweringContext, expr_id: NodeId, op: OP) -> R
+ where OP: FnOnce(&LoweringContext) -> R
+{
+ // Only reset the id if it was previously 0, i.e., was not cached.
+ // If it was cached, we are in a nested node, but our id count will
+ // still count towards the parent's count.
+ let reset_cached_id = lctx.cached_id.get() == 0;
+ // We always reset gensym_key so that if we use the same name in a nested
+ // node and after that node, they get different values.
+ let old_gensym_key = lctx.gensym_key.get();
+
+ {
+ let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut();
+
+ if id_cache.contains_key(&expr_id) {
+ let cached_id = lctx.cached_id.get();
+ if cached_id == 0 {
+ // We're entering a node where we need to track ids, but are not
+ // yet tracking.
+ lctx.cached_id.set(id_cache[&expr_id]);
+ } else {
+ // We're already tracking - check that the tracked id is the same
+ // as the expected id.
+ assert!(cached_id == id_cache[&expr_id], "id mismatch");
+ }
+ lctx.gensym_key.set(id_cache[&expr_id]);
+ } else {
+ // We've never lowered this node before, remember it for next time.
+ let next_id = lctx.id_assigner.peek_node_id();
+ id_cache.insert(expr_id, next_id);
+ lctx.gensym_key.set(next_id);
+ // self.cached_id is not set when we lower a node for the first time,
+ // only on re-lowering.
+ }
+ }
+
+ let result = op(lctx);
+
+ if reset_cached_id {
+ lctx.cached_id.set(0);
+ }
+ lctx.gensym_key.set(old_gensym_key);
+
+ result
+}
+
pub fn lower_ident(_lctx: &LoweringContext, ident: Ident) -> hir::Ident {
hir::Ident {
name: mtwt::resolve(ident),
})
}
-// Utility fn for setting and unsetting the cached id.
-fn cache_ids<'a, OP, R>(lctx: &LoweringContext, expr_id: NodeId, op: OP) -> R
- where OP: FnOnce(&LoweringContext) -> R
-{
- // Only reset the id if it was previously 0, i.e., was not cached.
- // If it was cached, we are in a nested node, but our id count will
- // still count towards the parent's count.
- let reset_cached_id = lctx.cached_id.get() == 0;
-
- {
- let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut();
-
- if id_cache.contains_key(&expr_id) {
- let cached_id = lctx.cached_id.get();
- if cached_id == 0 {
- // We're entering a node where we need to track ids, but are not
- // yet tracking.
- lctx.cached_id.set(id_cache[&expr_id]);
- lctx.gensym_key.set(id_cache[&expr_id]);
- } else {
- // We're already tracking - check that the tracked id is the same
- // as the expected id.
- assert!(cached_id == id_cache[&expr_id], "id mismatch");
- }
- } else {
- let next_id = lctx.id_assigner.peek_node_id();
- id_cache.insert(expr_id, next_id);
- lctx.gensym_key.set(next_id);
- }
- }
-
- let result = op(lctx);
-
- if reset_cached_id {
- lctx.cached_id.set(0);
- lctx.gensym_key.set(0);
- }
-
- result
-}
-
pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
P(hir::Expr {
id: e.id,
let ast_while_let = assigner.fold_expr(ast_while_let);
let ast_for = quote_expr!(&cx,
for i in 0..10 {
- foo(i);
+ for j in 0..10 {
+ foo(i, j);
+ }
});
let ast_for = assigner.fold_expr(ast_for);
let ast_in = quote_expr!(&cx, in HEAP { foo() });
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use middle::def;
+use middle::def::Def;
use middle::ty;
use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass};
fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
if let &hir::PatIdent(_, ref path1, _) = &p.node {
let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
- if let Some(def::DefLocal(..)) = def {
+ if let Some(Def::Local(..)) = def {
self.check_snake_case(cx, "variable", &path1.node.name.as_str(), Some(p.span));
}
}
fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
// Lint for constants that look like binding identifiers (#7526)
match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) {
- (&hir::PatIdent(_, ref path1, _), Some(def::DefConst(..))) => {
+ (&hir::PatIdent(_, ref path1, _), Some(Def::Const(..))) => {
NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
path1.node.name, p.span);
}
//! Use the former for unit-like structs and the latter for structs with
//! a `pub fn new()`.
-use middle::{cfg, def, infer, stability, traits};
+use middle::{cfg, infer, stability, traits};
+use middle::def::Def;
use middle::cstore::CrateStore;
use middle::def_id::DefId;
use middle::subst::Substs;
}
let def = def_map.get(&fieldpat.node.pat.id).map(|d| d.full_def());
if let Some(def_id) = cx.tcx.map.opt_local_def_id(fieldpat.node.pat.id) {
- def == Some(def::DefLocal(def_id, fieldpat.node.pat.id))
+ def == Some(Def::Local(def_id, fieldpat.node.pat.id))
} else {
false
}
match tcx.map.get(id) {
hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
match tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()) {
- Some(def::DefMethod(def_id)) => {
+ Some(Def::Method(def_id)) => {
let item_substs =
tcx.tables.borrow().item_substs
.get(&callee.id)
hir::ExprPath(..) => (),
_ => return None
}
- if let def::DefFn(did, _) = cx.tcx.resolve_expr(expr) {
+ if let Def::Fn(did) = cx.tcx.resolve_expr(expr) {
if !def_id_is_transmute(cx, did) {
return None;
}
use middle::cstore::{InlinedItem, InlinedItemRef};
use middle::ty::adjustment;
use middle::ty::cast;
-use middle::check_const::ConstQualif;
-use middle::def;
+use middle::const_qualif::ConstQualif;
+use middle::def::{self, Def};
use middle::def_id::DefId;
use middle::privacy::{AllPublic, LastMod};
use middle::region;
// ______________________________________________________________________
// Encoding and decoding of ast::def
-fn decode_def(dcx: &DecodeContext, dsr: &mut reader::Decoder) -> def::Def {
- let def: def::Def = Decodable::decode(dsr).unwrap();
+fn decode_def(dcx: &DecodeContext, dsr: &mut reader::Decoder) -> Def {
+ let def: Def = Decodable::decode(dsr).unwrap();
def.tr(dcx)
}
-impl tr for def::Def {
- fn tr(&self, dcx: &DecodeContext) -> def::Def {
+impl tr for Def {
+ fn tr(&self, dcx: &DecodeContext) -> Def {
match *self {
- def::DefFn(did, is_ctor) => def::DefFn(did.tr(dcx), is_ctor),
- def::DefMethod(did) => def::DefMethod(did.tr(dcx)),
- def::DefSelfTy(opt_did, impl_ids) => { def::DefSelfTy(opt_did.map(|did| did.tr(dcx)),
+ Def::Fn(did) => Def::Fn(did.tr(dcx)),
+ Def::Method(did) => Def::Method(did.tr(dcx)),
+ Def::SelfTy(opt_did, impl_ids) => { Def::SelfTy(opt_did.map(|did| did.tr(dcx)),
impl_ids.map(|(nid1, nid2)| {
(dcx.tr_id(nid1),
dcx.tr_id(nid2))
})) }
- def::DefMod(did) => { def::DefMod(did.tr(dcx)) }
- def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) }
- def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) }
- def::DefConst(did) => { def::DefConst(did.tr(dcx)) }
- def::DefAssociatedConst(did) => def::DefAssociatedConst(did.tr(dcx)),
- def::DefLocal(_, nid) => {
+ Def::Mod(did) => { Def::Mod(did.tr(dcx)) }
+ Def::ForeignMod(did) => { Def::ForeignMod(did.tr(dcx)) }
+ Def::Static(did, m) => { Def::Static(did.tr(dcx), m) }
+ Def::Const(did) => { Def::Const(did.tr(dcx)) }
+ Def::AssociatedConst(did) => Def::AssociatedConst(did.tr(dcx)),
+ Def::Local(_, nid) => {
let nid = dcx.tr_id(nid);
let did = dcx.tcx.map.local_def_id(nid);
- def::DefLocal(did, nid)
+ Def::Local(did, nid)
}
- def::DefVariant(e_did, v_did, is_s) => {
- def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s)
- },
- def::DefTrait(did) => def::DefTrait(did.tr(dcx)),
- def::DefTy(did, is_enum) => def::DefTy(did.tr(dcx), is_enum),
- def::DefAssociatedTy(trait_did, did) =>
- def::DefAssociatedTy(trait_did.tr(dcx), did.tr(dcx)),
- def::DefPrimTy(p) => def::DefPrimTy(p),
- def::DefTyParam(s, index, def_id, n) => def::DefTyParam(s, index, def_id.tr(dcx), n),
- def::DefUpvar(_, nid1, index, nid2) => {
+ Def::Variant(e_did, v_did) => Def::Variant(e_did.tr(dcx), v_did.tr(dcx)),
+ Def::Trait(did) => Def::Trait(did.tr(dcx)),
+ Def::Enum(did) => Def::Enum(did.tr(dcx)),
+ Def::TyAlias(did) => Def::TyAlias(did.tr(dcx)),
+ Def::AssociatedTy(trait_did, did) =>
+ Def::AssociatedTy(trait_did.tr(dcx), did.tr(dcx)),
+ Def::PrimTy(p) => Def::PrimTy(p),
+ Def::TyParam(s, index, def_id, n) => Def::TyParam(s, index, def_id.tr(dcx), n),
+ Def::Upvar(_, nid1, index, nid2) => {
let nid1 = dcx.tr_id(nid1);
let nid2 = dcx.tr_id(nid2);
let did1 = dcx.tcx.map.local_def_id(nid1);
- def::DefUpvar(did1, nid1, index, nid2)
+ Def::Upvar(did1, nid1, index, nid2)
}
- def::DefStruct(did) => def::DefStruct(did.tr(dcx)),
- def::DefLabel(nid) => def::DefLabel(dcx.tr_id(nid)),
- def::DefErr => def::DefErr,
+ Def::Struct(did) => Def::Struct(did.tr(dcx)),
+ Def::Label(nid) => Def::Label(dcx.tr_id(nid)),
+ Def::Err => Def::Err,
}
}
}
use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
use middle::def;
use middle::lang_items;
-use middle::ty::{self, Ty};
+use middle::ty::{self, Ty, VariantKind};
use middle::def_id::{DefId, DefIndex};
use rustc::front::map as hir_map;
local_path.into_iter().chain(path).collect()
}
+ fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> {
+ let cdata = self.get_crate_data(def_id.krate);
+ decoder::get_variant_kind(&cdata, def_id.index)
+ }
+
+ fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>
+ {
+ let cdata = self.get_crate_data(struct_def_id.krate);
+ decoder::get_struct_ctor_def_id(&cdata, struct_def_id.index)
+ }
+
fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>
{
let cdata = self.get_crate_data(did.krate);
use middle::cstore::{LOCAL_CRATE, FoundAst, InlinedItem, LinkagePreference};
use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls};
-use middle::def;
+use middle::def::Def;
use middle::def_id::{DefId, DefIndex};
use middle::lang_items;
use middle::subst;
use middle::ty::{ImplContainer, TraitContainer};
-use middle::ty::{self, Ty, TypeFoldable};
+use middle::ty::{self, Ty, TypeFoldable, VariantKind};
use rustc::mir;
use rustc::mir::visit::MutVisitor;
index::DenseIndex::from_buf(index.data, index.start, index.end)
}
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq)]
enum Family {
ImmStatic, // c
MutStatic, // b
Fn, // f
- CtorFn, // o
StaticMethod, // F
Method, // h
Type, // y
Mod, // m
ForeignMod, // n
Enum, // t
- StructVariant, // V
- TupleVariant, // v
- UnitVariant, // w
+ Variant(VariantKind), // V, v, w
Impl, // i
DefaultImpl, // d
Trait, // I
- Struct, // S
- TupleStruct, // s
- UnitStruct, // u
+ Struct(VariantKind), // S, s, u
PublicField, // g
InheritedField, // N
Constant, // C
'c' => ImmStatic,
'b' => MutStatic,
'f' => Fn,
- 'o' => CtorFn,
'F' => StaticMethod,
'h' => Method,
'y' => Type,
'm' => Mod,
'n' => ForeignMod,
't' => Enum,
- 'V' => StructVariant,
- 'v' => TupleVariant,
- 'w' => UnitVariant,
+ 'V' => Variant(VariantKind::Struct),
+ 'v' => Variant(VariantKind::Tuple),
+ 'w' => Variant(VariantKind::Unit),
'i' => Impl,
'd' => DefaultImpl,
'I' => Trait,
- 'S' => Struct,
- 's' => TupleStruct,
- 'u' => UnitStruct,
+ 'S' => Struct(VariantKind::Struct),
+ 's' => Struct(VariantKind::Tuple),
+ 'u' => Struct(VariantKind::Unit),
'g' => PublicField,
'N' => InheritedField,
c => panic!("unexpected family char: {}", c)
}
}
+fn family_to_variant_kind<'tcx>(family: Family) -> Option<ty::VariantKind> {
+ match family {
+ Struct(VariantKind::Struct) | Variant(VariantKind::Struct) =>
+ Some(ty::VariantKind::Struct),
+ Struct(VariantKind::Tuple) | Variant(VariantKind::Tuple) =>
+ Some(ty::VariantKind::Tuple),
+ Struct(VariantKind::Unit) | Variant(VariantKind::Unit) =>
+ Some(ty::VariantKind::Unit),
+ _ => None,
+ }
+}
+
fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike {
let fam = item_family(item);
match fam {
// Check whether we have an associated const item.
match item_sort(item) {
Some('C') | Some('c') => {
- DlDef(def::DefAssociatedConst(did))
+ DlDef(Def::AssociatedConst(did))
}
_ => {
// Regular const item.
- DlDef(def::DefConst(did))
+ DlDef(Def::Const(did))
}
}
}
- ImmStatic => DlDef(def::DefStatic(did, false)),
- MutStatic => DlDef(def::DefStatic(did, true)),
- Struct | TupleStruct | UnitStruct => DlDef(def::DefStruct(did)),
- Fn => DlDef(def::DefFn(did, false)),
- CtorFn => DlDef(def::DefFn(did, true)),
+ ImmStatic => DlDef(Def::Static(did, false)),
+ MutStatic => DlDef(Def::Static(did, true)),
+ Struct(..) => DlDef(Def::Struct(did)),
+ Fn => DlDef(Def::Fn(did)),
Method | StaticMethod => {
- DlDef(def::DefMethod(did))
+ DlDef(Def::Method(did))
}
Type => {
if item_sort(item) == Some('t') {
let trait_did = item_require_parent_item(cdata, item);
- DlDef(def::DefAssociatedTy(trait_did, did))
+ DlDef(Def::AssociatedTy(trait_did, did))
} else {
- DlDef(def::DefTy(did, false))
+ DlDef(Def::TyAlias(did))
}
}
- Mod => DlDef(def::DefMod(did)),
- ForeignMod => DlDef(def::DefForeignMod(did)),
- StructVariant => {
+ Mod => DlDef(Def::Mod(did)),
+ ForeignMod => DlDef(Def::ForeignMod(did)),
+ Variant(..) => {
let enum_did = item_require_parent_item(cdata, item);
- DlDef(def::DefVariant(enum_did, did, true))
+ DlDef(Def::Variant(enum_did, did))
}
- TupleVariant | UnitVariant => {
- let enum_did = item_require_parent_item(cdata, item);
- DlDef(def::DefVariant(enum_did, did, false))
- }
- Trait => DlDef(def::DefTrait(did)),
- Enum => DlDef(def::DefTy(did, true)),
+ Trait => DlDef(Def::Trait(did)),
+ Enum => DlDef(Def::Enum(did)),
Impl | DefaultImpl => DlImpl(did),
PublicField | InheritedField => DlField,
}
item_id: DefIndex,
tcx: &ty::ctxt<'tcx>) -> ty::AdtDefMaster<'tcx>
{
- fn family_to_variant_kind<'tcx>(family: Family, tcx: &ty::ctxt<'tcx>) -> ty::VariantKind {
- match family {
- Struct | StructVariant => ty::VariantKind::Struct,
- TupleStruct | TupleVariant => ty::VariantKind::Tuple,
- UnitStruct | UnitVariant => ty::VariantKind::Unit,
+ fn expect_variant_kind<'tcx>(family: Family, tcx: &ty::ctxt<'tcx>) -> ty::VariantKind {
+ match family_to_variant_kind(family) {
+ Some(kind) => kind,
_ => tcx.sess.bug(&format!("unexpected family: {:?}", family)),
}
}
name: item_name(intr, item),
fields: get_variant_fields(intr, cdata, item, tcx),
disr_val: disr,
- kind: family_to_variant_kind(item_family(item), tcx),
+ kind: expect_variant_kind(item_family(item), tcx),
}
}).collect()
}
name: item_name(intr, doc),
fields: get_variant_fields(intr, cdata, doc, tcx),
disr_val: 0,
- kind: family_to_variant_kind(item_family(doc), tcx),
+ kind: expect_variant_kind(item_family(doc), tcx),
}
}
(ty::AdtKind::Enum,
get_enum_variants(intr, cdata, doc, tcx))
}
- Struct | TupleStruct | UnitStruct => {
+ Struct(..) => {
let ctor_did =
reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).
map_or(did, |ctor_doc| translated_def_id(cdata, ctor_doc));
}).collect()
}
+pub fn get_variant_kind(cdata: Cmd, node_id: DefIndex) -> Option<VariantKind>
+{
+ let item = cdata.lookup_item(node_id);
+ family_to_variant_kind(item_family(item))
+}
+
+pub fn get_struct_ctor_def_id(cdata: Cmd, node_id: DefIndex) -> Option<DefId>
+{
+ let item = cdata.lookup_item(node_id);
+ reader::maybe_get_doc(item, tag_items_data_item_struct_ctor).
+ map(|ctor_doc| translated_def_id(cdata, ctor_doc))
+}
+
/// If node_id is the constructor of a tuple struct, retrieve the NodeId of
/// the actual type definition, otherwise, return None
pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd,
fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
name: Name,
- ctor_id: NodeId,
+ struct_def: &hir::VariantData,
index: &mut CrateIndex<'tcx>,
struct_id: NodeId) {
+ let ctor_id = struct_def.id();
let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id);
index.record(ctor_def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, ctor_def_id);
- encode_family(rbml_w, 'o');
+ encode_family(rbml_w, match *struct_def {
+ hir::VariantData::Struct(..) => 'S',
+ hir::VariantData::Tuple(..) => 's',
+ hir::VariantData::Unit(..) => 'u',
+ });
encode_bounds_and_type_for_item(rbml_w, ecx, index, ctor_id);
encode_name(rbml_w, name);
ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path));
// If this is a tuple-like struct, encode the type of the constructor.
if !struct_def.is_struct() {
- encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def.id(), index, item.id);
+ encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def, index, item.id);
}
}
hir::ItemDefaultImpl(unsafety, _) => {
}
let dypair = self.dylibname();
+ let staticpair = self.staticlibname();
// want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
let dylib_prefix = format!("{}{}", dypair.0, self.crate_name);
let rlib_prefix = format!("lib{}", self.crate_name);
- let staticlib_prefix = format!("lib{}", self.crate_name);
+ let staticlib_prefix = format!("{}{}", staticpair.0, self.crate_name);
let mut candidates = HashMap::new();
let mut staticlibs = vec!();
false)
} else {
if file.starts_with(&staticlib_prefix[..]) &&
- file.ends_with(".a") {
+ file.ends_with(&staticpair.1) {
staticlibs.push(CrateMismatch {
path: path.to_path_buf(),
got: "static".to_string()
(t.options.dll_prefix.clone(), t.options.dll_suffix.clone())
}
+ // Returns the corresponding (prefix, suffix) that files need to have for
+ // static libraries
+ fn staticlibname(&self) -> (String, String) {
+ let t = &self.target;
+ (t.options.staticlib_prefix.clone(), t.options.staticlib_suffix.clone())
+ }
+
fn find_commandline_library(&mut self, locs: &[String]) -> Option<Library> {
// First, filter out all libraries that look suspicious. We only accept
// files which actually exist that have the correct naming scheme for
// start the loop
this.cfg.terminate(block, Terminator::Goto { target: loop_block });
- this.in_loop_scope(loop_block, exit_block, |this| {
+ let might_break = this.in_loop_scope(loop_block, exit_block, move |this| {
// conduct the test, if necessary
let body_block;
- let opt_cond_expr = opt_cond_expr; // FIXME rustc bug
if let Some(cond_expr) = opt_cond_expr {
+ // This loop has a condition, ergo its exit_block is reachable.
+ this.find_loop_scope(expr_span, None).might_break = true;
+
let loop_block_end;
let cond = unpack!(loop_block_end = this.as_operand(loop_block, cond_expr));
body_block = this.cfg.start_new_block();
body_block = loop_block;
}
- // execute the body, branching back to the test
- // We write body’s “return value” into the destination of loop. This is fine,
- // because:
- //
- // * In Rust both loop expression and its body are required to have `()`
- // as the “return value”;
- // * The destination will be considered uninitialised (given it was
- // uninitialised before the loop) during the first iteration, thus
- // disallowing its use inside the body. Alternatively, if it was already
- // initialised, the `destination` can only possibly have a value of `()`,
- // therefore, “mutating” the destination during iteration is fine.
- let body_block_end = unpack!(this.into(destination, body_block, body));
+ // The “return” value of the loop body must always be an unit, but we cannot
+ // reuse that as a “return” value of the whole loop expressions, because some
+ // loops are diverging (e.g. `loop {}`). Thus, we introduce a unit temporary as
+ // the destination for the loop body and assign the loop’s own “return” value
+ // immediately after the iteration is finished.
+ let tmp = this.get_unit_temp();
+ // Execute the body, branching back to the test.
+ let body_block_end = unpack!(this.into(&tmp, body_block, body));
this.cfg.terminate(body_block_end, Terminator::Goto { target: loop_block });
- exit_block.unit()
- })
+ });
+ // If the loop may reach its exit_block, we assign an empty tuple to the
+ // destination to keep the MIR well-formed.
+ if might_break {
+ this.cfg.push_assign_unit(exit_block, expr_span, destination);
+ }
+ exit_block.unit()
}
ExprKind::Assign { lhs, rhs } => {
// Note: we evaluate assignments right-to-left. This
|loop_scope| loop_scope.continue_block)
}
ExprKind::Break { label } => {
- this.break_or_continue(expr_span, label, block, |loop_scope| loop_scope.break_block)
+ this.break_or_continue(expr_span, label, block, |loop_scope| {
+ loop_scope.might_break = true;
+ loop_scope.break_block
+ })
}
ExprKind::Return { value } => {
block = match value {
block: BasicBlock,
exit_selector: F)
-> BlockAnd<()>
- where F: FnOnce(&LoopScope) -> BasicBlock
+ where F: FnOnce(&mut LoopScope) -> BasicBlock
{
- let loop_scope = self.find_loop_scope(span, label);
- let exit_block = exit_selector(&loop_scope);
- self.exit_scope(span, loop_scope.extent, block, exit_block);
+ let (exit_block, extent) = {
+ let loop_scope = self.find_loop_scope(span, label);
+ (exit_selector(loop_scope), loop_scope.extent)
+ };
+ self.exit_scope(span, extent, block, exit_block);
self.cfg.start_new_block().unit()
}
}
var_decls: Vec<VarDecl<'tcx>>,
var_indices: FnvHashMap<ast::NodeId, u32>,
temp_decls: Vec<TempDecl<'tcx>>,
+ unit_temp: Option<Lvalue<'tcx>>,
}
struct CFG<'tcx> {
temp_decls: vec![],
var_decls: vec![],
var_indices: FnvHashMap(),
+ unit_temp: None
};
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
block.and(arg_decls)
})
}
+
+ fn get_unit_temp(&mut self) -> Lvalue<'tcx> {
+ match self.unit_temp {
+ Some(ref tmp) => tmp.clone(),
+ None => {
+ let ty = self.hir.unit_ty();
+ let tmp = self.temp(ty);
+ self.unit_temp = Some(tmp.clone());
+ tmp
+ }
+ }
+ }
}
///////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug)]
pub struct LoopScope {
- pub extent: CodeExtent, // extent of the loop
- pub continue_block: BasicBlock, // where to go on a `loop`
+ /// Extent of the loop
+ pub extent: CodeExtent,
+ /// Where the body of the loop begins
+ pub continue_block: BasicBlock,
+ /// Block to branch into when the loop terminates (either by being `break`-en out from, or by
+ /// having its condition to become false)
pub break_block: BasicBlock, // where to go on a `break
+ /// Indicates the reachability of the break_block for this loop
+ pub might_break: bool
}
impl<'a,'tcx> Builder<'a,'tcx> {
/// Start a loop scope, which tracks where `continue` and `break`
/// should branch to. See module comment for more details.
- pub fn in_loop_scope<F, R>(&mut self,
+ ///
+ /// Returns the might_break attribute of the LoopScope used.
+ pub fn in_loop_scope<F>(&mut self,
loop_block: BasicBlock,
break_block: BasicBlock,
f: F)
- -> BlockAnd<R>
- where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>
+ -> bool
+ where F: FnOnce(&mut Builder<'a, 'tcx>)
{
let extent = self.extent_of_innermost_scope();
let loop_scope = LoopScope {
extent: extent.clone(),
continue_block: loop_block,
break_block: break_block,
+ might_break: false
};
self.loop_scopes.push(loop_scope);
- let r = f(self);
- assert!(self.loop_scopes.pop().unwrap().extent == extent);
- r
+ f(self);
+ let loop_scope = self.loop_scopes.pop().unwrap();
+ assert!(loop_scope.extent == extent);
+ loop_scope.might_break
}
/// Convenience wrapper that pushes a scope and then executes `f`
pub fn find_loop_scope(&mut self,
span: Span,
label: Option<CodeExtent>)
- -> LoopScope {
- let loop_scope =
- match label {
- None => {
- // no label? return the innermost loop scope
- self.loop_scopes.iter()
- .rev()
- .next()
- }
- Some(label) => {
- // otherwise, find the loop-scope with the correct id
- self.loop_scopes.iter()
- .rev()
- .filter(|loop_scope| loop_scope.extent == label)
- .next()
- }
- };
-
- match loop_scope {
- Some(loop_scope) => loop_scope.clone(),
- None => self.hir.span_bug(span, "no enclosing loop scope found?"),
- }
+ -> &mut LoopScope {
+ let Builder { ref mut loop_scopes, ref mut hir, .. } = *self;
+ match label {
+ None => {
+ // no label? return the innermost loop scope
+ loop_scopes.iter_mut().rev().next()
+ }
+ Some(label) => {
+ // otherwise, find the loop-scope with the correct id
+ loop_scopes.iter_mut()
+ .rev()
+ .filter(|loop_scope| loop_scope.extent == label)
+ .next()
+ }
+ }.unwrap_or_else(|| hir.span_bug(span, "no enclosing loop scope found?"))
}
/// Branch out of `block` to `target`, exiting all scopes up to
extent: CodeExtent,
block: BasicBlock,
target: BasicBlock) {
- let popped_scopes =
- match self.scopes.iter().rev().position(|scope| scope.extent == extent) {
- Some(p) => p + 1,
- None => self.hir.span_bug(span, &format!("extent {:?} does not enclose",
- extent)),
- };
-
- for scope in self.scopes.iter_mut().rev().take(popped_scopes) {
+ let Builder { ref mut scopes, ref mut cfg, ref mut hir, .. } = *self;
+
+ let scope_count = 1 + scopes.iter().rev().position(|scope| scope.extent == extent)
+ .unwrap_or_else(||{
+ hir.span_bug(span, &format!("extent {:?} does not enclose", extent))
+ });
+
+ for scope in scopes.iter_mut().rev().take(scope_count) {
for &(kind, drop_span, ref lvalue) in &scope.drops {
- self.cfg.push_drop(block, drop_span, kind, lvalue);
+ cfg.push_drop(block, drop_span, kind, lvalue);
}
}
-
- self.cfg.terminate(block, Terminator::Goto { target: target });
+ cfg.terminate(block, Terminator::Goto { target: target });
}
/// Creates a path that performs all required cleanup for unwinding.
use hair::cx::block;
use hair::cx::to_ref::ToRef;
use rustc::front::map;
-use rustc::middle::def;
+use rustc::middle::def::Def;
use rustc::middle::region::CodeExtent;
use rustc::middle::pat_util;
use rustc::middle::ty::{self, VariantDef, Ty};
// Tuple-like ADTs are represented as ExprCall. We convert them here.
expr_ty.ty_adt_def().and_then(|adt_def|{
match cx.tcx.def_map.borrow()[&fun.id].full_def() {
- def::DefVariant(_, variant_id, false) => {
+ Def::Variant(_, variant_id) => {
Some((adt_def, adt_def.variant_index_with_id(variant_id)))
},
- def::DefStruct(_) => {
+ Def::Struct(..) => {
Some((adt_def, 0))
},
_ => None
}
ty::TyEnum(adt, substs) => {
match cx.tcx.def_map.borrow()[&self.id].full_def() {
- def::DefVariant(enum_id, variant_id, _) => {
+ Def::Variant(enum_id, variant_id) => {
debug_assert!(adt.did == enum_id);
let index = adt.variant_index_with_id(variant_id);
let field_refs = field_refs(&adt.variants[index], fields);
let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
let (def_id, kind) = match def {
// A regular function.
- def::DefFn(def_id, _) => (def_id, ItemKind::Function),
- def::DefMethod(def_id) => (def_id, ItemKind::Method),
- def::DefStruct(def_id) => match cx.tcx.node_id_to_type(expr.id).sty {
+ Def::Fn(def_id) => (def_id, ItemKind::Function),
+ Def::Method(def_id) => (def_id, ItemKind::Method),
+ Def::Struct(def_id) => match cx.tcx.node_id_to_type(expr.id).sty {
// A tuple-struct constructor. Should only be reached if not called in the same
// expression.
ty::TyBareFn(..) => (def_id, ItemKind::Function),
},
ref sty => panic!("unexpected sty: {:?}", sty)
},
- def::DefVariant(enum_id, variant_id, false) => match cx.tcx.node_id_to_type(expr.id).sty {
+ Def::Variant(enum_id, variant_id) => match cx.tcx.node_id_to_type(expr.id).sty {
// A variant constructor. Should only be reached if not called in the same
// expression.
ty::TyBareFn(..) => (variant_id, ItemKind::Function),
},
ref sty => panic!("unexpected sty: {:?}", sty)
},
- def::DefConst(def_id) |
- def::DefAssociatedConst(def_id) => {
+ Def::Const(def_id) |
+ Def::AssociatedConst(def_id) => {
if let Some(v) = cx.try_const_eval_literal(expr) {
return ExprKind::Literal { literal: v };
} else {
}
}
- def::DefStatic(node_id, _) => return ExprKind::StaticRef {
+ Def::Static(node_id, _) => return ExprKind::StaticRef {
id: node_id,
},
- def @ def::DefLocal(..) |
- def @ def::DefUpvar(..) => return convert_var(cx, expr, def),
+ def @ Def::Local(..) |
+ def @ Def::Upvar(..) => return convert_var(cx, expr, def),
def =>
cx.tcx.sess.span_bug(
fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
expr: &'tcx hir::Expr,
- def: def::Def)
+ def: Def)
-> ExprKind<'tcx> {
let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
match def {
- def::DefLocal(_, node_id) => {
+ Def::Local(_, node_id) => {
ExprKind::VarRef {
id: node_id,
}
}
- def::DefUpvar(_, id_var, index, closure_expr_id) => {
+ Def::Upvar(_, id_var, index, closure_expr_id) => {
debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id);
let var_ty = cx.tcx.node_id_to_type(id_var);
fn loop_label<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> CodeExtent {
match cx.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
- Some(def::DefLabel(loop_id)) => cx.tcx.region_maps.node_extent(loop_id),
+ Some(Def::Label(loop_id)) => cx.tcx.region_maps.node_extent(loop_id),
d => {
cx.tcx.sess.span_bug(expr.span, &format!("loop scope resolved to {:?}", d));
}
self.tcx.types.bool
}
+ pub fn unit_ty(&mut self) -> Ty<'tcx> {
+ self.tcx.mk_nil()
+ }
+
pub fn str_literal(&mut self, value: token::InternedString) -> Literal<'tcx> {
Literal::Value { value: ConstVal::Str(value) }
}
use hair::cx::Cx;
use rustc_data_structures::fnv::FnvHashMap;
use rustc::middle::const_eval;
-use rustc::middle::def;
+use rustc::middle::def::Def;
use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
use rustc::middle::ty::{self, Ty};
use rustc::mir::repr::*;
{
let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
match def {
- def::DefConst(def_id) | def::DefAssociatedConst(def_id) =>
+ Def::Const(def_id) | Def::AssociatedConst(def_id) =>
match const_eval::lookup_const_by_id(self.cx.tcx, def_id,
Some(pat.id), None) {
Some(const_expr) => {
-> PatternKind<'tcx> {
let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
match def {
- def::DefVariant(enum_id, variant_id, _) => {
+ Def::Variant(enum_id, variant_id) => {
let adt_def = self.cx.tcx.lookup_adt_def(enum_id);
if adt_def.variants.len() > 1 {
PatternKind::Variant {
}
}
- // NB: resolving to DefStruct means the struct *constructor*,
- // not the struct as a type.
- def::DefStruct(..) | def::DefTy(..) => {
+ Def::Struct(..) | Def::TyAlias(..) => {
PatternKind::Leaf { subpatterns: subpatterns }
}
--- /dev/null
+// Copyright 2012-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.
+
+// Verifies that the types and values of const and static items
+// are safe. The rules enforced by this module are:
+//
+// - For each *mutable* static item, it checks that its **type**:
+// - doesn't have a destructor
+// - doesn't own a box
+//
+// - For each *immutable* static item, it checks that its **value**:
+// - doesn't own a box
+// - doesn't contain a struct literal or a call to an enum variant / struct constructor where
+// - the type of the struct/enum has a dtor
+//
+// Rules Enforced Elsewhere:
+// - It's not possible to take the address of a static item with unsafe interior. This is enforced
+// by borrowck::gather_loans
+
+use rustc::dep_graph::DepNode;
+use rustc::middle::ty::cast::{CastKind};
+use rustc::middle::const_eval::{self, ConstEvalErr};
+use rustc::middle::const_eval::ErrKind::IndexOpFeatureGated;
+use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
+use rustc::middle::def::Def;
+use rustc::middle::def_id::DefId;
+use rustc::middle::expr_use_visitor as euv;
+use rustc::middle::infer;
+use rustc::middle::mem_categorization as mc;
+use rustc::middle::mem_categorization::Categorization;
+use rustc::middle::traits;
+use rustc::middle::ty::{self, Ty};
+use rustc::util::nodemap::NodeMap;
+use rustc::middle::const_qualif::ConstQualif;
+use rustc::lint::builtin::CONST_ERR;
+
+use rustc_front::hir;
+use syntax::ast;
+use syntax::codemap::Span;
+use syntax::feature_gate::UnstableFeatures;
+use rustc_front::intravisit::{self, FnKind, Visitor};
+
+use std::collections::hash_map::Entry;
+use std::cmp::Ordering;
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+enum Mode {
+ Const,
+ ConstFn,
+ Static,
+ StaticMut,
+
+ // An expression that occurs outside of any constant context
+ // (i.e. `const`, `static`, array lengths, etc.). The value
+ // can be variable at runtime, but will be promotable to
+ // static memory if we can prove it is actually constant.
+ Var,
+}
+
+struct CheckCrateVisitor<'a, 'tcx: 'a> {
+ tcx: &'a ty::ctxt<'tcx>,
+ mode: Mode,
+ qualif: ConstQualif,
+ rvalue_borrows: NodeMap<hir::Mutability>
+}
+
+impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
+ fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R where
+ F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>) -> R,
+ {
+ let (old_mode, old_qualif) = (self.mode, self.qualif);
+ self.mode = mode;
+ self.qualif = ConstQualif::empty();
+ let r = f(self);
+ self.mode = old_mode;
+ self.qualif = old_qualif;
+ r
+ }
+
+ fn with_euv<'b, F, R>(&'b mut self, item_id: Option<ast::NodeId>, f: F) -> R where
+ F: for<'t> FnOnce(&mut euv::ExprUseVisitor<'b, 't, 'b, 'tcx>) -> R,
+ {
+ let param_env = match item_id {
+ Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
+ None => self.tcx.empty_parameter_environment()
+ };
+
+ let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env));
+
+ f(&mut euv::ExprUseVisitor::new(self, &infcx))
+ }
+
+ fn global_expr(&mut self, mode: Mode, expr: &hir::Expr) -> ConstQualif {
+ assert!(mode != Mode::Var);
+ match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) {
+ Entry::Occupied(entry) => return *entry.get(),
+ Entry::Vacant(entry) => {
+ // Prevent infinite recursion on re-entry.
+ entry.insert(ConstQualif::empty());
+ }
+ }
+ self.with_mode(mode, |this| {
+ this.with_euv(None, |euv| euv.consume_expr(expr));
+ this.visit_expr(expr);
+ this.qualif
+ })
+ }
+
+ fn fn_like(&mut self,
+ fk: FnKind,
+ fd: &hir::FnDecl,
+ b: &hir::Block,
+ s: Span,
+ fn_id: ast::NodeId)
+ -> ConstQualif {
+ match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) {
+ Entry::Occupied(entry) => return *entry.get(),
+ Entry::Vacant(entry) => {
+ // Prevent infinite recursion on re-entry.
+ entry.insert(ConstQualif::empty());
+ }
+ }
+
+ let mode = match fk {
+ FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _) => {
+ Mode::ConstFn
+ }
+ FnKind::Method(_, m, _) => {
+ if m.constness == hir::Constness::Const {
+ Mode::ConstFn
+ } else {
+ Mode::Var
+ }
+ }
+ _ => Mode::Var
+ };
+
+ let qualif = self.with_mode(mode, |this| {
+ this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
+ intravisit::walk_fn(this, fk, fd, b, s);
+ this.qualif
+ });
+
+ // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
+ // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
+ let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
+
+ self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
+ qualif
+ }
+
+ fn add_qualif(&mut self, qualif: ConstQualif) {
+ self.qualif = self.qualif | qualif;
+ }
+
+ /// Returns true if the call is to a const fn or method.
+ fn handle_const_fn_call(&mut self,
+ expr: &hir::Expr,
+ def_id: DefId,
+ ret_ty: Ty<'tcx>)
+ -> bool {
+ if let Some(fn_like) = const_eval::lookup_const_fn_by_id(self.tcx, def_id) {
+ if
+ // we are in a static/const initializer
+ self.mode != Mode::Var &&
+
+ // feature-gate is not enabled
+ !self.tcx.sess.features.borrow().const_fn &&
+
+ // this doesn't come from a macro that has #[allow_internal_unstable]
+ !self.tcx.sess.codemap().span_allows_unstable(expr.span)
+ {
+ let mut err = self.tcx.sess.struct_span_err(
+ expr.span,
+ "const fns are an unstable feature");
+ fileline_help!(
+ &mut err,
+ expr.span,
+ "in Nightly builds, add `#![feature(const_fn)]` to the crate \
+ attributes to enable");
+ err.emit();
+ }
+
+ let qualif = self.fn_like(fn_like.kind(),
+ fn_like.decl(),
+ fn_like.body(),
+ fn_like.span(),
+ fn_like.id());
+ self.add_qualif(qualif);
+
+ if ret_ty.type_contents(self.tcx).interior_unsafe() {
+ self.add_qualif(ConstQualif::MUTABLE_MEM);
+ }
+
+ true
+ } else {
+ false
+ }
+ }
+
+ fn record_borrow(&mut self, id: ast::NodeId, mutbl: hir::Mutability) {
+ match self.rvalue_borrows.entry(id) {
+ Entry::Occupied(mut entry) => {
+ // Merge the two borrows, taking the most demanding
+ // one, mutability-wise.
+ if mutbl == hir::MutMutable {
+ entry.insert(mutbl);
+ }
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(mutbl);
+ }
+ }
+ }
+
+ fn msg(&self) -> &'static str {
+ match self.mode {
+ Mode::Const => "constant",
+ Mode::ConstFn => "constant function",
+ Mode::StaticMut | Mode::Static => "static",
+ Mode::Var => unreachable!(),
+ }
+ }
+
+ fn check_static_mut_type(&self, e: &hir::Expr) {
+ let node_ty = self.tcx.node_id_to_type(e.id);
+ let tcontents = node_ty.type_contents(self.tcx);
+
+ let suffix = if tcontents.has_dtor() {
+ "destructors"
+ } else if tcontents.owns_owned() {
+ "boxes"
+ } else {
+ return
+ };
+
+ span_err!(self.tcx.sess, e.span, E0397,
+ "mutable statics are not allowed to have {}", suffix);
+ }
+
+ fn check_static_type(&self, e: &hir::Expr) {
+ let ty = self.tcx.node_id_to_type(e.id);
+ let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
+ let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
+ let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();
+ fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
+ match fulfill_cx.select_all_or_error(&infcx) {
+ Ok(()) => { },
+ Err(ref errors) => {
+ traits::report_fulfillment_errors(&infcx, errors);
+ }
+ }
+ }
+}
+
+impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
+ fn visit_item(&mut self, i: &hir::Item) {
+ debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
+ assert_eq!(self.mode, Mode::Var);
+ match i.node {
+ hir::ItemStatic(_, hir::MutImmutable, ref expr) => {
+ self.check_static_type(&**expr);
+ self.global_expr(Mode::Static, &**expr);
+ }
+ hir::ItemStatic(_, hir::MutMutable, ref expr) => {
+ self.check_static_mut_type(&**expr);
+ self.global_expr(Mode::StaticMut, &**expr);
+ }
+ hir::ItemConst(_, ref expr) => {
+ self.global_expr(Mode::Const, &**expr);
+ }
+ hir::ItemEnum(ref enum_definition, _) => {
+ for var in &enum_definition.variants {
+ if let Some(ref ex) = var.node.disr_expr {
+ self.global_expr(Mode::Const, &**ex);
+ }
+ }
+ }
+ _ => {
+ intravisit::walk_item(self, i);
+ }
+ }
+ }
+
+ fn visit_trait_item(&mut self, t: &'v hir::TraitItem) {
+ match t.node {
+ hir::ConstTraitItem(_, ref default) => {
+ if let Some(ref expr) = *default {
+ self.global_expr(Mode::Const, &*expr);
+ } else {
+ intravisit::walk_trait_item(self, t);
+ }
+ }
+ _ => self.with_mode(Mode::Var, |v| intravisit::walk_trait_item(v, t)),
+ }
+ }
+
+ fn visit_impl_item(&mut self, i: &'v hir::ImplItem) {
+ match i.node {
+ hir::ImplItemKind::Const(_, ref expr) => {
+ self.global_expr(Mode::Const, &*expr);
+ }
+ _ => self.with_mode(Mode::Var, |v| intravisit::walk_impl_item(v, i)),
+ }
+ }
+
+ fn visit_fn(&mut self,
+ fk: FnKind<'v>,
+ fd: &'v hir::FnDecl,
+ b: &'v hir::Block,
+ s: Span,
+ fn_id: ast::NodeId) {
+ self.fn_like(fk, fd, b, s, fn_id);
+ }
+
+ fn visit_pat(&mut self, p: &hir::Pat) {
+ match p.node {
+ hir::PatLit(ref lit) => {
+ self.global_expr(Mode::Const, &**lit);
+ }
+ hir::PatRange(ref start, ref end) => {
+ self.global_expr(Mode::Const, &**start);
+ self.global_expr(Mode::Const, &**end);
+
+ match const_eval::compare_lit_exprs(self.tcx, start, end) {
+ Some(Ordering::Less) |
+ Some(Ordering::Equal) => {}
+ Some(Ordering::Greater) => {
+ span_err!(self.tcx.sess, start.span, E0030,
+ "lower range bound must be less than or equal to upper");
+ }
+ None => {
+ self.tcx.sess.delay_span_bug(start.span,
+ "non-constant path in constant expr");
+ }
+ }
+ }
+ _ => intravisit::walk_pat(self, p)
+ }
+ }
+
+ fn visit_block(&mut self, block: &hir::Block) {
+ // Check all statements in the block
+ for stmt in &block.stmts {
+ match stmt.node {
+ hir::StmtDecl(ref decl, _) => {
+ match decl.node {
+ hir::DeclLocal(_) => {},
+ // Item statements are allowed
+ hir::DeclItem(_) => continue
+ }
+ }
+ hir::StmtExpr(_, _) => {},
+ hir::StmtSemi(_, _) => {},
+ }
+ self.add_qualif(ConstQualif::NOT_CONST);
+ // anything else should have been caught by check_const_fn
+ assert_eq!(self.mode, Mode::Var);
+ }
+ intravisit::walk_block(self, block);
+ }
+
+ fn visit_expr(&mut self, ex: &hir::Expr) {
+ let mut outer = self.qualif;
+ self.qualif = ConstQualif::empty();
+
+ let node_ty = self.tcx.node_id_to_type(ex.id);
+ check_expr(self, ex, node_ty);
+ check_adjustments(self, ex);
+
+ // Special-case some expressions to avoid certain flags bubbling up.
+ match ex.node {
+ hir::ExprCall(ref callee, ref args) => {
+ for arg in args {
+ self.visit_expr(&**arg)
+ }
+
+ let inner = self.qualif;
+ self.visit_expr(&**callee);
+ // The callee's size doesn't count in the call.
+ let added = self.qualif - inner;
+ self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
+ }
+ hir::ExprRepeat(ref element, _) => {
+ self.visit_expr(&**element);
+ // The count is checked elsewhere (typeck).
+ let count = match node_ty.sty {
+ ty::TyArray(_, n) => n,
+ _ => unreachable!()
+ };
+ // [element; 0] is always zero-sized.
+ if count == 0 {
+ self.qualif.remove(ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
+ }
+ }
+ hir::ExprMatch(ref discr, ref arms, _) => {
+ // Compute the most demanding borrow from all the arms'
+ // patterns and set that on the discriminator.
+ let mut borrow = None;
+ for pat in arms.iter().flat_map(|arm| &arm.pats) {
+ let pat_borrow = self.rvalue_borrows.remove(&pat.id);
+ match (borrow, pat_borrow) {
+ (None, _) | (_, Some(hir::MutMutable)) => {
+ borrow = pat_borrow;
+ }
+ _ => {}
+ }
+ }
+ if let Some(mutbl) = borrow {
+ self.record_borrow(discr.id, mutbl);
+ }
+ intravisit::walk_expr(self, ex);
+ }
+ // Division by zero and overflow checking.
+ hir::ExprBinary(op, _, _) => {
+ intravisit::walk_expr(self, ex);
+ let div_or_rem = op.node == hir::BiDiv || op.node == hir::BiRem;
+ match node_ty.sty {
+ ty::TyUint(_) | ty::TyInt(_) if div_or_rem => {
+ if !self.qualif.intersects(ConstQualif::NOT_CONST) {
+ match const_eval::eval_const_expr_partial(
+ self.tcx, ex, ExprTypeChecked, None) {
+ Ok(_) => {}
+ Err(ConstEvalErr { kind: IndexOpFeatureGated, ..}) => {},
+ Err(msg) => {
+ self.tcx.sess.add_lint(CONST_ERR, ex.id,
+ msg.span,
+ msg.description().into_owned())
+ }
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ _ => intravisit::walk_expr(self, ex)
+ }
+
+ // Handle borrows on (or inside the autorefs of) this expression.
+ match self.rvalue_borrows.remove(&ex.id) {
+ Some(hir::MutImmutable) => {
+ // Constants cannot be borrowed if they contain interior mutability as
+ // it means that our "silent insertion of statics" could change
+ // initializer values (very bad).
+ // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
+ // propagated from another error, so erroring again would be just noise.
+ let tc = node_ty.type_contents(self.tcx);
+ if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
+ outer = outer | ConstQualif::NOT_CONST;
+ if self.mode != Mode::Var {
+ span_err!(self.tcx.sess, ex.span, E0492,
+ "cannot borrow a constant which contains \
+ interior mutability, create a static instead");
+ }
+ }
+ // If the reference has to be 'static, avoid in-place initialization
+ // as that will end up pointing to the stack instead.
+ if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
+ self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
+ self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
+ }
+ }
+ Some(hir::MutMutable) => {
+ // `&mut expr` means expr could be mutated, unless it's zero-sized.
+ if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) {
+ if self.mode == Mode::Var {
+ outer = outer | ConstQualif::NOT_CONST;
+ self.add_qualif(ConstQualif::MUTABLE_MEM);
+ } else {
+ span_err!(self.tcx.sess, ex.span, E0017,
+ "references in {}s may only refer \
+ to immutable values", self.msg())
+ }
+ }
+ if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
+ self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
+ }
+ }
+ None => {}
+ }
+ self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
+ // Don't propagate certain flags.
+ self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
+ }
+}
+
+/// This function is used to enforce the constraints on
+/// const/static items. It walks through the *value*
+/// of the item walking down the expression and evaluating
+/// every nested expression. If the expression is not part
+/// of a const/static item, it is qualified for promotion
+/// instead of producing errors.
+fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
+ e: &hir::Expr, node_ty: Ty<'tcx>) {
+ match node_ty.sty {
+ ty::TyStruct(def, _) |
+ ty::TyEnum(def, _) if def.has_dtor() => {
+ v.add_qualif(ConstQualif::NEEDS_DROP);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0493,
+ "{}s are not allowed to have destructors",
+ v.msg());
+ }
+ }
+ _ => {}
+ }
+
+ let method_call = ty::MethodCall::expr(e.id);
+ match e.node {
+ hir::ExprUnary(..) |
+ hir::ExprBinary(..) |
+ hir::ExprIndex(..) if v.tcx.tables.borrow().method_map.contains_key(&method_call) => {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0011,
+ "user-defined operators are not allowed in {}s", v.msg());
+ }
+ }
+ hir::ExprBox(_) => {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0010,
+ "allocations are not allowed in {}s", v.msg());
+ }
+ }
+ hir::ExprUnary(op, ref inner) => {
+ match v.tcx.node_id_to_type(inner.id).sty {
+ ty::TyRawPtr(_) => {
+ assert!(op == hir::UnDeref);
+
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0396,
+ "raw pointers cannot be dereferenced in {}s", v.msg());
+ }
+ }
+ _ => {}
+ }
+ }
+ hir::ExprBinary(op, ref lhs, _) => {
+ match v.tcx.node_id_to_type(lhs.id).sty {
+ ty::TyRawPtr(_) => {
+ assert!(op.node == hir::BiEq || op.node == hir::BiNe ||
+ op.node == hir::BiLe || op.node == hir::BiLt ||
+ op.node == hir::BiGe || op.node == hir::BiGt);
+
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0395,
+ "raw pointers cannot be compared in {}s", v.msg());
+ }
+ }
+ _ => {}
+ }
+ }
+ hir::ExprCast(ref from, _) => {
+ debug!("Checking const cast(id={})", from.id);
+ match v.tcx.cast_kinds.borrow().get(&from.id) {
+ None => v.tcx.sess.span_bug(e.span, "no kind for cast"),
+ Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0018,
+ "raw pointers cannot be cast to integers in {}s", v.msg());
+ }
+ }
+ _ => {}
+ }
+ }
+ hir::ExprPath(..) => {
+ let def = v.tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
+ match def {
+ Some(Def::Variant(..)) => {
+ // Count the discriminator or function pointer.
+ v.add_qualif(ConstQualif::NON_ZERO_SIZED);
+ }
+ Some(Def::Struct(..)) => {
+ if let ty::TyBareFn(..) = node_ty.sty {
+ // Count the function pointer.
+ v.add_qualif(ConstQualif::NON_ZERO_SIZED);
+ }
+ }
+ Some(Def::Fn(..)) | Some(Def::Method(..)) => {
+ // Count the function pointer.
+ v.add_qualif(ConstQualif::NON_ZERO_SIZED);
+ }
+ Some(Def::Static(..)) => {
+ match v.mode {
+ Mode::Static | Mode::StaticMut => {}
+ Mode::Const | Mode::ConstFn => {
+ span_err!(v.tcx.sess, e.span, E0013,
+ "{}s cannot refer to other statics, insert \
+ an intermediate constant instead", v.msg());
+ }
+ Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
+ }
+ }
+ Some(Def::Const(did)) |
+ Some(Def::AssociatedConst(did)) => {
+ if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
+ Some(e.id),
+ None) {
+ let inner = v.global_expr(Mode::Const, expr);
+ v.add_qualif(inner);
+ }
+ }
+ Some(Def::Local(..)) if v.mode == Mode::ConstFn => {
+ // Sadly, we can't determine whether the types are zero-sized.
+ v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
+ }
+ def => {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ debug!("(checking const) found bad def: {:?}", def);
+ span_err!(v.tcx.sess, e.span, E0014,
+ "paths in {}s may only refer to constants \
+ or functions", v.msg());
+ }
+ }
+ }
+ }
+ hir::ExprCall(ref callee, _) => {
+ let mut callee = &**callee;
+ loop {
+ callee = match callee.node {
+ hir::ExprBlock(ref block) => match block.expr {
+ Some(ref tail) => &**tail,
+ None => break
+ },
+ _ => break
+ };
+ }
+ let def = v.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def());
+ let is_const = match def {
+ Some(Def::Struct(..)) => true,
+ Some(Def::Variant(..)) => {
+ // Count the discriminator.
+ v.add_qualif(ConstQualif::NON_ZERO_SIZED);
+ true
+ }
+ Some(Def::Fn(did)) => {
+ v.handle_const_fn_call(e, did, node_ty)
+ }
+ Some(Def::Method(did)) => {
+ match v.tcx.impl_or_trait_item(did).container() {
+ ty::ImplContainer(_) => {
+ v.handle_const_fn_call(e, did, node_ty)
+ }
+ ty::TraitContainer(_) => false
+ }
+ }
+ _ => false
+ };
+ if !is_const {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ // FIXME(#24111) Remove this check when const fn stabilizes
+ let (msg, note) =
+ if let UnstableFeatures::Disallow = v.tcx.sess.opts.unstable_features {
+ (format!("function calls in {}s are limited to \
+ struct and enum constructors",
+ v.msg()),
+ Some("a limited form of compile-time function \
+ evaluation is available on a nightly \
+ compiler via `const fn`"))
+ } else {
+ (format!("function calls in {}s are limited \
+ to constant functions, \
+ struct and enum constructors",
+ v.msg()),
+ None)
+ };
+ let mut err = struct_span_err!(v.tcx.sess, e.span, E0015, "{}", msg);
+ if let Some(note) = note {
+ err.span_note(e.span, note);
+ }
+ err.emit();
+ }
+ }
+ }
+ hir::ExprMethodCall(..) => {
+ let method = v.tcx.tables.borrow().method_map[&method_call];
+ let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() {
+ ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
+ ty::TraitContainer(_) => false
+ };
+ if !is_const {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0378,
+ "method calls in {}s are limited to \
+ constant inherent methods", v.msg());
+ }
+ }
+ }
+ hir::ExprStruct(..) => {
+ let did = v.tcx.def_map.borrow().get(&e.id).map(|def| def.def_id());
+ if did == v.tcx.lang_items.unsafe_cell_type() {
+ v.add_qualif(ConstQualif::MUTABLE_MEM);
+ }
+ }
+
+ hir::ExprLit(_) |
+ hir::ExprAddrOf(..) => {
+ v.add_qualif(ConstQualif::NON_ZERO_SIZED);
+ }
+
+ hir::ExprRepeat(..) => {
+ v.add_qualif(ConstQualif::PREFER_IN_PLACE);
+ }
+
+ hir::ExprClosure(..) => {
+ // Paths in constant contexts cannot refer to local variables,
+ // as there are none, and thus closures can't have upvars there.
+ if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) {
+ assert!(v.mode == Mode::Var,
+ "global closures can't capture anything");
+ v.add_qualif(ConstQualif::NOT_CONST);
+ }
+ }
+
+ hir::ExprBlock(_) |
+ hir::ExprIndex(..) |
+ hir::ExprField(..) |
+ hir::ExprTupField(..) |
+ hir::ExprVec(_) |
+ hir::ExprType(..) |
+ hir::ExprTup(..) => {}
+
+ // Conditional control flow (possible to implement).
+ hir::ExprMatch(..) |
+ hir::ExprIf(..) |
+
+ // Loops (not very meaningful in constants).
+ hir::ExprWhile(..) |
+ hir::ExprLoop(..) |
+
+ // More control flow (also not very meaningful).
+ hir::ExprBreak(_) |
+ hir::ExprAgain(_) |
+ hir::ExprRet(_) |
+
+ // Miscellaneous expressions that could be implemented.
+ hir::ExprRange(..) |
+
+ // Expressions with side-effects.
+ hir::ExprAssign(..) |
+ hir::ExprAssignOp(..) |
+ hir::ExprInlineAsm(_) => {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0019,
+ "{} contains unimplemented expression type", v.msg());
+ }
+ }
+ }
+}
+
+/// Check the adjustments of an expression
+fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
+ match v.tcx.tables.borrow().adjustments.get(&e.id) {
+ None |
+ Some(&ty::adjustment::AdjustReifyFnPointer) |
+ Some(&ty::adjustment::AdjustUnsafeFnPointer) => {}
+
+ Some(&ty::adjustment::AdjustDerefRef(
+ ty::adjustment::AutoDerefRef { autoderefs, .. }
+ )) => {
+ if (0..autoderefs as u32).any(|autoderef| {
+ v.tcx.is_overloaded_autoderef(e.id, autoderef)
+ }) {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0400,
+ "user-defined dereference operators are not allowed in {}s",
+ v.msg());
+ }
+ }
+ }
+ }
+}
+
+pub fn check_crate(tcx: &ty::ctxt) {
+ tcx.visit_all_items_in_krate(DepNode::CheckConst, &mut CheckCrateVisitor {
+ tcx: tcx,
+ mode: Mode::Var,
+ qualif: ConstQualif::NOT_CONST,
+ rvalue_borrows: NodeMap()
+ });
+ tcx.sess.abort_if_errors();
+}
+
+impl<'a, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'tcx> {
+ fn consume(&mut self,
+ _consume_id: ast::NodeId,
+ consume_span: Span,
+ cmt: mc::cmt,
+ _mode: euv::ConsumeMode) {
+ let mut cur = &cmt;
+ loop {
+ match cur.cat {
+ Categorization::StaticItem => {
+ if self.mode != Mode::Var {
+ // statics cannot be consumed by value at any time, that would imply
+ // that they're an initializer (what a const is for) or kept in sync
+ // over time (not feasible), so deny it outright.
+ span_err!(self.tcx.sess, consume_span, E0394,
+ "cannot refer to other statics by value, use the \
+ address-of operator or a constant instead");
+ }
+ break;
+ }
+ Categorization::Deref(ref cmt, _, _) |
+ Categorization::Downcast(ref cmt, _) |
+ Categorization::Interior(ref cmt, _) => cur = cmt,
+
+ Categorization::Rvalue(..) |
+ Categorization::Upvar(..) |
+ Categorization::Local(..) => break
+ }
+ }
+ }
+ fn borrow(&mut self,
+ borrow_id: ast::NodeId,
+ borrow_span: Span,
+ cmt: mc::cmt<'tcx>,
+ _loan_region: ty::Region,
+ bk: ty::BorrowKind,
+ loan_cause: euv::LoanCause)
+ {
+ // Kind of hacky, but we allow Unsafe coercions in constants.
+ // These occur when we convert a &T or *T to a *U, as well as
+ // when making a thin pointer (e.g., `*T`) into a fat pointer
+ // (e.g., `*Trait`).
+ match loan_cause {
+ euv::LoanCause::AutoUnsafe => {
+ return;
+ }
+ _ => { }
+ }
+
+ let mut cur = &cmt;
+ let mut is_interior = false;
+ loop {
+ match cur.cat {
+ Categorization::Rvalue(..) => {
+ if loan_cause == euv::MatchDiscriminant {
+ // Ignore the dummy immutable borrow created by EUV.
+ break;
+ }
+ let mutbl = bk.to_mutbl_lossy();
+ if mutbl == hir::MutMutable && self.mode == Mode::StaticMut {
+ // Mutable slices are the only `&mut` allowed in
+ // globals, but only in `static mut`, nowhere else.
+ // FIXME: This exception is really weird... there isn't
+ // any fundamental reason to restrict this based on
+ // type of the expression. `&mut [1]` has exactly the
+ // same representation as &mut 1.
+ match cmt.ty.sty {
+ ty::TyArray(_, _) | ty::TySlice(_) => break,
+ _ => {}
+ }
+ }
+ self.record_borrow(borrow_id, mutbl);
+ break;
+ }
+ Categorization::StaticItem => {
+ if is_interior && self.mode != Mode::Var {
+ // Borrowed statics can specifically *only* have their address taken,
+ // not any number of other borrows such as borrowing fields, reading
+ // elements of an array, etc.
+ span_err!(self.tcx.sess, borrow_span, E0494,
+ "cannot refer to the interior of another \
+ static, use a constant instead");
+ }
+ break;
+ }
+ Categorization::Deref(ref cmt, _, _) |
+ Categorization::Downcast(ref cmt, _) |
+ Categorization::Interior(ref cmt, _) => {
+ is_interior = true;
+ cur = cmt;
+ }
+
+ Categorization::Upvar(..) |
+ Categorization::Local(..) => break
+ }
+ }
+ }
+
+ fn decl_without_init(&mut self,
+ _id: ast::NodeId,
+ _span: Span) {}
+ fn mutate(&mut self,
+ _assignment_id: ast::NodeId,
+ _assignment_span: Span,
+ _assignee_cmt: mc::cmt,
+ _mode: euv::MutateMode) {}
+
+ fn matched_pat(&mut self,
+ _: &hir::Pat,
+ _: mc::cmt,
+ _: euv::MatchMode) {}
+
+ fn consume_pat(&mut self,
+ _consume_pat: &hir::Pat,
+ _cmt: mc::cmt,
+ _mode: euv::ConsumeMode) {}
+}
#![allow(non_snake_case)]
register_long_diagnostics! {
+
+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
+the heap at runtime, and therefore cannot be done at compile time. Erroneous
+code example:
+
+```
+#![feature(box_syntax)]
+
+const CON : Box<i32> = box 0;
+```
+"##,
+
+E0011: r##"
+Initializers for constants and statics are evaluated at compile time.
+User-defined operators rely on user-defined functions, which cannot be evaluated
+at compile time.
+
+Bad example:
+
+```
+use std::ops::Index;
+
+struct Foo { a: u8 }
+
+impl Index<u8> for Foo {
+ type Output = u8;
+
+ fn index<'a>(&'a self, idx: u8) -> &'a u8 { &self.a }
+}
+
+const a: Foo = Foo { a: 0u8 };
+const b: u8 = a[0]; // Index trait is defined by the user, bad!
+```
+
+Only operators on builtin types are allowed.
+
+Example:
+
+```
+const a: &'static [i32] = &[1, 2, 3];
+const b: i32 = a[0]; // Good!
+```
+"##,
+
+E0013: r##"
+Static and const variables can refer to other const variables. But a const
+variable cannot refer to a static variable. For example, `Y` cannot refer to `X`
+here:
+
+```
+static X: i32 = 42;
+const Y: i32 = X;
+```
+
+To fix this, the value can be extracted as a const and then used:
+
+```
+const A: i32 = 42;
+static X: i32 = A;
+const Y: i32 = A;
+```
+"##,
+
+E0014: r##"
+Constants can only be initialized by a constant value or, in a future
+version of Rust, a call to a const function. This error indicates the use
+of a path (like a::b, or x) denoting something other than one of these
+allowed items. Example:
+
+```
+const FOO: i32 = { let x = 0; x }; // 'x' isn't a constant nor a function!
+```
+
+To avoid it, you have to replace the non-constant value:
+
+```
+const FOO: i32 = { const X : i32 = 0; X };
+// or even:
+const FOO: i32 = { 0 }; // but brackets are useless here
+```
+"##,
+
+// FIXME(#24111) Change the language here when const fn stabilizes
+E0015: r##"
+The only functions that can be called in static or constant expressions are
+`const` functions, and struct/enum constructors. `const` functions are only
+available on a nightly compiler. Rust currently does not support more general
+compile-time function execution.
+
+```
+const FOO: Option<u8> = Some(1); // enum constructor
+struct Bar {x: u8}
+const BAR: Bar = Bar {x: 1}; // struct constructor
+```
+
+See [RFC 911] for more details on the design of `const fn`s.
+
+[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
+"##,
+
E0016: r##"
Blocks in constants may only contain items (such as constant, function
definition, etc...) and a tail expression. Example:
```
"##,
+E0017: r##"
+References in statics and constants may only refer to immutable values. Example:
+
+```
+static X: i32 = 1;
+const C: i32 = 2;
+
+// these three are not allowed:
+const CR: &'static mut i32 = &mut C;
+static STATIC_REF: &'static mut i32 = &mut X;
+static CONST_REF: &'static mut i32 = &mut C;
+```
+
+Statics are shared everywhere, and if they refer to mutable data one might
+violate memory safety since holding multiple mutable references to shared data
+is not allowed.
+
+If you really want global mutable state, try using `static mut` or a global
+`UnsafeCell`.
+"##,
+
+E0018: r##"
+The value of static and const variables must be known at compile time. You
+can't cast a pointer as an integer because we can't know what value the
+address will take.
+
+However, pointers to other constants' addresses are allowed in constants,
+example:
+
+```
+const X: u32 = 50;
+const Y: *const u32 = &X;
+```
+
+Therefore, casting one of these non-constant pointers to an integer results
+in a non-constant integer which lead to this error. Example:
+
+```
+const X: u32 = 1;
+const Y: usize = &X as *const u32 as usize;
+println!("{}", Y);
+```
+"##,
+
+E0019: r##"
+A function call isn't allowed in the const's initialization expression
+because the expression's value must be known at compile-time. Example of
+erroneous code:
+
+```
+enum Test {
+ V1
+}
+
+impl Test {
+ fn test(&self) -> i32 {
+ 12
+ }
+}
+
+fn main() {
+ const FOO: Test = Test::V1;
+
+ const A: i32 = FOO.test(); // You can't call Test::func() here !
+}
+```
+
+Remember: you can't use a function call inside a const's initialization
+expression! However, you can totally use it anywhere else:
+
+```
+fn main() {
+ const FOO: Test = Test::V1;
+
+ FOO.func(); // here is good
+ let x = FOO.func(); // or even here!
+}
+```
+"##,
+
E0022: r##"
Constant functions are not allowed to mutate anything. Thus, binding to an
argument with a mutable pattern is not allowed. For example,
instead of using a `const fn`, or refactoring the code to a functional style to
avoid mutation if possible.
"##,
+
+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:
+
+```
+match 5u32 {
+ // This range is ok, albeit pointless.
+ 1 ... 1 => ...
+ // This range is empty, and the compiler can tell.
+ 1000 ... 5 => ...
+}
+```
+"##,
+
+E0161: r##"
+In Rust, you can only move a value when its size is known at compile time.
+
+To work around this restriction, consider "hiding" the value behind a reference:
+either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
+it around as usual.
+"##,
+
+E0265: r##"
+This error indicates that a static or constant references itself.
+All statics and constants need to resolve to a value in an acyclic manner.
+
+For example, neither of the following can be sensibly compiled:
+
+```
+const X: u32 = X;
+```
+
+```
+const X: u32 = Y;
+const Y: u32 = X;
+```
+"##,
+
+E0267: r##"
+This error indicates the use of a loop keyword (`break` or `continue`) inside a
+closure but outside of any loop. Erroneous code example:
+
+```
+let w = || { break; }; // error: `break` inside of a closure
+```
+
+`break` and `continue` keywords can be used as normal inside closures as long as
+they are also contained within a loop. To halt the execution of a closure you
+should instead use a return statement. Example:
+
+```
+let w = || {
+ for _ in 0..10 {
+ break;
+ }
+};
+
+w();
+```
+"##,
+
+E0268: r##"
+This error indicates the use of a loop keyword (`break` or `continue`) outside
+of a loop. Without a loop to break out of or continue in, no sensible action can
+be taken. Erroneous code example:
+
+```
+fn some_func() {
+ break; // error: `break` outside of loop
+}
+```
+
+Please verify that you are using `break` and `continue` only in loops. Example:
+
+```
+fn some_func() {
+ for _ in 0..10 {
+ break; // ok!
+ }
+}
+```
+"##,
+
+E0378: r##"
+Method calls that aren't calls to inherent `const` methods are disallowed
+in statics, constants, and constant functions.
+
+For example:
+
+```
+const BAZ: i32 = Foo(25).bar(); // error, `bar` isn't `const`
+
+struct Foo(i32);
+
+impl Foo {
+ const fn foo(&self) -> i32 {
+ self.bar() // error, `bar` isn't `const`
+ }
+
+ fn bar(&self) -> i32 { self.0 }
+}
+```
+
+For more information about `const fn`'s, see [RFC 911].
+
+[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
+"##,
+
+E0394: r##"
+From [RFC 246]:
+
+ > It is invalid for a static to reference another static by value. It is
+ > required that all references be borrowed.
+
+[RFC 246]: https://github.com/rust-lang/rfcs/pull/246
+"##,
+
+E0395: r##"
+The value assigned to a constant expression must be known at compile time,
+which is not the case when comparing raw pointers. Erroneous code example:
+
+```
+static foo: i32 = 42;
+static bar: i32 = 43;
+
+static baz: bool = { (&foo as *const i32) == (&bar as *const i32) };
+// error: raw pointers cannot be compared in statics!
+```
+
+Please check that the result of the comparison can be determined at compile time
+or isn't assigned to a constant expression. Example:
+
+```
+static foo: i32 = 42;
+static bar: i32 = 43;
+
+let baz: bool = { (&foo as *const i32) == (&bar as *const i32) };
+// baz isn't a constant expression so it's ok
+```
+"##,
+
+E0396: r##"
+The value assigned to a constant expression must be known at compile time,
+which is not the case when dereferencing raw pointers. Erroneous code
+example:
+
+```
+const foo: i32 = 42;
+const baz: *const i32 = (&foo as *const i32);
+
+const deref: i32 = *baz;
+// error: raw pointers cannot be dereferenced in constants
+```
+
+To fix this error, please do not assign this value to a constant expression.
+Example:
+
+```
+const foo: i32 = 42;
+const baz: *const i32 = (&foo as *const i32);
+
+unsafe { let deref: i32 = *baz; }
+// baz isn't a constant expression so it's ok
+```
+
+You'll also note that this assignment must be done in an unsafe block!
+"##,
+
+E0397: r##"
+It is not allowed for a mutable static to allocate or have destructors. For
+example:
+
+```
+// error: mutable statics are not allowed to have boxes
+static mut FOO: Option<Box<usize>> = None;
+
+// error: mutable statics are not allowed to have destructors
+static mut BAR: Option<Vec<i32>> = None;
+```
+"##,
+
+E0400: r##"
+A user-defined dereference was attempted in an invalid context. Erroneous
+code example:
+
+```
+use std::ops::Deref;
+
+struct A;
+
+impl Deref for A {
+ type Target = str;
+
+ fn deref(&self)-> &str { "foo" }
+}
+
+const S: &'static str = &A;
+// error: user-defined dereference operators are not allowed in constants
+
+fn main() {
+ let foo = S;
+}
+```
+
+You cannot directly use a dereference operation whilst initializing a constant
+or a static. To fix this error, restructure your code to avoid this dereference,
+perhaps moving it inline:
+
+```
+use std::ops::Deref;
+
+struct A;
+
+impl Deref for A {
+ type Target = str;
+
+ fn deref(&self)-> &str { "foo" }
+}
+
+fn main() {
+ let foo : &str = &A;
+}
+```
+"##,
+
+E0492: r##"
+A borrow of a constant containing interior mutability was attempted. Erroneous
+code example:
+
+```
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
+
+const A: AtomicUsize = ATOMIC_USIZE_INIT;
+static B: &'static AtomicUsize = &A;
+// error: cannot borrow a constant which contains interior mutability, create a
+// static instead
+```
+
+A `const` represents a constant value that should never change. If one takes
+a `&` reference to the constant, then one is taking a pointer to some memory
+location containing the value. Normally this is perfectly fine: most values
+can't be changed via a shared `&` pointer, but interior mutability would allow
+it. That is, a constant value could be mutated. On the other hand, a `static` is
+explicitly a single memory location, which can be mutated at will.
+
+So, in order to solve this error, either use statics which are `Sync`:
+
+```
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
+
+static A: AtomicUsize = ATOMIC_USIZE_INIT;
+static B: &'static AtomicUsize = &A; // ok!
+```
+
+You can also have this error while using a cell type:
+
+```
+#![feature(const_fn)]
+
+use std::cell::Cell;
+
+const A: Cell<usize> = Cell::new(1);
+const B: &'static Cell<usize> = &A;
+// error: cannot borrow a constant which contains interior mutability, create
+// a static instead
+
+// or:
+struct C { a: Cell<usize> }
+
+const D: C = C { a: Cell::new(1) };
+const E: &'static Cell<usize> = &D.a; // error
+
+// or:
+const F: &'static C = &D; // error
+```
+
+This is because cell types do operations that are not thread-safe. Due to this,
+they don't implement Sync and thus can't be placed in statics. In this
+case, `StaticMutex` would work just fine, but it isn't stable yet:
+https://doc.rust-lang.org/nightly/std/sync/struct.StaticMutex.html
+
+However, if you still wish to use these types, you can achieve this by an unsafe
+wrapper:
+
+```
+#![feature(const_fn)]
+
+use std::cell::Cell;
+use std::marker::Sync;
+
+struct NotThreadSafe<T> {
+ value: Cell<T>,
+}
+
+unsafe impl<T> Sync for NotThreadSafe<T> {}
+
+static A: NotThreadSafe<usize> = NotThreadSafe { value : Cell::new(1) };
+static B: &'static NotThreadSafe<usize> = &A; // ok!
+```
+
+Remember this solution is unsafe! You will have to ensure that accesses to the
+cell are synchronized.
+"##,
+
+E0493: r##"
+A type with a destructor was assigned to an invalid type of variable. Erroneous
+code example:
+
+```
+struct Foo {
+ a: u32
+}
+
+impl Drop for Foo {
+ fn drop(&mut self) {}
+}
+
+const F : Foo = Foo { a : 0 };
+// error: constants are not allowed to have destructors
+static S : Foo = Foo { a : 0 };
+// error: statics are not allowed to have destructors
+```
+
+To solve this issue, please use a type which does allow the usage of type with
+destructors.
+"##,
+
+E0494: r##"
+A reference of an interior static was assigned to another const/static.
+Erroneous code example:
+
+```
+struct Foo {
+ a: u32
+}
+
+static S : Foo = Foo { a : 0 };
+static A : &'static u32 = &S.a;
+// error: cannot refer to the interior of another static, use a
+// constant instead
+```
+
+The "base" variable has to be a const if you want another static/const variable
+to refer to one of its fields. Example:
+
+```
+struct Foo {
+ a: u32
+}
+
+const S : Foo = Foo { a : 0 };
+static A : &'static u32 = &S.a; // ok!
+```
+"##,
+
}
register_diagnostics! {
extern crate core;
extern crate rustc;
+extern crate rustc_front;
+#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
pub mod diagnostics;
+
pub mod const_fn;
+pub mod consts;
+pub mod loops;
pub mod no_asm;
+pub mod rvalues;
+pub mod static_recursion;
--- /dev/null
+// Copyright 2012-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.
+use self::Context::*;
+
+use rustc::session::Session;
+
+use syntax::codemap::Span;
+use rustc_front::intravisit::{self, Visitor};
+use rustc_front::hir;
+
+#[derive(Clone, Copy, PartialEq)]
+enum Context {
+ Normal, Loop, Closure
+}
+
+#[derive(Copy, Clone)]
+struct CheckLoopVisitor<'a> {
+ sess: &'a Session,
+ cx: Context
+}
+
+pub fn check_crate(sess: &Session, krate: &hir::Crate) {
+ krate.visit_all_items(&mut CheckLoopVisitor { sess: sess, cx: Normal });
+}
+
+impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
+ fn visit_item(&mut self, i: &hir::Item) {
+ self.with_context(Normal, |v| intravisit::walk_item(v, i));
+ }
+
+ fn visit_expr(&mut self, e: &hir::Expr) {
+ match e.node {
+ hir::ExprWhile(ref e, ref b, _) => {
+ self.visit_expr(&**e);
+ self.with_context(Loop, |v| v.visit_block(&**b));
+ }
+ hir::ExprLoop(ref b, _) => {
+ self.with_context(Loop, |v| v.visit_block(&**b));
+ }
+ hir::ExprClosure(_, _, ref b) => {
+ self.with_context(Closure, |v| v.visit_block(&**b));
+ }
+ hir::ExprBreak(_) => self.require_loop("break", e.span),
+ hir::ExprAgain(_) => self.require_loop("continue", e.span),
+ _ => intravisit::walk_expr(self, e)
+ }
+ }
+}
+
+impl<'a> CheckLoopVisitor<'a> {
+ fn with_context<F>(&mut self, cx: Context, f: F) where
+ F: FnOnce(&mut CheckLoopVisitor<'a>),
+ {
+ let old_cx = self.cx;
+ self.cx = cx;
+ f(self);
+ self.cx = old_cx;
+ }
+
+ fn require_loop(&self, name: &str, span: Span) {
+ match self.cx {
+ Loop => {}
+ Closure => {
+ span_err!(self.sess, span, E0267,
+ "`{}` inside of a closure", name);
+ }
+ Normal => {
+ span_err!(self.sess, span, E0268,
+ "`{}` outside of loop", name);
+ }
+ }
+ }
+}
--- /dev/null
+// 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.
+
+// Checks that all rvalues in a crate have statically known size. check_crate
+// is the public starting point.
+
+use rustc::dep_graph::DepNode;
+use rustc::middle::expr_use_visitor as euv;
+use rustc::middle::infer;
+use rustc::middle::mem_categorization as mc;
+use rustc::middle::ty::{self, ParameterEnvironment};
+
+use rustc_front::hir;
+use rustc_front::intravisit;
+use syntax::ast;
+use syntax::codemap::Span;
+
+pub fn check_crate(tcx: &ty::ctxt) {
+ let mut rvcx = RvalueContext { tcx: tcx };
+ tcx.visit_all_items_in_krate(DepNode::RvalueCheck, &mut rvcx);
+}
+
+struct RvalueContext<'a, 'tcx: 'a> {
+ tcx: &'a ty::ctxt<'tcx>,
+}
+
+impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
+ fn visit_fn(&mut self,
+ fk: intravisit::FnKind<'v>,
+ fd: &'v hir::FnDecl,
+ b: &'v hir::Block,
+ s: Span,
+ fn_id: ast::NodeId) {
+ {
+ // FIXME (@jroesch) change this to be an inference context
+ let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
+ let infcx = infer::new_infer_ctxt(self.tcx,
+ &self.tcx.tables,
+ Some(param_env.clone()));
+ let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: ¶m_env };
+ let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
+ euv.walk_fn(fd, b);
+ }
+ intravisit::walk_fn(self, fk, fd, b, s)
+ }
+}
+
+struct RvalueContextDelegate<'a, 'tcx: 'a> {
+ tcx: &'a ty::ctxt<'tcx>,
+ param_env: &'a ty::ParameterEnvironment<'a,'tcx>,
+}
+
+impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
+ fn consume(&mut self,
+ _: ast::NodeId,
+ span: Span,
+ cmt: mc::cmt<'tcx>,
+ _: euv::ConsumeMode) {
+ debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty);
+ if !cmt.ty.is_sized(self.param_env, span) {
+ span_err!(self.tcx.sess, span, E0161,
+ "cannot move a value of type {0}: the size of {0} cannot be statically determined",
+ cmt.ty);
+ }
+ }
+
+ fn matched_pat(&mut self,
+ _matched_pat: &hir::Pat,
+ _cmt: mc::cmt,
+ _mode: euv::MatchMode) {}
+
+ fn consume_pat(&mut self,
+ _consume_pat: &hir::Pat,
+ _cmt: mc::cmt,
+ _mode: euv::ConsumeMode) {
+ }
+
+ fn borrow(&mut self,
+ _borrow_id: ast::NodeId,
+ _borrow_span: Span,
+ _cmt: mc::cmt,
+ _loan_region: ty::Region,
+ _bk: ty::BorrowKind,
+ _loan_cause: euv::LoanCause) {
+ }
+
+ fn decl_without_init(&mut self,
+ _id: ast::NodeId,
+ _span: Span) {
+ }
+
+ fn mutate(&mut self,
+ _assignment_id: ast::NodeId,
+ _assignment_span: Span,
+ _assignee_cmt: mc::cmt,
+ _mode: euv::MutateMode) {
+ }
+}
--- /dev/null
+// 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.
+
+// This compiler pass detects constants that refer to themselves
+// recursively.
+
+use rustc::front::map as ast_map;
+use rustc::session::Session;
+use rustc::middle::def::{Def, DefMap};
+use rustc::util::nodemap::NodeMap;
+
+use syntax::{ast};
+use syntax::codemap::Span;
+use syntax::feature_gate::{GateIssue, emit_feature_err};
+use rustc_front::intravisit::{self, Visitor};
+use rustc_front::hir;
+
+use std::cell::RefCell;
+
+struct CheckCrateVisitor<'a, 'ast: 'a> {
+ sess: &'a Session,
+ def_map: &'a DefMap,
+ ast_map: &'a ast_map::Map<'ast>,
+ // `discriminant_map` is a cache that associates the `NodeId`s of local
+ // variant definitions with the discriminant expression that applies to
+ // each one. If the variant uses the default values (starting from `0`),
+ // then `None` is stored.
+ discriminant_map: RefCell<NodeMap<Option<&'ast hir::Expr>>>,
+}
+
+impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
+ fn visit_item(&mut self, it: &'ast hir::Item) {
+ match it.node {
+ hir::ItemStatic(..) |
+ hir::ItemConst(..) => {
+ let mut recursion_visitor =
+ CheckItemRecursionVisitor::new(self, &it.span);
+ recursion_visitor.visit_item(it);
+ },
+ hir::ItemEnum(ref enum_def, ref generics) => {
+ // We could process the whole enum, but handling the variants
+ // with discriminant expressions one by one gives more specific,
+ // less redundant output.
+ for variant in &enum_def.variants {
+ if let Some(_) = variant.node.disr_expr {
+ let mut recursion_visitor =
+ CheckItemRecursionVisitor::new(self, &variant.span);
+ recursion_visitor.populate_enum_discriminants(enum_def);
+ recursion_visitor.visit_variant(variant, generics, it.id);
+ }
+ }
+ }
+ _ => {}
+ }
+ intravisit::walk_item(self, it)
+ }
+
+ fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
+ match ti.node {
+ hir::ConstTraitItem(_, ref default) => {
+ if let Some(_) = *default {
+ let mut recursion_visitor =
+ CheckItemRecursionVisitor::new(self, &ti.span);
+ recursion_visitor.visit_trait_item(ti);
+ }
+ }
+ _ => {}
+ }
+ intravisit::walk_trait_item(self, ti)
+ }
+
+ fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
+ match ii.node {
+ hir::ImplItemKind::Const(..) => {
+ let mut recursion_visitor =
+ CheckItemRecursionVisitor::new(self, &ii.span);
+ recursion_visitor.visit_impl_item(ii);
+ }
+ _ => {}
+ }
+ intravisit::walk_impl_item(self, ii)
+ }
+}
+
+pub fn check_crate<'ast>(sess: &Session,
+ krate: &'ast hir::Crate,
+ def_map: &DefMap,
+ ast_map: &ast_map::Map<'ast>) {
+ let mut visitor = CheckCrateVisitor {
+ sess: sess,
+ def_map: def_map,
+ ast_map: ast_map,
+ discriminant_map: RefCell::new(NodeMap()),
+ };
+ sess.abort_if_new_errors(|| {
+ krate.visit_all_items(&mut visitor);
+ });
+}
+
+struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
+ root_span: &'a Span,
+ sess: &'a Session,
+ ast_map: &'a ast_map::Map<'ast>,
+ def_map: &'a DefMap,
+ discriminant_map: &'a RefCell<NodeMap<Option<&'ast hir::Expr>>>,
+ idstack: Vec<ast::NodeId>,
+}
+
+impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
+ fn new(v: &'a CheckCrateVisitor<'a, 'ast>, span: &'a Span)
+ -> CheckItemRecursionVisitor<'a, 'ast> {
+ CheckItemRecursionVisitor {
+ root_span: span,
+ sess: v.sess,
+ ast_map: v.ast_map,
+ def_map: v.def_map,
+ discriminant_map: &v.discriminant_map,
+ idstack: Vec::new(),
+ }
+ }
+ fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F)
+ where F: Fn(&mut Self) {
+ if self.idstack.iter().any(|&x| x == id) {
+ let any_static = self.idstack.iter().any(|&x| {
+ if let ast_map::NodeItem(item) = self.ast_map.get(x) {
+ if let hir::ItemStatic(..) = item.node {
+ true
+ } else {
+ false
+ }
+ } else {
+ false
+ }
+ });
+ if any_static {
+ if !self.sess.features.borrow().static_recursion {
+ emit_feature_err(&self.sess.parse_sess.span_diagnostic,
+ "static_recursion",
+ *self.root_span, GateIssue::Language, "recursive static");
+ }
+ } else {
+ span_err!(self.sess, *self.root_span, E0265, "recursive constant");
+ }
+ return;
+ }
+ self.idstack.push(id);
+ f(self);
+ self.idstack.pop();
+ }
+ // If a variant has an expression specifying its discriminant, then it needs
+ // to be checked just like a static or constant. However, if there are more
+ // variants with no explicitly specified discriminant, those variants will
+ // increment the same expression to get their values.
+ //
+ // So for every variant, we need to track whether there is an expression
+ // somewhere in the enum definition that controls its discriminant. We do
+ // this by starting from the end and searching backward.
+ fn populate_enum_discriminants(&self, enum_definition: &'ast hir::EnumDef) {
+ // Get the map, and return if we already processed this enum or if it
+ // has no variants.
+ let mut discriminant_map = self.discriminant_map.borrow_mut();
+ match enum_definition.variants.first() {
+ None => { return; }
+ Some(variant) if discriminant_map.contains_key(&variant.node.data.id()) => {
+ return;
+ }
+ _ => {}
+ }
+
+ // Go through all the variants.
+ let mut variant_stack: Vec<ast::NodeId> = Vec::new();
+ for variant in enum_definition.variants.iter().rev() {
+ variant_stack.push(variant.node.data.id());
+ // When we find an expression, every variant currently on the stack
+ // is affected by that expression.
+ if let Some(ref expr) = variant.node.disr_expr {
+ for id in &variant_stack {
+ discriminant_map.insert(*id, Some(expr));
+ }
+ variant_stack.clear()
+ }
+ }
+ // If we are at the top, that always starts at 0, so any variant on the
+ // stack has a default value and does not need to be checked.
+ for id in &variant_stack {
+ discriminant_map.insert(*id, None);
+ }
+ }
+}
+
+impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
+ fn visit_item(&mut self, it: &'ast hir::Item) {
+ self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it));
+ }
+
+ fn visit_enum_def(&mut self, enum_definition: &'ast hir::EnumDef,
+ generics: &'ast hir::Generics, item_id: ast::NodeId, _: Span) {
+ self.populate_enum_discriminants(enum_definition);
+ intravisit::walk_enum_def(self, enum_definition, generics, item_id);
+ }
+
+ fn visit_variant(&mut self, variant: &'ast hir::Variant,
+ _: &'ast hir::Generics, _: ast::NodeId) {
+ let variant_id = variant.node.data.id();
+ let maybe_expr;
+ if let Some(get_expr) = self.discriminant_map.borrow().get(&variant_id) {
+ // This is necessary because we need to let the `discriminant_map`
+ // borrow fall out of scope, so that we can reborrow farther down.
+ maybe_expr = (*get_expr).clone();
+ } else {
+ self.sess.span_bug(variant.span,
+ "`check_static_recursion` attempted to visit \
+ variant with unknown discriminant")
+ }
+ // If `maybe_expr` is `None`, that's because no discriminant is
+ // specified that affects this variant. Thus, no risk of recursion.
+ if let Some(expr) = maybe_expr {
+ self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr));
+ }
+ }
+
+ fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
+ self.with_item_id_pushed(ti.id, |v| intravisit::walk_trait_item(v, ti));
+ }
+
+ fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
+ self.with_item_id_pushed(ii.id, |v| intravisit::walk_impl_item(v, ii));
+ }
+
+ fn visit_expr(&mut self, e: &'ast hir::Expr) {
+ match e.node {
+ hir::ExprPath(..) => {
+ match self.def_map.get(&e.id).map(|d| d.base_def) {
+ Some(Def::Static(def_id, _)) |
+ Some(Def::AssociatedConst(def_id)) |
+ Some(Def::Const(def_id)) => {
+ if let Some(node_id) = self.ast_map.as_local_node_id(def_id) {
+ match self.ast_map.get(node_id) {
+ ast_map::NodeItem(item) =>
+ self.visit_item(item),
+ ast_map::NodeTraitItem(item) =>
+ self.visit_trait_item(item),
+ ast_map::NodeImplItem(item) =>
+ self.visit_impl_item(item),
+ ast_map::NodeForeignItem(_) => {},
+ _ => {
+ self.sess.span_bug(
+ e.span,
+ &format!("expected item, found {}",
+ self.ast_map.node_to_string(node_id)));
+ }
+ }
+ }
+ }
+ // For variants, we only want to check expressions that
+ // affect the specific variant used, but we need to check
+ // the whole enum definition to see what expression that
+ // might be (if any).
+ Some(Def::Variant(enum_id, variant_id)) => {
+ if let Some(enum_node_id) = self.ast_map.as_local_node_id(enum_id) {
+ if let hir::ItemEnum(ref enum_def, ref generics) =
+ self.ast_map.expect_item(enum_node_id).node
+ {
+ self.populate_enum_discriminants(enum_def);
+ let enum_id = self.ast_map.as_local_node_id(enum_id).unwrap();
+ let variant_id = self.ast_map.as_local_node_id(variant_id).unwrap();
+ let variant = self.ast_map.expect_variant(variant_id);
+ self.visit_variant(variant, generics, enum_id);
+ } else {
+ self.sess.span_bug(e.span,
+ "`check_static_recursion` found \
+ non-enum in Def::Variant");
+ }
+ }
+ }
+ _ => ()
+ }
+ },
+ _ => ()
+ }
+ intravisit::walk_expr(self, e);
+ }
+}
use rustc::dep_graph::DepNode;
use rustc::lint;
-use rustc::middle::def;
+use rustc::middle::def::{self, Def};
use rustc::middle::def_id::DefId;
use rustc::middle::privacy::{AccessLevel, AccessLevels};
use rustc::middle::privacy::ImportUse::*;
fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
if let hir::TyPath(..) = ty.node {
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
- def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {
+ Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
Some(AccessLevel::Public)
}
def => {
hir::ItemTy(ref ty, _) if item_level.is_some() => {
if let hir::TyPath(..) = ty.node {
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
- def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {},
+ Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {},
def => {
if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
self.update(node_id, Some(AccessLevel::Reachable));
// be accurate and we can get slightly wonky error messages (but type
// checking is always correct).
match path_res.full_def() {
- def::DefFn(..) => ck("function"),
- def::DefStatic(..) => ck("static"),
- def::DefConst(..) => ck("const"),
- def::DefAssociatedConst(..) => ck("associated const"),
- def::DefVariant(..) => ck("variant"),
- def::DefTy(_, false) => ck("type"),
- def::DefTy(_, true) => ck("enum"),
- def::DefTrait(..) => ck("trait"),
- def::DefStruct(..) => ck("struct"),
- def::DefMethod(..) => ck("method"),
- def::DefMod(..) => ck("module"),
+ Def::Fn(..) => ck("function"),
+ Def::Static(..) => ck("static"),
+ Def::Const(..) => ck("const"),
+ Def::AssociatedConst(..) => ck("associated const"),
+ Def::Variant(..) => ck("variant"),
+ Def::TyAlias(..) => ck("type"),
+ Def::Enum(..) => ck("enum"),
+ Def::Trait(..) => ck("trait"),
+ Def::Struct(..) => ck("struct"),
+ Def::Method(..) => ck("method"),
+ Def::Mod(..) => ck("module"),
_ => {}
}
}
}
hir::ExprPath(..) => {
- if let def::DefStruct(_) = self.tcx.resolve_expr(expr) {
+ if let Def::Struct(..) = self.tcx.resolve_expr(expr) {
let expr_ty = self.tcx.expr_ty(expr);
let def = match expr_ty.sty {
ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
fn path_is_private_type(&self, path_id: ast::NodeId) -> bool {
let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) {
// `int` etc. (None doesn't seem to occur.)
- None | Some(def::DefPrimTy(..)) | Some(def::DefSelfTy(..)) => return false,
+ None | Some(Def::PrimTy(..)) | Some(Def::SelfTy(..)) => return false,
Some(def) => def.def_id(),
};
if let hir::TyPath(_, ref path) = ty.node {
let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
match def {
- def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {
+ Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
// Public
}
- def::DefAssociatedTy(..) if self.is_quiet => {
+ Def::AssociatedTy(..) if self.is_quiet => {
// Conservatively approximate the whole type alias as public without
// recursing into its components when determining impl publicity.
// For example, `impl <Type as Trait>::Alias {...}` may be a public impl
// free type aliases, but this isn't done yet.
return
}
- def::DefStruct(def_id) | def::DefTy(def_id, _) |
- def::DefTrait(def_id) | def::DefAssociatedTy(def_id, _) => {
+ Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
+ Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
// Non-local means public (private items can't leave their crate, modulo bugs)
if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
let item = self.tcx.map.expect_item(node_id);
use rustc::middle::cstore::{CrateStore, ChildItem, DlDef, DlField, DlImpl};
use rustc::middle::def::*;
use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::middle::ty::VariantKind;
use syntax::ast::{Name, NodeId};
use syntax::attr::AttrMetaMethods;
};
self.external_exports.insert(def_id);
let parent_link = ModuleParentLink(parent, name);
- let def = DefMod(def_id);
+ let def = Def::Mod(def_id);
let external_module = self.new_module(parent_link, Some(def), false, true);
debug!("(build reduced graph for item) found extern `{}`",
let name_bindings = self.add_child(name, parent, ForbidDuplicateTypes, sp);
let parent_link = ModuleParentLink(parent, name);
- let def = DefMod(self.ast_map.local_def_id(item.id));
+ let def = Def::Mod(self.ast_map.local_def_id(item.id));
let module = self.new_module(parent_link, Some(def), false, is_public);
name_bindings.define_module(module.clone(), sp);
module
let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp);
let mutbl = m == hir::MutMutable;
- name_bindings.define_value(DefStatic(self.ast_map.local_def_id(item.id), mutbl),
+ name_bindings.define_value(Def::Static(self.ast_map.local_def_id(item.id), mutbl),
sp,
modifiers);
parent
}
ItemConst(_, _) => {
self.add_child(name, parent, ForbidDuplicateValues, sp)
- .define_value(DefConst(self.ast_map.local_def_id(item.id)), sp, modifiers);
+ .define_value(Def::Const(self.ast_map.local_def_id(item.id)), sp, modifiers);
parent
}
ItemFn(_, _, _, _, _, _) => {
let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp);
- let def = DefFn(self.ast_map.local_def_id(item.id), false);
+ let def = Def::Fn(self.ast_map.local_def_id(item.id));
name_bindings.define_value(def, sp, modifiers);
parent
}
sp);
let parent_link = ModuleParentLink(parent, name);
- let def = DefTy(self.ast_map.local_def_id(item.id), false);
+ let def = Def::TyAlias(self.ast_map.local_def_id(item.id));
let module = self.new_module(parent_link, Some(def), false, is_public);
name_bindings.define_module(module, sp);
parent
sp);
let parent_link = ModuleParentLink(parent, name);
- let def = DefTy(self.ast_map.local_def_id(item.id), true);
+ let def = Def::Enum(self.ast_map.local_def_id(item.id));
let module = self.new_module(parent_link, Some(def), false, is_public);
name_bindings.define_module(module.clone(), sp);
let name_bindings = self.add_child(name, parent, forbid, sp);
// Define a name in the type namespace.
- name_bindings.define_type(DefTy(self.ast_map.local_def_id(item.id), false),
+ name_bindings.define_type(Def::Struct(self.ast_map.local_def_id(item.id)),
sp,
modifiers);
// If this is a newtype or unit-like struct, define a name
// in the value namespace as well
if let Some(cid) = ctor_id {
- name_bindings.define_value(DefStruct(self.ast_map.local_def_id(cid)),
+ name_bindings.define_value(Def::Struct(self.ast_map.local_def_id(cid)),
sp,
modifiers);
}
// Add all the items within to a new module.
let parent_link = ModuleParentLink(parent, name);
- let def = DefTrait(def_id);
+ let def = Def::Trait(def_id);
let module_parent = self.new_module(parent_link, Some(def), false, is_public);
name_bindings.define_module(module_parent.clone(), sp);
match trait_item.node {
hir::ConstTraitItem(..) => {
- let def = DefAssociatedConst(self.ast_map.local_def_id(trait_item.id));
+ let def = Def::AssociatedConst(self.ast_map.
+ local_def_id(trait_item.id));
// NB: not DefModifiers::IMPORTABLE
name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC);
}
hir::MethodTraitItem(..) => {
- let def = DefMethod(self.ast_map.local_def_id(trait_item.id));
+ let def = Def::Method(self.ast_map.local_def_id(trait_item.id));
// NB: not DefModifiers::IMPORTABLE
name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC);
}
hir::TypeTraitItem(..) => {
- let def = DefAssociatedTy(self.ast_map.local_def_id(item.id),
+ let def = Def::AssociatedTy(self.ast_map.local_def_id(item.id),
self.ast_map.local_def_id(trait_item.id));
// NB: not DefModifiers::IMPORTABLE
name_bindings.define_type(def, trait_item.span, DefModifiers::PUBLIC);
parent: Module<'b>,
variant_modifiers: DefModifiers) {
let name = variant.node.name;
- let is_exported = if variant.node.data.is_struct() {
+ if variant.node.data.is_struct() {
// Not adding fields for variants as they are not accessed with a self receiver
let variant_def_id = self.ast_map.local_def_id(variant.node.data.id());
self.structs.insert(variant_def_id, Vec::new());
- true
- } else {
- false
- };
+ }
let child = self.add_child(name, parent, ForbidDuplicateTypesAndValues, variant.span);
// variants are always treated as importable to allow them to be glob
// used
- child.define_value(DefVariant(item_id,
- self.ast_map.local_def_id(variant.node.data.id()),
- is_exported),
+ child.define_value(Def::Variant(item_id, self.ast_map.local_def_id(variant.node.data.id())),
variant.span,
DefModifiers::PUBLIC | DefModifiers::IMPORTABLE | variant_modifiers);
- child.define_type(DefVariant(item_id,
- self.ast_map.local_def_id(variant.node.data.id()),
- is_exported),
+ child.define_type(Def::Variant(item_id, self.ast_map.local_def_id(variant.node.data.id())),
variant.span,
DefModifiers::PUBLIC | DefModifiers::IMPORTABLE | variant_modifiers);
}
let def = match foreign_item.node {
ForeignItemFn(..) => {
- DefFn(self.ast_map.local_def_id(foreign_item.id), false)
+ Def::Fn(self.ast_map.local_def_id(foreign_item.id))
}
ForeignItemStatic(_, m) => {
- DefStatic(self.ast_map.local_def_id(foreign_item.id), m)
+ Def::Static(self.ast_map.local_def_id(foreign_item.id), m)
}
};
name_bindings.define_value(def, foreign_item.span, modifiers);
if is_exported {
self.external_exports.insert(def.def_id());
}
+ let is_struct_ctor = if let Def::Struct(def_id) = def {
+ self.session.cstore.tuple_struct_definition_if_ctor(def_id).is_some()
+ } else {
+ false
+ };
match def {
- DefMod(_) |
- DefForeignMod(_) |
- DefStruct(_) |
- DefTy(..) => {
+ Def::Mod(_) |
+ Def::ForeignMod(_) |
+ Def::Struct(..) |
+ Def::Enum(..) |
+ Def::TyAlias(..) if !is_struct_ctor => {
if let Some(module_def) = child_name_bindings.type_ns.module() {
debug!("(building reduced graph for external crate) already created module");
module_def.def.set(Some(def));
}
match def {
- DefMod(_) | DefForeignMod(_) => {}
- DefVariant(_, variant_id, is_struct) => {
+ Def::Mod(_) | Def::ForeignMod(_) => {}
+ Def::Variant(_, variant_id) => {
debug!("(building reduced graph for external crate) building variant {}",
final_ident);
// variants are always treated as importable to allow them to be
// glob used
let modifiers = DefModifiers::PUBLIC | DefModifiers::IMPORTABLE;
- if is_struct {
+ if self.session.cstore.variant_kind(variant_id) == Some(VariantKind::Struct) {
child_name_bindings.define_type(def, DUMMY_SP, modifiers);
// Not adding fields for variants as they are not accessed with a self receiver
self.structs.insert(variant_id, Vec::new());
child_name_bindings.define_value(def, DUMMY_SP, modifiers);
}
}
- DefFn(ctor_id, true) => {
- child_name_bindings.define_value(
- self.session.cstore.tuple_struct_definition_if_ctor(ctor_id)
- .map_or(def, |_| DefStruct(ctor_id)), DUMMY_SP, modifiers);
- }
- DefFn(..) |
- DefStatic(..) |
- DefConst(..) |
- DefAssociatedConst(..) |
- DefMethod(..) => {
+ Def::Fn(..) |
+ Def::Static(..) |
+ Def::Const(..) |
+ Def::AssociatedConst(..) |
+ Def::Method(..) => {
debug!("(building reduced graph for external crate) building value (fn/static) {}",
final_ident);
// impl methods have already been defined with the correct importability
}
child_name_bindings.define_value(def, DUMMY_SP, modifiers);
}
- DefTrait(def_id) => {
+ Def::Trait(def_id) => {
debug!("(building reduced graph for external crate) building type {}",
final_ident);
let module = self.new_module(parent_link, Some(def), true, is_public);
child_name_bindings.define_module(module, DUMMY_SP);
}
- DefTy(..) | DefAssociatedTy(..) => {
+ Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => {
debug!("(building reduced graph for external crate) building type {}",
final_ident);
_ => modifiers & !DefModifiers::IMPORTABLE,
};
- if let DefTy(..) = def {
+ if let Def::Enum(..) = def {
+ child_name_bindings.type_ns.set_modifiers(modifiers);
+ } else if let Def::TyAlias(..) = def {
child_name_bindings.type_ns.set_modifiers(modifiers);
} else {
child_name_bindings.define_type(def, DUMMY_SP, modifiers);
}
}
- DefStruct(def_id) => {
+ Def::Struct(..) if is_struct_ctor => {
+ // Do nothing
+ }
+ Def::Struct(def_id) => {
debug!("(building reduced graph for external crate) building type and value for \
{}",
final_ident);
- child_name_bindings.define_type(def, DUMMY_SP, modifiers);
- let fields = self.session.cstore.struct_field_names(def_id);
- if fields.is_empty() {
- child_name_bindings.define_value(def, DUMMY_SP, modifiers);
+ child_name_bindings.define_type(def, DUMMY_SP, modifiers);
+ if let Some(ctor_def_id) = self.session.cstore.struct_ctor_def_id(def_id) {
+ child_name_bindings.define_value(Def::Struct(ctor_def_id), DUMMY_SP, modifiers);
}
// Record the def ID and fields of this struct.
+ let fields = self.session.cstore.struct_field_names(def_id);
self.structs.insert(def_id, fields);
}
- DefLocal(..) |
- DefPrimTy(..) |
- DefTyParam(..) |
- DefUpvar(..) |
- DefLabel(..) |
- DefSelfTy(..) |
- DefErr => {
+ Def::Local(..) |
+ Def::PrimTy(..) |
+ Def::TyParam(..) |
+ Def::Upvar(..) |
+ Def::Label(..) |
+ Def::SelfTy(..) |
+ Def::Err => {
panic!("didn't expect `{:?}`", def);
}
}
DlDef(def) => {
// Add the new child item, if necessary.
match def {
- DefForeignMod(def_id) => {
+ Def::ForeignMod(def_id) => {
// Foreign modules have no names. Recur and populate
// eagerly.
for child in self.session.cstore.item_children(def_id) {
}
// The rib kind controls the translation of local
-// definitions (`DefLocal`) to upvars (`DefUpvar`).
+// definitions (`Def::Local`) to upvars (`Def::Upvar`).
#[derive(Copy, Clone, Debug)]
enum RibKind {
// No translation needs to be applied.
fn is_normal(&self) -> bool {
match self.def.get() {
- Some(DefMod(_)) | Some(DefForeignMod(_)) => true,
+ Some(Def::Mod(_)) | Some(Def::ForeignMod(_)) => true,
_ => false,
}
}
fn is_trait(&self) -> bool {
match self.def.get() {
- Some(DefTrait(_)) => true,
+ Some(Def::Trait(_)) => true,
_ => false,
}
}
arenas: &'a ResolverArenas<'a>)
-> Resolver<'a, 'tcx> {
let root_def_id = ast_map.local_def_id(CRATE_NODE_ID);
- let graph_root = ModuleS::new(NoParentLink, Some(DefMod(root_def_id)), false, true);
+ let graph_root = ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false, true);
let graph_root = arenas.modules.alloc(graph_root);
Resolver {
ItemRibKind),
|this| {
let local_def_id = this.ast_map.local_def_id(item.id);
- this.with_self_rib(DefSelfTy(Some(local_def_id), None), |this| {
+ this.with_self_rib(Def::SelfTy(Some(local_def_id), None), |this| {
this.visit_generics(generics);
walk_list!(this, visit_ty_param_bound, bounds);
// check for imports shadowing primitive types
let check_rename = |this: &Self, id, name| {
match this.def_map.borrow().get(&id).map(|d| d.full_def()) {
- Some(DefTy(..)) | Some(DefStruct(..)) | Some(DefTrait(..)) | None => {
+ Some(Def::Enum(..)) | Some(Def::TyAlias(..)) | Some(Def::Struct(..)) |
+ Some(Def::Trait(..)) | None => {
this.check_if_primitive_type_name(name, item.span);
}
_ => {}
// plain insert (no renaming)
function_type_rib.bindings
.insert(name,
- DlDef(DefTyParam(space,
+ DlDef(Def::TyParam(space,
index as u32,
self.ast_map
.local_def_id(type_parameter.id),
path_depth: usize)
-> Result<PathResolution, ()> {
if let Some(path_res) = self.resolve_path(id, trait_path, path_depth, TypeNS, true) {
- if let DefTrait(_) = path_res.base_def {
+ if let Def::Trait(_) = path_res.base_def {
debug!("(resolving trait) found trait def: {:?}", path_res);
Ok(path_res)
} else {
path_depth)));
// If it's a typedef, give a note
- if let DefTy(..) = path_res.base_def {
+ if let Def::TyAlias(..) = path_res.base_def {
err.span_note(trait_path.span,
"`type` aliases cannot be used for traits");
}
&hir::WherePredicate::RegionPredicate(_) => {}
&hir::WherePredicate::EqPredicate(ref eq_pred) => {
let path_res = self.resolve_path(eq_pred.id, &eq_pred.path, 0, TypeNS, true);
- if let Some(PathResolution { base_def: DefTyParam(..), .. }) = path_res {
+ if let Some(PathResolution { base_def: Def::TyParam(..), .. }) = path_res {
self.record_def(eq_pred.id, path_res.unwrap());
} else {
resolve_error(self,
// Resolve the self type.
this.visit_ty(self_type);
- this.with_self_rib(DefSelfTy(trait_id, Some((item_id, self_type.id))), |this| {
+ this.with_self_rib(Def::SelfTy(trait_id, Some((item_id, self_type.id))), |this| {
this.with_current_self_type(self_type, |this| {
for impl_item in impl_items {
match impl_item.node {
debug!("(resolving pattern) binding `{}`", renamed);
let def_id = self.ast_map.local_def_id(pattern.id);
- let def = DefLocal(def_id, pattern.id);
+ let def = Def::Local(def_id, pattern.id);
// Record the definition so that later passes
// will be able to distinguish variants from
};
if let Some(path_res) = resolution {
match path_res.base_def {
- DefVariant(..) | DefStruct(..) | DefConst(..) => {
+ Def::Struct(..) if path_res.depth == 0 => {
self.record_def(pattern.id, path_res);
}
- DefStatic(..) => {
+ Def::Variant(..) | Def::Const(..) => {
+ self.record_def(pattern.id, path_res);
+ }
+ Def::Static(..) => {
resolve_error(&self,
path.span,
ResolutionError::StaticVariableReference);
match path_res.base_def {
// All `<T as Trait>::CONST` should end up here, and
// have the trait already selected.
- DefAssociatedConst(..) => {
+ Def::AssociatedConst(..) => {
self.record_def(pattern.id, path_res);
}
_ => {
// For the two success cases, this lookup can be
// considered as not having a private component because
// the lookup happened only within the current module.
- Some(def @ DefVariant(..)) | Some(def @ DefStruct(..)) => {
+ Some(def @ Def::Variant(..)) | Some(def @ Def::Struct(..)) => {
return FoundStructOrEnumVariant(def, LastMod(AllPublic));
}
- Some(def @ DefConst(..)) | Some(def @ DefAssociatedConst(..)) => {
+ Some(def @ Def::Const(..)) | Some(def @ Def::AssociatedConst(..)) => {
return FoundConst(def, LastMod(AllPublic), name);
}
- Some(DefStatic(..)) => {
+ Some(Def::Static(..)) => {
resolve_error(self, span, ResolutionError::StaticVariableReference);
return BareIdentifierPatternUnresolved;
}
resolution = this.resolve_path(id, path, depth, TypeNS, true);
});
}
- if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
+ if let Some(Def::Mod(_)) = resolution.map(|r| r.base_def) {
// A module is not a valid type or value.
resolution = None;
}
if let Some(&prim_ty) = self.primitive_type_table
.primitive_types
.get(&identifier.unhygienic_name) {
- return Some(LocalDef::from_def(DefPrimTy(prim_ty)));
+ return Some(LocalDef::from_def(Def::PrimTy(prim_ty)));
}
}
};
let mut def = local_def.def;
match def {
- DefUpvar(..) => {
+ Def::Upvar(..) => {
self.session.span_bug(span, &format!("unexpected {:?} in bindings", def))
}
- DefLocal(_, node_id) => {
+ Def::Local(_, node_id) => {
for rib in ribs {
match rib.kind {
NormalRibKind => {
.entry(function_id)
.or_insert_with(|| NodeMap());
if let Some(&index) = seen.get(&node_id) {
- def = DefUpvar(node_def_id, node_id, index, function_id);
+ def = Def::Upvar(node_def_id, node_id, index, function_id);
continue;
}
let vec = self.freevars
span: span,
});
- def = DefUpvar(node_def_id, node_id, depth, function_id);
+ def = Def::Upvar(node_def_id, node_id, depth, function_id);
seen.insert(node_id, depth);
}
ItemRibKind | MethodRibKind => {
}
}
}
- DefTyParam(..) | DefSelfTy(..) => {
+ Def::TyParam(..) | Def::SelfTy(..) => {
for rib in ribs {
match rib.kind {
NormalRibKind | MethodRibKind | ClosureRibKind(..) => {
if allowed == Everything {
// Look for a field with the same name in the current self_type.
match self.def_map.borrow().get(&node_id).map(|d| d.full_def()) {
- Some(DefTy(did, _)) |
- Some(DefStruct(did)) |
- Some(DefVariant(_, did, _)) => match self.structs.get(&did) {
+ Some(Def::Enum(did)) |
+ Some(Def::TyAlias(did)) |
+ Some(Def::Struct(did)) |
+ Some(Def::Variant(_, did)) => match self.structs.get(&did) {
None => {}
Some(fields) => {
if fields.iter().any(|&field_name| name == field_name) {
// Look for a method in the current self type's impl module.
if let Some(module) = get_module(self, path.span, &name_path) {
if let Some(binding) = module.children.borrow().get(&name) {
- if let Some(DefMethod(did)) = binding.value_ns.def() {
+ if let Some(Def::Method(did)) = binding.value_ns.def() {
if is_static_method(self, did) {
return StaticMethod(path_names_to_string(&path, 0));
}
// scopes looking for it.
if let Some(path_res) = resolution {
// Check if struct variant
- if let DefVariant(_, _, true) = path_res.base_def {
+ let is_struct_variant = if let Def::Variant(_, variant_id) = path_res.base_def {
+ self.structs.contains_key(&variant_id)
+ } else {
+ false
+ };
+ if is_struct_variant {
+ let _ = self.structs.contains_key(&path_res.base_def.def_id());
let path_name = path_names_to_string(path, 0);
let mut err = resolve_struct_error(self,
self.record_def(expr.id, err_path_resolution());
match type_res.map(|r| r.base_def) {
- Some(DefTy(struct_id, _)) if self.structs.contains_key(&struct_id) => {
+ Some(Def::Struct(..)) => {
let mut err = resolve_struct_error(self,
expr.span,
ResolutionError::StructVariantUsedAsFunction(&*path_name));
ExprLoop(_, Some(label)) | ExprWhile(_, _, Some(label)) => {
self.with_label_rib(|this| {
- let def_like = DlDef(DefLabel(expr.id));
+ let def_like = DlDef(Def::Label(expr.id));
{
let rib = this.label_ribs.last_mut().unwrap();
label.span,
ResolutionError::UndeclaredLabel(&label.node.name.as_str()))
}
- Some(DlDef(def @ DefLabel(_))) => {
+ Some(DlDef(def @ Def::Label(_))) => {
// Since this def is a label, it is never read.
self.record_def(expr.id,
PathResolution {
None => continue,
};
let trait_def_id = match def {
- DefTrait(trait_def_id) => trait_def_id,
+ Def::Trait(trait_def_id) => trait_def_id,
_ => continue,
};
if self.trait_item_map.contains_key(&(name, trait_def_id)) {
Some(ref target) => target,
};
let did = match target.binding.def() {
- Some(DefTrait(trait_def_id)) => trait_def_id,
+ Some(Def::Trait(trait_def_id)) => trait_def_id,
Some(..) | None => continue,
};
if self.trait_item_map.contains_key(&(name, did)) {
fn err_path_resolution() -> PathResolution {
PathResolution {
- base_def: DefErr,
+ base_def: Def::Err,
last_private: LastMod(AllPublic),
depth: 0,
}
if let Some(did) = target_module.def_id() {
self.resolver.def_map.borrow_mut().insert(id,
PathResolution {
- base_def: DefMod(did),
+ base_def: Def::Mod(did),
last_private: lp,
depth: 0,
});
suffix))
}
config::CrateTypeStaticlib => {
- outputs.out_directory.join(&format!("lib{}.a", libname))
+ let (prefix, suffix) = (&sess.target.target.options.staticlib_prefix,
+ &sess.target.target.options.staticlib_suffix);
+ outputs.out_directory.join(&format!("{}{}{}", prefix, libname,
+ suffix))
}
config::CrateTypeExecutable => {
let suffix = &sess.target.target.options.exe_suffix;
fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); }
fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
fn args(&mut self, args: &[String]) { self.cmd.args(args); }
- fn build_dylib(&mut self, _out_filename: &Path) { self.cmd.arg("/DLL"); }
+
+ fn build_dylib(&mut self, out_filename: &Path) {
+ self.cmd.arg("/DLL");
+ let mut arg: OsString = "/IMPLIB:".into();
+ arg.push(out_filename.with_extension("dll.lib"));
+ self.cmd.arg(arg);
+ }
+
fn gc_sections(&mut self, _is_dylib: bool) { self.cmd.arg("/OPT:REF,ICF"); }
fn link_dylib(&mut self, lib: &str) {
// `foo.lib` file if the dll doesn't actually export any symbols, so we
// check to see if the file is there and just omit linking to it if it's
// not present.
- let name = format!("{}.lib", lib);
+ let name = format!("{}.dll.lib", lib);
if fs::metadata(&path.join(&name)).is_ok() {
self.cmd.arg(name);
}
use session::Session;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::ty;
}
let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
match def {
- def::DefPrimTy(..) => None,
- def::DefSelfTy(..) => None,
+ Def::PrimTy(..) => None,
+ Def::SelfTy(..) => None,
_ => Some(def.def_id()),
}
}
}
let def = def_map.get(&ref_id).unwrap().full_def();
match def {
- def::DefMod(_) |
- def::DefForeignMod(_) => Some(recorder::ModRef),
- def::DefStruct(_) => Some(recorder::TypeRef),
- def::DefTy(..) |
- def::DefAssociatedTy(..) |
- def::DefTrait(_) => Some(recorder::TypeRef),
- def::DefStatic(_, _) |
- def::DefConst(_) |
- def::DefAssociatedConst(..) |
- def::DefLocal(..) |
- def::DefVariant(_, _, _) |
- def::DefUpvar(..) => Some(recorder::VarRef),
-
- def::DefFn(..) => Some(recorder::FnRef),
-
- def::DefSelfTy(..) |
- def::DefLabel(_) |
- def::DefTyParam(..) |
- def::DefMethod(..) |
- def::DefPrimTy(_) |
- def::DefErr => {
+ Def::Mod(_) |
+ Def::ForeignMod(_) => Some(recorder::ModRef),
+ Def::Struct(..) => Some(recorder::TypeRef),
+ Def::Enum(..) |
+ Def::TyAlias(..) |
+ Def::AssociatedTy(..) |
+ Def::Trait(_) => Some(recorder::TypeRef),
+ Def::Static(_, _) |
+ Def::Const(_) |
+ Def::AssociatedConst(..) |
+ Def::Local(..) |
+ Def::Variant(..) |
+ Def::Upvar(..) => Some(recorder::VarRef),
+
+ Def::Fn(..) => Some(recorder::FnRef),
+
+ Def::SelfTy(..) |
+ Def::Label(_) |
+ Def::TyParam(..) |
+ Def::Method(..) |
+ Def::PrimTy(_) |
+ Def::Err => {
self.sess.span_bug(span,
&format!("lookup_def_kind for unexpected item: {:?}", def));
}
let def_map = self.tcx.def_map.borrow();
let def = def_map.get(&id).unwrap().full_def();
match def {
- def::DefMethod(did) => {
+ Def::Method(did) => {
let ti = self.tcx.impl_or_trait_item(did);
if let ty::MethodTraitItem(m) = ti {
if m.explicit_self == ty::ExplicitSelfCategory::Static {
}
}
}
- def::DefLocal(..) |
- def::DefStatic(_,_) |
- def::DefConst(..) |
- def::DefAssociatedConst(..) |
- def::DefStruct(_) |
- def::DefVariant(..) |
- def::DefFn(..) => self.write_sub_paths_truncated(path, false),
+ Def::Local(..) |
+ Def::Static(_,_) |
+ Def::Const(..) |
+ Def::AssociatedConst(..) |
+ Def::Struct(..) |
+ Def::Variant(..) |
+ Def::Fn(..) => self.write_sub_paths_truncated(path, false),
_ => {}
}
}
}
let def = def_map.get(&id).unwrap().full_def();
match def {
- def::DefLocal(_, id) => {
+ Def::Local(_, id) => {
let value = if immut == ast::MutImmutable {
self.span.snippet(p.span).to_string()
} else {
"qualified path for local variable def in arm");
self.fmt.variable_str(p.span, Some(p.span), id, &path_to_string(p), &value, "")
}
- def::DefVariant(..) | def::DefTy(..) | def::DefStruct(..) => {
+ Def::Variant(..) | Def::Enum(..) |
+ Def::TyAlias(..) | Def::Struct(..) => {
paths_to_process.push((id, p.clone(), Some(ref_kind)))
}
// FIXME(nrc) what are these doing here?
- def::DefStatic(_, _) |
- def::DefConst(..) |
- def::DefAssociatedConst(..) => {}
+ Def::Static(_, _) |
+ Def::Const(..) |
+ Def::AssociatedConst(..) => {}
_ => error!("unexpected definition kind when processing collected paths: {:?}",
def),
}
// except according to those terms.
use middle::ty;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use std::env;
let def = def_map.get(&id).unwrap().full_def();
let sub_span = self.span_utils.span_for_last_ident(path.span);
match def {
- def::DefUpvar(..) |
- def::DefLocal(..) |
- def::DefStatic(..) |
- def::DefConst(..) |
- def::DefAssociatedConst(..) |
- def::DefVariant(..) => {
+ Def::Upvar(..) |
+ Def::Local(..) |
+ Def::Static(..) |
+ Def::Const(..) |
+ Def::AssociatedConst(..) |
+ Def::Variant(..) => {
Some(Data::VariableRefData(VariableRefData {
name: self.span_utils.snippet(sub_span.unwrap()),
span: sub_span.unwrap(),
ref_id: def.def_id(),
}))
}
- def::DefStruct(def_id) |
- def::DefTy(def_id, _) |
- def::DefTrait(def_id) |
- def::DefTyParam(_, _, def_id, _) => {
+ Def::Struct(def_id) |
+ Def::Enum(def_id) |
+ Def::TyAlias(def_id) |
+ Def::Trait(def_id) |
+ Def::TyParam(_, _, def_id, _) => {
Some(Data::TypeRefData(TypeRefData {
span: sub_span.unwrap(),
ref_id: def_id,
scope: self.enclosing_scope(id),
}))
}
- def::DefMethod(decl_id) => {
+ Def::Method(decl_id) => {
let sub_span = self.span_utils.sub_span_for_meth_name(path.span);
let def_id = if decl_id.is_local() {
let ti = self.tcx.impl_or_trait_item(decl_id);
decl_id: Some(decl_id),
}))
}
- def::DefFn(def_id, _) => {
+ Def::Fn(def_id) => {
Some(Data::FunctionCallData(FunctionCallData {
ref_id: def_id,
span: sub_span.unwrap(),
scope: self.enclosing_scope(id),
}))
}
- def::DefMod(def_id) => {
+ Def::Mod(def_id) => {
Some(Data::ModRefData(ModRefData {
ref_id: def_id,
span: sub_span.unwrap(),
}
let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
match def {
- def::DefPrimTy(_) | def::DefSelfTy(..) => None,
+ Def::PrimTy(_) | Def::SelfTy(..) => None,
_ => Some(def.def_id()),
}
}
use middle::check_match::StaticInliner;
use middle::check_match;
use middle::const_eval;
-use middle::def::{self, DefMap};
+use middle::def::{Def, DefMap};
use middle::def_id::DefId;
use middle::expr_use_visitor as euv;
use middle::infer;
// This is either an enum variant or a variable binding.
let opt_def = tcx.def_map.borrow().get(&cur.id).map(|d| d.full_def());
match opt_def {
- Some(def::DefVariant(enum_id, var_id, _)) => {
+ Some(Def::Variant(enum_id, var_id)) => {
let variant = tcx.lookup_adt_def(enum_id).variant_with_id(var_id);
Variant(Disr::from(variant.disr_val),
adt::represent_node(bcx, cur.id),
hir::PatTup(_) => true,
hir::PatStruct(..) => {
match tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(def::DefVariant(..)) => false,
+ Some(Def::Variant(..)) => false,
_ => true,
}
}
hir::PatEnum(..) | hir::PatIdent(_, _, None) => {
match tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(def::DefStruct(..)) => true,
+ Some(Def::Struct(..)) => true,
_ => false
}
}
fn is_discr_reassigned(bcx: Block, discr: &hir::Expr, body: &hir::Expr) -> bool {
let (vid, field) = match discr.node {
hir::ExprPath(..) => match bcx.def(discr.id) {
- def::DefLocal(_, vid) | def::DefUpvar(_, vid, _, _) => (vid, None),
+ Def::Local(_, vid) | Def::Upvar(_, vid, _, _) => (vid, None),
_ => return false
},
hir::ExprField(ref base, field) => {
let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
- Some(def::DefLocal(_, vid)) | Some(def::DefUpvar(_, vid, _, _)) => vid,
+ Some(Def::Local(_, vid)) | Some(Def::Upvar(_, vid, _, _)) => vid,
_ => return false
};
(vid, Some(mc::NamedField(field.node)))
},
hir::ExprTupField(ref base, field) => {
let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
- Some(def::DefLocal(_, vid)) | Some(def::DefUpvar(_, vid, _, _)) => vid,
+ Some(Def::Local(_, vid)) | Some(Def::Upvar(_, vid, _, _)) => vid,
_ => return false
};
(vid, Some(mc::PositionalField(field.node)))
hir::PatEnum(_, ref sub_pats) => {
let opt_def = bcx.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def());
match opt_def {
- Some(def::DefVariant(enum_id, var_id, _)) => {
+ Some(Def::Variant(enum_id, var_id)) => {
let repr = adt::represent_node(bcx, pat.id);
let vinfo = ccx.tcx().lookup_adt_def(enum_id).variant_with_id(var_id);
let args = extract_variant_args(bcx,
}
}
}
- Some(def::DefStruct(..)) => {
+ Some(Def::Struct(..)) => {
match *sub_pats {
None => {
// This is a unit-like struct. Nothing to do here.
assert_eq!(val_ty(ptr), llty.ptr_to());
let bits = machine::llbitsize_of_real(bcx.ccx(), llty);
assert!(bits <= 64);
- let bits = bits as usize;
+ let bits = bits as usize;
let mask = Disr(!0u64 >> (64 - bits));
// For a (max) discr of -1, max will be `-1 as usize`, which overflows.
// However, that is fine here (it would still represent the full range),
} else {
// llvm::ConstantRange can deal with ranges that wrap around,
// so an overflow on (max + 1) is fine.
- LoadRangeAssert(bcx, ptr, min, max.wrapping_add(Disr(1)), /* signed: */ True)
+ LoadRangeAssert(bcx, ptr, min.0, max.0.wrapping_add(1), /* signed: */ True)
}
}
}
let val = if t.is_bool() {
- LoadRangeAssert(cx, ptr, Disr(0), Disr(2), llvm::False)
+ LoadRangeAssert(cx, ptr, 0, 2, llvm::False)
} else if t.is_char() {
// a char is a Unicode codepoint, and so takes values from 0
// to 0x10FFFF inclusive only.
- LoadRangeAssert(cx, ptr, Disr(0), Disr(0x10FFFF + 1), llvm::False)
+ LoadRangeAssert(cx, ptr, 0, 0x10FFFF + 1, llvm::False)
} else if (t.is_region_ptr() || t.is_unique()) && !common::type_is_fat_ptr(cx.tcx(), t) {
LoadNonNull(cx, ptr)
} else {
use trans::builder::Builder;
use trans::type_::Type;
use trans::debuginfo::DebugLoc;
-use trans::Disr;
use libc::{c_uint, c_char};
}
-pub fn LoadRangeAssert(cx: Block, pointer_val: ValueRef, lo: Disr,
- hi: Disr, signed: llvm::Bool) -> ValueRef {
+pub fn LoadRangeAssert(cx: Block, pointer_val: ValueRef, lo: u64,
+ hi: u64, signed: llvm::Bool) -> ValueRef {
if cx.unreachable.get() {
let ccx = cx.fcx.ccx;
let ty = val_ty(pointer_val);
llvm::LLVMGetUndef(eltty.to_ref())
}
} else {
- B(cx).load_range_assert(pointer_val, lo.0, hi.0, signed)
+ B(cx).load_range_assert(pointer_val, lo, hi, signed)
}
}
use back::link;
use llvm::{self, ValueRef, get_params};
use middle::cstore::LOCAL_CRATE;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::infer;
use middle::subst;
}
fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- def: def::Def,
+ def: Def,
ref_expr: &hir::Expr)
-> Callee<'blk, 'tcx> {
debug!("trans_def(def={:?}, ref_expr={:?})", def, ref_expr);
let expr_ty = common::node_id_type(bcx, ref_expr.id);
match def {
- def::DefFn(did, _) if {
+ Def::Fn(did) if {
let maybe_def_id = inline::get_local_instance(bcx.ccx(), did);
let maybe_ast_node = maybe_def_id.and_then(|def_id| {
let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
ty: expr_ty
}
}
- def::DefFn(did, _) if match expr_ty.sty {
+ Def::Fn(did) if match expr_ty.sty {
ty::TyBareFn(_, ref f) => f.abi == synabi::RustIntrinsic ||
f.abi == synabi::PlatformIntrinsic,
_ => false
let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
Callee { bcx: bcx, data: Intrinsic(node_id, substs), ty: expr_ty }
}
- def::DefFn(did, _) => {
+ Def::Fn(did) => {
fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
bcx.fcx.param_substs))
}
- def::DefMethod(meth_did) => {
+ Def::Method(meth_did) => {
let method_item = bcx.tcx().impl_or_trait_item(meth_did);
let fn_datum = match method_item.container() {
ty::ImplContainer(_) => {
};
fn_callee(bcx, fn_datum)
}
- def::DefVariant(tid, vid, _) => {
+ Def::Variant(tid, vid) => {
let vinfo = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
assert_eq!(vinfo.kind(), ty::VariantKind::Tuple);
ty: expr_ty
}
}
- def::DefStruct(_) => {
+ Def::Struct(..) => {
Callee {
bcx: bcx,
data: NamedTupleConstructor(Disr(0)),
ty: expr_ty
}
}
- def::DefStatic(..) |
- def::DefConst(..) |
- def::DefAssociatedConst(..) |
- def::DefLocal(..) |
- def::DefUpvar(..) => {
+ Def::Static(..) |
+ Def::Const(..) |
+ Def::AssociatedConst(..) |
+ Def::Local(..) |
+ Def::Upvar(..) => {
datum_callee(bcx, ref_expr)
}
- def::DefMod(..) | def::DefForeignMod(..) | def::DefTrait(..) |
- def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) |
- def::DefLabel(..) | def::DefTyParam(..) |
- def::DefSelfTy(..) | def::DefErr => {
+ Def::Mod(..) | Def::ForeignMod(..) | Def::Trait(..) |
+ Def::Enum(..) | Def::TyAlias(..) | Def::PrimTy(..) |
+ Def::AssociatedTy(..) | Def::Label(..) | Def::TyParam(..) |
+ Def::SelfTy(..) | Def::Err => {
bcx.tcx().sess.span_bug(
ref_expr.span,
&format!("cannot translate def {:?} \
use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef, TypeKind};
use llvm::{True, False, Bool};
use middle::cfg;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::infer;
use middle::lang_items::LangItem;
impl<'tcx> VariantInfo<'tcx> {
pub fn from_ty(tcx: &ty::ctxt<'tcx>,
ty: Ty<'tcx>,
- opt_def: Option<def::Def>)
+ opt_def: Option<Def>)
-> Self
{
match ty.sty {
self.tcx().map.node_to_string(id).to_string()
}
- pub fn def(&self, nid: ast::NodeId) -> def::Def {
+ pub fn def(&self, nid: ast::NodeId) -> Def {
match self.tcx().def_map.borrow().get(&nid) {
Some(v) => v.full_def(),
None => {
use llvm;
use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
use llvm::{InternalLinkage, ValueRef, Bool, True};
-use middle::{check_const, def};
+use middle::const_qualif::ConstQualif;
use middle::cstore::LOCAL_CRATE;
use middle::const_eval::{self, ConstVal, ConstEvalErr};
use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg};
use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr};
use middle::const_eval::EvalHint::ExprTypeChecked;
use middle::const_eval::eval_const_expr_partial;
+use middle::def::Def;
use middle::def_id::DefId;
use trans::{adt, closure, debuginfo, expr, inline, machine};
use trans::base::{self, push_ctxt};
-> Result<ValueRef, ConstEvalFailure> {
let expr = get_const_expr(ccx, def_id, ref_expr, param_substs);
let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
- match get_const_expr_as_global(ccx, expr, check_const::ConstQualif::empty(),
- empty_substs, TrueConst::Yes) {
+ match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) {
Err(Runtime(err)) => {
ccx.tcx().sess.span_err(expr.span, &err.description());
Err(Compiletime(err))
pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
expr: &hir::Expr,
- qualif: check_const::ConstQualif,
+ qualif: ConstQualif,
param_substs: &'tcx Substs<'tcx>,
trueconst: TrueConst)
-> Result<ValueRef, ConstEvalFailure> {
// of just to get the `def` value
let def = ccx.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
match def {
- def::DefConst(def_id) | def::DefAssociatedConst(def_id) => {
+ Def::Const(def_id) | Def::AssociatedConst(def_id) => {
if !ccx.tcx().tables.borrow().adjustments.contains_key(&expr.id) {
debug!("get_const_expr_as_global ({:?}): found const {:?}",
expr.id, def_id);
}
let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs,
&ccx.tcx().expr_ty(expr));
- let val = if qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS) {
+ let val = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
// Avoid autorefs as they would create global instead of stack
// references, even when only the latter are correct.
try!(const_expr_unadjusted(ccx, expr, ty, param_substs, None, trueconst))
}
}
let opt_def = cx.tcx().def_map.borrow().get(&cur.id).map(|d| d.full_def());
- if let Some(def::DefStatic(def_id, _)) = opt_def {
+ if let Some(Def::Static(def_id, _)) = opt_def {
common::get_static_val(cx, def_id, ety)
} else {
// If this isn't the address of a static, then keep going through
hir::ExprPath(..) => {
let def = cx.tcx().def_map.borrow().get(&e.id).unwrap().full_def();
match def {
- def::DefLocal(_, id) => {
+ Def::Local(_, id) => {
if let Some(val) = fn_args.and_then(|args| args.get(&id).cloned()) {
val
} else {
cx.sess().span_bug(e.span, "const fn argument not found")
}
}
- def::DefFn(..) | def::DefMethod(..) => {
+ Def::Fn(..) | Def::Method(..) => {
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
}
- def::DefConst(def_id) | def::DefAssociatedConst(def_id) => {
+ Def::Const(def_id) | Def::AssociatedConst(def_id) => {
const_deref_ptr(cx, try!(get_const_val(cx, def_id, e, param_substs)))
}
- def::DefVariant(enum_did, variant_did, _) => {
+ Def::Variant(enum_did, variant_did) => {
let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);
match vinfo.kind() {
ty::VariantKind::Unit => {
}
}
}
- def::DefStruct(_) => {
+ Def::Struct(..) => {
if let ty::TyBareFn(..) = ety.sty {
// Tuple struct.
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
let def = cx.tcx().def_map.borrow()[&callee.id].full_def();
let arg_vals = try!(map_list(args));
match def {
- def::DefFn(did, _) | def::DefMethod(did) => {
+ Def::Fn(did) | Def::Method(did) => {
try!(const_fn_call(
cx,
ExprId(callee.id),
trueconst,
))
}
- def::DefStruct(_) => {
+ Def::Struct(..) => {
if ety.is_simd() {
C_vector(&arg_vals[..])
} else {
adt::trans_const(cx, &*repr, Disr(0), &arg_vals[..])
}
}
- def::DefVariant(enum_did, variant_did, _) => {
+ Def::Variant(enum_did, variant_did) => {
let repr = adt::represent_type(cx, ety);
let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);
adt::trans_const(cx,
// except according to those terms.
use llvm::ValueRef;
-use middle::def;
+use middle::def::Def;
use middle::lang_items::{PanicFnLangItem, PanicBoundsCheckFnLangItem};
use trans::base::*;
use trans::basic_block::BasicBlock;
None => fcx.top_loop_scope(),
Some(_) => {
match bcx.tcx().def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
- Some(def::DefLabel(loop_id)) => loop_id,
+ Some(Def::Label(loop_id)) => loop_id,
r => {
bcx.tcx().sess.bug(&format!("{:?} in def-map for label", r))
}
use back::abi;
use llvm::{self, ValueRef, TypeKind};
-use middle::check_const;
-use middle::def;
+use middle::const_qualif::ConstQualif;
+use middle::def::Def;
use middle::lang_items::CoerceUnsizedTraitLangItem;
use middle::subst::{Substs, VecPerParamSpace};
use middle::traits;
}
let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
- if !qualif.intersects(
- check_const::ConstQualif::NOT_CONST |
- check_const::ConstQualif::NEEDS_DROP
- ) {
- if !qualif.intersects(check_const::ConstQualif::PREFER_IN_PLACE) {
+ if !qualif.intersects(ConstQualif::NOT_CONST | ConstQualif::NEEDS_DROP) {
+ if !qualif.intersects(ConstQualif::PREFER_IN_PLACE) {
if let SaveIn(lldest) = dest {
match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
bcx.fcx.param_substs,
match expr.node {
hir::ExprPath(..) => {
match bcx.def(expr.id) {
- def::DefConst(did) => {
+ Def::Const(did) => {
let empty_substs = bcx.tcx().mk_substs(Substs::trans_empty());
let const_expr = consts::get_const_expr(bcx.ccx(), did, expr,
empty_substs);
let mut bcx = bcx;
let fcx = bcx.fcx;
let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
- let adjusted_global = !qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS);
- let global = if !qualif.intersects(
- check_const::ConstQualif::NOT_CONST |
- check_const::ConstQualif::NEEDS_DROP
- ) {
+ let adjusted_global = !qualif.intersects(ConstQualif::NON_STATIC_BORROWS);
+ let global = if !qualif.intersects(ConstQualif::NOT_CONST | ConstQualif::NEEDS_DROP) {
match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
bcx.fcx.param_substs,
consts::TrueConst::No) {
Ok(global) => {
- if qualif.intersects(check_const::ConstQualif::HAS_STATIC_BORROWS) {
+ if qualif.intersects(ConstQualif::HAS_STATIC_BORROWS) {
// Is borrowed as 'static, must return lvalue.
// Cast pointer to global, because constants have different types.
fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ref_expr: &hir::Expr,
- def: def::Def)
+ def: Def)
-> DatumBlock<'blk, 'tcx, Expr> {
//! Translates a reference to a path.
let _icx = push_ctxt("trans_def_lvalue");
match def {
- def::DefFn(..) | def::DefMethod(..) |
- def::DefStruct(_) | def::DefVariant(..) => {
+ Def::Fn(..) | Def::Method(..) |
+ Def::Struct(..) | Def::Variant(..) => {
let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def,
bcx.fcx.param_substs);
DatumBlock::new(bcx, datum.to_expr_datum())
}
- def::DefStatic(did, _) => {
+ Def::Static(did, _) => {
let const_ty = expr_ty(bcx, ref_expr);
let val = get_static_val(bcx.ccx(), did, const_ty);
let lval = Lvalue::new("expr::trans_def");
DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr(lval)))
}
- def::DefConst(_) => {
+ Def::Const(_) => {
bcx.sess().span_bug(ref_expr.span,
"constant expression should not reach expr::trans_def")
}
fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ref_expr: &hir::Expr,
- def: def::Def,
+ def: Def,
dest: Dest)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_def_dps_unadjusted");
};
match def {
- def::DefVariant(tid, vid, _) => {
+ Def::Variant(tid, vid) => {
let variant = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
if let ty::VariantKind::Tuple = variant.kind() {
// N-ary variant.
return bcx;
}
}
- def::DefStruct(_) => {
+ Def::Struct(..) => {
let ty = expr_ty(bcx, ref_expr);
match ty.sty {
ty::TyStruct(def, _) if def.has_dtor() => {
pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ref_expr: &hir::Expr,
- def: def::Def,
+ def: Def,
param_substs: &'tcx Substs<'tcx>)
-> Datum<'tcx, Rvalue> {
let _icx = push_ctxt("trans_def_datum_unadjusted");
match def {
- def::DefFn(did, _) |
- def::DefStruct(did) | def::DefVariant(_, did, _) => {
+ Def::Fn(did) |
+ Def::Struct(did) | Def::Variant(_, did) => {
callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs)
}
- def::DefMethod(method_did) => {
+ Def::Method(method_did) => {
match ccx.tcx().impl_or_trait_item(method_did).container() {
ty::ImplContainer(_) => {
callee::trans_fn_ref(ccx, method_did,
/// Translates a reference to a local variable or argument. This always results in an lvalue datum.
pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- def: def::Def)
+ def: Def)
-> Datum<'tcx, Lvalue> {
let _icx = push_ctxt("trans_local_var");
match def {
- def::DefUpvar(_, nid, _, _) => {
+ Def::Upvar(_, nid, _, _) => {
// Can't move upvars, so this is never a ZeroMemLastUse.
let local_ty = node_id_type(bcx, nid);
let lval = Lvalue::new_with_hint("expr::trans_local_var (upvar)",
}
}
}
- def::DefLocal(_, nid) => {
+ Def::Local(_, nid) => {
let datum = match bcx.fcx.lllocals.borrow().get(&nid) {
Some(&v) => v,
None => {
match expr.node {
hir::ExprPath(..) => {
match tcx.resolve_expr(expr) {
- def::DefStruct(_) | def::DefVariant(..) => {
+ Def::Struct(..) | Def::Variant(..) => {
if let ty::TyBareFn(..) = tcx.node_id_to_type(expr.id).sty {
// ctor function
ExprKind::RvalueDatum
}
}
- // Special case: A unit like struct's constructor must be called without () at the
- // end (like `UnitStruct`) which means this is an ExprPath to a DefFn. But in case
- // of unit structs this is should not be interpreted as function pointer but as
- // call to the constructor.
- def::DefFn(_, true) => ExprKind::RvalueDps,
-
// Fn pointers are just scalar values.
- def::DefFn(..) | def::DefMethod(..) => ExprKind::RvalueDatum,
+ Def::Fn(..) | Def::Method(..) => ExprKind::RvalueDatum,
// Note: there is actually a good case to be made that
// DefArg's, particularly those of immediate type, ought to
// considered rvalues.
- def::DefStatic(..) |
- def::DefUpvar(..) |
- def::DefLocal(..) => ExprKind::Lvalue,
+ Def::Static(..) |
+ Def::Upvar(..) |
+ Def::Local(..) => ExprKind::Lvalue,
- def::DefConst(..) |
- def::DefAssociatedConst(..) => ExprKind::RvalueDatum,
+ Def::Const(..) |
+ Def::AssociatedConst(..) => ExprKind::RvalueDatum,
def => {
tcx.sess.span_bug(
use trans::type_::Type;
use trans::type_of::*;
use trans::type_of;
-use trans::Disr;
use middle::infer;
use middle::ty::{self, Ty};
use middle::subst::Substs;
llarg_rust
} else {
if passed_arg_tys[i].is_bool() {
- let val = LoadRangeAssert(bcx, llarg_rust, Disr(0), Disr(2), llvm::False);
+ let val = LoadRangeAssert(bcx, llarg_rust, 0, 2, llvm::False);
Trunc(bcx, val, Type::i1(bcx.ccx()))
} else {
Load(bcx, llarg_rust)
// except according to those terms.
use llvm::{BasicBlockRef, ValueRef};
+use rustc::middle::ty;
use rustc::mir::repr as mir;
+use syntax::abi::Abi;
use trans::adt;
+use trans::attributes;
use trans::base;
use trans::build;
-use trans::attributes;
use trans::common::{self, Block};
use trans::debuginfo::DebugLoc;
+use trans::foreign;
use trans::type_of;
use trans::type_::Type;
use trans::Disr;
// The else branch of the Switch can't be hit, so branch to an unreachable
// instruction so LLVM knows that
let unreachable_blk = self.unreachable_block();
-
let switch = build::Switch(bcx, discr, unreachable_blk.llbb, targets.len());
assert_eq!(adt_def.variants.len(), targets.len());
for (adt_variant, target) in adt_def.variants.iter().zip(targets) {
let debugloc = DebugLoc::None;
// The arguments we'll be passing. Plus one to account for outptr, if used.
let mut llargs = Vec::with_capacity(args.len() + 1);
+ // Types of the arguments. We do not preallocate, because this vector is only
+ // filled when `is_foreign` is `true` and foreign calls are minority of the cases.
+ let mut arg_tys = Vec::new();
+
+ // Foreign-ABI functions are translated differently
+ let is_foreign = if let ty::TyBareFn(_, ref f) = callee.ty.sty {
+ // We do not translate intrinsics here (they shouldn’t be functions)
+ assert!(f.abi != Abi::RustIntrinsic && f.abi != Abi::PlatformIntrinsic);
+ f.abi != Abi::Rust && f.abi != Abi::RustCall
+ } else {
+ false
+ };
// Prepare the return value destination
let (ret_dest_ty, must_copy_dest) = if let Some(d) = kind.destination() {
let dest = self.trans_lvalue(bcx, d);
let ret_ty = dest.ty.to_ty(bcx.tcx());
- if type_of::return_uses_outptr(bcx.ccx(), ret_ty) {
+ if !is_foreign && type_of::return_uses_outptr(bcx.ccx(), ret_ty) {
llargs.push(dest.llval);
(Some((dest, ret_ty)), false)
} else {
// Process the rest of the args.
for arg in args {
- match self.trans_operand(bcx, arg).val {
+ let operand = self.trans_operand(bcx, arg);
+ match operand.val {
Ref(llval) | Immediate(llval) => llargs.push(llval),
FatPtr(b, e) => {
llargs.push(b);
llargs.push(e);
}
}
+ if is_foreign {
+ arg_tys.push(operand.ty);
+ }
}
// Many different ways to call a function handled here
- match (base::avoid_invoke(bcx), kind) {
+ match (is_foreign, base::avoid_invoke(bcx), kind) {
// The two cases below are the only ones to use LLVM’s `invoke`.
- (false, &mir::CallKind::DivergingCleanup(cleanup)) => {
+ (false, false, &mir::CallKind::DivergingCleanup(cleanup)) => {
let cleanup = self.bcx(cleanup);
let landingpad = self.make_landing_pad(cleanup);
+ let unreachable_blk = self.unreachable_block();
build::Invoke(bcx,
callee.immediate(),
&llargs[..],
- self.unreachable_block().llbb,
+ unreachable_blk.llbb,
landingpad.llbb,
Some(attrs),
debugloc);
},
- (false, &mir::CallKind::ConvergingCleanup { ref targets, .. }) => {
+ (false, false, &mir::CallKind::ConvergingCleanup { ref targets, .. }) => {
let cleanup = self.bcx(targets.1);
let landingpad = self.make_landing_pad(cleanup);
let (target, postinvoke) = if must_copy_dest {
build::Br(target, postinvoketarget.llbb, debugloc);
}
},
- (_, &mir::CallKind::DivergingCleanup(_)) |
- (_, &mir::CallKind::Diverging) => {
+ (false, _, &mir::CallKind::DivergingCleanup(_)) |
+ (false, _, &mir::CallKind::Diverging) => {
build::Call(bcx, callee.immediate(), &llargs[..], Some(attrs), debugloc);
build::Unreachable(bcx);
}
- (_, k@&mir::CallKind::ConvergingCleanup { .. }) |
- (_, k@&mir::CallKind::Converging { .. }) => {
- // Bug #20046
+ (false, _, k@&mir::CallKind::ConvergingCleanup { .. }) |
+ (false, _, k@&mir::CallKind::Converging { .. }) => {
+ // FIXME: Bug #20046
let target = match *k {
mir::CallKind::ConvergingCleanup { targets, .. } => targets.0,
mir::CallKind::Converging { target, .. } => target,
}
build::Br(bcx, self.llblock(target), debugloc);
}
+ // Foreign functions
+ (true, _, k) => {
+ let (dest, _) = ret_dest_ty
+ .expect("return destination is not set");
+ bcx = foreign::trans_native_call(bcx,
+ callee.ty,
+ callee.immediate(),
+ dest.llval,
+ &llargs[..],
+ arg_tys,
+ debugloc);
+ match *k {
+ mir::CallKind::ConvergingCleanup { targets, .. } =>
+ build::Br(bcx, self.llblock(targets.0), debugloc),
+ mir::CallKind::Converging { target, .. } =>
+ build::Br(bcx, self.llblock(target), debugloc),
+ _ => ()
+ };
+ },
}
}
}
use middle::astconv_util::{prim_ty_to_ty, prohibit_type_params, prohibit_projection};
use middle::const_eval::{self, ConstVal};
use middle::const_eval::EvalHint::UncheckedExprHint;
-use middle::def;
+use middle::def::{self, Def};
use middle::def_id::DefId;
use middle::resolve_lifetime as rl;
use middle::privacy::{AllPublic, LastMod};
fn trait_def_id<'tcx>(this: &AstConv<'tcx>, trait_ref: &hir::TraitRef) -> DefId {
let path = &trait_ref.path;
match ::lookup_full_def(this.tcx(), path.span, trait_ref.ref_id) {
- def::DefTrait(trait_def_id) => trait_def_id,
- def::DefErr => {
+ Def::Trait(trait_def_id) => trait_def_id,
+ Def::Err => {
this.tcx().sess.fatal("cannot continue compilation due to previous error");
}
_ => {
_ => None
};
match def {
- Some(def::DefTrait(trait_def_id)) => {
+ Some(Def::Trait(trait_def_id)) => {
let mut projection_bounds = Vec::new();
let trait_ref = object_path_to_poly_trait_ref(this,
rscope,
fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
span: Span,
ty: Ty<'tcx>,
- ty_path_def: def::Def,
+ ty_path_def: Def,
item_segment: &hir::PathSegment)
- -> (Ty<'tcx>, def::Def)
+ -> (Ty<'tcx>, Def)
{
let tcx = this.tcx();
let assoc_name = item_segment.identifier.name;
// Find the type of the associated item, and the trait where the associated
// item is declared.
let bound = match (&ty.sty, ty_path_def) {
- (_, def::DefSelfTy(Some(trait_did), Some((impl_id, _)))) => {
+ (_, Def::SelfTy(Some(trait_did), Some((impl_id, _)))) => {
// `Self` in an impl of a trait - we have a concrete self type and a
// trait reference.
let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap();
Err(ErrorReported) => return (tcx.types.err, ty_path_def),
}
}
- (&ty::TyParam(_), def::DefSelfTy(Some(trait_did), None)) => {
+ (&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => {
let trait_node_id = tcx.map.as_local_node_id(trait_did).unwrap();
match find_bound_for_assoc_item(this,
trait_node_id,
Err(ErrorReported) => return (tcx.types.err, ty_path_def),
}
}
- (&ty::TyParam(_), def::DefTyParam(_, _, param_did, param_name)) => {
+ (&ty::TyParam(_), Def::TyParam(_, _, param_did, param_name)) => {
let param_node_id = tcx.map.as_local_node_id(param_did).unwrap();
match find_bound_for_assoc_item(this,
param_node_id,
item.expect("missing associated type").def_id()
};
- (ty, def::DefAssociatedTy(trait_did, item_did))
+ (ty, Def::AssociatedTy(trait_did, item_did))
}
fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
param_mode: PathParamMode,
- def: &def::Def,
+ def: &Def,
opt_self_ty: Option<Ty<'tcx>>,
base_segments: &[hir::PathSegment])
-> Ty<'tcx> {
let tcx = this.tcx();
match *def {
- def::DefTrait(trait_def_id) => {
+ Def::Trait(trait_def_id) => {
// N.B. this case overlaps somewhat with
// TyObjectSum, see that fn for details
let mut projection_bounds = Vec::new();
projection_bounds,
&[])
}
- def::DefTy(did, _) | def::DefStruct(did) => {
+ Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
prohibit_type_params(tcx, base_segments.split_last().unwrap().1);
ast_path_to_ty(this,
rscope,
did,
base_segments.last().unwrap())
}
- def::DefTyParam(space, index, _, name) => {
+ Def::TyParam(space, index, _, name) => {
prohibit_type_params(tcx, base_segments);
tcx.mk_param(space, index, name)
}
- def::DefSelfTy(_, Some((_, self_ty_id))) => {
+ Def::SelfTy(_, Some((_, self_ty_id))) => {
// Self in impl (we know the concrete type).
prohibit_type_params(tcx, base_segments);
if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&self_ty_id) {
tcx.sess.span_bug(span, "self type has not been fully resolved")
}
}
- def::DefSelfTy(Some(_), None) => {
+ Def::SelfTy(Some(_), None) => {
// Self in trait.
prohibit_type_params(tcx, base_segments);
tcx.mk_self_type()
}
- def::DefAssociatedTy(trait_did, _) => {
+ Def::AssociatedTy(trait_did, _) => {
prohibit_type_params(tcx, &base_segments[..base_segments.len()-2]);
qpath_to_ty(this,
rscope,
&base_segments[base_segments.len()-2],
base_segments.last().unwrap())
}
- def::DefMod(id) => {
+ Def::Mod(id) => {
// Used as sentinel by callers to indicate the `<T>::A::B::C` form.
// FIXME(#22519) This part of the resolution logic should be
// avoided entirely for that form, once we stop needed a Def
opt_self_ty.expect("missing T in <T>::a::b::c")
}
- def::DefPrimTy(prim_ty) => {
+ Def::PrimTy(prim_ty) => {
prim_ty_to_ty(tcx, base_segments, prim_ty)
}
- def::DefErr => {
+ Def::Err => {
return this.tcx().types.err;
}
_ => {
rscope: &RegionScope,
span: Span,
param_mode: PathParamMode,
- def: &def::Def,
+ def: &Def,
opt_self_ty: Option<Ty<'tcx>>,
base_segments: &[hir::PathSegment],
assoc_segments: &[hir::PathSegment])
} else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
// Create some fake resolution that can't possibly be a type.
def::PathResolution {
- base_def: def::DefMod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
+ base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
last_private: LastMod(AllPublic),
depth: path.segments.len()
}
match *ast_bound {
hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => {
match ::lookup_full_def(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) {
- def::DefTrait(trait_did) => {
+ Def::Trait(trait_did) => {
if tcx.try_add_builtin_trait(trait_did,
&mut builtin_bounds) {
let segments = &b.trait_ref.path.segments;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use middle::def;
+use middle::def::{self, Def};
use middle::infer::{self, TypeOrigin};
use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
use middle::pat_util::pat_is_resolved_const;
hir::PatQPath(ref qself, ref path) => {
let self_ty = fcx.to_ty(&qself.ty);
let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) {
- if d.base_def == def::DefErr {
+ if d.base_def == Def::Err {
fcx.write_error(pat.id);
return;
}
// This is just a sentinel for finish_resolving_def_to_ty.
let sentinel = fcx.tcx().map.local_def_id(ast::CRATE_NODE_ID);
def::PathResolution {
- base_def: def::DefMod(sentinel),
+ base_def: Def::Mod(sentinel),
last_private: LastMod(AllPublic),
depth: path.segments.len()
}
// subtyping.
}
-fn check_assoc_item_is_const(pcx: &pat_ctxt, def: def::Def, span: Span) -> bool {
+fn check_assoc_item_is_const(pcx: &pat_ctxt, def: Def, span: Span) -> bool {
match def {
- def::DefAssociatedConst(..) => true,
- def::DefMethod(..) => {
+ Def::AssociatedConst(..) => true,
+ Def::Method(..) => {
span_err!(pcx.fcx.ccx.tcx.sess, span, E0327,
"associated items in match patterns must be constants");
false
let tcx = pcx.fcx.ccx.tcx;
let path_res = match tcx.def_map.borrow().get(&pat.id) {
- Some(&path_res) if path_res.base_def != def::DefErr => path_res,
+ Some(&path_res) if path_res.base_def != Def::Err => path_res,
_ => {
fcx.write_error(pat.id);
let real_path_ty = fcx.node_ty(pat.id);
let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
- ty::TyEnum(enum_def, expected_substs)
- if def == def::DefVariant(enum_def.did, def.def_id(), false) =>
- {
+ ty::TyEnum(enum_def, expected_substs) => {
let variant = enum_def.variant_of_def(def);
+ if variant.kind() == ty::VariantKind::Struct {
+ report_bad_struct_kind(false);
+ return;
+ }
if is_tuple_struct_pat && variant.kind() != ty::VariantKind::Tuple {
// Matching unit variants with tuple variant patterns (`UnitVariant(..)`)
// is allowed for backward compatibility.
use CrateCtxt;
use middle::cstore::LOCAL_CRATE;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::infer;
use middle::ty::{self, LvaluePreference, Ty};
if let hir::ExprCall(ref expr, _) = call_expr.node {
let tcx = fcx.tcx();
if let Some(pr) = tcx.def_map.borrow().get(&expr.id) {
- if pr.depth == 0 && pr.base_def != def::DefErr {
+ if pr.depth == 0 && pr.base_def != Def::Err {
if let Some(span) = tcx.map.span_if_local(pr.def_id()) {
err.span_note(span, "defined here");
}
use astconv::AstConv;
use check::FnCtxt;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod};
use middle::subst;
method_name: ast::Name,
self_ty: ty::Ty<'tcx>,
expr_id: ast::NodeId)
- -> Result<(def::Def, LastPrivate), MethodError<'tcx>>
+ -> Result<(Def, LastPrivate), MethodError<'tcx>>
{
let mode = probe::Mode::Path;
let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
}
}
let def_result = match pick.item {
- ty::ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id),
- ty::ImplOrTraitItem::ConstTraitItem(..) => def::DefAssociatedConst(def_id),
+ ty::ImplOrTraitItem::MethodTraitItem(..) => Def::Method(def_id),
+ ty::ImplOrTraitItem::ConstTraitItem(..) => Def::AssociatedConst(def_id),
ty::ImplOrTraitItem::TypeTraitItem(..) => {
fcx.tcx().sess.span_bug(span, "resolve_ufcs: probe picked associated type");
}
use front::map as hir_map;
use middle::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
use middle::cstore::{self, CrateStore, DefLike};
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::lang_items::FnOnceTraitLangItem;
use middle::subst::Substs;
cstore: &for<'a> cstore::CrateStore<'a>,
dl: cstore::DefLike) {
match dl {
- cstore::DlDef(def::DefTrait(did)) => {
+ cstore::DlDef(Def::Trait(did)) => {
traits.push(TraitInfo::new(did));
}
- cstore::DlDef(def::DefMod(did)) => {
+ cstore::DlDef(Def::Mod(did)) => {
if !external_mods.insert(did) {
return;
}
use fmt_macros::{Parser, Piece, Position};
use middle::astconv_util::prohibit_type_params;
use middle::cstore::LOCAL_CRATE;
-use middle::def;
+use middle::def::{self, Def};
use middle::def_id::DefId;
use middle::infer;
use middle::infer::{TypeOrigin, type_variable};
/// Return the dict-like variant corresponding to a given `Def`.
pub fn def_struct_variant(&self,
- def: def::Def,
+ def: Def,
span: Span)
-> Option<(ty::AdtDef<'tcx>, ty::VariantDef<'tcx>)>
{
let (adt, variant) = match def {
- def::DefVariant(enum_id, variant_id, _) => {
+ Def::Variant(enum_id, variant_id) => {
let adt = self.tcx().lookup_adt_def(enum_id);
(adt, adt.variant_with_id(variant_id))
}
- def::DefTy(did, _) | def::DefStruct(did) => {
+ Def::Struct(did) | Def::TyAlias(did) => {
let typ = self.tcx().lookup_item_type(did);
if let ty::TyStruct(adt, _) = typ.ty.sty {
(adt, adt.struct_variant())
// Find the relevant variant
let def = lookup_full_def(tcx, path.span, expr.id);
- if def == def::DefErr {
+ if def == Def::Err {
check_struct_fields_on_error(fcx, expr.id, fields, base_expr);
return;
}
} else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
// Create some fake resolution that can't possibly be a type.
def::PathResolution {
- base_def: def::DefMod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
+ base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
last_private: LastMod(AllPublic),
depth: path.segments.len()
}
if let Some((opt_ty, segments, def)) =
resolve_ty_and_def_ufcs(fcx, path_res, opt_self_ty, path,
expr.span, expr.id) {
- if def != def::DefErr {
+ if def != Def::Err {
let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx,
expr.span,
def);
node_id: ast::NodeId)
-> Option<(Option<Ty<'tcx>>,
&'a [hir::PathSegment],
- def::Def)>
+ Def)>
{
// If fully resolved already, we don't have to do anything.
// Returns the type parameter count and the type for the given definition.
fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
sp: Span,
- defn: def::Def)
+ defn: Def)
-> (TypeScheme<'tcx>, GenericPredicates<'tcx>) {
match defn {
- def::DefLocal(_, nid) | def::DefUpvar(_, nid, _, _) => {
+ Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => {
let typ = fcx.local_ty(sp, nid);
(ty::TypeScheme { generics: ty::Generics::empty(), ty: typ },
ty::GenericPredicates::empty())
}
- def::DefFn(id, _) | def::DefMethod(id) |
- def::DefStatic(id, _) | def::DefVariant(_, id, _) |
- def::DefStruct(id) | def::DefConst(id) | def::DefAssociatedConst(id) => {
+ Def::Fn(id) | Def::Method(id) |
+ Def::Static(id, _) | Def::Variant(_, id) |
+ Def::Struct(id) | Def::Const(id) | Def::AssociatedConst(id) => {
(fcx.tcx().lookup_item_type(id), fcx.tcx().lookup_predicates(id))
}
- def::DefTrait(_) |
- def::DefTy(..) |
- def::DefAssociatedTy(..) |
- def::DefPrimTy(_) |
- def::DefTyParam(..) |
- def::DefMod(..) |
- def::DefForeignMod(..) |
- def::DefLabel(..) |
- def::DefSelfTy(..) |
- def::DefErr => {
+ Def::Trait(_) |
+ Def::Enum(..) |
+ Def::TyAlias(..) |
+ Def::AssociatedTy(..) |
+ Def::PrimTy(_) |
+ Def::TyParam(..) |
+ Def::Mod(..) |
+ Def::ForeignMod(..) |
+ Def::Label(..) |
+ Def::SelfTy(..) |
+ Def::Err => {
fcx.ccx.tcx.sess.span_bug(sp, &format!("expected value, found {:?}", defn));
}
}
type_scheme: TypeScheme<'tcx>,
type_predicates: &ty::GenericPredicates<'tcx>,
opt_self_ty: Option<Ty<'tcx>>,
- def: def::Def,
+ def: Def,
span: Span,
node_id: ast::NodeId) {
debug!("instantiate_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})",
let mut segment_spaces: Vec<_>;
match def {
// Case 1 and 1b. Reference to a *type* or *enum variant*.
- def::DefSelfTy(..) |
- def::DefStruct(..) |
- def::DefVariant(..) |
- def::DefTy(..) |
- def::DefAssociatedTy(..) |
- def::DefTrait(..) |
- def::DefPrimTy(..) |
- def::DefTyParam(..) => {
+ Def::SelfTy(..) |
+ Def::Struct(..) |
+ Def::Variant(..) |
+ Def::Enum(..) |
+ Def::TyAlias(..) |
+ Def::AssociatedTy(..) |
+ Def::Trait(..) |
+ Def::PrimTy(..) |
+ Def::TyParam(..) => {
// Everything but the final segment should have no
// parameters at all.
segment_spaces = vec![None; segments.len() - 1];
}
// Case 2. Reference to a top-level value.
- def::DefFn(..) |
- def::DefConst(..) |
- def::DefStatic(..) => {
+ Def::Fn(..) |
+ Def::Const(..) |
+ Def::Static(..) => {
segment_spaces = vec![None; segments.len() - 1];
segment_spaces.push(Some(subst::FnSpace));
}
// Case 3. Reference to a method.
- def::DefMethod(def_id) => {
+ Def::Method(def_id) => {
let container = fcx.tcx().impl_or_trait_item(def_id).container();
match container {
ty::TraitContainer(trait_did) => {
}
}
- def::DefAssociatedConst(def_id) => {
+ Def::AssociatedConst(def_id) => {
let container = fcx.tcx().impl_or_trait_item(def_id).container();
match container {
ty::TraitContainer(trait_did) => {
// Other cases. Various nonsense that really shouldn't show up
// here. If they do, an error will have been reported
// elsewhere. (I hope)
- def::DefMod(..) |
- def::DefForeignMod(..) |
- def::DefLocal(..) |
- def::DefLabel(..) |
- def::DefUpvar(..) |
- def::DefErr => {
+ Def::Mod(..) |
+ Def::ForeignMod(..) |
+ Def::Local(..) |
+ Def::Label(..) |
+ Def::Upvar(..) |
+ Def::Err => {
segment_spaces = vec![None; segments.len()];
}
}
// <id> nested anywhere inside the loop?
(block_query(b, |e| {
if let hir::ExprBreak(Some(_)) = e.node {
- lookup_full_def(cx, e.span, e.id) == def::DefLabel(id)
+ lookup_full_def(cx, e.span, e.id) == Def::Label(id)
} else {
false
}
use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region};
use lint;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use constrained_type_params as ctp;
use middle::lang_items::SizedTraitLangItem;
if let hir::TyPath(None, _) = ast_ty.node {
let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap();
match path_res.base_def {
- def::DefSelfTy(Some(def_id), None) => {
+ Def::SelfTy(Some(def_id), None) => {
path_res.depth == 0 && def_id == tcx.map.local_def_id(param_id)
}
- def::DefTyParam(_, _, def_id, _) => {
+ Def::TyParam(_, _, def_id, _) => {
path_res.depth == 0 && def_id == tcx.map.local_def_id(param_id)
}
_ => {
name: name,
disr_val: disr_val,
fields: fields,
- kind: match *def {
- hir::VariantData::Struct(..) => ty::VariantKind::Struct,
- hir::VariantData::Tuple(..) => ty::VariantKind::Tuple,
- hir::VariantData::Unit(..) => ty::VariantKind::Unit,
- }
+ kind: VariantKind::from_variant_data(def),
}
}
pub use rustc::util;
use front::map as hir_map;
-use middle::def;
+use middle::def::Def;
use middle::infer::{self, TypeOrigin};
use middle::subst;
use middle::ty::{self, Ty, TypeFoldable};
}
}
-fn lookup_full_def(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def {
+fn lookup_full_def(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) -> Def {
match tcx.def_map.borrow().get(&id) {
Some(x) => x.full_def(),
None => {
use rustc_front::hir;
use rustc::middle::cstore::{self, CrateStore};
-use rustc::middle::def;
+use rustc::middle::def::Def;
use rustc::middle::def_id::DefId;
use rustc::middle::ty;
use rustc::middle::subst;
}
fn try_inline_def(cx: &DocContext, tcx: &ty::ctxt,
- def: def::Def) -> Option<Vec<clean::Item>> {
+ def: Def) -> Option<Vec<clean::Item>> {
let mut ret = Vec::new();
let did = def.def_id();
let inner = match def {
- def::DefTrait(did) => {
+ Def::Trait(did) => {
record_extern_fqn(cx, did, clean::TypeTrait);
clean::TraitItem(build_external_trait(cx, tcx, did))
}
- def::DefFn(did, false) => {
- // If this function is a tuple struct constructor, we just skip it
+ Def::Fn(did) => {
record_extern_fqn(cx, did, clean::TypeFunction);
clean::FunctionItem(build_external_function(cx, tcx, did))
}
- def::DefStruct(did) => {
+ Def::Struct(did)
+ // If this is a struct constructor, we skip it
+ if tcx.sess.cstore.tuple_struct_definition_if_ctor(did).is_none() => {
record_extern_fqn(cx, did, clean::TypeStruct);
ret.extend(build_impls(cx, tcx, did));
clean::StructItem(build_struct(cx, tcx, did))
}
- def::DefTy(did, false) => {
+ Def::TyAlias(did) => {
record_extern_fqn(cx, did, clean::TypeTypedef);
ret.extend(build_impls(cx, tcx, did));
build_type(cx, tcx, did)
}
- def::DefTy(did, true) => {
+ Def::Enum(did) => {
record_extern_fqn(cx, did, clean::TypeEnum);
ret.extend(build_impls(cx, tcx, did));
build_type(cx, tcx, did)
}
// Assume that the enum type is reexported next to the variant, and
// variants don't show up in documentation specially.
- def::DefVariant(..) => return Some(Vec::new()),
- def::DefMod(did) => {
+ Def::Variant(..) => return Some(Vec::new()),
+ Def::Mod(did) => {
record_extern_fqn(cx, did, clean::TypeModule);
clean::ModuleItem(build_module(cx, tcx, did))
}
- def::DefStatic(did, mtbl) => {
+ Def::Static(did, mtbl) => {
record_extern_fqn(cx, did, clean::TypeStatic);
clean::StaticItem(build_static(cx, tcx, did, mtbl))
}
- def::DefConst(did) | def::DefAssociatedConst(did) => {
+ Def::Const(did) | Def::AssociatedConst(did) => {
record_extern_fqn(cx, did, clean::TypeConst);
clean::ConstantItem(build_const(cx, tcx, did))
}
impls: &mut Vec<clean::Item>) {
match def {
cstore::DlImpl(did) => build_impl(cx, tcx, did, impls),
- cstore::DlDef(def::DefMod(did)) => {
+ cstore::DlDef(Def::Mod(did)) => {
for item in tcx.sess.cstore.item_children(did) {
populate_impls(cx, tcx, item.def, impls)
}
let mut visited = HashSet::new();
for item in tcx.sess.cstore.item_children(did) {
match item.def {
- cstore::DlDef(def::DefForeignMod(did)) => {
+ cstore::DlDef(Def::ForeignMod(did)) => {
fill_in(cx, tcx, did, items);
}
cstore::DlDef(def) if item.vis == hir::Public => {
use rustc_trans::back::link;
use rustc::middle::cstore::{self, CrateStore};
-use rustc::middle::def;
+use rustc::middle::def::Def;
use rustc::middle::def_id::{DefId, DefIndex};
use rustc::middle::subst::{self, ParamSpace, VecPerParamSpace};
use rustc::middle::ty;
cx.tcx_opt().map(|tcx| {
for item in tcx.sess.cstore.crate_top_level_items(self.0) {
let did = match item.def {
- cstore::DlDef(def::DefMod(did)) => did,
+ cstore::DlDef(Def::Mod(did)) => did,
_ => continue
};
let attrs = inline::load_attrs(cx, tcx, did);
debug!("resolve_type: def={:?}", def);
let is_generic = match def {
- def::DefPrimTy(p) => match p {
+ Def::PrimTy(p) => match p {
hir::TyStr => return Primitive(Str),
hir::TyBool => return Primitive(Bool),
hir::TyChar => return Primitive(Char),
hir::TyFloat(ast::TyF32) => return Primitive(F32),
hir::TyFloat(ast::TyF64) => return Primitive(F64),
},
- def::DefSelfTy(..) if path.segments.len() == 1 => {
+ Def::SelfTy(..) if path.segments.len() == 1 => {
return Generic(special_idents::type_self.name.to_string());
}
- def::DefSelfTy(..) | def::DefTyParam(..) => true,
+ Def::SelfTy(..) | Def::TyParam(..) => true,
_ => false,
};
let did = register_def(&*cx, def);
ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic }
}
-fn register_def(cx: &DocContext, def: def::Def) -> DefId {
+fn register_def(cx: &DocContext, def: Def) -> DefId {
debug!("register_def({:?})", def);
let (did, kind) = match def {
- def::DefFn(i, _) => (i, TypeFunction),
- def::DefTy(i, false) => (i, TypeTypedef),
- def::DefTy(i, true) => (i, TypeEnum),
- def::DefTrait(i) => (i, TypeTrait),
- def::DefStruct(i) => (i, TypeStruct),
- def::DefMod(i) => (i, TypeModule),
- def::DefStatic(i, _) => (i, TypeStatic),
- def::DefVariant(i, _, _) => (i, TypeEnum),
- def::DefSelfTy(Some(def_id), _) => (def_id, TypeTrait),
- def::DefSelfTy(_, Some((impl_id, _))) => return cx.map.local_def_id(impl_id),
+ Def::Fn(i) => (i, TypeFunction),
+ Def::TyAlias(i) => (i, TypeTypedef),
+ Def::Enum(i) => (i, TypeEnum),
+ Def::Trait(i) => (i, TypeTrait),
+ Def::Struct(i) => (i, TypeStruct),
+ Def::Mod(i) => (i, TypeModule),
+ Def::Static(i, _) => (i, TypeStatic),
+ Def::Variant(i, _) => (i, TypeEnum),
+ Def::SelfTy(Some(def_id), _) => (def_id, TypeTrait),
+ Def::SelfTy(_, Some((impl_id, _))) => return cx.map.local_def_id(impl_id),
_ => return def.def_id()
};
if did.is_local() { return did }
}
impl OpenOptions {
- /// Creates a blank net set of options ready for configuration.
+ /// Creates a blank new set of options ready for configuration.
///
/// All options are initially set to `false`.
///
/// ```no_run
/// use std::fs::OpenOptions;
///
- /// let file = OpenOptions::new().open("foo.txt");
+ /// let mut options = OpenOptions::new();
+ /// let file = options.read(true).open("foo.txt");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> OpenOptions {
/// This option, when true, will indicate that the file should be
/// `write`-able if opened.
///
+ /// If a file already exist, any write calls on the file will overwrite its
+ /// contents, without truncating it.
+ ///
/// # Examples
///
/// ```no_run
///
/// This option, when true, means that writes will append to a file instead
/// of overwriting previous contents.
+ /// Note that setting `.write(true).append(true)` has the same effect as
+ /// setting only `.append(true)`.
+ ///
+ /// For most filesystems the operating system guarantees all writes are
+ /// atomic: no writes get mangled because another process writes at the same
+ /// time.
+ ///
+ /// One maybe obvious note when using append-mode: make sure that all data
+ /// that belongs together, is written the the file in one operation. This
+ /// can be done by concatenating strings before passing them to `write()`,
+ /// or using a buffered writer (with a more than adequately sized buffer)
+ /// and calling `flush()` when the message is complete.
+ ///
+ /// If a file is opened with both read and append access, beware that after
+ /// opening and after every write the position for reading may be set at the
+ /// end of the file. So before writing save the current position (using
+ /// `seek(SeekFrom::Current(0))`, and restore it before the next read.
///
/// # Examples
///
/// ```no_run
/// use std::fs::OpenOptions;
///
- /// let file = OpenOptions::new().write(true).append(true).open("foo.txt");
+ /// let file = OpenOptions::new().append(true).open("foo.txt");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn append(&mut self, append: bool) -> &mut OpenOptions {
/// If a file is successfully opened with this option set it will truncate
/// the file to 0 length if it already exists.
///
+ /// The file must be opened with write access for truncate to work.
+ ///
/// # Examples
///
/// ```no_run
/// This option indicates whether a new file will be created if the file
/// does not yet already exist.
///
+ /// The file must be opened with write or append access in order to create
+ /// a new file.
+ ///
/// # Examples
///
/// ```no_run
/// use std::fs::OpenOptions;
///
- /// let file = OpenOptions::new().create(true).open("foo.txt");
+ /// let file = OpenOptions::new().write(true).create(true).open("foo.txt");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn create(&mut self, create: bool) -> &mut OpenOptions {
self.0.create(create); self
}
+ /// Sets the option to always create a new file.
+ ///
+ /// This option indicates whether a new file will be created.
+ /// No file is allowed to exist at the target location, also no (dangling)
+ /// symlink.
+ ///
+ /// This option is usefull because it as atomic. Otherwise between checking
+ /// whether a file exists and creating a new one, the file may have been
+ /// created by another process (a TOCTOU race condition / attack).
+ ///
+ /// If `.create_new(true)` is set, `.create()` and `.truncate()` are
+ /// ignored.
+ ///
+ /// The file must be opened with write or append access in order to create
+ /// a new file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(expand_open_options)]
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().write(true)
+ /// .create_new(true)
+ /// .open("foo.txt");
+ /// ```
+ #[unstable(feature = "expand_open_options",
+ reason = "recently added",
+ issue = "30014")]
+ pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
+ self.0.create_new(create_new); self
+ }
+
/// Opens a file at `path` with the options specified by `self`.
///
/// # Errors
/// This function will return an error under a number of different
/// circumstances, to include but not limited to:
///
- /// * Opening a file that does not exist with read access.
+ /// * Opening a file that does not exist without setting `create` or
+ /// `create_new`.
/// * Attempting to open a file with access that the user lacks
/// permissions for
/// * Filesystem-level errors (full disk, etc)
+ /// * Invalid combinations of open options (truncate without write access,
+ /// no access mode set, etc)
///
/// # Examples
///
let mut r = OO::new(); r.read(true);
let mut w = OO::new(); w.write(true);
- let mut rw = OO::new(); rw.write(true).read(true);
-
- match r.open(&tmpdir.join("a")) {
- Ok(..) => panic!(), Err(..) => {}
- }
-
- // Perform each one twice to make sure that it succeeds the second time
- // (where the file exists)
- check!(c(&w).create(true).open(&tmpdir.join("b")));
- assert!(tmpdir.join("b").exists());
- check!(c(&w).create(true).open(&tmpdir.join("b")));
- check!(w.open(&tmpdir.join("b")));
-
+ let mut rw = OO::new(); rw.read(true).write(true);
+ let mut a = OO::new(); a.append(true);
+ let mut ra = OO::new(); ra.read(true).append(true);
+
+ let invalid_options = if cfg!(windows) { "The parameter is incorrect" }
+ else { "Invalid argument" };
+
+ // Test various combinations of creation modes and access modes.
+ //
+ // Allowed:
+ // creation mode | read | write | read-write | append | read-append |
+ // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:|
+ // not set (open existing) | X | X | X | X | X |
+ // create | | X | X | X | X |
+ // truncate | | X | X | | |
+ // create and truncate | | X | X | | |
+ // create_new | | X | X | X | X |
+ //
+ // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it.
+
+ // write-only
+ check!(c(&w).create_new(true).open(&tmpdir.join("a")));
+ check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a")));
+ check!(c(&w).truncate(true).open(&tmpdir.join("a")));
+ check!(c(&w).create(true).open(&tmpdir.join("a")));
+ check!(c(&w).open(&tmpdir.join("a")));
+
+ // read-only
+ error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options);
+ error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options);
+ error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options);
+ error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options);
+ check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only
+
+ // read-write
+ check!(c(&rw).create_new(true).open(&tmpdir.join("c")));
+ check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c")));
+ check!(c(&rw).truncate(true).open(&tmpdir.join("c")));
check!(c(&rw).create(true).open(&tmpdir.join("c")));
- assert!(tmpdir.join("c").exists());
- check!(c(&rw).create(true).open(&tmpdir.join("c")));
- check!(rw.open(&tmpdir.join("c")));
-
- check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
- assert!(tmpdir.join("d").exists());
- check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
- check!(c(&w).append(true).open(&tmpdir.join("d")));
-
- check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
- assert!(tmpdir.join("e").exists());
- check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
- check!(c(&rw).append(true).open(&tmpdir.join("e")));
-
- check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
- assert!(tmpdir.join("f").exists());
- check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
- check!(c(&w).truncate(true).open(&tmpdir.join("f")));
-
- check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
- assert!(tmpdir.join("g").exists());
- check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
- check!(c(&rw).truncate(true).open(&tmpdir.join("g")));
-
- check!(check!(File::create(&tmpdir.join("h"))).write("foo".as_bytes()));
+ check!(c(&rw).open(&tmpdir.join("c")));
+
+ // append
+ check!(c(&a).create_new(true).open(&tmpdir.join("d")));
+ error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options);
+ error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options);
+ check!(c(&a).create(true).open(&tmpdir.join("d")));
+ check!(c(&a).open(&tmpdir.join("d")));
+
+ // read-append
+ check!(c(&ra).create_new(true).open(&tmpdir.join("e")));
+ error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options);
+ error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options);
+ check!(c(&ra).create(true).open(&tmpdir.join("e")));
+ check!(c(&ra).open(&tmpdir.join("e")));
+
+ // Test opening a file without setting an access mode
+ let mut blank = OO::new();
+ error!(blank.create(true).open(&tmpdir.join("f")), invalid_options);
+
+ // Test write works
+ check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes()));
+
+ // Test write fails for read-only
check!(r.open(&tmpdir.join("h")));
{
let mut f = check!(r.open(&tmpdir.join("h")));
assert!(f.write("wut".as_bytes()).is_err());
}
+
+ // Test write overwrites
+ {
+ let mut f = check!(c(&w).open(&tmpdir.join("h")));
+ check!(f.write("baz".as_bytes()));
+ }
+ {
+ let mut f = check!(c(&r).open(&tmpdir.join("h")));
+ let mut b = vec![0; 6];
+ check!(f.read(&mut b));
+ assert_eq!(b, "bazbar".as_bytes());
+ }
+
+ // Test truncate works
+ {
+ let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
+ check!(f.write("foo".as_bytes()));
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
+
+ // Test append works
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
{
- let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
+ let mut f = check!(c(&a).open(&tmpdir.join("h")));
check!(f.write("bar".as_bytes()));
}
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
+
+ // Test .append(true) equals .write(true).append(true)
{
- let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
- check!(f.write("bar".as_bytes()));
+ let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
+ check!(f.write("baz".as_bytes()));
}
- assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9);
+ }
+
+ #[test]
+ fn _assert_send_sync() {
+ fn _assert_send_sync<T: Send + Sync>() {}
+ _assert_send_sync::<OpenOptions>();
}
#[test]
#[cfg(not(target_os = "linux"))]
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
- haystack.iter().rposition(|&b| b == needle)
+ fallback::memrchr(needle, haystack)
}
memrchr_specific(needle, haystack)
}
}
+#[stable(feature = "mpsc_debug", since = "1.7.0")]
+impl<T> fmt::Debug for Sender<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Sender {{ .. }}")
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// SyncSender
////////////////////////////////////////////////////////////////////////////////
}
}
+#[stable(feature = "mpsc_debug", since = "1.7.0")]
+impl<T> fmt::Debug for SyncSender<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "SyncSender {{ .. }}")
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// Receiver
////////////////////////////////////////////////////////////////////////////////
}
}
+#[stable(feature = "mpsc_debug", since = "1.7.0")]
+impl<T> fmt::Debug for Receiver<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Receiver {{ .. }}")
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> fmt::Debug for SendError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
repro()
}
}
+
+ #[test]
+ fn fmt_debug_sender() {
+ let (tx, _) = channel::<i32>();
+ assert_eq!(format!("{:?}", tx), "Sender { .. }");
+ }
+
+ #[test]
+ fn fmt_debug_recv() {
+ let (_, rx) = channel::<i32>();
+ assert_eq!(format!("{:?}", rx), "Receiver { .. }");
+ }
+
+ #[test]
+ fn fmt_debug_sync_sender() {
+ let (tx, _) = sync_channel::<i32>(1);
+ assert_eq!(format!("{:?}", tx), "SyncSender { .. }");
+ }
}
issue = "27800")]
+use fmt;
+
use core::cell::{Cell, UnsafeCell};
use core::marker;
use core::ptr;
}
}
+#[stable(feature = "mpsc_debug", since = "1.7.0")]
+impl fmt::Debug for Select {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Select {{ .. }}")
+ }
+}
+
+#[stable(feature = "mpsc_debug", since = "1.7.0")]
+impl<'rx, T:Send+'rx> fmt::Debug for Handle<'rx, T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Handle {{ .. }}")
+ }
+}
+
#[cfg(test)]
#[allow(unused_imports)]
mod tests {
}
}
}
+
+ #[test]
+ fn fmt_debug_select() {
+ let sel = Select::new();
+ assert_eq!(format!("{:?}", sel), "Select { .. }");
+ }
+
+ #[test]
+ fn fmt_debug_handle() {
+ let (_, rx) = channel::<i32>();
+ let sel = Select::new();
+ let mut handle = sel.handle(&rx);
+ assert_eq!(format!("{:?}", handle), "Handle { .. }");
+ }
}
///
/// If a new file is created as part of a `File::open_opts` call then this
/// specified `mode` will be used as the permission bits for the new file.
+ /// If no `mode` is set, the default of `0o666` will be used.
+ /// The operating system masks out bits with the systems `umask`, to produce
+ /// the final permissions.
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&mut self, mode: raw::mode_t) -> &mut Self;
+
+ /// Pass custom flags to the `flags` agument of `open`.
+ ///
+ /// The bits that define the access mode are masked out with `O_ACCMODE`, to
+ /// ensure they do not interfere with the access mode set by Rusts options.
+ ///
+ /// Custom flags can only set flags, not remove flags set by Rusts options.
+ /// This options overwrites any previously set custom flags.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// extern crate libc;
+ /// use std::fs::OpenOptions;
+ /// use std::os::unix::fs::OpenOptionsExt;
+ ///
+ /// let mut options = OpenOptions::new();
+ /// options.write(true);
+ /// if cfg!(unix) {
+ /// options.custom_flags(libc::O_NOFOLLOW);
+ /// }
+ /// let file = options.open("foo.txt");
+ /// ```
+ #[unstable(feature = "expand_open_options",
+ reason = "recently added",
+ issue = "30014")]
+ fn custom_flags(&mut self, flags: i32) -> &mut Self;
}
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&mut self, mode: raw::mode_t) -> &mut OpenOptions {
self.as_inner_mut().mode(mode); self
}
+
+ fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
+ self.as_inner_mut().custom_flags(flags); self
+ }
}
// Hm, why are there casts here to the returned type, shouldn't the types always
self
}
}
-
#[derive(Clone)]
pub struct OpenOptions {
- flags: c_int,
+ // generic
read: bool,
write: bool,
+ append: bool,
+ truncate: bool,
+ create: bool,
+ create_new: bool,
+ // system-specific
+ custom_flags: i32,
mode: mode_t,
}
impl OpenOptions {
pub fn new() -> OpenOptions {
OpenOptions {
- flags: libc::O_CLOEXEC,
+ // generic
read: false,
write: false,
+ append: false,
+ truncate: false,
+ create: false,
+ create_new: false,
+ // system-specific
+ custom_flags: 0,
mode: 0o666,
}
}
- pub fn read(&mut self, read: bool) {
- self.read = read;
- }
-
- pub fn write(&mut self, write: bool) {
- self.write = write;
- }
-
- pub fn append(&mut self, append: bool) {
- self.flag(libc::O_APPEND, append);
- }
-
- pub fn truncate(&mut self, truncate: bool) {
- self.flag(libc::O_TRUNC, truncate);
- }
-
- pub fn create(&mut self, create: bool) {
- self.flag(libc::O_CREAT, create);
- }
-
- pub fn mode(&mut self, mode: raw::mode_t) {
- self.mode = mode as mode_t;
+ pub fn read(&mut self, read: bool) { self.read = read; }
+ pub fn write(&mut self, write: bool) { self.write = write; }
+ pub fn append(&mut self, append: bool) { self.append = append; }
+ pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
+ pub fn create(&mut self, create: bool) { self.create = create; }
+ pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
+
+ pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; }
+ pub fn mode(&mut self, mode: raw::mode_t) { self.mode = mode as mode_t; }
+
+ fn get_access_mode(&self) -> io::Result<c_int> {
+ match (self.read, self.write, self.append) {
+ (true, false, false) => Ok(libc::O_RDONLY),
+ (false, true, false) => Ok(libc::O_WRONLY),
+ (true, true, false) => Ok(libc::O_RDWR),
+ (false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND),
+ (true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND),
+ (false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)),
+ }
}
- fn flag(&mut self, bit: c_int, on: bool) {
- if on {
- self.flags |= bit;
- } else {
- self.flags &= !bit;
+ fn get_creation_mode(&self) -> io::Result<c_int> {
+ match (self.write, self.append) {
+ (true, false) => {}
+ (false, false) =>
+ if self.truncate || self.create || self.create_new {
+ return Err(Error::from_raw_os_error(libc::EINVAL));
+ },
+ (_, true) =>
+ if self.truncate && !self.create_new {
+ return Err(Error::from_raw_os_error(libc::EINVAL));
+ },
}
+
+ Ok(match (self.create, self.truncate, self.create_new) {
+ (false, false, false) => 0,
+ (true, false, false) => libc::O_CREAT,
+ (false, true, false) => libc::O_TRUNC,
+ (true, true, false) => libc::O_CREAT | libc::O_TRUNC,
+ (_, _, true) => libc::O_CREAT | libc::O_EXCL,
+ })
}
}
}
pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
- let flags = opts.flags | match (opts.read, opts.write) {
- (true, true) => libc::O_RDWR,
- (false, true) => libc::O_WRONLY,
- (true, false) |
- (false, false) => libc::O_RDONLY,
- };
+ let flags = libc::O_CLOEXEC |
+ try!(opts.get_access_mode()) |
+ try!(opts.get_creation_mode()) |
+ (opts.custom_flags as c_int & !libc::O_ACCMODE);
let fd = try!(cvt_r(|| unsafe {
libc::open(path.as_ptr(), flags, opts.mode as c_int)
}));
pub const OPEN_ALWAYS: DWORD = 4;
pub const OPEN_EXISTING: DWORD = 3;
pub const TRUNCATE_EXISTING: DWORD = 5;
-pub const FILE_APPEND_DATA: DWORD = 0x00000004;
+
pub const FILE_READ_DATA: DWORD = 0x00000001;
pub const FILE_WRITE_DATA: DWORD = 0x00000002;
-pub const STANDARD_RIGHTS_READ: DWORD = 0x20000;
-pub const STANDARD_RIGHTS_WRITE: DWORD = 0x20000;
-pub const FILE_WRITE_EA: DWORD = 0x00000010;
+pub const FILE_APPEND_DATA: DWORD = 0x00000004;
pub const FILE_READ_EA: DWORD = 0x00000008;
-pub const SYNCHRONIZE: DWORD = 0x00100000;
-pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100;
+pub const FILE_WRITE_EA: DWORD = 0x00000010;
+pub const FILE_EXECUTE: DWORD = 0x00000020;
pub const FILE_READ_ATTRIBUTES: DWORD = 0x00000080;
+pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100;
+
+pub const DELETE: DWORD = 0x00008000;
+pub const READ_CONTROL: DWORD = 0x00020000;
+pub const WRITE_DAC: DWORD = 0x00040000;
+pub const WRITE_OWNER: DWORD = 0x00080000;
+pub const SYNCHRONIZE: DWORD = 0x00100000;
+
+pub const GENERIC_READ: DWORD = 0x80000000;
+pub const GENERIC_WRITE: DWORD = 0x40000000;
+pub const GENERIC_EXECUTE: DWORD = 0x20000000;
+pub const GENERIC_ALL: DWORD = 0x10000000;
+
+pub const STANDARD_RIGHTS_READ: DWORD = READ_CONTROL;
+pub const STANDARD_RIGHTS_WRITE: DWORD = READ_CONTROL;
+pub const STANDARD_RIGHTS_EXECUTE: DWORD = READ_CONTROL;
pub const FILE_GENERIC_READ: DWORD = STANDARD_RIGHTS_READ | FILE_READ_DATA |
FILE_READ_ATTRIBUTES |
FILE_READ_EA |
FILE_APPEND_DATA |
SYNCHRONIZE;
+pub const SECURITY_ANONYMOUS: DWORD = 0 << 16;
+pub const SECURITY_IDENTIFICATION: DWORD = 1 << 16;
+pub const SECURITY_IMPERSONATION: DWORD = 2 << 16;
+pub const SECURITY_DELEGATION: DWORD = 3 << 16;
+pub const SECURITY_CONTEXT_TRACKING: DWORD = 0x00040000;
+pub const SECURITY_EFFECTIVE_ONLY: DWORD = 0x00080000;
+pub const SECURITY_SQOS_PRESENT: DWORD = 0x00100000;
+
#[repr(C)]
#[derive(Copy)]
pub struct WIN32_FIND_DATAW {
pub trait OpenOptionsExt {
/// Overrides the `dwDesiredAccess` argument to the call to `CreateFile`
/// with the specified value.
- fn desired_access(&mut self, access: u32) -> &mut Self;
-
- /// Overrides the `dwCreationDisposition` argument to the call to
- /// `CreateFile` with the specified value.
///
- /// This will override any values of the standard `create` flags, for
- /// example.
- fn creation_disposition(&mut self, val: u32) -> &mut Self;
-
- /// Overrides the `dwFlagsAndAttributes` argument to the call to
- /// `CreateFile` with the specified value.
+ /// This will override the `read`, `write`, and `append` flags on the
+ /// `OpenOptions` structure. This method provides fine-grained control over
+ /// the permissions to read, write and append data, attributes (like hidden
+ /// and system) and extended attributes.
+ ///
+ /// # Examples
///
- /// This will override any values of the standard flags on the
- /// `OpenOptions` structure.
- fn flags_and_attributes(&mut self, val: u32) -> &mut Self;
+ /// ```no_run
+ /// #![feature(open_options_ext)]
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::fs::OpenOptionsExt;
+ ///
+ /// // Open without read and write permission, for example if you only need
+ /// // to call `stat()` on the file
+ /// let file = OpenOptions::new().access_mode(0).open("foo.txt");
+ /// ```
+ fn access_mode(&mut self, access: u32) -> &mut Self;
/// Overrides the `dwShareMode` argument to the call to `CreateFile` with
/// the specified value.
///
- /// This will override any values of the standard flags on the
- /// `OpenOptions` structure.
+ /// By default `share_mode` is set to
+ /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. Specifying
+ /// less permissions denies others to read from, write to and/or delete the
+ /// file while it is open.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(open_options_ext)]
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::fs::OpenOptionsExt;
+ ///
+ /// // Do not allow others to read or modify this file while we have it open
+ /// // for writing
+ /// let file = OpenOptions::new().write(true)
+ /// .share_mode(0)
+ /// .open("foo.txt");
+ /// ```
fn share_mode(&mut self, val: u32) -> &mut Self;
+
+ /// Sets extra flags for the `dwFileFlags` argument to the call to
+ /// `CreateFile2` (or combines it with `attributes` and `security_qos_flags`
+ /// to set the `dwFlagsAndAttributes` for `CreateFile`).
+ ///
+ /// Custom flags can only set flags, not remove flags set by Rusts options.
+ /// This options overwrites any previously set custom flags.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// extern crate winapi;
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::fs::OpenOptionsExt;
+ ///
+ /// let mut options = OpenOptions::new();
+ /// options.create(true).write(true);
+ /// if cfg!(windows) {
+ /// options.custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE);
+ /// }
+ /// let file = options.open("foo.txt");
+ /// ```
+ #[unstable(feature = "expand_open_options",
+ reason = "recently added",
+ issue = "30014")]
+ fn custom_flags(&mut self, flags: u32) -> &mut Self;
+
+ /// Sets the `dwFileAttributes` argument to the call to `CreateFile2` to
+ /// the specified value (or combines it with `custom_flags` and
+ /// `security_qos_flags` to set the `dwFlagsAndAttributes` for
+ /// `CreateFile`).
+ ///
+ /// If a _new_ file is created because it does not yet exist and
+ ///`.create(true)` or `.create_new(true)` are specified, the new file is
+ /// given the attributes declared with `.attributes()`.
+ ///
+ /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
+ /// existing attributes are preserved and combined with the ones declared
+ /// with `.attributes()`.
+ ///
+ /// In all other cases the attributes get ignored.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// #![feature(open_options_ext)]
+ /// extern crate winapi;
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::fs::OpenOptionsExt;
+ ///
+ /// let file = OpenOptions::new().write(true).create(true)
+ /// .attributes(winapi::FILE_ATTRIBUTE_HIDDEN)
+ /// .open("foo.txt");
+ /// ```
+ fn attributes(&mut self, val: u32) -> &mut Self;
+
+ /// Sets the `dwSecurityQosFlags` argument to the call to `CreateFile2` to
+ /// the specified value (or combines it with `custom_flags` and `attributes`
+ /// to set the `dwFlagsAndAttributes` for `CreateFile`).
+ fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions;
}
#[unstable(feature = "open_options_ext",
reason = "may require more thought/methods",
issue = "27720")]
impl OpenOptionsExt for OpenOptions {
- fn desired_access(&mut self, access: u32) -> &mut OpenOptions {
- self.as_inner_mut().desired_access(access); self
+ fn access_mode(&mut self, access: u32) -> &mut OpenOptions {
+ self.as_inner_mut().access_mode(access); self
}
- fn creation_disposition(&mut self, access: u32) -> &mut OpenOptions {
- self.as_inner_mut().creation_disposition(access); self
+
+ fn share_mode(&mut self, share: u32) -> &mut OpenOptions {
+ self.as_inner_mut().share_mode(share); self
}
- fn flags_and_attributes(&mut self, access: u32) -> &mut OpenOptions {
- self.as_inner_mut().flags_and_attributes(access); self
+
+ fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions {
+ self.as_inner_mut().custom_flags(flags); self
}
- fn share_mode(&mut self, access: u32) -> &mut OpenOptions {
- self.as_inner_mut().share_mode(access); self
+
+ fn attributes(&mut self, attributes: u32) -> &mut OpenOptions {
+ self.as_inner_mut().attributes(attributes); self
+ }
+
+ fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions {
+ self.as_inner_mut().security_qos_flags(flags); self
}
}
data: c::WIN32_FIND_DATAW,
}
-#[derive(Clone, Default)]
+#[derive(Clone)]
pub struct OpenOptions {
- create: bool,
- append: bool,
+ // generic
read: bool,
write: bool,
+ append: bool,
truncate: bool,
- desired_access: Option<c::DWORD>,
- share_mode: Option<c::DWORD>,
- creation_disposition: Option<c::DWORD>,
- flags_and_attributes: Option<c::DWORD>,
- security_attributes: usize, // *mut T doesn't have a Default impl
+ create: bool,
+ create_new: bool,
+ // system-specific
+ custom_flags: u32,
+ access_mode: Option<c::DWORD>,
+ attributes: c::DWORD,
+ share_mode: c::DWORD,
+ security_qos_flags: c::DWORD,
+ security_attributes: usize, // FIXME: should be a reference
}
#[derive(Clone, PartialEq, Eq, Debug)]
}
impl OpenOptions {
- pub fn new() -> OpenOptions { Default::default() }
+ pub fn new() -> OpenOptions {
+ OpenOptions {
+ // generic
+ read: false,
+ write: false,
+ append: false,
+ truncate: false,
+ create: false,
+ create_new: false,
+ // system-specific
+ custom_flags: 0,
+ access_mode: None,
+ share_mode: c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE,
+ attributes: 0,
+ security_qos_flags: 0,
+ security_attributes: 0,
+ }
+ }
+
pub fn read(&mut self, read: bool) { self.read = read; }
pub fn write(&mut self, write: bool) { self.write = write; }
pub fn append(&mut self, append: bool) { self.append = append; }
- pub fn create(&mut self, create: bool) { self.create = create; }
pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
- pub fn creation_disposition(&mut self, val: u32) {
- self.creation_disposition = Some(val);
- }
- pub fn flags_and_attributes(&mut self, val: u32) {
- self.flags_and_attributes = Some(val);
- }
- pub fn desired_access(&mut self, val: u32) {
- self.desired_access = Some(val);
- }
- pub fn share_mode(&mut self, val: u32) {
- self.share_mode = Some(val);
- }
+ pub fn create(&mut self, create: bool) { self.create = create; }
+ pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
+
+ pub fn custom_flags(&mut self, flags: u32) { self.custom_flags = flags; }
+ pub fn access_mode(&mut self, access_mode: u32) { self.access_mode = Some(access_mode); }
+ pub fn share_mode(&mut self, share_mode: u32) { self.share_mode = share_mode; }
+ pub fn attributes(&mut self, attrs: u32) { self.attributes = attrs; }
+ pub fn security_qos_flags(&mut self, flags: u32) { self.security_qos_flags = flags; }
pub fn security_attributes(&mut self, attrs: c::LPSECURITY_ATTRIBUTES) {
self.security_attributes = attrs as usize;
}
- fn get_desired_access(&self) -> c::DWORD {
- self.desired_access.unwrap_or({
- let mut base = if self.read {c::FILE_GENERIC_READ} else {0} |
- if self.write {c::FILE_GENERIC_WRITE} else {0};
- if self.append {
- base &= !c::FILE_WRITE_DATA;
- base |= c::FILE_APPEND_DATA;
- }
- base
- })
+ fn get_access_mode(&self) -> io::Result<c::DWORD> {
+ const ERROR_INVALID_PARAMETER: i32 = 87;
+
+ match (self.read, self.write, self.append, self.access_mode) {
+ (_, _, _, Some(mode)) => Ok(mode),
+ (true, false, false, None) => Ok(c::GENERIC_READ),
+ (false, true, false, None) => Ok(c::GENERIC_WRITE),
+ (true, true, false, None) => Ok(c::GENERIC_READ | c::GENERIC_WRITE),
+ (false, _, true, None) => Ok(c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA),
+ (true, _, true, None) => Ok(c::GENERIC_READ |
+ (c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA)),
+ (false, false, false, None) => Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)),
+ }
}
- fn get_share_mode(&self) -> c::DWORD {
- // libuv has a good comment about this, but the basic idea is that
- // we try to emulate unix semantics by enabling all sharing by
- // allowing things such as deleting a file while it's still open.
- self.share_mode.unwrap_or(c::FILE_SHARE_READ |
- c::FILE_SHARE_WRITE |
- c::FILE_SHARE_DELETE)
- }
-
- fn get_creation_disposition(&self) -> c::DWORD {
- self.creation_disposition.unwrap_or({
- match (self.create, self.truncate) {
- (true, true) => c::CREATE_ALWAYS,
- (true, false) => c::OPEN_ALWAYS,
- (false, false) => c::OPEN_EXISTING,
- (false, true) => {
- if self.write && !self.append {
- c::CREATE_ALWAYS
- } else {
- c::TRUNCATE_EXISTING
- }
- }
- }
- })
+ fn get_creation_mode(&self) -> io::Result<c::DWORD> {
+ const ERROR_INVALID_PARAMETER: i32 = 87;
+
+ match (self.write, self.append) {
+ (true, false) => {}
+ (false, false) =>
+ if self.truncate || self.create || self.create_new {
+ return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER));
+ },
+ (_, true) =>
+ if self.truncate && !self.create_new {
+ return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER));
+ },
+ }
+
+ Ok(match (self.create, self.truncate, self.create_new) {
+ (false, false, false) => c::OPEN_EXISTING,
+ (true, false, false) => c::OPEN_ALWAYS,
+ (false, true, false) => c::TRUNCATE_EXISTING,
+ (true, true, false) => c::CREATE_ALWAYS,
+ (_, _, true) => c::CREATE_NEW,
+ })
}
fn get_flags_and_attributes(&self) -> c::DWORD {
- self.flags_and_attributes.unwrap_or(c::FILE_ATTRIBUTE_NORMAL)
+ self.custom_flags |
+ self.attributes |
+ self.security_qos_flags |
+ if self.security_qos_flags != 0 { c::SECURITY_SQOS_PRESENT } else { 0 } |
+ if self.create_new { c::FILE_FLAG_OPEN_REPARSE_POINT } else { 0 }
}
}
let mut opts = OpenOptions::new();
opts.read(!write);
opts.write(write);
- opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT |
- c::FILE_FLAG_BACKUP_SEMANTICS);
+ opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT |
+ c::FILE_FLAG_BACKUP_SEMANTICS);
File::open(path, &opts)
}
let path = try!(to_u16s(path));
let handle = unsafe {
c::CreateFileW(path.as_ptr(),
- opts.get_desired_access(),
- opts.get_share_mode(),
+ try!(opts.get_access_mode()),
+ opts.share_mode,
opts.security_attributes as *mut _,
- opts.get_creation_disposition(),
+ try!(opts.get_creation_mode()),
opts.get_flags_and_attributes(),
ptr::null_mut())
};
// metadata information is.
if attr.is_reparse_point() {
let mut opts = OpenOptions::new();
- opts.flags_and_attributes(c::FILE_FLAG_BACKUP_SEMANTICS);
+ // No read or write permissions are necessary
+ opts.access_mode(0);
+ // This flag is so we can open directories too
+ opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
let file = try!(File::open(p, &opts));
file.file_attr()
} else {
pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
let mut opts = OpenOptions::new();
- opts.read(true);
+ // No read or write permissions are necessary
+ opts.access_mode(0);
// This flag is so we can open directories too
- opts.flags_and_attributes(c::FILE_FLAG_BACKUP_SEMANTICS);
+ opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
let f = try!(File::open(p, &opts));
get_path(&f)
}
impl Encodable for Span {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- try!(s.emit_u32(self.lo.0));
- s.emit_u32(self.hi.0)
+ s.emit_struct("Span", 2, |s| {
+ try!(s.emit_struct_field("lo", 0, |s| {
+ self.lo.encode(s)
+ }));
+
+ s.emit_struct_field("hi", 1, |s| {
+ self.hi.encode(s)
+ })
+ })
}
}
impl Decodable for Span {
fn decode<D: Decoder>(d: &mut D) -> Result<Span, D::Error> {
- let lo = BytePos(try! { d.read_u32() });
- let hi = BytePos(try! { d.read_u32() });
- Ok(mk_sp(lo, hi))
+ d.read_struct("Span", 2, |d| {
+ let lo = try!(d.read_struct_field("lo", 0, |d| {
+ BytePos::decode(d)
+ }));
+
+ let hi = try!(d.read_struct_field("hi", 1, |d| {
+ BytePos::decode(d)
+ }));
+
+ Ok(mk_sp(lo, hi))
+ })
}
}
mod win;
/// Alias for stdout terminals.
-pub type StdoutTerminal = Terminal<Output=Stdout> + Send;
+pub type StdoutTerminal = Terminal<Output = Stdout> + Send;
/// Alias for stderr terminals.
-pub type StderrTerminal = Terminal<Output=Stderr> + Send;
+pub type StderrTerminal = Terminal<Output = Stderr> + Send;
#[cfg(not(windows))]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
ti: TermInfo,
}
-impl<T: Write+Send> Terminal for TerminfoTerminal<T> {
+impl<T: Write + Send> Terminal for TerminfoTerminal<T> {
type Output = T;
fn fg(&mut self, color: color::Color) -> io::Result<bool> {
let color = self.dim_if_necessary(color);
}
}
-impl<T: Write+Send> TerminfoTerminal<T> {
+impl<T: Write + Send> TerminfoTerminal<T> {
/// Create a new TerminfoTerminal with the given TermInfo and Write.
pub fn new_with_terminfo(out: T, terminfo: TermInfo) -> TerminfoTerminal<T> {
let nc = if terminfo.strings.contains_key("setaf") &&
color | (bits & 0x8) // copy the hi-intensity bit
}
-impl<T: Write+Send+'static> WinConsole<T> {
+impl<T: Write + Send + 'static> WinConsole<T> {
fn apply(&mut self) {
let _unused = self.buf.flush();
let mut accum: WORD = 0;
}
}
-impl<T: Write+Send+'static> Terminal for WinConsole<T> {
+impl<T: Write + Send + 'static> Terminal for WinConsole<T> {
type Output = T;
fn fg(&mut self, color: color::Color) -> io::Result<bool> {
// to be used by rustc to compile tests in libtest
pub mod test {
- pub use {Bencher, TestName, TestResult, TestDesc,
- TestDescAndFn, TestOpts, TrFailed, TrIgnored, TrOk,
- Metric, MetricMap,
- StaticTestFn, StaticTestName, DynTestName, DynTestFn,
- run_test, test_main, test_main_static, filter_tests,
- parse_opts, StaticBenchFn, ShouldPanic};
+ pub use {Bencher, TestName, TestResult, TestDesc, TestDescAndFn, TestOpts, TrFailed,
+ TrIgnored, TrOk, Metric, MetricMap, StaticTestFn, StaticTestName, DynTestName,
+ DynTestFn, run_test, test_main, test_main_static, filter_tests, parse_opts,
+ StaticBenchFn, ShouldPanic};
}
pub mod stats;
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum TestName {
StaticTestName(&'static str),
- DynTestName(String)
+ DynTestName(String),
}
impl TestName {
fn as_slice(&self) -> &str {
match *self {
StaticTestName(s) => s,
- DynTestName(ref s) => s
+ DynTestName(ref s) => s,
}
}
}
StaticBenchFn(fn(&mut Bencher)),
StaticMetricFn(fn(&mut MetricMap)),
DynTestFn(Box<FnBox() + Send>),
- DynMetricFn(Box<FnBox(&mut MetricMap)+Send>),
- DynBenchFn(Box<TDynBenchFn+'static>)
+ DynMetricFn(Box<FnBox(&mut MetricMap) + Send>),
+ DynBenchFn(Box<TDynBenchFn + 'static>),
}
impl TestFn {
fn padding(&self) -> NamePadding {
match *self {
- StaticTestFn(..) => PadNone,
- StaticBenchFn(..) => PadOnRight,
+ StaticTestFn(..) => PadNone,
+ StaticBenchFn(..) => PadOnRight,
StaticMetricFn(..) => PadOnRight,
- DynTestFn(..) => PadNone,
- DynMetricFn(..) => PadOnRight,
- DynBenchFn(..) => PadOnRight,
+ DynTestFn(..) => PadNone,
+ DynMetricFn(..) => PadOnRight,
+ DynBenchFn(..) => PadOnRight,
}
}
}
StaticMetricFn(..) => "StaticMetricFn(..)",
DynTestFn(..) => "DynTestFn(..)",
DynMetricFn(..) => "DynMetricFn(..)",
- DynBenchFn(..) => "DynBenchFn(..)"
+ DynBenchFn(..) => "DynBenchFn(..)",
})
}
}
pub enum ShouldPanic {
No,
Yes,
- YesWithMessage(&'static str)
+ YesWithMessage(&'static str),
}
// The definition of a single test. A test runner will run a list of
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Copy)]
pub struct Metric {
value: f64,
- noise: f64
+ noise: f64,
}
impl Metric {
pub fn new(value: f64, noise: f64) -> Metric {
- Metric {value: value, noise: noise}
+ Metric {
+ value: value,
+ noise: noise,
+ }
}
}
#[derive(PartialEq)]
-pub struct MetricMap(BTreeMap<String,Metric>);
+pub struct MetricMap(BTreeMap<String, Metric>);
impl Clone for MetricMap {
fn clone(&self) -> MetricMap {
// The default console test runner. It accepts the command line
// arguments and a vector of test_descs.
-pub fn test_main(args: &[String], tests: Vec<TestDescAndFn> ) {
- let opts =
- match parse_opts(args) {
- Some(Ok(o)) => o,
- Some(Err(msg)) => panic!("{:?}", msg),
- None => return
- };
+pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>) {
+ let opts = match parse_opts(args) {
+ Some(Ok(o)) => o,
+ Some(Err(msg)) => panic!("{:?}", msg),
+ None => return,
+ };
match run_tests_console(&opts, tests) {
Ok(true) => {}
Ok(false) => std::process::exit(101),
// rather than a &[].
pub fn test_main_static(tests: &[TestDescAndFn]) {
let args = env::args().collect::<Vec<_>>();
- let owned_tests = tests.iter().map(|t| {
- match t.testfn {
- StaticTestFn(f) => TestDescAndFn { testfn: StaticTestFn(f), desc: t.desc.clone() },
- StaticBenchFn(f) => TestDescAndFn { testfn: StaticBenchFn(f), desc: t.desc.clone() },
- _ => panic!("non-static tests passed to test::test_main_static")
- }
- }).collect();
+ let owned_tests = tests.iter()
+ .map(|t| {
+ match t.testfn {
+ StaticTestFn(f) => {
+ TestDescAndFn {
+ testfn: StaticTestFn(f),
+ desc: t.desc.clone(),
+ }
+ }
+ StaticBenchFn(f) => {
+ TestDescAndFn {
+ testfn: StaticBenchFn(f),
+ desc: t.desc.clone(),
+ }
+ }
+ _ => panic!("non-static tests passed to test::test_main_static"),
+ }
+ })
+ .collect();
test_main(&args, owned_tests)
}
/// Result of parsing the options.
pub type OptRes = Result<TestOpts, String>;
+#[cfg_attr(rustfmt, rustfmt_skip)]
fn optgroups() -> Vec<getopts::OptGroup> {
vec!(getopts::optflag("", "ignored", "Run ignored tests"),
getopts::optflag("", "test", "Run tests and not benchmarks"),
// Parses command line arguments into test options
pub fn parse_opts(args: &[String]) -> Option<OptRes> {
let args_ = &args[1..];
- let matches =
- match getopts::getopts(args_, &optgroups()) {
- Ok(m) => m,
- Err(f) => return Some(Err(f.to_string()))
- };
+ let matches = match getopts::getopts(args_, &optgroups()) {
+ Ok(m) => m,
+ Err(f) => return Some(Err(f.to_string())),
+ };
- if matches.opt_present("h") { usage(&args[0]); return None; }
+ if matches.opt_present("h") {
+ usage(&args[0]);
+ return None;
+ }
let filter = if !matches.free.is_empty() {
Some(matches.free[0].clone())
let logfile = logfile.map(|s| PathBuf::from(&s));
let bench_benchmarks = matches.opt_present("bench");
- let run_tests = ! bench_benchmarks ||
- matches.opt_present("test");
+ let run_tests = !bench_benchmarks || matches.opt_present("test");
let mut nocapture = matches.opt_present("nocapture");
if !nocapture {
Some("always") => AlwaysColor,
Some("never") => NeverColor,
- Some(v) => return Some(Err(format!("argument for --color must be \
- auto, always, or never (was {})",
- v))),
+ Some(v) => {
+ return Some(Err(format!("argument for --color must be auto, always, or never (was \
+ {})",
+ v)))
+ }
};
let test_opts = TestOpts {
ignored: usize,
measured: usize,
metrics: MetricMap,
- failures: Vec<(TestDesc, Vec<u8> )> ,
+ failures: Vec<(TestDesc, Vec<u8>)>,
max_name_len: usize, // number of columns to fill when aligning names
}
impl<T: Write> ConsoleTestState<T> {
- pub fn new(opts: &TestOpts,
- _: Option<T>) -> io::Result<ConsoleTestState<io::Stdout>> {
+ pub fn new(opts: &TestOpts, _: Option<T>) -> io::Result<ConsoleTestState<io::Stdout>> {
let log_out = match opts.logfile {
Some(ref path) => Some(try!(File::create(path))),
- None => None
+ None => None,
};
let out = match term::stdout() {
None => Raw(io::stdout()),
- Some(t) => Pretty(t)
+ Some(t) => Pretty(t),
};
Ok(ConsoleTestState {
self.write_pretty("bench", term::color::CYAN)
}
- pub fn write_pretty(&mut self,
- word: &str,
- color: term::color::Color) -> io::Result<()> {
+ pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
match self.out {
Pretty(ref mut term) => {
if self.use_color {
Pretty(ref mut term) => {
try!(term.write_all(s.as_bytes()));
term.flush()
- },
+ }
Raw(ref mut stdout) => {
try!(stdout.write_all(s.as_bytes()));
stdout.flush()
- },
+ }
}
}
pub fn write_run_start(&mut self, len: usize) -> io::Result<()> {
self.total = len;
- let noun = if len != 1 { "tests" } else { "test" };
+ let noun = if len != 1 {
+ "tests"
+ } else {
+ "test"
+ };
self.write_plain(&format!("\nrunning {} {}\n", len, noun))
}
- pub fn write_test_start(&mut self, test: &TestDesc,
- align: NamePadding) -> io::Result<()> {
+ pub fn write_test_start(&mut self, test: &TestDesc, align: NamePadding) -> io::Result<()> {
let name = test.padded_name(self.max_name_len, align);
self.write_plain(&format!("test {} ... ", name))
}
self.write_plain("\n")
}
- pub fn write_log(&mut self, test: &TestDesc,
- result: &TestResult) -> io::Result<()> {
+ pub fn write_log(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> {
match self.log_out {
None => Ok(()),
Some(ref mut o) => {
- let s = format!("{} {}\n", match *result {
- TrOk => "ok".to_owned(),
- TrFailed => "failed".to_owned(),
- TrIgnored => "ignored".to_owned(),
- TrMetrics(ref mm) => mm.fmt_metrics(),
- TrBench(ref bs) => fmt_bench_samples(bs)
- }, test.name);
+ let s = format!("{} {}\n",
+ match *result {
+ TrOk => "ok".to_owned(),
+ TrFailed => "failed".to_owned(),
+ TrIgnored => "ignored".to_owned(),
+ TrMetrics(ref mm) => mm.fmt_metrics(),
+ TrBench(ref bs) => fmt_bench_samples(bs),
+ },
+ test.name);
o.write_all(s.as_bytes())
}
}
try!(self.write_failed());
}
let s = format!(". {} passed; {} failed; {} ignored; {} measured\n\n",
- self.passed, self.failed, self.ignored, self.measured);
+ self.passed,
+ self.failed,
+ self.ignored,
+ self.measured);
try!(self.write_plain(&s));
return Ok(success);
}
let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
output.write_fmt(format_args!("{:>11} ns/iter (+/- {})",
- fmt_thousands_sep(median, ','),
- fmt_thousands_sep(deviation, ','))).unwrap();
+ fmt_thousands_sep(median, ','),
+ fmt_thousands_sep(deviation, ',')))
+ .unwrap();
if bs.mb_s != 0 {
output.write_fmt(format_args!(" = {} MB/s", bs.mb_s)).unwrap();
}
}
// A simple console test runner
-pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn> ) -> io::Result<bool> {
+pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<bool> {
- fn callback<T: Write>(event: &TestEvent,
- st: &mut ConsoleTestState<T>) -> io::Result<()> {
+ fn callback<T: Write>(event: &TestEvent, st: &mut ConsoleTestState<T>) -> io::Result<()> {
match (*event).clone() {
TeFiltered(ref filtered_tests) => st.write_run_start(filtered_tests.len()),
TeWait(ref test, padding) => st.write_test_start(test, padding),
TrMetrics(mm) => {
let tname = test.name;
let MetricMap(mm) = mm;
- for (k,v) in &mm {
+ for (k, v) in &mm {
st.metrics
- .insert_metric(&format!("{}.{}",
- tname,
- k),
- v.value,
- v.noise);
+ .insert_metric(&format!("{}.{}", tname, k), v.value, v.noise);
}
st.measured += 1
}
PadOnRight => t.desc.name.as_slice().len(),
}
}
- match tests.iter().max_by_key(|t|len_if_padded(*t)) {
+ match tests.iter().max_by_key(|t| len_if_padded(*t)) {
Some(t) => {
let n = t.desc.name.as_slice();
st.max_name_len = n.len();
- },
+ }
None => {}
}
try!(run_tests(opts, tests, |x| callback(&x, &mut st)));
let test_a = TestDesc {
name: StaticTestName("a"),
ignore: false,
- should_panic: ShouldPanic::No
+ should_panic: ShouldPanic::No,
};
let test_b = TestDesc {
name: StaticTestName("b"),
ignore: false,
- should_panic: ShouldPanic::No
+ should_panic: ShouldPanic::No,
};
let mut st = ConsoleTestState {
measured: 0,
max_name_len: 10,
metrics: MetricMap::new(),
- failures: vec!((test_b, Vec::new()), (test_a, Vec::new()))
+ failures: vec![(test_b, Vec::new()), (test_a, Vec::new())],
};
st.write_failures().unwrap();
let s = match st.out {
Raw(ref m) => String::from_utf8_lossy(&m[..]),
- Pretty(_) => unreachable!()
+ Pretty(_) => unreachable!(),
};
let apos = s.find("a").unwrap();
#[derive(Clone)]
enum TestEvent {
- TeFiltered(Vec<TestDesc> ),
+ TeFiltered(Vec<TestDesc>),
TeWait(TestDesc, NamePadding),
- TeResult(TestDesc, TestResult, Vec<u8> ),
+ TeResult(TestDesc, TestResult, Vec<u8>),
}
-pub type MonitorMsg = (TestDesc, TestResult, Vec<u8> );
+pub type MonitorMsg = (TestDesc, TestResult, Vec<u8>);
-fn run_tests<F>(opts: &TestOpts,
- tests: Vec<TestDescAndFn> ,
- mut callback: F) -> io::Result<()> where
- F: FnMut(TestEvent) -> io::Result<()>,
+fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()>
+ where F: FnMut(TestEvent) -> io::Result<()>
{
let mut filtered_tests = filter_tests(opts, tests);
if !opts.bench_benchmarks {
filtered_tests.into_iter().partition(|e| {
match e.testfn {
StaticTestFn(_) | DynTestFn(_) => true,
- _ => false
+ _ => false,
}
});
let opt_n: Option<usize> = s.parse().ok();
match opt_n {
Some(n) if n > 0 => n,
- _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", s)
+ _ => {
+ panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.",
+ s)
+ }
}
}
Err(..) => num_cpus(),
target_os = "ios",
target_os = "android"))]
fn num_cpus() -> usize {
- unsafe {
- libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize
- }
+ unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
}
#[cfg(any(target_os = "freebsd",
let mut mib = [libc::CTL_HW, libc::HW_AVAILCPU, 0, 0];
unsafe {
- libc::sysctl(mib.as_mut_ptr(), 2,
+ libc::sysctl(mib.as_mut_ptr(),
+ 2,
&mut cpus as *mut _ as *mut _,
&mut cpus_size as *mut _ as *mut _,
- 0 as *mut _, 0);
+ 0 as *mut _,
+ 0);
}
if cpus < 1 {
mib[1] = libc::HW_NCPU;
unsafe {
- libc::sysctl(mib.as_mut_ptr(), 2,
+ libc::sysctl(mib.as_mut_ptr(),
+ 2,
&mut cpus as *mut _ as *mut _,
&mut cpus_size as *mut _ as *mut _,
- 0 as *mut _, 0);
+ 0 as *mut _,
+ 0);
}
if cpus < 1 {
cpus = 1;
let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
unsafe {
- libc::sysctl(mib.as_mut_ptr(), 2,
+ libc::sysctl(mib.as_mut_ptr(),
+ 2,
&mut cpus as *mut _ as *mut _,
&mut cpus_size as *mut _ as *mut _,
- 0 as *mut _, 0);
+ 0 as *mut _,
+ 0);
}
if cpus < 1 {
cpus = 1;
filtered = match opts.filter {
None => filtered,
Some(ref filter) => {
- filtered.into_iter().filter(|test| {
- test.desc.name.as_slice().contains(&filter[..])
- }).collect()
+ filtered.into_iter()
+ .filter(|test| test.desc.name.as_slice().contains(&filter[..]))
+ .collect()
}
};
if test.desc.ignore {
let TestDescAndFn {desc, testfn} = test;
Some(TestDescAndFn {
- desc: TestDesc {ignore: false, ..desc},
- testfn: testfn
+ desc: TestDesc { ignore: false, ..desc },
+ testfn: testfn,
})
} else {
None
pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
// convert benchmarks to tests, if we're not benchmarking them
- tests.into_iter().map(|x| {
- let testfn = match x.testfn {
- DynBenchFn(bench) => {
- DynTestFn(Box::new(move || bench::run_once(|b| bench.run(b))))
- }
- StaticBenchFn(benchfn) => {
- DynTestFn(Box::new(move || bench::run_once(|b| benchfn(b))))
- }
- f => f
- };
- TestDescAndFn { desc: x.desc, testfn: testfn }
- }).collect()
+ tests.into_iter()
+ .map(|x| {
+ let testfn = match x.testfn {
+ DynBenchFn(bench) => {
+ DynTestFn(Box::new(move || bench::run_once(|b| bench.run(b))))
+ }
+ StaticBenchFn(benchfn) => {
+ DynTestFn(Box::new(move || bench::run_once(|b| benchfn(b))))
+ }
+ f => f,
+ };
+ TestDescAndFn {
+ desc: x.desc,
+ testfn: testfn,
+ }
+ })
+ .collect()
}
pub fn run_test(opts: &TestOpts,
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
Write::write(&mut *self.0.lock().unwrap(), data)
}
- fn flush(&mut self) -> io::Result<()> { Ok(()) }
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
}
thread::spawn(move || {
});
let result_guard = cfg.spawn(move || {
- if !nocapture {
- io::set_print(box Sink(data2.clone()));
- io::set_panic(box Sink(data2));
- }
- testfn()
- }).unwrap();
+ if !nocapture {
+ io::set_print(box Sink(data2.clone()));
+ io::set_panic(box Sink(data2));
+ }
+ testfn()
+ })
+ .unwrap();
let test_result = calc_result(&desc, result_guard.join());
let stdout = data.lock().unwrap().to_vec();
monitor_ch.send((desc.clone(), test_result, stdout)).unwrap();
return;
}
DynTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, f),
- StaticTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture,
- Box::new(f))
+ StaticTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(f)),
}
}
-fn calc_result(desc: &TestDesc, task_result: Result<(), Box<Any+Send>>) -> TestResult {
+fn calc_result(desc: &TestDesc, task_result: Result<(), Box<Any + Send>>) -> TestResult {
match (&desc.should_panic, task_result) {
(&ShouldPanic::No, Ok(())) |
(&ShouldPanic::Yes, Err(_)) => TrOk,
(&ShouldPanic::YesWithMessage(msg), Err(ref err))
if err.downcast_ref::<String>()
- .map(|e| &**e)
- .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e))
- .map(|e| e.contains(msg))
- .unwrap_or(false) => TrOk,
+ .map(|e| &**e)
+ .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e))
+ .map(|e| e.contains(msg))
+ .unwrap_or(false) => TrOk,
_ => TrFailed,
}
}
impl MetricMap {
-
pub fn new() -> MetricMap {
MetricMap(BTreeMap::new())
}
pub fn insert_metric(&mut self, name: &str, value: f64, noise: f64) {
let m = Metric {
value: value,
- noise: noise
+ noise: noise,
};
let MetricMap(ref mut map) = *self;
map.insert(name.to_owned(), m);
pub fn fmt_metrics(&self) -> String {
let MetricMap(ref mm) = *self;
- let v : Vec<String> = mm.iter()
- .map(|(k,v)| format!("{}: {} (+/- {})", *k,
- v.value, v.noise))
- .collect();
+ let v: Vec<String> = mm.iter()
+ .map(|(k, v)| format!("{}: {} (+/- {})", *k, v.value, v.noise))
+ .collect();
v.join(", ")
}
}
pub fn black_box<T>(dummy: T) -> T {
// we need to "use" the argument in some way LLVM can't
// introspect.
- unsafe {asm!("" : : "r"(&dummy))}
+ unsafe { asm!("" : : "r"(&dummy)) }
dummy
}
#[cfg(all(target_os = "nacl", target_arch = "le32"))]
#[inline(never)]
-pub fn black_box<T>(dummy: T) -> T { dummy }
+pub fn black_box<T>(dummy: T) -> T {
+ dummy
+}
impl Bencher {
/// Callback for benchmark functions to run in their body.
- pub fn iter<T, F>(&mut self, mut inner: F) where F: FnMut() -> T {
+ pub fn iter<T, F>(&mut self, mut inner: F)
+ where F: FnMut() -> T
+ {
let start = Instant::now();
let k = self.iterations;
for _ in 0..k {
}
}
- pub fn bench_n<F>(&mut self, n: u64, f: F) where F: FnOnce(&mut Bencher) {
+ pub fn bench_n<F>(&mut self, n: u64, f: F)
+ where F: FnOnce(&mut Bencher)
+ {
self.iterations = n;
f(self);
}
// This is a more statistics-driven benchmark algorithm
- pub fn auto_bench<F>(&mut self, mut f: F) -> stats::Summary where F: FnMut(&mut Bencher) {
+ pub fn auto_bench<F>(&mut self, mut f: F) -> stats::Summary
+ where F: FnMut(&mut Bencher)
+ {
// Initial bench run to get ballpark figure.
let mut n = 1;
self.bench_n(n, |x| f(x));
// side effect of not being able to do as many runs is
// automatically handled by the statistical analysis below
// (i.e. larger error bars).
- if n == 0 { n = 1; }
+ if n == 0 {
+ n = 1;
+ }
let mut total_run = Duration::new(0, 0);
- let samples : &mut [f64] = &mut [0.0_f64; 50];
+ let samples: &mut [f64] = &mut [0.0_f64; 50];
loop {
let loop_start = Instant::now();
for p in &mut *samples {
self.bench_n(n, |x| f(x));
*p = self.ns_per_iter() as f64;
- };
+ }
stats::winsorize(samples, 5.0);
let summ = stats::Summary::new(samples);
for p in &mut *samples {
self.bench_n(5 * n, |x| f(x));
*p = self.ns_per_iter() as f64;
- };
+ }
stats::winsorize(samples, 5.0);
let summ5 = stats::Summary::new(samples);
// If we've run for 100ms and seem to have converged to a
// stable median.
- if loop_run > Duration::from_millis(100) &&
- summ.median_abs_dev_pct < 1.0 &&
- summ.median - summ5.median < summ5.median_abs_dev {
+ if loop_run > Duration::from_millis(100) && summ.median_abs_dev_pct < 1.0 &&
+ summ.median - summ5.median < summ5.median_abs_dev {
return summ5;
}
use std::time::Duration;
use super::{Bencher, BenchSamples};
- pub fn benchmark<F>(f: F) -> BenchSamples where F: FnMut(&mut Bencher) {
+ pub fn benchmark<F>(f: F) -> BenchSamples
+ where F: FnMut(&mut Bencher)
+ {
let mut bs = Bencher {
iterations: 0,
dur: Duration::new(0, 0),
- bytes: 0
+ bytes: 0,
};
let ns_iter_summ = bs.auto_bench(f);
BenchSamples {
ns_iter_summ: ns_iter_summ,
- mb_s: mb_s as usize
+ mb_s: mb_s as usize,
}
}
- pub fn run_once<F>(f: F) where F: FnOnce(&mut Bencher) {
+ pub fn run_once<F>(f: F)
+ where F: FnOnce(&mut Bencher)
+ {
let mut bs = Bencher {
iterations: 0,
dur: Duration::new(0, 0),
- bytes: 0
+ bytes: 0,
};
bs.bench_n(1, f);
}
#[cfg(test)]
mod tests {
- use test::{TrFailed, TrIgnored, TrOk, filter_tests, parse_opts,
- TestDesc, TestDescAndFn, TestOpts, run_test,
- MetricMap,
- StaticTestName, DynTestName, DynTestFn, ShouldPanic};
+ use test::{TrFailed, TrIgnored, TrOk, filter_tests, parse_opts, TestDesc, TestDescAndFn,
+ TestOpts, run_test, MetricMap, StaticTestName, DynTestName, DynTestFn, ShouldPanic};
use std::sync::mpsc::channel;
#[test]
pub fn do_not_run_ignored_tests() {
- fn f() { panic!(); }
+ fn f() {
+ panic!();
+ }
let desc = TestDescAndFn {
desc: TestDesc {
name: StaticTestName("whatever"),
ignore: true,
should_panic: ShouldPanic::No,
},
- testfn: DynTestFn(Box::new(move|| f())),
+ testfn: DynTestFn(Box::new(move || f())),
};
let (tx, rx) = channel();
run_test(&TestOpts::new(), false, desc, tx);
#[test]
pub fn ignored_tests_result_in_ignored() {
- fn f() { }
+ fn f() {}
let desc = TestDescAndFn {
desc: TestDesc {
name: StaticTestName("whatever"),
ignore: true,
should_panic: ShouldPanic::No,
},
- testfn: DynTestFn(Box::new(move|| f())),
+ testfn: DynTestFn(Box::new(move || f())),
};
let (tx, rx) = channel();
run_test(&TestOpts::new(), false, desc, tx);
#[test]
fn test_should_panic() {
- fn f() { panic!(); }
+ fn f() {
+ panic!();
+ }
let desc = TestDescAndFn {
desc: TestDesc {
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::Yes,
},
- testfn: DynTestFn(Box::new(move|| f())),
+ testfn: DynTestFn(Box::new(move || f())),
};
let (tx, rx) = channel();
run_test(&TestOpts::new(), false, desc, tx);
#[test]
fn test_should_panic_good_message() {
- fn f() { panic!("an error message"); }
+ fn f() {
+ panic!("an error message");
+ }
let desc = TestDescAndFn {
desc: TestDesc {
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::YesWithMessage("error message"),
},
- testfn: DynTestFn(Box::new(move|| f())),
+ testfn: DynTestFn(Box::new(move || f())),
};
let (tx, rx) = channel();
run_test(&TestOpts::new(), false, desc, tx);
#[test]
fn test_should_panic_bad_message() {
- fn f() { panic!("an error message"); }
+ fn f() {
+ panic!("an error message");
+ }
let desc = TestDescAndFn {
desc: TestDesc {
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::YesWithMessage("foobar"),
},
- testfn: DynTestFn(Box::new(move|| f())),
+ testfn: DynTestFn(Box::new(move || f())),
};
let (tx, rx) = channel();
run_test(&TestOpts::new(), false, desc, tx);
#[test]
fn test_should_panic_but_succeeds() {
- fn f() { }
+ fn f() {}
let desc = TestDescAndFn {
desc: TestDesc {
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::Yes,
},
- testfn: DynTestFn(Box::new(move|| f())),
+ testfn: DynTestFn(Box::new(move || f())),
};
let (tx, rx) = channel();
run_test(&TestOpts::new(), false, desc, tx);
#[test]
fn parse_ignored_flag() {
- let args = vec!("progname".to_string(),
- "filter".to_string(),
- "--ignored".to_string());
+ let args = vec!["progname".to_string(), "filter".to_string(), "--ignored".to_string()];
let opts = match parse_opts(&args) {
Some(Ok(o)) => o,
- _ => panic!("Malformed arg in parse_ignored_flag")
+ _ => panic!("Malformed arg in parse_ignored_flag"),
};
assert!((opts.run_ignored));
}
opts.run_tests = true;
opts.run_ignored = true;
- let tests = vec!(
- TestDescAndFn {
- desc: TestDesc {
- name: StaticTestName("1"),
- ignore: true,
- should_panic: ShouldPanic::No,
- },
- testfn: DynTestFn(Box::new(move|| {})),
- },
- TestDescAndFn {
- desc: TestDesc {
- name: StaticTestName("2"),
- ignore: false,
- should_panic: ShouldPanic::No,
- },
- testfn: DynTestFn(Box::new(move|| {})),
- });
+ let tests = vec![TestDescAndFn {
+ desc: TestDesc {
+ name: StaticTestName("1"),
+ ignore: true,
+ should_panic: ShouldPanic::No,
+ },
+ testfn: DynTestFn(Box::new(move || {})),
+ },
+ TestDescAndFn {
+ desc: TestDesc {
+ name: StaticTestName("2"),
+ ignore: false,
+ should_panic: ShouldPanic::No,
+ },
+ testfn: DynTestFn(Box::new(move || {})),
+ }];
let filtered = filter_tests(&opts, tests);
assert_eq!(filtered.len(), 1);
- assert_eq!(filtered[0].desc.name.to_string(),
- "1");
+ assert_eq!(filtered[0].desc.name.to_string(), "1");
assert!(filtered[0].desc.ignore == false);
}
let mut opts = TestOpts::new();
opts.run_tests = true;
- let names =
- vec!("sha1::test".to_string(),
- "isize::test_to_str".to_string(),
- "isize::test_pow".to_string(),
- "test::do_not_run_ignored_tests".to_string(),
- "test::ignored_tests_result_in_ignored".to_string(),
- "test::first_free_arg_should_be_a_filter".to_string(),
- "test::parse_ignored_flag".to_string(),
- "test::filter_for_ignored_option".to_string(),
- "test::sort_tests".to_string());
- let tests =
- {
- fn testfn() { }
+ let names = vec!["sha1::test".to_string(),
+ "isize::test_to_str".to_string(),
+ "isize::test_pow".to_string(),
+ "test::do_not_run_ignored_tests".to_string(),
+ "test::ignored_tests_result_in_ignored".to_string(),
+ "test::first_free_arg_should_be_a_filter".to_string(),
+ "test::parse_ignored_flag".to_string(),
+ "test::filter_for_ignored_option".to_string(),
+ "test::sort_tests".to_string()];
+ let tests = {
+ fn testfn() {}
let mut tests = Vec::new();
for name in &names {
let test = TestDescAndFn {
};
let filtered = filter_tests(&opts, tests);
- let expected =
- vec!("isize::test_pow".to_string(),
- "isize::test_to_str".to_string(),
- "sha1::test".to_string(),
- "test::do_not_run_ignored_tests".to_string(),
- "test::filter_for_ignored_option".to_string(),
- "test::first_free_arg_should_be_a_filter".to_string(),
- "test::ignored_tests_result_in_ignored".to_string(),
- "test::parse_ignored_flag".to_string(),
- "test::sort_tests".to_string());
+ let expected = vec!["isize::test_pow".to_string(),
+ "isize::test_to_str".to_string(),
+ "sha1::test".to_string(),
+ "test::do_not_run_ignored_tests".to_string(),
+ "test::filter_for_ignored_option".to_string(),
+ "test::first_free_arg_should_be_a_filter".to_string(),
+ "test::ignored_tests_result_in_ignored".to_string(),
+ "test::parse_ignored_flag".to_string(),
+ "test::sort_tests".to_string()];
for (a, b) in expected.iter().zip(filtered) {
assert!(*a == b.desc.name.to_string());
/// is otherwise equivalent.
///
/// See also: https://en.wikipedia.org/wiki/Quartile
- fn quartiles(&self) -> (f64,f64,f64);
+ fn quartiles(&self) -> (f64, f64, f64);
/// Inter-quartile range: the difference between the 25th percentile (1st quartile) and the 75th
/// percentile (3rd quartile). See `quartiles`.
pub std_dev_pct: f64,
pub median_abs_dev: f64,
pub median_abs_dev_pct: f64,
- pub quartiles: (f64,f64,f64),
+ pub quartiles: (f64, f64, f64),
pub iqr: f64,
}
median_abs_dev: samples.median_abs_dev(),
median_abs_dev_pct: samples.median_abs_dev_pct(),
quartiles: samples.quartiles(),
- iqr: samples.iqr()
+ iqr: samples.iqr(),
}
}
}
partials.push(x);
} else {
partials[j] = x;
- partials.truncate(j+1);
+ partials.truncate(j + 1);
}
}
let zero: f64 = 0.0;
let mut v: f64 = 0.0;
for s in self {
let x = *s - mean;
- v = v + x*x;
+ v = v + x * x;
}
// NB: this is _supposed to be_ len-1, not len. If you
// change it back to len, you will be calculating a
// population variance, not a sample variance.
let denom = (self.len() - 1) as f64;
- v/denom
+ v / denom
}
}
percentile_of_sorted(&tmp, pct)
}
- fn quartiles(&self) -> (f64,f64,f64) {
+ fn quartiles(&self) -> (f64, f64, f64) {
let mut tmp = self.to_vec();
local_sort(&mut tmp);
let first = 25f64;
let b = percentile_of_sorted(&tmp, secound);
let third = 75f64;
let c = percentile_of_sorted(&tmp, third);
- (a,b,c)
+ (a, b, c)
}
fn iqr(&self) -> f64 {
- let (a,_,c) = self.quartiles();
+ let (a, _, c) = self.quartiles();
c - a
}
}
let d = rank - lrank;
let n = lrank as usize;
let lo = sorted_samples[n];
- let hi = sorted_samples[n+1];
+ let hi = sorted_samples[n + 1];
lo + (hi - lo) * d
}
local_sort(&mut tmp);
let lo = percentile_of_sorted(&tmp, pct);
let hundred = 100 as f64;
- let hi = percentile_of_sorted(&tmp, hundred-pct);
+ let hi = percentile_of_sorted(&tmp, hundred - pct);
for samp in samples {
if *samp > hi {
*samp = hi
#[test]
fn test_norm2() {
- let val = &[
- 958.0000000000,
- 924.0000000000,
- ];
+ let val = &[958.0000000000, 924.0000000000];
let summ = &Summary {
sum: 1882.0000000000,
min: 924.0000000000,
std_dev_pct: 2.5549022912,
median_abs_dev: 25.2042000000,
median_abs_dev_pct: 2.6784484591,
- quartiles: (932.5000000000,941.0000000000,949.5000000000),
+ quartiles: (932.5000000000, 941.0000000000, 949.5000000000),
iqr: 17.0000000000,
};
check(val, summ);
}
#[test]
fn test_norm10narrow() {
- let val = &[
- 966.0000000000,
- 985.0000000000,
- 1110.0000000000,
- 848.0000000000,
- 821.0000000000,
- 975.0000000000,
- 962.0000000000,
- 1157.0000000000,
- 1217.0000000000,
- 955.0000000000,
- ];
+ let val = &[966.0000000000,
+ 985.0000000000,
+ 1110.0000000000,
+ 848.0000000000,
+ 821.0000000000,
+ 975.0000000000,
+ 962.0000000000,
+ 1157.0000000000,
+ 1217.0000000000,
+ 955.0000000000];
let summ = &Summary {
sum: 9996.0000000000,
min: 821.0000000000,
std_dev_pct: 12.6742097933,
median_abs_dev: 102.2994000000,
median_abs_dev_pct: 10.5408964451,
- quartiles: (956.7500000000,970.5000000000,1078.7500000000),
+ quartiles: (956.7500000000, 970.5000000000, 1078.7500000000),
iqr: 122.0000000000,
};
check(val, summ);
}
#[test]
fn test_norm10medium() {
- let val = &[
- 954.0000000000,
- 1064.0000000000,
- 855.0000000000,
- 1000.0000000000,
- 743.0000000000,
- 1084.0000000000,
- 704.0000000000,
- 1023.0000000000,
- 357.0000000000,
- 869.0000000000,
- ];
+ let val = &[954.0000000000,
+ 1064.0000000000,
+ 855.0000000000,
+ 1000.0000000000,
+ 743.0000000000,
+ 1084.0000000000,
+ 704.0000000000,
+ 1023.0000000000,
+ 357.0000000000,
+ 869.0000000000];
let summ = &Summary {
sum: 8653.0000000000,
min: 357.0000000000,
std_dev_pct: 25.4846418487,
median_abs_dev: 195.7032000000,
median_abs_dev_pct: 21.4704552935,
- quartiles: (771.0000000000,911.5000000000,1017.2500000000),
+ quartiles: (771.0000000000, 911.5000000000, 1017.2500000000),
iqr: 246.2500000000,
};
check(val, summ);
}
#[test]
fn test_norm10wide() {
- let val = &[
- 505.0000000000,
- 497.0000000000,
- 1591.0000000000,
- 887.0000000000,
- 1026.0000000000,
- 136.0000000000,
- 1580.0000000000,
- 940.0000000000,
- 754.0000000000,
- 1433.0000000000,
- ];
+ let val = &[505.0000000000,
+ 497.0000000000,
+ 1591.0000000000,
+ 887.0000000000,
+ 1026.0000000000,
+ 136.0000000000,
+ 1580.0000000000,
+ 940.0000000000,
+ 754.0000000000,
+ 1433.0000000000];
let summ = &Summary {
sum: 9349.0000000000,
min: 136.0000000000,
std_dev_pct: 52.3146817750,
median_abs_dev: 611.5725000000,
median_abs_dev_pct: 66.9482758621,
- quartiles: (567.2500000000,913.5000000000,1331.2500000000),
+ quartiles: (567.2500000000, 913.5000000000, 1331.2500000000),
iqr: 764.0000000000,
};
check(val, summ);
}
#[test]
fn test_norm25verynarrow() {
- let val = &[
- 991.0000000000,
- 1018.0000000000,
- 998.0000000000,
- 1013.0000000000,
- 974.0000000000,
- 1007.0000000000,
- 1014.0000000000,
- 999.0000000000,
- 1011.0000000000,
- 978.0000000000,
- 985.0000000000,
- 999.0000000000,
- 983.0000000000,
- 982.0000000000,
- 1015.0000000000,
- 1002.0000000000,
- 977.0000000000,
- 948.0000000000,
- 1040.0000000000,
- 974.0000000000,
- 996.0000000000,
- 989.0000000000,
- 1015.0000000000,
- 994.0000000000,
- 1024.0000000000,
- ];
+ let val = &[991.0000000000,
+ 1018.0000000000,
+ 998.0000000000,
+ 1013.0000000000,
+ 974.0000000000,
+ 1007.0000000000,
+ 1014.0000000000,
+ 999.0000000000,
+ 1011.0000000000,
+ 978.0000000000,
+ 985.0000000000,
+ 999.0000000000,
+ 983.0000000000,
+ 982.0000000000,
+ 1015.0000000000,
+ 1002.0000000000,
+ 977.0000000000,
+ 948.0000000000,
+ 1040.0000000000,
+ 974.0000000000,
+ 996.0000000000,
+ 989.0000000000,
+ 1015.0000000000,
+ 994.0000000000,
+ 1024.0000000000];
let summ = &Summary {
sum: 24926.0000000000,
min: 948.0000000000,
std_dev_pct: 1.9888308788,
median_abs_dev: 22.2390000000,
median_abs_dev_pct: 2.2283567134,
- quartiles: (983.0000000000,998.0000000000,1013.0000000000),
+ quartiles: (983.0000000000, 998.0000000000, 1013.0000000000),
iqr: 30.0000000000,
};
check(val, summ);
}
#[test]
fn test_exp10a() {
- let val = &[
- 23.0000000000,
- 11.0000000000,
- 2.0000000000,
- 57.0000000000,
- 4.0000000000,
- 12.0000000000,
- 5.0000000000,
- 29.0000000000,
- 3.0000000000,
- 21.0000000000,
- ];
+ let val = &[23.0000000000,
+ 11.0000000000,
+ 2.0000000000,
+ 57.0000000000,
+ 4.0000000000,
+ 12.0000000000,
+ 5.0000000000,
+ 29.0000000000,
+ 3.0000000000,
+ 21.0000000000];
let summ = &Summary {
sum: 167.0000000000,
min: 2.0000000000,
std_dev_pct: 101.5828843560,
median_abs_dev: 13.3434000000,
median_abs_dev_pct: 116.0295652174,
- quartiles: (4.2500000000,11.5000000000,22.5000000000),
+ quartiles: (4.2500000000, 11.5000000000, 22.5000000000),
iqr: 18.2500000000,
};
check(val, summ);
}
#[test]
fn test_exp10b() {
- let val = &[
- 24.0000000000,
- 17.0000000000,
- 6.0000000000,
- 38.0000000000,
- 25.0000000000,
- 7.0000000000,
- 51.0000000000,
- 2.0000000000,
- 61.0000000000,
- 32.0000000000,
- ];
+ let val = &[24.0000000000,
+ 17.0000000000,
+ 6.0000000000,
+ 38.0000000000,
+ 25.0000000000,
+ 7.0000000000,
+ 51.0000000000,
+ 2.0000000000,
+ 61.0000000000,
+ 32.0000000000];
let summ = &Summary {
sum: 263.0000000000,
min: 2.0000000000,
std_dev_pct: 74.4671410520,
median_abs_dev: 22.9803000000,
median_abs_dev_pct: 93.7971428571,
- quartiles: (9.5000000000,24.5000000000,36.5000000000),
+ quartiles: (9.5000000000, 24.5000000000, 36.5000000000),
iqr: 27.0000000000,
};
check(val, summ);
}
#[test]
fn test_exp10c() {
- let val = &[
- 71.0000000000,
- 2.0000000000,
- 32.0000000000,
- 1.0000000000,
- 6.0000000000,
- 28.0000000000,
- 13.0000000000,
- 37.0000000000,
- 16.0000000000,
- 36.0000000000,
- ];
+ let val = &[71.0000000000,
+ 2.0000000000,
+ 32.0000000000,
+ 1.0000000000,
+ 6.0000000000,
+ 28.0000000000,
+ 13.0000000000,
+ 37.0000000000,
+ 16.0000000000,
+ 36.0000000000];
let summ = &Summary {
sum: 242.0000000000,
min: 1.0000000000,
std_dev_pct: 88.4507754589,
median_abs_dev: 21.4977000000,
median_abs_dev_pct: 97.7168181818,
- quartiles: (7.7500000000,22.0000000000,35.0000000000),
+ quartiles: (7.7500000000, 22.0000000000, 35.0000000000),
iqr: 27.2500000000,
};
check(val, summ);
}
#[test]
fn test_exp25() {
- let val = &[
- 3.0000000000,
- 24.0000000000,
- 1.0000000000,
- 19.0000000000,
- 7.0000000000,
- 5.0000000000,
- 30.0000000000,
- 39.0000000000,
- 31.0000000000,
- 13.0000000000,
- 25.0000000000,
- 48.0000000000,
- 1.0000000000,
- 6.0000000000,
- 42.0000000000,
- 63.0000000000,
- 2.0000000000,
- 12.0000000000,
- 108.0000000000,
- 26.0000000000,
- 1.0000000000,
- 7.0000000000,
- 44.0000000000,
- 25.0000000000,
- 11.0000000000,
- ];
+ let val = &[3.0000000000,
+ 24.0000000000,
+ 1.0000000000,
+ 19.0000000000,
+ 7.0000000000,
+ 5.0000000000,
+ 30.0000000000,
+ 39.0000000000,
+ 31.0000000000,
+ 13.0000000000,
+ 25.0000000000,
+ 48.0000000000,
+ 1.0000000000,
+ 6.0000000000,
+ 42.0000000000,
+ 63.0000000000,
+ 2.0000000000,
+ 12.0000000000,
+ 108.0000000000,
+ 26.0000000000,
+ 1.0000000000,
+ 7.0000000000,
+ 44.0000000000,
+ 25.0000000000,
+ 11.0000000000];
let summ = &Summary {
sum: 593.0000000000,
min: 1.0000000000,
std_dev_pct: 103.3565983562,
median_abs_dev: 19.2738000000,
median_abs_dev_pct: 101.4410526316,
- quartiles: (6.0000000000,19.0000000000,31.0000000000),
+ quartiles: (6.0000000000, 19.0000000000, 31.0000000000),
iqr: 25.0000000000,
};
check(val, summ);
}
#[test]
fn test_binom25() {
- let val = &[
- 18.0000000000,
- 17.0000000000,
- 27.0000000000,
- 15.0000000000,
- 21.0000000000,
- 25.0000000000,
- 17.0000000000,
- 24.0000000000,
- 25.0000000000,
- 24.0000000000,
- 26.0000000000,
- 26.0000000000,
- 23.0000000000,
- 15.0000000000,
- 23.0000000000,
- 17.0000000000,
- 18.0000000000,
- 18.0000000000,
- 21.0000000000,
- 16.0000000000,
- 15.0000000000,
- 31.0000000000,
- 20.0000000000,
- 17.0000000000,
- 15.0000000000,
- ];
+ let val = &[18.0000000000,
+ 17.0000000000,
+ 27.0000000000,
+ 15.0000000000,
+ 21.0000000000,
+ 25.0000000000,
+ 17.0000000000,
+ 24.0000000000,
+ 25.0000000000,
+ 24.0000000000,
+ 26.0000000000,
+ 26.0000000000,
+ 23.0000000000,
+ 15.0000000000,
+ 23.0000000000,
+ 17.0000000000,
+ 18.0000000000,
+ 18.0000000000,
+ 21.0000000000,
+ 16.0000000000,
+ 15.0000000000,
+ 31.0000000000,
+ 20.0000000000,
+ 17.0000000000,
+ 15.0000000000];
let summ = &Summary {
sum: 514.0000000000,
min: 15.0000000000,
std_dev_pct: 22.2037202539,
median_abs_dev: 5.9304000000,
median_abs_dev_pct: 29.6520000000,
- quartiles: (17.0000000000,20.0000000000,24.0000000000),
+ quartiles: (17.0000000000, 20.0000000000, 24.0000000000),
iqr: 7.0000000000,
};
check(val, summ);
}
#[test]
fn test_pois25lambda30() {
- let val = &[
- 27.0000000000,
- 33.0000000000,
- 34.0000000000,
- 34.0000000000,
- 24.0000000000,
- 39.0000000000,
- 28.0000000000,
- 27.0000000000,
- 31.0000000000,
- 28.0000000000,
- 38.0000000000,
- 21.0000000000,
- 33.0000000000,
- 36.0000000000,
- 29.0000000000,
- 37.0000000000,
- 32.0000000000,
- 34.0000000000,
- 31.0000000000,
- 39.0000000000,
- 25.0000000000,
- 31.0000000000,
- 32.0000000000,
- 40.0000000000,
- 24.0000000000,
- ];
+ let val = &[27.0000000000,
+ 33.0000000000,
+ 34.0000000000,
+ 34.0000000000,
+ 24.0000000000,
+ 39.0000000000,
+ 28.0000000000,
+ 27.0000000000,
+ 31.0000000000,
+ 28.0000000000,
+ 38.0000000000,
+ 21.0000000000,
+ 33.0000000000,
+ 36.0000000000,
+ 29.0000000000,
+ 37.0000000000,
+ 32.0000000000,
+ 34.0000000000,
+ 31.0000000000,
+ 39.0000000000,
+ 25.0000000000,
+ 31.0000000000,
+ 32.0000000000,
+ 40.0000000000,
+ 24.0000000000];
let summ = &Summary {
sum: 787.0000000000,
min: 21.0000000000,
std_dev_pct: 16.3814245145,
median_abs_dev: 5.9304000000,
median_abs_dev_pct: 18.5325000000,
- quartiles: (28.0000000000,32.0000000000,34.0000000000),
+ quartiles: (28.0000000000, 32.0000000000, 34.0000000000),
iqr: 6.0000000000,
};
check(val, summ);
}
#[test]
fn test_pois25lambda40() {
- let val = &[
- 42.0000000000,
- 50.0000000000,
- 42.0000000000,
- 46.0000000000,
- 34.0000000000,
- 45.0000000000,
- 34.0000000000,
- 49.0000000000,
- 39.0000000000,
- 28.0000000000,
- 40.0000000000,
- 35.0000000000,
- 37.0000000000,
- 39.0000000000,
- 46.0000000000,
- 44.0000000000,
- 32.0000000000,
- 45.0000000000,
- 42.0000000000,
- 37.0000000000,
- 48.0000000000,
- 42.0000000000,
- 33.0000000000,
- 42.0000000000,
- 48.0000000000,
- ];
+ let val = &[42.0000000000,
+ 50.0000000000,
+ 42.0000000000,
+ 46.0000000000,
+ 34.0000000000,
+ 45.0000000000,
+ 34.0000000000,
+ 49.0000000000,
+ 39.0000000000,
+ 28.0000000000,
+ 40.0000000000,
+ 35.0000000000,
+ 37.0000000000,
+ 39.0000000000,
+ 46.0000000000,
+ 44.0000000000,
+ 32.0000000000,
+ 45.0000000000,
+ 42.0000000000,
+ 37.0000000000,
+ 48.0000000000,
+ 42.0000000000,
+ 33.0000000000,
+ 42.0000000000,
+ 48.0000000000];
let summ = &Summary {
sum: 1019.0000000000,
min: 28.0000000000,
std_dev_pct: 14.3978417577,
median_abs_dev: 5.9304000000,
median_abs_dev_pct: 14.1200000000,
- quartiles: (37.0000000000,42.0000000000,45.0000000000),
+ quartiles: (37.0000000000, 42.0000000000, 45.0000000000),
iqr: 8.0000000000,
};
check(val, summ);
}
#[test]
fn test_pois25lambda50() {
- let val = &[
- 45.0000000000,
- 43.0000000000,
- 44.0000000000,
- 61.0000000000,
- 51.0000000000,
- 53.0000000000,
- 59.0000000000,
- 52.0000000000,
- 49.0000000000,
- 51.0000000000,
- 51.0000000000,
- 50.0000000000,
- 49.0000000000,
- 56.0000000000,
- 42.0000000000,
- 52.0000000000,
- 51.0000000000,
- 43.0000000000,
- 48.0000000000,
- 48.0000000000,
- 50.0000000000,
- 42.0000000000,
- 43.0000000000,
- 42.0000000000,
- 60.0000000000,
- ];
+ let val = &[45.0000000000,
+ 43.0000000000,
+ 44.0000000000,
+ 61.0000000000,
+ 51.0000000000,
+ 53.0000000000,
+ 59.0000000000,
+ 52.0000000000,
+ 49.0000000000,
+ 51.0000000000,
+ 51.0000000000,
+ 50.0000000000,
+ 49.0000000000,
+ 56.0000000000,
+ 42.0000000000,
+ 52.0000000000,
+ 51.0000000000,
+ 43.0000000000,
+ 48.0000000000,
+ 48.0000000000,
+ 50.0000000000,
+ 42.0000000000,
+ 43.0000000000,
+ 42.0000000000,
+ 60.0000000000];
let summ = &Summary {
sum: 1235.0000000000,
min: 42.0000000000,
std_dev_pct: 11.3913245723,
median_abs_dev: 4.4478000000,
median_abs_dev_pct: 8.8956000000,
- quartiles: (44.0000000000,50.0000000000,52.0000000000),
+ quartiles: (44.0000000000, 50.0000000000, 52.0000000000),
iqr: 8.0000000000,
};
check(val, summ);
}
#[test]
fn test_unif25() {
- let val = &[
- 99.0000000000,
- 55.0000000000,
- 92.0000000000,
- 79.0000000000,
- 14.0000000000,
- 2.0000000000,
- 33.0000000000,
- 49.0000000000,
- 3.0000000000,
- 32.0000000000,
- 84.0000000000,
- 59.0000000000,
- 22.0000000000,
- 86.0000000000,
- 76.0000000000,
- 31.0000000000,
- 29.0000000000,
- 11.0000000000,
- 41.0000000000,
- 53.0000000000,
- 45.0000000000,
- 44.0000000000,
- 98.0000000000,
- 98.0000000000,
- 7.0000000000,
- ];
+ let val = &[99.0000000000,
+ 55.0000000000,
+ 92.0000000000,
+ 79.0000000000,
+ 14.0000000000,
+ 2.0000000000,
+ 33.0000000000,
+ 49.0000000000,
+ 3.0000000000,
+ 32.0000000000,
+ 84.0000000000,
+ 59.0000000000,
+ 22.0000000000,
+ 86.0000000000,
+ 76.0000000000,
+ 31.0000000000,
+ 29.0000000000,
+ 11.0000000000,
+ 41.0000000000,
+ 53.0000000000,
+ 45.0000000000,
+ 44.0000000000,
+ 98.0000000000,
+ 98.0000000000,
+ 7.0000000000];
let summ = &Summary {
sum: 1242.0000000000,
min: 2.0000000000,
std_dev_pct: 64.1488719719,
median_abs_dev: 45.9606000000,
median_abs_dev_pct: 102.1346666667,
- quartiles: (29.0000000000,45.0000000000,79.0000000000),
+ quartiles: (29.0000000000, 45.0000000000, 79.0000000000),
iqr: 50.0000000000,
};
check(val, summ);
#[bench]
pub fn sum_many_f64(b: &mut Bencher) {
let nums = [-1e30f64, 1e60, 1e30, 1.0, -1e60];
- let v = (0..500).map(|i| nums[i%5]).collect::<Vec<_>>();
+ let v = (0..500).map(|i| nums[i % 5]).collect::<Vec<_>>();
b.iter(|| {
v.sum();
#include <stdint.h>
#include <assert.h>
+#include <stdarg.h>
// These functions are used in the unit tests for C ABI calls.
uint64_t get_c_many_params(void *a, void *b, void *c, void *d, struct quad f) {
return f.c;
}
+
+// Calculates the average of `(x + y) / n` where x: i64, y: f64. There must be exactly n pairs
+// passed as variadic arguments.
+double rust_interesting_average(uint64_t n, ...) {
+ va_list pairs;
+ double sum = 0.0;
+ int i;
+ va_start(pairs, n);
+ for(i = 0; i < n; i += 1) {
+ sum += (double)va_arg(pairs, int64_t);
+ sum += va_arg(pairs, double);
+ }
+ va_end(pairs);
+ return sum / n;
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-msvc everything is the system allocator on msvc
+// ignore-windows everything is the system allocator on windows
// ignore-musl no dylibs on musl yet
// ignore-bitrig no jemalloc on bitrig
// ignore-openbsd no jemalloc on openbsd
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-msvc everything is the system allocator on msvc
+// ignore-windows everything is the system allocator on windows
// ignore-musl no dylibs on musl right now
// ignore-bitrig no jemalloc on bitrig
// ignore-openbsd no jemalloc on openbsd
let e3 = E::Empty3; //~ ERROR `E::Empty3` is the name of a struct or struct variant
let e3 = E::Empty3(); //~ ERROR `E::Empty3` is the name of a struct or struct variant
- // FIXME: non-local struct kind should be known early (e.g. kept in `DefStruct`)
- // let xe1 = XEmpty1; // ERROR `XEmpty1` is the name of a struct or struct variant
- let xe1 = XEmpty1(); //~ ERROR expected function, found `empty_struct::XEmpty1`
+ let xe1 = XEmpty1; //~ ERROR `XEmpty1` is the name of a struct or struct variant
+ let xe1 = XEmpty1(); //~ ERROR `XEmpty1` is the name of a struct or struct variant
let xe3 = XE::Empty3; //~ ERROR no associated item named `Empty3` found for type
let xe3 = XE::Empty3(); //~ ERROR no associated item named `Empty3` found for type
}
Empty1(..) => () //~ ERROR unresolved enum variant, struct or const `Empty1`
}
match xe1 {
- XEmpty1(..) => () //~ ERROR `XEmpty1` does not name a tuple variant or a tuple struct
+ XEmpty1(..) => () //~ ERROR unresolved enum variant, struct or const `XEmpty1`
}
}
impl S { }
}
-fn foo(_: a::S) { //~ ERROR: type `S` is private
+fn foo(_: a::S) { //~ ERROR: struct `S` is private
}
fn main() {}
}
fn main() {
- if 1 == 2 { forever(); }
}
--- /dev/null
+// 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.
+
+fn test1() {
+ // In this test the outer 'a loop may terminate without `x` getting initialised. Although the
+ // `x = loop { ... }` statement is reached, the value itself ends up never being computed and
+ // thus leaving `x` uninit.
+ let x: i32;
+ 'a: loop {
+ x = loop { break 'a };
+ }
+ println!("{:?}", x); //~ ERROR use of possibly uninitialized variable
+}
+
+// test2 and test3 should not fail.
+fn test2() {
+ // In this test the `'a` loop will never terminate thus making the use of `x` unreachable.
+ let x: i32;
+ 'a: loop {
+ x = loop { continue 'a };
+ }
+ println!("{:?}", x);
+}
+
+fn test3() {
+ let x: i32;
+ // Similarly, the use of variable `x` is unreachable.
+ 'a: loop {
+ x = loop { return };
+ }
+ println!("{:?}", x);
+}
+
+fn main() {
+}
--- /dev/null
+// 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.
+
+fn forever2() -> i32 {
+ let x: i32 = loop { break }; //~ ERROR mismatched types
+ x
+}
+
+fn main() {}
--- /dev/null
+// 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.
+
+fn forever2() -> ! { //~ ERROR computation may converge in a function marked as diverging
+ loop { break }
+}
+
+fn main() {}
// Even though the inner `A` struct is a publicly exported item (usable from
// external crates through `foo::foo`, it should not be accessible through
// its definition path (which has the private `i` module).
- use self::foo::i::A; //~ ERROR: type `A` is inaccessible
+ use self::foo::i::A; //~ ERROR: struct `A` is inaccessible
//~^ NOTE: module `i` is private
pub mod foo {
}
fn test(a: A, b: inner::A, c: inner::B, d: xc::A, e: xc::B) {
- //~^ ERROR: type `A` is private
+ //~^ ERROR: struct `A` is private
//~^^ ERROR: struct `A` is private
a.a;
extern crate xcrate_unit_struct;
fn main() {
- let _ = xcrate_unit_struct::StructWithFields; //~ ERROR: unresolved name
+ let _ = xcrate_unit_struct::StructWithFields;
+ //~^ ERROR: `xcrate_unit_struct::StructWithFields` is the name of a struct or struct variant
let _ = xcrate_unit_struct::Struct;
}
ifdef IS_MSVC
$(TMPDIR)/$(call BIN,bar): $(call DYLIB,foo)
- $(CC) bar.c $(TMPDIR)/foo.lib $(call OUT_EXE,bar)
+ $(CC) bar.c $(TMPDIR)/foo.dll.lib $(call OUT_EXE,bar)
else
$(TMPDIR)/$(call BIN,bar): $(call DYLIB,foo)
$(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) -L $(TMPDIR)
ifneq ($(shell uname),FreeBSD)
all:
$(RUSTC) foo.rs
- cp $(TMPDIR)/libfoo.a $(call NATIVE_STATICLIB,foo2)
- $(CC) bar.c $(call NATIVE_STATICLIB,foo2) $(call OUT_EXE,bar) \
+ $(CC) bar.c $(call STATICLIB,foo) $(call OUT_EXE,bar) \
$(EXTRACFLAGS) $(EXTRACXXFLAGS)
$(call RUN,bar)
- rm $(call STATICLIB,foo*)
+ rm $(call STATICLIB,foo)
$(call RUN,bar)
else
all:
$(RUSTC) foo.rs -C lto
- $(CC) bar.c $(TMPDIR)/libfoo.a \
+ $(CC) bar.c $(call STATICLIB,foo) \
$(call OUT_EXE,bar) \
$(EXTRACFLAGS) $(EXTRACXXFLAGS)
$(call RUN,bar)
$(RUSTC) foo.rs --crate-type=rlib,dylib,staticlib
$(call REMOVE_RLIBS,bar)
$(call REMOVE_DYLIBS,bar)
- rm $(TMPDIR)/libbar.a
- rm -f $(TMPDIR)/bar.{exp,lib,pdb}
+ rm $(call STATICLIB,bar)
+ rm -f $(TMPDIR)/bar.{dll.exp,dll.lib,pdb}
# Check that $(TMPDIR) is empty.
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
rm $(TMPDIR)/$(call BIN,foo)
$(RUSTC) foo.rs --crate-type=dylib --emit=link=$(TMPDIR)/$(call BIN,foo)
rm $(TMPDIR)/$(call BIN,foo)
- rm -f $(TMPDIR)/foo.{exp,lib,pdb}
+ rm -f $(TMPDIR)/foo.{dll.exp,dll.lib,pdb}
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
$(RUSTC) foo.rs --crate-type=staticlib -o $(TMPDIR)/foo
rm $(TMPDIR)/bar.ll
rm $(TMPDIR)/bar.s
rm $(TMPDIR)/bar.o
- rm $(TMPDIR)/libbar.a
+ rm $(call STATICLIB,bar)
mv $(TMPDIR)/bar.bc $(TMPDIR)/foo.bc
# Don't check that the $(TMPDIR) is empty - we left `foo.bc` for later
# comparison.
TO_LINK := $(call DYLIB,bar)
ifdef IS_MSVC
-LINK_ARG = $(TO_LINK:dll=lib)
+LINK_ARG = $(TO_LINK:dll=dll.lib)
else
LINK_ARG = $(TO_LINK)
endif
#![feature(alloc_jemalloc, alloc_system)]
-#[cfg(not(any(target_env = "msvc", target_os = "bitrig", target_os = "openbsd")))]
+#[cfg(not(any(windows, target_os = "bitrig", target_os = "openbsd")))]
extern crate alloc_jemalloc;
-#[cfg(any(target_env = "msvc", target_os = "bitrig", target_os = "openbsd"))]
+#[cfg(any(windows, target_os = "bitrig", target_os = "openbsd"))]
extern crate alloc_system;
fn main() {
// except according to those terms.
// no-prefer-dynamic
-// ignore-msvc no jemalloc on msvc
+// ignore-windows no jemalloc on windows
// ignore-bitrig no jemalloc on bitrig
// ignore-openbsd no jemalloc on openbsd
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// aux-build:empty-struct.rs
+
#![feature(associated_consts)]
+extern crate empty_struct;
+use empty_struct::XEmpty2 as XFoo;
+
struct Foo;
enum Bar {
const THEBAR: Bar = Bar::Var1;
}
+impl HasBar for XFoo {
+ const THEBAR: Bar = Bar::Var1;
+}
+
fn main() {
// Inherent impl
assert!(match Bar::Var2 {
<Foo as HasBar>::THEBAR => true,
_ => false,
});
+ assert!(match Bar::Var1 {
+ XFoo::THEBAR => true,
+ _ => false,
+ });
+ assert!(match Bar::Var1 {
+ <XFoo>::THEBAR => true,
+ _ => false,
+ });
+ assert!(match Bar::Var1 {
+ <XFoo as HasBar>::THEBAR => true,
+ _ => false,
+ });
}
Two::two()
}
+extern fn simple_extern(x: u32, y: (u32, u32)) -> u32 {
+ x + y.0 * y.1
+}
+
+#[rustc_mir]
+fn test9() -> u32 {
+ simple_extern(41, (42, 43))
+}
+
#[rustc_mir]
fn test_closure<F>(f: &F, x: i32, y: i32) -> i32
where F: Fn(i32, i32) -> i32
assert_eq!(test6(&Foo, 12367), 12367);
assert_eq!(test7(), 1);
assert_eq!(test8(), 2);
+ assert_eq!(test9(), 41 + 42 * 43);
let closure = |x: i32, y: i32| { x + y };
assert_eq!(test_closure(&closure, 100, 1), 101);
--- /dev/null
+// 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.
+
+#![feature(rustc_attrs)]
+
+#[link(name = "rust_test_helpers")]
+extern {
+ fn rust_interesting_average(_: i64, ...) -> f64;
+}
+
+#[rustc_mir]
+fn test(a: i64, b: i64, c: i64, d: i64, e: i64, f: i64) -> i64 {
+ unsafe {
+ rust_interesting_average(6, a, a as f64,
+ b, b as f64,
+ c, c as f64,
+ d, d as f64,
+ e, e as f64,
+ f, f as f64) as i64
+ }
+}
+
+fn main(){
+ assert_eq!(test(10, 20, 30, 40, 50, 60), 70);
+}
--- /dev/null
+// Copyright 2013 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::collections::BinaryHeap;
+use std::iter::Iterator;
+
+fn main() {
+ const N: usize = 8;
+
+ for len in 0..N {
+ let mut tester = BinaryHeap::with_capacity(len);
+ assert_eq!(tester.len(), 0);
+ assert!(tester.capacity() >= len);
+ for bit in 0..len {
+ tester.push(());
+ }
+ assert_eq!(tester.len(), len);
+ assert_eq!(tester.iter().count(), len);
+ tester.clear();
+ }
+}
--- /dev/null
+// Copyright 2013 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::{Ord, Ordering, PartialOrd};
+use std::collections::BTreeMap;
+use std::iter::Iterator;
+
+#[derive(Eq, Hash, Debug, Ord, PartialEq, PartialOrd)]
+struct Zst;
+
+fn main() {
+ const N: usize = 8;
+
+ for len in 0..N {
+ let mut tester = BTreeMap::new();
+ assert_eq!(tester.len(), 0);
+ for bit in 0..len {
+ tester.insert(Zst, ());
+ }
+ assert_eq!(tester.len(), if len == 0 { 0 } else { 1 });
+ assert_eq!(tester.iter().count(), if len == 0 { 0 } else { 1 });
+ assert_eq!(tester.get(&Zst).is_some(), len > 0);
+ tester.clear();
+ }
+}
--- /dev/null
+// Copyright 2013 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::collections::LinkedList;
+use std::iter::Iterator;
+
+fn main() {
+ const N: usize = 8;
+
+ // Test that for all possible sequences of push_front / push_back,
+ // we end up with a LinkedList of the correct size
+
+ for len in 0..N {
+ let mut tester = LinkedList::new();
+ assert_eq!(tester.len(), 0);
+ assert_eq!(tester.front(), None);
+ for case in 0..(1 << len) {
+ assert_eq!(tester.len(), 0);
+ for bit in 0..len {
+ if case & (1 << bit) != 0 {
+ tester.push_front(());
+ } else {
+ tester.push_back(());
+ }
+ }
+ assert_eq!(tester.len(), len);
+ assert_eq!(tester.iter().count(), len);
+ tester.clear();
+ }
+ }
+}
--- /dev/null
+// Copyright 2013 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::collections::VecDeque;
+use std::iter::Iterator;
+
+fn main() {
+ const N: usize = 8;
+
+ // Zero sized type
+ struct Zst;
+
+ // Test that for all possible sequences of push_front / push_back,
+ // we end up with a deque of the correct size
+
+ for len in 0..N {
+ let mut tester = VecDeque::with_capacity(len);
+ assert_eq!(tester.len(), 0);
+ assert!(tester.capacity() >= len);
+ for case in 0..(1 << len) {
+ assert_eq!(tester.len(), 0);
+ for bit in 0..len {
+ if case & (1 << bit) != 0 {
+ tester.push_front(Zst);
+ } else {
+ tester.push_back(Zst);
+ }
+ }
+ assert_eq!(tester.len(), len);
+ assert_eq!(tester.iter().count(), len);
+ tester.clear();
+ }
+ }
+}
--- /dev/null
+// Copyright 2013 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::iter::Iterator;
+use std::vec::Vec;
+
+fn main() {
+ const N: usize = 8;
+
+ for len in 0..N {
+ let mut tester = Vec::with_capacity(len);
+ assert_eq!(tester.len(), 0);
+ assert!(tester.capacity() >= len);
+ for bit in 0..len {
+ tester.push(());
+ }
+ assert_eq!(tester.len(), len);
+ assert_eq!(tester.iter().count(), len);
+ tester.clear();
+ }
+}