<commit_before>//! An abstraction over exfiltrating information out of signal handlers.
//!
//! The [`Exfiltrator`] trait provides a way to abstract the information extracted from a signal
//! handler and the way it is extracted out of it.
//!
//! The implementations can be used to parametrize the
//! [`SignalsInfo`][crate::iterator::SignalsInfo] to specify what results are returned.
//!
//! # Sealed
//!
//! Currently, the trait is sealed and all methods hidden. This is likely temporary, until some
//! experience with them is gained.

use std::sync::atomic::{AtomicBool, Ordering};

use libc::{c_int, siginfo_t};

mod sealed {
    use std::fmt::Debug;

    use libc::{c_int, siginfo_t};

    pub unsafe trait Exfiltrator: Debug + Send + Sync + 'static {
        type Storage: Debug + Default + Send + Sync + 'static;
        type Output;
        fn supports_signal(&self, sig: c_int) -> bool;
        fn store(&self, slot: &Self::Storage, signal: c_int, info: &siginfo_t);
        fn load(&self, slot: &Self::Storage, signal: c_int) -> Option<Self::Output>;
    }
}

/// A trait describing what and how is extracted from signal handlers.
///
/// By choosing a specific implementor as the type parameter for
/// [`SignalsInfo`][crate::iterator::SignalsInfo], one can pick how much and what information is
/// returned from the iterator.
pub trait Exfiltrator: sealed::Exfiltrator {}

impl<E: sealed::Exfiltrator> Exfiltrator for E {}

/// An [`Exfiltrator`] providing just the signal numbers.
///
/// This is the basic exfiltrator for most needs. For that reason, there's the
/// [`crate::iterator::Signals`] type alias, to simplify the type names for usual needs.
#[derive(Clone, Copy, Debug, Default)]
pub struct SignalOnly;

unsafe impl sealed::Exfiltrator for SignalOnly {
    type Storage = AtomicBool;
    fn supports_signal(&self, _: c_int) -> bool {
        true
    }
    type Output = c_int;

    fn store(&self, slot: &Self::Storage, _: c_int, _: &siginfo_t) {
        slot.store(true, Ordering::SeqCst);
    }

    fn load(&self, slot: &Self::Storage, signal: c_int) -> Option<Self::Output> {
        if slot
            .compare_exchange(true, false, Ordering::SeqCst, Ordering::Relaxed)
            .is_ok()
        {
            Some(signal)
        } else {
            None
        }
    }
}
<commit_msg>Document the (internal) Exfiltrator trait<commit_after>//! An abstraction over exfiltrating information out of signal handlers.
//!
//! The [`Exfiltrator`] trait provides a way to abstract the information extracted from a signal
//! handler and the way it is extracted out of it.
//!
//! The implementations can be used to parametrize the
//! [`SignalsInfo`][crate::iterator::SignalsInfo] to specify what results are returned.
//!
//! # Sealed
//!
//! Currently, the trait is sealed and all methods hidden. This is likely temporary, until some
//! experience with them is gained.

use std::sync::atomic::{AtomicBool, Ordering};

use libc::{c_int, siginfo_t};

mod sealed {
    use std::fmt::Debug;

    use libc::{c_int, siginfo_t};

    /// The actual implementation of the [`Exfiltrator`][super::Exfiltrator].
    ///
    /// For now, this is hidden from the public API, but the intention is to move it to a public
    /// place so users can implement it eventually, once we verify that it works well.
    ///
    /// The trait is unsafe as the [`Exfiltrator::store`] is called inside the signal handler and
    /// must be async-signal-safe. Implementing this correctly may be difficult, therefore care
    /// needs to be taken. One method known to work is encoding the data into an atomic variable.
    /// Other, less limiting approaches, will be eventually explored.
    pub unsafe trait Exfiltrator: Debug + Send + Sync + 'static {
        /// One slot for storing the data.
        ///
        /// Each signal will get its one slot of this type, independent of other signals. It can
        /// store the information in there inside the signal handler and will be loaded from it in
        /// load.
        ///
        /// Each slot is initialized to the [`Default`] value. It is expected this value represents
        /// „no signal delivered“ state.
        type Storage: Debug + Default + Send + Sync + 'static;

        /// The type returned to the user.
        type Output;

        /// If the given signal is supported by this specific exfiltrator.
        ///
        /// Not all information is available to all signals, therefore not all exfiltrators must
        /// support all signals. If `false` is returned, the user is prevented for registering such
        /// signal number with the given exfiltrator.
        fn supports_signal(&self, sig: c_int) -> bool;

        /// Puts the signal information inside the slot.
        ///
        /// It needs to somehow store the relevant information and the fact that a signal happened.
        ///
        /// # Warning
        ///
        /// This will be called inside the signal handler. It needs to be async-signal-safe. In
        /// particular, very small amount of operations are allowed in there. This namely does
        /// *not* include any locking nor allocation.
        ///
        /// It is also possible that multiple store methods are called concurrently; it is up to
        /// the implementor to deal with that.
        fn store(&self, slot: &Self::Storage, signal: c_int, info: &siginfo_t);

        /// Loads the signal information from the given slot.
        ///
        /// The method shall check if the signal happened (it may be possible to be called without
        /// the signal previously being delivered; it is up to the implementer to recognize it). It
        /// is assumed the [`Default`] value is recognized as no signal delivered.
        ///
        /// If it was delivered, the method shall extract the relevant information *and reset the
        /// slot* to the no signal delivered state.
        ///
        /// It shall return `Some(value)` if the signal was successfully received and `None` in
        /// case no signal was delivered.
        ///
        /// No blocking shall happen inside this method. It may be called concurrently with
        /// [`store`][Exfiltrator::store] (due to how signals work, concurrently even inside the
        /// same thread ‒ a `store` may „interrupt“ a call to `load`). It is up to the implementer
        /// to deal with that.
        fn load(&self, slot: &Self::Storage, signal: c_int) -> Option<Self::Output>;
    }
}

/// A trait describing what and how is extracted from signal handlers.
///
/// By choosing a specific implementor as the type parameter for
/// [`SignalsInfo`][crate::iterator::SignalsInfo], one can pick how much and what information is
/// returned from the iterator.
pub trait Exfiltrator: sealed::Exfiltrator {}

impl<E: sealed::Exfiltrator> Exfiltrator for E {}

/// An [`Exfiltrator`] providing just the signal numbers.
///
/// This is the basic exfiltrator for most needs. For that reason, there's the
/// [`crate::iterator::Signals`] type alias, to simplify the type names for usual needs.
#[derive(Clone, Copy, Debug, Default)]
pub struct SignalOnly;

unsafe impl sealed::Exfiltrator for SignalOnly {
    type Storage = AtomicBool;
    fn supports_signal(&self, _: c_int) -> bool {
        true
    }
    type Output = c_int;

    fn store(&self, slot: &Self::Storage, _: c_int, _: &siginfo_t) {
        slot.store(true, Ordering::SeqCst);
    }

    fn load(&self, slot: &Self::Storage, signal: c_int) -> Option<Self::Output> {
        if slot
            .compare_exchange(true, false, Ordering::SeqCst, Ordering::Relaxed)
            .is_ok()
        {
            Some(signal)
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use std::num;

pub trait Addressable<ADDR: Int> {
	pub fn get (&self, addr: ADDR) -> u8;
	pub fn set (&mut self, addr: ADDR, data: u8);
}

// FIXME: With default methods, we won't need this anymore
pub trait AddressableUtil<ADDR: Int> {
	pub fn getx (&self, addr:ADDR, offset: int) -> u8;
	pub fn get_be_n (&self, addr: ADDR, nbytes: uint) -> u64;
	pub fn get_be<T: Int> (&self, addr: ADDR) -> T;
	pub fn get_le_n (&self, addr: ADDR, nbytes: uint) -> u64;
	pub fn get_le<T: Int> (&self, addr: ADDR) -> T;

	pub fn setx (&mut self, addr: ADDR, offset: int, data: u8);
	pub fn set_be_n (&mut self, addr: ADDR, nbytes: uint, val: u64);
	pub fn set_be<T: Int> (&mut self, addr: ADDR, val: T);
	pub fn set_le_n (&mut self, addr: ADDR, nbytes: uint, val: u64);
	pub fn set_le<T: Int> (&mut self, addr: ADDR, val: T);
}

impl<ADDR: Int+Copy, A: Addressable<ADDR>> AddressableUtil<ADDR> for A {
	pub fn getx (&self, addr:ADDR, offset: int) -> u8 {
		self.get(addr + num::cast(offset))
	}

	pub fn get_be_n (&self, addr: ADDR, nbytes: uint) -> u64 {
		assert!(nbytes > 0 && nbytes < 8);
		let mut val = 0u64;
		let mut i = nbytes;
		while i > 0 {
			i -= 1;
			val |= self.get(addr + num::cast(i)) as u64 << (nbytes-i-1) * 8;
		}
		val
	}

	pub fn get_be<T: Int> (&self, addr: ADDR) -> T {
		num::cast(self.get_be_n(addr, num::Primitive::bytes::<T>()))
	}

	pub fn get_le_n (&self, addr: ADDR, nbytes: uint) -> u64 {
		assert!(nbytes > 0 && nbytes < 8);
		let mut val = 0u64;
		let mut i = nbytes;
		while i > 0 {
			i -= 1;
			val |= self.get(addr + num::cast(i)) as u64 << i * 8;
		}
		val
	}

	pub fn get_le<T: Int> (&self, addr: ADDR) -> T {
		num::cast(self.get_le_n(addr, num::Primitive::bytes::<T>()))
	}

	pub fn setx (&mut self, addr: ADDR, offset: int, data: u8) {
		self.set(addr + num::cast(offset), data);
	}

	pub fn set_be_n (&mut self, addr: ADDR, nbytes: uint, val: u64) {
		assert!(nbytes > 0 && nbytes < 8);
		let mut i = nbytes;
		while i > 0 {
			i -= 1;
			self.set(addr + num::cast(i), (val >> (nbytes-i-1) * 8) as u8);
		}
	}

	pub fn set_be<T: Int> (&mut self, addr: ADDR, val: T) {
		self.set_be_n(addr, num::Primitive::bytes::<T>(), num::cast(val));
	}

	pub fn set_le_n (&mut self, addr: ADDR, nbytes: uint, val: u64) {
		assert!(nbytes > 0 && nbytes < 8);
		let mut i = nbytes;
		while i > 0 {
			i -= 1;
			self.set(addr + num::cast(i), (val >> i * 8) as u8);
		}
	}

	pub fn set_le<T: Int> (&mut self, addr: ADDR, val: T) {
		self.set_le_n(addr, num::Primitive::bytes::<T>(), num::cast(val));
	}
}

#[cfg(test)]
mod tests {
	use super::*;

	struct DummyData;
	impl Addressable<u16> for DummyData {
		pub fn get (&self, addr: u16) -> u8 {
			addr as u8
		}
		pub fn set (&mut self, addr: u16, data: u8) {
			assert_eq!(data, addr as u8);
		}
	}

	#[test]
	fn test_get () {
		let data = DummyData;
		assert_eq!(data.get(0x0012), 0x12);
		assert_eq!(data.get(0x1234), 0x34);
	}

	#[test]
	fn test_getx () {
		let data = DummyData;
		assert_eq!(data.getx(0x0012_u16, 5), 0x17);
		assert_eq!(data.getx(0x1234_u16, 5), 0x39);
	}

	#[test]
	fn test_get_big_endian () {
		let data = DummyData;
		assert_eq!(      0x02_u8 , data.get_be(0x0002_u16));
		assert_eq!(      0x54_u8 , data.get_be(0x0054_u16));
		assert_eq!(    0x0203_u16, data.get_be(0x0002_u16));
		assert_eq!(    0x5455_u16, data.get_be(0x0054_u16));
		assert_eq!(0x02030405_u32, data.get_be(0x0002_u16));
		assert_eq!(0x54555657_u32, data.get_be(0x0054_u16));
	}

	#[test]
	fn test_get_signed_big_endian () {
		let data = DummyData;
		assert_eq!(       0x54_i8 , data.get_be(0x0054_u16));
		assert_eq!(      -0x5b_i8 , data.get_be(0x00a5_u16));
		assert_eq!(     0x5455_i16, data.get_be(0x0054_u16));
		assert_eq!(    -0x5a5a_i16, data.get_be(0x00a5_u16));
		assert_eq!( 0x54555657_i32, data.get_be(0x0054_u16));
		assert_eq!(-0x5a595858_i32, data.get_be(0x00a5_u16));
	}

	#[test]
	fn test_get_little_endian () {
		let data = DummyData;
		assert_eq!(      0x02_u8 , data.get_le(0x0002_u16));
		assert_eq!(      0x54_u8 , data.get_le(0x0054_u16));
		assert_eq!(    0x0302_u16, data.get_le(0x0002_u16));
		assert_eq!(    0x5554_u16, data.get_le(0x0054_u16));
		assert_eq!(0x05040302_u32, data.get_le(0x0002_u16));
		assert_eq!(0x57565554_u32, data.get_le(0x0054_u16));
	}

	#[test]
	fn test_get_signed_little_endian () {
		let data = DummyData;
		assert_eq!(       0x54_i8 , data.get_le(0x0054_u16));
		assert_eq!(      -0x5b_i8 , data.get_le(0x00a5_u16));
		assert_eq!(     0x5554_i16, data.get_le(0x0054_u16));
		assert_eq!(    -0x595b_i16, data.get_le(0x00a5_u16));
		assert_eq!( 0x57565554_i32, data.get_le(0x0054_u16));
		assert_eq!(-0x5758595b_i32, data.get_le(0x00a5_u16));
	}

	#[test]
	fn test_set () {
		let mut data = DummyData;
		data.set(0x0012, 0x12);
		data.set(0x1234, 0x34);
	}

	#[test]
	fn test_setx () {
		let mut data = DummyData;
		data.setx(0x0012_u16, 5, 0x17);
		data.setx(0x1234_u16, 5, 0x39);
	}

	#[test]
	fn test_set_big_endian () {
		let mut data = DummyData;
		data.set_be(0x0002_u16,       0x02_u8 );
		data.set_be(0x0054_u16,       0x54_u8 );
		data.set_be(0x0002_u16,     0x0203_u16);
		data.set_be(0x0054_u16,     0x5455_u16);
		data.set_be(0x0002_u16, 0x02030405_u32);
		data.set_be(0x0054_u16, 0x54555657_u32);
	}

	#[test]
	fn test_set_signed_big_endian () {
		let mut data = DummyData;
		data.set_be(0x0054_u16,        0x54_i8 );
		data.set_be(0x00a5_u16,       -0x5b_i8 );
		data.set_be(0x0054_u16,      0x5455_i16);
		data.set_be(0x00a5_u16,     -0x5a5a_i16);
		data.set_be(0x0054_u16,  0x54555657_i32);
		data.set_be(0x00a5_u16, -0x5a595858_i32);
	}

	#[test]
	fn test_set_little_endian () {
		let mut data = DummyData;
		data.set_le(0x0002_u16,       0x02_u8 );
		data.set_le(0x0054_u16,       0x54_u8 );
		data.set_le(0x0002_u16,     0x0302_u16);
		data.set_le(0x0054_u16,     0x5554_u16);
		data.set_le(0x0002_u16, 0x05040302_u32);
		data.set_le(0x0054_u16, 0x57565554_u32);
	}

	fn test_set_signed_little_endian () {
		let mut data = DummyData;
		data.set_le(0x0054_u16,        0x54_i8 );
		data.set_le(0x00a5_u16,       -0x5b_i8 );
		data.set_le(0x0054_u16,      0x5554_i16);
		data.set_le(0x00a5_u16,     -0x595b_i16);
		data.set_le(0x0054_u16,  0x57565554_i32);
		data.set_le(0x00a5_u16, -0x5758595b_i32);
	}
}
<commit_msg>No need to explicitly require the Copy trait for ADDR<commit_after>use std::num;

pub trait Addressable<ADDR: Int> {
	pub fn get (&self, addr: ADDR) -> u8;
	pub fn set (&mut self, addr: ADDR, data: u8);
}

// FIXME: With default methods, we won't need this anymore
pub trait AddressableUtil<ADDR: Int> {
	pub fn getx (&self, addr:ADDR, offset: int) -> u8;
	pub fn get_be_n (&self, addr: ADDR, nbytes: uint) -> u64;
	pub fn get_be<T: Int> (&self, addr: ADDR) -> T;
	pub fn get_le_n (&self, addr: ADDR, nbytes: uint) -> u64;
	pub fn get_le<T: Int> (&self, addr: ADDR) -> T;

	pub fn setx (&mut self, addr: ADDR, offset: int, data: u8);
	pub fn set_be_n (&mut self, addr: ADDR, nbytes: uint, val: u64);
	pub fn set_be<T: Int> (&mut self, addr: ADDR, val: T);
	pub fn set_le_n (&mut self, addr: ADDR, nbytes: uint, val: u64);
	pub fn set_le<T: Int> (&mut self, addr: ADDR, val: T);
}

impl<ADDR: Int, A: Addressable<ADDR>> AddressableUtil<ADDR> for A {
	pub fn getx (&self, addr:ADDR, offset: int) -> u8 {
		self.get(addr + num::cast(offset))
	}

	pub fn get_be_n (&self, addr: ADDR, nbytes: uint) -> u64 {
		assert!(nbytes > 0 && nbytes < 8);
		let mut val = 0u64;
		let mut i = nbytes;
		while i > 0 {
			i -= 1;
			val |= self.get(addr + num::cast(i)) as u64 << (nbytes-i-1) * 8;
		}
		val
	}

	pub fn get_be<T: Int> (&self, addr: ADDR) -> T {
		num::cast(self.get_be_n(addr, num::Primitive::bytes::<T>()))
	}

	pub fn get_le_n (&self, addr: ADDR, nbytes: uint) -> u64 {
		assert!(nbytes > 0 && nbytes < 8);
		let mut val = 0u64;
		let mut i = nbytes;
		while i > 0 {
			i -= 1;
			val |= self.get(addr + num::cast(i)) as u64 << i * 8;
		}
		val
	}

	pub fn get_le<T: Int> (&self, addr: ADDR) -> T {
		num::cast(self.get_le_n(addr, num::Primitive::bytes::<T>()))
	}

	pub fn setx (&mut self, addr: ADDR, offset: int, data: u8) {
		self.set(addr + num::cast(offset), data);
	}

	pub fn set_be_n (&mut self, addr: ADDR, nbytes: uint, val: u64) {
		assert!(nbytes > 0 && nbytes < 8);
		let mut i = nbytes;
		while i > 0 {
			i -= 1;
			self.set(addr + num::cast(i), (val >> (nbytes-i-1) * 8) as u8);
		}
	}

	pub fn set_be<T: Int> (&mut self, addr: ADDR, val: T) {
		self.set_be_n(addr, num::Primitive::bytes::<T>(), num::cast(val));
	}

	pub fn set_le_n (&mut self, addr: ADDR, nbytes: uint, val: u64) {
		assert!(nbytes > 0 && nbytes < 8);
		let mut i = nbytes;
		while i > 0 {
			i -= 1;
			self.set(addr + num::cast(i), (val >> i * 8) as u8);
		}
	}

	pub fn set_le<T: Int> (&mut self, addr: ADDR, val: T) {
		self.set_le_n(addr, num::Primitive::bytes::<T>(), num::cast(val));
	}
}

#[cfg(test)]
mod tests {
	use super::*;

	struct DummyData;
	impl Addressable<u16> for DummyData {
		pub fn get (&self, addr: u16) -> u8 {
			addr as u8
		}
		pub fn set (&mut self, addr: u16, data: u8) {
			assert_eq!(data, addr as u8);
		}
	}

	#[test]
	fn test_get () {
		let data = DummyData;
		assert_eq!(data.get(0x0012), 0x12);
		assert_eq!(data.get(0x1234), 0x34);
	}

	#[test]
	fn test_getx () {
		let data = DummyData;
		assert_eq!(data.getx(0x0012_u16, 5), 0x17);
		assert_eq!(data.getx(0x1234_u16, 5), 0x39);
	}

	#[test]
	fn test_get_big_endian () {
		let data = DummyData;
		assert_eq!(      0x02_u8 , data.get_be(0x0002_u16));
		assert_eq!(      0x54_u8 , data.get_be(0x0054_u16));
		assert_eq!(    0x0203_u16, data.get_be(0x0002_u16));
		assert_eq!(    0x5455_u16, data.get_be(0x0054_u16));
		assert_eq!(0x02030405_u32, data.get_be(0x0002_u16));
		assert_eq!(0x54555657_u32, data.get_be(0x0054_u16));
	}

	#[test]
	fn test_get_signed_big_endian () {
		let data = DummyData;
		assert_eq!(       0x54_i8 , data.get_be(0x0054_u16));
		assert_eq!(      -0x5b_i8 , data.get_be(0x00a5_u16));
		assert_eq!(     0x5455_i16, data.get_be(0x0054_u16));
		assert_eq!(    -0x5a5a_i16, data.get_be(0x00a5_u16));
		assert_eq!( 0x54555657_i32, data.get_be(0x0054_u16));
		assert_eq!(-0x5a595858_i32, data.get_be(0x00a5_u16));
	}

	#[test]
	fn test_get_little_endian () {
		let data = DummyData;
		assert_eq!(      0x02_u8 , data.get_le(0x0002_u16));
		assert_eq!(      0x54_u8 , data.get_le(0x0054_u16));
		assert_eq!(    0x0302_u16, data.get_le(0x0002_u16));
		assert_eq!(    0x5554_u16, data.get_le(0x0054_u16));
		assert_eq!(0x05040302_u32, data.get_le(0x0002_u16));
		assert_eq!(0x57565554_u32, data.get_le(0x0054_u16));
	}

	#[test]
	fn test_get_signed_little_endian () {
		let data = DummyData;
		assert_eq!(       0x54_i8 , data.get_le(0x0054_u16));
		assert_eq!(      -0x5b_i8 , data.get_le(0x00a5_u16));
		assert_eq!(     0x5554_i16, data.get_le(0x0054_u16));
		assert_eq!(    -0x595b_i16, data.get_le(0x00a5_u16));
		assert_eq!( 0x57565554_i32, data.get_le(0x0054_u16));
		assert_eq!(-0x5758595b_i32, data.get_le(0x00a5_u16));
	}

	#[test]
	fn test_set () {
		let mut data = DummyData;
		data.set(0x0012, 0x12);
		data.set(0x1234, 0x34);
	}

	#[test]
	fn test_setx () {
		let mut data = DummyData;
		data.setx(0x0012_u16, 5, 0x17);
		data.setx(0x1234_u16, 5, 0x39);
	}

	#[test]
	fn test_set_big_endian () {
		let mut data = DummyData;
		data.set_be(0x0002_u16,       0x02_u8 );
		data.set_be(0x0054_u16,       0x54_u8 );
		data.set_be(0x0002_u16,     0x0203_u16);
		data.set_be(0x0054_u16,     0x5455_u16);
		data.set_be(0x0002_u16, 0x02030405_u32);
		data.set_be(0x0054_u16, 0x54555657_u32);
	}

	#[test]
	fn test_set_signed_big_endian () {
		let mut data = DummyData;
		data.set_be(0x0054_u16,        0x54_i8 );
		data.set_be(0x00a5_u16,       -0x5b_i8 );
		data.set_be(0x0054_u16,      0x5455_i16);
		data.set_be(0x00a5_u16,     -0x5a5a_i16);
		data.set_be(0x0054_u16,  0x54555657_i32);
		data.set_be(0x00a5_u16, -0x5a595858_i32);
	}

	#[test]
	fn test_set_little_endian () {
		let mut data = DummyData;
		data.set_le(0x0002_u16,       0x02_u8 );
		data.set_le(0x0054_u16,       0x54_u8 );
		data.set_le(0x0002_u16,     0x0302_u16);
		data.set_le(0x0054_u16,     0x5554_u16);
		data.set_le(0x0002_u16, 0x05040302_u32);
		data.set_le(0x0054_u16, 0x57565554_u32);
	}

	fn test_set_signed_little_endian () {
		let mut data = DummyData;
		data.set_le(0x0054_u16,        0x54_i8 );
		data.set_le(0x00a5_u16,       -0x5b_i8 );
		data.set_le(0x0054_u16,      0x5554_i16);
		data.set_le(0x00a5_u16,     -0x595b_i16);
		data.set_le(0x0054_u16,  0x57565554_i32);
		data.set_le(0x00a5_u16, -0x5758595b_i32);
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use colored::Colorize;
use diff::Result::*;

/// Prints a diff between the expected and actual strings to stdout.
pub(crate) fn print_diff(expected: &str, actual: &str) {
    let changes = diff::lines(expected, actual);
    for (line_index, change) in changes.iter().enumerate() {
        let formatted_line = match change {
            Both(context, _context) => {
                // Print 1 line of context
                let prev_is_change = line_index > 0 && is_change(&changes[line_index - 1]);
                let next_is_change = changes.get(line_index + 1).map_or(false, is_change);
                if prev_is_change || next_is_change {
                    format!("| {}", context).dimmed()
                } else {
                    continue;
                }
            }
            Left(removed) => format!("- {}", removed).red(),
            Right(added) => format!("+ {}", added).green(),
        };
        println!("{:4} {}", line_index + 1, formatted_line);
    }
}

fn is_change<T>(result: &diff::Result<T>) -> bool {
    match result {
        Left(_) | Right(_) => true,
        _ => false,
    }
}
<commit_msg>Fix clippy errors in fixture-tests<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use colored::Colorize;
use diff::Result::*;

/// Prints a diff between the expected and actual strings to stdout.
pub(crate) fn print_diff(expected: &str, actual: &str) {
    let changes = diff::lines(expected, actual);
    for (line_index, change) in changes.iter().enumerate() {
        let formatted_line = match change {
            Both(context, _context) => {
                // Print 1 line of context
                let prev_is_change = line_index > 0 && is_change(&changes[line_index - 1]);
                let next_is_change = changes.get(line_index + 1).map_or(false, is_change);
                if prev_is_change || next_is_change {
                    format!("| {}", context).dimmed()
                } else {
                    continue;
                }
            }
            Left(removed) => format!("- {}", removed).red(),
            Right(added) => format!("+ {}", added).green(),
        };
        println!("{:4} {}", line_index + 1, formatted_line);
    }
}

fn is_change<T>(result: &diff::Result<T>) -> bool {
    matches!(result, Left(_) | Right(_))
}
<|endoftext|>


<commit_before>//! Removes assignments to ZST places.

use crate::transform::MirPass;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{Body, LocalDecls, Place, StatementKind};
use rustc_middle::ty::{self, Ty, TyCtxt};

pub struct RemoveZsts;

impl<'tcx> MirPass<'tcx> for RemoveZsts {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
        if tcx.sess.mir_opt_level() < 3 {
            return;
        }
        let param_env = tcx.param_env(body.source.def_id());
        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
        for block in basic_blocks.iter_mut() {
            for statement in block.statements.iter_mut() {
                match statement.kind {
                    StatementKind::Assign(box (place, _)) => {
                        let place_ty = place.ty(local_decls, tcx).ty;
                        if !maybe_zst(place_ty) {
                            continue;
                        }
                        let layout = match tcx.layout_of(param_env.and(place_ty)) {
                            Ok(layout) => layout,
                            Err(_) => continue,
                        };
                        if !layout.is_zst() {
                            continue;
                        }
                        if involves_a_union(place, local_decls, tcx) {
                            continue;
                        }
                        if tcx.consider_optimizing(|| {
                            format!(
                                "RemoveZsts - Place: {:?} SourceInfo: {:?}",
                                place, statement.source_info
                            )
                        }) {
                            statement.make_nop();
                        }
                    }
                    _ => {}
                }
            }
        }
    }
}

/// A cheap, approximate check to avoid unnecessary `layout_of` calls.
fn maybe_zst(ty: Ty<'_>) -> bool {
    match ty.kind() {
        // maybe ZST (could be more precise)
        ty::Adt(..) | ty::Array(..) | ty::Closure(..) | ty::Tuple(..) | ty::Opaque(..) => true,
        // definitely ZST
        ty::FnDef(..) | ty::Never => true,
        // unreachable or can't be ZST
        _ => false,
    }
}

/// Miri lazily allocates memory for locals on assignment,
/// so we must preserve writes to unions and union fields,
/// or it will ICE on reads of those fields.
fn involves_a_union<'tcx>(
    place: Place<'tcx>,
    local_decls: &LocalDecls<'tcx>,
    tcx: TyCtxt<'tcx>,
) -> bool {
    let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty);
    if place_ty.ty.is_union() {
        return true;
    }
    for elem in place.projection {
        place_ty = place_ty.projection_ty(tcx, elem);
        if place_ty.ty.is_union() {
            return true;
        }
    }
    return false;
}
<commit_msg>Replace a `match` with an `if let`<commit_after>//! Removes assignments to ZST places.

use crate::transform::MirPass;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{Body, LocalDecls, Place, StatementKind};
use rustc_middle::ty::{self, Ty, TyCtxt};

pub struct RemoveZsts;

impl<'tcx> MirPass<'tcx> for RemoveZsts {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
        if tcx.sess.mir_opt_level() < 3 {
            return;
        }
        let param_env = tcx.param_env(body.source.def_id());
        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
        for block in basic_blocks.iter_mut() {
            for statement in block.statements.iter_mut() {
                if let StatementKind::Assign(box (place, _)) = statement.kind {
                    let place_ty = place.ty(local_decls, tcx).ty;
                    if !maybe_zst(place_ty) {
                        continue;
                    }
                    let layout = match tcx.layout_of(param_env.and(place_ty)) {
                        Ok(layout) => layout,
                        Err(_) => continue,
                    };
                    if !layout.is_zst() {
                        continue;
                    }
                    if involves_a_union(place, local_decls, tcx) {
                        continue;
                    }
                    if tcx.consider_optimizing(|| {
                        format!(
                            "RemoveZsts - Place: {:?} SourceInfo: {:?}",
                            place, statement.source_info
                        )
                    }) {
                        statement.make_nop();
                    }
                }
            }
        }
    }
}

/// A cheap, approximate check to avoid unnecessary `layout_of` calls.
fn maybe_zst(ty: Ty<'_>) -> bool {
    match ty.kind() {
        // maybe ZST (could be more precise)
        ty::Adt(..) | ty::Array(..) | ty::Closure(..) | ty::Tuple(..) | ty::Opaque(..) => true,
        // definitely ZST
        ty::FnDef(..) | ty::Never => true,
        // unreachable or can't be ZST
        _ => false,
    }
}

/// Miri lazily allocates memory for locals on assignment,
/// so we must preserve writes to unions and union fields,
/// or it will ICE on reads of those fields.
fn involves_a_union<'tcx>(
    place: Place<'tcx>,
    local_decls: &LocalDecls<'tcx>,
    tcx: TyCtxt<'tcx>,
) -> bool {
    let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty);
    if place_ty.ty.is_union() {
        return true;
    }
    for elem in place.projection {
        place_ty = place_ty.projection_ty(tcx, elem);
        if place_ty.ty.is_union() {
            return true;
        }
    }
    return false;
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::prelude::*;
use core::str;
use core::io;

use driver::session::{OptLevel, No, Less, Aggressive};
use driver::session::{Session};
use lib::llvm::{PassRef, ModuleRef,PassManagerRef,TargetDataRef};
use lib::llvm::llvm;
use lib;

pub struct PassManager {
    priv llpm: PassManagerRef
}

impl Drop for PassManager {
    fn finalize(&self) {
        unsafe {
            llvm::LLVMDisposePassManager(self.llpm);
        }
    }
}

impl PassManager {
    pub fn new(td: TargetDataRef) -> PassManager {
        unsafe {
            let pm = PassManager {
                llpm: llvm::LLVMCreatePassManager()
            };
            llvm::LLVMAddTargetData(td, pm.llpm);

            return pm;
        }
    }

    pub fn add_pass(&mut self, pass:PassRef) {
        unsafe {
            llvm::LLVMAddPass(self.llpm, pass);
        }
    }

    pub fn add_pass_from_name(&mut self, name:&str) {
        let pass = create_pass(name).unwrap();
        self.add_pass(pass);
    }

    pub fn run(&self, md:ModuleRef) -> bool {
        unsafe {
            llvm::LLVMRunPassManager(self.llpm, md) == lib::llvm::True
        }
    }
}

pub fn create_standard_passes(level:OptLevel) -> ~[~str] {
    let mut passes = ~[~"strip-dead-prototypes"];

    if level == No {
        passes.push(~"always-inline");
        return passes;
    }

    passes.push(~"targetlibinfo");

    passes.push(~"tbaa");
    passes.push(~"basicaa");

    passes.push(~"early-cse");

    passes.push(~"globalopt");
    passes.push(~"ipsccp");
    passes.push(~"deadargelim");
    passes.push(~"instcombine");
    passes.push(~"simplifycfg");

    passes.push(~"prune-eh");

    if level == Aggressive {
        passes.push(~"mergefunc");
    }

    passes.push(~"inline");

    passes.push(~"functionattrs");

    if level == Aggressive {
        passes.push(~"argpromotion");
    }

    passes.push(~"early-cse");
    passes.push(~"simplify-libcalls");
    passes.push(~"jump-threading");
    passes.push(~"correlated-propagation");
    passes.push(~"simplifycfg");
    passes.push(~"instcombine");

    passes.push(~"tailcallelim");
    passes.push(~"simplifycfg");
    passes.push(~"reassociate");
    passes.push(~"loop-rotate");
    passes.push(~"licm");

    passes.push(~"lcssa");
    passes.push(~"loop-unswitch");

    passes.push(~"instcombine");
    passes.push(~"indvars");
    passes.push(~"loop-idiom");
    passes.push(~"loop-deletion");

    if level == Aggressive {
        passes.push(~"loop-vectorize");
    }

    passes.push(~"loop-unroll");

    if level != Less {
        passes.push(~"gvn");
    }

    passes.push(~"memcpyopt");
    passes.push(~"sccp");

    passes.push(~"instcombine");
    passes.push(~"jump-threading");
    passes.push(~"correlated-propagation");
    passes.push(~"dse");

    passes.push(~"bb-vectorize");
    passes.push(~"instcombine");
    passes.push(~"early-cse");

    passes.push(~"loop-unroll");

    passes.push(~"adce");
    passes.push(~"simplifycfg");
    passes.push(~"instsimplify");

    if level != Less {
        passes.push(~"globaldce");
        passes.push(~"constmerge");
    }

    return passes;
}

pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) {
    for pass_list.each |&nm| {
        match create_pass(nm) {
            Some(p) => pm.add_pass(p),
            None    => sess.warn(fmt!("Unknown pass %s", nm))
        }
    }
}

pub fn create_pass(name:&str) -> Option<PassRef> {
    do str::as_c_str(name) |s| {
        unsafe {
            let p = llvm::LLVMCreatePass(s);
            if p.is_null() {
                None
            } else {
                Some(p)
            }
        }
    }
}

pub fn list_passes() {
    io::println("\nAvailable Passes:");

    io::println("\nAnalysis Passes:");
    for analysis_passes.each |&(name, desc)| {
        io::println(fmt!("    %-30s -- %s", name, desc));
    }
    io::println("\nTransformation Passes:");
    for transform_passes.each |&(name, desc)| {
        io::println(fmt!("    %-30s -- %s", name, desc));
    }
    io::println("\nUtility Passes:");
    for utility_passes.each |&(name, desc)| {
        io::println(fmt!("    %-30s -- %s", name, desc));
    }
}

/** Analysis Passes */
pub static analysis_passes : &'static [(&'static str, &'static str)] = &'static [
    ("aa-eval",                         "Exhausive Alias Analysis Precision Evaluator"),
    ("asan",                            "AddressSanitizer"),
    ("basicaa",                         "Basic Alias Analysis"),
    ("basiccg",                         "Basic CallGraph Construction"),
    ("block-freq",                      "Block Frequency Analysis"),
    ("cost-model",                      "Cost Model Analysis"),
    ("count-aa",                        "Count Alias Analysis Query Responses"),
    ("da",                              "Dependence Analysis"),
    ("debug-aa",                        "AA Use Debugger"),
    ("domfrontier",                     "Dominance Frontier Construction"),
    ("domtree",                         "Dominator Tree Construction"),
    ("globalsmodref-aa",                "Simple mod/ref analysis for globals"),
    ("instcount",                       "Count the various types of Instructions"),
    ("intervals",                       "Interval Partition Construction"),
    ("iv-users",                        "Induction Variable Users"),
    ("lazy-value-info",                 "Lazy Value Information Analysis"),
    ("libcall-aa",                      "LibCall Alias Analysis"),
    ("lint",                            "Statically lint-check LLVM IR"),
    ("loops",                           "Natural Loop Information"),
    ("memdep",                          "Memory Dependence Analysis"),
    ("module-debuginfo",                "Decodes module-level debug info"),
    ("profile-estimator",               "Estimate profiling information"),
    ("profile-loader",                  "Load profile information from llvmprof.out"),
    ("profile-verifier",                "Verify profiling information"),
    ("regions",                         "Detect single entry single exit regions"),
    ("scalar-evolution",                "Scalar Evolution Analysis"),
    ("scev-aa",                         "Scalar Evolution-based Alias Analysis"),
    ("tbaa",                            "Type-Based Alias Analysis"),
    ("tsan",                            "ThreadSanitizer"),
];

/** Transformation Passes */
pub static transform_passes : &'static [(&'static str, &'static str)] = &'static [
    ("adce",                            "Aggressive Dead Code Elimination"),
    ("always-inline",                   "Inliner for #[inline(always)] functions"),
    ("argpromotion",                    "Promote 'by reference' arguments to scalars"),
    ("bb-vectorize",                    "Basic-Block Vectorization"),
    ("block-placement",                 "Profile Guided Basic Block Placement"),
    ("bounds-checking",                 "Run-time bounds checking"),
    ("break-crit-edges",                "Break critical edges in CFG"),
    ("codegenprepare",                  "Optimize for code generation"),
    ("constmerge",                      "Merge Duplicate Global Constants"),
    ("constprop",                       "Simple constant propagation"),
    ("correlated-propagation",          "Value Propagation"),
    ("da",                              "Data Layout"),
    ("dce",                             "Dead Code Elimination"),
    ("deadargelim",                     "Dead Argument Elimination"),
    ("die",                             "Dead Instruction Elimination"),
    ("dse",                             "Dead Store Elimination"),
    ("early-cse",                       "Early CSE"),
    ("functionattrs",                   "Deduce function attributes"),
    ("globaldce",                       "Dead Global Elimination"),
    ("globalopt",                       "Global Variable Optimizer"),
    ("gvn",                             "Global Value Numbering"),
    ("indvars",                         "Canonicalize Induction Variables"),
    ("inline",                          "Function Integration/Inlining"),
    ("insert-edge-profiling",           "Insert instrumentation for edge profiling"),
    ("insert-gcov-profiling",           "Insert instrumentation for GCOV profiling"),
    ("insert-optimal-edge-profiling",   "Insert optimal instrumentation for edge profiling"),
    ("instcombine",                     "Combine redundant instructions"),
    ("instsimplify",                    "Remove redundant instructions"),
    ("ipconstprop",                     "Interprocedural constant propagation"),
    ("ipsccp",                          "Interprocedural Sparse Conditional Constant Propagation"),
    ("jump-threading",                  "Jump Threading"),
    ("lcssa",                           "Loop-Closed SSA Form Pass"),
    ("licm",                            "Loop Invariant Code Motion"),
    ("loop-deletion",                   "Delete dead loops"),
    ("loop-extract",                    "Extract loops into new functions"),
    ("loop-extract-single",             "Extract at most one loop into a new function"),
    ("loop-idiom",                      "Recognise loop idioms"),
    ("loop-instsimplify",               "Simplify instructions in loops"),
    ("loop-reduce",                     "Loop Strength Reduction"),
    ("loop-rotate",                     "Rotate Loops"),
    ("loop-simplify",                   "Canonicalize natural loops"),
    ("loop-unroll",                     "Unroll loops"),
    ("loop-unswitch",                   "Unswitch loops"),
    ("loop-vectorize",                  "Loop Vectorization"),
    ("lower-expect",                    "Lower 'expect' Intrinsics"),
    ("mem2reg",                         "Promote Memory to Register"),
    ("memcpyopt",                       "MemCpy Optimization"),
    ("mergefunc",                       "Merge Functions"),
    ("mergereturn",                     "Unify function exit nodes"),
    ("partial-inliner",                 "Partial Inliner"),
    ("prune-eh",                        "Remove unused exception handling info"),
    ("reassociate",                     "Reassociate expressions"),
    ("reg2mem",                         "Demote all values to stack slots"),
    ("scalarrepl",                      "Scalar Replacement of Aggregates (DT)"),
    ("scalarrepl-ssa",                  "Scalar Replacement of Aggregates (SSAUp)"),
    ("sccp",                            "Sparse Conditional Constant Propagation"),
    ("simplify-libcalls",               "Simplify well-known library calls"),
    ("simplifycfg",                     "Simplify the CFG"),
    ("sink",                            "Code sinking"),
    ("strip",                           "Strip all symbols from a module"),
    ("strip-dead-debug-info",           "Strip debug info for unused symbols"),
    ("strip-dead-prototypes",           "Strip Unused Function Prototypes"),
    ("strip-debug-declare",             "Strip all llvm.dbg.declare intrinsics"),
    ("strip-nondebug",                  "Strip all symbols, except dbg symbols, from a module"),
    ("sroa",                            "Scalar Replacement of Aggregates"),
    ("tailcallelim",                    "Tail Call Elimination"),
];

/** Utility Passes */
static utility_passes : &'static [(&'static str, &'static str)] = &'static [
    ("instnamer",                       "Assign names to anonymous instructions"),
    ("verify",                          "Module Verifier"),
];

#[test]
fn passes_exist() {
    let mut failed = ~[];
    unsafe { llvm::LLVMInitializePasses(); }
    for analysis_passes.each() |&(name,_)| {
        if !create_pass(name).is_some() {
            failed.push(name);
        }
    }
    for transform_passes.each() |&(name,_)| {
        if !create_pass(name).is_some() {
            failed.push(name);
        }
    }
    for utility_passes.each() |&(name,_)| {
        if !create_pass(name).is_some() {
            failed.push(name);
        }
    }

    if failed.len() > 0 {
        io::println("Some passes don't exist:");
        for failed.each |&n| {
            io::println(fmt!("    %s", n));
        }
        fail!();
    }
}
<commit_msg>Remove the slow bb-vectorize pass<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::prelude::*;
use core::str;
use core::io;

use driver::session::{OptLevel, No, Less, Aggressive};
use driver::session::{Session};
use lib::llvm::{PassRef, ModuleRef,PassManagerRef,TargetDataRef};
use lib::llvm::llvm;
use lib;

pub struct PassManager {
    priv llpm: PassManagerRef
}

impl Drop for PassManager {
    fn finalize(&self) {
        unsafe {
            llvm::LLVMDisposePassManager(self.llpm);
        }
    }
}

impl PassManager {
    pub fn new(td: TargetDataRef) -> PassManager {
        unsafe {
            let pm = PassManager {
                llpm: llvm::LLVMCreatePassManager()
            };
            llvm::LLVMAddTargetData(td, pm.llpm);

            return pm;
        }
    }

    pub fn add_pass(&mut self, pass:PassRef) {
        unsafe {
            llvm::LLVMAddPass(self.llpm, pass);
        }
    }

    pub fn add_pass_from_name(&mut self, name:&str) {
        let pass = create_pass(name).unwrap();
        self.add_pass(pass);
    }

    pub fn run(&self, md:ModuleRef) -> bool {
        unsafe {
            llvm::LLVMRunPassManager(self.llpm, md) == lib::llvm::True
        }
    }
}

pub fn create_standard_passes(level:OptLevel) -> ~[~str] {
    let mut passes = ~[~"strip-dead-prototypes"];

    if level == No {
        passes.push(~"always-inline");
        return passes;
    }

    passes.push(~"targetlibinfo");

    passes.push(~"tbaa");
    passes.push(~"basicaa");

    passes.push(~"early-cse");

    passes.push(~"globalopt");
    passes.push(~"ipsccp");
    passes.push(~"deadargelim");
    passes.push(~"instcombine");
    passes.push(~"simplifycfg");

    passes.push(~"prune-eh");

    if level == Aggressive {
        passes.push(~"mergefunc");
    }

    passes.push(~"inline");

    passes.push(~"functionattrs");

    if level == Aggressive {
        passes.push(~"argpromotion");
    }

    passes.push(~"early-cse");
    passes.push(~"simplify-libcalls");
    passes.push(~"jump-threading");
    passes.push(~"correlated-propagation");
    passes.push(~"simplifycfg");
    passes.push(~"instcombine");

    passes.push(~"tailcallelim");
    passes.push(~"simplifycfg");
    passes.push(~"reassociate");
    passes.push(~"loop-rotate");
    passes.push(~"licm");

    passes.push(~"lcssa");
    passes.push(~"loop-unswitch");

    passes.push(~"instcombine");
    passes.push(~"indvars");
    passes.push(~"loop-idiom");
    passes.push(~"loop-deletion");

    if level == Aggressive {
        passes.push(~"loop-vectorize");
    }

    passes.push(~"loop-unroll");

    if level != Less {
        passes.push(~"gvn");
    }

    passes.push(~"memcpyopt");
    passes.push(~"sccp");

    passes.push(~"instcombine");
    passes.push(~"jump-threading");
    passes.push(~"correlated-propagation");
    passes.push(~"dse");

    passes.push(~"instcombine");
    passes.push(~"early-cse");

    passes.push(~"loop-unroll");

    passes.push(~"adce");
    passes.push(~"simplifycfg");
    passes.push(~"instsimplify");

    if level != Less {
        passes.push(~"globaldce");
        passes.push(~"constmerge");
    }

    return passes;
}

pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) {
    for pass_list.each |&nm| {
        match create_pass(nm) {
            Some(p) => pm.add_pass(p),
            None    => sess.warn(fmt!("Unknown pass %s", nm))
        }
    }
}

pub fn create_pass(name:&str) -> Option<PassRef> {
    do str::as_c_str(name) |s| {
        unsafe {
            let p = llvm::LLVMCreatePass(s);
            if p.is_null() {
                None
            } else {
                Some(p)
            }
        }
    }
}

pub fn list_passes() {
    io::println("\nAvailable Passes:");

    io::println("\nAnalysis Passes:");
    for analysis_passes.each |&(name, desc)| {
        io::println(fmt!("    %-30s -- %s", name, desc));
    }
    io::println("\nTransformation Passes:");
    for transform_passes.each |&(name, desc)| {
        io::println(fmt!("    %-30s -- %s", name, desc));
    }
    io::println("\nUtility Passes:");
    for utility_passes.each |&(name, desc)| {
        io::println(fmt!("    %-30s -- %s", name, desc));
    }
}

/** Analysis Passes */
pub static analysis_passes : &'static [(&'static str, &'static str)] = &'static [
    ("aa-eval",                         "Exhausive Alias Analysis Precision Evaluator"),
    ("asan",                            "AddressSanitizer"),
    ("basicaa",                         "Basic Alias Analysis"),
    ("basiccg",                         "Basic CallGraph Construction"),
    ("block-freq",                      "Block Frequency Analysis"),
    ("cost-model",                      "Cost Model Analysis"),
    ("count-aa",                        "Count Alias Analysis Query Responses"),
    ("da",                              "Dependence Analysis"),
    ("debug-aa",                        "AA Use Debugger"),
    ("domfrontier",                     "Dominance Frontier Construction"),
    ("domtree",                         "Dominator Tree Construction"),
    ("globalsmodref-aa",                "Simple mod/ref analysis for globals"),
    ("instcount",                       "Count the various types of Instructions"),
    ("intervals",                       "Interval Partition Construction"),
    ("iv-users",                        "Induction Variable Users"),
    ("lazy-value-info",                 "Lazy Value Information Analysis"),
    ("libcall-aa",                      "LibCall Alias Analysis"),
    ("lint",                            "Statically lint-check LLVM IR"),
    ("loops",                           "Natural Loop Information"),
    ("memdep",                          "Memory Dependence Analysis"),
    ("module-debuginfo",                "Decodes module-level debug info"),
    ("profile-estimator",               "Estimate profiling information"),
    ("profile-loader",                  "Load profile information from llvmprof.out"),
    ("profile-verifier",                "Verify profiling information"),
    ("regions",                         "Detect single entry single exit regions"),
    ("scalar-evolution",                "Scalar Evolution Analysis"),
    ("scev-aa",                         "Scalar Evolution-based Alias Analysis"),
    ("tbaa",                            "Type-Based Alias Analysis"),
    ("tsan",                            "ThreadSanitizer"),
];

/** Transformation Passes */
pub static transform_passes : &'static [(&'static str, &'static str)] = &'static [
    ("adce",                            "Aggressive Dead Code Elimination"),
    ("always-inline",                   "Inliner for #[inline(always)] functions"),
    ("argpromotion",                    "Promote 'by reference' arguments to scalars"),
    ("bb-vectorize",                    "Basic-Block Vectorization"),
    ("block-placement",                 "Profile Guided Basic Block Placement"),
    ("bounds-checking",                 "Run-time bounds checking"),
    ("break-crit-edges",                "Break critical edges in CFG"),
    ("codegenprepare",                  "Optimize for code generation"),
    ("constmerge",                      "Merge Duplicate Global Constants"),
    ("constprop",                       "Simple constant propagation"),
    ("correlated-propagation",          "Value Propagation"),
    ("da",                              "Data Layout"),
    ("dce",                             "Dead Code Elimination"),
    ("deadargelim",                     "Dead Argument Elimination"),
    ("die",                             "Dead Instruction Elimination"),
    ("dse",                             "Dead Store Elimination"),
    ("early-cse",                       "Early CSE"),
    ("functionattrs",                   "Deduce function attributes"),
    ("globaldce",                       "Dead Global Elimination"),
    ("globalopt",                       "Global Variable Optimizer"),
    ("gvn",                             "Global Value Numbering"),
    ("indvars",                         "Canonicalize Induction Variables"),
    ("inline",                          "Function Integration/Inlining"),
    ("insert-edge-profiling",           "Insert instrumentation for edge profiling"),
    ("insert-gcov-profiling",           "Insert instrumentation for GCOV profiling"),
    ("insert-optimal-edge-profiling",   "Insert optimal instrumentation for edge profiling"),
    ("instcombine",                     "Combine redundant instructions"),
    ("instsimplify",                    "Remove redundant instructions"),
    ("ipconstprop",                     "Interprocedural constant propagation"),
    ("ipsccp",                          "Interprocedural Sparse Conditional Constant Propagation"),
    ("jump-threading",                  "Jump Threading"),
    ("lcssa",                           "Loop-Closed SSA Form Pass"),
    ("licm",                            "Loop Invariant Code Motion"),
    ("loop-deletion",                   "Delete dead loops"),
    ("loop-extract",                    "Extract loops into new functions"),
    ("loop-extract-single",             "Extract at most one loop into a new function"),
    ("loop-idiom",                      "Recognise loop idioms"),
    ("loop-instsimplify",               "Simplify instructions in loops"),
    ("loop-reduce",                     "Loop Strength Reduction"),
    ("loop-rotate",                     "Rotate Loops"),
    ("loop-simplify",                   "Canonicalize natural loops"),
    ("loop-unroll",                     "Unroll loops"),
    ("loop-unswitch",                   "Unswitch loops"),
    ("loop-vectorize",                  "Loop Vectorization"),
    ("lower-expect",                    "Lower 'expect' Intrinsics"),
    ("mem2reg",                         "Promote Memory to Register"),
    ("memcpyopt",                       "MemCpy Optimization"),
    ("mergefunc",                       "Merge Functions"),
    ("mergereturn",                     "Unify function exit nodes"),
    ("partial-inliner",                 "Partial Inliner"),
    ("prune-eh",                        "Remove unused exception handling info"),
    ("reassociate",                     "Reassociate expressions"),
    ("reg2mem",                         "Demote all values to stack slots"),
    ("scalarrepl",                      "Scalar Replacement of Aggregates (DT)"),
    ("scalarrepl-ssa",                  "Scalar Replacement of Aggregates (SSAUp)"),
    ("sccp",                            "Sparse Conditional Constant Propagation"),
    ("simplify-libcalls",               "Simplify well-known library calls"),
    ("simplifycfg",                     "Simplify the CFG"),
    ("sink",                            "Code sinking"),
    ("strip",                           "Strip all symbols from a module"),
    ("strip-dead-debug-info",           "Strip debug info for unused symbols"),
    ("strip-dead-prototypes",           "Strip Unused Function Prototypes"),
    ("strip-debug-declare",             "Strip all llvm.dbg.declare intrinsics"),
    ("strip-nondebug",                  "Strip all symbols, except dbg symbols, from a module"),
    ("sroa",                            "Scalar Replacement of Aggregates"),
    ("tailcallelim",                    "Tail Call Elimination"),
];

/** Utility Passes */
static utility_passes : &'static [(&'static str, &'static str)] = &'static [
    ("instnamer",                       "Assign names to anonymous instructions"),
    ("verify",                          "Module Verifier"),
];

#[test]
fn passes_exist() {
    let mut failed = ~[];
    unsafe { llvm::LLVMInitializePasses(); }
    for analysis_passes.each() |&(name,_)| {
        if !create_pass(name).is_some() {
            failed.push(name);
        }
    }
    for transform_passes.each() |&(name,_)| {
        if !create_pass(name).is_some() {
            failed.push(name);
        }
    }
    for utility_passes.each() |&(name,_)| {
        if !create_pass(name).is_some() {
            failed.push(name);
        }
    }

    if failed.len() > 0 {
        io::println("Some passes don't exist:");
        for failed.each |&n| {
            io::println(fmt!("    %s", n));
        }
        fail!();
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0001: r##"
This error suggests that the expression arm corresponding to the noted pattern
will never be reached as for all possible values of the expression being
matched, one of the preceding patterns will match.

This means that perhaps some of the preceding patterns are too general, this one
is too specific or the ordering is incorrect.
"##,

E0002: r##"
This error indicates that an empty match expression is illegal because the type
it is matching on is non-empty (there exist values of this type). In safe code
it is impossible to create an instance of an empty type, so empty match
expressions are almost never desired.  This error is typically fixed by adding
one or more cases to the match expression.

An example of an empty type is `enum Empty { }`.
"##,

E0003: r##"
Not-a-Number (NaN) values cannot be compared for equality and hence can never
match the input to a match expression. To match against NaN values, you should
instead use the `is_nan` method in a guard, as in: x if x.is_nan() => ...
"##,

E0004: r##"
This error indicates that the compiler cannot guarantee a matching pattern for
one or more possible inputs to a match expression. Guaranteed matches are
required in order to assign values to match expressions, or alternatively,
determine the flow of execution.

If you encounter this error you must alter your patterns so that every possible
value of the input type is matched. For types with a small number of variants
(like enums) you should probably cover all cases explicitly. Alternatively, the
underscore `_` wildcard pattern can be added after all other patterns to match
"anything else".
"##,

// FIXME: Remove duplication here?
E0005: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee
that a name will be extracted in all cases. If you encounter this error you
probably need to use a `match` or `if let` to deal with the possibility of
failure.
"##,

E0006: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee
that a name will be extracted in all cases. If you encounter this error you
probably need to use a `match` or `if let` to deal with the possibility of
failure.
"##,

E0007: r##"
This error indicates that the bindings in a match arm would require a value to
be moved into more than one location, thus violating unique ownership. Code like
the following is invalid as it requires the entire Option<String> to be moved
into a variable called `op_string` while simultaneously requiring the inner
String to be moved into a variable called `s`.

let x = Some("s".to_string());
match x {
    op_string @ Some(s) => ...
    None => ...
}

See also Error 303.
"##,

E0008: r##"
Names bound in match arms retain their type in pattern guards. As such, if a
name is bound by move in a pattern, it should also be moved to wherever it is
referenced in the pattern guard code. Doing so however would prevent the name
from being available in the body of the match arm. Consider the following:

match Some("hi".to_string()) {
    Some(s) if s.len() == 0 => // use s.
    ...
}

The variable `s` has type String, and its use in the guard is as a variable of
type String. The guard code effectively executes in a separate scope to the body
of the arm, so the value would be moved into this anonymous scope and therefore
become unavailable in the body of the arm. Although this example seems
innocuous, the problem is most clear when considering functions that take their
argument by value.

match Some("hi".to_string()) {
    Some(s) if { drop(s); false } => (),
    Some(s) => // use s.
    ...
}

The value would be dropped in the guard then become unavailable not only in the
body of that arm but also in all subsequent arms! The solution is to bind by
reference when using guards or refactor the entire expression, perhaps by
putting the condition inside the body of the arm.
"##,

E0152: r##"
Lang items are already implemented in the standard library. Unless you are
writing a free-standing application (e.g. a kernel), you do not need to provide
them yourself.

You can build a free-standing crate by adding `#![no_std]` to the crate
attributes:

#![feature(no_std)]
#![no_std]

See also https://doc.rust-lang.org/book/no-stdlib.html
"##,

E0158: r##"
`const` and `static` mean different things. A `const` is a compile-time
constant, an alias for a literal value. This property means you can match it
directly within a pattern.

The `static` keyword, on the other hand, guarantees a fixed location in memory.
This does not always mean that the value is constant. For example, a global
mutex can be declared `static` as well.

If you want to match against a `static`, consider using a guard instead:

static FORTY_TWO: i32 = 42;
match Some(42) {
    Some(x) if x == FORTY_TWO => ...
    ...
}
"##,

E0161: r##"
In Rust, you can only move a value when its size is known at compile time.

To work around this restriction, consider "hiding" the value behind a reference:
either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
it around as usual.
"##,

E0162: r##"
An if-let pattern attempts to match the pattern, and enters the body if the
match was succesful. If the match is irrefutable (when it cannot fail to match),
use a regular `let`-binding instead. For instance:

struct Irrefutable(i32);
let irr = Irrefutable(0);

// This fails to compile because the match is irrefutable.
if let Irrefutable(x) = irr {
    // This body will always be executed.
    foo(x);
}

// Try this instead:
let Irrefutable(x) = irr;
foo(x);
"##,

E0165: r##"
A while-let pattern attempts to match the pattern, and enters the body if the
match was succesful. If the match is irrefutable (when it cannot fail to match),
use a regular `let`-binding inside a `loop` instead. For instance:

struct Irrefutable(i32);
let irr = Irrefutable(0);

// This fails to compile because the match is irrefutable.
while let Irrefutable(x) = irr {
    ...
}

// Try this instead:
loop {
    let Irrefutable(x) = irr;
    ...
}
"##,

E0170: r##"
Enum variants are qualified by default. For example, given this type:

enum Method {
    GET,
    POST
}

you would match it using:

match m {
    Method::GET => ...
    Method::POST => ...
}

If you don't qualify the names, the code will bind new variables named "GET" and
"POST" instead. This behavior is likely not what you want, so rustc warns when
that happens.

Qualified names are good practice, and most code works well with them. But if
you prefer them unqualified, you can import the variants into scope:

use Method::*;
enum Method { GET, POST }
"##,

E0267: r##"
This error indicates the use of loop keyword (break or continue) inside a
closure but outside of any loop. Break and continue can be used as normal
inside closures as long as they are also contained within a loop. To halt the
execution of a closure you should instead use a return statement.
"##,

E0268: r##"
This error indicates the use of loop keyword (break or continue) outside of a
loop. Without a loop to break out of or continue in, no sensible action can be
taken.
"##,

E0296: r##"
This error indicates that the given recursion limit could not be parsed. Ensure
that the value provided is a positive integer between quotes, like so:

#![recursion_limit="1000"]
"##,

E0297: r##"
Patterns used to bind names must be irrefutable. That is, they must guarantee
that a name will be extracted in all cases. Instead of pattern matching the
loop variable, consider using a `match` or `if let` inside the loop body. For
instance:

// This fails because `None` is not covered.
for Some(x) in xs {
    ...
}

// Match inside the loop instead:
for item in xs {
    match item {
        Some(x) => ...
        None => ...
    }
}

// Or use `if let`:
for item in xs {
    if let Some(x) = item {
        ...
    }
}
"##,

E0301: r##"
Mutable borrows are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if mutable
borrows were allowed:

match Some(()) {
    None => { },
    option if option.take().is_none() => { /* impossible, option is `Some` */ },
    Some(_) => { } // When the previous match failed, the option became `None`.
}
"##,

E0302: r##"
Assignments are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if assignments
were allowed:

match Some(()) {
    None => { },
    option if { option = None; false } { },
    Some(_) => { } // When the previous match failed, the option became `None`.
}
"##,

E0303: r##"
In certain cases it is possible for sub-bindings to violate memory safety.
Updates to the borrow checker in a future version of Rust may remove this
restriction, but for now patterns must be rewritten without sub-bindings.

// Before.
match Some("hi".to_string()) {
    ref op_string_ref @ Some(ref s) => ...
    None => ...
}

// After.
match Some("hi".to_string()) {
    Some(ref s) => {
        let op_string_ref = &Some(&s);
        ...
    }
    None => ...
}

The `op_string_ref` binding has type &Option<&String> in both cases.

See also https://github.com/rust-lang/rust/issues/14587
"##,

E0306: r##"
In an array literal `[x; N]`, `N` is the number of elements in the array. This
number cannot be negative.
"##,

E0307: r##"
The length of an array is part of its type. For this reason, this length must be
a compile-time constant.
"##

}

register_diagnostics! {
    E0009,
    E0010,
    E0011,
    E0012,
    E0013,
    E0014,
    E0015,
    E0016,
    E0017,
    E0018,
    E0019,
    E0020,
    E0022,
    E0079, // enum variant: expected signed integer constant
    E0080, // enum variant: constant evaluation error
    E0109,
    E0110,
    E0133,
    E0134,
    E0135,
    E0136,
    E0137,
    E0138,
    E0139,
    E0261, // use of undeclared lifetime name
    E0262, // illegal lifetime parameter name
    E0263, // lifetime name declared twice in same scope
    E0264, // unknown external lang item
    E0265, // recursive constant
    E0266, // expected item
    E0269, // not all control paths return a value
    E0270, // computation may converge in a function marked as diverging
    E0271, // type mismatch resolving
    E0272, // rustc_on_unimplemented attribute refers to non-existent type parameter
    E0273, // rustc_on_unimplemented must have named format arguments
    E0274, // rustc_on_unimplemented must have a value
    E0275, // overflow evaluating requirement
    E0276, // requirement appears on impl method but not on corresponding trait method
    E0277, // trait is not implemented for type
    E0278, // requirement is not satisfied
    E0279, // requirement is not satisfied
    E0280, // requirement is not satisfied
    E0281, // type implements trait but other trait is required
    E0282, // unable to infer enough type information about
    E0283, // cannot resolve type
    E0284, // cannot resolve type
    E0285, // overflow evaluation builtin bounds
    E0298, // mismatched types between arms
    E0299, // mismatched types between arms
    E0300, // unexpanded macro
    E0304, // expected signed integer constant
    E0305, // expected constant
    E0308,
    E0309, // thing may not live long enough
    E0310, // thing may not live long enough
    E0311, // thing may not live long enough
    E0312, // lifetime of reference outlives lifetime of borrowed content
    E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
    E0314, // closure outlives stack frame
    E0315, // cannot invoke closure outside of its lifetime
    E0316, // nested quantification of lifetimes
    E0370  // discriminant overflow
}

__build_diagnostic_array! { DIAGNOSTICS }
<commit_msg>Add long diagnostics for E0020<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0001: r##"
This error suggests that the expression arm corresponding to the noted pattern
will never be reached as for all possible values of the expression being
matched, one of the preceding patterns will match.

This means that perhaps some of the preceding patterns are too general, this one
is too specific or the ordering is incorrect.
"##,

E0002: r##"
This error indicates that an empty match expression is illegal because the type
it is matching on is non-empty (there exist values of this type). In safe code
it is impossible to create an instance of an empty type, so empty match
expressions are almost never desired.  This error is typically fixed by adding
one or more cases to the match expression.

An example of an empty type is `enum Empty { }`.
"##,

E0003: r##"
Not-a-Number (NaN) values cannot be compared for equality and hence can never
match the input to a match expression. To match against NaN values, you should
instead use the `is_nan` method in a guard, as in: x if x.is_nan() => ...
"##,

E0004: r##"
This error indicates that the compiler cannot guarantee a matching pattern for
one or more possible inputs to a match expression. Guaranteed matches are
required in order to assign values to match expressions, or alternatively,
determine the flow of execution.

If you encounter this error you must alter your patterns so that every possible
value of the input type is matched. For types with a small number of variants
(like enums) you should probably cover all cases explicitly. Alternatively, the
underscore `_` wildcard pattern can be added after all other patterns to match
"anything else".
"##,

// FIXME: Remove duplication here?
E0005: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee
that a name will be extracted in all cases. If you encounter this error you
probably need to use a `match` or `if let` to deal with the possibility of
failure.
"##,

E0006: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee
that a name will be extracted in all cases. If you encounter this error you
probably need to use a `match` or `if let` to deal with the possibility of
failure.
"##,

E0007: r##"
This error indicates that the bindings in a match arm would require a value to
be moved into more than one location, thus violating unique ownership. Code like
the following is invalid as it requires the entire Option<String> to be moved
into a variable called `op_string` while simultaneously requiring the inner
String to be moved into a variable called `s`.

let x = Some("s".to_string());
match x {
    op_string @ Some(s) => ...
    None => ...
}

See also Error 303.
"##,

E0008: r##"
Names bound in match arms retain their type in pattern guards. As such, if a
name is bound by move in a pattern, it should also be moved to wherever it is
referenced in the pattern guard code. Doing so however would prevent the name
from being available in the body of the match arm. Consider the following:

match Some("hi".to_string()) {
    Some(s) if s.len() == 0 => // use s.
    ...
}

The variable `s` has type String, and its use in the guard is as a variable of
type String. The guard code effectively executes in a separate scope to the body
of the arm, so the value would be moved into this anonymous scope and therefore
become unavailable in the body of the arm. Although this example seems
innocuous, the problem is most clear when considering functions that take their
argument by value.

match Some("hi".to_string()) {
    Some(s) if { drop(s); false } => (),
    Some(s) => // use s.
    ...
}

The value would be dropped in the guard then become unavailable not only in the
body of that arm but also in all subsequent arms! The solution is to bind by
reference when using guards or refactor the entire expression, perhaps by
putting the condition inside the body of the arm.
"##,

E0020: r##"
This error indicates that an attempt was made to divide by zero (or take the
remainder of a zero divisor) in a static or constant expression.
"##,

E0152: r##"
Lang items are already implemented in the standard library. Unless you are
writing a free-standing application (e.g. a kernel), you do not need to provide
them yourself.

You can build a free-standing crate by adding `#![no_std]` to the crate
attributes:

#![feature(no_std)]
#![no_std]

See also https://doc.rust-lang.org/book/no-stdlib.html
"##,

E0158: r##"
`const` and `static` mean different things. A `const` is a compile-time
constant, an alias for a literal value. This property means you can match it
directly within a pattern.

The `static` keyword, on the other hand, guarantees a fixed location in memory.
This does not always mean that the value is constant. For example, a global
mutex can be declared `static` as well.

If you want to match against a `static`, consider using a guard instead:

static FORTY_TWO: i32 = 42;
match Some(42) {
    Some(x) if x == FORTY_TWO => ...
    ...
}
"##,

E0161: r##"
In Rust, you can only move a value when its size is known at compile time.

To work around this restriction, consider "hiding" the value behind a reference:
either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
it around as usual.
"##,

E0162: r##"
An if-let pattern attempts to match the pattern, and enters the body if the
match was succesful. If the match is irrefutable (when it cannot fail to match),
use a regular `let`-binding instead. For instance:

struct Irrefutable(i32);
let irr = Irrefutable(0);

// This fails to compile because the match is irrefutable.
if let Irrefutable(x) = irr {
    // This body will always be executed.
    foo(x);
}

// Try this instead:
let Irrefutable(x) = irr;
foo(x);
"##,

E0165: r##"
A while-let pattern attempts to match the pattern, and enters the body if the
match was succesful. If the match is irrefutable (when it cannot fail to match),
use a regular `let`-binding inside a `loop` instead. For instance:

struct Irrefutable(i32);
let irr = Irrefutable(0);

// This fails to compile because the match is irrefutable.
while let Irrefutable(x) = irr {
    ...
}

// Try this instead:
loop {
    let Irrefutable(x) = irr;
    ...
}
"##,

E0170: r##"
Enum variants are qualified by default. For example, given this type:

enum Method {
    GET,
    POST
}

you would match it using:

match m {
    Method::GET => ...
    Method::POST => ...
}

If you don't qualify the names, the code will bind new variables named "GET" and
"POST" instead. This behavior is likely not what you want, so rustc warns when
that happens.

Qualified names are good practice, and most code works well with them. But if
you prefer them unqualified, you can import the variants into scope:

use Method::*;
enum Method { GET, POST }
"##,

E0267: r##"
This error indicates the use of loop keyword (break or continue) inside a
closure but outside of any loop. Break and continue can be used as normal
inside closures as long as they are also contained within a loop. To halt the
execution of a closure you should instead use a return statement.
"##,

E0268: r##"
This error indicates the use of loop keyword (break or continue) outside of a
loop. Without a loop to break out of or continue in, no sensible action can be
taken.
"##,

E0296: r##"
This error indicates that the given recursion limit could not be parsed. Ensure
that the value provided is a positive integer between quotes, like so:

#![recursion_limit="1000"]
"##,

E0297: r##"
Patterns used to bind names must be irrefutable. That is, they must guarantee
that a name will be extracted in all cases. Instead of pattern matching the
loop variable, consider using a `match` or `if let` inside the loop body. For
instance:

// This fails because `None` is not covered.
for Some(x) in xs {
    ...
}

// Match inside the loop instead:
for item in xs {
    match item {
        Some(x) => ...
        None => ...
    }
}

// Or use `if let`:
for item in xs {
    if let Some(x) = item {
        ...
    }
}
"##,

E0301: r##"
Mutable borrows are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if mutable
borrows were allowed:

match Some(()) {
    None => { },
    option if option.take().is_none() => { /* impossible, option is `Some` */ },
    Some(_) => { } // When the previous match failed, the option became `None`.
}
"##,

E0302: r##"
Assignments are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if assignments
were allowed:

match Some(()) {
    None => { },
    option if { option = None; false } { },
    Some(_) => { } // When the previous match failed, the option became `None`.
}
"##,

E0303: r##"
In certain cases it is possible for sub-bindings to violate memory safety.
Updates to the borrow checker in a future version of Rust may remove this
restriction, but for now patterns must be rewritten without sub-bindings.

// Before.
match Some("hi".to_string()) {
    ref op_string_ref @ Some(ref s) => ...
    None => ...
}

// After.
match Some("hi".to_string()) {
    Some(ref s) => {
        let op_string_ref = &Some(&s);
        ...
    }
    None => ...
}

The `op_string_ref` binding has type &Option<&String> in both cases.

See also https://github.com/rust-lang/rust/issues/14587
"##,

E0306: r##"
In an array literal `[x; N]`, `N` is the number of elements in the array. This
number cannot be negative.
"##,

E0307: r##"
The length of an array is part of its type. For this reason, this length must be
a compile-time constant.
"##

}

register_diagnostics! {
    E0009,
    E0010,
    E0011,
    E0012,
    E0013,
    E0014,
    E0015,
    E0016,
    E0017,
    E0018,
    E0019,
    E0022,
    E0079, // enum variant: expected signed integer constant
    E0080, // enum variant: constant evaluation error
    E0109,
    E0110,
    E0133,
    E0134,
    E0135,
    E0136,
    E0137,
    E0138,
    E0139,
    E0261, // use of undeclared lifetime name
    E0262, // illegal lifetime parameter name
    E0263, // lifetime name declared twice in same scope
    E0264, // unknown external lang item
    E0265, // recursive constant
    E0266, // expected item
    E0269, // not all control paths return a value
    E0270, // computation may converge in a function marked as diverging
    E0271, // type mismatch resolving
    E0272, // rustc_on_unimplemented attribute refers to non-existent type parameter
    E0273, // rustc_on_unimplemented must have named format arguments
    E0274, // rustc_on_unimplemented must have a value
    E0275, // overflow evaluating requirement
    E0276, // requirement appears on impl method but not on corresponding trait method
    E0277, // trait is not implemented for type
    E0278, // requirement is not satisfied
    E0279, // requirement is not satisfied
    E0280, // requirement is not satisfied
    E0281, // type implements trait but other trait is required
    E0282, // unable to infer enough type information about
    E0283, // cannot resolve type
    E0284, // cannot resolve type
    E0285, // overflow evaluation builtin bounds
    E0298, // mismatched types between arms
    E0299, // mismatched types between arms
    E0300, // unexpanded macro
    E0304, // expected signed integer constant
    E0305, // expected constant
    E0308,
    E0309, // thing may not live long enough
    E0310, // thing may not live long enough
    E0311, // thing may not live long enough
    E0312, // lifetime of reference outlives lifetime of borrowed content
    E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
    E0314, // closure outlives stack frame
    E0315, // cannot invoke closure outside of its lifetime
    E0316, // nested quantification of lifetimes
    E0370  // discriminant overflow
}

__build_diagnostic_array! { DIAGNOSTICS }
<|endoftext|>


<commit_before>/* kernel::sgash.rs */
#[allow(unused_imports)];
use core::*;
use core::str::*;
use core::option::{Some, Option, None};
use core::iter::Iterator;
use kernel::*;
use kernel::cstr::cstr;
use super::super::platform::*;
use kernel::memory::Allocator;

static PROMPT_COLOR: u32 = 0xFFAF00;
static mut count: uint = 0;

static mut buffer: cstr = cstr {
    p: 0 as *mut u8,
    p_cstr_i: 0,
    size: 0,
};

/* Thanks to https://github.com/jvns/puddle/blob/master/src/stdio.rs */
pub fn putnum(x: uint, max: uint) {
    let mut i = max;
    if i == 0 {
        i = 1000000;
    }
    while(i > 0) {
        // Get the offset from each decimal point up to a certain value
        putchar(((((x / i) % 10) as u8) + ('0' as u8)) as char);
        i /= 10;
    }
    putchar(' ');
}

pub fn putkeycode(x: u8) {
    putnum(x as uint, 100);
}

pub fn putchar(key: char) {
    unsafe {
        /*
        * We need to include a blank asm call to prevent rustc
        * from optimizing this part out
        */
        asm!("");
        io::write_char(key, io::UART0);
    }
}

pub fn putstr(msg: &str) {
    for c in slice::iter(as_bytes(msg)) {
        putchar(*c as char);
    }
}

pub unsafe fn drawstr(msg: &str) {
    for c in slice::iter(as_bytes(msg)) {
        drawchar(*c as char);
    }
}

unsafe fn drawchar(x: char) {
    io::restore();
    if x == '\n' {
        io::CURSOR_Y += io::CURSOR_HEIGHT;
        io::CURSOR_X = 0u32;
    } else {
        io::draw_char(x);
        io::CURSOR_X += io::CURSOR_WIDTH;
    }
    io::backup();
    io::draw_cursor();
}

unsafe fn backspace() {
    io::restore();
    if (io::CURSOR_X >= io::CURSOR_WIDTH) {
        io::CURSOR_X -= io::CURSOR_WIDTH;
        io::draw_char(' ');
    }
    io::backup();
    io::draw_cursor();
}

pub unsafe fn parsekey(x: char) {
    let x = x as u8;
    // Set this to false to learn the keycodes of various keys!
    // Key codes are printed backwards because life is hard

    match x {
        13      =>  {
            putstr(&"\n");
            drawstr(&"\n");
            buffer.send_at_c(putchar);
            buffer.send_at_c(drawchar);
            putstr(&"\n");
            drawstr(&"\n");
            buffer.send_at(putkeycode);
            putstr(&" | ");
            prompt();
            buffer.reset();
        }
        127     =>  {
            putchar('');
            putchar(' ');
            putchar('');
            backspace();
        }
        _       =>  {
            buffer.add_u8(x);
            if io::CURSOR_X < io::SCREEN_WIDTH-io::CURSOR_WIDTH {
                putchar(x as char);
                drawchar(x as char);
            }
        }
    }
}

pub unsafe fn screen() {
    putstr(&"\n                                                               ");
    putstr(&"\n                                                               ");
    putstr(&"\n                       7=..~$=..:7                             ");
    putstr(&"\n                  +$: =$$$+$$$?$$$+ ,7?                        ");
    putstr(&"\n                  $$$$$$$$$$$$$$$$$$Z$$                        ");
    putstr(&"\n              7$$$$$$$$$$$$. .Z$$$$$Z$$$$$$                    ");
    putstr(&"\n           ~..7$$Z$$$$$7+7$+.?Z7=7$$Z$$Z$$$..:                 ");
    putstr(&"\n          ~$$$$$$$$7:     :ZZZ,     :7ZZZZ$$$$=                ");
    putstr(&"\n           Z$$$$$?                    .+ZZZZ$$                 ");
    putstr(&"\n       +$ZZ$$$Z7                         7ZZZ$Z$$I.            ");
    putstr(&"\n        $$$$ZZZZZZZZZZZZZZZZZZZZZZZZI,    ,ZZZ$$Z              ");
    putstr(&"\n      :+$$$$ZZZZZZZZZZZZZZZZZZZZZZZZZZZ=    $ZZ$$+~,           ");
    putstr(&"\n     ?$Z$$$$ZZZZZZZZZZZZZZZZZZZZZZZZZZZZI   7ZZZ$ZZI           ");
    putstr(&"\n      =Z$$+7Z$$7ZZZZZZZZ$$$$$$$ZZZZZZZZZZ  ~Z$?$ZZ?            ");
    putstr(&"\n    :$Z$Z...$Z  $ZZZZZZZ~       ~ZZZZZZZZ,.ZZ...Z$Z$~          ");
    putstr(&"\n    7ZZZZZI$ZZ  $ZZZZZZZ~       =ZZZZZZZ7..ZZ$?$ZZZZ$          ");
    putstr(&"\n      ZZZZ$:    $ZZZZZZZZZZZZZZZZZZZZZZ=     ~$ZZZ$:           ");
    putstr(&"\n    7Z$ZZ$,     $ZZZZZZZZZZZZZZZZZZZZ7         ZZZ$Z$          ");
    putstr(&"\n   =ZZZZZZ,     $ZZZZZZZZZZZZZZZZZZZZZZ,       ZZZ$ZZ+         ");
    putstr(&"\n     ,ZZZZ,     $ZZZZZZZ:     =ZZZZZZZZZ     ZZZZZ$:           ");
    putstr(&"\n    =$ZZZZ+     ZZZZZZZZ~       ZZZZZZZZ~   =ZZZZZZZI          ");
    putstr(&"\n    $ZZ$ZZZ$$Z$$ZZZZZZZZZ$$$$   IZZZZZZZZZ$ZZZZZZZZZ$          ");
    putstr(&"\n      :ZZZZZZZZZZZZZZZZZZZZZZ   ~ZZZZZZZZZZZZZZZZZ~            ");
    putstr(&"\n     ,Z$$ZZZZZZZZZZZZZZZZZZZZ    ZZZZZZZZZZZZZZZZZZ~           ");
    putstr(&"\n     =$ZZZZZZZZZZZZZZZZZZZZZZ     $ZZZZZZZZZZZZZZZ$+           ");
    putstr(&"\n        IZZZZZ:.                        . ,ZZZZZ$              ");
    putstr(&"\n       ~$ZZZZZZZZZZZ                 ZZZZ$ZZZZZZZ+             ");
    putstr(&"\n           Z$ZZZ. ,Z~               =Z:.,ZZZ$Z                 ");
    putstr(&"\n          ,ZZZZZ..~Z$.             .7Z:..ZZZZZ:                ");
    putstr(&"\n          ~7+:$ZZZZZZZZI=:.   .,=IZZZZZZZ$Z:=7=                ");
    putstr(&"\n              $$ZZZZZZZZZZZZZZZZZZZZZZ$ZZZZ                    ");
    putstr(&"\n              ==..$ZZZ$ZZZZZZZZZZZ$ZZZZ .~+                    ");
    putstr(&"\n                  I$?.?ZZZ$ZZZ$ZZZI =$7                        ");
    putstr(&"\n                       $7..I$7..I$,                            ");
    putstr(&"\n");
    putstr(&"\n _                     _     _                         _  ");
    putstr(&"\n| |                   (_)   | |                       | | ");
    putstr(&"\n| | ____ ___  ____     _____| |_____  ____ ____  _____| | ");
    putstr(&"\n| |/ ___) _ \\|  _ \\   |  _   _) ___ |/ ___)  _ \\| ___ | | ");
    putstr(&"\n| | |  | |_| | | | |  | |  \\ \\| ____| |   | | | | ____| | ");
    putstr(&"\n|_|_|  \\____/|_| |_|  |_|   \\_\\_____)_|   |_| |_|_____)__)\n\n");
}

pub unsafe fn init() {
    buffer = cstr::new();
    screen();
    prompt();
}

pub unsafe fn prompt() {
    putnum(buffer.len(), 0);
    putnum(buffer.p as uint, 0);
    putstr(&"sgash> ");
    let prev_c = super::super::io::FG_COLOR;
    super::super::io::set_fg(PROMPT_COLOR);
    drawstr(&"sgash> ");
    super::super::io::set_fg(prev_c);
}

<commit_msg>closes #4: remove debug printing<commit_after>/* kernel::sgash.rs */
#[allow(unused_imports)];
use core::*;
use core::str::*;
use core::option::{Some, Option, None};
use core::iter::Iterator;
use kernel::*;
use kernel::cstr::cstr;
use super::super::platform::*;
use kernel::memory::Allocator;

static PROMPT_COLOR: u32 = 0xFFAF00;
static mut count: uint = 0;

static mut buffer: cstr = cstr {
    p: 0 as *mut u8,
    p_cstr_i: 0,
    size: 0,
};

/* Thanks to https://github.com/jvns/puddle/blob/master/src/stdio.rs */
pub fn putnum(x: uint, max: uint) {
    let mut i = max;
    if i == 0 {
        i = 1000000;
    }
    while(i > 0) {
        // Get the offset from each decimal point up to a certain value
        putchar(((((x / i) % 10) as u8) + ('0' as u8)) as char);
        i /= 10;
    }
    putchar(' ');
}

pub fn putkeycode(x: u8) {
    putnum(x as uint, 100);
}

pub fn putchar(key: char) {
    unsafe {
        /*
        * We need to include a blank asm call to prevent rustc
        * from optimizing this part out
        */
        asm!("");
        io::write_char(key, io::UART0);
    }
}

pub fn putstr(msg: &str) {
    for c in slice::iter(as_bytes(msg)) {
        putchar(*c as char);
    }
}

pub unsafe fn drawstr(msg: &str) {
    for c in slice::iter(as_bytes(msg)) {
        drawchar(*c as char);
    }
}

unsafe fn drawchar(x: char) {
    io::restore();
    if x == '\n' {
        io::CURSOR_Y += io::CURSOR_HEIGHT;
        io::CURSOR_X = 0u32;
    } else {
        io::draw_char(x);
        io::CURSOR_X += io::CURSOR_WIDTH;
    }
    io::backup();
    io::draw_cursor();
}

unsafe fn backspace() {
    io::restore();
    if (io::CURSOR_X >= io::CURSOR_WIDTH) {
        io::CURSOR_X -= io::CURSOR_WIDTH;
        io::draw_char(' ');
    }
    io::backup();
    io::draw_cursor();
}

pub unsafe fn parsekey(x: char) {
    let x = x as u8;
    // Set this to false to learn the keycodes of various keys!
    // Key codes are printed backwards because life is hard

    match x {
        13      =>  {
            putstr(&"\n");
            drawstr(&"\n");
            buffer.send_at_c(putchar);
            buffer.send_at_c(drawchar);
            putstr(&"\n");
            drawstr(&"\n");
            prompt();
            buffer.reset();
        }
        127     =>  {
            putchar('');
            putchar(' ');
            putchar('');
            backspace();
        }
        _       =>  {
            buffer.add_u8(x);
            if io::CURSOR_X < io::SCREEN_WIDTH-io::CURSOR_WIDTH {
                putchar(x as char);
                drawchar(x as char);
            }
        }
    }
}

pub unsafe fn screen() {
    putstr(&"\n                                                               ");
    putstr(&"\n                                                               ");
    putstr(&"\n                       7=..~$=..:7                             ");
    putstr(&"\n                  +$: =$$$+$$$?$$$+ ,7?                        ");
    putstr(&"\n                  $$$$$$$$$$$$$$$$$$Z$$                        ");
    putstr(&"\n              7$$$$$$$$$$$$. .Z$$$$$Z$$$$$$                    ");
    putstr(&"\n           ~..7$$Z$$$$$7+7$+.?Z7=7$$Z$$Z$$$..:                 ");
    putstr(&"\n          ~$$$$$$$$7:     :ZZZ,     :7ZZZZ$$$$=                ");
    putstr(&"\n           Z$$$$$?                    .+ZZZZ$$                 ");
    putstr(&"\n       +$ZZ$$$Z7                         7ZZZ$Z$$I.            ");
    putstr(&"\n        $$$$ZZZZZZZZZZZZZZZZZZZZZZZZI,    ,ZZZ$$Z              ");
    putstr(&"\n      :+$$$$ZZZZZZZZZZZZZZZZZZZZZZZZZZZ=    $ZZ$$+~,           ");
    putstr(&"\n     ?$Z$$$$ZZZZZZZZZZZZZZZZZZZZZZZZZZZZI   7ZZZ$ZZI           ");
    putstr(&"\n      =Z$$+7Z$$7ZZZZZZZZ$$$$$$$ZZZZZZZZZZ  ~Z$?$ZZ?            ");
    putstr(&"\n    :$Z$Z...$Z  $ZZZZZZZ~       ~ZZZZZZZZ,.ZZ...Z$Z$~          ");
    putstr(&"\n    7ZZZZZI$ZZ  $ZZZZZZZ~       =ZZZZZZZ7..ZZ$?$ZZZZ$          ");
    putstr(&"\n      ZZZZ$:    $ZZZZZZZZZZZZZZZZZZZZZZ=     ~$ZZZ$:           ");
    putstr(&"\n    7Z$ZZ$,     $ZZZZZZZZZZZZZZZZZZZZ7         ZZZ$Z$          ");
    putstr(&"\n   =ZZZZZZ,     $ZZZZZZZZZZZZZZZZZZZZZZ,       ZZZ$ZZ+         ");
    putstr(&"\n     ,ZZZZ,     $ZZZZZZZ:     =ZZZZZZZZZ     ZZZZZ$:           ");
    putstr(&"\n    =$ZZZZ+     ZZZZZZZZ~       ZZZZZZZZ~   =ZZZZZZZI          ");
    putstr(&"\n    $ZZ$ZZZ$$Z$$ZZZZZZZZZ$$$$   IZZZZZZZZZ$ZZZZZZZZZ$          ");
    putstr(&"\n      :ZZZZZZZZZZZZZZZZZZZZZZ   ~ZZZZZZZZZZZZZZZZZ~            ");
    putstr(&"\n     ,Z$$ZZZZZZZZZZZZZZZZZZZZ    ZZZZZZZZZZZZZZZZZZ~           ");
    putstr(&"\n     =$ZZZZZZZZZZZZZZZZZZZZZZ     $ZZZZZZZZZZZZZZZ$+           ");
    putstr(&"\n        IZZZZZ:.                        . ,ZZZZZ$              ");
    putstr(&"\n       ~$ZZZZZZZZZZZ                 ZZZZ$ZZZZZZZ+             ");
    putstr(&"\n           Z$ZZZ. ,Z~               =Z:.,ZZZ$Z                 ");
    putstr(&"\n          ,ZZZZZ..~Z$.             .7Z:..ZZZZZ:                ");
    putstr(&"\n          ~7+:$ZZZZZZZZI=:.   .,=IZZZZZZZ$Z:=7=                ");
    putstr(&"\n              $$ZZZZZZZZZZZZZZZZZZZZZZ$ZZZZ                    ");
    putstr(&"\n              ==..$ZZZ$ZZZZZZZZZZZ$ZZZZ .~+                    ");
    putstr(&"\n                  I$?.?ZZZ$ZZZ$ZZZI =$7                        ");
    putstr(&"\n                       $7..I$7..I$,                            ");
    putstr(&"\n");
    putstr(&"\n _                     _     _                         _  ");
    putstr(&"\n| |                   (_)   | |                       | | ");
    putstr(&"\n| | ____ ___  ____     _____| |_____  ____ ____  _____| | ");
    putstr(&"\n| |/ ___) _ \\|  _ \\   |  _   _) ___ |/ ___)  _ \\| ___ | | ");
    putstr(&"\n| | |  | |_| | | | |  | |  \\ \\| ____| |   | | | | ____| | ");
    putstr(&"\n|_|_|  \\____/|_| |_|  |_|   \\_\\_____)_|   |_| |_|_____)__)\n\n");
}

pub unsafe fn init() {
    buffer = cstr::new();
    screen();
    prompt();
}

pub unsafe fn prompt() {
    putstr(&"sgash> ");
    let prev_c = super::super::io::FG_COLOR;
    super::super::io::set_fg(PROMPT_COLOR);
    drawstr(&"sgash> ");
    super::super::io::set_fg(prev_c);
}

<|endoftext|>


<commit_before>// Copyright 2012 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.

/*!
Pulls a brief description out of a long description.

If the first paragraph of a long description is short enough then it
is interpreted as the brief description.
*/

use doc::ItemUtils;
use doc;
use text_pass;

use core::str;

pub fn mk_pass() -> Pass {
    text_pass::mk_pass(~"trim", |s| str::trim(s) )
}

#[test]
fn should_trim_text() {
    let doc = test::mk_doc(~"#[doc = \" desc \"] \
                            mod m {
                                #[legacy_exports]; }");
    assert doc.cratemod().mods()[0].desc() == Some(~"desc");
}

#[cfg(test)]
mod test {
    #[legacy_exports];

    use astrsrv;
    use attr_pass;
    use doc;
    use extract;

    fn mk_doc(source: ~str) -> doc::Doc {
        do astsrv::from_str(source) |srv| {
            let doc = extract::from_srv(srv, ~"");
            let doc = (attr_pass::mk_pass().f)(srv, doc);
            (mk_pass().f)(srv, doc)
        }
    }
}
<commit_msg>librustdoc: Fix typo. rs=busted<commit_after>// Copyright 2012 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.

/*!
Pulls a brief description out of a long description.

If the first paragraph of a long description is short enough then it
is interpreted as the brief description.
*/

use doc::ItemUtils;
use doc;
use text_pass;

use core::str;

pub fn mk_pass() -> Pass {
    text_pass::mk_pass(~"trim", |s| str::trim(s) )
}

#[test]
fn should_trim_text() {
    let doc = test::mk_doc(~"#[doc = \" desc \"] \
                            mod m {
                                #[legacy_exports]; }");
    assert doc.cratemod().mods()[0].desc() == Some(~"desc");
}

#[cfg(test)]
mod test {
    #[legacy_exports];

    use astsrv;
    use attr_pass;
    use doc;
    use extract;

    fn mk_doc(source: ~str) -> doc::Doc {
        do astsrv::from_str(source) |srv| {
            let doc = extract::from_srv(srv, ~"");
            let doc = (attr_pass::mk_pass().f)(srv, doc);
            (mk_pass().f)(srv, doc)
        }
    }
}
<|endoftext|>