1. Make sure you have installed the dependencies:
* `g++` 4.7 or `clang++` 3.x
- * `python` 2.6 or later (but not 3.x)
+ * `python` 2.7 or later (but not 3.x)
* GNU `make` 3.81 or later
* `curl`
* `git`
CFG_LIB_GLOB_x86_64-unknown-bitrig=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_x86_64-unknown-bitrig=$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_x86_64-unknown-bitrig := -m64 -I/usr/include $(CFLAGS)
-CFG_GCCISH_CFLAGS_x86_64-unknown-bitrig := -Wall -Werror -fPIC -m64 -I/usr/include $(CFLAGS)
+CFG_GCCISH_CFLAGS_x86_64-unknown-bitrig := -Wall -Werror -fPIE -fPIC -m64 -I/usr/include $(CFLAGS)
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-bitrig := -shared -pic -pthread -m64 $(LDFLAGS)
CFG_GCCISH_DEF_FLAG_x86_64-unknown-bitrig := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_x86_64-unknown-bitrig :=
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
DEPS_rustc_metadata := rustc rustc_front syntax rbml
DEPS_rustc_mir := rustc rustc_front syntax
-DEPS_rustc_resolve := rustc rustc_front log syntax
+DEPS_rustc_resolve := arena rustc rustc_front log syntax
DEPS_rustc_platform_intrinsics := rustc rustc_llvm
DEPS_rustc_plugin := rustc rustc_metadata syntax
DEPS_rustc_privacy := rustc rustc_front log syntax
* [Non-blocking steal-half work queues](http://www.cs.bgu.ac.il/%7Ehendlerd/papers/p280-hendler.pdf)
* [Reagents: expressing and composing fine-grained concurrency](http://www.mpi-sws.org/~turon/reagents.pdf)
* [Algorithms for scalable synchronization of shared-memory multiprocessors](https://www.cs.rochester.edu/u/scott/papers/1991_TOCS_synch.pdf)
-* [Epoc-based reclamation](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf).
+* [Epoch-based reclamation](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf).
### Others
```
It’s important to be able to explicitly delineate code that may have bugs that
-cause big problems. If a Rust program segfaults, you can be sure it’s somewhere
-in the sections marked `unsafe`.
+cause big problems. If a Rust program segfaults, you can be sure the cause is
+related to something marked `unsafe`.
# What does ‘safe’ mean?
* `let` statements where an explicit type is given.
- For example, `128` is coerced to have type `i8` in the following:
+ For example, `42` is coerced to have type `i8` in the following:
```rust
- let _: i8 = 128;
+ let _: i8 = 42;
```
* `static` and `const` statements (similar to `let` statements).
The value being coerced is the actual parameter, and it is coerced to
the type of the formal parameter.
- For example, `128` is coerced to have type `i8` in the following:
+ For example, `42` is coerced to have type `i8` in the following:
```rust
fn bar(_: i8) { }
fn main() {
- bar(128);
+ bar(42);
}
```
* Instantiations of struct or variant fields
- For example, `128` is coerced to have type `i8` in the following:
+ For example, `42` is coerced to have type `i8` in the following:
```rust
struct Foo { x: i8 }
fn main() {
- Foo { x: 128 };
+ Foo { x: 42 };
}
```
* Function results, either the final line of a block if it is not
semicolon-terminated or any expression in a `return` statement
- For example, `128` is coerced to have type `i8` in the following:
+ For example, `42` is coerced to have type `i8` in the following:
```rust
fn foo() -> i8 {
- 128
+ 42
}
```
#![feature(unsize)]
#![feature(drop_in_place)]
#![feature(fn_traits)]
+#![feature(const_fn)]
#![feature(needs_allocator)]
+// Issue# 30592: Systematically use alloc_system during stage0 since jemalloc
+// might be unavailable or disabled
+#![cfg_attr(stage0, feature(alloc_system))]
+
#![cfg_attr(test, feature(test, rustc_private, box_heap))]
+#[cfg(stage0)]
+extern crate alloc_system;
+
// Allow testing this library
#[cfg(test)]
pub mod arc;
pub mod rc;
pub mod raw_vec;
+pub mod oom;
-/// Common out-of-memory routine
-#[cold]
-#[inline(never)]
-#[unstable(feature = "oom", reason = "not a scrutinized interface",
- issue = "27700")]
-pub fn oom() -> ! {
- // FIXME(#14674): This really needs to do something other than just abort
- // here, but any printing done must be *guaranteed* to not
- // allocate.
- unsafe { core::intrinsics::abort() }
-}
+pub use oom::oom;
--- /dev/null
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core::sync::atomic::{AtomicPtr, Ordering};
+use core::mem;
+use core::intrinsics;
+
+static OOM_HANDLER: AtomicPtr<()> = AtomicPtr::new(default_oom_handler as *mut ());
+
+fn default_oom_handler() -> ! {
+ // The default handler can't do much more since we can't assume the presence
+ // of libc or any way of printing an error message.
+ unsafe { intrinsics::abort() }
+}
+
+/// Common out-of-memory routine
+#[cold]
+#[inline(never)]
+#[unstable(feature = "oom", reason = "not a scrutinized interface",
+ issue = "27700")]
+pub fn oom() -> ! {
+ let value = OOM_HANDLER.load(Ordering::SeqCst);
+ let handler: fn() -> ! = unsafe { mem::transmute(value) };
+ handler();
+}
+
+/// Set a custom handler for out-of-memory conditions
+///
+/// To avoid recursive OOM failures, it is critical that the OOM handler does
+/// not allocate any memory itself.
+#[unstable(feature = "oom", reason = "not a scrutinized interface",
+ issue = "27700")]
+pub fn set_oom_handler(handler: fn() -> !) {
+ OOM_HANDLER.store(handler as *mut (), Ordering::SeqCst);
+}
//! Collection types.
//!
-//! See [std::collections](../std/collections) for a detailed discussion of
+//! See [std::collections](../std/collections/index.html) for a detailed discussion of
//! collections in Rust.
#![crate_name = "collections"]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![unstable(feature = "collections_range", reason = "was just added",
- issue = "27711")]
+#![unstable(feature = "collections_range",
+ reason = "waiting for dust to settle on inclusive ranges",
+ issue = "30877")]
//! Range syntax.
///
/// For iterating from the front, the [`matches()`] method can be used.
///
- /// [`matches`]: #method.matches
+ /// [`matches()`]: #method.matches
///
/// # Examples
///
//!
//! [`String`]: struct.String.html
//! [`ToString`]: trait.ToString.html
+//!
+//! # Examples
+//!
+//! There are multiple ways to create a new `String` from a string literal:
+//!
+//! ```rust
+//! let s = "Hello".to_string();
+//!
+//! let s = String::from("world");
+//! let s: String = "also this".into();
+//! ```
+//!
+//! You can create a new `String` from an existing one by concatenating with
+//! `+`:
+//!
+//! ```rust
+//! let s = "Hello".to_string();
+//!
+//! let message = s + " world!";
+//! ```
+//!
+//! If you have a vector of valid UTF-8 bytes, you can make a `String` out of
+//! it. You can do the reverse too.
+//!
+//! ```rust
+//! let sparkle_heart = vec![240, 159, 146, 150];
+//!
+//! // We know these bytes are valid, so we'll use `unwrap()`.
+//! let sparkle_heart = String::from_utf8(sparkle_heart).unwrap();
+//!
+//! assert_eq!("💖", sparkle_heart);
+//!
+//! let bytes = sparkle_heart.into_bytes();
+//!
+//! assert_eq!(bytes, [240, 159, 146, 150]);
+//! ```
#![stable(feature = "rust1", since = "1.0.0")]
/// hello.push_str("orld!");
/// ```
///
+/// [`char`]: ../primitive.char.html
/// [`push()`]: #method.push
/// [`push_str()`]: #method.push_str
///
/// ```
///
/// [`as_ptr()`]: #method.as_ptr
-/// [`len()`]: # method.len
-/// [`capacity()`]: # method.capacity
+/// [`len()`]: #method.len
+/// [`capacity()`]: #method.capacity
///
/// If a `String` has enough capacity, adding elements to it will not
/// re-allocate. For example, consider this program:
/// Converts a slice of bytes to a `String`, including invalid characters.
///
/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a slice of
- /// bytes ([`&[u8]`]) is made of bytes, so this function converts between
+ /// bytes ([`&[u8]`][byteslice]) is made of bytes, so this function converts between
/// the two. Not all byte slices are valid string slices, however: [`&str`]
/// requires that it is valid UTF-8. During this conversion,
/// `from_utf8_lossy()` will replace any invalid UTF-8 sequences with
///
/// [`&str`]: ../primitive.str.html
/// [`u8`]: ../primitive.u8.html
- /// [`&[u8]`]: ../primitive.slice.html
+ /// [byteslice]: ../primitive.slice.html
///
/// If you are sure that the byte slice is valid UTF-8, and you don't want
/// to incur the overhead of the conversion, there is an unsafe version
///
/// [`Utf8Error`]: ../str/struct.Utf8Error.html
/// [`std::str`]: ../str/index.html
+ /// [`u8`]: ../primitive.u8.html
+ /// [`&str`]: ../primitive.str.html
///
/// # Examples
///
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Debug for PhantomData<T> {
+impl<T: ?Sized> Debug for PhantomData<T> {
fn fmt(&self, f: &mut Formatter) -> Result {
f.pad("PhantomData")
}
/// One of the keys to `collect()`'s power is that many things you might
/// not think of as 'collections' actually are. For example, a [`String`]
/// is a collection of [`char`]s. And a collection of [`Result<T, E>`] can
- /// be thought of as single [`Result<Collection<T>, E>`]. See the examples
+ /// be thought of as single `Result<Collection<T>, E>`. See the examples
/// below for more.
///
/// [`String`]: ../string/struct.String.html
// `Int` + `SignedInt` implemented for signed integers
macro_rules! int_impl {
- ($ActualT:ty, $UnsignedT:ty, $BITS:expr,
+ ($ActualT:ident, $UnsignedT:ty, $BITS:expr,
$add_with_overflow:path,
$sub_with_overflow:path,
$mul_with_overflow:path) => {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn checked_add(self, other: Self) -> Option<Self> {
- checked_op!($ActualT, $add_with_overflow, self, other)
+ let (a, b) = self.overflowing_add(other);
+ if b {None} else {Some(a)}
}
/// Checked integer subtraction. Computes `self - other`, returning
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn checked_sub(self, other: Self) -> Option<Self> {
- checked_op!($ActualT, $sub_with_overflow, self, other)
+ let (a, b) = self.overflowing_sub(other);
+ if b {None} else {Some(a)}
}
/// Checked integer multiplication. Computes `self * other`, returning
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn checked_mul(self, other: Self) -> Option<Self> {
- checked_op!($ActualT, $mul_with_overflow, self, other)
+ let (a, b) = self.overflowing_mul(other);
+ if b {None} else {Some(a)}
}
/// Checked integer division. Computes `self / other`, returning `None`
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn checked_div(self, other: Self) -> Option<Self> {
- match other {
- 0 => None,
- -1 if self == Self::min_value()
- => None,
- other => Some(self / other),
+ if other == 0 {
+ None
+ } else {
+ let (a, b) = self.overflowing_div(other);
+ if b {None} else {Some(a)}
}
}
+ /// Checked integer remainder. Computes `self % other`, returning `None`
+ /// if `other == 0` or the operation results in underflow or overflow.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// use std::i32;
+ ///
+ /// assert_eq!(5i32.checked_rem(2), Some(1));
+ /// assert_eq!(5i32.checked_rem(0), None);
+ /// assert_eq!(i32::MIN.checked_rem(-1), None);
+ /// ```
+ #[unstable(feature = "wrapping", issue = "27755")]
+ #[inline]
+ pub fn checked_rem(self, other: Self) -> Option<Self> {
+ if other == 0 {
+ None
+ } else {
+ let (a, b) = self.overflowing_rem(other);
+ if b {None} else {Some(a)}
+ }
+ }
+
+ /// Checked negation. Computes `!self`, returning `None` if `self ==
+ /// MIN`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// use std::i32;
+ ///
+ /// assert_eq!(5i32.checked_neg(), Some(-5));
+ /// assert_eq!(i32::MIN.checked_neg(), None);
+ /// ```
+ #[unstable(feature = "wrapping", issue = "27755")]
+ #[inline]
+ pub fn checked_neg(self) -> Option<Self> {
+ let (a, b) = self.overflowing_neg();
+ if b {None} else {Some(a)}
+ }
+
+ /// Checked shift left. Computes `self << rhs`, returning `None`
+ /// if `rhs` is larger than or equal to the number of bits in `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(0x10i32.checked_shl(4), Some(0x100));
+ /// assert_eq!(0x10i32.checked_shl(33), None);
+ /// ```
+ #[unstable(feature = "wrapping", issue = "27755")]
+ #[inline]
+ pub fn checked_shl(self, rhs: u32) -> Option<Self> {
+ let (a, b) = self.overflowing_shl(rhs);
+ if b {None} else {Some(a)}
+ }
+
+ /// Checked shift right. Computes `self >> rhs`, returning `None`
+ /// if `rhs` is larger than or equal to the number of bits in `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(0x10i32.checked_shr(4), Some(0x1));
+ /// assert_eq!(0x10i32.checked_shr(33), None);
+ /// ```
+ #[unstable(feature = "wrapping", issue = "27755")]
+ #[inline]
+ pub fn checked_shr(self, rhs: u32) -> Option<Self> {
+ let (a, b) = self.overflowing_shr(rhs);
+ if b {None} else {Some(a)}
+ }
+
/// Saturating integer addition. Computes `self + other`, saturating at
/// the numeric bounds instead of overflowing.
///
#[inline]
pub fn saturating_add(self, other: Self) -> Self {
match self.checked_add(other) {
- Some(x) => x,
+ Some(x) => x,
None if other >= Self::zero() => Self::max_value(),
None => Self::min_value(),
}
#[inline]
pub fn saturating_sub(self, other: Self) -> Self {
match self.checked_sub(other) {
- Some(x) => x,
+ Some(x) => x,
None if other >= Self::zero() => Self::min_value(),
None => Self::max_value(),
}
}
+ /// Saturating integer multiplication. Computes `self * other`,
+ /// saturating at the numeric bounds instead of overflowing.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// use std::i32;
+ ///
+ /// assert_eq!(100i32.saturating_mul(127), 12700);
+ /// assert_eq!((1i32 << 23).saturating_mul(1 << 23), i32::MAX);
+ /// assert_eq!((-1i32 << 23).saturating_mul(1 << 23), i32::MIN);
+ /// ```
+ #[unstable(feature = "wrapping", issue = "27755")]
+ #[inline]
+ pub fn saturating_mul(self, other: Self) -> Self {
+ self.checked_mul(other).unwrap_or_else(|| {
+ if (self < 0 && other < 0) || (self > 0 && other > 0) {
+ Self::max_value()
+ } else {
+ Self::min_value()
+ }
+ })
+ }
+
/// Wrapping (modular) addition. Computes `self + other`,
/// wrapping around at the boundary of the type.
///
/// in the type. In such a case, this function returns `MIN`
/// itself.
///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
/// # Examples
///
/// Basic usage:
/// -1` on a signed type (where `MIN` is the negative
/// minimal value). In such a case, this function returns `0`.
///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
/// # Examples
///
/// Basic usage:
self.overflowing_shr(rhs).0
}
+ /// Calculates `self` + `rhs`
+ ///
+ /// Returns a tuple of the addition along with a boolean indicating
+ /// whether an arithmetic overflow would occur. If an overflow would
+ /// have occurred then the wrapped value is returned.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// use std::i32;
+ ///
+ /// assert_eq!(5i32.overflowing_add(2), (7, false));
+ /// assert_eq!(i32::MAX.overflowing_add(1), (i32::MIN, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+ unsafe {
+ let (a, b) = $add_with_overflow(self as $ActualT,
+ rhs as $ActualT);
+ (a as Self, b)
+ }
+ }
+
+ /// Calculates `self` - `rhs`
+ ///
+ /// Returns a tuple of the subtraction along with a boolean indicating
+ /// whether an arithmetic overflow would occur. If an overflow would
+ /// have occurred then the wrapped value is returned.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// use std::i32;
+ ///
+ /// assert_eq!(5i32.overflowing_sub(2), (3, false));
+ /// assert_eq!(i32::MIN.overflowing_sub(1), (i32::MAX, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+ unsafe {
+ let (a, b) = $sub_with_overflow(self as $ActualT,
+ rhs as $ActualT);
+ (a as Self, b)
+ }
+ }
+
+ /// Calculates the multiplication of `self` and `rhs`.
+ ///
+ /// Returns a tuple of the multiplication along with a boolean
+ /// indicating whether an arithmetic overflow would occur. If an
+ /// overflow would have occurred then the wrapped value is returned.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(5i32.overflowing_mul(2), (10, false));
+ /// assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
+ unsafe {
+ let (a, b) = $mul_with_overflow(self as $ActualT,
+ rhs as $ActualT);
+ (a as Self, b)
+ }
+ }
+
+ /// Calculates the divisor when `self` is divided by `rhs`.
+ ///
+ /// Returns a tuple of the divisor along with a boolean indicating
+ /// whether an arithmetic overflow would occur. If an overflow would
+ /// occur then self is returned.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// use std::i32;
+ ///
+ /// assert_eq!(5i32.overflowing_div(2), (2, false));
+ /// assert_eq!(i32::MIN.overflowing_div(-1), (i32::MIN, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_div(self, rhs: Self) -> (Self, bool) {
+ if self == Self::min_value() && rhs == -1 {
+ (self, true)
+ } else {
+ (self / rhs, false)
+ }
+ }
+
+ /// Calculates the remainder when `self` is divided by `rhs`.
+ ///
+ /// Returns a tuple of the remainder after dividing along with a boolean
+ /// indicating whether an arithmetic overflow would occur. If an
+ /// overflow would occur then 0 is returned.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// use std::i32;
+ ///
+ /// assert_eq!(5i32.overflowing_rem(2), (1, false));
+ /// assert_eq!(i32::MIN.overflowing_rem(-1), (0, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
+ if self == Self::min_value() && rhs == -1 {
+ (0, true)
+ } else {
+ (self % rhs, false)
+ }
+ }
+
+ /// Negates self, overflowing if this is equal to the minimum value.
+ ///
+ /// Returns a tuple of the negated version of self along with a boolean
+ /// indicating whether an overflow happened. If `self` is the minimum
+ /// value (e.g. `i32::MIN` for values of type `i32`), then the minimum
+ /// value will be returned again and `true` will be returned for an
+ /// overflow happening.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// use std::i32;
+ ///
+ /// assert_eq!(2i32.overflowing_neg(), (-2, false));
+ /// assert_eq!(i32::MIN.overflowing_neg(), (i32::MIN, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_neg(self) -> (Self, bool) {
+ if self == Self::min_value() {
+ (Self::min_value(), true)
+ } else {
+ (-self, false)
+ }
+ }
+
+ /// Shifts self left by `rhs` bits.
+ ///
+ /// Returns a tuple of the shifted version of self along with a boolean
+ /// indicating whether the shift value was larger than or equal to the
+ /// number of bits. If the shift value is too large, then value is
+ /// masked (N-1) where N is the number of bits, and this value is then
+ /// used to perform the shift.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(0x10i32.overflowing_shl(4), (0x100, false));
+ /// assert_eq!(0x10i32.overflowing_shl(36), (0x100, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+ (self << (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
+ }
+
+ /// Shifts self right by `rhs` bits.
+ ///
+ /// Returns a tuple of the shifted version of self along with a boolean
+ /// indicating whether the shift value was larger than or equal to the
+ /// number of bits. If the shift value is too large, then value is
+ /// masked (N-1) where N is the number of bits, and this value is then
+ /// used to perform the shift.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(0x10i32.overflowing_shr(4), (0x1, false));
+ /// assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+ (self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
+ }
+
/// Raises self to the power of `exp`, using exponentiation by squaring.
///
/// # Examples
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn checked_add(self, other: Self) -> Option<Self> {
- checked_op!($ActualT, $add_with_overflow, self, other)
+ let (a, b) = self.overflowing_add(other);
+ if b {None} else {Some(a)}
}
/// Checked integer subtraction. Computes `self - other`, returning
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn checked_sub(self, other: Self) -> Option<Self> {
- checked_op!($ActualT, $sub_with_overflow, self, other)
+ let (a, b) = self.overflowing_sub(other);
+ if b {None} else {Some(a)}
}
/// Checked integer multiplication. Computes `self * other`, returning
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn checked_mul(self, other: Self) -> Option<Self> {
- checked_op!($ActualT, $mul_with_overflow, self, other)
+ let (a, b) = self.overflowing_mul(other);
+ if b {None} else {Some(a)}
}
/// Checked integer division. Computes `self / other`, returning `None`
}
}
+ /// Checked integer remainder. Computes `self % other`, returning `None`
+ /// if `other == 0` or the operation results in underflow or overflow.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(5u32.checked_rem(2), Some(1));
+ /// assert_eq!(5u32.checked_rem(0), None);
+ /// ```
+ #[unstable(feature = "wrapping", issue = "27755")]
+ #[inline]
+ pub fn checked_rem(self, other: Self) -> Option<Self> {
+ if other == 0 {
+ None
+ } else {
+ Some(self % other)
+ }
+ }
+
+ /// Checked shift left. Computes `self << rhs`, returning `None`
+ /// if `rhs` is larger than or equal to the number of bits in `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(0x10u32.checked_shl(4), Some(0x100));
+ /// assert_eq!(0x10u32.checked_shl(33), None);
+ /// ```
+ #[unstable(feature = "wrapping", issue = "27755")]
+ #[inline]
+ pub fn checked_shl(self, rhs: u32) -> Option<Self> {
+ let (a, b) = self.overflowing_shl(rhs);
+ if b {None} else {Some(a)}
+ }
+
+ /// Checked shift right. Computes `self >> rhs`, returning `None`
+ /// if `rhs` is larger than or equal to the number of bits in `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(0x10u32.checked_shr(4), Some(0x1));
+ /// assert_eq!(0x10u32.checked_shr(33), None);
+ /// ```
+ #[unstable(feature = "wrapping", issue = "27755")]
+ #[inline]
+ pub fn checked_shr(self, rhs: u32) -> Option<Self> {
+ let (a, b) = self.overflowing_shr(rhs);
+ if b {None} else {Some(a)}
+ }
+
/// Saturating integer addition. Computes `self + other`, saturating at
/// the numeric bounds instead of overflowing.
///
}
}
+ /// Saturating integer multiplication. Computes `self * other`,
+ /// saturating at the numeric bounds instead of overflowing.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// use std::u32;
+ ///
+ /// assert_eq!(100u32.saturating_mul(127), 12700);
+ /// assert_eq!((1u32 << 23).saturating_mul(1 << 23), u32::MAX);
+ /// ```
+ #[unstable(feature = "wrapping", issue = "27755")]
+ #[inline]
+ pub fn saturating_mul(self, other: Self) -> Self {
+ self.checked_mul(other).unwrap_or(Self::max_value())
+ }
+
/// Wrapping (modular) addition. Computes `self + other`,
/// wrapping around at the boundary of the type.
///
self.overflowing_shr(rhs).0
}
+ /// Calculates `self` + `rhs`
+ ///
+ /// Returns a tuple of the addition along with a boolean indicating
+ /// whether an arithmetic overflow would occur. If an overflow would
+ /// have occurred then the wrapped value is returned.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// use std::u32;
+ ///
+ /// assert_eq!(5u32.overflowing_add(2), (7, false));
+ /// assert_eq!(u32::MAX.overflowing_add(1), (0, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+ unsafe {
+ let (a, b) = $add_with_overflow(self as $ActualT,
+ rhs as $ActualT);
+ (a as Self, b)
+ }
+ }
+
+ /// Calculates `self` - `rhs`
+ ///
+ /// Returns a tuple of the subtraction along with a boolean indicating
+ /// whether an arithmetic overflow would occur. If an overflow would
+ /// have occurred then the wrapped value is returned.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// use std::u32;
+ ///
+ /// assert_eq!(5u32.overflowing_sub(2), (3, false));
+ /// assert_eq!(0u32.overflowing_sub(1), (u32::MAX, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+ unsafe {
+ let (a, b) = $sub_with_overflow(self as $ActualT,
+ rhs as $ActualT);
+ (a as Self, b)
+ }
+ }
+
+ /// Calculates the multiplication of `self` and `rhs`.
+ ///
+ /// Returns a tuple of the multiplication along with a boolean
+ /// indicating whether an arithmetic overflow would occur. If an
+ /// overflow would have occurred then the wrapped value is returned.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(5u32.overflowing_mul(2), (10, false));
+ /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
+ unsafe {
+ let (a, b) = $mul_with_overflow(self as $ActualT,
+ rhs as $ActualT);
+ (a as Self, b)
+ }
+ }
+
+ /// Calculates the divisor when `self` is divided by `rhs`.
+ ///
+ /// Returns a tuple of the divisor along with a boolean indicating
+ /// whether an arithmetic overflow would occur. Note that for unsigned
+ /// integers overflow never occurs, so the second value is always
+ /// `false`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(5u32.overflowing_div(2), (2, false));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_div(self, rhs: Self) -> (Self, bool) {
+ (self / rhs, false)
+ }
+
+ /// Calculates the remainder when `self` is divided by `rhs`.
+ ///
+ /// Returns a tuple of the remainder after dividing along with a boolean
+ /// indicating whether an arithmetic overflow would occur. Note that for
+ /// unsigned integers overflow never occurs, so the second value is
+ /// always `false`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(5u32.overflowing_rem(2), (1, false));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
+ (self % rhs, false)
+ }
+
+ /// Negates self in an overflowing fashion.
+ ///
+ /// Returns `!self + 1` using wrapping operations to return the value
+ /// that represents the negation of this unsigned value. Note that for
+ /// positive unsigned values overflow always occurs, but negating 0 does
+ /// not overflow.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(0u32.overflowing_neg(), (0, false));
+ /// assert_eq!(2u32.overflowing_neg(), (-2i32 as u32, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_neg(self) -> (Self, bool) {
+ ((!self).wrapping_add(1), self != 0)
+ }
+
+ /// Shifts self left by `rhs` bits.
+ ///
+ /// Returns a tuple of the shifted version of self along with a boolean
+ /// indicating whether the shift value was larger than or equal to the
+ /// number of bits. If the shift value is too large, then value is
+ /// masked (N-1) where N is the number of bits, and this value is then
+ /// used to perform the shift.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(0x10u32.overflowing_shl(4), (0x100, false));
+ /// assert_eq!(0x10u32.overflowing_shl(36), (0x100, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+ (self << (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
+ }
+
+ /// Shifts self right by `rhs` bits.
+ ///
+ /// Returns a tuple of the shifted version of self along with a boolean
+ /// indicating whether the shift value was larger than or equal to the
+ /// number of bits. If the shift value is too large, then value is
+ /// masked (N-1) where N is the number of bits, and this value is then
+ /// used to perform the shift.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// #![feature(wrapping)]
+ ///
+ /// assert_eq!(0x10u32.overflowing_shr(4), (0x1, false));
+ /// assert_eq!(0x10u32.overflowing_shr(36), (0x1, true));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping", issue = "27755")]
+ pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+ (self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
+ }
+
/// Raises self to the power of `exp`, using exponentiation by squaring.
///
/// # Examples
pub prints: Vec<PrintRequest>,
pub cg: CodegenOptions,
pub color: ColorConfig,
- pub show_span: Option<String>,
pub externs: HashMap<String, Vec<String>>,
pub crate_name: Option<String>,
/// An optional name to use as the crate for std during std injection,
prints: Vec::new(),
cg: basic_codegen_options(),
color: ColorConfig::Auto,
- show_span: None,
externs: HashMap::new(),
crate_name: None,
alt_std_name: None,
"don't clear the resolution tables after analysis"),
keep_ast: bool = (false, parse_bool,
"keep the AST after lowering it to HIR"),
+ show_span: Option<String> = (None, parse_opt_string,
+ "show spans for compiler debugging (expr|pat|ty)"),
}
pub fn default_lib_output() -> CrateType {
`hir` (the HIR), `hir,identified`, or
`hir,typed` (HIR with types for each node).",
"TYPE"),
- opt::opt_u("", "show-span", "Show spans for compiler debugging", "expr|pat|ty"),
]);
opts
}
prints: prints,
cg: cg,
color: color,
- show_span: None,
externs: externs,
crate_name: crate_name,
alt_std_name: None,
println!("Pre-expansion node count: {}", count_nodes(&krate));
}
- if let Some(ref s) = sess.opts.show_span {
+ if let Some(ref s) = sess.opts.debugging_opts.show_span {
syntax::show_span::run(sess.diagnostic(), s, &krate);
}
};
let cstore = Rc::new(CStore::new(token::get_ident_interner()));
- let mut sess = build_session(sopts, input_file_path, descriptions,
+ let sess = build_session(sopts, input_file_path, descriptions,
cstore.clone());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
- if sess.unstable_options() {
- sess.opts.show_span = matches.opt_str("show-span");
- }
let mut cfg = config::build_configuration(&sess);
target_features::add_configuration(&mut cfg, &sess);
fn build_controller(&mut self, sess: &Session) -> CompileController<'a> {
let mut control = CompileController::basic();
- if sess.opts.parse_only || sess.opts.show_span.is_some() ||
+ if sess.opts.parse_only || sess.opts.debugging_opts.show_span.is_some() ||
sess.opts.debugging_opts.ast_json_noexpand {
control.after_parse.stop = Compilation::Stop;
}
use Namespace::{TypeNS, ValueNS};
use NameBindings;
use {names_to_string, module_to_string};
-use ParentLink::{self, ModuleParentLink, BlockParentLink};
+use ParentLink::{ModuleParentLink, BlockParentLink};
use Resolver;
use resolve_imports::Shadowable;
use {resolve_error, resolve_struct_error, ResolutionError};
use std::mem::replace;
use std::ops::{Deref, DerefMut};
-use std::rc::Rc;
// Specifies how duplicates should be handled when adding a child item if
// another item exists with the same name in some namespace.
/// Constructs the reduced graph for the entire crate.
fn build_reduced_graph(self, krate: &hir::Crate) {
let mut visitor = BuildReducedGraphVisitor {
- parent: self.graph_root.clone(),
+ parent: self.graph_root,
builder: self,
};
intravisit::walk_crate(&mut visitor, krate);
/// Returns the child's corresponding name bindings.
fn add_child(&self,
name: Name,
- parent: &Rc<Module>,
+ parent: Module<'b>,
duplicate_checking_mode: DuplicateCheckingMode,
// For printing errors
sp: Span)
- -> NameBindings {
- self.check_for_conflicts_between_external_crates_and_items(&**parent, name, sp);
+ -> NameBindings<'b> {
+ self.check_for_conflicts_between_external_crates_and_items(parent, name, sp);
// Add or reuse the child.
let child = parent.children.borrow().get(&name).cloned();
return false;
}
- fn get_parent_link(&mut self, parent: &Rc<Module>, name: Name) -> ParentLink {
- ModuleParentLink(Rc::downgrade(parent), name)
- }
-
/// Constructs the reduced graph for one item.
- fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) -> Rc<Module> {
+ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: Module<'b>) -> Module<'b> {
let name = item.name;
let sp = item.span;
let is_public = item.vis == hir::Public;
}
let subclass = SingleImport(binding, source_name);
- self.build_import_directive(&**parent,
+ self.build_import_directive(parent,
module_path,
subclass,
view_path.span,
(module_path.to_vec(), name, rename)
}
};
- self.build_import_directive(&**parent,
+ self.build_import_directive(parent,
module_path,
SingleImport(rename, name),
source_item.span,
}
}
ViewPathGlob(_) => {
- self.build_import_directive(&**parent,
+ self.build_import_directive(parent,
module_path,
GlobImport,
view_path.span,
shadowable);
}
}
- parent.clone()
+ parent
}
ItemExternCrate(_) => {
index: CRATE_DEF_INDEX,
};
self.external_exports.insert(def_id);
- let parent_link = ModuleParentLink(Rc::downgrade(parent), name);
+ let parent_link = ModuleParentLink(parent, name);
let def = DefMod(def_id);
- let external_module = Module::new(parent_link, Some(def), false, true);
+ let external_module = self.new_module(parent_link, Some(def), false, true);
debug!("(build reduced graph for item) found extern `{}`",
module_to_string(&*external_module));
- self.check_for_conflicts_for_external_crate(&parent, name, sp);
+ self.check_for_conflicts_for_external_crate(parent, name, sp);
parent.external_module_children
.borrow_mut()
- .insert(name, external_module.clone());
+ .insert(name, external_module);
self.build_reduced_graph_for_external_crate(&external_module);
}
- parent.clone()
+ parent
}
ItemMod(..) => {
let name_bindings = self.add_child(name, parent, ForbidDuplicateTypes, sp);
- let parent_link = self.get_parent_link(parent, name);
+ let parent_link = ModuleParentLink(parent, name);
let def = DefMod(self.ast_map.local_def_id(item.id));
- let module = Module::new(parent_link, Some(def), false, is_public);
+ let module = self.new_module(parent_link, Some(def), false, is_public);
name_bindings.define_module(module.clone(), sp);
module
}
- ItemForeignMod(..) => parent.clone(),
+ ItemForeignMod(..) => parent,
// These items live in the value namespace.
ItemStatic(_, m, _) => {
name_bindings.define_value(DefStatic(self.ast_map.local_def_id(item.id), mutbl),
sp,
modifiers);
- parent.clone()
+ parent
}
ItemConst(_, _) => {
self.add_child(name, parent, ForbidDuplicateValues, sp)
.define_value(DefConst(self.ast_map.local_def_id(item.id)), sp, modifiers);
- parent.clone()
+ parent
}
ItemFn(_, _, _, _, _, _) => {
let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp);
let def = DefFn(self.ast_map.local_def_id(item.id), false);
name_bindings.define_value(def, sp, modifiers);
- parent.clone()
+ parent
}
// These items live in the type namespace.
ForbidDuplicateTypes,
sp);
- let parent_link = self.get_parent_link(parent, name);
+ let parent_link = ModuleParentLink(parent, name);
let def = DefTy(self.ast_map.local_def_id(item.id), false);
- let module = Module::new(parent_link, Some(def), false, is_public);
+ let module = self.new_module(parent_link, Some(def), false, is_public);
name_bindings.define_module(module, sp);
- parent.clone()
+ parent
}
ItemEnum(ref enum_definition, _) => {
ForbidDuplicateTypes,
sp);
- let parent_link = self.get_parent_link(parent, name);
+ let parent_link = ModuleParentLink(parent, name);
let def = DefTy(self.ast_map.local_def_id(item.id), true);
- let module = Module::new(parent_link, Some(def), false, is_public);
+ let module = self.new_module(parent_link, Some(def), false, is_public);
name_bindings.define_module(module.clone(), sp);
let variant_modifiers = if is_public {
self.build_reduced_graph_for_variant(variant, item_def_id,
&module, variant_modifiers);
}
- parent.clone()
+ parent
}
// These items live in both the type and value namespaces.
let item_def_id = self.ast_map.local_def_id(item.id);
self.structs.insert(item_def_id, named_fields);
- parent.clone()
+ parent
}
ItemDefaultImpl(_, _) |
- ItemImpl(..) => parent.clone(),
+ ItemImpl(..) => parent,
ItemTrait(_, _, _, ref items) => {
let name_bindings = self.add_child(name,
let def_id = self.ast_map.local_def_id(item.id);
// Add all the items within to a new module.
- let parent_link = self.get_parent_link(parent, name);
+ let parent_link = ModuleParentLink(parent, name);
let def = DefTrait(def_id);
- let module_parent = Module::new(parent_link, Some(def), false, is_public);
+ let module_parent = self.new_module(parent_link, Some(def), false, is_public);
name_bindings.define_module(module_parent.clone(), sp);
// Add the names of all the items to the trait info.
self.trait_item_map.insert((trait_item.name, def_id), trait_item_def_id);
}
- parent.clone()
+ parent
}
}
}
fn build_reduced_graph_for_variant(&mut self,
variant: &Variant,
item_id: DefId,
- parent: &Rc<Module>,
+ parent: Module<'b>,
variant_modifiers: DefModifiers) {
let name = variant.node.name;
let is_exported = if variant.node.data.is_struct() {
/// Constructs the reduced graph for one foreign item.
fn build_reduced_graph_for_foreign_item(&mut self,
foreign_item: &ForeignItem,
- parent: &Rc<Module>) {
+ parent: Module<'b>) {
let name = foreign_item.name;
let is_public = foreign_item.vis == hir::Public;
let modifiers = if is_public {
name_bindings.define_value(def, foreign_item.span, modifiers);
}
- fn build_reduced_graph_for_block(&mut self, block: &Block, parent: &Rc<Module>) -> Rc<Module> {
+ fn build_reduced_graph_for_block(&mut self, block: &Block, parent: Module<'b>) -> Module<'b> {
if self.block_needs_anonymous_module(block) {
let block_id = block.id;
{}",
block_id);
- let parent_link = BlockParentLink(Rc::downgrade(parent), block_id);
- let new_module = Module::new(parent_link, None, false, false);
- parent.anonymous_children.borrow_mut().insert(block_id, new_module.clone());
+ let parent_link = BlockParentLink(parent, block_id);
+ let new_module = self.new_module(parent_link, None, false, false);
+ parent.anonymous_children.borrow_mut().insert(block_id, new_module);
new_module
} else {
- parent.clone()
+ parent
}
}
fn handle_external_def(&mut self,
def: Def,
vis: Visibility,
- child_name_bindings: &NameBindings,
+ child_name_bindings: &NameBindings<'b>,
final_ident: &str,
name: Name,
- new_parent: &Rc<Module>) {
+ new_parent: Module<'b>) {
debug!("(building reduced graph for external crate) building external def {}, priv {:?}",
final_ident,
vis);
debug!("(building reduced graph for external crate) building module {} {}",
final_ident,
is_public);
- let parent_link = self.get_parent_link(new_parent, name);
- let module = Module::new(parent_link, Some(def), true, is_public);
+ let parent_link = ModuleParentLink(new_parent, name);
+ let module = self.new_module(parent_link, Some(def), true, is_public);
child_name_bindings.define_module(module, DUMMY_SP);
}
}
}
// Define a module if necessary.
- let parent_link = self.get_parent_link(new_parent, name);
- let module = Module::new(parent_link, Some(def), true, is_public);
+ let parent_link = ModuleParentLink(new_parent, name);
+ let module = self.new_module(parent_link, Some(def), true, is_public);
child_name_bindings.define_module(module, DUMMY_SP);
}
DefTy(..) | DefAssociatedTy(..) => {
/// Builds the reduced graph for a single item in an external crate.
fn build_reduced_graph_for_external_crate_def(&mut self,
- root: &Rc<Module>,
+ root: Module<'b>,
xcdef: ChildItem) {
match xcdef.def {
DlDef(def) => {
}
/// Builds the reduced graph rooted at the given external module.
- fn populate_external_module(&mut self, module: &Rc<Module>) {
+ fn populate_external_module(&mut self, module: Module<'b>) {
debug!("(populating external module) attempting to populate {}",
- module_to_string(&**module));
+ module_to_string(module));
let def_id = match module.def_id() {
None => {
/// Ensures that the reduced graph rooted at the given external module
/// is built, building it if it is not.
- fn populate_module_if_necessary(&mut self, module: &Rc<Module>) {
+ fn populate_module_if_necessary(&mut self, module: Module<'b>) {
if !module.populated.get() {
self.populate_external_module(module)
}
/// Builds the reduced graph rooted at the 'use' directive for an external
/// crate.
- fn build_reduced_graph_for_external_crate(&mut self, root: &Rc<Module>) {
+ fn build_reduced_graph_for_external_crate(&mut self, root: Module<'b>) {
let root_cnum = root.def_id().unwrap().krate;
for child in self.session.cstore.crate_top_level_items(root_cnum) {
self.build_reduced_graph_for_external_crate_def(root, child);
/// Creates and adds an import directive to the given module.
fn build_import_directive(&mut self,
- module_: &Module,
+ module_: Module<'b>,
module_path: Vec<Name>,
subclass: ImportDirectiveSubclass,
span: Span,
struct BuildReducedGraphVisitor<'a, 'b: 'a, 'tcx: 'b> {
builder: GraphBuilder<'a, 'b, 'tcx>,
- parent: Rc<Module>,
+ parent: Module<'b>,
}
impl<'a, 'b, 'v, 'tcx> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
GraphBuilder { resolver: resolver }.build_reduced_graph(krate);
}
-pub fn populate_module_if_necessary(resolver: &mut Resolver, module: &Rc<Module>) {
+pub fn populate_module_if_necessary<'a, 'tcx>(resolver: &mut Resolver<'a, 'tcx>,
+ module: Module<'a>) {
GraphBuilder { resolver: resolver }.populate_module_if_necessary(module);
}
extern crate log;
#[macro_use]
extern crate syntax;
+extern crate arena;
#[macro_use]
#[no_link]
extern crate rustc_bitflags;
use std::cell::{Cell, RefCell};
use std::fmt;
use std::mem::replace;
-use std::rc::{Rc, Weak};
+use std::rc::Rc;
use resolve_imports::{Target, ImportDirective, ImportResolutionPerNamespace};
use resolve_imports::Shadowable;
/// a particular namespace. The result is either definitely-resolved,
/// definitely- unresolved, or unknown.
#[derive(Clone)]
-enum NamespaceResult {
+enum NamespaceResult<'a> {
/// Means that resolve hasn't gathered enough information yet to determine
/// whether the name is bound in this namespace. (That is, it hasn't
/// resolved all `use` directives yet.)
UnboundResult,
/// Means that resolve has determined that the name is bound in the Module
/// argument, and specified by the NameBinding argument.
- BoundResult(Rc<Module>, NameBinding),
+ BoundResult(Module<'a>, NameBinding<'a>),
}
-impl NamespaceResult {
+impl<'a> NamespaceResult<'a> {
fn is_unknown(&self) -> bool {
match *self {
UnknownResult => true,
UseLexicalScope,
}
-enum ModulePrefixResult {
+enum ModulePrefixResult<'a> {
NoPrefixFound,
- PrefixFound(Rc<Module>, usize),
+ PrefixFound(Module<'a>, usize),
}
#[derive(Copy, Clone)]
/// The link from a module up to its nearest parent node.
#[derive(Clone,Debug)]
-enum ParentLink {
+enum ParentLink<'a> {
NoParentLink,
- ModuleParentLink(Weak<Module>, Name),
- BlockParentLink(Weak<Module>, NodeId),
+ ModuleParentLink(Module<'a>, Name),
+ BlockParentLink(Module<'a>, NodeId),
}
/// One node in the tree of modules.
-pub struct Module {
- parent_link: ParentLink,
+pub struct ModuleS<'a> {
+ parent_link: ParentLink<'a>,
def: Cell<Option<Def>>,
is_public: bool,
- children: RefCell<HashMap<Name, NameBindings>>,
+ children: RefCell<HashMap<Name, NameBindings<'a>>>,
imports: RefCell<Vec<ImportDirective>>,
// The external module children of this node that were declared with
// `extern crate`.
- external_module_children: RefCell<HashMap<Name, Rc<Module>>>,
+ external_module_children: RefCell<HashMap<Name, Module<'a>>>,
// The anonymous children of this node. Anonymous children are pseudo-
// modules that are implicitly created around items contained within
//
// There will be an anonymous module created around `g` with the ID of the
// entry block for `f`.
- anonymous_children: RefCell<NodeMap<Rc<Module>>>,
+ anonymous_children: RefCell<NodeMap<Module<'a>>>,
// The status of resolving each import in this module.
- import_resolutions: RefCell<HashMap<Name, ImportResolutionPerNamespace>>,
+ import_resolutions: RefCell<HashMap<Name, ImportResolutionPerNamespace<'a>>>,
// The number of unresolved globs that this module exports.
glob_count: Cell<usize>,
populated: Cell<bool>,
}
-impl Module {
- fn new(parent_link: ParentLink,
- def: Option<Def>,
- external: bool,
- is_public: bool)
- -> Rc<Module> {
- Rc::new(Module {
+pub type Module<'a> = &'a ModuleS<'a>;
+
+impl<'a> ModuleS<'a> {
+ fn new(parent_link: ParentLink<'a>, def: Option<Def>, external: bool, is_public: bool) -> Self {
+ ModuleS {
parent_link: parent_link,
def: Cell::new(def),
is_public: is_public,
pub_glob_count: Cell::new(0),
resolved_import_count: Cell::new(0),
populated: Cell::new(!external),
- })
+ }
}
fn def_id(&self) -> Option<DefId> {
self.imports.borrow().len() == self.resolved_import_count.get()
}
}
-}
-impl Module {
pub fn inc_glob_count(&self) {
self.glob_count.set(self.glob_count.get() + 1);
}
}
}
-impl fmt::Debug for Module {
+impl<'a> fmt::Debug for ModuleS<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"{:?}, {}",
// Records a possibly-private value, type, or module definition.
#[derive(Debug)]
-struct NsDef {
+struct NsDef<'a> {
modifiers: DefModifiers, // see note in ImportResolutionPerNamespace about how to use this
- def_or_module: DefOrModule,
+ def_or_module: DefOrModule<'a>,
span: Option<Span>,
}
#[derive(Debug)]
-enum DefOrModule {
+enum DefOrModule<'a> {
Def(Def),
- Module(Rc<Module>),
+ Module(Module<'a>),
}
-impl NsDef {
- fn create_from_module(module: Rc<Module>, span: Option<Span>) -> Self {
+impl<'a> NsDef<'a> {
+ fn create_from_module(module: Module<'a>, span: Option<Span>) -> Self {
let modifiers = if module.is_public {
DefModifiers::PUBLIC
} else {
NsDef { modifiers: modifiers, def_or_module: DefOrModule::Def(def), span: span }
}
- fn module(&self) -> Option<Rc<Module>> {
+ fn module(&self) -> Option<Module<'a>> {
match self.def_or_module {
- DefOrModule::Module(ref module) => Some(module.clone()),
+ DefOrModule::Module(ref module) => Some(module),
DefOrModule::Def(_) => None,
}
}
// Records at most one definition that a name in a namespace is bound to
#[derive(Clone,Debug)]
-pub struct NameBinding(Rc<RefCell<Option<NsDef>>>);
+pub struct NameBinding<'a>(Rc<RefCell<Option<NsDef<'a>>>>);
-impl NameBinding {
+impl<'a> NameBinding<'a> {
fn new() -> Self {
NameBinding(Rc::new(RefCell::new(None)))
}
- fn create_from_module(module: Rc<Module>) -> Self {
+ fn create_from_module(module: Module<'a>) -> Self {
NameBinding(Rc::new(RefCell::new(Some(NsDef::create_from_module(module, None)))))
}
- fn set(&self, ns_def: NsDef) {
+ fn set(&self, ns_def: NsDef<'a>) {
*self.0.borrow_mut() = Some(ns_def);
}
}
}
- fn borrow(&self) -> ::std::cell::Ref<Option<NsDef>> {
+ fn borrow(&self) -> ::std::cell::Ref<Option<NsDef<'a>>> {
self.0.borrow()
}
fn def(&self) -> Option<Def> {
self.borrow().as_ref().and_then(NsDef::def)
}
- fn module(&self) -> Option<Rc<Module>> {
+ fn module(&self) -> Option<Module<'a>> {
self.borrow().as_ref().and_then(NsDef::module)
}
fn span(&self) -> Option<Span> {
// Records the definitions (at most one for each namespace) that a name is
// bound to.
#[derive(Clone,Debug)]
-pub struct NameBindings {
- type_ns: NameBinding, // < Meaning in type namespace.
- value_ns: NameBinding, // < Meaning in value namespace.
+pub struct NameBindings<'a> {
+ type_ns: NameBinding<'a>, // < Meaning in type namespace.
+ value_ns: NameBinding<'a>, // < Meaning in value namespace.
}
-impl ::std::ops::Index<Namespace> for NameBindings {
- type Output = NameBinding;
- fn index(&self, namespace: Namespace) -> &NameBinding {
+impl<'a> ::std::ops::Index<Namespace> for NameBindings<'a> {
+ type Output = NameBinding<'a>;
+ fn index(&self, namespace: Namespace) -> &NameBinding<'a> {
match namespace { TypeNS => &self.type_ns, ValueNS => &self.value_ns }
}
}
-impl NameBindings {
- fn new() -> NameBindings {
+impl<'a> NameBindings<'a> {
+ fn new() -> Self {
NameBindings {
type_ns: NameBinding::new(),
value_ns: NameBinding::new(),
}
/// Creates a new module in this set of name bindings.
- fn define_module(&self, module: Rc<Module>, sp: Span) {
+ fn define_module(&self, module: Module<'a>, sp: Span) {
self.type_ns.set(NsDef::create_from_module(module, Some(sp)));
}
ast_map: &'a hir_map::Map<'tcx>,
- graph_root: Rc<Module>,
+ graph_root: Module<'a>,
trait_item_map: FnvHashMap<(Name, DefId), DefId>,
unresolved_imports: usize,
// The module that represents the current item scope.
- current_module: Rc<Module>,
+ current_module: Module<'a>,
// The current set of local scopes, for values.
// FIXME #4948: Reuse ribs to avoid allocation.
// The intention is that the callback modifies this flag.
// Once set, the resolver falls out of the walk, preserving the ribs.
resolved: bool,
+
+ arenas: &'a ResolverArenas<'a>,
+}
+
+pub struct ResolverArenas<'a> {
+ modules: arena::TypedArena<ModuleS<'a>>,
}
#[derive(PartialEq)]
impl<'a, 'tcx> Resolver<'a, 'tcx> {
fn new(session: &'a Session,
ast_map: &'a hir_map::Map<'tcx>,
- make_glob_map: MakeGlobMap)
+ make_glob_map: MakeGlobMap,
+ arenas: &'a ResolverArenas<'a>)
-> Resolver<'a, 'tcx> {
let root_def_id = ast_map.local_def_id(CRATE_NODE_ID);
- let graph_root = Module::new(NoParentLink, Some(DefMod(root_def_id)), false, true);
+ let graph_root = ModuleS::new(NoParentLink, Some(DefMod(root_def_id)), false, true);
+ let graph_root = arenas.modules.alloc(graph_root);
Resolver {
session: session,
// The outermost module has def ID 0; this is not reflected in the
// AST.
- graph_root: graph_root.clone(),
+ graph_root: graph_root,
trait_item_map: FnvHashMap(),
structs: FnvHashMap(),
callback: None,
resolved: false,
+
+ arenas: arenas,
+ }
+ }
+
+ fn arenas() -> ResolverArenas<'a> {
+ ResolverArenas {
+ modules: arena::TypedArena::new(),
}
}
+ fn new_module(&self,
+ parent_link: ParentLink<'a>,
+ def: Option<Def>,
+ external: bool,
+ is_public: bool) -> Module<'a> {
+ self.arenas.modules.alloc(ModuleS::new(parent_link, def, external, is_public))
+ }
+
#[inline]
fn record_import_use(&mut self, import_id: NodeId, name: Name) {
if !self.make_glob_map {
}
/// Check that an external crate doesn't collide with items or other external crates.
- fn check_for_conflicts_for_external_crate(&self, module: &Module, name: Name, span: Span) {
+ fn check_for_conflicts_for_external_crate(&self, module: Module<'a>, name: Name, span: Span) {
if module.external_module_children.borrow().contains_key(&name) {
span_err!(self.session,
span,
/// Checks that the names of items don't collide with external crates.
fn check_for_conflicts_between_external_crates_and_items(&self,
- module: &Module,
+ module: Module<'a>,
name: Name,
span: Span) {
if module.external_module_children.borrow().contains_key(&name) {
/// Resolves the given module path from the given root `module_`.
fn resolve_module_path_from_root(&mut self,
- module_: Rc<Module>,
+ module_: Module<'a>,
module_path: &[Name],
index: usize,
span: Span,
name_search_type: NameSearchType,
lp: LastPrivate)
- -> ResolveResult<(Rc<Module>, LastPrivate)> {
- fn search_parent_externals(needle: Name, module: &Rc<Module>) -> Option<Rc<Module>> {
+ -> ResolveResult<(Module<'a>, LastPrivate)> {
+ fn search_parent_externals<'a>(needle: Name, module: Module<'a>)
+ -> Option<Module<'a>> {
match module.external_module_children.borrow().get(&needle) {
- Some(_) => Some(module.clone()),
+ Some(_) => Some(module),
None => match module.parent_link {
ModuleParentLink(ref parent, _) => {
- search_parent_externals(needle, &parent.upgrade().unwrap())
+ search_parent_externals(needle, parent)
}
_ => None,
},
// modules as we go.
while index < module_path_len {
let name = module_path[index];
- match self.resolve_name_in_module(search_module.clone(),
+ match self.resolve_name_in_module(search_module,
name,
TypeNS,
name_search_type,
false) {
Failed(None) => {
let segment_name = name.as_str();
- let module_name = module_to_string(&*search_module);
+ let module_name = module_to_string(search_module);
let mut span = span;
let msg = if "???" == &module_name[..] {
span.hi = span.lo + Pos::from_usize(segment_name.len());
/// On success, returns the resolved module, and the closest *private*
/// module found to the destination when resolving this path.
fn resolve_module_path(&mut self,
- module_: Rc<Module>,
+ module_: Module<'a>,
module_path: &[Name],
use_lexical_scope: UseLexicalScopeFlag,
span: Span,
name_search_type: NameSearchType)
- -> ResolveResult<(Rc<Module>, LastPrivate)> {
+ -> ResolveResult<(Module<'a>, LastPrivate)> {
let module_path_len = module_path.len();
assert!(module_path_len > 0);
module_to_string(&*module_));
// Resolve the module prefix, if any.
- let module_prefix_result = self.resolve_module_prefix(module_.clone(), module_path);
+ let module_prefix_result = self.resolve_module_prefix(module_, module_path);
let search_module;
let start_index;
DontUseLexicalScope => {
// This is a crate-relative path. We will start the
// resolution process at index zero.
- search_module = self.graph_root.clone();
+ search_module = self.graph_root;
start_index = 0;
last_private = LastMod(AllPublic);
}
}
}
Success(PrefixFound(ref containing_module, index)) => {
- search_module = containing_module.clone();
+ search_module = containing_module;
start_index = index;
last_private = LastMod(DependsOn(containing_module.def_id()
.unwrap()));
/// Invariant: This must only be called during main resolution, not during
/// import resolution.
fn resolve_item_in_lexical_scope(&mut self,
- module_: Rc<Module>,
+ module_: Module<'a>,
name: Name,
namespace: Namespace,
record_used: bool)
- -> ResolveResult<(Target, bool)> {
+ -> ResolveResult<(Target<'a>, bool)> {
debug!("(resolving item in lexical scope) resolving `{}` in namespace {:?} in `{}`",
name,
namespace,
match module_.children.borrow().get(&name) {
Some(name_bindings) if name_bindings[namespace].defined() => {
debug!("top name bindings succeeded");
- return Success((Target::new(module_.clone(),
+ return Success((Target::new(module_,
name_bindings[namespace].clone(),
Shadowable::Never),
false));
// Search for external modules.
if namespace == TypeNS {
- // FIXME (21114): In principle unclear `child` *has* to be lifted.
- let child = module_.external_module_children.borrow().get(&name).cloned();
- if let Some(module) = child {
+ let children = module_.external_module_children.borrow();
+ if let Some(module) = children.get(&name) {
let name_binding = NameBinding::create_from_module(module);
debug!("lower name bindings succeeded");
return Success((Target::new(module_, name_binding, Shadowable::Never),
let mut search_module = module_;
loop {
// Go to the next parent.
- match search_module.parent_link.clone() {
+ match search_module.parent_link {
NoParentLink => {
// No more parents. This module was unresolved.
debug!("(resolving item in lexical scope) unresolved module");
searching through module parents");
return Failed(None);
} else {
- search_module = parent_module_node.upgrade().unwrap();
+ search_module = parent_module_node;
}
}
- BlockParentLink(ref parent_module_node, _) => {
- search_module = parent_module_node.upgrade().unwrap();
+ BlockParentLink(parent_module_node, _) => {
+ search_module = parent_module_node;
}
}
// Resolve the name in the parent module.
- match self.resolve_name_in_module(search_module.clone(),
+ match self.resolve_name_in_module(search_module,
name,
namespace,
PathSearch,
/// Resolves a module name in the current lexical scope.
fn resolve_module_in_lexical_scope(&mut self,
- module_: Rc<Module>,
+ module_: Module<'a>,
name: Name)
- -> ResolveResult<Rc<Module>> {
+ -> ResolveResult<Module<'a>> {
// If this module is an anonymous module, resolve the item in the
// lexical scope. Otherwise, resolve the item from the crate root.
let resolve_result = self.resolve_item_in_lexical_scope(module_, name, TypeNS, true);
}
/// Returns the nearest normal module parent of the given module.
- fn get_nearest_normal_module_parent(&mut self, module_: Rc<Module>) -> Option<Rc<Module>> {
+ fn get_nearest_normal_module_parent(&mut self, module_: Module<'a>) -> Option<Module<'a>> {
let mut module_ = module_;
loop {
- match module_.parent_link.clone() {
+ match module_.parent_link {
NoParentLink => return None,
ModuleParentLink(new_module, _) |
BlockParentLink(new_module, _) => {
- let new_module = new_module.upgrade().unwrap();
+ let new_module = new_module;
if new_module.is_normal() {
return Some(new_module);
}
/// Returns the nearest normal module parent of the given module, or the
/// module itself if it is a normal module.
- fn get_nearest_normal_module_parent_or_self(&mut self, module_: Rc<Module>) -> Rc<Module> {
+ fn get_nearest_normal_module_parent_or_self(&mut self, module_: Module<'a>) -> Module<'a> {
if module_.is_normal() {
return module_;
}
- match self.get_nearest_normal_module_parent(module_.clone()) {
+ match self.get_nearest_normal_module_parent(module_) {
None => module_,
Some(new_module) => new_module,
}
/// (b) some chain of `super::`.
/// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) *
fn resolve_module_prefix(&mut self,
- module_: Rc<Module>,
+ module_: Module<'a>,
module_path: &[Name])
- -> ResolveResult<ModulePrefixResult> {
+ -> ResolveResult<ModulePrefixResult<'a>> {
// Start at the current module if we see `self` or `super`, or at the
// top of the crate otherwise.
let mut i = match &*module_path[0].as_str() {
/// The boolean returned on success is an indicator of whether this lookup
/// passed through a public re-export proxy.
fn resolve_name_in_module(&mut self,
- module_: Rc<Module>,
+ module_: Module<'a>,
name: Name,
namespace: Namespace,
name_search_type: NameSearchType,
allow_private_imports: bool)
- -> ResolveResult<(Target, bool)> {
+ -> ResolveResult<(Target<'a>, bool)> {
debug!("(resolving name in module) resolving `{}` in `{}`",
name,
module_to_string(&*module_));
// First, check the direct children of the module.
build_reduced_graph::populate_module_if_necessary(self, &module_);
- match module_.children.borrow().get(&name) {
+ let children = module_.children.borrow();
+ match children.get(&name) {
Some(name_bindings) if name_bindings[namespace].defined() => {
debug!("(resolving name in module) found node as child");
- return Success((Target::new(module_.clone(),
+ return Success((Target::new(module_,
name_bindings[namespace].clone(),
Shadowable::Never),
false));
}
// Check the list of resolved imports.
- match module_.import_resolutions.borrow().get(&name) {
+ let children = module_.import_resolutions.borrow();
+ match children.get(&name) {
Some(import_resolution) if allow_private_imports ||
import_resolution[namespace].is_public => {
// Finally, search through external children.
if namespace == TypeNS {
- // FIXME (21114): In principle unclear `child` *has* to be lifted.
- let child = module_.external_module_children.borrow().get(&name).cloned();
- if let Some(module) = child {
+ let children = module_.external_module_children.borrow();
+ if let Some(module) = children.get(&name) {
let name_binding = NameBinding::create_from_module(module);
return Success((Target::new(module_, name_binding, Shadowable::Never),
false));
return Failed(None);
}
- fn report_unresolved_imports(&mut self, module_: Rc<Module>) {
+ fn report_unresolved_imports(&mut self, module_: Module<'a>) {
let index = module_.resolved_import_count.get();
let imports = module_.imports.borrow();
let import_count = imports.len();
}
for (_, module_) in module_.anonymous_children.borrow().iter() {
- self.report_unresolved_imports(module_.clone());
+ self.report_unresolved_imports(module_);
}
}
fn with_scope<F>(&mut self, name: Option<Name>, f: F)
where F: FnOnce(&mut Resolver)
{
- let orig_module = self.current_module.clone();
+ let orig_module = self.current_module;
// Move down in the graph.
match name {
self.value_ribs.push(Rib::new(NormalRibKind));
// Move down in the graph, if there's an anonymous module rooted here.
- let orig_module = self.current_module.clone();
+ let orig_module = self.current_module;
match orig_module.anonymous_children.borrow().get(&block.id) {
None => {
// Nothing to do.
}
Some(anonymous_module) => {
debug!("(resolving block) found anonymous module, moving down");
- self.current_module = anonymous_module.clone();
+ self.current_module = anonymous_module;
}
}
name: Name,
span: Span)
-> BareIdentifierPatternResolution {
- let module = self.current_module.clone();
+ let module = self.current_module;
match self.resolve_item_in_lexical_scope(module, name, ValueNS, true) {
Success((target, _)) => {
debug!("(resolve bare identifier pattern) succeeded in finding {} at {:?}",
let containing_module;
let last_private;
- let current_module = self.current_module.clone();
+ let current_module = self.current_module;
match self.resolve_module_path(current_module,
&module_path[..],
UseLexicalScope,
}
let name = segments.last().unwrap().identifier.name;
- let def = match self.resolve_name_in_module(containing_module.clone(),
+ let def = match self.resolve_name_in_module(containing_module,
name,
namespace,
NameSearchType::PathSearch,
.map(|ps| ps.identifier.name)
.collect::<Vec<_>>();
- let root_module = self.graph_root.clone();
+ let root_module = self.graph_root;
let containing_module;
let last_private;
record_used: bool)
-> Option<Def> {
// Check the items.
- let module = self.current_module.clone();
+ let module = self.current_module;
match self.resolve_item_in_lexical_scope(module, name, namespace, record_used) {
Success((target, _)) => {
match target.binding.def() {
}
}
- fn get_module(this: &mut Resolver,
- span: Span,
- name_path: &[ast::Name])
- -> Option<Rc<Module>> {
- let root = this.current_module.clone();
+ fn get_module<'a, 'tcx>(this: &mut Resolver<'a, 'tcx>,
+ span: Span,
+ name_path: &[ast::Name])
+ -> Option<Module<'a>> {
+ let root = this.current_module;
let last_name = name_path.last().unwrap();
if name_path.len() == 1 {
let name_path = path.segments.iter()
.map(|seg| seg.identifier.name)
.collect::<Vec<_>>();
- let current_module = self.current_module.clone();
+ let current_module = self.current_module;
match self.resolve_module_path(current_module,
&name_path[..],
}
let mut found_traits = Vec::new();
- let mut search_module = self.current_module.clone();
+ let mut search_module = self.current_module;
loop {
// Look for the current trait.
match self.current_trait_ref {
}
}
- match search_module.parent_link.clone() {
+ match search_module.parent_link {
NoParentLink | ModuleParentLink(..) => break,
BlockParentLink(parent_module, _) => {
- search_module = parent_module.upgrade().unwrap();
+ search_module = parent_module;
}
}
}
//
#[allow(dead_code)] // useful for debugging
- fn dump_module(&mut self, module_: Rc<Module>) {
+ fn dump_module(&mut self, module_: Module<'a>) {
debug!("Dump of module `{}`:", module_to_string(&*module_));
debug!("Children:");
}
/// A somewhat inefficient routine to obtain the name of a module.
-fn module_to_string(module: &Module) -> String {
+fn module_to_string<'a>(module: Module<'a>) -> String {
let mut names = Vec::new();
- fn collect_mod(names: &mut Vec<ast::Name>, module: &Module) {
+ fn collect_mod<'a>(names: &mut Vec<ast::Name>, module: Module<'a>) {
match module.parent_link {
NoParentLink => {}
ModuleParentLink(ref module, name) => {
names.push(name);
- collect_mod(names, &*module.upgrade().unwrap());
+ collect_mod(names, module);
}
BlockParentLink(ref module, _) => {
// danger, shouldn't be ident?
names.push(special_idents::opaque.name);
- collect_mod(names, &*module.upgrade().unwrap());
+ collect_mod(names, module);
}
}
}
make_glob_map: MakeGlobMap)
-> CrateMap {
let krate = ast_map.krate();
- let mut resolver = create_resolver(session, ast_map, krate, make_glob_map, None);
+ let arenas = Resolver::arenas();
+ let mut resolver = create_resolver(session, ast_map, krate, make_glob_map, &arenas, None);
resolver.resolve_crate(krate);
ast_map: &'a hir_map::Map<'tcx>,
krate: &'a Crate,
make_glob_map: MakeGlobMap,
+ arenas: &'a ResolverArenas<'a>,
callback: Option<Box<Fn(hir_map::Node, &mut bool) -> bool>>)
-> Resolver<'a, 'tcx> {
- let mut resolver = Resolver::new(session, ast_map, make_glob_map);
+ let mut resolver = Resolver::new(session, ast_map, make_glob_map, arenas);
resolver.callback = callback;
use syntax::ast;
use std::ops::{Deref, DerefMut};
-use std::rc::Rc;
struct ExportRecorder<'a, 'b: 'a, 'tcx: 'b> {
resolver: &'a mut Resolver<'b, 'tcx>,
}
impl<'a, 'b, 'tcx> ExportRecorder<'a, 'b, 'tcx> {
- fn record_exports_for_module_subtree(&mut self, module_: Rc<Module>) {
+ fn record_exports_for_module_subtree(&mut self, module_: Module<'b>) {
// If this isn't a local krate, then bail out. We don't need to record
// exports for nonlocal crates.
// OK. Continue.
debug!("(recording exports for module subtree) recording exports for local \
module `{}`",
- module_to_string(&*module_));
+ module_to_string(module_));
}
None => {
// Record exports for the root module.
debug!("(recording exports for module subtree) recording exports for root module \
`{}`",
- module_to_string(&*module_));
+ module_to_string(module_));
}
Some(_) => {
// Bail out.
debug!("(recording exports for module subtree) not recording exports for `{}`",
- module_to_string(&*module_));
+ module_to_string(module_));
return;
}
}
- self.record_exports_for_module(&*module_);
+ self.record_exports_for_module(module_);
build_reduced_graph::populate_module_if_necessary(self.resolver, &module_);
for (_, child_name_bindings) in module_.children.borrow().iter() {
}
for (_, child_module) in module_.anonymous_children.borrow().iter() {
- self.record_exports_for_module_subtree(child_module.clone());
+ self.record_exports_for_module_subtree(child_module);
}
}
- fn record_exports_for_module(&mut self, module_: &Module) {
+ fn record_exports_for_module(&mut self, module_: Module<'b>) {
let mut exports = Vec::new();
self.add_exports_for_module(&mut exports, module_);
}
}
- fn add_exports_for_module(&mut self, exports: &mut Vec<Export>, module_: &Module) {
+ fn add_exports_for_module(&mut self, exports: &mut Vec<Export>, module_: Module<'b>) {
for (name, import_resolution) in module_.import_resolutions.borrow().iter() {
let xs = [TypeNS, ValueNS];
for &ns in &xs {
pub fn record(resolver: &mut Resolver) {
let mut recorder = ExportRecorder { resolver: resolver };
- let root_module = recorder.graph_root.clone();
+ let root_module = recorder.graph_root;
recorder.record_exports_for_module_subtree(root_module);
}
use syntax::util::lev_distance::find_best_match_for_name;
use std::mem::replace;
-use std::rc::Rc;
/// Contains data for specific types of import directives.
#[derive(Copy, Clone,Debug)]
/// The item that an import resolves to.
#[derive(Clone,Debug)]
-pub struct Target {
- pub target_module: Rc<Module>,
- pub binding: NameBinding,
+pub struct Target<'a> {
+ pub target_module: Module<'a>,
+ pub binding: NameBinding<'a>,
pub shadowable: Shadowable,
}
-impl Target {
- pub fn new(target_module: Rc<Module>,
- binding: NameBinding,
- shadowable: Shadowable)
- -> Target {
+impl<'a> Target<'a> {
+ pub fn new(target_module: Module<'a>, binding: NameBinding<'a>, shadowable: Shadowable)
+ -> Self {
Target {
target_module: target_module,
binding: binding,
/// and for each namespace, it records the `use` directive importing the name in the namespace
/// and the `Target` to which the name in the namespace resolves (if applicable).
/// Different `use` directives may import the same name in different namespaces.
-pub struct ImportResolutionPerNamespace {
+pub struct ImportResolutionPerNamespace<'a> {
// When outstanding_references reaches zero, outside modules can count on the targets being
// correct. Before then, all bets are off; future `use` directives could override the name.
// Since shadowing is forbidden, the only way outstanding_references > 1 in a legal program
// is if the name is imported by exactly two `use` directives, one of which resolves to a
// value and the other of which resolves to a type.
pub outstanding_references: usize,
- pub type_ns: ImportResolution,
- pub value_ns: ImportResolution,
+ pub type_ns: ImportResolution<'a>,
+ pub value_ns: ImportResolution<'a>,
}
/// Records what we know about an imported name in a namespace (see `ImportResolutionPerNamespace`).
#[derive(Clone,Debug)]
-pub struct ImportResolution {
+pub struct ImportResolution<'a> {
/// Whether the name in the namespace was imported with a `use` or a `pub use`.
pub is_public: bool,
/// Resolution of the name in the namespace
- pub target: Option<Target>,
+ pub target: Option<Target<'a>>,
/// The source node of the `use` directive
pub id: NodeId,
}
-impl ::std::ops::Index<Namespace> for ImportResolutionPerNamespace {
- type Output = ImportResolution;
- fn index(&self, ns: Namespace) -> &ImportResolution {
+impl<'a> ::std::ops::Index<Namespace> for ImportResolutionPerNamespace<'a> {
+ type Output = ImportResolution<'a>;
+ fn index(&self, ns: Namespace) -> &ImportResolution<'a> {
match ns { TypeNS => &self.type_ns, ValueNS => &self.value_ns }
}
}
-impl ::std::ops::IndexMut<Namespace> for ImportResolutionPerNamespace {
- fn index_mut(&mut self, ns: Namespace) -> &mut ImportResolution {
+impl<'a> ::std::ops::IndexMut<Namespace> for ImportResolutionPerNamespace<'a> {
+ fn index_mut(&mut self, ns: Namespace) -> &mut ImportResolution<'a> {
match ns { TypeNS => &mut self.type_ns, ValueNS => &mut self.value_ns }
}
}
-impl ImportResolutionPerNamespace {
+impl<'a> ImportResolutionPerNamespace<'a> {
pub fn new(id: NodeId, is_public: bool) -> Self {
let resolution = ImportResolution { id: id, is_public: is_public, target: None };
ImportResolutionPerNamespace {
i,
self.resolver.unresolved_imports);
- let module_root = self.resolver.graph_root.clone();
- let errors = self.resolve_imports_for_module_subtree(module_root.clone());
+ let module_root = self.resolver.graph_root;
+ let errors = self.resolve_imports_for_module_subtree(module_root);
if self.resolver.unresolved_imports == 0 {
debug!("(resolving imports) success");
/// Attempts to resolve imports for the given module and all of its
/// submodules.
fn resolve_imports_for_module_subtree(&mut self,
- module_: Rc<Module>)
+ module_: Module<'b>)
-> Vec<ImportResolvingError> {
let mut errors = Vec::new();
debug!("(resolving imports for module subtree) resolving {}",
module_to_string(&*module_));
- let orig_module = replace(&mut self.resolver.current_module, module_.clone());
- errors.extend(self.resolve_imports_for_module(module_.clone()));
+ let orig_module = replace(&mut self.resolver.current_module, module_);
+ errors.extend(self.resolve_imports_for_module(module_));
self.resolver.current_module = orig_module;
build_reduced_graph::populate_module_if_necessary(self.resolver, &module_);
}
for (_, child_module) in module_.anonymous_children.borrow().iter() {
- errors.extend(self.resolve_imports_for_module_subtree(child_module.clone()));
+ errors.extend(self.resolve_imports_for_module_subtree(child_module));
}
errors
}
/// Attempts to resolve imports for the given module only.
- fn resolve_imports_for_module(&mut self, module: Rc<Module>) -> Vec<ImportResolvingError> {
+ fn resolve_imports_for_module(&mut self, module: Module<'b>) -> Vec<ImportResolvingError> {
let mut errors = Vec::new();
if module.all_imports_resolved() {
let mut indeterminate_imports = Vec::new();
while module.resolved_import_count.get() + indeterminate_imports.len() < import_count {
let import_index = module.resolved_import_count.get();
- match self.resolve_import_for_module(module.clone(), &imports[import_index]) {
+ match self.resolve_import_for_module(module, &imports[import_index]) {
ResolveResult::Failed(err) => {
let import_directive = &imports[import_index];
let (span, help) = match err {
/// currently-unresolved imports, or success if we know the name exists.
/// If successful, the resolved bindings are written into the module.
fn resolve_import_for_module(&mut self,
- module_: Rc<Module>,
+ module_: Module<'b>,
import_directive: &ImportDirective)
-> ResolveResult<()> {
let mut resolution_result = ResolveResult::Failed(None);
// First, resolve the module path for the directive, if necessary.
let container = if module_path.is_empty() {
// Use the crate root.
- Some((self.resolver.graph_root.clone(), LastMod(AllPublic)))
+ Some((self.resolver.graph_root, LastMod(AllPublic)))
} else {
- match self.resolver.resolve_module_path(module_.clone(),
+ match self.resolver.resolve_module_path(module_,
&module_path[..],
UseLexicalScopeFlag::DontUseLexicalScope,
import_directive.span,
}
fn resolve_single_import(&mut self,
- module_: &Module,
- target_module: Rc<Module>,
+ module_: Module<'b>,
+ target_module: Module<'b>,
target: Name,
source: Name,
directive: &ImportDirective,
let mut pub_err = false;
if child_name_bindings.value_ns.defined() {
debug!("(resolving single import) found value binding");
- value_result = BoundResult(target_module.clone(),
+ value_result = BoundResult(target_module,
child_name_bindings.value_ns.clone());
if directive.is_public && !child_name_bindings.value_ns.is_public() {
let msg = format!("`{}` is private, and cannot be reexported", source);
}
if child_name_bindings.type_ns.defined() {
debug!("(resolving single import) found type binding");
- type_result = BoundResult(target_module.clone(),
+ type_result = BoundResult(target_module,
child_name_bindings.type_ns.clone());
if !pub_err && directive.is_public &&
!child_name_bindings.type_ns.is_public() {
}
Some(import_resolution) if import_resolution.outstanding_references == 0 => {
- fn get_binding(this: &mut Resolver,
- import_resolution: &ImportResolutionPerNamespace,
- namespace: Namespace,
- source: Name)
- -> NamespaceResult {
+ fn get_binding<'a>(this: &mut Resolver,
+ import_resolution: &ImportResolutionPerNamespace<'a>,
+ namespace: Namespace,
+ source: Name)
+ -> NamespaceResult<'a> {
// Import resolutions must be declared with "pub"
// in order to be exported.
match type_result {
BoundResult(..) => {}
_ => {
- match target_module.external_module_children.borrow_mut().get(&source).cloned() {
+ match target_module.external_module_children.borrow_mut().get(&source) {
None => {} // Continue.
Some(module) => {
debug!("(resolving single import) found external module");
_ => {}
}
let name_binding = NameBinding::create_from_module(module);
- type_result = BoundResult(target_module.clone(), name_binding);
+ type_result = BoundResult(target_module, name_binding);
type_used_public = true;
}
}
target);
import_resolution[namespace] = ImportResolution {
- target: Some(Target::new(target_module.clone(),
+ target: Some(Target::new(target_module,
name_binding.clone(),
directive.shadowable)),
id: directive.id,
// that exports nothing is valid). target_module is the module we are
// actually importing, i.e., `foo` in `use foo::*`.
fn resolve_glob_import(&mut self,
- module_: &Module,
- target_module: Rc<Module>,
+ module_: Module<'b>,
+ target_module: Module<'b>,
import_directive: &ImportDirective,
lp: LastPrivate)
-> ResolveResult<()> {
for (&name, name_bindings) in target_module.children.borrow().iter() {
self.merge_import_resolution(module_,
- target_module.clone(),
+ target_module,
import_directive,
name,
name_bindings.clone());
}
fn merge_import_resolution(&mut self,
- module_: &Module,
- containing_module: Rc<Module>,
+ module_: Module<'b>,
+ containing_module: Module<'b>,
import_directive: &ImportDirective,
name: Name,
- name_bindings: NameBindings) {
+ name_bindings: NameBindings<'b>) {
let id = import_directive.id;
let is_public = import_directive.is_public;
msg);
} else {
dest_import_resolution[namespace] = ImportResolution {
- target: Some(Target::new(containing_module.clone(),
+ target: Some(Target::new(containing_module,
name_bindings[namespace].clone(),
import_directive.shadowable)),
id: id,
/// Checks that imported names and items don't have the same name.
fn check_for_conflicts_between_imports_and_items(&mut self,
- module: &Module,
- import: &ImportResolutionPerNamespace,
+ module: Module<'b>,
+ import: &ImportResolutionPerNamespace<'b>,
import_span: Span,
name: Name) {
// First, check for conflicts between imports and `extern crate`s.
}
// Check for item conflicts.
- let children = module.children.borrow();
- let name_bindings = match children.get(&name) {
+ let name_bindings = match module.children.borrow().get(&name) {
None => {
// There can't be any conflicts.
return;
let lvalue = Lvalue::new_with_hint(caller_name, bcx, p_id, HintKind::DontZeroJustUse);
let datum = Datum::new(llval, var_ty, lvalue);
+ debug!("mk_binding_alloca cleanup_scope={:?} llval={} var_ty={:?}",
+ cleanup_scope, bcx.ccx().tn().val_to_string(llval), var_ty);
+
// Subtle: be sure that we *populate* the memory *before*
// we schedule the cleanup.
call_lifetime_start(bcx, llval);
use syntax::attr;
use syntax::attr::IntType;
use trans::_match;
+use trans::base::InitAlloca;
use trans::build::*;
use trans::cleanup;
use trans::cleanup::CleanupMethods;
let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
let scratch = unpack_datum!(bcx, datum::lvalue_scratch_datum(
bcx, tcx.dtor_type(), "drop_flag",
- cleanup::CustomScope(custom_cleanup_scope), (), |_, bcx, _| bcx
+ InitAlloca::Uninit("drop flag itself has no dtor"),
+ cleanup::CustomScope(custom_cleanup_scope), (), |_, bcx, _| {
+ debug!("no-op populate call for trans_drop_flag_ptr on dtor_type={:?}",
+ tcx.dtor_type());
+ bcx
+ }
));
bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {
let ptr = struct_field_ptr(variant_cx, st, MaybeSizedValue::sized(value),
next_cx
}
-pub fn call_lifetime_start(cx: Block, ptr: ValueRef) {
- if cx.sess().opts.optimize == config::No {
+enum Lifetime { Start, End }
+
+// If LLVM lifetime intrinsic support is enabled (i.e. optimizations
+// on), and `ptr` is nonzero-sized, then extracts the size of `ptr`
+// and the intrinsic for `lt` and passes them to `emit`, which is in
+// charge of generating code to call the passed intrinsic on whatever
+// block of generated code is targetted for the intrinsic.
+//
+// If LLVM lifetime intrinsic support is disabled (i.e. optimizations
+// off) or `ptr` is zero-sized, then no-op (does not call `emit`).
+fn core_lifetime_emit<'blk, 'tcx, F>(ccx: &'blk CrateContext<'blk, 'tcx>,
+ ptr: ValueRef,
+ lt: Lifetime,
+ emit: F)
+ where F: FnOnce(&'blk CrateContext<'blk, 'tcx>, machine::llsize, ValueRef)
+{
+ if ccx.sess().opts.optimize == config::No {
return;
}
- let _icx = push_ctxt("lifetime_start");
- let ccx = cx.ccx();
+ let _icx = push_ctxt(match lt {
+ Lifetime::Start => "lifetime_start",
+ Lifetime::End => "lifetime_end"
+ });
let size = machine::llsize_of_alloc(ccx, val_ty(ptr).element_type());
if size == 0 {
return;
}
- let ptr = PointerCast(cx, ptr, Type::i8p(ccx));
- let lifetime_start = ccx.get_intrinsic(&"llvm.lifetime.start");
- Call(cx,
- lifetime_start,
- &[C_u64(ccx, size), ptr],
- None,
- DebugLoc::None);
+ let lifetime_intrinsic = ccx.get_intrinsic(match lt {
+ Lifetime::Start => "llvm.lifetime.start",
+ Lifetime::End => "llvm.lifetime.end"
+ });
+ emit(ccx, size, lifetime_intrinsic)
}
-pub fn call_lifetime_end(cx: Block, ptr: ValueRef) {
- if cx.sess().opts.optimize == config::No {
- return;
- }
-
- let _icx = push_ctxt("lifetime_end");
- let ccx = cx.ccx();
-
- let size = machine::llsize_of_alloc(ccx, val_ty(ptr).element_type());
- if size == 0 {
- return;
- }
+pub fn call_lifetime_start(cx: Block, ptr: ValueRef) {
+ core_lifetime_emit(cx.ccx(), ptr, Lifetime::Start, |ccx, size, lifetime_start| {
+ let ptr = PointerCast(cx, ptr, Type::i8p(ccx));
+ Call(cx,
+ lifetime_start,
+ &[C_u64(ccx, size), ptr],
+ None,
+ DebugLoc::None);
+ })
+}
- let ptr = PointerCast(cx, ptr, Type::i8p(ccx));
- let lifetime_end = ccx.get_intrinsic(&"llvm.lifetime.end");
- Call(cx,
- lifetime_end,
- &[C_u64(ccx, size), ptr],
- None,
- DebugLoc::None);
+pub fn call_lifetime_end(cx: Block, ptr: ValueRef) {
+ core_lifetime_emit(cx.ccx(), ptr, Lifetime::End, |ccx, size, lifetime_end| {
+ let ptr = PointerCast(cx, ptr, Type::i8p(ccx));
+ Call(cx,
+ lifetime_end,
+ &[C_u64(ccx, size), ptr],
+ None,
+ DebugLoc::None);
+ })
}
// Generates code for resumption of unwind at the end of a landing pad.
None);
}
-pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, name: &str) -> ValueRef {
+/// In general, when we create an scratch value in an alloca, the
+/// creator may not know if the block (that initializes the scratch
+/// with the desired value) actually dominates the cleanup associated
+/// with the scratch value.
+///
+/// To deal with this, when we do an alloca (at the *start* of whole
+/// function body), we optionally can also set the associated
+/// dropped-flag state of the alloca to "dropped."
+#[derive(Copy, Clone, Debug)]
+pub enum InitAlloca {
+ /// Indicates that the state should have its associated drop flag
+ /// set to "dropped" at the point of allocation.
+ Dropped,
+ /// Indicates the value of the associated drop flag is irrelevant.
+ /// The embedded string literal is a programmer provided argument
+ /// for why. This is a safeguard forcing compiler devs to
+ /// document; it might be a good idea to also emit this as a
+ /// comment with the alloca itself when emitting LLVM output.ll.
+ Uninit(&'static str),
+}
+
+
+pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ t: Ty<'tcx>,
+ name: &str) -> ValueRef {
+ // pnkfelix: I do not know why alloc_ty meets the assumptions for
+ // passing Uninit, but it was never needed (even back when we had
+ // the original boolean `zero` flag on `lvalue_scratch_datum`).
+ alloc_ty_init(bcx, t, InitAlloca::Uninit("all alloc_ty are uninit"), name)
+}
+
+/// This variant of `fn alloc_ty` does not necessarily assume that the
+/// alloca should be created with no initial value. Instead the caller
+/// controls that assumption via the `init` flag.
+///
+/// Note that if the alloca *is* initialized via `init`, then we will
+/// also inject an `llvm.lifetime.start` before that initialization
+/// occurs, and thus callers should not call_lifetime_start
+/// themselves. But if `init` says "uninitialized", then callers are
+/// in charge of choosing where to call_lifetime_start and
+/// subsequently populate the alloca.
+///
+/// (See related discussion on PR #30823.)
+pub fn alloc_ty_init<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ t: Ty<'tcx>,
+ init: InitAlloca,
+ name: &str) -> ValueRef {
let _icx = push_ctxt("alloc_ty");
let ccx = bcx.ccx();
let ty = type_of::type_of(ccx, t);
assert!(!t.has_param_types());
- alloca(bcx, ty, name)
+ match init {
+ InitAlloca::Dropped => alloca_dropped(bcx, t, name),
+ InitAlloca::Uninit(_) => alloca(bcx, ty, name),
+ }
+}
+
+pub fn alloca_dropped<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ty: Ty<'tcx>, name: &str) -> ValueRef {
+ let _icx = push_ctxt("alloca_dropped");
+ let llty = type_of::type_of(cx.ccx(), ty);
+ if cx.unreachable.get() {
+ unsafe { return llvm::LLVMGetUndef(llty.ptr_to().to_ref()); }
+ }
+ let p = alloca(cx, llty, name);
+ let b = cx.fcx.ccx.builder();
+ b.position_before(cx.fcx.alloca_insert_pt.get().unwrap());
+
+ // This is just like `call_lifetime_start` (but latter expects a
+ // Block, which we do not have for `alloca_insert_pt`).
+ core_lifetime_emit(cx.ccx(), p, Lifetime::Start, |ccx, size, lifetime_start| {
+ let ptr = b.pointercast(p, Type::i8p(ccx));
+ b.call(lifetime_start, &[C_u64(ccx, size), ptr], None);
+ });
+ memfill(&b, p, ty, adt::DTOR_DONE);
+ p
}
pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef {
// Create the drop-flag hints for every unfragmented path in the function.
let tcx = fcx.ccx.tcx();
let fn_did = tcx.map.local_def_id(fcx.id);
+ let tables = tcx.tables.borrow();
let mut hints = fcx.lldropflag_hints.borrow_mut();
let fragment_infos = tcx.fragment_infos.borrow();
let (var, datum) = match info {
ty::FragmentInfo::Moved { var, .. } |
ty::FragmentInfo::Assigned { var, .. } => {
- let datum = seen.get(&var).cloned().unwrap_or_else(|| {
- let datum = make_datum(var);
- seen.insert(var, datum.clone());
- datum
+ let opt_datum = seen.get(&var).cloned().unwrap_or_else(|| {
+ let ty = tables.node_types[&var];
+ if fcx.type_needs_drop(ty) {
+ let datum = make_datum(var);
+ seen.insert(var, Some(datum.clone()));
+ Some(datum)
+ } else {
+ // No drop call needed, so we don't need a dropflag hint
+ None
+ }
});
- (var, datum)
+ if let Some(datum) = opt_datum {
+ (var, datum)
+ } else {
+ continue
+ }
}
};
match info {
let fcx = bcx.fcx;
let arg_scope_id = cleanup::CustomScope(arg_scope);
+ debug!("create_datums_for_fn_args");
+
// Return an array wrapping the ValueRefs that we get from `get_param` for
// each argument into datums.
//
// This alloca should be optimized away by LLVM's mem-to-reg pass in
// the event it's not truly needed.
let mut idx = fcx.arg_offset() as c_uint;
+ let uninit_reason = InitAlloca::Uninit("fn_arg populate dominates dtor");
for (i, &arg_ty) in arg_tys.iter().enumerate() {
let arg_datum = if !has_tupled_arg || i < arg_tys.len() - 1 {
if type_of::arg_is_indirect(bcx.ccx(), arg_ty) &&
let data = get_param(fcx.llfn, idx);
let extra = get_param(fcx.llfn, idx + 1);
idx += 2;
- unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "",
+ unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "", uninit_reason,
arg_scope_id, (data, extra),
|(data, extra), bcx, dst| {
+ debug!("populate call for create_datum_for_fn_args \
+ early fat arg, on arg[{}] ty={:?}", i, arg_ty);
+
Store(bcx, data, expr::get_dataptr(bcx, dst));
Store(bcx, extra, expr::get_meta(bcx, dst));
bcx
datum::lvalue_scratch_datum(bcx,
arg_ty,
"",
+ uninit_reason,
arg_scope_id,
tmp,
- |tmp, bcx, dst| tmp.store_to(bcx, dst)))
+ |tmp, bcx, dst| {
+
+ debug!("populate call for create_datum_for_fn_args \
+ early thin arg, on arg[{}] ty={:?}", i, arg_ty);
+
+ tmp.store_to(bcx, dst)
+ }))
}
} else {
// FIXME(pcwalton): Reduce the amount of code bloat this is responsible for.
datum::lvalue_scratch_datum(bcx,
arg_ty,
"tupled_args",
+ uninit_reason,
arg_scope_id,
(),
|(),
mut bcx,
- llval| {
+ llval| {
+ debug!("populate call for create_datum_for_fn_args \
+ tupled_args, on arg[{}] ty={:?}", i, arg_ty);
for (j, &tupled_arg_ty) in
tupled_arg_tys.iter().enumerate() {
let lldest = StructGEP(bcx, llval, j);
return DatumBlock::new(bcx, immediate_rvalue(val, ty))
}
-
/// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to
/// it. The memory will be dropped upon exit from `scope`. The callback `populate` should
/// initialize the memory.
+///
+/// The flag `zero` indicates how the temporary space itself should be
+/// initialized at the outset of the function; the only time that
+/// `InitAlloca::Uninit` is a valid value for `zero` is when the
+/// caller can prove that either (1.) the code injected by `populate`
+/// onto `bcx` always dominates the end of `scope`, or (2.) the data
+/// being allocated has no associated destructor.
pub fn lvalue_scratch_datum<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
ty: Ty<'tcx>,
name: &str,
+ zero: InitAlloca,
scope: cleanup::ScopeId,
arg: A,
populate: F)
-> DatumBlock<'blk, 'tcx, Lvalue> where
F: FnOnce(A, Block<'blk, 'tcx>, ValueRef) -> Block<'blk, 'tcx>,
{
- let scratch = alloc_ty(bcx, ty, name);
+ // Very subtle: potentially initialize the scratch memory at point where it is alloca'ed.
+ // (See discussion at Issue 30530.)
+ let scratch = alloc_ty_init(bcx, ty, zero, name);
+ debug!("lvalue_scratch_datum scope={:?} scratch={} ty={:?}",
+ scope, bcx.ccx().tn().val_to_string(scratch), ty);
// Subtle. Populate the scratch memory *before* scheduling cleanup.
let bcx = populate(arg, bcx, scratch);
scope: cleanup::ScopeId,
val: ValueRef,
ty: Ty<'tcx>) {
+ debug!("add_rvalue_clean scope={:?} val={} ty={:?}",
+ scope, fcx.ccx.tn().val_to_string(val), ty);
match mode {
ByValue => { fcx.schedule_drop_immediate(scope, val, ty); }
ByRef => {
ByValue => {
lvalue_scratch_datum(
- bcx, self.ty, name, scope, self,
+ bcx, self.ty, name, InitAlloca::Dropped, scope, self,
|this, bcx, llval| {
- call_lifetime_start(bcx, llval);
+ debug!("populate call for Datum::to_lvalue_datum_in_scope \
+ self.ty={:?}", this.ty);
+ // do not call_lifetime_start here; the
+ // `InitAlloc::Dropped` will start scratch
+ // value's lifetime at open of function body.
let bcx = this.store_to(bcx, llval);
bcx.fcx.schedule_lifetime_end(scope, llval);
bcx
}
};
+ debug!("trans_adt");
+
// This scope holds intermediates that must be cleaned should
// panic occur before the ADT as a whole is ready.
let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
// Always create an alloca even if zero-sized, to preserve
// the non-null invariant of the inner slice ptr
- let llfixed = base::alloc_ty(bcx, fixed_ty, "");
- call_lifetime_start(bcx, llfixed);
+ let llfixed;
+ // Issue 30018: ensure state is initialized as dropped if necessary.
+ if fcx.type_needs_drop(vt.unit_ty) {
+ llfixed = base::alloc_ty_init(bcx, fixed_ty, InitAlloca::Dropped, "");
+ } else {
+ let uninit = InitAlloca::Uninit("fcx says vt.unit_ty is non-drop");
+ llfixed = base::alloc_ty_init(bcx, fixed_ty, uninit, "");
+ call_lifetime_start(bcx, llfixed);
+ };
if count > 0 {
// Arrange for the backing array to be cleaned up.
bcx = expr::trans_into(bcx, &**element,
SaveIn(lleltptr));
let scope = cleanup::CustomScope(temp_scope);
- fcx.schedule_lifetime_end(scope, lleltptr);
- fcx.schedule_drop_mem(scope, lleltptr, vt.unit_ty, None);
+ // Issue #30822: mark memory as dropped after running destructor
+ fcx.schedule_drop_and_fill_mem(scope, lleltptr, vt.unit_ty, None);
}
fcx.pop_custom_cleanup_scope(temp_scope);
}
/// This `struct` is created by the [`to_lowercase()`] method on [`char`]. See
/// its documentation for more.
///
-/// [`to_lowercase()`]: primitive.char.html#method.escape_to_lowercase
-/// [`char`]: primitive.char.html
+/// [`to_lowercase()`]: ../primitive.char.html#method.to_lowercase
+/// [`char`]: ../primitive.char.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct ToLowercase(CaseMappingIter);
/// This `struct` is created by the [`to_uppercase()`] method on [`char`]. See
/// its documentation for more.
///
-/// [`to_uppercase()`]: primitive.char.html#method.escape_to_uppercase
-/// [`char`]: primitive.char.html
+/// [`to_uppercase()`]: ../primitive.char.html#method.to_uppercase
+/// [`char`]: ../primitive.char.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct ToUppercase(CaseMappingIter);
} else if stab.level == stability::Unstable {
let unstable_extra = if show_reason {
match (!stab.feature.is_empty(), &cx.issue_tracker_base_url, stab.issue) {
- (true, &Some(ref tracker_url), Some(issue_no)) =>
+ (true, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
format!(" (<code>{}</code> <a href=\"{}{}\">#{}</a>)",
Escape(&stab.feature), tracker_url, issue_no, issue_no),
- (false, &Some(ref tracker_url), Some(issue_no)) =>
+ (false, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
format!(" (<a href=\"{}{}\">#{}</a>)", Escape(&tracker_url), issue_no,
issue_no),
(true, _, _) =>
}
}
-struct InternalBufWriter<W: Write>(BufWriter<W>);
-
-impl<W: Read + Write> InternalBufWriter<W> {
- fn get_mut(&mut self) -> &mut BufWriter<W> {
- let InternalBufWriter(ref mut w) = *self;
- return w;
- }
-}
-
-impl<W: Read + Write> Read for InternalBufWriter<W> {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- self.get_mut().inner.as_mut().unwrap().read(buf)
- }
-}
-
#[cfg(test)]
mod tests {
use prelude::v1::*;
//! ```
//!
//! `BufWriter` doesn't add any new ways of writing; it just buffers every call
-//! to [`write()`][write]:
+//! to [`write()`][write()]:
//!
//! ```
//! use std::io;
//! # }
//! ```
//!
-//! [write]: trait.Write.html#tymethod.write
+//! [write()]: trait.Write.html#tymethod.write
//!
//! ## Standard input and output
//!
///
/// [`File`][file]s implement `Read`:
///
-/// [file]: ../std/fs/struct.File.html
+/// [file]: ../fs/struct.File.html
///
/// ```
/// use std::io;
///
/// [`File`][file]s implement `Read`:
///
- /// [file]: ../std/fs/struct.File.html
+ /// [file]: ../fs/struct.File.html
///
/// ```
/// use std::io;
///
/// [`File`][file]s implement `Read`:
///
- /// [file]: ../std/fs/struct.File.html
+ /// [file]: ../fs/struct.File.html
///
/// ```
/// use std::io;
///
/// [`File`][file]s implement `Read`:
///
- /// [file]: ../std/fs/struct.File.html
+ /// [file]: ../fs/struct.File.html
///
/// ```
/// use std::io;
///
/// [`File`][file]s implement `Read`:
///
- /// [file]: ../std/fs/struct.File.html
+ /// [file]: ../fs/struct.File.html
///
/// ```
/// use std::io;
///
/// [`File`][file]s implement `Read`:
///
- /// [file]: ../std/fs/struct.File.html
+ /// [file]: ../fs/struct.File.html
///
/// ```
/// use std::io;
///
/// [`File`][file]s implement `Read`:
///
- /// [file]: ../std/fs/struct.File.html
+ /// [file]: ../fs/struct.File.html
///
/// ```
/// use std::io;
///
/// [`File`][file]s implement `Read`:
///
- /// [file]: ../std/fs/struct.File.html
+ /// [file]: ../fs/struct.File.html
///
/// ```
/// #![feature(io)]
///
/// [`File`][file]s implement `Read`:
///
- /// [file]: ../std/fs/struct.File.html
+ /// [file]: ../fs/struct.File.html
///
/// ```
/// use std::io;
///
/// [`File`][file]s implement `Read`:
///
- /// [file]: ../std/fs/struct.File.html
+ /// [file]: ../fs/struct.File.html
///
/// ```
/// use std::io;
///
/// [`File`][file]s implement `Read`:
///
- /// [file]: ../std/fs/struct.File.html
+ /// [file]: ../fs/struct.File.html
///
/// ```
/// #![feature(io)]
// debugger provides a useable stacktrace.
if panics >= 3 {
util::dumb_print(format_args!("thread panicked while processing \
- panic. aborting."));
+ panic. aborting.\n"));
unsafe { intrinsics::abort() }
}
// just abort. In the future we may consider resuming
// unwinding or otherwise exiting the thread cleanly.
util::dumb_print(format_args!("thread panicked while panicking. \
- aborting."));
+ aborting.\n"));
unsafe { intrinsics::abort() }
}
}
// getentropy(2) permits a maximum buffer size of 256 bytes
for s in v.chunks_mut(256) {
let ret = unsafe {
- libc::syscall(libc::NR_GETENTROPY, s.as_mut_ptr(), s.len())
+ libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
};
if ret == -1 {
panic!("unexpected getentropy error: {}", errno());
}
pub fn abort(args: fmt::Arguments) -> ! {
- dumb_print(format_args!("fatal runtime error: {}", args));
+ dumb_print(format_args!("fatal runtime error: {}\n", args));
unsafe { intrinsics::abort(); }
}
#[allow(dead_code)] // stack overflow detection not enabled on all platforms
pub unsafe fn report_overflow() {
- dumb_print(format_args!("\nthread '{}' has overflowed its stack",
+ dumb_print(format_args!("\nthread '{}' has overflowed its stack\n",
thread::current().name().unwrap_or("<unknown>")));
}
#[cfg(any(target_os = "macos",
target_os = "ios",
- target_os = "netbsd"))]
+ target_os = "netbsd",
+ target_os = "openbsd"))]
fn name_bytes(&self) -> &[u8] {
unsafe {
::slice::from_raw_parts(self.entry.d_name.as_ptr() as *const u8,
}
#[cfg(any(target_os = "freebsd",
target_os = "dragonfly",
- target_os = "bitrig",
- target_os = "openbsd"))]
+ target_os = "bitrig"))]
fn name_bytes(&self) -> &[u8] {
unsafe {
::slice::from_raw_parts(self.entry.d_name.as_ptr() as *const u8,
use libc;
use num::One;
use ops::Neg;
+use alloc::oom;
#[cfg(target_os = "android")] pub use os::android as platform;
#[cfg(target_os = "bitrig")] pub use os::bitrig as platform;
pub mod time;
pub mod stdio;
+// A nicer handler for out-of-memory situations than the default one. This one
+// prints a message to stderr before aborting. It is critical that this code
+// does not allocate any memory since we are in an OOM situation. Any errors are
+// ignored while printing since there's nothing we can do about them and we are
+// about to exit anyways.
+fn oom_handler() -> ! {
+ use intrinsics;
+ let msg = "fatal runtime error: out of memory\n";
+ unsafe {
+ libc::write(libc::STDERR_FILENO,
+ msg.as_ptr() as *const libc::c_void,
+ msg.len() as libc::size_t);
+ intrinsics::abort();
+ }
+}
+
#[cfg(not(any(target_os = "nacl", test)))]
pub fn init() {
use libc::signal;
unsafe {
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
}
+
+ oom::set_oom_handler(oom_handler);
}
#[cfg(all(target_os = "nacl", not(test)))]
-pub fn init() { }
+pub fn init() {
+ oom::set_oom_handler(oom_handler);
+}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno as libc::c_int {
static mut PAGE_SIZE: usize = 0;
#[cfg(any(target_os = "linux", target_os = "android"))]
- unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> *mut libc::c_void {
+ unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
#[repr(C)]
struct siginfo_t {
a: [libc::c_int; 3], // si_signo, si_code, si_errno,
si_addr: *mut libc::c_void,
}
- (*(info as *const siginfo_t)).si_addr
+ (*(info as *const siginfo_t)).si_addr as usize
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
- unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> *mut libc::c_void {
- (*info).si_addr
+ unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
+ (*info).si_addr as usize
}
// Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
use sys_common::util::report_overflow;
let guard = thread_info::stack_guard().unwrap_or(0);
- let addr = siginfo_si_addr(info) as usize;
+ let addr = siginfo_si_addr(info);
// If the faulting address is within the guard page, then we print a
// message saying so.
use os::windows::ffi::{OsStrExt, OsStringExt};
use path::PathBuf;
use time::Duration;
+use alloc::oom;
#[macro_use] pub mod compat;
pub mod time;
pub mod stdio;
-pub fn init() {}
+// See comment in sys/unix/mod.rs
+fn oom_handler() -> ! {
+ use intrinsics;
+ use ptr;
+ let msg = "fatal runtime error: out of memory\n";
+ unsafe {
+ // WriteFile silently fails if it is passed an invalid handle, so there
+ // is no need to check the result of GetStdHandle.
+ c::WriteFile(c::GetStdHandle(c::STD_ERROR_HANDLE),
+ msg.as_ptr() as c::LPVOID,
+ msg.len() as c::DWORD,
+ ptr::null_mut(),
+ ptr::null_mut());
+ intrinsics::abort();
+ }
+}
+
+pub fn init() {
+ oom::set_oom_handler(oom_handler);
+}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno as c::DWORD {
/// let ten_millis = Duration::from_millis(10);
/// ```
#[stable(feature = "duration", since = "1.3.0")]
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Duration {
secs: u64,
nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
#[cfg(any(target_os = "freebsd",
target_os = "dragonfly",
target_os = "bitrig",
- target_os = "openbsd",
target_os = "netbsd"))]
fn num_cpus() -> usize {
let mut cpus: libc::c_uint = 0;
}
cpus as usize
}
+
+ #[cfg(target_os = "openbsd")]
+ fn num_cpus() -> usize {
+ let mut cpus: libc::c_uint = 0;
+ let mut cpus_size = std::mem::size_of_val(&cpus);
+ let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+
+ unsafe {
+ libc::sysctl(mib.as_mut_ptr(), 2,
+ &mut cpus as *mut _ as *mut _,
+ &mut cpus_size as *mut _ as *mut _,
+ 0 as *mut _, 0);
+ }
+ if cpus < 1 {
+ cpus = 1;
+ }
+ cpus as usize
+ }
}
pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
--- /dev/null
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for Issue #29092.
+//
+// (Possibly redundant with regression test run-pass/issue-30530.rs)
+
+use self::Term::*;
+
+#[derive(Clone)]
+pub enum Term {
+ Dummy,
+ A(Box<Term>),
+ B(Box<Term>),
+}
+
+// a small-step evaluator
+pub fn small_eval(v: Term) -> Term {
+ match v {
+ A(t) => *t.clone(),
+ B(t) => *t.clone(),
+ _ => Dummy,
+ }
+}
+
+fn main() {
+ small_eval(Dummy);
+}
--- /dev/null
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// More thorough regression test for Issues #30018 and #30822. This
+// attempts to explore different ways that array element construction
+// (for both scratch arrays and non-scratch ones) interacts with
+// breaks in the control-flow, in terms of the order of evaluation of
+// the destructors (which may change; see RFC Issue 744) and the
+// number of times that the destructor evaluates for each value (which
+// should never exceed 1; this latter case is what #30822 is about).
+
+use std::cell::RefCell;
+
+struct D<'a>(&'a RefCell<Vec<i32>>, i32);
+
+impl<'a> Drop for D<'a> {
+ fn drop(&mut self) {
+ println!("Dropping D({})", self.1);
+ (self.0).borrow_mut().push(self.1);
+ }
+}
+
+fn main() {
+ println!("Start");
+ break_during_elem();
+ break_after_whole();
+ println!("Finis");
+}
+
+fn break_during_elem() {
+ let log = &RefCell::new(Vec::new());
+
+ // CASE 1: Fixed-size array itself is stored in _r slot.
+ loop {
+ let _r = [D(log, 10),
+ D(log, 11),
+ { D(log, 12); break; },
+ D(log, 13)];
+ }
+ assert_eq!(&log.borrow()[..], &[12, 11, 10]);
+ log.borrow_mut().clear();
+
+ // CASE 2: Slice (borrow of array) is stored in _r slot.
+ // This is the case that is actually being reported in #30018.
+ loop {
+ let _r = &[D(log, 20),
+ D(log, 21),
+ { D(log, 22); break; },
+ D(log, 23)];
+ }
+ assert_eq!(&log.borrow()[..], &[22, 21, 20]);
+ log.borrow_mut().clear();
+
+ // CASE 3: (Borrow of) slice-index of array is stored in _r slot.
+ loop {
+ let _r = &[D(log, 30),
+ D(log, 31),
+ { D(log, 32); break; },
+ D(log, 33)][..];
+ }
+ assert_eq!(&log.borrow()[..], &[32, 31, 30]);
+ log.borrow_mut().clear();
+}
+
+// The purpose of these functions is to test what happens when we
+// panic after an array has been constructed in its entirety.
+//
+// It is meant to act as proof that we still need to continue
+// scheduling the destruction of an array even after we've scheduling
+// drop for its elements during construction; the latter is tested by
+// `fn break_during_elem()`.
+fn break_after_whole() {
+ let log = &RefCell::new(Vec::new());
+
+ // CASE 1: Fixed-size array itself is stored in _r slot.
+ loop {
+ let _r = [D(log, 10),
+ D(log, 11),
+ D(log, 12)];
+ break;
+ }
+ assert_eq!(&log.borrow()[..], &[10, 11, 12]);
+ log.borrow_mut().clear();
+
+ // CASE 2: Slice (borrow of array) is stored in _r slot.
+ loop {
+ let _r = &[D(log, 20),
+ D(log, 21),
+ D(log, 22)];
+ break;
+ }
+ assert_eq!(&log.borrow()[..], &[20, 21, 22]);
+ log.borrow_mut().clear();
+
+ // CASE 3: (Borrow of) slice-index of array is stored in _r slot.
+ loop {
+ let _r = &[D(log, 30),
+ D(log, 31),
+ D(log, 32)][..];
+ break;
+ }
+ assert_eq!(&log.borrow()[..], &[30, 31, 32]);
+ log.borrow_mut().clear();
+}
--- /dev/null
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for Issue #30018. This is very similar to the
+// original reported test, except that the panic is wrapped in a
+// spawned thread to isolate the expected error result from the
+// SIGTRAP injected by the drop-flag consistency checking.
+
+struct Foo;
+
+impl Drop for Foo {
+ fn drop(&mut self) {}
+}
+
+fn foo() -> Foo {
+ panic!();
+}
+
+fn main() {
+ use std::thread;
+ let handle = thread::spawn(|| {
+ let _ = &[foo()];
+ });
+ let _ = handle.join();
+}
--- /dev/null
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for Issue #30530: alloca's created for storing
+// intermediate scratch values during brace-less match arms need to be
+// initialized with their drop-flag set to "dropped" (or else we end
+// up running the destructors on garbage data at the end of the
+// function).
+
+pub enum Handler {
+ Default,
+ #[allow(dead_code)]
+ Custom(*mut Box<Fn()>),
+}
+
+fn main() {
+ take(Handler::Default, Box::new(main));
+}
+
+#[inline(never)]
+pub fn take(h: Handler, f: Box<Fn()>) -> Box<Fn()> {
+ unsafe {
+ match h {
+ Handler::Custom(ptr) => *Box::from_raw(ptr),
+ Handler::Default => f,
+ }
+ }
+}