- [alloc_system](alloc-system.md)
- [allocator](allocator.md)
- [allow_internal_unstable](allow-internal-unstable.md)
+- [as_c_str](as-c-str.md)
- [as_unsafe_cell](as-unsafe-cell.md)
- [ascii_ctype](ascii-ctype.md)
- [asm](asm.md)
- [collections](collections.md)
- [collections_range](collections-range.md)
- [command_envs](command-envs.md)
+- [compiler_barriers](compiler-barriers.md)
- [compiler_builtins](compiler-builtins.md)
- [compiler_builtins_lib](compiler-builtins-lib.md)
- [concat_idents](concat-idents.md)
- [link_llvm_intrinsics](link-llvm-intrinsics.md)
- [linkage](linkage.md)
- [linked_list_extras](linked-list-extras.md)
+- [linker_flavor](linker-flavor.md)
- [log_syntax](log-syntax.md)
- [lookup_host](lookup-host.md)
- [loop_break_value](loop-break-value.md)
- [macro_reexport](macro-reexport.md)
- [main](main.md)
+- [manually_drop](manually-drop.md)
- [map_entry_recover_keys](map-entry-recover-keys.md)
- [mpsc_select](mpsc-select.md)
- [n16](n16.md)
- [str_checked_slicing](str-checked-slicing.md)
- [str_escape](str-escape.md)
- [str_internals](str-internals.md)
+- [str_mut_extras](str-mut-extras.md)
- [struct_field_attributes](struct-field-attributes.md)
- [structural_match](structural-match.md)
- [target_feature](target-feature.md)
--- /dev/null
+# `as_c_str`
+
+The tracking issue for this feature is: [#40380]
+
+[#40380]: https://github.com/rust-lang/rust/issues/40380
+
+------------------------
+
--- /dev/null
+# `compiler_barriers`
+
+The tracking issue for this feature is: [#41091]
+
+[#41091]: https://github.com/rust-lang/rust/issues/41091
+
+------------------------
+
+The `compiler_barriers` feature exposes the `compiler_barrier` function
+in `std::sync::atomic`. This function is conceptually similar to C++'s
+`atomic_signal_fence`, which can currently only be accessed in nightly
+Rust using the `atomic_singlethreadfence_*` instrinsic functions in
+`core`, or through the mostly equivalent literal assembly:
+
+```rust
+#![feature(asm)]
+unsafe { asm!("" ::: "memory" : "volatile") };
+```
+
+A `compiler_barrier` restricts the kinds of memory re-ordering the
+compiler is allowed to do. Specifically, depending on the given ordering
+semantics, the compiler may be disallowed from moving reads or writes
+from before or after the call to the other side of the call to
+`compiler_barrier`. Note that it does **not** prevent the *hardware*
+from doing such re-ordering. This is not a problem in a single-threaded,
+execution context, but when other threads may modify memory at the same
+time, stronger synchronization primitives are required.
+
+## Examples
+
+`compiler_barrier` is generally only useful for preventing a thread from
+racing *with itself*. That is, if a given thread is executing one piece
+of code, and is then interrupted, and starts executing code elsewhere
+(while still in the same thread, and conceptually still on the same
+core). In traditional programs, this can only occur when a signal
+handler is registered. In more low-level code, such situations can also
+arise when handling interrupts, when implementing green threads with
+pre-emption, etc.
+
+To give a straightforward example of when a `compiler_barrier` is
+necessary, consider the following example:
+
+```rust
+# use std::sync::atomic::{AtomicBool, AtomicUsize};
+# use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT};
+# use std::sync::atomic::Ordering;
+static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT;
+static IS_READY: AtomicBool = ATOMIC_BOOL_INIT;
+
+fn main() {
+ IMPORTANT_VARIABLE.store(42, Ordering::Relaxed);
+ IS_READY.store(true, Ordering::Relaxed);
+}
+
+fn signal_handler() {
+ if IS_READY.load(Ordering::Relaxed) {
+ assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42);
+ }
+}
+```
+
+The way it is currently written, the `assert_eq!` is *not* guaranteed to
+succeed, despite everything happening in a single thread. To see why,
+remember that the compiler is free to swap the stores to
+`IMPORTANT_VARIABLE` and `IS_READ` since they are both
+`Ordering::Relaxed`. If it does, and the signal handler is invoked right
+after `IS_READY` is updated, then the signal handler will see
+`IS_READY=1`, but `IMPORTANT_VARIABLE=0`.
+
+Using a `compiler_barrier`, we can remedy this situation:
+
+```rust
+#![feature(compiler_barriers)]
+# use std::sync::atomic::{AtomicBool, AtomicUsize};
+# use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT};
+# use std::sync::atomic::Ordering;
+use std::sync::atomic::compiler_barrier;
+
+static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT;
+static IS_READY: AtomicBool = ATOMIC_BOOL_INIT;
+
+fn main() {
+ IMPORTANT_VARIABLE.store(42, Ordering::Relaxed);
+ // prevent earlier writes from being moved beyond this point
+ compiler_barrier(Ordering::Release);
+ IS_READY.store(true, Ordering::Relaxed);
+}
+
+fn signal_handler() {
+ if IS_READY.load(Ordering::Relaxed) {
+ assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42);
+ }
+}
+```
+
+A deeper discussion of compiler barriers with various re-ordering
+semantics (such as `Ordering::SeqCst`) is beyond the scope of this text.
+Curious readers are encouraged to read the Linux kernel's discussion of
+[memory barriers][1], the C++ references on [`std::memory_order`][2] and
+[`atomic_signal_fence`][3], and [this StackOverflow answer][4] for
+further details.
+
+[1]: https://www.kernel.org/doc/Documentation/memory-barriers.txt
+[2]: http://en.cppreference.com/w/cpp/atomic/memory_order
+[3]: http://www.cplusplus.com/reference/atomic/atomic_signal_fence/
+[4]: http://stackoverflow.com/a/18454971/472927
--- /dev/null
+# `linker-flavor`
+
+The tracking issue for this feature is: None
+
+------------------------
+
+Every `rustc` target defaults to some linker. For example, Linux targets default
+to gcc. In some cases, you may want to override the default; you can do that
+with the unstable CLI argument: `-Z linker-flavor`.
+
+Here how you would use this flag to link a Rust binary for the
+`thumbv7m-none-eabi` using LLD instead of GCC.
+
+``` text
+$ xargo rustc --target thumbv7m-none-eabi -- \
+ -C linker=ld.lld \
+ -Z linker-flavor=ld \
+ -Z print-link-args | tr ' ' '\n'
+"ld.lld"
+"-L"
+"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib"
+"$PWD/target/thumbv7m-none-eabi/debug/deps/app-512e9dbf385f233c.0.o"
+"-o"
+"$PWD/target/thumbv7m-none-eabi/debug/deps/app-512e9dbf385f233c"
+"--gc-sections"
+"-L"
+"$PWD/target/thumbv7m-none-eabi/debug/deps"
+"-L"
+"$PWD/target/debug/deps"
+"-L"
+"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib"
+"-Bstatic"
+"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib/libcore-e1ccb7dfb1cb9ebb.rlib"
+"-Bdynamic"
+```
+
+Whereas the default is:
+
+``` text
+$ xargo rustc --target thumbv7m-none-eabi -- \
+ -C link-arg=-nostartfiles \
+ -Z print-link-args | tr ' ' '\n'
+"arm-none-eabi-gcc"
+"-L"
+"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib"
+"$PWD/target/thumbv7m-none-eabi/debug/deps/app-961e39416baa38d9.0.o"
+"-o"
+"$PWD/target/thumbv7m-none-eabi/debug/deps/app-961e39416baa38d9"
+"-Wl,--gc-sections"
+"-nodefaultlibs"
+"-L"
+"$PWD/target/thumbv7m-none-eabi/debug/deps"
+"-L"
+"$PWD/target/debug/deps"
+"-L"
+"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib"
+"-Wl,-Bstatic"
+"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib/libcore-e1ccb7dfb1cb9ebb.rlib"
+"-nostartfiles"
+"-Wl,-Bdynamic"
+```
--- /dev/null
+# `str_mut_extras`
+
+The tracking issue for this feature is: [#str_mut_extras]
+
+[#str_mut_extras]: https://github.com/rust-lang/rust/issues/41119
+
+------------------------
+
// should be good to go!
cmd.arg("--with-jemalloc-prefix=je_");
cmd.arg("--disable-tls");
- } else if target.contains("dragonfly") {
+ } else if target.contains("dragonfly") || target.contains("musl") {
cmd.arg("--with-jemalloc-prefix=je_");
}
// request it as unprefixing cause segfaults (mismatches in allocators).
extern "C" {
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows"),
+ target_os = "dragonfly", target_os = "windows", target_env = "musl"),
link_name = "je_mallocx")]
fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows"),
+ target_os = "dragonfly", target_os = "windows", target_env = "musl"),
link_name = "je_rallocx")]
fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows"),
+ target_os = "dragonfly", target_os = "windows", target_env = "musl"),
link_name = "je_xallocx")]
fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows"),
+ target_os = "dragonfly", target_os = "windows", target_env = "musl"),
link_name = "je_sdallocx")]
fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows"),
+ target_os = "dragonfly", target_os = "windows", target_env = "musl"),
link_name = "je_nallocx")]
fn nallocx(size: size_t, flags: c_int) -> size_t;
}
}
}
-/// An iterator over a BTreeMap's entries.
+/// An iterator over a `BTreeMap`'s entries.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, K: 'a, V: 'a> {
range: Range<'a, K, V>,
}
}
-/// A mutable iterator over a BTreeMap's entries.
+/// A mutable iterator over a `BTreeMap`'s entries.
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct IterMut<'a, K: 'a, V: 'a> {
length: usize,
}
-/// An owning iterator over a BTreeMap's entries.
+/// An owning iterator over a `BTreeMap`'s entries.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<K, V> {
front: Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge>,
}
}
-/// An iterator over a BTreeMap's keys.
+/// An iterator over a `BTreeMap`'s keys.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Keys<'a, K: 'a, V: 'a> {
inner: Iter<'a, K, V>,
}
}
-/// An iterator over a BTreeMap's values.
+/// An iterator over a `BTreeMap`'s values.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Values<'a, K: 'a, V: 'a> {
inner: Iter<'a, K, V>,
}
}
-/// A mutable iterator over a BTreeMap's values.
+/// A mutable iterator over a `BTreeMap`'s values.
#[stable(feature = "map_values_mut", since = "1.10.0")]
#[derive(Debug)]
pub struct ValuesMut<'a, K: 'a, V: 'a> {
inner: IterMut<'a, K, V>,
}
-/// An iterator over a sub-range of BTreeMap's entries.
+/// An iterator over a sub-range of `BTreeMap`'s entries.
#[stable(feature = "btree_range", since = "1.17.0")]
pub struct Range<'a, K: 'a, V: 'a> {
front: Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge>,
}
}
-/// A mutable iterator over a sub-range of BTreeMap's entries.
+/// A mutable iterator over a sub-range of `BTreeMap`'s entries.
#[stable(feature = "btree_range", since = "1.17.0")]
pub struct RangeMut<'a, K: 'a, V: 'a> {
front: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>,
/// [`entry`]: struct.BTreeMap.html#method.entry
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Entry<'a, K: 'a, V: 'a> {
- /// A vacant Entry
+ /// A vacant `Entry`
#[stable(feature = "rust1", since = "1.0.0")]
Vacant(#[stable(feature = "rust1", since = "1.0.0")]
VacantEntry<'a, K, V>),
- /// An occupied Entry
+ /// An occupied `Entry`
#[stable(feature = "rust1", since = "1.0.0")]
Occupied(#[stable(feature = "rust1", since = "1.0.0")]
OccupiedEntry<'a, K, V>),
}
}
-/// A vacant Entry. It is part of the [`Entry`] enum.
+/// A vacant `Entry`. It is part of the [`Entry`] enum.
///
/// [`Entry`]: enum.Entry.html
#[stable(feature = "rust1", since = "1.0.0")]
}
}
-/// An occupied Entry. It is part of the [`Entry`] enum.
+/// An occupied `Entry`. It is part of the [`Entry`] enum.
///
/// [`Entry`]: enum.Entry.html
#[stable(feature = "rust1", since = "1.0.0")]
}
}
-/// An iterator over an EnumSet
+/// An iterator over an `EnumSet`
pub struct Iter<E> {
index: usize,
bits: usize,
//! Collection types.
//!
-//! See [std::collections](../std/collections/index.html) for a detailed discussion of
-//! collections in Rust.
+//! See [`std::collections`](../std/collections/index.html) for a detailed
+//! discussion of collections in Rust.
#![crate_name = "collections"]
#![crate_type = "rlib"]
#![feature(heap_api)]
#![feature(inclusive_range)]
#![feature(lang_items)]
+#![feature(manually_drop)]
#![feature(nonzero)]
#![feature(pattern)]
#![feature(placement_in)]
#![feature(specialization)]
#![feature(staged_api)]
#![feature(str_internals)]
+#![feature(str_mut_extras)]
#![feature(trusted_len)]
#![feature(unicode)]
#![feature(unique)]
use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive};
use Bound::{self, Excluded, Included, Unbounded};
-/// **RangeArgument** is implemented by Rust's built-in range types, produced
+/// `RangeArgument` is implemented by Rust's built-in range types, produced
/// by range syntax like `..`, `a..`, `..b` or `c..d`.
pub trait RangeArgument<T: ?Sized> {
/// Start index bound.
// performance than with the 2nd method.
//
// All methods were benchmarked, and the 3rd showed best results. So we chose that one.
- let mut tmp = NoDrop { value: ptr::read(&v[0]) };
+ let mut tmp = mem::ManuallyDrop::new(ptr::read(&v[0]));
// Intermediate state of the insertion process is always tracked by `hole`, which
// serves two purposes:
// fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it
// initially held exactly once.
let mut hole = InsertionHole {
- src: &mut tmp.value,
+ src: &mut *tmp,
dest: &mut v[1],
};
ptr::copy_nonoverlapping(&v[1], &mut v[0], 1);
for i in 2..v.len() {
- if !is_less(&v[i], &tmp.value) {
+ if !is_less(&v[i], &*tmp) {
break;
}
ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1);
}
}
- // Holds a value, but never drops it.
- #[allow(unions_with_drop_fields)]
- union NoDrop<T> {
- value: T
- }
-
// When dropped, copies from `src` into `dest`.
struct InsertionHole<T> {
src: *mut T,
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::str::{from_utf8, Chars, CharIndices, Bytes};
#[stable(feature = "rust1", since = "1.0.0")]
-pub use core::str::{from_utf8_unchecked, ParseBoolError};
+pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError};
#[stable(feature = "rust1", since = "1.0.0")]
pub use std_unicode::str::SplitWhitespace;
#[stable(feature = "rust1", since = "1.0.0")]
core_str::StrExt::as_bytes(self)
}
+ /// Converts a mutable string slice to a mutable byte slice.
+ #[unstable(feature = "str_mut_extras", issue = "41119")]
+ #[inline(always)]
+ pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
+ core_str::StrExt::as_bytes_mut(self)
+ }
+
/// Converts a string slice to a raw pointer.
///
/// As string slices are a slice of bytes, the raw pointer points to a
impl ops::IndexMut<ops::RangeFull> for String {
#[inline]
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
- unsafe { mem::transmute(&mut *self.vec) }
+ unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) }
}
}
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl ops::DerefMut for String {
#[inline]
fn deref_mut(&mut self) -> &mut str {
- unsafe { mem::transmute(&mut *self.vec) }
+ unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) }
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! VecDeque is a double-ended queue, which is implemented with the help of a
+//! `VecDeque` is a double-ended queue, which is implemented with the help of a
//! growing ring buffer.
//!
//! This queue has `O(1)` amortized inserts and removals from both ends of the
index & (size - 1)
}
-/// Returns the two slices that cover the VecDeque's valid range
+/// Returns the two slices that cover the `VecDeque`'s valid range
trait RingSlices: Sized {
fn slice(self, from: usize, to: usize) -> Self;
fn split_at(self, i: usize) -> (Self, Self);
#[unstable(feature = "fused", issue = "35602")]
impl<'a, T> FusedIterator for IterMut<'a, T> {}
-/// A by-value VecDeque iterator
+/// A by-value `VecDeque` iterator
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<T> {
#[unstable(feature = "fused", issue = "35602")]
impl<T> FusedIterator for IntoIter<T> {}
-/// A draining VecDeque iterator
+/// A draining `VecDeque` iterator
#[stable(feature = "drain", since = "1.6.0")]
pub struct Drain<'a, T: 'a> {
after_tail: usize,
use convert::TryFrom;
use fmt::{self, Write};
use slice;
+use str::from_utf8_unchecked_mut;
use iter::FusedIterator;
use mem::transmute;
code,
dst.len())
};
- transmute(slice::from_raw_parts_mut(dst.as_mut_ptr(), len))
+ from_utf8_unchecked_mut(dst.get_unchecked_mut(..len))
}
}
/// ```
#[lang = "eq"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"]
pub trait PartialEq<Rhs: ?Sized = Self> {
/// This method tests for `self` and `other` values to be equal, and is used
/// by `==`.
/// ```
#[lang = "ord"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"]
pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
/// This method returns an ordering between `self` and `other` values if one exists.
///
pub mod v1;
}
-#[stable(feature = "rust1", since = "1.0.0")]
/// The type returned by formatter methods.
+///
+/// # Examples
+///
+/// ```
+/// use std::fmt;
+///
+/// #[derive(Debug)]
+/// struct Triangle {
+/// a: f32,
+/// b: f32,
+/// c: f32
+/// }
+///
+/// impl fmt::Display for Triangle {
+/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+/// write!(f, "({}, {}, {})", self.a, self.b, self.c)
+/// }
+/// }
+///
+/// let pythagorean_triple = Triangle { a: 3.0, b: 4.0, c: 5.0 };
+///
+/// println!("{}", pythagorean_triple);
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
pub type Result = result::Result<(), Error>;
/// The error type which is returned from formatting a message into a stream.
/// initialize memory previous set to the result of `uninit`.
pub fn uninit<T>() -> T;
- /// Moves a value out of scope without running drop glue.
- pub fn forget<T>(_: T) -> ();
-
/// Reinterprets the bits of a value of one type as another type.
///
/// Both types must have the same size. Neither the original, nor the result,
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn forget<T>(t: T) {
- unsafe { intrinsics::forget(t) }
+ ManuallyDrop::new(t);
}
/// Returns the size of a type in bytes.
}
}
+
+/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
+///
+/// This wrapper is 0-cost.
+///
+/// # Examples
+///
+/// This wrapper helps with explicitly documenting the drop order dependencies between fields of
+/// the type:
+///
+/// ```rust
+/// # #![feature(manually_drop)]
+/// use std::mem::ManuallyDrop;
+/// struct Peach;
+/// struct Banana;
+/// struct Melon;
+/// struct FruitBox {
+/// // Immediately clear there’s something non-trivial going on with these fields.
+/// peach: ManuallyDrop<Peach>,
+/// melon: Melon, // Field that’s independent of the other two.
+/// banana: ManuallyDrop<Banana>,
+/// }
+///
+/// impl Drop for FruitBox {
+/// fn drop(&mut self) {
+/// unsafe {
+/// // Explicit ordering in which field destructors are run specified in the intuitive
+/// // location – the destructor of the structure containing the fields.
+/// // Moreover, one can now reorder fields within the struct however much they want.
+/// ManuallyDrop::drop(&mut self.peach);
+/// ManuallyDrop::drop(&mut self.banana);
+/// }
+/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets
+/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
+/// }
+/// }
+/// ```
+#[unstable(feature = "manually_drop", issue = "40673")]
+#[allow(unions_with_drop_fields)]
+pub union ManuallyDrop<T>{ value: T }
+
+impl<T> ManuallyDrop<T> {
+ /// Wrap a value to be manually dropped.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # #![feature(manually_drop)]
+ /// use std::mem::ManuallyDrop;
+ /// ManuallyDrop::new(Box::new(()));
+ /// ```
+ #[unstable(feature = "manually_drop", issue = "40673")]
+ #[inline]
+ pub fn new(value: T) -> ManuallyDrop<T> {
+ ManuallyDrop { value: value }
+ }
+
+ /// Extract the value from the ManuallyDrop container.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # #![feature(manually_drop)]
+ /// use std::mem::ManuallyDrop;
+ /// let x = ManuallyDrop::new(Box::new(()));
+ /// let _: Box<()> = ManuallyDrop::into_inner(x);
+ /// ```
+ #[unstable(feature = "manually_drop", issue = "40673")]
+ #[inline]
+ pub fn into_inner(slot: ManuallyDrop<T>) -> T {
+ unsafe {
+ slot.value
+ }
+ }
+
+ /// Manually drops the contained value.
+ ///
+ /// # Unsafety
+ ///
+ /// This function runs the destructor of the contained value and thus the wrapped value
+ /// now represents uninitialized data. It is up to the user of this method to ensure the
+ /// uninitialized data is not actually used.
+ #[unstable(feature = "manually_drop", issue = "40673")]
+ #[inline]
+ pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
+ ptr::drop_in_place(&mut slot.value)
+ }
+}
+
+#[unstable(feature = "manually_drop", issue = "40673")]
+impl<T> ::ops::Deref for ManuallyDrop<T> {
+ type Target = T;
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ unsafe {
+ &self.value
+ }
+ }
+}
+
+#[unstable(feature = "manually_drop", issue = "40673")]
+impl<T> ::ops::DerefMut for ManuallyDrop<T> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ unsafe {
+ &mut self.value
+ }
+ }
+}
+
+#[unstable(feature = "manually_drop", issue = "40673")]
+impl<T: ::fmt::Debug> ::fmt::Debug for ManuallyDrop<T> {
+ fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result {
+ unsafe {
+ fmt.debug_tuple("ManuallyDrop").field(&self.value).finish()
+ }
+ }
+}
/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html
#[lang = "add"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} + {RHS}`"]
pub trait Add<RHS=Self> {
/// The resulting type after applying the `+` operator
#[stable(feature = "rust1", since = "1.0.0")]
/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html
#[lang = "sub"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} - {RHS}`"]
pub trait Sub<RHS=Self> {
/// The resulting type after applying the `-` operator
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "mul"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} * {RHS}`"]
pub trait Mul<RHS=Self> {
/// The resulting type after applying the `*` operator
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "div"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} / {RHS}`"]
pub trait Div<RHS=Self> {
/// The resulting type after applying the `/` operator
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "rem"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} % {RHS}`"]
pub trait Rem<RHS=Self> {
/// The resulting type after applying the `%` operator
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "bitand"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} & {RHS}`"]
pub trait BitAnd<RHS=Self> {
/// The resulting type after applying the `&` operator
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "bitor"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} | {RHS}`"]
pub trait BitOr<RHS=Self> {
/// The resulting type after applying the `|` operator
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "bitxor"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} ^ {RHS}`"]
pub trait BitXor<RHS=Self> {
/// The resulting type after applying the `^` operator
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "shl"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} << {RHS}`"]
pub trait Shl<RHS> {
/// The resulting type after applying the `<<` operator
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "shr"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} >> {RHS}`"]
pub trait Shr<RHS> {
/// The resulting type after applying the `>>` operator
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "add_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} += {Rhs}`"]
pub trait AddAssign<Rhs=Self> {
/// The method for the `+=` operator
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "sub_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} -= {Rhs}`"]
pub trait SubAssign<Rhs=Self> {
/// The method for the `-=` operator
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "mul_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} *= {Rhs}`"]
pub trait MulAssign<Rhs=Self> {
/// The method for the `*=` operator
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "div_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} /= {Rhs}`"]
pub trait DivAssign<Rhs=Self> {
/// The method for the `/=` operator
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "rem_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} %= {Rhs}`"]
pub trait RemAssign<Rhs=Self> {
/// The method for the `%=` operator
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "bitand_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} &= {Rhs}`"]
pub trait BitAndAssign<Rhs=Self> {
/// The method for the `&=` operator
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "bitor_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} |= {Rhs}`"]
pub trait BitOrAssign<Rhs=Self> {
/// The method for the `|=` operator
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "bitxor_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} ^= {Rhs}`"]
pub trait BitXorAssign<Rhs=Self> {
/// The method for the `^=` operator
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "shl_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} <<= {Rhs}`"]
pub trait ShlAssign<Rhs> {
/// The method for the `<<=` operator
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "shr_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_on_unimplemented = "no implementation for `{Self} >>= {Rhs}`"]
pub trait ShrAssign<Rhs=Self> {
/// The method for the `>>=` operator
#[stable(feature = "op_assign_traits", since = "1.8.0")]
}
}
}
+
+ fn rfind<F>(&mut self, mut predicate: F) -> Option<Self::Item>
+ where F: FnMut(&Self::Item) -> bool,
+ {
+ self.rsearch_while(None, move |elt| {
+ if predicate(&elt) {
+ SearchWhile::Done(Some(elt))
+ } else {
+ SearchWhile::Continue
+ }
+ })
+ }
+
}
// search_while is a generalization of the internal iteration methods.
use mem;
use ptr;
-/// Holds a value, but never drops it.
-#[allow(unions_with_drop_fields)]
-union NoDrop<T> {
- value: T
-}
-
/// When dropped, copies from `src` into `dest`.
struct CopyOnDrop<T> {
src: *mut T,
// Read the first element into a stack-allocated variable. If a following comparison
// operation panics, `hole` will get dropped and automatically write the element back
// into the slice.
- let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(0)) };
+ let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0)));
let mut hole = CopyOnDrop {
- src: &mut tmp.value,
+ src: &mut *tmp,
dest: v.get_unchecked_mut(1),
};
ptr::copy_nonoverlapping(v.get_unchecked(1), v.get_unchecked_mut(0), 1);
for i in 2..len {
- if !is_less(v.get_unchecked(i), &tmp.value) {
+ if !is_less(v.get_unchecked(i), &*tmp) {
break;
}
// Read the last element into a stack-allocated variable. If a following comparison
// operation panics, `hole` will get dropped and automatically write the element back
// into the slice.
- let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(len - 1)) };
+ let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1)));
let mut hole = CopyOnDrop {
- src: &mut tmp.value,
+ src: &mut *tmp,
dest: v.get_unchecked_mut(len - 2),
};
ptr::copy_nonoverlapping(v.get_unchecked(len - 2), v.get_unchecked_mut(len - 1), 1);
for i in (0..len-2).rev() {
- if !is_less(&tmp.value, v.get_unchecked(i)) {
+ if !is_less(&*tmp, v.get_unchecked(i)) {
break;
}
// Read the pivot into a stack-allocated variable for efficiency. If a following comparison
// operation panics, the pivot will be automatically written back into the slice.
- let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } };
+ let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
let _pivot_guard = CopyOnDrop {
- src: unsafe { &mut tmp.value },
+ src: &mut *tmp,
dest: pivot,
};
- let pivot = unsafe { &tmp.value };
+ let pivot = &*tmp;
// Find the first pair of out-of-order elements.
let mut l = 0;
// Read the pivot into a stack-allocated variable for efficiency. If a following comparison
// operation panics, the pivot will be automatically written back into the slice.
- let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } };
+ let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
let _pivot_guard = CopyOnDrop {
- src: unsafe { &mut tmp.value },
+ src: &mut *tmp,
dest: pivot,
};
- let pivot = unsafe { &tmp.value };
+ let pivot = &*tmp;
// Now partition the slice.
let mut l = 0;
use convert::TryFrom;
use fmt;
use iter::{Map, Cloned, FusedIterator};
-use mem;
use slice::{self, SliceIndex};
+use mem;
pub mod pattern;
Ok(unsafe { from_utf8_unchecked(v) })
}
+/// Converts a mutable slice of bytes to a mutable string slice.
+#[unstable(feature = "str_mut_extras", issue = "41119")]
+pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
+ run_utf8_validation(v)?;
+ Ok(unsafe { from_utf8_unchecked_mut(v) })
+}
+
/// Forms a str from a pointer and a length.
///
/// The `len` argument is the number of bytes in the string.
/// str is returned.
///
unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str {
- mem::transmute::<&mut [u8], &mut str>(slice::from_raw_parts_mut(p, len))
+ from_utf8_unchecked_mut(slice::from_raw_parts_mut(p, len))
}
/// Converts a slice of bytes to a string slice without checking
mem::transmute(v)
}
+/// Converts a slice of bytes to a string slice without checking
+/// that the string contains valid UTF-8; mutable version.
+///
+/// See the immutable version, [`from_utf8_unchecked()`][fromutf8], for more information.
+///
+/// [fromutf8]: fn.from_utf8_unchecked.html
+#[inline(always)]
+#[unstable(feature = "str_mut_extras", issue = "41119")]
+pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
+ mem::transmute(v)
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for Utf8Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
mod traits {
use cmp::Ordering;
use ops;
- use mem;
use slice::{self, SliceIndex};
use str::eq_slice;
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
let ptr = slice.as_ptr().offset(self.start as isize);
let len = self.end - self.start;
- mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len))
+ super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len))
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
let ptr = slice.as_ptr();
- mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end))
+ super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end))
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
let ptr = slice.as_ptr().offset(self.start as isize);
let len = slice.len() - self.start;
- mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len))
+ super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len))
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
let ptr = slice.as_ptr();
- mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1))
+ super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1))
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
fn is_char_boundary(&self, index: usize) -> bool;
#[stable(feature = "core", since = "1.6.0")]
fn as_bytes(&self) -> &[u8];
+ #[unstable(feature = "str_mut_extras", issue = "0")]
+ unsafe fn as_bytes_mut(&mut self) -> &mut [u8];
#[stable(feature = "core", since = "1.6.0")]
fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>;
#[stable(feature = "core", since = "1.6.0")]
unsafe { mem::transmute(self) }
}
+ #[inline]
+ unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
+ mem::transmute(self)
+ }
+
fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
pat.into_searcher(self).next_match().map(|(i, _)| i)
}
}
+/// A compiler memory barrier.
+///
+/// `compiler_barrier` does not emit any machine code, but prevents the compiler from re-ordering
+/// memory operations across this point. Which reorderings are disallowed is dictated by the given
+/// [`Ordering`]. Note that `compiler_barrier` does *not* introduce inter-thread memory
+/// synchronization; for that, a [`fence`] is needed.
+///
+/// The re-ordering prevented by the different ordering semantics are:
+///
+/// - with [`SeqCst`], no re-ordering of reads and writes across this point is allowed.
+/// - with [`Release`], preceding reads and writes cannot be moved past subsequent writes.
+/// - with [`Acquire`], subsequent reads and writes cannot be moved ahead of preceding reads.
+/// - with [`AcqRel`], both of the above rules are enforced.
+///
+/// # Panics
+///
+/// Panics if `order` is [`Relaxed`].
+///
+/// [`fence`]: fn.fence.html
+/// [`Ordering`]: enum.Ordering.html
+/// [`Acquire`]: enum.Ordering.html#variant.Acquire
+/// [`SeqCst`]: enum.Ordering.html#variant.SeqCst
+/// [`Release`]: enum.Ordering.html#variant.Release
+/// [`AcqRel`]: enum.Ordering.html#variant.AcqRel
+/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
+#[inline]
+#[unstable(feature = "compiler_barriers", issue = "41091")]
+pub fn compiler_barrier(order: Ordering) {
+ unsafe {
+ match order {
+ Acquire => intrinsics::atomic_singlethreadfence_acq(),
+ Release => intrinsics::atomic_singlethreadfence_rel(),
+ AcqRel => intrinsics::atomic_singlethreadfence_acqrel(),
+ SeqCst => intrinsics::atomic_singlethreadfence(),
+ Relaxed => panic!("there is no such thing as a relaxed barrier"),
+ __Nonexhaustive => panic!("invalid memory ordering"),
+ }
+ }
+}
+
+
#[cfg(target_has_atomic = "8")]
#[stable(feature = "atomic_debug", since = "1.3.0")]
impl fmt::Debug for AtomicBool {
#![feature(fixed_size_array)]
#![feature(flt2dec)]
#![feature(fmt_internals)]
+#![feature(iter_rfind)]
#![feature(libc)]
#![feature(nonzero)]
#![feature(rand)]
}
}
+#[test]
+fn test_find_rfind() {
+ let v = [0, 1, 2, 3, 4, 5];
+ let mut iter = v.iter();
+ let mut i = v.len();
+ while let Some(&elt) = iter.rfind(|_| true) {
+ i -= 1;
+ assert_eq!(elt, v[i]);
+ }
+ assert_eq!(i, 0);
+ assert_eq!(v.iter().rfind(|&&x| x <= 3), Some(&3));
+}
+
#[test]
fn sort_unstable() {
let mut v = [0; 600];
let from = unpack_option_like(self.infcx.tcx.global_tcx(), from);
match (&from.sty, sk_to) {
(&ty::TyFnDef(..), SizeSkeleton::Known(size_to))
- if size_to == Pointer.size(&self.infcx.tcx.data_layout) => {
+ if size_to == Pointer.size(self.infcx) => {
struct_span_err!(self.infcx.tcx.sess, span, E0591,
"`{}` is zero-sized and can't be transmuted to `{}`",
from, to)
use session::{early_error, early_warn, Session};
use session::search_paths::SearchPaths;
-use rustc_back::PanicStrategy;
+use rustc_back::{LinkerFlavor, PanicStrategy};
use rustc_back::target::Target;
use lint;
use middle::cstore;
Some("either `panic` or `abort`");
pub const parse_sanitizer: Option<&'static str> =
Some("one of: `address`, `leak`, `memory` or `thread`");
+ pub const parse_linker_flavor: Option<&'static str> =
+ Some(::rustc_back::LinkerFlavor::one_of());
+ pub const parse_optimization_fuel: Option<&'static str> =
+ Some("crate=integer");
}
#[allow(dead_code)]
mod $mod_set {
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer};
- use rustc_back::PanicStrategy;
+ use rustc_back::{LinkerFlavor, PanicStrategy};
$(
pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
}
true
}
+
+ fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
+ match v.and_then(LinkerFlavor::from_str) {
+ Some(lf) => *slote = Some(lf),
+ _ => return false,
+ }
+ true
+ }
+
+ fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
+ match v {
+ None => false,
+ Some(s) => {
+ let parts = s.split('=').collect::<Vec<_>>();
+ if parts.len() != 2 { return false; }
+ let crate_name = parts[0].to_string();
+ let fuel = parts[1].parse::<u64>();
+ if fuel.is_err() { return false; }
+ *slot = Some((crate_name, fuel.unwrap()));
+ true
+ }
+ }
+ }
}
) }
"pass `-install_name @rpath/...` to the macOS linker"),
sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
"Use a sanitizer"),
+ linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
+ "Linker flavor"),
+ fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
+ "Set the optimization fuel quota for a crate."),
+ print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
+ "Make Rustc print the total optimization fuel used by a crate."),
}
pub fn default_lib_output() -> CrateType {
impl_dep_tracking_hash_via_hash!(bool);
impl_dep_tracking_hash_via_hash!(usize);
+ impl_dep_tracking_hash_via_hash!(u64);
impl_dep_tracking_hash_via_hash!(String);
impl_dep_tracking_hash_via_hash!(lint::Level);
impl_dep_tracking_hash_via_hash!(Option<bool>);
impl_dep_tracking_hash_via_hash!(Option<usize>);
impl_dep_tracking_hash_via_hash!(Option<String>);
+ impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>,
Option<cstore::NativeLibraryKind>));
+ impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
impl DepTrackingHash for SearchPaths {
fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
let mut elems: Vec<_> = self
use syntax::feature_gate::AttributeType;
use syntax_pos::{Span, MultiSpan};
-use rustc_back::PanicStrategy;
+use rustc_back::{LinkerFlavor, PanicStrategy};
use rustc_back::target::Target;
use rustc_data_structures::flock;
use llvm;
pub code_stats: RefCell<CodeStats>,
next_node_id: Cell<ast::NodeId>,
+
+ /// If -zfuel=crate=n is specified, Some(crate).
+ optimization_fuel_crate: Option<String>,
+ /// If -zfuel=crate=n is specified, initially set to n. Otherwise 0.
+ optimization_fuel_limit: Cell<u64>,
+ /// We're rejecting all further optimizations.
+ out_of_fuel: Cell<bool>,
+
+ // The next two are public because the driver needs to read them.
+
+ /// If -zprint-fuel=crate, Some(crate).
+ pub print_fuel_crate: Option<String>,
+ /// Always set to zero and incremented so that we can print fuel expended by a crate.
+ pub print_fuel: Cell<u64>,
}
pub struct PerfStats {
pub fn panic_strategy(&self) -> PanicStrategy {
self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy)
}
+ pub fn linker_flavor(&self) -> LinkerFlavor {
+ self.opts.debugging_opts.linker_flavor.unwrap_or(self.target.target.linker_flavor)
+ }
pub fn no_landing_pads(&self) -> bool {
self.opts.debugging_opts.no_landing_pads || self.panic_strategy() == PanicStrategy::Abort
}
println!("Total time spent decoding DefPath tables: {}",
duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get()));
}
+
+ /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n.
+ /// This expends fuel if applicable, and records fuel if applicable.
+ pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool {
+ let mut ret = true;
+ match self.optimization_fuel_crate {
+ Some(ref c) if c == crate_name => {
+ let fuel = self.optimization_fuel_limit.get();
+ ret = fuel != 0;
+ if fuel == 0 && !self.out_of_fuel.get() {
+ println!("optimization-fuel-exhausted: {}", msg());
+ self.out_of_fuel.set(true);
+ } else if fuel > 0 {
+ self.optimization_fuel_limit.set(fuel-1);
+ }
+ }
+ _ => {}
+ }
+ match self.print_fuel_crate {
+ Some(ref c) if c == crate_name=> {
+ self.print_fuel.set(self.print_fuel.get()+1);
+ },
+ _ => {}
+ }
+ ret
+ }
}
pub fn build_session(sopts: config::Options,
}
);
+ let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone());
+ let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref()
+ .map(|i| i.1).unwrap_or(0));
+ let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
+ let print_fuel = Cell::new(0);
+
let sess = Session {
dep_graph: dep_graph.clone(),
target: target_cfg,
decode_def_path_tables_time: Cell::new(Duration::from_secs(0)),
},
code_stats: RefCell::new(CodeStats::new()),
+ optimization_fuel_crate: optimization_fuel_crate,
+ optimization_fuel_limit: optimization_fuel_limit,
+ print_fuel_crate: print_fuel_crate,
+ print_fuel: print_fuel,
+ out_of_fuel: Cell::new(false),
};
init_llvm(&sess);
"the trait bound `{}` is not satisfied{}",
trait_ref.to_predicate(),
post_message);
- err.span_label(span,
- &format!("{}the trait `{}` is not \
- implemented for `{}`",
- pre_message,
- trait_ref,
- trait_ref.self_ty()));
// Try to report a help message
-
if !trait_ref.has_infer_types() &&
self.predicate_can_apply(trait_ref) {
// If a where-clause may be useful, remind the
// which is somewhat confusing.
err.help(&format!("consider adding a `where {}` bound",
trait_ref.to_predicate()));
- } else if let Some(s) = self.on_unimplemented_note(trait_ref,
- obligation) {
+ } else if let Some(s) = self.on_unimplemented_note(trait_ref, obligation) {
// If it has a custom "#[rustc_on_unimplemented]"
// error message, let's display it!
err.note(&s);
} else {
- // If we can't show anything useful, try to find
- // similar impls.
+ // Can't show anything else useful, try to find similar impls.
let impl_candidates = self.find_similar_impl_candidates(trait_ref);
self.report_similar_impl_candidates(impl_candidates, &mut err);
}
+
+ err.span_label(span,
+ &format!("{}the trait `{}` is not implemented for `{}`",
+ pre_message,
+ trait_ref,
+ trait_ref.self_ty()));
err
}
suggested_limit));
}
}
+
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
}, f)
}
+
+ pub fn consider_optimizing<T: Fn() -> String>(&self, msg: T) -> bool {
+ let cname = self.crate_name(LOCAL_CRATE).as_str();
+ self.sess.consider_optimizing(&cname, msg)
+ }
}
impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> {
use std::fmt;
use std::i64;
use std::iter;
+use std::ops::Deref;
/// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
/// for a target, which contains everything needed to compute layouts.
}
}
+pub trait HasDataLayout: Copy {
+ fn data_layout(&self) -> &TargetDataLayout;
+}
+
+impl<'a> HasDataLayout for &'a TargetDataLayout {
+ fn data_layout(&self) -> &TargetDataLayout {
+ self
+ }
+}
+
/// Endianness of the target, which must match cfg(target-endian).
#[derive(Copy, Clone)]
pub enum Endian {
Size::from_bytes((self.bytes() + mask) & !mask)
}
- pub fn checked_add(self, offset: Size, dl: &TargetDataLayout) -> Option<Size> {
+ pub fn checked_add<C: HasDataLayout>(self, offset: Size, cx: C) -> Option<Size> {
+ let dl = cx.data_layout();
+
// Each Size is less than dl.obj_size_bound(), so the sum is
// also less than 1 << 62 (and therefore can't overflow).
let bytes = self.bytes() + offset.bytes();
}
}
- pub fn checked_mul(self, count: u64, dl: &TargetDataLayout) -> Option<Size> {
+ pub fn checked_mul<C: HasDataLayout>(self, count: u64, cx: C) -> Option<Size> {
+ let dl = cx.data_layout();
+
// Each Size is less than dl.obj_size_bound(), so the sum is
// also less than 1 << 62 (and therefore can't overflow).
match self.bytes().checked_mul(count) {
}
}
- pub fn align(&self, dl: &TargetDataLayout)-> Align {
+ pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
+ let dl = cx.data_layout();
+
match *self {
I1 => dl.i1_align,
I8 => dl.i8_align,
}
/// Find the smallest integer with the given alignment.
- pub fn for_abi_align(dl: &TargetDataLayout, align: Align) -> Option<Integer> {
+ pub fn for_abi_align<C: HasDataLayout>(cx: C, align: Align) -> Option<Integer> {
+ let dl = cx.data_layout();
+
let wanted = align.abi();
for &candidate in &[I8, I16, I32, I64] {
let ty = Int(candidate);
}
/// Get the Integer type from an attr::IntType.
- pub fn from_attr(dl: &TargetDataLayout, ity: attr::IntType) -> Integer {
+ pub fn from_attr<C: HasDataLayout>(cx: C, ity: attr::IntType) -> Integer {
+ let dl = cx.data_layout();
+
match ity {
attr::SignedInt(IntTy::I8) | attr::UnsignedInt(UintTy::U8) => I8,
attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16,
let min_default = I8;
if let Some(ity) = repr.int {
- let discr = Integer::from_attr(&tcx.data_layout, ity);
+ let discr = Integer::from_attr(tcx, ity);
let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
if discr < fit {
bug!("Integer::repr_discr: `#[repr]` hint too small for \
}
impl Primitive {
- pub fn size(self, dl: &TargetDataLayout) -> Size {
+ pub fn size<C: HasDataLayout>(self, cx: C) -> Size {
+ let dl = cx.data_layout();
+
match self {
Int(I1) | Int(I8) => Size::from_bits(8),
Int(I16) => Size::from_bits(16),
}
}
- pub fn align(self, dl: &TargetDataLayout) -> Align {
+ pub fn align<C: HasDataLayout>(self, cx: C) -> Align {
+ let dl = cx.data_layout();
+
match self {
Int(I1) => dl.i1_align,
Int(I8) => dl.i8_align,
}
impl<'a, 'gcx, 'tcx> Struct {
- // FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type.
fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
repr: &ReprOptions, kind: StructKind,
scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
// Neither do 1-member and 2-member structs.
// In addition, code in trans assume that 2-element structs can become pairs.
// It's easier to just short-circuit here.
- let mut can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
- && ! (repr.c || repr.packed);
-
- // Disable field reordering until we can decide what to do.
- // The odd pattern here avoids a warning about the value never being read.
- if can_optimize { can_optimize = false; }
+ let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
+ && !(repr.c || repr.packed || repr.linear || repr.simd);
let (optimize, sort_ascending) = match kind {
StructKind::AlwaysSizedUnivariant => (can_optimize, false),
}
/// Determine whether a structure would be zero-sized, given its fields.
- pub fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
- -> Result<bool, LayoutError<'gcx>>
+ fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
+ -> Result<bool, LayoutError<'gcx>>
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
for field in fields {
let field = field?;
}
impl<'a, 'gcx, 'tcx> Union {
- pub fn new(dl: &TargetDataLayout, packed: bool) -> Union {
+ fn new(dl: &TargetDataLayout, packed: bool) -> Union {
Union {
align: if packed { dl.i8_align } else { dl.aggregate_align },
min_size: Size::from_bytes(0),
}
/// Extend the Struct with more fields.
- pub fn extend<I>(&mut self, dl: &TargetDataLayout,
- fields: I,
- scapegoat: Ty<'gcx>)
- -> Result<(), LayoutError<'gcx>>
+ fn extend<I>(&mut self, dl: &TargetDataLayout,
+ fields: I,
+ scapegoat: Ty<'gcx>)
+ -> Result<(), LayoutError<'gcx>>
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
for (index, field) in fields.enumerate() {
let field = field?;
/// If true, the size is exact, otherwise it's only a lower bound.
sized: bool,
align: Align,
- size: Size
+ element_size: Size,
+ count: u64
},
/// TyRawPtr or TyRef with a !Sized pointee.
// Arrays and slices.
ty::TyArray(element, count) => {
let element = element.layout(infcx)?;
+ let element_size = element.size(dl);
+ // FIXME(eddyb) Don't use host `usize` for array lengths.
+ let usize_count: usize = count;
+ let count = usize_count as u64;
+ if element_size.checked_mul(count, dl).is_none() {
+ return Err(LayoutError::SizeOverflow(ty));
+ }
Array {
sized: true,
align: element.align(dl),
- size: element.size(dl).checked_mul(count as u64, dl)
- .map_or(Err(LayoutError::SizeOverflow(ty)), Ok)?
+ element_size: element_size,
+ count: count
}
}
ty::TySlice(element) => {
+ let element = element.layout(infcx)?;
Array {
sized: false,
- align: element.layout(infcx)?.align(dl),
- size: Size::from_bytes(0)
+ align: element.align(dl),
+ element_size: element.size(dl),
+ count: 0
}
}
ty::TyStr => {
Array {
sized: false,
align: dl.i8_align,
- size: Size::from_bytes(0)
+ element_size: Size::from_bytes(1),
+ count: 0
}
}
}
}
- pub fn size(&self, dl: &TargetDataLayout) -> Size {
+ pub fn size<C: HasDataLayout>(&self, cx: C) -> Size {
+ let dl = cx.data_layout();
+
match *self {
Scalar { value, .. } | RawNullablePointer { value, .. } => {
value.size(dl)
}
Vector { element, count } => {
- let elem_size = element.size(dl);
- let vec_size = match elem_size.checked_mul(count, dl) {
+ let element_size = element.size(dl);
+ let vec_size = match element_size.checked_mul(count, dl) {
Some(size) => size,
None => bug!("Layout::size({:?}): {} * {} overflowed",
- self, elem_size.bytes(), count)
+ self, element_size.bytes(), count)
};
vec_size.abi_align(self.align(dl))
}
+ Array { element_size, count, .. } => {
+ match element_size.checked_mul(count, dl) {
+ Some(size) => size,
+ None => bug!("Layout::size({:?}): {} * {} overflowed",
+ self, element_size.bytes(), count)
+ }
+ }
+
FatPointer { metadata, .. } => {
// Effectively a (ptr, meta) tuple.
Pointer.size(dl).abi_align(metadata.align(dl))
}
CEnum { discr, .. } => Int(discr).size(dl),
- Array { size, .. } | General { size, .. } => size,
+ General { size, .. } => size,
UntaggedUnion { ref variants } => variants.stride(),
Univariant { ref variant, .. } |
}
}
- pub fn align(&self, dl: &TargetDataLayout) -> Align {
+ pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
+ let dl = cx.data_layout();
+
match *self {
Scalar { value, .. } | RawNullablePointer { value, .. } => {
value.align(dl)
}
}
}
+
+ pub fn field_offset<C: HasDataLayout>(&self,
+ cx: C,
+ i: usize,
+ variant_index: Option<usize>)
+ -> Size {
+ let dl = cx.data_layout();
+
+ match *self {
+ Scalar { .. } |
+ CEnum { .. } |
+ UntaggedUnion { .. } |
+ RawNullablePointer { .. } => {
+ Size::from_bytes(0)
+ }
+
+ Vector { element, count } => {
+ let element_size = element.size(dl);
+ let i = i as u64;
+ assert!(i < count);
+ Size::from_bytes(element_size.bytes() * count)
+ }
+
+ Array { element_size, count, .. } => {
+ let i = i as u64;
+ assert!(i < count);
+ Size::from_bytes(element_size.bytes() * count)
+ }
+
+ FatPointer { metadata, .. } => {
+ // Effectively a (ptr, meta) tuple.
+ assert!(i < 2);
+ if i == 0 {
+ Size::from_bytes(0)
+ } else {
+ Pointer.size(dl).abi_align(metadata.align(dl))
+ }
+ }
+
+ Univariant { ref variant, .. } => variant.offsets[i],
+
+ General { ref variants, .. } => {
+ let v = variant_index.expect("variant index required");
+ variants[v].offsets[i + 1]
+ }
+
+ StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
+ if Some(nndiscr as usize) == variant_index {
+ nonnull.offsets[i]
+ } else {
+ Size::from_bytes(0)
+ }
+ }
+ }
+ }
}
/// Type size "skeleton", i.e. the only information determining a type's size.
// First try computing a static layout.
let err = match ty.layout(infcx) {
Ok(layout) => {
- return Ok(SizeSkeleton::Known(layout.size(&tcx.data_layout)));
+ return Ok(SizeSkeleton::Known(layout.size(tcx)));
}
Err(err) => err
};
}
}
}
+
+/// A pair of a type and its layout. Implements various
+/// type traversal APIs (e.g. recursing into fields).
+#[derive(Copy, Clone, Debug)]
+pub struct TyLayout<'tcx> {
+ pub ty: Ty<'tcx>,
+ pub layout: &'tcx Layout,
+ pub variant_index: Option<usize>,
+}
+
+impl<'tcx> Deref for TyLayout<'tcx> {
+ type Target = Layout;
+ fn deref(&self) -> &Layout {
+ self.layout
+ }
+}
+
+pub trait HasTyCtxt<'tcx>: HasDataLayout {
+ fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
+}
+
+impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> {
+ fn data_layout(&self) -> &TargetDataLayout {
+ &self.data_layout
+ }
+}
+
+impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
+ self.global_tcx()
+ }
+}
+
+impl<'a, 'gcx, 'tcx> HasDataLayout for &'a InferCtxt<'a, 'gcx, 'tcx> {
+ fn data_layout(&self) -> &TargetDataLayout {
+ &self.tcx.data_layout
+ }
+}
+
+impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
+ self.tcx.global_tcx()
+ }
+}
+
+pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> {
+ type TyLayout;
+
+ fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
+}
+
+impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
+ type TyLayout = Result<TyLayout<'gcx>, LayoutError<'gcx>>;
+
+ fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout {
+ let ty = normalize_associated_type(self, ty);
+
+ Ok(TyLayout {
+ ty: ty,
+ layout: ty.layout(self)?,
+ variant_index: None
+ })
+ }
+}
+
+impl<'a, 'tcx> TyLayout<'tcx> {
+ pub fn for_variant(&self, variant_index: usize) -> Self {
+ TyLayout {
+ variant_index: Some(variant_index),
+ ..*self
+ }
+ }
+
+ pub fn field_offset<C: HasDataLayout>(&self, cx: C, i: usize) -> Size {
+ self.layout.field_offset(cx, i, self.variant_index)
+ }
+
+ pub fn field_count(&self) -> usize {
+ // Handle enum/union through the type rather than Layout.
+ if let ty::TyAdt(def, _) = self.ty.sty {
+ let v = self.variant_index.unwrap_or(0);
+ if def.variants.is_empty() {
+ assert_eq!(v, 0);
+ return 0;
+ } else {
+ return def.variants[v].fields.len();
+ }
+ }
+
+ match *self.layout {
+ Scalar { .. } => {
+ bug!("TyLayout::field_count({:?}): not applicable", self)
+ }
+
+ // Handled above (the TyAdt case).
+ CEnum { .. } |
+ General { .. } |
+ UntaggedUnion { .. } |
+ RawNullablePointer { .. } |
+ StructWrappedNullablePointer { .. } => bug!(),
+
+ FatPointer { .. } => 2,
+
+ Vector { count, .. } |
+ Array { count, .. } => {
+ let usize_count = count as usize;
+ assert_eq!(usize_count as u64, count);
+ usize_count
+ }
+
+ Univariant { ref variant, .. } => variant.offsets.len(),
+ }
+ }
+
+ pub fn field_type<C: HasTyCtxt<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> {
+ let tcx = cx.tcx();
+
+ let ptr_field_type = |pointee: Ty<'tcx>| {
+ let slice = |element: Ty<'tcx>| {
+ assert!(i < 2);
+ if i == 0 {
+ tcx.mk_mut_ptr(element)
+ } else {
+ tcx.types.usize
+ }
+ };
+ match tcx.struct_tail(pointee).sty {
+ ty::TySlice(element) => slice(element),
+ ty::TyStr => slice(tcx.types.u8),
+ ty::TyDynamic(..) => tcx.mk_mut_ptr(tcx.mk_nil()),
+ _ => bug!("TyLayout::field_type({:?}): not applicable", self)
+ }
+ };
+
+ match self.ty.sty {
+ ty::TyBool |
+ ty::TyChar |
+ ty::TyInt(_) |
+ ty::TyUint(_) |
+ ty::TyFloat(_) |
+ ty::TyFnPtr(_) |
+ ty::TyNever |
+ ty::TyFnDef(..) |
+ ty::TyDynamic(..) => {
+ bug!("TyLayout::field_type({:?}): not applicable", self)
+ }
+
+ // Potentially-fat pointers.
+ ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) |
+ ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
+ ptr_field_type(pointee)
+ }
+ ty::TyAdt(def, _) if def.is_box() => {
+ ptr_field_type(self.ty.boxed_ty())
+ }
+
+ // Arrays and slices.
+ ty::TyArray(element, _) |
+ ty::TySlice(element) => element,
+ ty::TyStr => tcx.types.u8,
+
+ // Tuples and closures.
+ ty::TyClosure(def_id, ref substs) => {
+ substs.upvar_tys(def_id, tcx).nth(i).unwrap()
+ }
+
+ ty::TyTuple(tys, _) => tys[i],
+
+ // SIMD vector types.
+ ty::TyAdt(def, ..) if def.repr.simd => {
+ self.ty.simd_type(tcx)
+ }
+
+ // ADTs.
+ ty::TyAdt(def, substs) => {
+ def.variants[self.variant_index.unwrap_or(0)].fields[i].ty(tcx, substs)
+ }
+
+ ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
+ ty::TyInfer(_) | ty::TyError => {
+ bug!("TyLayout::field_type: unexpected type `{}`", self.ty)
+ }
+ }
+ }
+
+ pub fn field<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> C::TyLayout {
+ cx.layout_of(self.field_type(cx, i))
+ }
+}
pub packed: bool,
pub simd: bool,
pub int: Option<attr::IntType>,
+ // Internal only for now. If true, don't reorder fields.
+ pub linear: bool,
}
impl_stable_hash_for!(struct ReprOptions {
c,
packed,
simd,
- int
+ int,
+ linear
});
impl ReprOptions {
ret.simd = true;
}
+ // This is here instead of layout because the choice must make it into metadata.
+ ret.linear = !tcx.consider_optimizing(|| format!("Reorder fields of {:?}",
+ tcx.item_path_str(did)));
ret
}
use serialize::json::{Json, ToJson};
+macro_rules! linker_flavor {
+ ($(($variant:ident, $string:expr),)+) => {
+ #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash,
+ RustcEncodable, RustcDecodable)]
+ pub enum LinkerFlavor {
+ $($variant,)+
+ }
+
+ impl LinkerFlavor {
+ pub const fn one_of() -> &'static str {
+ concat!("one of: ", $($string, " ",)+)
+ }
+
+ pub fn from_str(s: &str) -> Option<Self> {
+ Some(match s {
+ $($string => LinkerFlavor::$variant,)+
+ _ => return None,
+ })
+ }
+
+ pub fn desc(&self) -> &str {
+ match *self {
+ $(LinkerFlavor::$variant => $string,)+
+ }
+ }
+ }
+
+ impl ToJson for LinkerFlavor {
+ fn to_json(&self) -> Json {
+ self.desc().to_json()
+ }
+ }
+ }
+}
+
+linker_flavor! {
+ (Em, "em"),
+ (Gcc, "gcc"),
+ (Ld, "ld"),
+ (Msvc, "msvc"),
+}
+
#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub enum PanicStrategy {
Unwind,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
use super::apple_ios_base::{opts, Arch};
target_os: "ios".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
features: "+neon,+fp-armv8,+cyclone".to_string(),
eliminate_frame_pointer: false,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
// See https://developer.android.com/ndk/guides/abis.html#arm64-v8a
target_os: "android".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
abi_blacklist: super::arm_base::abi_blacklist(),
.. base
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "freebsd".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
abi_blacklist: super::arm_base::abi_blacklist(),
.. base
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "fuchsia".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
abi_blacklist: super::arm_base::abi_blacklist(),
.. base
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
arch: "aarch64".to_string(),
target_os: "linux".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
abi_blacklist: super::arm_base::abi_blacklist(),
.. base
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::TargetOptions;
pub fn opts() -> TargetOptions {
let mut base = super::linux_base::opts();
// Many of the symbols defined in compiler-rt are also defined in libgcc.
// Android's linker doesn't like that by default.
- base.pre_link_args.push("-Wl,--allow-multiple-definition".to_string());
+ base.pre_link_args
+ .get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--allow-multiple-definition".to_string());
base.is_like_android = true;
base.position_independent_executables = true;
base.has_elf_tls = false;
use std::env;
-use target::TargetOptions;
+use target::{LinkArgs, TargetOptions};
pub fn opts() -> TargetOptions {
// ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
dll_prefix: "lib".to_string(),
dll_suffix: ".dylib".to_string(),
archive_format: "bsd".to_string(),
- pre_link_args: Vec::new(),
+ pre_link_args: LinkArgs::new(),
exe_allocation_crate: super::maybe_jemalloc(),
has_elf_tls: version >= (10, 7),
.. Default::default()
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use std::io;
use std::process::Command;
-use target::TargetOptions;
+use target::{LinkArgs, TargetOptions};
use self::Arch::*;
}
}
-fn build_pre_link_args(arch: Arch) -> Result<Vec<String>, String> {
+fn build_pre_link_args(arch: Arch) -> Result<LinkArgs, String> {
let sdk_name = match arch {
Armv7 | Armv7s | Arm64 => "iphoneos",
I386 | X86_64 => "iphonesimulator"
let sdk_root = get_sdk_root(sdk_name)?;
- Ok(vec!["-arch".to_string(), arch_name.to_string(),
- "-Wl,-syslibroot".to_string(), sdk_root])
+ let mut args = LinkArgs::new();
+ args.insert(LinkerFlavor::Gcc,
+ vec!["-arch".to_string(),
+ arch_name.to_string(),
+ "-Wl,-syslibroot".to_string(),
+ sdk_root]);
+
+ Ok(args)
}
fn target_cpu(arch: Arch) -> String {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "android".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
abi_blacklist: super::arm_base::abi_blacklist(),
.. base
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
features: "+v6".to_string(),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
features: "+v6,+vfp2".to_string(),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "musl".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
abi_blacklist: super::arm_base::abi_blacklist(),
.. base
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "musl".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
abi_blacklist: super::arm_base::abi_blacklist(),
.. base
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
features: "+soft-float".to_string(),
}
})
}
-
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
use super::apple_ios_base::{opts, Arch};
target_os: "ios".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
features: "+v7,+vfp3,+neon".to_string(),
max_atomic_width: Some(64),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
// See https://developer.android.com/ndk/guides/abis.html#v7a
target_os: "android".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
abi_blacklist: super::arm_base::abi_blacklist(),
.. base
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
// Info about features at https://wiki.debian.org/ArmHardFloatPort
}
})
}
-
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "musl".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
abi_blacklist: super::arm_base::abi_blacklist(),
.. base
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
use super::apple_ios_base::{opts, Arch};
target_os: "ios".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
features: "+v7,+vfp4,+neon".to_string(),
max_atomic_width: Some(64),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::{Target, TargetOptions};
+use LinkerFlavor;
+use super::{LinkArgs, Target, TargetOptions};
use super::emscripten_base::{cmd};
pub fn target() -> Result<Target, String> {
+ let mut args = LinkArgs::new();
+ args.insert(LinkerFlavor::Em,
+ vec!["-s".to_string(),
+ "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]);
+
let opts = TargetOptions {
linker: cmd("emcc"),
ar: cmd("emar"),
obj_is_bitcode: true,
is_like_emscripten: true,
max_atomic_width: Some(32),
- post_link_args: vec!["-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
+ post_link_args: args,
target_family: Some("unix".to_string()),
.. Default::default()
};
target_vendor: "unknown".to_string(),
data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
arch: "asmjs".to_string(),
+ linker_flavor: LinkerFlavor::Em,
options: opts,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
use std::default::Default;
pub fn opts() -> TargetOptions {
+ let mut args = LinkArgs::new();
+ args.insert(LinkerFlavor::Gcc, vec![
+ // GNU-style linkers will use this to omit linking to libraries
+ // which don't actually fulfill any relocations, but only for
+ // libraries which follow this flag. Thus, use it before
+ // specifying libraries to link to.
+ "-Wl,--as-needed".to_string(),
+
+ // Always enable NX protection when it is available
+ "-Wl,-z,noexecstack".to_string(),
+ ]);
+
TargetOptions {
dynamic_linking: true,
executables: true,
target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
- pre_link_args: vec![
- // GNU-style linkers will use this to omit linking to libraries
- // which don't actually fulfill any relocations, but only for
- // libraries which follow this flag. Thus, use it before
- // specifying libraries to link to.
- "-Wl,--as-needed".to_string(),
-
- // Always enable NX protection when it is available
- "-Wl,-z,noexecstack".to_string(),
- ],
+ pre_link_args: args,
position_independent_executables: true,
exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
use std::default::Default;
pub fn opts() -> TargetOptions {
+ let mut args = LinkArgs::new();
+ args.insert(LinkerFlavor::Gcc, vec![
+ // GNU-style linkers will use this to omit linking to libraries
+ // which don't actually fulfill any relocations, but only for
+ // libraries which follow this flag. Thus, use it before
+ // specifying libraries to link to.
+ "-Wl,--as-needed".to_string(),
+
+ // Always enable NX protection when it is available
+ "-Wl,-z,noexecstack".to_string(),
+ ]);
+
TargetOptions {
dynamic_linking: true,
executables: true,
target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
- pre_link_args: vec![
- // GNU-style linkers will use this to omit linking to libraries
- // which don't actually fulfill any relocations, but only for
- // libraries which follow this flag. Thus, use it before
- // specifying libraries to link to.
- "-Wl,--as-needed".to_string(),
-
- // Always enable NX protection when it is available
- "-Wl,-z,noexecstack".to_string(),
- ],
+ pre_link_args: args,
position_independent_executables: true,
exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
use std::default::Default;
pub fn opts() -> TargetOptions {
+ let mut args = LinkArgs::new();
+ args.insert(LinkerFlavor::Gcc, vec![
+ // We want to be able to strip as much executable code as possible
+ // from the linker command line, and this flag indicates to the
+ // linker that it can avoid linking in dynamic libraries that don't
+ // actually satisfy any symbols up to that point (as with many other
+ // resolutions the linker does). This option only applies to all
+ // following libraries so we're sure to pass it as one of the first
+ // arguments.
+ // FIXME: figure out whether these linker args are desirable
+ //"-Wl,--as-needed".to_string(),
+
+ // Always enable NX protection when it is available
+ //"-Wl,-z,noexecstack".to_string(),
+ ]);
+
TargetOptions {
dynamic_linking: true,
executables: true,
target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
- pre_link_args: vec![
- // We want to be able to strip as much executable code as possible
- // from the linker command line, and this flag indicates to the
- // linker that it can avoid linking in dynamic libraries that don't
- // actually satisfy any symbols up to that point (as with many other
- // resolutions the linker does). This option only applies to all
- // following libraries so we're sure to pass it as one of the first
- // arguments.
- // FIXME: figure out whether these linker args are desirable
- //"-Wl,--as-needed".to_string(),
-
- // Always enable NX protection when it is available
- //"-Wl,-z,noexecstack".to_string(),
- ],
+ pre_link_args: args,
position_independent_executables: true,
exe_allocation_crate: "alloc_system".to_string(),
has_elf_tls: true,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
use super::apple_ios_base::{opts, Arch};
target_os: "ios".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
max_atomic_width: Some(64),
.. base
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::apple_base::opts();
base.cpu = "yonah".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m32".to_string());
+ base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
Ok(Target {
llvm_target: "i686-apple-darwin".to_string(),
target_os: "macos".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
// See https://developer.android.com/ndk/guides/abis.html#x86
target_os: "android".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
// Mark all dynamic libraries and executables as compatible with the larger 4GiB address
// space available to x86 Windows binaries on x86_64.
- base.pre_link_args.push("-Wl,--large-address-aware".to_string());
+ base.pre_link_args
+ .get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--large-address-aware".to_string());
Ok(Target {
llvm_target: "i686-pc-windows-gnu".to_string(),
target_os: "windows".to_string(),
target_env: "gnu".to_string(),
target_vendor: "pc".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
// Mark all dynamic libraries and executables as compatible with the larger 4GiB address
// space available to x86 Windows binaries on x86_64.
- base.pre_link_args.push("/LARGEADDRESSAWARE".to_string());
+ base.pre_link_args
+ .get_mut(&LinkerFlavor::Msvc).unwrap().push("/LARGEADDRESSAWARE".to_string());
// Ensure the linker will only produce an image if it can also produce a table of
// the image's safe exception handlers.
// https://msdn.microsoft.com/en-us/library/9a89h429.aspx
- base.pre_link_args.push("/SAFESEH".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push("/SAFESEH".to_string());
Ok(Target {
llvm_target: "i686-pc-windows-msvc".to_string(),
target_os: "windows".to_string(),
target_env: "msvc".to_string(),
target_vendor: "pc".to_string(),
+ linker_flavor: LinkerFlavor::Msvc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::dragonfly_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m32".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
Ok(Target {
llvm_target: "i686-unknown-dragonfly".to_string(),
target_os: "dragonfly".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::freebsd_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m32".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
Ok(Target {
llvm_target: "i686-unknown-freebsd".to_string(),
target_os: "freebsd".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::haiku_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m32".to_string());
+ base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
Ok(Target {
llvm_target: "i686-unknown-haiku".to_string(),
target_os: "haiku".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m32".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
Ok(Target {
llvm_target: "i686-unknown-linux-gnu".to_string(),
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::linux_musl_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m32".to_string());
- base.pre_link_args.push("-Wl,-melf_i386".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-melf_i386".to_string());
// The unwinder used by i686-unknown-linux-musl, the LLVM libunwind
// implementation, apparently relies on frame pointers existing... somehow.
target_os: "linux".to_string(),
target_env: "musl".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::netbsd_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m32".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
Ok(Target {
llvm_target: "i686-unknown-netbsdelf".to_string(),
target_os: "netbsd".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::openbsd_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m32".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
Ok(Target {
llvm_target: "i686-unknown-openbsd".to_string(),
target_os: "openbsd".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::{Target, TargetOptions, TargetResult};
+use LinkerFlavor;
+use super::{LinkArgs, Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
+ let mut pre_link_args = LinkArgs::new();
+ pre_link_args.insert(LinkerFlavor::Gcc,
+ vec!["--pnacl-exceptions=sjlj".to_string(),
+ "--target=le32-unknown-nacl".to_string(),
+ "-Wl,--start-group".to_string()]);
+ let mut post_link_args = LinkArgs::new();
+ post_link_args.insert(LinkerFlavor::Gcc,
+ vec!["-Wl,--end-group".to_string()]);
+
let opts = TargetOptions {
linker: "pnacl-clang".to_string(),
ar: "pnacl-ar".to_string(),
- pre_link_args: vec!["--pnacl-exceptions=sjlj".to_string(),
- "--target=le32-unknown-nacl".to_string(),
- "-Wl,--start-group".to_string()],
- post_link_args: vec!["-Wl,--end-group".to_string()],
+ pre_link_args: pre_link_args,
+ post_link_args: post_link_args,
dynamic_linking: false,
executables: true,
exe_suffix: ".pexe".to_string(),
target_vendor: "unknown".to_string(),
data_layout: "e-i64:64:64-p:32:32:32-v128:32:32".to_string(),
arch: "le32".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: opts,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
use std::default::Default;
pub fn opts() -> TargetOptions {
+ let mut args = LinkArgs::new();
+ args.insert(LinkerFlavor::Gcc, vec![
+ // We want to be able to strip as much executable code as possible
+ // from the linker command line, and this flag indicates to the
+ // linker that it can avoid linking in dynamic libraries that don't
+ // actually satisfy any symbols up to that point (as with many other
+ // resolutions the linker does). This option only applies to all
+ // following libraries so we're sure to pass it as one of the first
+ // arguments.
+ "-Wl,--as-needed".to_string(),
+
+ // Always enable NX protection when it is available
+ "-Wl,-z,noexecstack".to_string(),
+ ]);
+
TargetOptions {
dynamic_linking: true,
executables: true,
target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
- pre_link_args: vec![
- // We want to be able to strip as much executable code as possible
- // from the linker command line, and this flag indicates to the
- // linker that it can avoid linking in dynamic libraries that don't
- // actually satisfy any symbols up to that point (as with many other
- // resolutions the linker does). This option only applies to all
- // following libraries so we're sure to pass it as one of the first
- // arguments.
- "-Wl,--as-needed".to_string(),
-
- // Always enable NX protection when it is available
- "-Wl,-z,noexecstack".to_string(),
- ],
+ pre_link_args: args,
position_independent_executables: true,
exe_allocation_crate: super::maybe_jemalloc(),
has_elf_tls: true,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::TargetOptions;
pub fn opts() -> TargetOptions {
// Make sure that the linker/gcc really don't pull in anything, including
// default objects, libs, etc.
- base.pre_link_args.push("-nostdlib".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
// At least when this was tested, the linker would not add the
// `GNU_EH_FRAME` program header to executables generated, which is required
// when unwinding to locate the unwinding information. I'm not sure why this
// argument is *not* necessary for normal builds, but it can't hurt!
- base.pre_link_args.push("-Wl,--eh-frame-hdr".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--eh-frame-hdr".to_string());
// There's a whole bunch of circular dependencies when dealing with MUSL
// unfortunately. To put this in perspective libc is statically linked to
// link everything as a group, not stripping anything out until everything
// is processed. The linker will still perform a pass to strip out object
// files but it won't do so until all objects/archives have been processed.
- base.pre_link_args.push("-Wl,-(".to_string());
- base.post_link_args.push("-Wl,-)".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-(".to_string());
+ base.post_link_args.insert(LinkerFlavor::Gcc, vec!["-Wl,-)".to_string()]);
// When generating a statically linked executable there's generally some
// small setup needed which is listed in these files. These are provided by
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
// NOTE(mips64r2) matches C toolchain
cpu: "mips64r2".to_string(),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
// NOTE(mips64r2) matches C toolchain
cpu: "mips64r2".to_string(),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
cpu: "mips32r2".to_string(),
features: "+mips32r2".to_string(),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "musl".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
cpu: "mips32r2".to_string(),
features: "+mips32r2,+soft-float".to_string(),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "uclibc".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
cpu: "mips32r2".to_string(),
features: "+mips32r2,+soft-float".to_string(),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
cpu: "mips32".to_string(),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "musl".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
cpu: "mips32".to_string(),
features: "+mips32,+soft-float".to_string(),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "uclibc".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
cpu: "mips32".to_string(),
use std::io::prelude::*;
use syntax::abi::{Abi, lookup as lookup_abi};
-use PanicStrategy;
+use {LinkerFlavor, PanicStrategy};
mod android_base;
mod apple_base;
mod fuchsia_base;
mod redox_base;
+pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<String>>;
pub type TargetResult = Result<Target, String>;
macro_rules! supported_targets {
pub arch: String,
/// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
pub data_layout: String,
+ /// Linker flavor
+ pub linker_flavor: LinkerFlavor,
/// Optional settings with defaults.
pub options: TargetOptions,
}
/// Linker arguments that are unconditionally passed *before* any
/// user-defined libraries.
- pub pre_link_args: Vec<String>,
+ pub pre_link_args: LinkArgs,
/// Objects to link before all others, always found within the
/// sysroot folder.
pub pre_link_objects_exe: Vec<String>, // ... when linking an executable
/// Linker arguments that are unconditionally passed after any
/// user-defined but before post_link_objects. Standard platform
/// libraries that should be always be linked to, usually go here.
- pub late_link_args: Vec<String>,
+ pub late_link_args: LinkArgs,
/// Objects to link after all others, always found within the
/// sysroot folder.
pub post_link_objects: Vec<String>,
/// Linker arguments that are unconditionally passed *after* any
/// user-defined libraries.
- pub post_link_args: Vec<String>,
+ pub post_link_args: LinkArgs,
/// Extra arguments to pass to the external assembler (when used)
pub asm_args: Vec<String>,
is_builtin: false,
linker: option_env!("CFG_DEFAULT_LINKER").unwrap_or("cc").to_string(),
ar: option_env!("CFG_DEFAULT_AR").unwrap_or("ar").to_string(),
- pre_link_args: Vec::new(),
- post_link_args: Vec::new(),
+ pre_link_args: LinkArgs::new(),
+ post_link_args: LinkArgs::new(),
asm_args: Vec::new(),
cpu: "generic".to_string(),
features: "".to_string(),
pre_link_objects_exe: Vec::new(),
pre_link_objects_dll: Vec::new(),
post_link_objects: Vec::new(),
- late_link_args: Vec::new(),
+ late_link_args: LinkArgs::new(),
archive_format: "gnu".to_string(),
custom_unwind_resume: false,
lib_allocation_crate: "alloc_system".to_string(),
target_os: get_req_field("os")?,
target_env: get_opt_field("env", ""),
target_vendor: get_opt_field("vendor", "unknown"),
+ linker_flavor: LinkerFlavor::from_str(&*get_req_field("linker-flavor")?)
+ .ok_or_else(|| {
+ format!("linker flavor must be {}", LinkerFlavor::one_of())
+ })?,
options: Default::default(),
};
.map(|s| s.to_string() );
}
} );
+ ($key_name:ident, LinkerFlavor) => ( {
+ let name = (stringify!($key_name)).replace("_", "-");
+ obj.find(&name[..]).and_then(|o| o.as_string().map(|s| {
+ LinkerFlavor::from_str(&s).ok_or_else(|| {
+ Err(format!("'{}' is not a valid value for linker-flavor. \
+ Use 'em', 'gcc', 'ld' or 'msvc.", s))
+ })
+ })).unwrap_or(Ok(()))
+ } );
+ ($key_name:ident, link_args) => ( {
+ let name = (stringify!($key_name)).replace("_", "-");
+ if let Some(obj) = obj.find(&name[..]).and_then(|o| o.as_object()) {
+ let mut args = LinkArgs::new();
+ for (k, v) in obj {
+ let k = LinkerFlavor::from_str(&k).ok_or_else(|| {
+ format!("{}: '{}' is not a valid value for linker-flavor. \
+ Use 'em', 'gcc', 'ld' or 'msvc'", name, k)
+ })?;
+
+ let v = v.as_array().map(|a| {
+ a
+ .iter()
+ .filter_map(|o| o.as_string())
+ .map(|s| s.to_owned())
+ .collect::<Vec<_>>()
+ }).unwrap_or(vec![]);
+
+ args.insert(k, v);
+ }
+ base.options.$key_name = args;
+ }
+ } );
}
key!(is_builtin, bool);
key!(linker);
key!(ar);
- key!(pre_link_args, list);
+ key!(pre_link_args, link_args);
key!(pre_link_objects_exe, list);
key!(pre_link_objects_dll, list);
- key!(late_link_args, list);
+ key!(late_link_args, link_args);
key!(post_link_objects, list);
- key!(post_link_args, list);
+ key!(post_link_args, link_args);
key!(asm_args, list);
key!(cpu);
key!(features);
d.insert(name.to_string(), self.options.$attr.to_json());
}
} );
+ (link_args - $attr:ident) => ( {
+ let name = (stringify!($attr)).replace("_", "-");
+ if default.$attr != self.options.$attr {
+ let obj = self.options.$attr
+ .iter()
+ .map(|(k, v)| (k.desc().to_owned(), v.clone()))
+ .collect::<BTreeMap<_, _>>();
+ d.insert(name.to_string(), obj.to_json());
+ }
+ } );
}
target_val!(llvm_target);
target_val!(target_os, "os");
target_val!(target_env, "env");
target_val!(target_vendor, "vendor");
- target_val!(arch);
target_val!(data_layout);
+ target_val!(linker_flavor);
target_option_val!(is_builtin);
target_option_val!(linker);
target_option_val!(ar);
- target_option_val!(pre_link_args);
+ target_option_val!(link_args - pre_link_args);
target_option_val!(pre_link_objects_exe);
target_option_val!(pre_link_objects_dll);
- target_option_val!(late_link_args);
+ target_option_val!(link_args - late_link_args);
target_option_val!(post_link_objects);
- target_option_val!(post_link_args);
+ target_option_val!(link_args - post_link_args);
target_option_val!(asm_args);
target_option_val!(cpu);
target_option_val!(features);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
use std::default::Default;
pub fn opts() -> TargetOptions {
+ let mut args = LinkArgs::new();
+ args.insert(LinkerFlavor::Gcc, vec![
+ // GNU-style linkers will use this to omit linking to libraries
+ // which don't actually fulfill any relocations, but only for
+ // libraries which follow this flag. Thus, use it before
+ // specifying libraries to link to.
+ "-Wl,--as-needed".to_string(),
+
+ // Always enable NX protection when it is available
+ "-Wl,-z,noexecstack".to_string(),
+ ]);
+
TargetOptions {
dynamic_linking: true,
executables: true,
target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
- pre_link_args: vec![
- // GNU-style linkers will use this to omit linking to libraries
- // which don't actually fulfill any relocations, but only for
- // libraries which follow this flag. Thus, use it before
- // specifying libraries to link to.
- "-Wl,--as-needed".to_string(),
-
- // Always enable NX protection when it is available
- "-Wl,-z,noexecstack".to_string(),
- ],
+ pre_link_args: args,
position_independent_executables: true,
.. Default::default()
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
use std::default::Default;
pub fn opts() -> TargetOptions {
+ let mut args = LinkArgs::new();
+ args.insert(LinkerFlavor::Gcc, vec![
+ // GNU-style linkers will use this to omit linking to libraries
+ // which don't actually fulfill any relocations, but only for
+ // libraries which follow this flag. Thus, use it before
+ // specifying libraries to link to.
+ "-Wl,--as-needed".to_string(),
+
+ // Always enable NX protection when it is available
+ "-Wl,-z,noexecstack".to_string(),
+ ]);
+
TargetOptions {
dynamic_linking: true,
executables: true,
linker_is_gnu: true,
has_rpath: true,
is_like_openbsd: true,
- pre_link_args: vec![
- // GNU-style linkers will use this to omit linking to libraries
- // which don't actually fulfill any relocations, but only for
- // libraries which follow this flag. Thus, use it before
- // specifying libraries to link to.
- "-Wl,--as-needed".to_string(),
-
- // Always enable NX protection when it is available
- "-Wl,-z,noexecstack".to_string(),
- ],
+ pre_link_args: args,
position_independent_executables: true,
exe_allocation_crate: "alloc_system".to_string(),
.. Default::default()
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.cpu = "ppc64".to_string();
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.max_atomic_width = Some(64);
// see #36994
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.cpu = "ppc64le".to_string();
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.max_atomic_width = Some(64);
// see #36994
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
- base.pre_link_args.push("-m32".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
base.max_atomic_width = Some(32);
// see #36994
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use PanicStrategy;
-use target::TargetOptions;
+use {LinkerFlavor, PanicStrategy};
+use target::{LinkArgs, TargetOptions};
use std::default::Default;
pub fn opts() -> TargetOptions {
- TargetOptions {
- pre_link_args: vec![
- // We want to be able to strip as much executable code as possible
- // from the linker command line, and this flag indicates to the
- // linker that it can avoid linking in dynamic libraries that don't
- // actually satisfy any symbols up to that point (as with many other
- // resolutions the linker does). This option only applies to all
- // following libraries so we're sure to pass it as one of the first
- // arguments.
- "-Wl,--as-needed".to_string(),
+ let mut args = LinkArgs::new();
+ args.insert(LinkerFlavor::Gcc, vec![
+ // We want to be able to strip as much executable code as possible
+ // from the linker command line, and this flag indicates to the
+ // linker that it can avoid linking in dynamic libraries that don't
+ // actually satisfy any symbols up to that point (as with many other
+ // resolutions the linker does). This option only applies to all
+ // following libraries so we're sure to pass it as one of the first
+ // arguments.
+ "-Wl,--as-needed".to_string(),
+
+ // Always enable NX protection when it is available
+ "-Wl,-z,noexecstack".to_string()
+ ]);
- // Always enable NX protection when it is available
- "-Wl,-z,noexecstack".to_string()
- ],
+ TargetOptions {
+ pre_link_args: args,
executables: true,
relocation_model: "static".to_string(),
disable_redzone: true,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::netbsd_base::opts();
base.cpu = "v9".to_string();
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.max_atomic_width = Some(64);
Ok(Target {
target_os: "netbsd".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::solaris_base::opts();
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
// llvm calls this "v9"
base.cpu = "v9".to_string();
base.max_atomic_width = Some(64);
target_os: "solaris".to_string(),
target_env: "".to_string(),
target_vendor: "sun".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture)
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "none".to_string(),
target_env: "".to_string(),
target_vendor: "".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
// The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them
// To opt-in to hardware accelerated floating point operations, you can use, for example,
// `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "none".to_string(),
target_env: "".to_string(),
target_vendor: "".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
max_atomic_width: Some(32),
//
// To opt into double precision hardware support, use the `-C target-feature=-fp-only-sp` flag.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "none".to_string(),
target_env: "".to_string(),
target_vendor: "".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
// `+vfp4` is the lowest common denominator between the Cortex-M4 (vfp4-16) and the
// Targets the Cortex-M3 processor (ARMv7-M)
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
target_os: "none".to_string(),
target_env: "".to_string(),
target_vendor: "".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
max_atomic_width: Some(32),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::{Target, TargetOptions};
+use LinkerFlavor;
+use super::{LinkArgs, Target, TargetOptions};
use super::emscripten_base::{cmd};
pub fn target() -> Result<Target, String> {
+ let mut post_link_args = LinkArgs::new();
+ post_link_args.insert(LinkerFlavor::Gcc,
+ vec!["-s".to_string(),
+ "BINARYEN=1".to_string(),
+ "-s".to_string(),
+ "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]);
+
let opts = TargetOptions {
linker: cmd("emcc"),
ar: cmd("emar"),
obj_is_bitcode: true,
is_like_emscripten: true,
max_atomic_width: Some(32),
- post_link_args: vec!["-s".to_string(), "BINARYEN=1".to_string(),
- "-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
+ post_link_args: post_link_args,
target_family: Some("unix".to_string()),
.. Default::default()
};
target_vendor: "unknown".to_string(),
data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
arch: "wasm32".to_string(),
+ linker_flavor: LinkerFlavor::Em,
options: opts,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
use std::default::Default;
pub fn opts() -> TargetOptions {
- TargetOptions {
- // FIXME(#13846) this should be enabled for windows
- function_sections: false,
- linker: "gcc".to_string(),
- dynamic_linking: true,
- executables: true,
- dll_prefix: "".to_string(),
- dll_suffix: ".dll".to_string(),
- exe_suffix: ".exe".to_string(),
- staticlib_prefix: "".to_string(),
- staticlib_suffix: ".lib".to_string(),
- no_default_libraries: true,
- target_family: Some("windows".to_string()),
- is_like_windows: true,
- allows_weak_linkage: false,
- pre_link_args: vec![
+ let mut pre_link_args = LinkArgs::new();
+ pre_link_args.insert(LinkerFlavor::Gcc, vec![
// And here, we see obscure linker flags #45. On windows, it has been
// found to be necessary to have this flag to compile liblibc.
//
// Do not use the standard system startup files or libraries when linking
"-nostdlib".to_string(),
- ],
+ ]);
+
+ let mut late_link_args = LinkArgs::new();
+ late_link_args.insert(LinkerFlavor::Gcc, vec![
+ "-lmingwex".to_string(),
+ "-lmingw32".to_string(),
+ "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc
+ "-lmsvcrt".to_string(),
+ "-luser32".to_string(),
+ "-lkernel32".to_string(),
+ ]);
+
+ TargetOptions {
+ // FIXME(#13846) this should be enabled for windows
+ function_sections: false,
+ linker: "gcc".to_string(),
+ dynamic_linking: true,
+ executables: true,
+ dll_prefix: "".to_string(),
+ dll_suffix: ".dll".to_string(),
+ exe_suffix: ".exe".to_string(),
+ staticlib_prefix: "".to_string(),
+ staticlib_suffix: ".lib".to_string(),
+ no_default_libraries: true,
+ target_family: Some("windows".to_string()),
+ is_like_windows: true,
+ allows_weak_linkage: false,
+ pre_link_args: pre_link_args,
pre_link_objects_exe: vec![
"crt2.o".to_string(), // mingw C runtime initialization for executables
"rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs
"dllcrt2.o".to_string(), // mingw C runtime initialization for dlls
"rsbegin.o".to_string(),
],
- late_link_args: vec![
- "-lmingwex".to_string(),
- "-lmingw32".to_string(),
- "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc
- "-lmsvcrt".to_string(),
- "-luser32".to_string(),
- "-lkernel32".to_string(),
- ],
+ late_link_args: late_link_args,
post_link_objects: vec![
"rsend.o".to_string()
],
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::TargetOptions;
+use LinkerFlavor;
+use target::{LinkArgs, TargetOptions};
use std::default::Default;
pub fn opts() -> TargetOptions {
+ let mut args = LinkArgs::new();
+ args.insert(LinkerFlavor::Msvc,
+ vec!["/NOLOGO".to_string(),
+ "/NXCOMPAT".to_string()]);
+
TargetOptions {
function_sections: true,
linker: "link.exe".to_string(),
target_family: Some("windows".to_string()),
is_like_windows: true,
is_like_msvc: true,
- pre_link_args: vec![
- "/NOLOGO".to_string(),
- "/NXCOMPAT".to_string(),
- ],
+ pre_link_args: args,
exe_allocation_crate: "alloc_system".to_string(),
.. Default::default()
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
base.cpu = "core2".to_string();
base.max_atomic_width = Some(128); // core2 support cmpxchg16b
base.eliminate_frame_pointer = false;
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
Ok(Target {
llvm_target: "x86_64-apple-darwin".to_string(),
target_os: "macos".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};
use super::apple_ios_base::{opts, Arch};
target_os: "ios".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: TargetOptions {
max_atomic_width: Some(64),
.. base
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::windows_base::opts();
base.cpu = "x86-64".to_string();
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.max_atomic_width = Some(64);
Ok(Target {
target_os: "windows".to_string(),
target_env: "gnu".to_string(),
target_vendor: "pc".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
target_os: "windows".to_string(),
target_env: "msvc".to_string(),
target_vendor: "pc".to_string(),
+ linker_flavor: LinkerFlavor::Msvc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::netbsd_base::opts();
base.cpu = "x86-64".to_string();
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.linker = "x86_64-rumprun-netbsd-gcc".to_string();
base.ar = "x86_64-rumprun-netbsd-ar".to_string();
base.max_atomic_width = Some(64);
target_os: "netbsd".to_string(),
target_env: "".to_string(),
target_vendor: "rumprun".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::solaris_base::opts();
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
target_os: "solaris".to_string(),
target_env: "".to_string(),
target_vendor: "sun".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::bitrig_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
Ok(Target {
llvm_target: "x86_64-unknown-bitrig".to_string(),
target_os: "bitrig".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::dragonfly_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
Ok(Target {
llvm_target: "x86_64-unknown-dragonfly".to_string(),
target_os: "dragonfly".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::freebsd_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
Ok(Target {
llvm_target: "x86_64-unknown-freebsd".to_string(),
target_os: "freebsd".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::fuchsia_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
Ok(Target {
llvm_target: "x86_64-unknown-fuchsia".to_string(),
target_os: "fuchsia".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::haiku_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
Ok(Target {
llvm_target: "x86_64-unknown-haiku".to_string(),
target_os: "haiku".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
Ok(Target {
llvm_target: "x86_64-unknown-linux-gnu".to_string(),
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::linux_musl_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
Ok(Target {
llvm_target: "x86_64-unknown-linux-musl".to_string(),
target_os: "linux".to_string(),
target_env: "musl".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::netbsd_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
Ok(Target {
llvm_target: "x86_64-unknown-netbsd".to_string(),
target_os: "netbsd".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::openbsd_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
Ok(Target {
llvm_target: "x86_64-unknown-openbsd".to_string(),
target_os: "openbsd".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::redox_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.push("-m64".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
Ok(Target {
llvm_target: "x86_64-unknown-redox".to_string(),
target_os: "redox".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
use std::mem;
use std::collections::range::RangeArgument;
use std::collections::Bound::{Excluded, Included, Unbounded};
+use std::mem::ManuallyDrop;
pub unsafe trait Array {
type Element;
- type PartialStorage: Default + Unsize<[ManuallyDrop<Self::Element>]>;
+ type PartialStorage: Unsize<[ManuallyDrop<Self::Element>]>;
const LEN: usize;
}
pub fn new() -> Self {
ArrayVec {
count: 0,
- values: Default::default(),
+ values: unsafe { ::std::mem::uninitialized() },
}
}
/// Panics when the stack vector is full.
pub fn push(&mut self, el: A::Element) {
let arr = &mut self.values as &mut [ManuallyDrop<_>];
- arr[self.count] = ManuallyDrop { value: el };
+ arr[self.count] = ManuallyDrop::new(el);
self.count += 1;
}
let arr = &mut self.values as &mut [ManuallyDrop<_>];
self.count -= 1;
unsafe {
- let value = ptr::read(&arr[self.count]);
- Some(value.value)
+ let value = ptr::read(&*arr[self.count]);
+ Some(value)
}
} else {
None
fn next(&mut self) -> Option<A::Element> {
let arr = &self.store as &[ManuallyDrop<_>];
unsafe {
- self.indices.next().map(|i| ptr::read(&arr[i]).value)
+ self.indices.next().map(|i| ptr::read(&*arr[i]))
}
}
#[inline]
fn next(&mut self) -> Option<A::Element> {
- self.iter.next().map(|elt| unsafe { ptr::read(elt as *const ManuallyDrop<_>).value })
+ self.iter.next().map(|elt| unsafe { ptr::read(&**elt) })
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter_mut()
}
}
-
-// FIXME: This should use repr(transparent) from rust-lang/rfcs#1758.
-#[allow(unions_with_drop_fields)]
-pub union ManuallyDrop<T> {
- value: T,
- #[allow(dead_code)]
- empty: (),
-}
-
-impl<T> ManuallyDrop<T> {
- fn new() -> ManuallyDrop<T> {
- ManuallyDrop {
- empty: ()
- }
- }
-}
-
-impl<T> Default for ManuallyDrop<T> {
- fn default() -> Self {
- ManuallyDrop::new()
- }
-}
#![feature(conservative_impl_trait)]
#![feature(discriminant_value)]
#![feature(specialization)]
+#![feature(manually_drop)]
#![cfg_attr(unix, feature(libc))]
#![cfg_attr(test, feature(test))]
control.make_glob_map = resolve::MakeGlobMap::Yes;
}
+ if sess.print_fuel_crate.is_some() {
+ let old_callback = control.compilation_done.callback;
+ control.compilation_done.callback = box move |state| {
+ old_callback(state);
+ let sess = state.session;
+ println!("Fuel used by {}: {}",
+ sess.print_fuel_crate.as_ref().unwrap(),
+ sess.print_fuel.get());
+ }
+ }
control
}
}
use std::io;
use std::rc::Rc;
use term;
+use std::collections::HashMap;
+use std::cmp::min;
/// Emitter trait for emitting errors.
pub trait Emitter {
}
let lo = cm.lookup_char_pos(span_label.span.lo);
let mut hi = cm.lookup_char_pos(span_label.span.hi);
- let mut is_minimized = false;
-
- // If the span is long multi-line, simplify down to the span of one character
- let max_multiline_span_length = 8;
- if lo.line != hi.line && (hi.line - lo.line) > max_multiline_span_length {
- hi.line = lo.line;
- hi.col = CharPos(lo.col.0 + 1);
- is_minimized = true;
- }
// Watch out for "empty spans". If we get a span like 6..6, we
// want to just display a `^` at 6, so convert that to
hi.col = CharPos(lo.col.0 + 1);
}
- let mut ann = Annotation {
- start_col: lo.col.0,
- end_col: hi.col.0,
- is_primary: span_label.is_primary,
- label: span_label.label.clone(),
- annotation_type: AnnotationType::Singleline,
- };
- if is_minimized {
- ann.annotation_type = AnnotationType::Minimized;
- } else if lo.line != hi.line {
+ let ann_type = if lo.line != hi.line {
let ml = MultilineAnnotation {
depth: 1,
line_start: lo.line,
is_primary: span_label.is_primary,
label: span_label.label.clone(),
};
- ann.annotation_type = AnnotationType::Multiline(ml.clone());
- multiline_annotations.push((lo.file.clone(), ml));
+ multiline_annotations.push((lo.file.clone(), ml.clone()));
+ AnnotationType::Multiline(ml)
+ } else {
+ AnnotationType::Singleline
+ };
+ let ann = Annotation {
+ start_col: lo.col.0,
+ end_col: hi.col.0,
+ is_primary: span_label.is_primary,
+ label: span_label.label.clone(),
+ annotation_type: ann_type,
};
if !ann.is_multiline() {
max_depth = ann.depth;
}
add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start());
- for line in ann.line_start + 1..ann.line_end {
+ let middle = min(ann.line_start + 4, ann.line_end);
+ for line in ann.line_start + 1..middle {
add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
}
+ if middle < ann.line_end - 1 {
+ for line in ann.line_end - 1..ann.line_end {
+ add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
+ }
+ }
add_annotation_to_file(&mut output, file, ann.line_end, ann.as_end());
}
for file_vec in output.iter_mut() {
file: Rc<FileMap>,
line: &Line,
width_offset: usize,
- multiline_depth: usize) {
+ code_offset: usize) -> Vec<(usize, Style)> {
let source_string = file.get_line(line.line_index - 1)
.unwrap_or("");
let line_offset = buffer.num_lines();
- let code_offset = if multiline_depth == 0 {
- width_offset
- } else {
- width_offset + multiline_depth + 1
- };
// First create the source line we will highlight.
buffer.puts(line_offset, code_offset, &source_string, Style::Quotation);
// previous borrow of `vec` occurs here
//
// For this reason, we group the lines into "highlight lines"
- // and "annotations lines", where the highlight lines have the `~`.
+ // and "annotations lines", where the highlight lines have the `^`.
// Sort the annotations by (start, end col)
let mut annotations = line.annotations.clone();
// If there are no annotations or the only annotations on this line are
// MultilineLine, then there's only code being shown, stop processing.
if line.annotations.is_empty() || line.annotations.iter()
- .filter(|a| {
- // Set the multiline annotation vertical lines to the left of
- // the code in this line.
- if let AnnotationType::MultilineLine(depth) = a.annotation_type {
- buffer.putc(line_offset,
- width_offset + depth - 1,
- '|',
- if a.is_primary {
- Style::UnderlinePrimary
- } else {
- Style::UnderlineSecondary
- });
- false
- } else {
- true
- }
- }).collect::<Vec<_>>().len() == 0
+ .filter(|a| !a.is_line()).collect::<Vec<_>>().len() == 0
{
- return;
+ return vec![];
}
// Write the colunmn separator.
}
}
- // Write the vertical lines for multiline spans and for labels that are
- // on a different line as the underline.
+ // Write the vertical lines for labels that are on a different line as the underline.
//
// After this we will have:
//
// | __________
// | | |
// | |
- // 3 | |
+ // 3 |
// 4 | | }
// | |_
for &(pos, annotation) in &annotations_position {
style);
}
}
- AnnotationType::MultilineLine(depth) => {
- // the first line will have already be filled when we checked
- // wether there were any annotations for this line.
- for p in line_offset + 1..line_offset + line_len + 2 {
- buffer.putc(p,
- width_offset + depth - 1,
- '|',
- style);
- }
- }
_ => (),
}
}
//
// 2 | fn foo() {
// | __________ starting here...
- // | | |
- // | | something about `foo`
- // 3 | |
- // 4 | | }
- // | |_ ...ending here: test
+ // | |
+ // | something about `foo`
+ // 3 |
+ // 4 | }
+ // | _ ...ending here: test
for &(pos, annotation) in &annotations_position {
let style = if annotation.is_primary {
Style::LabelPrimary
//
// 2 | fn foo() {
// | ____-_____^ starting here...
- // | | |
- // | | something about `foo`
- // 3 | |
- // 4 | | }
- // | |_^ ...ending here: test
+ // | |
+ // | something about `foo`
+ // 3 |
+ // 4 | }
+ // | _^ ...ending here: test
for &(_, annotation) in &annotations_position {
let (underline, style) = if annotation.is_primary {
('^', Style::UnderlinePrimary)
style);
}
}
+ annotations_position.iter().filter_map(|&(_, annotation)| {
+ match annotation.annotation_type {
+ AnnotationType::MultilineStart(p) | AnnotationType::MultilineEnd(p) => {
+ let style = if annotation.is_primary {
+ Style::LabelPrimary
+ } else {
+ Style::LabelSecondary
+ };
+ Some((p, style))
+ },
+ _ => None
+ }
+
+ }).collect::<Vec<_>>()
}
fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize {
let buffer_msg_line_offset = buffer.num_lines();
draw_col_separator_no_space(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
+ // Contains the vertical lines' positions for active multiline annotations
+ let mut multilines = HashMap::new();
+
// Next, output the annotate source for this file
for line_idx in 0..annotated_file.lines.len() {
- self.render_source_line(&mut buffer,
- annotated_file.file.clone(),
- &annotated_file.lines[line_idx],
- 3 + max_line_num_len,
- annotated_file.multiline_depth);
+ let previous_buffer_line = buffer.num_lines();
+
+ let width_offset = 3 + max_line_num_len;
+ let code_offset = if annotated_file.multiline_depth == 0 {
+ width_offset
+ } else {
+ width_offset + annotated_file.multiline_depth + 1
+ };
+
+ let depths = self.render_source_line(&mut buffer,
+ annotated_file.file.clone(),
+ &annotated_file.lines[line_idx],
+ width_offset,
+ code_offset);
+ let mut to_add = HashMap::new();
+
+ for (depth, style) in depths {
+ if multilines.get(&depth).is_some() {
+ multilines.remove(&depth);
+ } else {
+ to_add.insert(depth, style);
+ }
+ }
+
+ // Set the multiline annotation vertical lines to the left of
+ // the code in this line.
+ for (depth, style) in &multilines {
+ for line in previous_buffer_line..buffer.num_lines() {
+ draw_multiline_line(&mut buffer,
+ line,
+ width_offset,
+ *depth,
+ *style);
+ }
+ }
// check to see if we need to print out or elide lines that come between
- // this annotated line and the next one
+ // this annotated line and the next one.
if line_idx < (annotated_file.lines.len() - 1) {
let line_idx_delta = annotated_file.lines[line_idx + 1].line_index -
annotated_file.lines[line_idx].line_index;
if line_idx_delta > 2 {
let last_buffer_line_num = buffer.num_lines();
buffer.puts(last_buffer_line_num, 0, "...", Style::LineNumber);
+
+ // Set the multiline annotation vertical lines on `...` bridging line.
+ for (depth, style) in &multilines {
+ draw_multiline_line(&mut buffer,
+ last_buffer_line_num,
+ width_offset,
+ *depth,
+ *style);
+ }
} else if line_idx_delta == 2 {
let unannotated_line = annotated_file.file
.get_line(annotated_file.lines[line_idx].line_index)
Style::LineNumber);
draw_col_separator(&mut buffer, last_buffer_line_num, 1 + max_line_num_len);
buffer.puts(last_buffer_line_num,
- 3 + max_line_num_len,
+ code_offset,
&unannotated_line,
Style::Quotation);
+
+ for (depth, style) in &multilines {
+ draw_multiline_line(&mut buffer,
+ last_buffer_line_num,
+ width_offset,
+ *depth,
+ *style);
+ }
}
}
+
+ multilines.extend(&to_add);
}
}
buffer.puts(line, col, "= ", Style::LineNumber);
}
+fn draw_multiline_line(buffer: &mut StyledBuffer,
+ line: usize,
+ offset: usize,
+ depth: usize,
+ style: Style)
+{
+ buffer.putc(line, offset + depth - 1, '|', style);
+}
+
fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclusive: bool) -> bool {
let extra = if inclusive {
1
/// Annotation under a single line of code
Singleline,
- /// Annotation under the first character of a multiline span
- Minimized,
-
/// Annotation enclosing the first and last character of a multiline span
Multiline(MultilineAnnotation),
/// Annotation marking the last character of a fully shown multiline span
MultilineEnd(usize),
/// Line at the left enclosing the lines of a fully shown multiline span
+ // Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
+ // and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
+ // `draw_multiline_line`.
MultilineLine(usize),
}
}
impl Annotation {
- pub fn is_minimized(&self) -> bool {
- match self.annotation_type {
- AnnotationType::Minimized => true,
- _ => false,
- }
- }
-
/// Wether this annotation is a vertical line placeholder.
pub fn is_line(&self) -> bool {
if let AnnotationType::MultilineLine(_) = self.annotation_type {
});
if let Layout::General { ref variants, ref size, discr, .. } = *layout {
- let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes();
+ let discr_size = Primitive::Int(discr).size(cx.tcx).bytes();
debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
t, size.bytes(), layout);
// hack around this by replacing the host triple with the target and pray
// that those -L directories are the same!
let mut cmd = Command::new(&llvm_config);
+ if let Some(link_arg) = llvm_link_arg {
+ cmd.arg(link_arg);
+ }
cmd.arg("--ldflags");
for lib in output(&mut cmd).split_whitespace() {
if lib.starts_with("-LIBPATH:") {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace};
+use llvm::{self, ValueRef, AttributePlace};
use base;
use builder::Builder;
use common::{type_is_fat_ptr, C_uint};
use cabi_sparc64;
use cabi_nvptx;
use cabi_nvptx64;
-use machine::{llalign_of_min, llsize_of, llsize_of_alloc};
+use machine::llalign_of_min;
use type_::Type;
use type_of;
use rustc::hir;
use rustc::ty::{self, Ty};
+use rustc::ty::layout::{self, Layout, LayoutTyper, TyLayout, Size};
use libc::c_uint;
use std::cmp;
+use std::iter;
pub use syntax::abi::Abi;
pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
-use rustc::ty::layout::Layout;
#[derive(Clone, Copy, PartialEq, Debug)]
enum ArgKind {
}
}
}
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum RegKind {
+ Integer,
+ Float,
+ Vector
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct Reg {
+ pub kind: RegKind,
+ pub size: Size,
+}
+
+macro_rules! reg_ctor {
+ ($name:ident, $kind:ident, $bits:expr) => {
+ pub fn $name() -> Reg {
+ Reg {
+ kind: RegKind::$kind,
+ size: Size::from_bits($bits)
+ }
+ }
+ }
+}
+
+impl Reg {
+ reg_ctor!(i8, Integer, 8);
+ reg_ctor!(i16, Integer, 16);
+ reg_ctor!(i32, Integer, 32);
+ reg_ctor!(i64, Integer, 64);
+
+ reg_ctor!(f32, Float, 32);
+ reg_ctor!(f64, Float, 64);
+}
+
+impl Reg {
+ fn llvm_type(&self, ccx: &CrateContext) -> Type {
+ match self.kind {
+ RegKind::Integer => Type::ix(ccx, self.size.bits()),
+ RegKind::Float => {
+ match self.size.bits() {
+ 32 => Type::f32(ccx),
+ 64 => Type::f64(ccx),
+ _ => bug!("unsupported float: {:?}", self)
+ }
+ }
+ RegKind::Vector => {
+ Type::vector(&Type::i8(ccx), self.size.bytes())
+ }
+ }
+ }
+}
+
+/// An argument passed entirely registers with the
+/// same kind (e.g. HFA / HVA on PPC64 and AArch64).
+#[derive(Copy, Clone)]
+pub struct Uniform {
+ pub unit: Reg,
+
+ /// The total size of the argument, which can be:
+ /// * equal to `unit.size` (one scalar/vector)
+ /// * a multiple of `unit.size` (an array of scalar/vectors)
+ /// * if `unit.kind` is `Integer`, the last element
+ /// can be shorter, i.e. `{ i64, i64, i32 }` for
+ /// 64-bit integers with a total size of 20 bytes
+ pub total: Size,
+}
+
+impl From<Reg> for Uniform {
+ fn from(unit: Reg) -> Uniform {
+ Uniform {
+ unit,
+ total: unit.size
+ }
+ }
+}
+
+impl Uniform {
+ fn llvm_type(&self, ccx: &CrateContext) -> Type {
+ let llunit = self.unit.llvm_type(ccx);
+
+ if self.total <= self.unit.size {
+ return llunit;
+ }
+
+ let count = self.total.bytes() / self.unit.size.bytes();
+ let rem_bytes = self.total.bytes() % self.unit.size.bytes();
+
+ if rem_bytes == 0 {
+ return Type::array(&llunit, count);
+ }
+
+ // Only integers can be really split further.
+ assert_eq!(self.unit.kind, RegKind::Integer);
+
+ let args: Vec<_> = (0..count).map(|_| llunit)
+ .chain(iter::once(Type::ix(ccx, rem_bytes * 8)))
+ .collect();
+
+ Type::struct_(ccx, &args, false)
+ }
+}
+
+pub trait LayoutExt<'tcx> {
+ fn is_aggregate(&self) -> bool;
+ fn homogenous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option<Reg>;
+}
+
+impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
+ fn is_aggregate(&self) -> bool {
+ match *self.layout {
+ Layout::Scalar { .. } |
+ Layout::RawNullablePointer { .. } |
+ Layout::CEnum { .. } |
+ Layout::Vector { .. } => false,
+
+ Layout::Array { .. } |
+ Layout::FatPointer { .. } |
+ Layout::Univariant { .. } |
+ Layout::UntaggedUnion { .. } |
+ Layout::General { .. } |
+ Layout::StructWrappedNullablePointer { .. } => true
+ }
+ }
+
+ fn homogenous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option<Reg> {
+ match *self.layout {
+ // The primitives for this algorithm.
+ Layout::Scalar { value, .. } |
+ Layout::RawNullablePointer { value, .. } => {
+ let kind = match value {
+ layout::Int(_) |
+ layout::Pointer => RegKind::Integer,
+ layout::F32 |
+ layout::F64 => RegKind::Float
+ };
+ Some(Reg {
+ kind,
+ size: self.size(ccx)
+ })
+ }
+
+ Layout::CEnum { .. } => {
+ Some(Reg {
+ kind: RegKind::Integer,
+ size: self.size(ccx)
+ })
+ }
+
+ Layout::Vector { .. } => {
+ Some(Reg {
+ kind: RegKind::Integer,
+ size: self.size(ccx)
+ })
+ }
+
+ Layout::Array { count, .. } => {
+ if count > 0 {
+ self.field(ccx, 0).homogenous_aggregate(ccx)
+ } else {
+ None
+ }
+ }
+
+ Layout::Univariant { ref variant, .. } => {
+ let mut unaligned_offset = Size::from_bytes(0);
+ let mut result = None;
+
+ for i in 0..self.field_count() {
+ if unaligned_offset != variant.offsets[i] {
+ return None;
+ }
+
+ let field = self.field(ccx, i);
+ match (result, field.homogenous_aggregate(ccx)) {
+ // The field itself must be a homogenous aggregate.
+ (_, None) => return None,
+ // If this is the first field, record the unit.
+ (None, Some(unit)) => {
+ result = Some(unit);
+ }
+ // For all following fields, the unit must be the same.
+ (Some(prev_unit), Some(unit)) => {
+ if prev_unit != unit {
+ return None;
+ }
+ }
+ }
+
+ // Keep track of the offset (without padding).
+ let size = field.size(ccx);
+ match unaligned_offset.checked_add(size, ccx) {
+ Some(offset) => unaligned_offset = offset,
+ None => return None
+ }
+ }
+
+ // There needs to be no padding.
+ if unaligned_offset != self.size(ccx) {
+ None
+ } else {
+ result
+ }
+ }
+
+ Layout::UntaggedUnion { .. } => {
+ let mut max = Size::from_bytes(0);
+ let mut result = None;
+
+ for i in 0..self.field_count() {
+ let field = self.field(ccx, i);
+ match (result, field.homogenous_aggregate(ccx)) {
+ // The field itself must be a homogenous aggregate.
+ (_, None) => return None,
+ // If this is the first field, record the unit.
+ (None, Some(unit)) => {
+ result = Some(unit);
+ }
+ // For all following fields, the unit must be the same.
+ (Some(prev_unit), Some(unit)) => {
+ if prev_unit != unit {
+ return None;
+ }
+ }
+ }
+
+ // Keep track of the offset (without padding).
+ let size = field.size(ccx);
+ if size > max {
+ max = size;
+ }
+ }
+
+ // There needs to be no padding.
+ if max != self.size(ccx) {
+ None
+ } else {
+ result
+ }
+ }
+
+ // Rust-specific types, which we can ignore for C ABIs.
+ Layout::FatPointer { .. } |
+ Layout::General { .. } |
+ Layout::StructWrappedNullablePointer { .. } => None
+ }
+ }
+}
+
+pub enum CastTarget {
+ Uniform(Uniform),
+ Pair(Reg, Reg)
+}
+
+impl From<Reg> for CastTarget {
+ fn from(unit: Reg) -> CastTarget {
+ CastTarget::Uniform(Uniform::from(unit))
+ }
+}
+
+impl From<Uniform> for CastTarget {
+ fn from(uniform: Uniform) -> CastTarget {
+ CastTarget::Uniform(uniform)
+ }
+}
+
+impl CastTarget {
+ fn llvm_type(&self, ccx: &CrateContext) -> Type {
+ match *self {
+ CastTarget::Uniform(u) => u.llvm_type(ccx),
+ CastTarget::Pair(a, b) => {
+ Type::struct_(ccx, &[
+ a.llvm_type(ccx),
+ b.llvm_type(ccx)
+ ], false)
+ }
+ }
+ }
+}
/// Information about how a specific C type
/// should be passed to or returned from a function
///
/// This is borrowed from clang's ABIInfo.h
#[derive(Clone, Copy, Debug)]
-pub struct ArgType {
+pub struct ArgType<'tcx> {
kind: ArgKind,
- /// Original LLVM type
- pub original_ty: Type,
- /// Sizing LLVM type (pointers are opaque).
- /// Unlike original_ty, this is guaranteed to be complete.
- ///
- /// For example, while we're computing the function pointer type in
- /// `struct Foo(fn(Foo));`, `original_ty` is still LLVM's `%Foo = {}`.
- /// The field type will likely end up being `void(%Foo)*`, but we cannot
- /// use `%Foo` to compute properties (e.g. size and alignment) of `Foo`,
- /// until `%Foo` is completed by having all of its field types inserted,
- /// so `ty` holds the "sizing type" of `Foo`, which replaces all pointers
- /// with opaque ones, resulting in `{i8*}` for `Foo`.
- /// ABI-specific logic can then look at the size, alignment and fields of
- /// `{i8*}` in order to determine how the argument will be passed.
- /// Only later will `original_ty` aka `%Foo` be used in the LLVM function
- /// pointer type, without ever having introspected it.
- pub ty: Type,
- /// Signedness for integer types, None for other types
- pub signedness: Option<bool>,
+ pub layout: TyLayout<'tcx>,
/// Coerced LLVM Type
pub cast: Option<Type>,
/// Dummy argument, which is emitted before the real argument
pub attrs: ArgAttributes
}
-impl ArgType {
- fn new(original_ty: Type, ty: Type) -> ArgType {
+impl<'a, 'tcx> ArgType<'tcx> {
+ fn new(layout: TyLayout<'tcx>) -> ArgType<'tcx> {
ArgType {
kind: ArgKind::Direct,
- original_ty: original_ty,
- ty: ty,
- signedness: None,
+ layout: layout,
cast: None,
pad: None,
attrs: ArgAttributes::default()
}
}
- pub fn make_indirect(&mut self, ccx: &CrateContext) {
+ pub fn make_indirect(&mut self, ccx: &CrateContext<'a, 'tcx>) {
assert_eq!(self.kind, ArgKind::Direct);
// Wipe old attributes, likely not valid through indirection.
self.attrs = ArgAttributes::default();
- let llarg_sz = llsize_of_alloc(ccx, self.ty);
+ let llarg_sz = self.layout.size(ccx).bytes();
// For non-immediate arguments the callee gets its own copy of
// the value on the stack, so there are no aliases. It's also
pub fn extend_integer_width_to(&mut self, bits: u64) {
// Only integers have signedness
- if let Some(signed) = self.signedness {
- if self.ty.int_width() < bits {
- self.attrs.set(if signed {
- ArgAttribute::SExt
- } else {
- ArgAttribute::ZExt
- });
+ let (i, signed) = match *self.layout {
+ Layout::Scalar { value, .. } => {
+ match value {
+ layout::Int(i) => {
+ if self.layout.ty.is_integral() {
+ (i, self.layout.ty.is_signed())
+ } else {
+ return;
+ }
+ }
+ _ => return
+ }
}
+
+ // Rust enum types that map onto C enums also need to follow
+ // the target ABI zero-/sign-extension rules.
+ Layout::CEnum { discr, signed, .. } => (discr, signed),
+
+ _ => return
+ };
+
+ if i.size().bits() < bits {
+ self.attrs.set(if signed {
+ ArgAttribute::SExt
+ } else {
+ ArgAttribute::ZExt
+ });
}
}
+ pub fn cast_to<T: Into<CastTarget>>(&mut self, ccx: &CrateContext, target: T) {
+ self.cast = Some(target.into().llvm_type(ccx));
+ }
+
+ pub fn pad_with(&mut self, ccx: &CrateContext, reg: Reg) {
+ self.pad = Some(reg.llvm_type(ccx));
+ }
+
pub fn is_indirect(&self) -> bool {
self.kind == ArgKind::Indirect
}
self.kind == ArgKind::Ignore
}
+ /// Get the LLVM type for an lvalue of the original Rust type of
+ /// this argument/return, i.e. the result of `type_of::type_of`.
+ pub fn memory_ty(&self, ccx: &CrateContext<'a, 'tcx>) -> Type {
+ type_of::type_of(ccx, self.layout.ty)
+ }
+
/// Store a direct/indirect value described by this ArgType into a
/// lvalue for the original Rust type of this argument/return.
/// Can be used for both storing formal arguments into Rust variables
/// or results of call/invoke instructions into their destinations.
- pub fn store(&self, bcx: &Builder, mut val: ValueRef, dst: ValueRef) {
+ pub fn store(&self, bcx: &Builder<'a, 'tcx>, mut val: ValueRef, dst: ValueRef) {
if self.is_ignore() {
return;
}
let ccx = bcx.ccx;
if self.is_indirect() {
- let llsz = llsize_of(ccx, self.ty);
- let llalign = llalign_of_min(ccx, self.ty);
+ let llsz = C_uint(ccx, self.layout.size(ccx).bytes());
+ let llalign = self.layout.align(ccx).abi();
base::call_memcpy(bcx, dst, val, llsz, llalign as u32);
} else if let Some(ty) = self.cast {
// FIXME(eddyb): Figure out when the simpler Store is safe, clang
let can_store_through_cast_ptr = false;
if can_store_through_cast_ptr {
let cast_dst = bcx.pointercast(dst, ty.ptr_to());
- let llalign = llalign_of_min(ccx, self.ty);
- bcx.store(val, cast_dst, Some(llalign));
+ let llalign = self.layout.align(ccx).abi();
+ bcx.store(val, cast_dst, Some(llalign as u32));
} else {
// The actual return type is a struct, but the ABI
// adaptation code has cast it into some scalar type. The
base::call_memcpy(bcx,
bcx.pointercast(dst, Type::i8p(ccx)),
bcx.pointercast(llscratch, Type::i8p(ccx)),
- C_uint(ccx, llsize_of_alloc(ccx, self.ty)),
- cmp::min(llalign_of_min(ccx, self.ty),
- llalign_of_min(ccx, ty)) as u32);
+ C_uint(ccx, self.layout.size(ccx).bytes()),
+ cmp::min(self.layout.align(ccx).abi() as u32,
+ llalign_of_min(ccx, ty)));
base::Lifetime::End.call(bcx, llscratch);
}
} else {
- if self.original_ty == Type::i1(ccx) {
+ if self.layout.ty == ccx.tcx().types.bool {
val = bcx.zext(val, Type::i8(ccx));
}
bcx.store(val, dst, None);
}
}
- pub fn store_fn_arg(&self, bcx: &Builder, idx: &mut usize, dst: ValueRef) {
+ pub fn store_fn_arg(&self, bcx: &Builder<'a, 'tcx>, idx: &mut usize, dst: ValueRef) {
if self.pad.is_some() {
*idx += 1;
}
/// I will do my best to describe this structure, but these
/// comments are reverse-engineered and may be inaccurate. -NDM
#[derive(Clone, Debug)]
-pub struct FnType {
+pub struct FnType<'tcx> {
/// The LLVM types of each argument.
- pub args: Vec<ArgType>,
+ pub args: Vec<ArgType<'tcx>>,
/// LLVM return type.
- pub ret: ArgType,
+ pub ret: ArgType<'tcx>,
pub variadic: bool,
pub cconv: llvm::CallConv
}
-impl FnType {
- pub fn new<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> FnType {
+impl<'a, 'tcx> FnType<'tcx> {
+ pub fn new(ccx: &CrateContext<'a, 'tcx>,
+ sig: ty::FnSig<'tcx>,
+ extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
fn_ty.adjust_for_abi(ccx, sig);
fn_ty
}
- pub fn new_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> FnType {
+ pub fn new_vtable(ccx: &CrateContext<'a, 'tcx>,
+ sig: ty::FnSig<'tcx>,
+ extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
// Don't pass the vtable, it's not an argument of the virtual fn.
fn_ty.args[1].ignore();
fn_ty
}
- fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> FnType {
+ pub fn unadjusted(ccx: &CrateContext<'a, 'tcx>,
+ sig: ty::FnSig<'tcx>,
+ extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
use self::Abi::*;
let cconv = match ccx.sess().target.target.adjust_abi(sig.abi) {
RustIntrinsic | PlatformIntrinsic |
};
let arg_of = |ty: Ty<'tcx>, is_return: bool| {
+ let mut arg = ArgType::new(ccx.layout_of(ty));
if ty.is_bool() {
- let llty = Type::i1(ccx);
- let mut arg = ArgType::new(llty, llty);
arg.attrs.set(ArgAttribute::ZExt);
- arg
} else {
- let mut arg = ArgType::new(type_of::type_of(ccx, ty),
- type_of::sizing_type_of(ccx, ty));
- if ty.is_integral() {
- arg.signedness = Some(ty.is_signed());
- }
- // Rust enum types that map onto C enums also need to follow
- // the target ABI zero-/sign-extension rules.
- if let Layout::CEnum { signed, .. } = *ccx.layout_of(ty) {
- arg.signedness = Some(signed);
- }
- if llsize_of_alloc(ccx, arg.ty) == 0 {
+ if arg.layout.size(ccx).bytes() == 0 {
// For some forsaken reason, x86_64-pc-windows-gnu
// doesn't ignore zero-sized struct arguments.
// The same is true for s390x-unknown-linux-gnu.
arg.ignore();
}
}
- arg
}
+ arg
};
let ret_ty = sig.output();
match ret_ty.sty {
// These are not really pointers but pairs, (pointer, len)
ty::TyRef(_, ty::TypeAndMut { ty, .. }) => {
- let llty = type_of::sizing_type_of(ccx, ty);
- let llsz = llsize_of_alloc(ccx, llty);
- ret.attrs.set_dereferenceable(llsz);
+ ret.attrs.set_dereferenceable(ccx.size_of(ty));
}
ty::TyAdt(def, _) if def.is_box() => {
- let llty = type_of::sizing_type_of(ccx, ret_ty.boxed_ty());
- let llsz = llsize_of_alloc(ccx, llty);
- ret.attrs.set_dereferenceable(llsz);
+ ret.attrs.set_dereferenceable(ccx.size_of(ret_ty.boxed_ty()));
}
_ => {}
}
for ty in inputs.iter().chain(extra_args.iter()) {
let mut arg = arg_of(ty, false);
- if type_is_fat_ptr(ccx, ty) {
- let original_tys = arg.original_ty.field_types();
- let sizing_tys = arg.ty.field_types();
- assert_eq!((original_tys.len(), sizing_tys.len()), (2, 2));
-
- let mut data = ArgType::new(original_tys[0], sizing_tys[0]);
- let mut info = ArgType::new(original_tys[1], sizing_tys[1]);
+ if let ty::layout::FatPointer { .. } = *arg.layout {
+ let mut data = ArgType::new(arg.layout.field(ccx, 0));
+ let mut info = ArgType::new(arg.layout.field(ccx, 1));
if let Some(inner) = rust_ptr_attrs(ty, &mut data) {
data.attrs.set(ArgAttribute::NonNull);
args.push(info);
} else {
if let Some(inner) = rust_ptr_attrs(ty, &mut arg) {
- let llty = type_of::sizing_type_of(ccx, inner);
- let llsz = llsize_of_alloc(ccx, llty);
- arg.attrs.set_dereferenceable(llsz);
+ arg.attrs.set_dereferenceable(ccx.size_of(inner));
}
args.push(arg);
}
}
}
- fn adjust_for_abi<'a, 'tcx>(&mut self,
- ccx: &CrateContext<'a, 'tcx>,
- sig: ty::FnSig<'tcx>) {
+ fn adjust_for_abi(&mut self,
+ ccx: &CrateContext<'a, 'tcx>,
+ sig: ty::FnSig<'tcx>) {
let abi = sig.abi;
if abi == Abi::Unadjusted { return }
if abi == Abi::Rust || abi == Abi::RustCall ||
abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
- let fixup = |arg: &mut ArgType| {
- let mut llty = arg.ty;
-
- // Replace newtypes with their inner-most type.
- while llty.kind() == llvm::TypeKind::Struct {
- let inner = llty.field_types();
- if inner.len() != 1 {
- break;
- }
- llty = inner[0];
+ let fixup = |arg: &mut ArgType<'tcx>| {
+ if !arg.layout.is_aggregate() {
+ return;
}
- if !llty.is_aggregate() {
- // Scalars and vectors, always immediate.
- if llty != arg.ty {
+ let size = arg.layout.size(ccx);
+
+ if let Some(unit) = arg.layout.homogenous_aggregate(ccx) {
+ // Replace newtypes with their inner-most type.
+ if unit.size == size {
// Needs a cast as we've unpacked a newtype.
- arg.cast = Some(llty);
+ arg.cast_to(ccx, unit);
+ return;
+ }
+
+ // Pairs of floats.
+ if unit.kind == RegKind::Float {
+ if unit.size.checked_mul(2, ccx) == Some(size) {
+ // FIXME(eddyb) This should be using Uniform instead of a pair,
+ // but the resulting [2 x float/double] breaks emscripten.
+ // See https://github.com/kripken/emscripten-fastcomp/issues/178.
+ arg.cast_to(ccx, CastTarget::Pair(unit, unit));
+ return;
+ }
}
- return;
}
- let size = llsize_of_alloc(ccx, llty);
- if size > llsize_of_alloc(ccx, ccx.int_type()) {
+ if size > layout::Pointer.size(ccx) {
arg.make_indirect(ccx);
- } else if size > 0 {
+ } else {
// We want to pass small aggregates as immediates, but using
// a LLVM aggregate type for this leads to bad optimizations,
// so we pick an appropriately sized integer type instead.
- arg.cast = Some(Type::ix(ccx, size * 8));
+ arg.cast_to(ccx, Reg {
+ kind: RegKind::Integer,
+ size
+ });
}
};
// Fat pointers are returned by-value.
cabi_x86_64::compute_abi_info(ccx, self);
},
"aarch64" => cabi_aarch64::compute_abi_info(ccx, self),
- "arm" => {
- let flavor = if ccx.sess().target.target.target_os == "ios" {
- cabi_arm::Flavor::Ios
- } else {
- cabi_arm::Flavor::General
- };
- cabi_arm::compute_abi_info(ccx, self, flavor);
- },
+ "arm" => cabi_arm::compute_abi_info(ccx, self),
"mips" => cabi_mips::compute_abi_info(ccx, self),
"mips64" => cabi_mips64::compute_abi_info(ccx, self),
"powerpc" => cabi_powerpc::compute_abi_info(ccx, self),
}
}
- pub fn llvm_type(&self, ccx: &CrateContext) -> Type {
+ pub fn llvm_type(&self, ccx: &CrateContext<'a, 'tcx>) -> Type {
let mut llargument_tys = Vec::new();
let llreturn_ty = if self.ret.is_ignore() {
Type::void(ccx)
} else if self.ret.is_indirect() {
- llargument_tys.push(self.ret.original_ty.ptr_to());
+ llargument_tys.push(self.ret.memory_ty(ccx).ptr_to());
Type::void(ccx)
} else {
- self.ret.cast.unwrap_or(self.ret.original_ty)
+ self.ret.cast.unwrap_or_else(|| {
+ type_of::immediate_type_of(ccx, self.ret.layout.ty)
+ })
};
for arg in &self.args {
}
let llarg_ty = if arg.is_indirect() {
- arg.original_ty.ptr_to()
+ arg.memory_ty(ccx).ptr_to()
} else {
- arg.cast.unwrap_or(arg.original_ty)
+ arg.cast.unwrap_or_else(|| {
+ type_of::immediate_type_of(ccx, arg.layout.ty)
+ })
};
llargument_tys.push(llarg_ty);
}
}
-pub fn align_up_to(off: usize, a: usize) -> usize {
- return (off + a - 1) / a * a;
-}
-
-fn align(off: usize, ty: Type, pointer: usize) -> usize {
- let a = ty_align(ty, pointer);
- return align_up_to(off, a);
-}
-
-pub fn ty_align(ty: Type, pointer: usize) -> usize {
- match ty.kind() {
- Integer => ((ty.int_width() as usize) + 7) / 8,
- Pointer => pointer,
- Float => 4,
- Double => 8,
- Struct => {
- if ty.is_packed() {
- 1
- } else {
- let str_tys = ty.field_types();
- str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t, pointer)))
- }
- }
- Array => {
- let elt = ty.element_type();
- ty_align(elt, pointer)
- }
- Vector => {
- let len = ty.vector_length();
- let elt = ty.element_type();
- ty_align(elt, pointer) * len
- }
- _ => bug!("ty_align: unhandled type")
- }
-}
-
-pub fn ty_size(ty: Type, pointer: usize) -> usize {
- match ty.kind() {
- Integer => ((ty.int_width() as usize) + 7) / 8,
- Pointer => pointer,
- Float => 4,
- Double => 8,
- Struct => {
- if ty.is_packed() {
- let str_tys = ty.field_types();
- str_tys.iter().fold(0, |s, t| s + ty_size(*t, pointer))
- } else {
- let str_tys = ty.field_types();
- let size = str_tys.iter().fold(0, |s, t| {
- align(s, *t, pointer) + ty_size(*t, pointer)
- });
- align(size, ty, pointer)
- }
- }
- Array => {
- let len = ty.array_length();
- let elt = ty.element_type();
- let eltsz = ty_size(elt, pointer);
- len * eltsz
- }
- Vector => {
- let len = ty.vector_length();
- let elt = ty.element_type();
- let eltsz = ty_size(elt, pointer);
- len * eltsz
- },
- _ => bug!("ty_size: unhandled type")
- }
+pub fn align_up_to(off: u64, a: u64) -> u64 {
+ (off + a - 1) / a * a
}
use std;
use llvm::{ValueRef, True, IntEQ, IntNE};
-use rustc::ty::layout;
-use rustc::ty::{self, Ty, AdtKind};
+use rustc::ty::{self, Ty};
+use rustc::ty::layout::{self, LayoutTyper};
use common::*;
use builder::Builder;
use base;
generic_type_of(cx, t, None, false, false)
}
-
-// Pass dst=true if the type you are passing is a DST. Yes, we could figure
-// this out, but if you call this on an unsized type without realising it, you
-// are going to get the wrong type (it will not include the unsized parts of it).
-pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
- t: Ty<'tcx>, dst: bool) -> Type {
- generic_type_of(cx, t, None, true, dst)
-}
-
pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
t: Ty<'tcx>, name: &str) -> Type {
generic_type_of(cx, t, Some(name), false, false)
};
let nnty = monomorphize::field_ty(cx.tcx(), substs,
&def.variants[nndiscr as usize].fields[0]);
- type_of::sizing_type_of(cx, nnty)
+ if let layout::Scalar { value: layout::Pointer, .. } = *cx.layout_of(nnty) {
+ Type::i8p(cx)
+ } else {
+ type_of::type_of(cx, nnty)
+ }
}
layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
let fields = compute_fields(cx, t, nndiscr as usize, false);
}
}
}
- layout::Vector { element, count } => {
- let elem_ty = Type::from_primitive(cx, element);
- Type::vector(&elem_ty, count)
- }
layout::UntaggedUnion { ref variants, .. }=> {
// Use alignment-sized ints to fill all the union storage.
let size = variants.stride().bytes();
assert_eq!(size%align, 0);
assert_eq!(align.count_ones(), 1, "Alignment must be a power fof 2. Got {}", align);
let align_units = size/align;
- let dl = &cx.tcx().data_layout;
let layout_align = layout::Align::from_bytes(align, align).unwrap();
- if let Some(ity) = layout::Integer::for_abi_align(dl, layout_align) {
+ if let Some(ity) = layout::Integer::for_abi_align(cx, layout_align) {
Type::array(&Type::from_integer(cx, ity), align_units)
} else {
Type::array(&Type::vector(&Type::i32(cx), align/4),
fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec<Ty<'tcx>>,
variant: &layout::Struct,
- sizing: bool, dst: bool) -> Vec<Type> {
+ sizing: bool, _dst: bool) -> Vec<Type> {
let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]);
if sizing {
- fields.filter(|ty| !dst || cx.shared().type_is_sized(*ty))
- .map(|ty| type_of::sizing_type_of(cx, ty)).collect()
+ bug!()
} else {
fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect()
}
cast_to: Option<Type>,
range_assert: bool
) -> ValueRef {
- let (def, substs) = match t.sty {
- ty::TyAdt(ref def, substs) if def.adt_kind() == AdtKind::Enum => (def, substs),
- _ => bug!("{} is not an enum", t)
- };
-
debug!("trans_get_discr t: {:?}", t);
let l = bcx.ccx.layout_of(t);
layout::CEnum { discr, min, max, .. } => {
load_discr(bcx, discr, scrutinee, alignment, min, max, range_assert)
}
- layout::General { discr, .. } => {
+ layout::General { discr, ref variants, .. } => {
let ptr = bcx.struct_gep(scrutinee, 0);
load_discr(bcx, discr, ptr, alignment,
- 0, def.variants.len() as u64 - 1,
+ 0, variants.len() as u64 - 1,
range_assert)
}
layout::Univariant { .. } | layout::UntaggedUnion { .. } => C_u8(bcx.ccx, 0),
layout::RawNullablePointer { nndiscr, .. } => {
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
- let llptrty = type_of::sizing_type_of(bcx.ccx,
- monomorphize::field_ty(bcx.tcx(), substs,
- &def.variants[nndiscr as usize].fields[0]));
- bcx.icmp(cmp, bcx.load(scrutinee, alignment.to_align()), C_null(llptrty))
+ let discr = bcx.load(scrutinee, alignment.to_align());
+ bcx.icmp(cmp, discr, C_null(val_ty(discr)))
}
layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee, alignment)
assert_eq!(to, Disr(0));
}
layout::RawNullablePointer { nndiscr, .. } => {
- let nnty = compute_fields(bcx.ccx, t, nndiscr as usize, false)[0];
if to.0 != nndiscr {
- let llptrty = type_of::sizing_type_of(bcx.ccx, nnty);
+ let llptrty = val_ty(val).element_type();
bcx.store(C_null(llptrty), val, None);
}
}
outputs: &OutputFilenames,
tmpdir: &Path) {
info!("preparing {:?} from {:?} to {:?}", crate_type, objects, out_filename);
+ let flavor = sess.linker_flavor();
// The invocations of cc share some flags across platforms
let (pname, mut cmd, extra) = get_linker(sess);
cmd.env("PATH", command_path(sess, extra));
let root = sess.target_filesearch(PathKind::Native).get_lib_path();
- cmd.args(&sess.target.target.options.pre_link_args);
+ if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
+ cmd.args(args);
+ }
let pre_link_objects = if crate_type == config::CrateTypeExecutable {
&sess.target.target.options.pre_link_objects_exe
objects, out_filename, outputs, trans);
cmd = linker.finalize();
}
- cmd.args(&sess.target.target.options.late_link_args);
+ if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) {
+ cmd.args(args);
+ }
for obj in &sess.target.target.options.post_link_objects {
cmd.arg(root.join(obj));
}
- cmd.args(&sess.target.target.options.post_link_args);
+ if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
+ cmd.args(args);
+ }
if sess.opts.debugging_opts.print_link_args {
println!("{:?}", &cmd);
// except according to those terms.
use std::collections::HashMap;
-use std::ffi::OsString;
+use std::ffi::{OsStr, OsString};
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::{self, BufWriter};
use back::symbol_export::{self, ExportedSymbols};
use middle::dependency_format::Linkage;
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
+use rustc_back::LinkerFlavor;
use session::Session;
use session::config::{self, CrateType, OptLevel, DebugInfoLevel};
use serialize::{json, Encoder};
pub fn to_linker(&'a self,
cmd: Command,
sess: &'a Session) -> Box<Linker+'a> {
- if sess.target.target.options.is_like_msvc {
- Box::new(MsvcLinker {
- cmd: cmd,
- sess: sess,
- info: self
- }) as Box<Linker>
- } else if sess.target.target.options.is_like_emscripten {
- Box::new(EmLinker {
- cmd: cmd,
- sess: sess,
- info: self
- }) as Box<Linker>
- } else {
- Box::new(GnuLinker {
- cmd: cmd,
- sess: sess,
- info: self,
- hinted_static: false,
- }) as Box<Linker>
+ match sess.linker_flavor() {
+ LinkerFlavor::Msvc => {
+ Box::new(MsvcLinker {
+ cmd: cmd,
+ sess: sess,
+ info: self
+ }) as Box<Linker>
+ }
+ LinkerFlavor::Em => {
+ Box::new(EmLinker {
+ cmd: cmd,
+ sess: sess,
+ info: self
+ }) as Box<Linker>
+ }
+ LinkerFlavor::Gcc => {
+ Box::new(GccLinker {
+ cmd: cmd,
+ sess: sess,
+ info: self,
+ hinted_static: false,
+ is_ld: false,
+ }) as Box<Linker>
+ }
+ LinkerFlavor::Ld => {
+ Box::new(GccLinker {
+ cmd: cmd,
+ sess: sess,
+ info: self,
+ hinted_static: false,
+ is_ld: true,
+ }) as Box<Linker>
+ }
}
}
}
fn finalize(&mut self) -> Command;
}
-pub struct GnuLinker<'a> {
+pub struct GccLinker<'a> {
cmd: Command,
sess: &'a Session,
info: &'a LinkerInfo,
hinted_static: bool, // Keeps track of the current hinting mode.
+ // Link as ld
+ is_ld: bool,
}
-impl<'a> GnuLinker<'a> {
+impl<'a> GccLinker<'a> {
+ /// Argument that must be passed *directly* to the linker
+ ///
+ /// These arguments need to be prepended with '-Wl,' when a gcc-style linker is used
+ fn linker_arg<S>(&mut self, arg: S) -> &mut Self
+ where S: AsRef<OsStr>
+ {
+ if !self.is_ld {
+ let mut os = OsString::from("-Wl,");
+ os.push(arg.as_ref());
+ self.cmd.arg(os);
+ } else {
+ self.cmd.arg(arg);
+ }
+ self
+ }
+
fn takes_hints(&self) -> bool {
!self.sess.target.target.options.is_like_osx
}
fn hint_static(&mut self) {
if !self.takes_hints() { return }
if !self.hinted_static {
- self.cmd.arg("-Wl,-Bstatic");
+ self.linker_arg("-Bstatic");
self.hinted_static = true;
}
}
fn hint_dynamic(&mut self) {
if !self.takes_hints() { return }
if self.hinted_static {
- self.cmd.arg("-Wl,-Bdynamic");
+ self.linker_arg("-Bdynamic");
self.hinted_static = false;
}
}
}
-impl<'a> Linker for GnuLinker<'a> {
+impl<'a> Linker for GccLinker<'a> {
fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg("-l").arg(lib); }
fn link_staticlib(&mut self, lib: &str) { self.hint_static(); self.cmd.arg("-l").arg(lib); }
fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); }
self.hint_static();
let target = &self.sess.target.target;
if !target.options.is_like_osx {
- self.cmd.arg("-Wl,--whole-archive")
- .arg("-l").arg(lib)
- .arg("-Wl,--no-whole-archive");
+ self.linker_arg("--whole-archive").cmd.arg("-l").arg(lib);
+ self.linker_arg("--no-whole-archive");
} else {
// -force_load is the macOS equivalent of --whole-archive, but it
// involves passing the full path to the library to link.
- let mut v = OsString::from("-Wl,-force_load,");
+ let mut v = OsString::from("-force_load,");
v.push(&archive::find_library(lib, search_path, &self.sess));
- self.cmd.arg(&v);
+ self.linker_arg(&v);
}
}
fn link_whole_rlib(&mut self, lib: &Path) {
self.hint_static();
if self.sess.target.target.options.is_like_osx {
- let mut v = OsString::from("-Wl,-force_load,");
+ let mut v = OsString::from("-force_load,");
v.push(lib);
- self.cmd.arg(&v);
+ self.linker_arg(&v);
} else {
- self.cmd.arg("-Wl,--whole-archive").arg(lib)
- .arg("-Wl,--no-whole-archive");
+ self.linker_arg("--whole-archive").cmd.arg(lib);
+ self.linker_arg("--no-whole-archive");
}
}
// for partial linking when using multiple codegen units (-r). So we
// insert it here.
if self.sess.target.target.options.is_like_osx {
- self.cmd.arg("-Wl,-dead_strip");
+ self.linker_arg("-dead_strip");
} else if self.sess.target.target.options.is_like_solaris {
- self.cmd.arg("-Wl,-z");
- self.cmd.arg("-Wl,ignore");
+ self.linker_arg("-z");
+ self.linker_arg("ignore");
// If we're building a dylib, we don't use --gc-sections because LLVM
// has already done the best it can do, and we also don't want to
// --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
// reduction.
} else if !keep_metadata {
- self.cmd.arg("-Wl,--gc-sections");
+ self.linker_arg("--gc-sections");
}
}
// need a numeric argument, but other linkers do.
if self.sess.opts.optimize == config::OptLevel::Default ||
self.sess.opts.optimize == config::OptLevel::Aggressive {
- self.cmd.arg("-Wl,-O1");
+ self.linker_arg("-O1");
}
}
}
fn no_default_libraries(&mut self) {
- self.cmd.arg("-nodefaultlibs");
+ if !self.is_ld {
+ self.cmd.arg("-nodefaultlibs");
+ }
}
fn build_dylib(&mut self, out_filename: &Path) {
// On mac we need to tell the linker to let this library be rpathed
if self.sess.target.target.options.is_like_osx {
- self.cmd.args(&["-dynamiclib", "-Wl,-dylib"]);
+ self.cmd.arg("-dynamiclib");
+ self.linker_arg("-dylib");
// Note that the `osx_rpath_install_name` option here is a hack
// purely to support rustbuild right now, we should get a more
// the right `-Wl,-install_name` with an `@rpath` in it.
if self.sess.opts.cg.rpath ||
self.sess.opts.debugging_opts.osx_rpath_install_name {
- let mut v = OsString::from("-Wl,-install_name,@rpath/");
+ let mut v = OsString::from("-install_name,@rpath/");
v.push(out_filename.file_name().unwrap());
- self.cmd.arg(&v);
+ self.linker_arg(&v);
}
} else {
self.cmd.arg("-shared");
}
if self.sess.target.target.options.is_like_osx {
- arg.push("-Wl,-exported_symbols_list,");
+ if !self.is_ld {
+ arg.push("-Wl,")
+ }
+ arg.push("-exported_symbols_list,");
} else if self.sess.target.target.options.is_like_solaris {
- arg.push("-Wl,-M,");
+ if !self.is_ld {
+ arg.push("-Wl,")
+ }
+ arg.push("-M,");
} else {
- arg.push("-Wl,--version-script=");
+ if !self.is_ld {
+ arg.push("-Wl,")
+ }
+ arg.push("--version-script=");
}
arg.push(&path);
}
fn subsystem(&mut self, subsystem: &str) {
- self.cmd.arg(&format!("-Wl,--subsystem,{}", subsystem));
+ self.linker_arg(&format!("--subsystem,{}", subsystem));
}
fn finalize(&mut self) -> Command {
use debuginfo;
use declare;
use machine;
-use machine::llsize_of;
use meth;
use mir;
use monomorphize::{self, Instance};
) {
let ccx = bcx.ccx;
- if type_is_zero_size(ccx, t) {
+ let size = ccx.size_of(t);
+ if size == 0 {
return;
}
- let llty = type_of::type_of(ccx, t);
- let llsz = llsize_of(ccx, llty);
- let llalign = align.unwrap_or_else(|| type_of::align_of(ccx, t));
- call_memcpy(bcx, dst, src, llsz, llalign as u32);
+ let align = align.unwrap_or_else(|| ccx.align_of(t));
+ call_memcpy(bcx, dst, src, C_uint(ccx, size), align);
}
pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>,
// (delay format until we actually need it)
let record = |kind, opt_discr_size, variants| {
let type_desc = format!("{:?}", ty);
- let overall_size = layout.size(&tcx.data_layout);
- let align = layout.align(&tcx.data_layout);
+ let overall_size = layout.size(tcx);
+ let align = layout.align(tcx);
tcx.sess.code_stats.borrow_mut().record_type_size(kind,
type_desc,
align,
session::FieldInfo {
name: field_name.to_string(),
offset: offset.bytes(),
- size: field_layout.size(&tcx.data_layout).bytes(),
- align: field_layout.align(&tcx.data_layout).abi(),
+ size: field_layout.size(tcx).bytes(),
+ align: field_layout.align(tcx).abi(),
}
}
}
session::VariantInfo {
name: Some(name.to_string()),
kind: session::SizeKind::Exact,
- align: value.align(&tcx.data_layout).abi(),
- size: value.size(&tcx.data_layout).bytes(),
+ align: value.align(tcx).abi(),
+ size: value.size(tcx).bytes(),
fields: vec![],
}
};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(non_upper_case_globals)]
-
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{self, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform};
use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
- abi::ty_size(ty, 8)
-}
-
-fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
- fn check_array(ty: Type) -> Option<(Type, u64)> {
- let len = ty.array_length() as u64;
- if len == 0 {
- return None
- }
- let elt = ty.element_type();
-
- // if our element is an HFA/HVA, so are we; multiply members by our len
- is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members))
- }
-
- fn check_struct(ty: Type) -> Option<(Type, u64)> {
- let str_tys = ty.field_types();
- if str_tys.len() == 0 {
- return None
- }
-
- let mut prev_base_ty = None;
- let mut members = 0;
- for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) {
- match (prev_base_ty, opt_homog_agg) {
- // field isn't itself an HFA, so we aren't either
- (_, None) => return None,
-
- // first field - store its type and number of members
- (None, Some((field_ty, field_members))) => {
- prev_base_ty = Some(field_ty);
- members = field_members;
- },
- // 2nd or later field - give up if it's a different type; otherwise incr. members
- (Some(prev_ty), Some((field_ty, field_members))) => {
- if prev_ty != field_ty {
- return None;
- }
- members += field_members;
- }
- }
- }
-
- // Because of previous checks, we know prev_base_ty is Some(...) because
- // 1. str_tys has at least one element; and
- // 2. prev_base_ty was filled in (or we would've returned early)
- let (base_ty, members) = (prev_base_ty.unwrap(), members);
+fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>)
+ -> Option<Uniform> {
+ arg.layout.homogenous_aggregate(ccx).and_then(|unit| {
+ let size = arg.layout.size(ccx);
- // Ensure there is no padding.
- if ty_size(ty) == ty_size(base_ty) * (members as usize) {
- Some((base_ty, members))
- } else {
- None
+ // Ensure we have at most four uniquely addressable members.
+ if size > unit.size.checked_mul(4, ccx).unwrap() {
+ return None;
}
- }
- let homog_agg = match ty.kind() {
- Float => Some((ty, 1)),
- Double => Some((ty, 1)),
- Array => check_array(ty),
- Struct => check_struct(ty),
- Vector => match ty_size(ty) {
- 4|8 => Some((ty, 1)),
- _ => None
- },
- _ => None
- };
+ let valid_unit = match unit.kind {
+ RegKind::Integer => false,
+ RegKind::Float => true,
+ RegKind::Vector => size.bits() == 64 || size.bits() == 128
+ };
- // Ensure we have at most four uniquely addressable members
- homog_agg.and_then(|(base_ty, members)| {
- if members > 0 && members <= 4 {
- Some((base_ty, members))
+ if valid_unit {
+ Some(Uniform {
+ unit,
+ total: size
+ })
} else {
None
}
})
}
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+ if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(32);
return;
}
- if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
- ret.cast = Some(Type::array(&base_ty, members));
+ if let Some(uniform) = is_homogenous_aggregate(ccx, ret) {
+ ret.cast_to(ccx, uniform);
return;
}
- let size = ty_size(ret.ty);
- if size <= 16 {
- let llty = if size <= 1 {
- Type::i8(ccx)
- } else if size <= 2 {
- Type::i16(ccx)
- } else if size <= 4 {
- Type::i32(ccx)
- } else if size <= 8 {
- Type::i64(ccx)
+ let size = ret.layout.size(ccx);
+ let bits = size.bits();
+ if bits <= 128 {
+ let unit = if bits <= 8 {
+ Reg::i8()
+ } else if bits <= 16 {
+ Reg::i16()
+ } else if bits <= 32 {
+ Reg::i32()
} else {
- Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
+ Reg::i64()
};
- ret.cast = Some(llty);
+
+ ret.cast_to(ccx, Uniform {
+ unit,
+ total: size
+ });
return;
}
ret.make_indirect(ccx);
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
- if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+ if !arg.layout.is_aggregate() {
arg.extend_integer_width_to(32);
return;
}
- if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
- arg.cast = Some(Type::array(&base_ty, members));
+ if let Some(uniform) = is_homogenous_aggregate(ccx, arg) {
+ arg.cast_to(ccx, uniform);
return;
}
- let size = ty_size(arg.ty);
- if size <= 16 {
- let llty = if size == 0 {
- Type::array(&Type::i64(ccx), 0)
- } else if size == 1 {
- Type::i8(ccx)
- } else if size == 2 {
- Type::i16(ccx)
- } else if size <= 4 {
- Type::i32(ccx)
- } else if size <= 8 {
- Type::i64(ccx)
+ let size = arg.layout.size(ccx);
+ let bits = size.bits();
+ if bits <= 128 {
+ let unit = if bits <= 8 {
+ Reg::i8()
+ } else if bits <= 16 {
+ Reg::i16()
+ } else if bits <= 32 {
+ Reg::i32()
} else {
- Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
+ Reg::i64()
};
- arg.cast = Some(llty);
+
+ arg.cast_to(ccx, Uniform {
+ unit,
+ total: size
+ });
return;
}
arg.make_indirect(ccx);
}
-fn is_reg_ty(ty: Type) -> bool {
- match ty.kind() {
- Integer
- | Pointer
- | Float
- | Double
- | Vector => true,
- _ => false
- }
-}
-
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{self, align_up_to, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg, Uniform};
use context::CrateContext;
-use type_::Type;
-use std::cmp;
-
-pub enum Flavor {
- General,
- Ios
-}
-
-type TyAlignFn = fn(ty: Type) -> usize;
-
-fn align(off: usize, ty: Type, align_fn: TyAlignFn) -> usize {
- let a = align_fn(ty);
- return align_up_to(off, a);
-}
-
-fn general_ty_align(ty: Type) -> usize {
- abi::ty_align(ty, 4)
-}
-
-// For more information see:
-// ARMv7
-// https://developer.apple.com/library/ios/documentation/Xcode/Conceptual
-// /iPhoneOSABIReference/Articles/ARMv7FunctionCallingConventions.html
-// ARMv6
-// https://developer.apple.com/library/ios/documentation/Xcode/Conceptual
-// /iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html
-fn ios_ty_align(ty: Type) -> usize {
- match ty.kind() {
- Integer => cmp::min(4, ((ty.int_width() as usize) + 7) / 8),
- Pointer => 4,
- Float => 4,
- Double => 4,
- Struct => {
- if ty.is_packed() {
- 1
- } else {
- let str_tys = ty.field_types();
- str_tys.iter().fold(1, |a, t| cmp::max(a, ios_ty_align(*t)))
- }
- }
- Array => {
- let elt = ty.element_type();
- ios_ty_align(elt)
- }
- Vector => {
- let len = ty.vector_length();
- let elt = ty.element_type();
- ios_ty_align(elt) * len
- }
- _ => bug!("ty_align: unhandled type")
- }
-}
-
-fn ty_size(ty: Type, align_fn: TyAlignFn) -> usize {
- match ty.kind() {
- Integer => ((ty.int_width() as usize) + 7) / 8,
- Pointer => 4,
- Float => 4,
- Double => 8,
- Struct => {
- if ty.is_packed() {
- let str_tys = ty.field_types();
- str_tys.iter().fold(0, |s, t| s + ty_size(*t, align_fn))
- } else {
- let str_tys = ty.field_types();
- let size = str_tys.iter()
- .fold(0, |s, t| {
- align(s, *t, align_fn) + ty_size(*t, align_fn)
- });
- align(size, ty, align_fn)
- }
- }
- Array => {
- let len = ty.array_length();
- let elt = ty.element_type();
- let eltsz = ty_size(elt, align_fn);
- len * eltsz
- }
- Vector => {
- let len = ty.vector_length();
- let elt = ty.element_type();
- let eltsz = ty_size(elt, align_fn);
- len * eltsz
- }
- _ => bug!("ty_size: unhandled type")
- }
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) {
- if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+ if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(32);
return;
}
- let size = ty_size(ret.ty, align_fn);
- if size <= 4 {
- let llty = if size <= 1 {
- Type::i8(ccx)
- } else if size <= 2 {
- Type::i16(ccx)
+ let size = ret.layout.size(ccx);
+ let bits = size.bits();
+ if bits <= 32 {
+ let unit = if bits <= 8 {
+ Reg::i8()
+ } else if bits <= 16 {
+ Reg::i16()
} else {
- Type::i32(ccx)
+ Reg::i32()
};
- ret.cast = Some(llty);
+ ret.cast_to(ccx, Uniform {
+ unit,
+ total: size
+ });
return;
}
ret.make_indirect(ccx);
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, align_fn: TyAlignFn) {
- if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+ if !arg.layout.is_aggregate() {
arg.extend_integer_width_to(32);
return;
}
- let align = align_fn(arg.ty);
- let size = ty_size(arg.ty, align_fn);
- let llty = if align <= 4 {
- Type::array(&Type::i32(ccx), ((size + 3) / 4) as u64)
- } else {
- Type::array(&Type::i64(ccx), ((size + 7) / 8) as u64)
- };
- arg.cast = Some(llty);
+ let align = arg.layout.align(ccx).abi();
+ let total = arg.layout.size(ccx);
+ arg.cast_to(ccx, Uniform {
+ unit: if align <= 4 { Reg::i32() } else { Reg::i64() },
+ total
+ });
}
-fn is_reg_ty(ty: Type) -> bool {
- match ty.kind() {
- Integer
- | Pointer
- | Float
- | Double
- | Vector => true,
- _ => false
- }
-}
-
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
- let align_fn = match flavor {
- Flavor::General => general_ty_align as TyAlignFn,
- Flavor::Ios => ios_ty_align as TyAlignFn,
- };
-
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
- classify_ret_ty(ccx, &mut fty.ret, align_fn);
+ classify_ret_ty(ccx, &mut fty.ret);
}
for arg in &mut fty.args {
if arg.is_ignore() { continue; }
- classify_arg_ty(ccx, arg, align_fn);
+ classify_arg_ty(ccx, arg);
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(non_upper_case_globals)]
-
-use llvm::{Struct, Array};
-use abi::{FnType, ArgType, ArgAttribute};
+use abi::{FnType, ArgType, ArgAttribute, LayoutExt, Uniform};
use context::CrateContext;
// Data layout: e-p:32:32-i64:64-v128:32:128-n32-S128
// See the https://github.com/kripken/emscripten-fastcomp-clang repository.
// The class `EmscriptenABIInfo` in `/lib/CodeGen/TargetInfo.cpp` contains the ABI definitions.
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- match ret.ty.kind() {
- Struct => {
- let field_types = ret.ty.field_types();
- if field_types.len() == 1 {
- ret.cast = Some(field_types[0]);
- } else {
- ret.make_indirect(ccx);
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+ if ret.layout.is_aggregate() {
+ if let Some(unit) = ret.layout.homogenous_aggregate(ccx) {
+ let size = ret.layout.size(ccx);
+ if unit.size == size {
+ ret.cast_to(ccx, Uniform {
+ unit,
+ total: size
+ });
+ return;
}
}
- Array => {
- ret.make_indirect(ccx);
- }
- _ => {}
+
+ ret.make_indirect(ccx);
}
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
- if arg.ty.is_aggregate() {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+ if arg.layout.is_aggregate() {
arg.make_indirect(ccx);
arg.attrs.set(ArgAttribute::ByVal);
}
}
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(non_upper_case_globals)]
-
-use libc::c_uint;
use std::cmp;
-use llvm;
-use llvm::{Integer, Pointer, Float, Double, Vector};
-use abi::{self, align_up_to, ArgType, FnType};
+use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform};
use context::CrateContext;
-use type_::Type;
-
-fn ty_align(ty: Type) -> usize {
- abi::ty_align(ty, 4)
-}
-fn ty_size(ty: Type) -> usize {
- abi::ty_size(ty, 4)
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+ if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(32);
} else {
ret.make_indirect(ccx);
}
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
- let orig_offset = *offset;
- let size = ty_size(arg.ty) * 8;
- let mut align = ty_align(arg.ty);
-
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
+ let size = arg.layout.size(ccx);
+ let mut align = arg.layout.align(ccx).abi();
align = cmp::min(cmp::max(align, 4), 8);
- *offset = align_up_to(*offset, align);
- *offset += align_up_to(size, align * 8) / 8;
- if !is_reg_ty(arg.ty) {
- arg.cast = Some(struct_ty(ccx, arg.ty));
- arg.pad = padding_ty(ccx, align, orig_offset);
+ if arg.layout.is_aggregate() {
+ arg.cast_to(ccx, Uniform {
+ unit: Reg::i32(),
+ total: size
+ });
+ if ((align - 1) & *offset) > 0 {
+ arg.pad_with(ccx, Reg::i32());
+ }
} else {
arg.extend_integer_width_to(32);
}
-}
-
-fn is_reg_ty(ty: Type) -> bool {
- return match ty.kind() {
- Integer
- | Pointer
- | Float
- | Double
- | Vector => true,
- _ => false
- };
-}
-
-fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
- if ((align - 1 ) & offset) > 0 {
- Some(Type::i32(ccx))
- } else {
- None
- }
-}
-
-fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
- let int_ty = Type::i32(ccx);
- let mut args = Vec::new();
-
- let mut n = size / 32;
- while n > 0 {
- args.push(int_ty);
- n -= 1;
- }
- let r = size % 32;
- if r > 0 {
- unsafe {
- args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
- }
- }
-
- args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
- let size = ty_size(ty) * 8;
- Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+ *offset = align_up_to(*offset, align);
+ *offset += align_up_to(size.bytes(), align);
}
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(non_upper_case_globals)]
-
-use libc::c_uint;
use std::cmp;
-use llvm;
-use llvm::{Integer, Pointer, Float, Double, Vector};
-use abi::{self, align_up_to, ArgType, FnType};
+use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform};
use context::CrateContext;
-use type_::Type;
-
-fn ty_align(ty: Type) -> usize {
- abi::ty_align(ty, 8)
-}
-fn ty_size(ty: Type) -> usize {
- abi::ty_size(ty, 8)
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+ if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(64);
} else {
ret.make_indirect(ccx);
}
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
- let orig_offset = *offset;
- let size = ty_size(arg.ty) * 8;
- let mut align = ty_align(arg.ty);
-
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
+ let size = arg.layout.size(ccx);
+ let mut align = arg.layout.align(ccx).abi();
align = cmp::min(cmp::max(align, 4), 8);
- *offset = align_up_to(*offset, align);
- *offset += align_up_to(size, align * 8) / 8;
- if !is_reg_ty(arg.ty) {
- arg.cast = Some(struct_ty(ccx, arg.ty));
- arg.pad = padding_ty(ccx, align, orig_offset);
+ if arg.layout.is_aggregate() {
+ arg.cast_to(ccx, Uniform {
+ unit: Reg::i64(),
+ total: size
+ });
+ if ((align - 1) & *offset) > 0 {
+ arg.pad_with(ccx, Reg::i64());
+ }
} else {
arg.extend_integer_width_to(64);
}
-}
-
-fn is_reg_ty(ty: Type) -> bool {
- return match ty.kind() {
- Integer
- | Pointer
- | Float
- | Double
- | Vector => true,
- _ => false
- };
-}
-
-fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
- if ((align - 1 ) & offset) > 0 {
- Some(Type::i64(ccx))
- } else {
- None
- }
-}
-
-fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
- let int_ty = Type::i64(ccx);
- let mut args = Vec::new();
-
- let mut n = size / 64;
- while n > 0 {
- args.push(int_ty);
- n -= 1;
- }
- let r = size % 64;
- if r > 0 {
- unsafe {
- args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
- }
- }
-
- args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
- let size = ty_size(ty) * 8;
- Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+ *offset = align_up_to(*offset, align);
+ *offset += align_up_to(size.bytes(), align);
}
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
// Reference: MSP430 Embedded Application Binary Interface
// http://www.ti.com/lit/an/slaa534/slaa534.pdf
-#![allow(non_upper_case_globals)]
-
-use llvm::Struct;
-
-use abi::{self, ArgType, FnType};
+use abi::{ArgType, FnType, LayoutExt};
use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
- abi::ty_size(ty, 2)
-}
// 3.5 Structures or Unions Passed and Returned by Reference
//
// returned by reference. To pass a structure or union by reference, the caller
// places its address in the appropriate location: either in a register or on
// the stack, according to its position in the argument list. (..)"
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+ if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 32 {
ret.make_indirect(ccx);
} else {
ret.extend_integer_width_to(16);
}
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
- if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+ if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 32 {
arg.make_indirect(ccx);
} else {
arg.extend_integer_width_to(16);
}
}
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
// Reference: PTX Writer's Guide to Interoperability
// http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
-#![allow(non_upper_case_globals)]
-
-use llvm::Struct;
-
-use abi::{self, ArgType, FnType};
+use abi::{ArgType, FnType, LayoutExt};
use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
- abi::ty_size(ty, 4)
-}
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+ if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 32 {
ret.make_indirect(ccx);
} else {
ret.extend_integer_width_to(32);
}
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
- if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+ if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 32 {
arg.make_indirect(ccx);
} else {
arg.extend_integer_width_to(32);
}
}
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
// Reference: PTX Writer's Guide to Interoperability
// http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
-#![allow(non_upper_case_globals)]
-
-use llvm::Struct;
-
-use abi::{self, ArgType, FnType};
+use abi::{ArgType, FnType, LayoutExt};
use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
- abi::ty_size(ty, 8)
-}
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- if ret.ty.kind() == Struct && ty_size(ret.ty) > 64 {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+ if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 64 {
ret.make_indirect(ccx);
} else {
ret.extend_integer_width_to(64);
}
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
- if arg.ty.kind() == Struct && ty_size(arg.ty) > 64 {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+ if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 64 {
arg.make_indirect(ccx);
} else {
arg.extend_integer_width_to(64);
}
}
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use libc::c_uint;
-use llvm;
-use llvm::{Integer, Pointer, Float, Double, Vector};
-use abi::{self, align_up_to, FnType, ArgType};
+use abi::{align_up_to, FnType, ArgType, LayoutExt, Reg, Uniform};
use context::CrateContext;
-use type_::Type;
use std::cmp;
-fn ty_align(ty: Type) -> usize {
- if ty.kind() == Vector {
- bug!("ty_size: unhandled type")
- } else {
- abi::ty_align(ty, 4)
- }
-}
-
-fn ty_size(ty: Type) -> usize {
- if ty.kind() == Vector {
- bug!("ty_size: unhandled type")
- } else {
- abi::ty_size(ty, 4)
- }
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+ if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(32);
} else {
ret.make_indirect(ccx);
}
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
- let orig_offset = *offset;
- let size = ty_size(arg.ty) * 8;
- let mut align = ty_align(arg.ty);
-
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
+ let size = arg.layout.size(ccx);
+ let mut align = arg.layout.align(ccx).abi();
align = cmp::min(cmp::max(align, 4), 8);
- *offset = align_up_to(*offset, align);
- *offset += align_up_to(size, align * 8) / 8;
- if !is_reg_ty(arg.ty) {
- arg.cast = Some(struct_ty(ccx, arg.ty));
- arg.pad = padding_ty(ccx, align, orig_offset);
+ if arg.layout.is_aggregate() {
+ arg.cast_to(ccx, Uniform {
+ unit: Reg::i32(),
+ total: size
+ });
+ if ((align - 1) & *offset) > 0 {
+ arg.pad_with(ccx, Reg::i32());
+ }
} else {
arg.extend_integer_width_to(32);
}
-}
-
-fn is_reg_ty(ty: Type) -> bool {
- return match ty.kind() {
- Integer
- | Pointer
- | Float
- | Double => true,
- _ => false
- };
-}
-fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
- if ((align - 1 ) & offset) > 0 {
- Some(Type::i32(ccx))
- } else {
- None
- }
-}
-
-fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
- let int_ty = Type::i32(ccx);
- let mut args = Vec::new();
-
- let mut n = size / 32;
- while n > 0 {
- args.push(int_ty);
- n -= 1;
- }
-
- let r = size % 32;
- if r > 0 {
- unsafe {
- args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
- }
- }
-
- args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
- let size = ty_size(ty) * 8;
- Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+ *offset = align_up_to(*offset, align);
+ *offset += align_up_to(size.bytes(), align);
}
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// FIXME: The PowerPC64 ABI needs to zero or sign extend function
-// call parameters, but compute_abi_info() is passed LLVM types
-// which have no sign information.
-//
+// FIXME:
// Alignment of 128 bit types is not currently handled, this will
// need to be fixed when PowerPC vector support is added.
-use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array};
-use abi::{self, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform};
use context::CrateContext;
-use type_::Type;
-
-fn ty_size(ty: Type) -> usize {
- if ty.kind() == Vector {
- bug!("ty_size: unhandled type")
- } else {
- abi::ty_size(ty, 8)
- }
-}
-
-fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
- fn check_array(ty: Type) -> Option<(Type, u64)> {
- let len = ty.array_length() as u64;
- if len == 0 {
- return None
- }
- let elt = ty.element_type();
-
- // if our element is an HFA/HVA, so are we; multiply members by our len
- is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members))
- }
- fn check_struct(ty: Type) -> Option<(Type, u64)> {
- let str_tys = ty.field_types();
- if str_tys.len() == 0 {
- return None
- }
+fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>)
+ -> Option<Uniform> {
+ arg.layout.homogenous_aggregate(ccx).and_then(|unit| {
+ let size = arg.layout.size(ccx);
- let mut prev_base_ty = None;
- let mut members = 0;
- for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) {
- match (prev_base_ty, opt_homog_agg) {
- // field isn't itself an HFA, so we aren't either
- (_, None) => return None,
-
- // first field - store its type and number of members
- (None, Some((field_ty, field_members))) => {
- prev_base_ty = Some(field_ty);
- members = field_members;
- },
-
- // 2nd or later field - give up if it's a different type; otherwise incr. members
- (Some(prev_ty), Some((field_ty, field_members))) => {
- if prev_ty != field_ty {
- return None;
- }
- members += field_members;
- }
- }
+ // Ensure we have at most eight uniquely addressable members.
+ if size > unit.size.checked_mul(8, ccx).unwrap() {
+ return None;
}
- // Because of previous checks, we know prev_base_ty is Some(...) because
- // 1. str_tys has at least one element; and
- // 2. prev_base_ty was filled in (or we would've returned early)
- let (base_ty, members) = (prev_base_ty.unwrap(), members);
-
- // Ensure there is no padding.
- if ty_size(ty) == ty_size(base_ty) * (members as usize) {
- Some((base_ty, members))
- } else {
- None
- }
- }
+ let valid_unit = match unit.kind {
+ RegKind::Integer => false,
+ RegKind::Float => true,
+ RegKind::Vector => size.bits() == 128
+ };
- let homog_agg = match ty.kind() {
- Float => Some((ty, 1)),
- Double => Some((ty, 1)),
- Array => check_array(ty),
- Struct => check_struct(ty),
- _ => None
- };
-
- // Ensure we have at most eight uniquely addressable members
- homog_agg.and_then(|(base_ty, members)| {
- if members > 0 && members <= 8 {
- Some((base_ty, members))
+ if valid_unit {
+ Some(Uniform {
+ unit,
+ total: size
+ })
} else {
None
}
})
}
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+ if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(64);
return;
}
ret.make_indirect(ccx);
}
- if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
- ret.cast = Some(Type::array(&base_ty, members));
+ if let Some(uniform) = is_homogenous_aggregate(ccx, ret) {
+ ret.cast_to(ccx, uniform);
return;
}
- let size = ty_size(ret.ty);
- if size <= 16 {
- let llty = if size <= 1 {
- Type::i8(ccx)
- } else if size <= 2 {
- Type::i16(ccx)
- } else if size <= 4 {
- Type::i32(ccx)
- } else if size <= 8 {
- Type::i64(ccx)
+ let size = ret.layout.size(ccx);
+ let bits = size.bits();
+ if bits <= 128 {
+ let unit = if bits <= 8 {
+ Reg::i8()
+ } else if bits <= 16 {
+ Reg::i16()
+ } else if bits <= 32 {
+ Reg::i32()
} else {
- Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
+ Reg::i64()
};
- ret.cast = Some(llty);
+
+ ret.cast_to(ccx, Uniform {
+ unit,
+ total: size
+ });
return;
}
ret.make_indirect(ccx);
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
- if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+ if !arg.layout.is_aggregate() {
arg.extend_integer_width_to(64);
return;
}
- if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
- arg.cast = Some(Type::array(&base_ty, members));
+ if let Some(uniform) = is_homogenous_aggregate(ccx, arg) {
+ arg.cast_to(ccx, uniform);
return;
}
- arg.cast = Some(struct_ty(ccx, arg.ty));
-}
-
-fn is_reg_ty(ty: Type) -> bool {
- match ty.kind() {
- Integer
- | Pointer
- | Float
- | Double => true,
- _ => false
- }
-}
-
-fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec<Type> {
- let long_ty = Type::i64(ccx);
- let mut args = Vec::new();
-
- let mut n = size / 64;
- while n > 0 {
- args.push(long_ty);
- n -= 1;
- }
-
- let r = size % 64;
- if r > 0 {
- args.push(Type::ix(ccx, r as u64));
- }
-
- args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
- let size = ty_size(ty) * 8;
- Type::struct_(ccx, &coerce_to_long(ccx, size), false)
+ let total = arg.layout.size(ccx);
+ arg.cast_to(ccx, Uniform {
+ unit: Reg::i64(),
+ total
+ });
}
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
// FIXME: The assumes we're using the non-vector ABI, i.e. compiling
// for a pre-z13 machine or using -mno-vx.
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{align_up_to, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg};
use context::CrateContext;
-use type_::Type;
-use std::cmp;
+use rustc::ty::layout::{self, Layout, TyLayout};
-fn align(off: usize, ty: Type) -> usize {
- let a = ty_align(ty);
- return align_up_to(off, a);
-}
-
-fn ty_align(ty: Type) -> usize {
- match ty.kind() {
- Integer => ((ty.int_width() as usize) + 7) / 8,
- Pointer => 8,
- Float => 4,
- Double => 8,
- Struct => {
- if ty.is_packed() {
- 1
- } else {
- let str_tys = ty.field_types();
- str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
- }
- }
- Array => {
- let elt = ty.element_type();
- ty_align(elt)
- }
- Vector => ty_size(ty),
- _ => bug!("ty_align: unhandled type")
- }
-}
-
-fn ty_size(ty: Type) -> usize {
- match ty.kind() {
- Integer => ((ty.int_width() as usize) + 7) / 8,
- Pointer => 8,
- Float => 4,
- Double => 8,
- Struct => {
- if ty.is_packed() {
- let str_tys = ty.field_types();
- str_tys.iter().fold(0, |s, t| s + ty_size(*t))
- } else {
- let str_tys = ty.field_types();
- let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
- align(size, ty)
- }
- }
- Array => {
- let len = ty.array_length();
- let elt = ty.element_type();
- let eltsz = ty_size(elt);
- len * eltsz
- }
- Vector => {
- let len = ty.vector_length();
- let elt = ty.element_type();
- let eltsz = ty_size(elt);
- len * eltsz
- }
- _ => bug!("ty_size: unhandled type")
- }
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+ if !ret.layout.is_aggregate() && ret.layout.size(ccx).bits() <= 64 {
ret.extend_integer_width_to(64);
} else {
ret.make_indirect(ccx);
}
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
- if arg.ty.kind() == Struct {
- fn is_single_fp_element(tys: &[Type]) -> bool {
- if tys.len() != 1 {
- return false;
- }
- match tys[0].kind() {
- Float | Double => true,
- Struct => is_single_fp_element(&tys[0].field_types()),
- _ => false
- }
- }
-
- if is_single_fp_element(&arg.ty.field_types()) {
- match ty_size(arg.ty) {
- 4 => arg.cast = Some(Type::f32(ccx)),
- 8 => arg.cast = Some(Type::f64(ccx)),
- _ => arg.make_indirect(ccx)
- }
- } else {
- match ty_size(arg.ty) {
- 1 => arg.cast = Some(Type::i8(ccx)),
- 2 => arg.cast = Some(Type::i16(ccx)),
- 4 => arg.cast = Some(Type::i32(ccx)),
- 8 => arg.cast = Some(Type::i64(ccx)),
- _ => arg.make_indirect(ccx)
+fn is_single_fp_element<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ layout: TyLayout<'tcx>) -> bool {
+ match *layout {
+ Layout::Scalar { value: layout::F32, .. } |
+ Layout::Scalar { value: layout::F64, .. } => true,
+ Layout::Univariant { .. } => {
+ if layout.field_count() == 1 {
+ is_single_fp_element(ccx, layout.field(ccx, 0))
+ } else {
+ false
}
}
- return;
+ _ => false
}
+}
- if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+ let size = arg.layout.size(ccx);
+ if !arg.layout.is_aggregate() && size.bits() <= 64 {
arg.extend_integer_width_to(64);
- } else {
- arg.make_indirect(ccx);
+ return;
}
-}
-fn is_reg_ty(ty: Type) -> bool {
- match ty.kind() {
- Integer
- | Pointer
- | Float
- | Double => ty_size(ty) <= 8,
- _ => false
+ if is_single_fp_element(ccx, arg.layout) {
+ match size.bytes() {
+ 4 => arg.cast_to(ccx, Reg::f32()),
+ 8 => arg.cast_to(ccx, Reg::f64()),
+ _ => arg.make_indirect(ccx)
+ }
+ } else {
+ match size.bytes() {
+ 1 => arg.cast_to(ccx, Reg::i8()),
+ 2 => arg.cast_to(ccx, Reg::i16()),
+ 4 => arg.cast_to(ccx, Reg::i32()),
+ 8 => arg.cast_to(ccx, Reg::i64()),
+ _ => arg.make_indirect(ccx)
+ }
}
}
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(non_upper_case_globals)]
-
-use libc::c_uint;
use std::cmp;
-use llvm;
-use llvm::{Integer, Pointer, Float, Double, Vector};
-use abi::{self, align_up_to, ArgType, FnType};
+use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform};
use context::CrateContext;
-use type_::Type;
-
-fn ty_align(ty: Type) -> usize {
- abi::ty_align(ty, 4)
-}
-fn ty_size(ty: Type) -> usize {
- abi::ty_size(ty, 4)
-}
-
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+ if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(32);
} else {
ret.make_indirect(ccx);
}
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
- let orig_offset = *offset;
- let size = ty_size(arg.ty) * 8;
- let mut align = ty_align(arg.ty);
-
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
+ let size = arg.layout.size(ccx);
+ let mut align = arg.layout.align(ccx).abi();
align = cmp::min(cmp::max(align, 4), 8);
- *offset = align_up_to(*offset, align);
- *offset += align_up_to(size, align * 8) / 8;
-
- if !is_reg_ty(arg.ty) {
- arg.cast = Some(struct_ty(ccx, arg.ty));
- arg.pad = padding_ty(ccx, align, orig_offset);
- } else {
- arg.extend_integer_width_to(32);
- }
-}
-
-fn is_reg_ty(ty: Type) -> bool {
- return match ty.kind() {
- Integer
- | Pointer
- | Float
- | Double
- | Vector => true,
- _ => false
- };
-}
-
-fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
- if ((align - 1 ) & offset) > 0 {
- Some(Type::i32(ccx))
- } else {
- None
- }
-}
-
-fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
- let int_ty = Type::i32(ccx);
- let mut args = Vec::new();
- let mut n = size / 32;
- while n > 0 {
- args.push(int_ty);
- n -= 1;
- }
-
- let r = size % 32;
- if r > 0 {
- unsafe {
- args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
+ if arg.layout.is_aggregate() {
+ arg.cast_to(ccx, Uniform {
+ unit: Reg::i32(),
+ total: size
+ });
+ if ((align - 1) & *offset) > 0 {
+ arg.pad_with(ccx, Reg::i32());
}
+ } else {
+ arg.extend_integer_width_to(32)
}
- args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
- let size = ty_size(ty) * 8;
- Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+ *offset = align_up_to(*offset, align);
+ *offset += align_up_to(size.bytes(), align);
}
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
// FIXME: This needs an audit for correctness and completeness.
-use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array};
-use abi::{self, FnType, ArgType};
+use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform};
use context::CrateContext;
-use type_::Type;
-fn ty_size(ty: Type) -> usize {
- if ty.kind() == Vector {
- bug!("ty_size: unhandled type")
- } else {
- abi::ty_size(ty, 8)
- }
-}
-
-fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
- fn check_array(ty: Type) -> Option<(Type, u64)> {
- let len = ty.array_length() as u64;
- if len == 0 {
- return None
- }
- let elt = ty.element_type();
-
- // if our element is an HFA/HVA, so are we; multiply members by our len
- is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members))
- }
-
- fn check_struct(ty: Type) -> Option<(Type, u64)> {
- let str_tys = ty.field_types();
- if str_tys.len() == 0 {
- return None
- }
-
- let mut prev_base_ty = None;
- let mut members = 0;
- for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) {
- match (prev_base_ty, opt_homog_agg) {
- // field isn't itself an HFA, so we aren't either
- (_, None) => return None,
+fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>)
+ -> Option<Uniform> {
+ arg.layout.homogenous_aggregate(ccx).and_then(|unit| {
+ let size = arg.layout.size(ccx);
- // first field - store its type and number of members
- (None, Some((field_ty, field_members))) => {
- prev_base_ty = Some(field_ty);
- members = field_members;
- },
-
- // 2nd or later field - give up if it's a different type; otherwise incr. members
- (Some(prev_ty), Some((field_ty, field_members))) => {
- if prev_ty != field_ty {
- return None;
- }
- members += field_members;
- }
- }
+ // Ensure we have at most eight uniquely addressable members.
+ if size > unit.size.checked_mul(8, ccx).unwrap() {
+ return None;
}
- // Because of previous checks, we know prev_base_ty is Some(...) because
- // 1. str_tys has at least one element; and
- // 2. prev_base_ty was filled in (or we would've returned early)
- let (base_ty, members) = (prev_base_ty.unwrap(), members);
-
- // Ensure there is no padding.
- if ty_size(ty) == ty_size(base_ty) * (members as usize) {
- Some((base_ty, members))
- } else {
- None
- }
- }
-
- let homog_agg = match ty.kind() {
- Float => Some((ty, 1)),
- Double => Some((ty, 1)),
- Array => check_array(ty),
- Struct => check_struct(ty),
- _ => None
- };
+ let valid_unit = match unit.kind {
+ RegKind::Integer => false,
+ RegKind::Float => true,
+ RegKind::Vector => size.bits() == 128
+ };
- // Ensure we have at most eight uniquely addressable members
- homog_agg.and_then(|(base_ty, members)| {
- if members > 0 && members <= 8 {
- Some((base_ty, members))
+ if valid_unit {
+ Some(Uniform {
+ unit,
+ total: size
+ })
} else {
None
}
})
}
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- if is_reg_ty(ret.ty) {
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
+ if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(64);
return;
}
- // don't return aggregates in registers
- ret.make_indirect(ccx);
-
- if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
- ret.cast = Some(Type::array(&base_ty, members));
+ if let Some(uniform) = is_homogenous_aggregate(ccx, ret) {
+ ret.cast_to(ccx, uniform);
return;
}
- let size = ty_size(ret.ty);
- if size <= 16 {
- let llty = if size <= 1 {
- Type::i8(ccx)
- } else if size <= 2 {
- Type::i16(ccx)
- } else if size <= 4 {
- Type::i32(ccx)
- } else if size <= 8 {
- Type::i64(ccx)
+ let size = ret.layout.size(ccx);
+ let bits = size.bits();
+ if bits <= 128 {
+ let unit = if bits <= 8 {
+ Reg::i8()
+ } else if bits <= 16 {
+ Reg::i16()
+ } else if bits <= 32 {
+ Reg::i32()
} else {
- Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
+ Reg::i64()
};
- ret.cast = Some(llty);
+
+ ret.cast_to(ccx, Uniform {
+ unit,
+ total: size
+ });
return;
}
+
+ // don't return aggregates in registers
+ ret.make_indirect(ccx);
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
- if is_reg_ty(arg.ty) {
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+ if !arg.layout.is_aggregate() {
arg.extend_integer_width_to(64);
return;
}
- if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
- arg.cast = Some(Type::array(&base_ty, members));
+ if let Some(uniform) = is_homogenous_aggregate(ccx, arg) {
+ arg.cast_to(ccx, uniform);
return;
}
- arg.cast = Some(struct_ty(ccx, arg.ty));
-}
-
-fn is_reg_ty(ty: Type) -> bool {
- match ty.kind() {
- Integer
- | Pointer
- | Float
- | Double => true,
- _ => false
- }
-}
-
-fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec<Type> {
- let long_ty = Type::i64(ccx);
- let mut args = Vec::new();
-
- let mut n = size / 64;
- while n > 0 {
- args.push(long_ty);
- n -= 1;
- }
-
- let r = size % 64;
- if r > 0 {
- args.push(Type::ix(ccx, r as u64));
- }
-
- args
-}
-
-fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
- let size = ty_size(ty) * 8;
- Type::struct_(ccx, &coerce_to_long(ccx, size), false)
+ let total = arg.layout.size(ccx);
+ arg.cast_to(ccx, Uniform {
+ unit: Reg::i64(),
+ total
+ });
}
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use llvm::*;
-use abi::{ArgAttribute, FnType};
-use type_::Type;
-use super::common::*;
-use super::machine::*;
+use abi::{ArgAttribute, FnType, LayoutExt, Reg, RegKind};
+use common::CrateContext;
#[derive(PartialEq)]
pub enum Flavor {
Fastcall
}
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ fty: &mut FnType<'tcx>,
+ flavor: Flavor) {
if !fty.ret.is_ignore() {
- if fty.ret.ty.kind() == Struct {
+ if fty.ret.layout.is_aggregate() {
// Returning a structure. Most often, this will use
// a hidden first argument. On some platforms, though,
// small structs are returned as integers.
let t = &ccx.sess().target.target;
if t.options.is_like_osx || t.options.is_like_windows
|| t.options.is_like_openbsd {
- match llsize_of_alloc(ccx, fty.ret.ty) {
- 1 => fty.ret.cast = Some(Type::i8(ccx)),
- 2 => fty.ret.cast = Some(Type::i16(ccx)),
- 4 => fty.ret.cast = Some(Type::i32(ccx)),
- 8 => fty.ret.cast = Some(Type::i64(ccx)),
+ let size = fty.ret.layout.size(ccx);
+ match size.bytes() {
+ 1 => fty.ret.cast_to(ccx, Reg::i8()),
+ 2 => fty.ret.cast_to(ccx, Reg::i16()),
+ 4 => fty.ret.cast_to(ccx, Reg::i32()),
+ 8 => fty.ret.cast_to(ccx, Reg::i64()),
_ => fty.ret.make_indirect(ccx)
}
} else {
for arg in &mut fty.args {
if arg.is_ignore() { continue; }
- if arg.ty.kind() == Struct {
+ if arg.layout.is_aggregate() {
arg.make_indirect(ccx);
arg.attrs.set(ArgAttribute::ByVal);
} else {
for arg in &mut fty.args {
if arg.is_ignore() || arg.is_indirect() { continue; }
- if arg.ty.kind() == Float {
+ // At this point we know this must be a primitive of sorts.
+ let unit = arg.layout.homogenous_aggregate(ccx).unwrap();
+ let size = arg.layout.size(ccx);
+ assert_eq!(unit.size, size);
+ if unit.kind == RegKind::Float {
continue;
}
- let size = llbitsize_of_real(ccx, arg.ty);
- let size_in_regs = (size + 31) / 32;
+ let size_in_regs = (size.bits() + 31) / 32;
if size_in_regs == 0 {
continue;
free_regs -= size_in_regs;
- if size <= 32 && (arg.ty.kind() == Pointer || arg.ty.kind() == Integer) {
+ if size.bits() <= 32 && unit.kind == RegKind::Integer {
arg.attrs.set(ArgAttribute::InReg);
}
// The classification code for the x86_64 ABI is taken from the clay language
// https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp
-#![allow(non_upper_case_globals)]
-use self::RegClass::*;
-
-use llvm::{Integer, Pointer, Float, Double};
-use llvm::{Struct, Array, Vector};
-use abi::{self, ArgType, ArgAttribute, FnType};
+use abi::{ArgType, ArgAttribute, CastTarget, FnType, LayoutExt, Reg, RegKind};
use context::CrateContext;
-use type_::Type;
-
-#[derive(Clone, Copy, PartialEq)]
-enum RegClass {
- NoClass,
- Int,
- SSEFs,
- SSEFv,
- SSEDs,
- SSEDv,
- SSEInt(/* bitwidth */ u64),
- /// Data that can appear in the upper half of an SSE register.
- SSEUp,
- X87,
- X87Up,
- ComplexX87,
- Memory
-}
-
-trait TypeMethods {
- fn is_reg_ty(&self) -> bool;
-}
-
-impl TypeMethods for Type {
- fn is_reg_ty(&self) -> bool {
- match self.kind() {
- Integer | Pointer | Float | Double => true,
- _ => false
- }
- }
-}
-
-impl RegClass {
- fn is_sse(&self) -> bool {
- match *self {
- SSEFs | SSEFv | SSEDs | SSEDv | SSEInt(_) => true,
- _ => false
- }
- }
-}
-
-trait ClassList {
- fn is_pass_byval(&self) -> bool;
- fn is_ret_bysret(&self) -> bool;
-}
-
-impl ClassList for [RegClass] {
- fn is_pass_byval(&self) -> bool {
- if self.is_empty() { return false; }
-
- let class = self[0];
- class == Memory
- || class == X87
- || class == ComplexX87
- }
- fn is_ret_bysret(&self) -> bool {
- if self.is_empty() { return false; }
+use rustc::ty::layout::{self, Layout, TyLayout, Size};
- self[0] == Memory
- }
+#[derive(Clone, Copy, PartialEq, Debug)]
+enum Class {
+ None,
+ Int,
+ Sse,
+ SseUp
}
-fn classify_ty(ty: Type) -> Vec<RegClass> {
- fn align(off: usize, ty: Type) -> usize {
- let a = ty_align(ty);
- return (off + a - 1) / a * a;
- }
-
- fn ty_align(ty: Type) -> usize {
- abi::ty_align(ty, 8)
- }
-
- fn ty_size(ty: Type) -> usize {
- abi::ty_size(ty, 8)
- }
-
- fn all_mem(cls: &mut [RegClass]) {
- for elt in cls {
- *elt = Memory;
- }
- }
-
- fn unify(cls: &mut [RegClass],
- i: usize,
- newv: RegClass) {
- if cls[i] == newv { return }
+#[derive(Clone, Copy, Debug)]
+struct Memory;
- let to_write = match (cls[i], newv) {
- (NoClass, _) => newv,
- (_, NoClass) => return,
+// Currently supported vector size (AVX).
+const LARGEST_VECTOR_SIZE: usize = 256;
+const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64;
- (Memory, _) |
- (_, Memory) => Memory,
+fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
+ -> Result<[Class; MAX_EIGHTBYTES], Memory> {
+ fn unify(cls: &mut [Class],
+ off: u64,
+ c: Class) {
+ let i = (off / 8) as usize;
+ let to_write = match (cls[i], c) {
+ (Class::None, _) => c,
+ (_, Class::None) => return,
- (Int, _) |
- (_, Int) => Int,
+ (Class::Int, _) |
+ (_, Class::Int) => Class::Int,
- (X87, _) |
- (X87Up, _) |
- (ComplexX87, _) |
- (_, X87) |
- (_, X87Up) |
- (_, ComplexX87) => Memory,
+ (Class::Sse, _) |
+ (_, Class::Sse) => Class::Sse,
- (SSEFv, SSEUp) |
- (SSEFs, SSEUp) |
- (SSEDv, SSEUp) |
- (SSEDs, SSEUp) |
- (SSEInt(_), SSEUp) => return,
-
- (..) => newv
+ (Class::SseUp, Class::SseUp) => Class::SseUp
};
cls[i] = to_write;
}
- fn classify_struct(tys: &[Type],
- cls: &mut [RegClass],
- i: usize,
- off: usize,
- packed: bool) {
- let mut field_off = off;
- for ty in tys {
- if !packed {
- field_off = align(field_off, *ty);
+ fn classify<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ layout: TyLayout<'tcx>,
+ cls: &mut [Class],
+ off: u64)
+ -> Result<(), Memory> {
+ if off % layout.align(ccx).abi() != 0 {
+ if layout.size(ccx).bytes() > 0 {
+ return Err(Memory);
}
- classify(*ty, cls, i, field_off);
- field_off += ty_size(*ty);
+ return Ok(());
}
- }
- fn classify(ty: Type,
- cls: &mut [RegClass], ix: usize,
- off: usize) {
- let t_align = ty_align(ty);
- let t_size = ty_size(ty);
-
- let misalign = off % t_align;
- if misalign != 0 {
- let mut i = off / 8;
- let e = (off + t_size + 7) / 8;
- while i < e {
- unify(cls, ix + i, Memory);
- i += 1;
+ match *layout {
+ Layout::Scalar { value, .. } |
+ Layout::RawNullablePointer { value, .. } => {
+ let reg = match value {
+ layout::Int(_) |
+ layout::Pointer => Class::Int,
+ layout::F32 |
+ layout::F64 => Class::Sse
+ };
+ unify(cls, off, reg);
}
- return;
- }
- match ty.kind() {
- Integer |
- Pointer => {
- unify(cls, ix + off / 8, Int);
+ Layout::CEnum { .. } => {
+ unify(cls, off, Class::Int);
}
- Float => {
- if off % 8 == 4 {
- unify(cls, ix + off / 8, SSEFv);
- } else {
- unify(cls, ix + off / 8, SSEFs);
+
+ Layout::Vector { element, count } => {
+ unify(cls, off, Class::Sse);
+
+ // everything after the first one is the upper
+ // half of a register.
+ let eltsz = element.size(ccx).bytes();
+ for i in 1..count {
+ unify(cls, off + i * eltsz, Class::SseUp);
}
}
- Double => {
- unify(cls, ix + off / 8, SSEDs);
- }
- Struct => {
- classify_struct(&ty.field_types(), cls, ix, off, ty.is_packed());
- }
- Array => {
- let len = ty.array_length();
- let elt = ty.element_type();
- let eltsz = ty_size(elt);
- let mut i = 0;
- while i < len {
- classify(elt, cls, ix, off + i * eltsz);
- i += 1;
+
+ Layout::Array { count, .. } => {
+ if count > 0 {
+ let elt = layout.field(ccx, 0);
+ let eltsz = elt.size(ccx).bytes();
+ for i in 0..count {
+ classify(ccx, elt, cls, off + i * eltsz)?;
+ }
}
}
- Vector => {
- let len = ty.vector_length();
- let elt = ty.element_type();
- let eltsz = ty_size(elt);
- let mut reg = match elt.kind() {
- Integer => SSEInt(elt.int_width()),
- Float => SSEFv,
- Double => SSEDv,
- _ => bug!("classify: unhandled vector element type")
- };
- let mut i = 0;
- while i < len {
- unify(cls, ix + (off + i * eltsz) / 8, reg);
+ Layout::Univariant { ref variant, .. } => {
+ for i in 0..layout.field_count() {
+ let field_off = off + variant.offsets[i].bytes();
+ classify(ccx, layout.field(ccx, i), cls, field_off)?;
+ }
+ }
- // everything after the first one is the upper
- // half of a register.
- reg = SSEUp;
- i += 1;
+ Layout::UntaggedUnion { .. } => {
+ for i in 0..layout.field_count() {
+ classify(ccx, layout.field(ccx, i), cls, off)?;
}
}
- _ => bug!("classify: unhandled type")
+
+ Layout::FatPointer { .. } |
+ Layout::General { .. } |
+ Layout::StructWrappedNullablePointer { .. } => return Err(Memory)
}
+
+ Ok(())
+ }
+
+ let n = ((arg.layout.size(ccx).bytes() + 7) / 8) as usize;
+ if n > MAX_EIGHTBYTES {
+ return Err(Memory);
}
- fn fixup(ty: Type, cls: &mut [RegClass]) {
+ let mut cls = [Class::None; MAX_EIGHTBYTES];
+ classify(ccx, arg.layout, &mut cls, 0)?;
+ if n > 2 {
+ if cls[0] != Class::Sse {
+ return Err(Memory);
+ }
+ if cls[1..n].iter().any(|&c| c != Class::SseUp) {
+ return Err(Memory);
+ }
+ } else {
let mut i = 0;
- let ty_kind = ty.kind();
- let e = cls.len();
- if cls.len() > 2 && (ty_kind == Struct || ty_kind == Array || ty_kind == Vector) {
- if cls[i].is_sse() {
+ while i < n {
+ if cls[i] == Class::SseUp {
+ cls[i] = Class::Sse;
+ } else if cls[i] == Class::Sse {
i += 1;
- while i < e {
- if cls[i] != SSEUp {
- all_mem(cls);
- return;
- }
- i += 1;
- }
+ while i != n && cls[i] == Class::SseUp { i += 1; }
} else {
- all_mem(cls);
- return
- }
- } else {
- while i < e {
- if cls[i] == Memory {
- all_mem(cls);
- return;
- }
- if cls[i] == X87Up {
- // for darwin
- // cls[i] = SSEDs;
- all_mem(cls);
- return;
- }
- if cls[i] == SSEUp {
- cls[i] = SSEDv;
- } else if cls[i].is_sse() {
- i += 1;
- while i != e && cls[i] == SSEUp { i += 1; }
- } else if cls[i] == X87 {
- i += 1;
- while i != e && cls[i] == X87Up { i += 1; }
- } else {
- i += 1;
- }
+ i += 1;
}
}
}
- let words = (ty_size(ty) + 7) / 8;
- let mut cls = vec![NoClass; words];
- if words > 4 {
- all_mem(&mut cls);
- return cls;
- }
- classify(ty, &mut cls, 0, 0);
- fixup(ty, &mut cls);
- return cls;
+ Ok(cls)
}
-fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
- fn llvec_len(cls: &[RegClass]) -> usize {
- let mut len = 1;
- for c in cls {
- if *c != SSEUp {
- break;
- }
- len += 1;
- }
- return len;
+fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option<Reg> {
+ if *i >= cls.len() {
+ return None;
}
- let mut tys = Vec::new();
- let mut i = 0;
- let e = cls.len();
- while i < e {
- match cls[i] {
- Int => {
- tys.push(Type::i64(ccx));
- }
- SSEFv | SSEDv | SSEInt(_) => {
- let (elts_per_word, elt_ty) = match cls[i] {
- SSEFv => (2, Type::f32(ccx)),
- SSEDv => (1, Type::f64(ccx)),
- SSEInt(bits) => {
- assert!(bits == 8 || bits == 16 || bits == 32 || bits == 64,
- "llreg_ty: unsupported SSEInt width {}", bits);
- (64 / bits, Type::ix(ccx, bits))
+ match cls[*i] {
+ Class::None => None,
+ Class::Int => {
+ *i += 1;
+ Some(match size {
+ 1 => Reg::i8(),
+ 2 => Reg::i16(),
+ 3 |
+ 4 => Reg::i32(),
+ _ => Reg::i64()
+ })
+ }
+ Class::Sse => {
+ let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count();
+ *i += vec_len;
+ Some(match size {
+ 4 => Reg::f32(),
+ 8 => Reg::f64(),
+ _ => {
+ Reg {
+ kind: RegKind::Vector,
+ size: Size::from_bytes(vec_len as u64 * 8)
}
- _ => bug!(),
- };
- let vec_len = llvec_len(&cls[i + 1..]);
- let vec_ty = Type::vector(&elt_ty, vec_len as u64 * elts_per_word);
- tys.push(vec_ty);
- i += vec_len;
- continue;
- }
- SSEFs => {
- tys.push(Type::f32(ccx));
- }
- SSEDs => {
- tys.push(Type::f64(ccx));
- }
- _ => bug!("llregtype: unhandled class")
+ }
+ })
}
- i += 1;
+ c => bug!("reg_component: unhandled class {:?}", c)
}
- if tys.len() == 1 && tys[0].kind() == Vector {
- // if the type contains only a vector, pass it as that vector.
- tys[0]
+}
+
+fn cast_target(cls: &[Class], size: u64) -> CastTarget {
+ let mut i = 0;
+ let lo = reg_component(cls, &mut i, size).unwrap();
+ let offset = i as u64 * 8;
+ let target = if size <= offset {
+ CastTarget::from(lo)
} else {
- Type::struct_(ccx, &tys, false)
- }
+ let hi = reg_component(cls, &mut i, size - offset).unwrap();
+ CastTarget::Pair(lo, hi)
+ };
+ assert_eq!(reg_component(cls, &mut i, 0), None);
+ target
}
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
- fn x86_64_ty<F>(ccx: &CrateContext,
- arg: &mut ArgType,
- is_mem_cls: F,
- ind_attr: Option<ArgAttribute>)
- where F: FnOnce(&[RegClass]) -> bool
- {
- if !arg.ty.is_reg_ty() {
- let cls = classify_ty(arg.ty);
- if is_mem_cls(&cls) {
- arg.make_indirect(ccx);
- if let Some(attr) = ind_attr {
- arg.attrs.set(attr);
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
+ let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
+ let mut sse_regs = 8; // XMM0-7
+
+ let mut x86_64_ty = |arg: &mut ArgType<'tcx>, is_arg: bool| {
+ let cls = classify_arg(ccx, arg);
+
+ let mut needed_int = 0;
+ let mut needed_sse = 0;
+ let in_mem = match cls {
+ Err(Memory) => true,
+ Ok(ref cls) if is_arg => {
+ for &c in cls {
+ match c {
+ Class::Int => needed_int += 1,
+ Class::Sse => needed_sse += 1,
+ _ => {}
+ }
}
- } else {
- arg.cast = Some(llreg_ty(ccx, &cls));
+ arg.layout.is_aggregate() &&
+ (int_regs < needed_int || sse_regs < needed_sse)
}
- } else {
- arg.extend_integer_width_to(32);
- }
- }
+ Ok(_) => false
+ };
- let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
- let mut sse_regs = 8; // XMM0-7
+ if in_mem {
+ // `sret` / `byval` parameter thus one less integer register available
+ int_regs -= 1;
- if !fty.ret.is_ignore() {
- x86_64_ty(ccx, &mut fty.ret, |cls| {
- if cls.is_ret_bysret() {
- // `sret` parameter thus one less register available
- int_regs -= 1;
- true
+ arg.make_indirect(ccx);
+ if is_arg {
+ arg.attrs.set(ArgAttribute::ByVal);
+ }
+ } else {
+ // split into sized chunks passed individually
+ int_regs -= needed_int;
+ sse_regs -= needed_sse;
+
+ if arg.layout.is_aggregate() {
+ let size = arg.layout.size(ccx).bytes();
+ arg.cast_to(ccx, cast_target(cls.as_ref().unwrap(), size))
} else {
- false
+ arg.extend_integer_width_to(32);
}
- }, None);
+ }
+ };
+
+ if !fty.ret.is_ignore() {
+ x86_64_ty(&mut fty.ret, false);
}
for arg in &mut fty.args {
if arg.is_ignore() { continue; }
- x86_64_ty(ccx, arg, |cls| {
- let needed_int = cls.iter().filter(|&&c| c == Int).count() as isize;
- let needed_sse = cls.iter().filter(|c| c.is_sse()).count() as isize;
- let in_mem = cls.is_pass_byval() ||
- int_regs < needed_int ||
- sse_regs < needed_sse;
- if in_mem {
- // `byval` parameter thus one less integer register available
- int_regs -= 1;
- } else {
- // split into sized chunks passed individually
- int_regs -= needed_int;
- sse_regs -= needed_sse;
- }
- in_mem
- }, Some(ArgAttribute::ByVal));
-
- // An integer, pointer, double or float parameter
- // thus the above closure passed to `x86_64_ty` won't
- // get called.
- match arg.ty.kind() {
- Integer | Pointer => int_regs -= 1,
- Double | Float => sse_regs -= 1,
- _ => {}
- }
+ x86_64_ty(arg, true);
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use llvm::*;
-use super::common::*;
-use super::machine::*;
-use abi::{ArgType, FnType};
-use type_::Type;
+use abi::{ArgType, FnType, LayoutExt, Reg};
+use common::CrateContext;
+
+use rustc::ty::layout::Layout;
// Win64 ABI: http://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
- let fixup = |a: &mut ArgType| {
- match a.ty.kind() {
- Struct => match llsize_of_alloc(ccx, a.ty) {
- 1 => a.cast = Some(Type::i8(ccx)),
- 2 => a.cast = Some(Type::i16(ccx)),
- 4 => a.cast = Some(Type::i32(ccx)),
- 8 => a.cast = Some(Type::i64(ccx)),
- _ => a.make_indirect(ccx)
- },
- Integer => match llsize_of_alloc(ccx, a.ty) {
- 1 ... 8 => a.extend_integer_width_to(32),
- 16 => a.make_indirect(ccx),
- _ => bug!(),
- },
- _ => (),
+pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
+ let fixup = |a: &mut ArgType<'tcx>| {
+ let size = a.layout.size(ccx);
+ if a.layout.is_aggregate() {
+ match size.bits() {
+ 8 => a.cast_to(ccx, Reg::i8()),
+ 16 => a.cast_to(ccx, Reg::i16()),
+ 32 => a.cast_to(ccx, Reg::i32()),
+ 64 => a.cast_to(ccx, Reg::i64()),
+ _ => a.make_indirect(ccx)
+ };
+ } else {
+ if let Layout::Vector { .. } = *a.layout {
+ // FIXME(eddyb) there should be a size cap here
+ // (probably what clang calls "illegal vectors").
+ } else if size.bytes() > 8 {
+ a.make_indirect(ccx);
+ } else {
+ a.extend_integer_width_to(32);
+ }
}
};
use type_::Type;
use value::Value;
use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::layout::Layout;
+use rustc::ty::layout::{Layout, LayoutTyper};
use rustc::ty::subst::{Subst, Substs};
use rustc::hir;
Layout::UntaggedUnion { .. } |
Layout::RawNullablePointer { .. } |
Layout::StructWrappedNullablePointer { .. } => {
- !layout.is_unsized() && layout.size(&ccx.tcx().data_layout).bytes() == 0
+ !layout.is_unsized() && layout.size(ccx).bytes() == 0
}
}
}
/// Identify types which have size zero at runtime.
pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
- use machine::llsize_of_alloc;
- use type_of::sizing_type_of;
- let llty = sizing_type_of(ccx, ty);
- llsize_of_alloc(ccx, llty) == 0
+ let layout = ccx.layout_of(ty);
+ !layout.is_unsized() && layout.size(ccx).bytes() == 0
}
/*
ccx.statics_to_rauw().borrow_mut().push((g, new_g));
new_g
};
- llvm::LLVMSetAlignment(g, type_of::align_of(ccx, ty));
+ llvm::LLVMSetAlignment(g, ccx.align_of(ty));
llvm::LLVMSetInitializer(g, v);
// As an optimization, all shared statics which do not have interior
use rustc_data_structures::base_n;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::layout::{LayoutTyper, TyLayout};
use session::config::NoDebugInfo;
use session::Session;
use session::config;
TypeOfDepthLock(self.local())
}
- pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout {
- self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
- ty.layout(&infcx).unwrap_or_else(|e| {
- match e {
- ty::layout::LayoutError::SizeOverflow(_) =>
- self.sess().fatal(&e.to_string()),
- _ => bug!("failed to get layout for `{}`: {}", ty, e)
- }
- })
- })
- }
-
pub fn check_overflow(&self) -> bool {
self.shared.check_overflow
}
}
}
+impl<'a, 'tcx> ty::layout::HasDataLayout for &'a SharedCrateContext<'a, 'tcx> {
+ fn data_layout(&self) -> &ty::layout::TargetDataLayout {
+ &self.tcx.data_layout
+ }
+}
+
+impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
+ self.tcx
+ }
+}
+
+impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CrateContext<'a, 'tcx> {
+ fn data_layout(&self) -> &ty::layout::TargetDataLayout {
+ &self.shared.tcx.data_layout
+ }
+}
+
+impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CrateContext<'a, 'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
+ self.shared.tcx
+ }
+}
+
+impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
+ type TyLayout = TyLayout<'tcx>;
+
+ fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
+ self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
+ infcx.layout_of(ty).unwrap_or_else(|e| {
+ match e {
+ ty::layout::LayoutError::SizeOverflow(_) =>
+ self.sess().fatal(&e.to_string()),
+ _ => bug!("failed to get layout for `{}`: {}", ty, e)
+ }
+ })
+ })
+ }
+}
+
+impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> {
+ type TyLayout = TyLayout<'tcx>;
+
+ fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
+ self.shared.layout_of(ty)
+ }
+}
+
pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>);
impl<'a, 'tcx> Drop for TypeOfDepthLock<'a, 'tcx> {
use {type_of, machine, monomorphize};
use common::{self, CrateContext};
use type_::Type;
-use rustc::ty::{self, AdtKind, Ty, layout};
+use rustc::ty::{self, AdtKind, Ty};
+use rustc::ty::layout::{self, LayoutTyper};
use session::config;
use util::nodemap::FxHashMap;
use util::common::path2cstr;
let offsets = match *layout {
layout::Univariant { ref variant, .. } => &variant.offsets,
layout::Vector { element, count } => {
- let element_size = element.size(&cx.tcx().data_layout).bytes();
+ let element_size = element.size(cx).bytes();
tmp = (0..count).
map(|i| layout::Size::from_bytes(i*element_size))
.collect::<Vec<layout::Size>>();
enum_llvm_type,
EnumMDF(EnumMemberDescriptionFactory {
enum_type: enum_type,
- type_rep: type_rep,
+ type_rep: type_rep.layout,
discriminant_type_metadata: discriminant_type_metadata,
containing_scope: containing_scope,
file_metadata: file_metadata,
let var_name = CString::new(var_name).unwrap();
let linkage_name = CString::new(linkage_name).unwrap();
- let global_align = type_of::align_of(cx, variable_type);
+ let global_align = cx.align_of(variable_type);
unsafe {
llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx),
LocalVariable |
CapturedVariable => (0, DW_TAG_auto_variable)
};
- let align = ::type_of::align_of(cx, variable_type);
+ let align = cx.align_of(variable_type);
let name = CString::new(variable_name.as_str().as_bytes()).unwrap();
match (variable_access, &[][..]) {
use llvm::{ValueRef};
use rustc::traits;
use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::layout::LayoutTyper;
use common::*;
-use machine::*;
use meth;
use monomorphize;
-use type_of::{sizing_type_of, align_of};
use value::Value;
use builder::Builder;
if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) {
scx.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
let layout = t.layout(&infcx).unwrap();
- if layout.size(&scx.tcx().data_layout).bytes() == 0 {
+ if layout.size(scx).bytes() == 0 {
// `Box<ZeroSizeType>` does not allocate.
false
} else {
debug!("calculate size of DST: {}; with lost info: {:?}",
t, Value(info));
if bcx.ccx.shared().type_is_sized(t) {
- let sizing_type = sizing_type_of(bcx.ccx, t);
- let size = llsize_of_alloc(bcx.ccx, sizing_type);
- let align = align_of(bcx.ccx, t);
+ let size = bcx.ccx.size_of(t);
+ let align = bcx.ccx.align_of(t);
debug!("size_and_align_of_dst t={} info={:?} size: {} align: {}",
t, Value(info), size, align);
let size = C_uint(bcx.ccx, size);
ty::TyAdt(def, substs) => {
let ccx = bcx.ccx;
// First get the size of all statically known fields.
- // Don't use type_of::sizing_type_of because that expects t to be sized,
- // and it also rounds up to alignment, which we want to avoid,
- // as the unsized field's alignment could be smaller.
+ // Don't use size_of because it also rounds up to alignment, which we
+ // want to avoid, as the unsized field's alignment could be smaller.
assert!(!t.is_simd());
let layout = ccx.layout_of(t);
debug!("DST {} layout: {:?}", t, layout);
(meth::SIZE.get_usize(bcx, info), meth::ALIGN.get_usize(bcx, info))
}
ty::TySlice(_) | ty::TyStr => {
- let unit_ty = t.sequence_element_type(bcx.tcx());
+ let unit = t.sequence_element_type(bcx.tcx());
// The info in this case is the length of the str, so the size is that
// times the unit size.
- let llunit_ty = sizing_type_of(bcx.ccx, unit_ty);
- let unit_align = llalign_of_min(bcx.ccx, llunit_ty);
- let unit_size = llsize_of_alloc(bcx.ccx, llunit_ty);
- (bcx.mul(info, C_uint(bcx.ccx, unit_size)),
- C_uint(bcx.ccx, unit_align))
+ (bcx.mul(info, C_uint(bcx.ccx, bcx.ccx.size_of(unit))),
+ C_uint(bcx.ccx, bcx.ccx.align_of(unit)))
}
_ => bug!("Unexpected unsized type, found {}", t)
}
use llvm::{ValueRef};
use abi::{Abi, FnType};
use adt;
-use mir::lvalue::LvalueRef;
+use mir::lvalue::{LvalueRef, Alignment};
use base::*;
use common::*;
use declare;
use std::cmp::Ordering;
use std::iter;
-use mir::lvalue::Alignment;
-
fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
let llvm_name = match name {
"sqrtf32" => "llvm.sqrt.f32",
}
"min_align_of" => {
let tp_ty = substs.type_at(0);
- C_uint(ccx, type_of::align_of(ccx, tp_ty))
+ C_uint(ccx, ccx.align_of(tp_ty))
}
"min_align_of_val" => {
let tp_ty = substs.type_at(0);
glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
llalign
} else {
- C_uint(ccx, type_of::align_of(ccx, tp_ty))
+ C_uint(ccx, ccx.align_of(tp_ty))
}
}
"pref_align_of" => {
C_nil(ccx)
}
// Effectively no-ops
- "uninit" | "forget" => {
+ "uninit" => {
C_nil(ccx)
}
"needs_drop" => {
}
let load = bcx.volatile_load(ptr);
unsafe {
- llvm::LLVMSetAlignment(load, type_of::align_of(ccx, tp_ty));
+ llvm::LLVMSetAlignment(load, ccx.align_of(tp_ty));
}
to_immediate(bcx, load, tp_ty)
},
let ptr = bcx.pointercast(llargs[0], val_ty(val).ptr_to());
let store = bcx.volatile_store(val, ptr);
unsafe {
- llvm::LLVMSetAlignment(store, type_of::align_of(ccx, tp_ty));
+ llvm::LLVMSetAlignment(store, ccx.align_of(tp_ty));
}
}
C_nil(ccx)
for i in 0..elems.len() {
let val = bcx.extract_value(val, i);
- bcx.store(val, bcx.struct_gep(llresult, i), None);
+ let lval = LvalueRef::new_sized_ty(llresult, ret_ty,
+ Alignment::AbiAligned);
+ let (dest, align) = lval.trans_field_ptr(bcx, i);
+ bcx.store(val, dest, align.to_align());
}
C_nil(ccx)
}
if val_ty(llval) != Type::void(ccx) && machine::llsize_of_alloc(ccx, val_ty(llval)) != 0 {
if let Some(ty) = fn_ty.ret.cast {
let ptr = bcx.pointercast(llresult, ty.ptr_to());
- bcx.store(llval, ptr, Some(type_of::align_of(ccx, ret_ty)));
+ bcx.store(llval, ptr, Some(ccx.align_of(ret_ty)));
} else {
store_ty(bcx, llval, llresult, Alignment::AbiAligned, ret_ty);
}
-> ValueRef {
let ccx = bcx.ccx;
let lltp_ty = type_of::type_of(ccx, tp_ty);
- let align = C_i32(ccx, type_of::align_of(ccx, tp_ty) as i32);
+ let align = C_i32(ccx, ccx.align_of(tp_ty) as i32);
let size = machine::llsize_of(ccx, lltp_ty);
let int_size = machine::llbitsize_of_real(ccx, ccx.int_type());
count: ValueRef
) -> ValueRef {
let ccx = bcx.ccx;
- let align = C_i32(ccx, type_of::align_of(ccx, ty) as i32);
+ let align = C_i32(ccx, ccx.align_of(ty) as i32);
let lltp_ty = type_of::type_of(ccx, ty);
let size = machine::llsize_of(ccx, lltp_ty);
let dst = bcx.pointercast(dst, Type::i8p(ccx));
use machine;
use monomorphize;
use type_::Type;
-use type_of::*;
use value::Value;
use rustc::ty;
// Not in the cache. Build it.
let nullptr = C_null(Type::nil(ccx).ptr_to());
- let size_ty = sizing_type_of(ccx, ty);
- let size = machine::llsize_of_alloc(ccx, size_ty);
- let align = align_of(ccx, ty);
-
let mut components: Vec<_> = [
callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.shared(), ty)),
- C_uint(ccx, size),
- C_uint(ccx, align)
+ C_uint(ccx, ccx.size_of(ty)),
+ C_uint(ccx, ccx.align_of(ty))
].iter().cloned().collect();
if let Some(trait_ref) = trait_ref {
use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
use rustc::middle::lang_items;
use rustc::middle::const_val::ConstInt;
-use rustc::ty::{self, layout, TypeFoldable};
+use rustc::ty::{self, TypeFoldable};
+use rustc::ty::layout::{self, LayoutTyper};
use rustc::mir;
use abi::{Abi, FnType, ArgType};
use base::{self, Lifetime};
use machine::llalign_of_min;
use meth;
use monomorphize;
+use type_of;
use tvec;
-use type_of::{self, align_of};
use type_::Type;
use rustc_data_structures::indexed_vec::IndexVec;
};
let llslot = match op.val {
Immediate(_) | Pair(..) => {
- let llscratch = bcx.alloca(ret.original_ty, "ret");
+ let llscratch = bcx.alloca(ret.memory_ty(bcx.ccx), "ret");
self.store_operand(&bcx, llscratch, None, op);
llscratch
}
};
let load = bcx.load(
bcx.pointercast(llslot, cast_ty.ptr_to()),
- Some(llalign_of_min(bcx.ccx, ret.ty)));
+ Some(ret.layout.align(bcx.ccx).abi() as u32));
load
} else {
let op = self.trans_consume(&bcx, &mir::Lvalue::Local(mir::RETURN_POINTER));
(llargs[0], &llargs[1..])
}
ReturnDest::Nothing => {
- (C_undef(fn_ty.ret.original_ty.ptr_to()), &llargs[..])
+ (C_undef(fn_ty.ret.memory_ty(bcx.ccx).ptr_to()), &llargs[..])
}
ReturnDest::IndirectOperand(dst, _) |
ReturnDest::Store(dst) => (dst, &llargs[..]),
val: Ref(dst, Alignment::AbiAligned),
ty: sig.output(),
};
- self.store_return(&bcx, ret_dest, fn_ty.ret, op);
+ self.store_return(&bcx, ret_dest, &fn_ty.ret, op);
}
if let Some((_, target)) = *destination {
val: Immediate(invokeret),
ty: sig.output(),
};
- self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op);
+ self.store_return(&ret_bcx, ret_dest, &fn_ty.ret, op);
}
} else {
let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle);
val: Immediate(llret),
ty: sig.output(),
};
- self.store_return(&bcx, ret_dest, fn_ty.ret, op);
+ self.store_return(&bcx, ret_dest, &fn_ty.ret, op);
funclet_br(self, bcx, target);
} else {
bcx.unreachable();
bcx: &Builder<'a, 'tcx>,
op: OperandRef<'tcx>,
llargs: &mut Vec<ValueRef>,
- fn_ty: &FnType,
+ fn_ty: &FnType<'tcx>,
next_idx: &mut usize,
llfn: &mut Option<ValueRef>,
def: &Option<ty::InstanceDef<'tcx>>) {
let (mut llval, align, by_ref) = match op.val {
Immediate(_) | Pair(..) => {
if arg.is_indirect() || arg.cast.is_some() {
- let llscratch = bcx.alloca(arg.original_ty, "arg");
+ let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg");
self.store_operand(bcx, llscratch, None, op);
(llscratch, Alignment::AbiAligned, true)
} else {
// think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't
// have scary latent bugs around.
- let llscratch = bcx.alloca(arg.original_ty, "arg");
+ let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg");
base::memcpy_ty(bcx, llscratch, llval, op.ty, Some(1));
(llscratch, Alignment::AbiAligned, true)
}
if by_ref && !arg.is_indirect() {
// Have to load the argument, maybe while casting it.
- if arg.original_ty == Type::i1(bcx.ccx) {
+ if arg.layout.ty == bcx.tcx().types.bool {
// We store bools as i8 so we need to truncate to i1.
llval = bcx.load_range_assert(llval, 0, 2, llvm::False, None);
- llval = bcx.trunc(llval, arg.original_ty);
+ llval = bcx.trunc(llval, Type::i1(bcx.ccx));
} else if let Some(ty) = arg.cast {
llval = bcx.load(bcx.pointercast(llval, ty.ptr_to()),
- align.min_with(llalign_of_min(bcx.ccx, arg.ty)));
+ align.min_with(arg.layout.align(bcx.ccx).abi() as u32));
} else {
llval = bcx.load(llval, align.to_align());
}
bcx: &Builder<'a, 'tcx>,
operand: &mir::Operand<'tcx>,
llargs: &mut Vec<ValueRef>,
- fn_ty: &FnType,
+ fn_ty: &FnType<'tcx>,
next_idx: &mut usize,
llfn: &mut Option<ValueRef>,
def: &Option<ty::InstanceDef<'tcx>>) {
let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to());
let in_type = val.ty;
let out_type = dst.ty.to_ty(bcx.tcx());;
- let llalign = cmp::min(align_of(bcx.ccx, in_type), align_of(bcx.ccx, out_type));
+ let llalign = cmp::min(bcx.ccx.align_of(in_type), bcx.ccx.align_of(out_type));
self.store_operand(bcx, cast_ptr, Some(llalign), val);
}
fn store_return(&mut self,
bcx: &Builder<'a, 'tcx>,
dest: ReturnDest,
- ret_ty: ArgType,
+ ret_ty: &ArgType<'tcx>,
op: OperandRef<'tcx>) {
use self::ReturnDest::*;
use rustc::infer::TransNormalize;
use rustc::mir;
use rustc::mir::tcx::LvalueTy;
-use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::layout::{self, LayoutTyper};
use rustc::ty::cast::{CastTy, IntTy};
use rustc::ty::subst::{Kind, Substs, Subst};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
} else {
// Otherwise, or if the value is not immediate, we create
// a constant LLVM global and cast its address if necessary.
- let align = type_of::align_of(ccx, self.ty);
+ let align = ccx.align_of(self.ty);
let ptr = consts::addr_of(ccx, self.llval, align, "const");
OperandValue::Ref(consts::ptrcast(ptr, llty.ptr_to()), Alignment::AbiAligned)
};
Base::Value(llval) => {
// FIXME: may be wrong for &*(&simd_vec as &fmt::Debug)
let align = if self.ccx.shared().type_is_sized(ty) {
- type_of::align_of(self.ccx, ty)
+ self.ccx.align_of(ty)
} else {
self.ccx.tcx().data_layout.pointer_align.abi() as machine::llalign
};
vals: &[ValueRef]
) -> ValueRef {
let l = ccx.layout_of(t);
- let dl = &ccx.tcx().data_layout;
let variant_index = match *kind {
mir::AggregateKind::Adt(_, index, _, _) => index,
_ => 0,
let mut vals_with_discr = vec![lldiscr];
vals_with_discr.extend_from_slice(vals);
let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
- let needed_padding = l.size(dl).bytes() - variant.stride().bytes();
+ let needed_padding = l.size(ccx).bytes() - variant.stride().bytes();
if needed_padding > 0 {
contents.push(padding(ccx, needed_padding));
}
C_vector(vals)
}
layout::RawNullablePointer { nndiscr, .. } => {
- let nnty = adt::compute_fields(ccx, t, nndiscr as usize, false)[0];
if variant_index as u64 == nndiscr {
assert_eq!(vals.len(), 1);
vals[0]
} else {
- C_null(type_of::sizing_type_of(ccx, nnty))
+ C_null(type_of::type_of(ccx, t))
}
}
layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
if variant_index as u64 == nndiscr {
C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false)
} else {
- let fields = adt::compute_fields(ccx, t, nndiscr as usize, false);
- let vals = fields.iter().map(|&ty| {
- // Always use null even if it's not the `discrfield`th
- // field; see #8506.
- C_null(type_of::sizing_type_of(ccx, ty))
- }).collect::<Vec<ValueRef>>();
- C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false)
+ // Always use null even if it's not the `discrfield`th
+ // field; see #8506.
+ C_null(type_of::type_of(ccx, t))
}
}
_ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l)
// except according to those terms.
use llvm::ValueRef;
-use rustc::ty::{self, layout, Ty, TypeFoldable};
+use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::layout::{self, LayoutTyper};
use rustc::mir;
use rustc::mir::tcx::LvalueTy;
use rustc_data_structures::indexed_vec::Idx;
use libc::c_uint;
use llvm::{self, ValueRef, BasicBlockRef};
use llvm::debuginfo::DIScope;
-use rustc::ty::{self, layout};
+use rustc::ty;
+use rustc::ty::layout::{self, LayoutTyper};
use rustc::mir::{self, Mir};
use rustc::mir::tcx::LvalueTy;
use rustc::ty::subst::Substs;
ccx: &'a CrateContext<'a, 'tcx>,
- fn_ty: FnType,
+ fn_ty: FnType<'tcx>,
/// When unwinding is initiated, we have to store this personality
/// value somewhere so that we can load it and re-use it in the
let lvalue = LvalueRef::alloca(bcx, arg_ty, &format!("arg{}", arg_index));
for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
- let dst = bcx.struct_gep(lvalue.llval, i);
+ let (dst, _) = lvalue.trans_field_ptr(bcx, i);
let arg = &mircx.fn_ty.args[idx];
idx += 1;
if common::type_is_fat_ptr(bcx.ccx, tupled_arg_ty) {
assert_eq!((meta.cast, meta.pad), (None, None));
let llmeta = llvm::get_param(bcx.llfn(), llarg_idx as c_uint);
llarg_idx += 1;
+
+ // FIXME(eddyb) As we can't perfectly represent the data and/or
+ // vtable pointer in a fat pointers in Rust's typesystem, and
+ // because we split fat pointers into two ArgType's, they're
+ // not the right type so we have to cast them for now.
+ let pointee = match arg_ty.sty {
+ ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
+ ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => ty,
+ ty::TyAdt(def, _) if def.is_box() => arg_ty.boxed_ty(),
+ _ => bug!()
+ };
+ let data_llty = type_of::in_memory_type_of(bcx.ccx, pointee);
+ let meta_llty = type_of::unsized_info_ty(bcx.ccx, pointee);
+
+ let llarg = bcx.pointercast(llarg, data_llty.ptr_to());
+ let llmeta = bcx.pointercast(llmeta, meta_llty);
+
OperandValue::Pair(llarg, llmeta)
} else {
OperandValue::Immediate(llarg)
use llvm::ValueRef;
use rustc::ty::{self, Ty};
-use rustc::ty::layout::Layout;
+use rustc::ty::layout::{Layout, LayoutTyper};
use rustc::mir;
use rustc::mir::tcx::LvalueTy;
use rustc_data_structures::indexed_vec::Idx;
use llvm::{self, ValueRef};
use rustc::ty::{self, Ty};
use rustc::ty::cast::{CastTy, IntTy};
-use rustc::ty::layout::Layout;
+use rustc::ty::layout::{Layout, LayoutTyper};
use rustc::mir::tcx::LvalueTy;
use rustc::mir;
use middle::lang_items::ExchangeMallocFnLangItem;
let content_ty: Ty<'tcx> = self.monomorphize(&content_ty);
let llty = type_of::type_of(bcx.ccx, content_ty);
let llsize = machine::llsize_of(bcx.ccx, llty);
- let align = type_of::align_of(bcx.ccx, content_ty);
+ let align = bcx.ccx.align_of(content_ty);
let llalign = C_uint(bcx.ccx, align);
let llty_ptr = llty.ptr_to();
let box_ty = bcx.tcx().mk_box(content_ty);
use common::*;
use machine;
use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::layout::LayoutTyper;
use trans_item::DefPathBasedNames;
use type_::Type;
use syntax::ast;
-
-// A "sizing type" is an LLVM type, the size and alignment of which are
-// guaranteed to be equivalent to what you would get out of `type_of()`. It's
-// useful because:
-//
-// (1) It may be cheaper to compute the sizing type than the full type if all
-// you're interested in is the size and/or alignment;
-//
-// (2) It won't make any recursive calls to determine the structure of the
-// type behind pointers. This can help prevent infinite loops for
-// recursive types. For example, enum types rely on this behavior.
-
-pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
- if let Some(t) = cx.llsizingtypes().borrow().get(&t).cloned() {
- return t;
- }
-
- debug!("sizing_type_of {:?}", t);
- let _recursion_lock = cx.enter_type_of(t);
-
- let ptr_sizing_ty = |ty: Ty<'tcx>| {
- if cx.shared().type_is_sized(ty) {
- Type::i8p(cx)
- } else {
- Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, ty)], false)
- }
- };
- let llsizingty = match t.sty {
- _ if !cx.shared().type_is_sized(t) => {
- Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, t)], false)
- }
-
- ty::TyBool => Type::bool(cx),
- ty::TyChar => Type::char(cx),
- ty::TyInt(t) => Type::int_from_ty(cx, t),
- ty::TyUint(t) => Type::uint_from_ty(cx, t),
- ty::TyFloat(t) => Type::float_from_ty(cx, t),
- ty::TyNever => Type::nil(cx),
-
- ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
- ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => {
- ptr_sizing_ty(ty)
- }
- ty::TyAdt(def, _) if def.is_box() => {
- ptr_sizing_ty(t.boxed_ty())
- }
-
- ty::TyFnDef(..) => Type::nil(cx),
- ty::TyFnPtr(_) => Type::i8p(cx),
-
- ty::TyArray(ty, size) => {
- let llty = sizing_type_of(cx, ty);
- let size = size as u64;
- Type::array(&llty, size)
- }
-
- ty::TyTuple(ref tys, _) if tys.is_empty() => {
- Type::nil(cx)
- }
-
- ty::TyAdt(..) if t.is_simd() => {
- let e = t.simd_type(cx.tcx());
- if !e.is_machine() {
- cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
- a non-machine element type `{}`",
- t, e))
- }
- let llet = type_of(cx, e);
- let n = t.simd_size(cx.tcx()) as u64;
- Type::vector(&llet, n)
- }
-
- ty::TyTuple(..) | ty::TyAdt(..) | ty::TyClosure(..) => {
- adt::sizing_type_of(cx, t, false)
- }
-
- ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) |
- ty::TyAnon(..) | ty::TyError => {
- bug!("fictitious type {:?} in sizing_type_of()", t)
- }
- ty::TySlice(_) | ty::TyDynamic(..) | ty::TyStr => bug!()
- };
-
- debug!("--> mapped t={:?} to llsizingty={:?}", t, llsizingty);
-
- cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
-
- // FIXME(eddyb) Temporary sanity check for ty::layout.
- let layout = cx.layout_of(t);
- if !cx.shared().type_is_sized(t) {
- if !layout.is_unsized() {
- bug!("layout should be unsized for type `{}` / {:#?}",
- t, layout);
- }
-
- // Unsized types get turned into a fat pointer for LLVM.
- return llsizingty;
- }
-
- let r = layout.size(&cx.tcx().data_layout).bytes();
- let l = machine::llsize_of_alloc(cx, llsizingty);
- if r != l {
- bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
- r, l, t, layout);
- }
-
- let r = layout.align(&cx.tcx().data_layout).abi();
- let l = machine::llalign_of_min(cx, llsizingty) as u64;
- if r != l {
- bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
- r, l, t, layout);
- }
-
- llsizingty
-}
-
pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
match ty.sty {
ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) |
}
}
-fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
+pub fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
let unsized_part = ccx.tcx().struct_tail(ty);
match unsized_part.sty {
ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => {
/// of that field's type - this is useful for taking the address of
/// that field and ensuring the struct has the right alignment.
/// For the LLVM type of a value as a whole, see `type_of`.
-/// NB: If you update this, be sure to update `sizing_type_of()` as well.
pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
// Check the cache.
if let Some(&llty) = cx.lltypes().borrow().get(&t) {
llty
}
-pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>)
- -> machine::llalign {
- let layout = cx.layout_of(t);
- layout.align(&cx.tcx().data_layout).abi() as machine::llalign
+impl<'a, 'tcx> CrateContext<'a, 'tcx> {
+ pub fn align_of(&self, ty: Ty<'tcx>) -> machine::llalign {
+ self.layout_of(ty).align(self).abi() as machine::llalign
+ }
+
+ pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize {
+ self.layout_of(ty).size(self).bytes() as machine::llsize
+ }
}
fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> String {
"rustc_peek" => (1, vec![param(0)], param(0)),
"init" => (1, Vec::new(), param(0)),
"uninit" => (1, Vec::new(), param(0)),
- "forget" => (1, vec![ param(0) ], tcx.mk_nil()),
"transmute" => (2, vec![ param(0) ], param(1)),
"move_val_init" => {
(1,
/// with a space after it.
#[derive(Copy, Clone)]
pub struct ConstnessSpace(pub hir::Constness);
-/// Wrapper struct for properly emitting a method declaration.
-pub struct Method<'a>(pub &'a clean::FnDecl, pub usize);
/// Similar to VisSpace, but used for mutability
#[derive(Copy, Clone)]
pub struct MutableSpace(pub clean::Mutability);
/// Similar to VisSpace, but used for mutability
#[derive(Copy, Clone)]
pub struct RawMutableSpace(pub clean::Mutability);
-/// Wrapper struct for emitting a where clause from Generics.
-pub struct WhereClause<'a>(pub &'a clean::Generics, pub usize);
/// Wrapper struct for emitting type parameter bounds.
pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]);
/// Wrapper struct for emitting a comma-separated list of items
pub struct CommaSep<'a, T: 'a>(pub &'a [T]);
pub struct AbiSpace(pub Abi);
+/// Wrapper struct for properly emitting a method declaration.
+pub struct Method<'a> {
+ /// The declaration to emit.
+ pub decl: &'a clean::FnDecl,
+ /// The length of the function's "name", used to determine line-wrapping.
+ pub name_len: usize,
+ /// The number of spaces to indent each successive line with, if line-wrapping is necessary.
+ pub indent: usize,
+}
+
+/// Wrapper struct for emitting a where clause from Generics.
+pub struct WhereClause<'a>{
+ /// The Generics from which to emit a where clause.
+ pub gens: &'a clean::Generics,
+ /// The number of spaces to indent each line with.
+ pub indent: usize,
+ /// Whether the where clause needs to add a comma and newline after the last bound.
+ pub end_newline: bool,
+}
+
pub struct HRef<'a> {
pub did: DefId,
pub text: &'a str,
impl<'a> fmt::Display for WhereClause<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let &WhereClause(gens, pad) = self;
+ let &WhereClause { gens, indent, end_newline } = self;
if gens.where_predicates.is_empty() {
return Ok(());
}
let mut clause = String::new();
if f.alternate() {
- clause.push_str(" where ");
+ clause.push_str(" where");
} else {
- clause.push_str(" <span class=\"where fmt-newline\">where ");
+ if end_newline {
+ clause.push_str(" <span class=\"where fmt-newline\">where");
+ } else {
+ clause.push_str(" <span class=\"where\">where");
+ }
}
for (i, pred) in gens.where_predicates.iter().enumerate() {
- if i > 0 {
- if f.alternate() {
- clause.push_str(", ");
- } else {
- clause.push_str(",<br>");
- }
+ if f.alternate() {
+ clause.push(' ');
+ } else {
+ clause.push_str("<br>");
}
+
match pred {
&clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => {
let bounds = bounds;
}
}
}
+
+ if i < gens.where_predicates.len() - 1 || end_newline {
+ clause.push(',');
+ }
}
+
+ if end_newline {
+ //add a space so stripping <br> tags and breaking spaces still renders properly
+ if f.alternate() {
+ clause.push(' ');
+ } else {
+ clause.push_str(" ");
+ }
+ }
+
if !f.alternate() {
clause.push_str("</span>");
- let plain = format!("{:#}", self);
- if plain.len() + pad > 80 {
- // break it onto its own line regardless, but make sure method impls and trait
- // blocks keep their fixed padding (2 and 9, respectively)
- let padding = if pad > 10 {
- repeat(" ").take(8).collect::<String>()
- } else {
- repeat(" ").take(pad + 6).collect::<String>()
- };
- clause = clause.replace("<br>", &format!("<br>{}", padding));
- } else {
- clause = clause.replace("<br>", " ");
+ let padding = repeat(" ").take(indent + 4).collect::<String>();
+ clause = clause.replace("<br>", &format!("<br>{}", padding));
+ clause.insert_str(0, &repeat(" ").take(indent.saturating_sub(1))
+ .collect::<String>());
+ if !end_newline {
+ clause.insert_str(0, "<br>");
}
}
write!(f, "{}", clause)
f: &mut fmt::Formatter,
link_trait: bool,
use_absolute: bool) -> fmt::Result {
- let mut plain = String::new();
-
if f.alternate() {
write!(f, "impl{:#} ", i.generics)?;
} else {
write!(f, "impl{} ", i.generics)?;
}
- plain.push_str(&format!("impl{:#} ", i.generics));
if let Some(ref ty) = i.trait_ {
if i.polarity == Some(clean::ImplPolarity::Negative) {
write!(f, "!")?;
- plain.push_str("!");
}
if link_trait {
fmt::Display::fmt(ty, f)?;
- plain.push_str(&format!("{:#}", ty));
} else {
match *ty {
clean::ResolvedPath { typarams: None, ref path, is_generic: false, .. } => {
let last = path.segments.last().unwrap();
fmt::Display::fmt(&last.name, f)?;
fmt::Display::fmt(&last.params, f)?;
- plain.push_str(&format!("{:#}{:#}", last.name, last.params));
}
_ => unreachable!(),
}
}
write!(f, " for ")?;
- plain.push_str(" for ");
}
fmt_type(&i.for_, f, use_absolute, true)?;
- plain.push_str(&format!("{:#}", i.for_));
- fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?;
+ fmt::Display::fmt(&WhereClause { gens: &i.generics, indent: 0, end_newline: true }, f)?;
Ok(())
}
impl<'a> fmt::Display for Method<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let decl = self.0;
- let indent = self.1;
+ let &Method { decl, name_len, indent } = self;
let amp = if f.alternate() { "&" } else { "&" };
let mut args = String::new();
let mut args_plain = String::new();
for (i, input) in decl.inputs.values.iter().enumerate() {
+ if i == 0 {
+ args.push_str("<br>");
+ }
+
if let Some(selfty) = input.to_self() {
match selfty {
clean::SelfValue => {
}
} else {
if i > 0 {
- args.push_str("<br> ");
+ args.push_str(" <br>");
args_plain.push_str(" ");
}
if !input.name.is_empty() {
args_plain.push_str(&format!("{:#}", input.type_));
}
if i + 1 < decl.inputs.values.len() {
- args.push_str(",");
- args_plain.push_str(",");
+ args.push(',');
+ args_plain.push(',');
}
}
format!("{}", decl.output)
};
- let mut output: String;
- let plain: String;
- let pad = repeat(" ").take(indent).collect::<String>();
- if arrow.is_empty() {
- output = format!("({})", args);
- plain = format!("{}({})", pad, args_plain);
+ let pad = repeat(" ").take(name_len).collect::<String>();
+ let plain = format!("{pad}({args}){arrow}",
+ pad = pad,
+ args = args_plain,
+ arrow = arrow_plain);
+
+ let output = if plain.len() > 80 {
+ let full_pad = format!("<br>{}", repeat(" ").take(indent + 4).collect::<String>());
+ let close_pad = format!("<br>{}", repeat(" ").take(indent).collect::<String>());
+ format!("({args}{close}){arrow}",
+ args = args.replace("<br>", &full_pad),
+ close = close_pad,
+ arrow = arrow)
} else {
- output = format!("({args})<br>{arrow}", args = args, arrow = arrow);
- plain = format!("{pad}({args}){arrow}",
- pad = pad,
- args = args_plain,
- arrow = arrow_plain);
- }
+ format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow)
+ };
- if plain.len() > 80 {
- let pad = repeat(" ").take(indent).collect::<String>();
- let pad = format!("<br>{}", pad);
- output = output.replace("<br>", &pad);
- } else {
- output = output.replace("<br>", "");
- }
if f.alternate() {
write!(f, "{}", output.replace("<br>", "\n"))
} else {
UnstableFeatures::Allow => f.constness,
_ => hir::Constness::NotConst
};
- let indent = format!("{}{}{}{:#}fn {}{:#}",
- VisSpace(&it.visibility),
- ConstnessSpace(vis_constness),
- UnsafetySpace(f.unsafety),
- AbiSpace(f.abi),
- it.name.as_ref().unwrap(),
- f.generics).len();
+ let name_len = format!("{}{}{}{:#}fn {}{:#}",
+ VisSpace(&it.visibility),
+ ConstnessSpace(vis_constness),
+ UnsafetySpace(f.unsafety),
+ AbiSpace(f.abi),
+ it.name.as_ref().unwrap(),
+ f.generics).len();
write!(w, "<pre class='rust fn'>")?;
render_attributes(w, it)?;
write!(w, "{vis}{constness}{unsafety}{abi}fn \
abi = AbiSpace(f.abi),
name = it.name.as_ref().unwrap(),
generics = f.generics,
- where_clause = WhereClause(&f.generics, 2),
- decl = Method(&f.decl, indent))?;
+ where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
+ decl = Method {
+ decl: &f.decl,
+ name_len: name_len,
+ indent: 0,
+ })?;
document(w, cx, it)
}
// Output the trait definition
write!(w, "<pre class='rust trait'>")?;
render_attributes(w, it)?;
- write!(w, "{}{}trait {}{}{}{} ",
+ write!(w, "{}{}trait {}{}{}",
VisSpace(&it.visibility),
UnsafetySpace(t.unsafety),
it.name.as_ref().unwrap(),
t.generics,
- bounds,
- // Where clauses in traits are indented nine spaces, per rustdoc.css
- WhereClause(&t.generics, 9))?;
+ bounds)?;
+
+ if !t.generics.where_predicates.is_empty() {
+ write!(w, "{}", WhereClause { gens: &t.generics, indent: 0, end_newline: true })?;
+ } else {
+ write!(w, " ")?;
+ }
let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
for m in &provided {
write!(w, " ")?;
render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?;
- write!(w, " {{ ... }}\n")?;
+ match m.inner {
+ clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => {
+ write!(w, ",\n {{ ... }}\n")?;
+ },
+ _ => {
+ write!(w, " {{ ... }}\n")?;
+ },
+ }
}
write!(w, "}}")?;
}
} else {
hir::Constness::NotConst
};
- let prefix = format!("{}{}{:#}fn {}{:#}",
- ConstnessSpace(vis_constness),
- UnsafetySpace(unsafety),
- AbiSpace(abi),
- name,
- *g);
- let mut indent = prefix.len();
- let where_indent = if parent == ItemType::Trait {
- indent += 4;
- 8
- } else if parent == ItemType::Impl {
- 2
+ let mut head_len = format!("{}{}{:#}fn {}{:#}",
+ ConstnessSpace(vis_constness),
+ UnsafetySpace(unsafety),
+ AbiSpace(abi),
+ name,
+ *g).len();
+ let (indent, end_newline) = if parent == ItemType::Trait {
+ head_len += 4;
+ (4, false)
} else {
- let prefix = prefix + &format!("{:#}", Method(d, indent));
- prefix.lines().last().unwrap().len() + 1
+ (0, true)
};
write!(w, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
{generics}{decl}{where_clause}",
href = href,
name = name,
generics = *g,
- decl = Method(d, indent),
- where_clause = WhereClause(g, where_indent))
+ decl = Method {
+ decl: d,
+ name_len: head_len,
+ indent: indent,
+ },
+ where_clause = WhereClause {
+ gens: g,
+ indent: indent,
+ end_newline: end_newline,
+ })
}
match item.inner {
clean::StrippedItem(..) => Ok(()),
e: &clean::Enum) -> fmt::Result {
write!(w, "<pre class='rust enum'>")?;
render_attributes(w, it)?;
- let padding = format!("{}enum {}{:#} ",
- VisSpace(&it.visibility),
- it.name.as_ref().unwrap(),
- e.generics).len();
write!(w, "{}enum {}{}{}",
VisSpace(&it.visibility),
it.name.as_ref().unwrap(),
e.generics,
- WhereClause(&e.generics, padding))?;
+ WhereClause { gens: &e.generics, indent: 0, end_newline: true })?;
if e.variants.is_empty() && !e.variants_stripped {
write!(w, " {{}}")?;
} else {
fields: &[clean::Item],
tab: &str,
structhead: bool) -> fmt::Result {
- let mut plain = String::new();
write!(w, "{}{}{}",
VisSpace(&it.visibility),
if structhead {"struct "} else {""},
it.name.as_ref().unwrap())?;
- plain.push_str(&format!("{}{}{}",
- VisSpace(&it.visibility),
- if structhead {"struct "} else {""},
- it.name.as_ref().unwrap()));
if let Some(g) = g {
- plain.push_str(&format!("{:#}", g));
write!(w, "{}", g)?
}
match ty {
doctree::Plain => {
if let Some(g) = g {
- write!(w, "{}", WhereClause(g, plain.len() + 1))?
+ write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?
}
let mut has_visible_fields = false;
write!(w, " {{")?;
}
doctree::Tuple => {
write!(w, "(")?;
- plain.push_str("(");
for (i, field) in fields.iter().enumerate() {
if i > 0 {
write!(w, ", ")?;
- plain.push_str(", ");
}
match field.inner {
clean::StrippedItem(box clean::StructFieldItem(..)) => {
- plain.push_str("_");
write!(w, "_")?
}
clean::StructFieldItem(ref ty) => {
- plain.push_str(&format!("{}{:#}", VisSpace(&field.visibility), *ty));
write!(w, "{}{}", VisSpace(&field.visibility), *ty)?
}
_ => unreachable!()
}
}
write!(w, ")")?;
- plain.push_str(")");
if let Some(g) = g {
- write!(w, "{}", WhereClause(g, plain.len() + 1))?
+ write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })?
}
write!(w, ";")?;
}
doctree::Unit => {
// Needed for PhantomData.
if let Some(g) = g {
- write!(w, "{}", WhereClause(g, plain.len() + 1))?
+ write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })?
}
write!(w, ";")?;
}
fields: &[clean::Item],
tab: &str,
structhead: bool) -> fmt::Result {
- let mut plain = String::new();
write!(w, "{}{}{}",
VisSpace(&it.visibility),
if structhead {"union "} else {""},
it.name.as_ref().unwrap())?;
- plain.push_str(&format!("{}{}{}",
- VisSpace(&it.visibility),
- if structhead {"union "} else {""},
- it.name.as_ref().unwrap()));
if let Some(g) = g {
write!(w, "{}", g)?;
- plain.push_str(&format!("{:#}", g));
- write!(w, "{}", WhereClause(g, plain.len() + 1))?;
+ write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?;
}
write!(w, " {{\n{}", tab)?;
fn item_typedef(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
t: &clean::Typedef) -> fmt::Result {
- let indent = format!("type {}{:#} ", it.name.as_ref().unwrap(), t.generics).len();
write!(w, "<pre class='rust typedef'>")?;
render_attributes(w, it)?;
write!(w, "type {}{}{where_clause} = {type_};</pre>",
it.name.as_ref().unwrap(),
t.generics,
- where_clause = WhereClause(&t.generics, indent),
+ where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true },
type_ = t.type_)?;
document(w, cx, it)
.content .where.fmt-newline {
display: block;
}
-/* Bit of whitespace to indent it */
-.content .method .where::before,
-.content .fn .where::before,
-.content .where.fmt-newline::before {
- content: ' ';
-}
.content .methods > div { margin-left: 40px; }
font-size: 90%;
}
-/* Shift where in trait listing down a line */
-pre.trait .where::before {
- content: '\a ';
-}
-
nav {
border-bottom: 1px solid;
padding-bottom: 10px;
nav.sub, .content .out-of-band, .collapse-toggle {
display: none;
}
-}
\ No newline at end of file
+}
#![stable(feature = "rust1", since = "1.0.0")]
use fmt;
-use mem;
use ops::Range;
use iter::FusedIterator;
}
fn make_ascii_uppercase(&mut self) {
- let me: &mut [u8] = unsafe { mem::transmute(self) };
+ let me = unsafe { self.as_bytes_mut() };
me.make_ascii_uppercase()
}
fn make_ascii_lowercase(&mut self) {
- let me: &mut [u8] = unsafe { mem::transmute(self) };
+ let me = unsafe { self.as_bytes_mut() };
me.make_ascii_lowercase()
}
&self.inner
}
+ /// Extracts a `CStr` slice containing the entire string.
+ #[unstable(feature = "as_c_str", issue = "40380")]
+ pub fn as_c_str(&self) -> &CStr {
+ &*self
+ }
+
/// Converts this `CString` into a boxed `CStr`.
#[unstable(feature = "into_boxed_c_str", issue = "40380")]
pub fn into_boxed_c_str(self) -> Box<CStr> {
#![feature(stmt_expr_attributes)]
#![feature(str_char)]
#![feature(str_internals)]
+#![feature(str_mut_extras)]
#![feature(str_utf16)]
#![feature(test, rustc_private)]
#![feature(thread_local)]
}
}
-/// A handle to a child process's stderr. This struct is used in the [`stderr`]
-/// field on [`Child`].
+/// A handle to a child process's stderr.
+///
+/// This struct is used in the [`stderr`] field on [`Child`].
///
/// [`Child`]: struct.Child.html
/// [`stderr`]: struct.Child.html#structfield.stderr
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> !Sync for SyncSender<T> {}
-/// An error returned from the [`send`] function on channels.
+/// An error returned from the [`Sender::send`] or [`SyncSender::send`]
+/// function on **channel**s.
///
-/// A [`send`] operation can only fail if the receiving end of a channel is
+/// A **send** operation can only fail if the receiving end of a channel is
/// disconnected, implying that the data could never be received. The error
/// contains the data being sent as a payload so it can be recovered.
///
-/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send
+/// [`Sender::send`]: struct.Sender.html#method.send
+/// [`SyncSender::send`]: struct.SyncSender.html#method.send
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
/// An error returned from the [`recv`] function on a [`Receiver`].
///
-/// The [`recv`] operation can only fail if the sending half of a channel is
-/// disconnected, implying that no further messages will ever be received.
+/// The [`recv`] operation can only fail if the sending half of a
+/// [`channel`] (or [`sync_channel`]) is disconnected, implying that no further
+/// messages will ever be received.
///
-/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv
-/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+/// [`recv`]: struct.Receiver.html#method.recv
+/// [`Receiver`]: struct.Receiver.html
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RecvError;
/// This enumeration is the list of the possible reasons that [`try_recv`] could
-/// not return data when called.
+/// not return data when called. This can occur with both a [`channel`] and
+/// a [`sync_channel`].
///
-/// [`try_recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.try_recv
+/// [`try_recv`]: struct.Receiver.html#method.try_recv
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum TryRecvError {
- /// This channel is currently empty, but the sender(s) have not yet
+ /// This **channel** is currently empty, but the **Sender**(s) have not yet
/// disconnected, so data may yet become available.
#[stable(feature = "rust1", since = "1.0.0")]
Empty,
- /// This channel's sending half has become disconnected, and there will
- /// never be any more data received on this channel
+ /// The **channel**'s sending half has become disconnected, and there will
+ /// never be any more data received on it.
#[stable(feature = "rust1", since = "1.0.0")]
Disconnected,
}
-/// This enumeration is the list of possible errors that [`recv_timeout`] could
-/// not return data when called.
+/// This enumeration is the list of possible errors that made [`recv_timeout`]
+/// unable to return data when called. This can occur with both a [`channel`] and
+/// a [`sync_channel`].
///
-/// [`recv_timeout`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv_timeout
+/// [`recv_timeout`]: struct.Receiver.html#method.recv_timeout
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
pub enum RecvTimeoutError {
- /// This channel is currently empty, but the sender(s) have not yet
+ /// This **channel** is currently empty, but the **Sender**(s) have not yet
/// disconnected, so data may yet become available.
#[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
Timeout,
- /// This channel's sending half has become disconnected, and there will
- /// never be any more data received on this channel
+ /// The **channel**'s sending half has become disconnected, and there will
+ /// never be any more data received on it.
#[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
Disconnected,
}
/// This enumeration is the list of the possible error outcomes for the
-/// [`SyncSender::try_send`] method.
+/// [`try_send`] method.
///
-/// [`SyncSender::try_send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.try_send
+/// [`try_send`]: struct.SyncSender.html#method.try_send
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum TrySendError<T> {
- /// The data could not be sent on the channel because it would require that
+ /// The data could not be sent on the [`sync_channel`] because it would require that
/// the callee block to send the data.
///
/// If this is a buffered channel, then the buffer is full at this time. If
- /// this is not a buffered channel, then there is no receiver available to
+ /// this is not a buffered channel, then there is no [`Receiver`] available to
/// acquire the data.
+ ///
+ /// [`sync_channel`]: fn.sync_channel.html
+ /// [`Receiver`]: struct.Receiver.html
#[stable(feature = "rust1", since = "1.0.0")]
Full(#[stable(feature = "rust1", since = "1.0.0")] T),
- /// This channel's receiving half has disconnected, so the data could not be
+ /// This [`sync_channel`]'s receiving half has disconnected, so the data could not be
/// sent. The data is returned back to the callee in this case.
+ ///
+ /// [`sync_channel`]: fn.sync_channel.html
#[stable(feature = "rust1", since = "1.0.0")]
Disconnected(#[stable(feature = "rust1", since = "1.0.0")] T),
}
}
/// Creates a new asynchronous channel, returning the sender/receiver halves.
-/// All data sent on the sender will become available on the receiver, and no
-/// send will block the calling thread (this channel has an "infinite buffer").
+/// All data sent on the [`Sender`] will become available on the [`Receiver`] in
+/// the same order as it was sent, and no [`send`] will block the calling thread
+/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
+/// block after its buffer limit is reached). [`recv`] will block until a message
+/// is available.
+///
+/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but
+/// only one [`Receiver`] is supported.
///
/// If the [`Receiver`] is disconnected while trying to [`send`] with the
-/// [`Sender`], the [`send`] method will return an error.
+/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, If the
+/// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will
+/// return a [`RecvError`].
///
-/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send
-/// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html
-/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+/// [`send`]: struct.Sender.html#method.send
+/// [`recv`]: struct.Receiver.html#method.recv
+/// [`Sender`]: struct.Sender.html
+/// [`Receiver`]: struct.Receiver.html
+/// [`sync_channel`]: fn.sync_channel.html
+/// [`SendError`]: struct.SendError.html
+/// [`RecvError`]: struct.RecvError.html
///
/// # Examples
///
/// use std::sync::mpsc::channel;
/// use std::thread;
///
-/// // tx is the sending half (tx for transmission), and rx is the receiving
-/// // half (rx for receiving).
-/// let (tx, rx) = channel();
+/// let (sender, receiver) = channel();
///
/// // Spawn off an expensive computation
/// thread::spawn(move|| {
/// # fn expensive_computation() {}
-/// tx.send(expensive_computation()).unwrap();
+/// sender.send(expensive_computation()).unwrap();
/// });
///
/// // Do some useful work for awhile
///
/// // Let's see what that answer was
-/// println!("{:?}", rx.recv().unwrap());
+/// println!("{:?}", receiver.recv().unwrap());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
}
/// Creates a new synchronous, bounded channel.
-///
-/// Like asynchronous channels, the [`Receiver`] will block until a message
-/// becomes available. These channels differ greatly in the semantics of the
-/// sender from asynchronous channels, however.
+/// All data sent on the [`SyncSender`] will become available on the [`Receiver`]
+/// in the same order as it was sent. Like asynchronous [`channel`]s, the
+/// [`Receiver`] will block until a message becomes available. `sync_channel`
+/// differs greatly in the semantics of the sender, however.
///
/// This channel has an internal buffer on which messages will be queued.
/// `bound` specifies the buffer size. When the internal buffer becomes full,
/// future sends will *block* waiting for the buffer to open up. Note that a
/// buffer size of 0 is valid, in which case this becomes "rendezvous channel"
-/// where each [`send`] will not return until a recv is paired with it.
+/// where each [`send`] will not return until a [`recv`] is paired with it.
+///
+/// The [`SyncSender`] can be cloned to [`send`] to the same channel multiple
+/// times, but only one [`Receiver`] is supported.
///
-/// Like asynchronous channels, if the [`Receiver`] is disconnected while
-/// trying to [`send`] with the [`SyncSender`], the [`send`] method will
-/// return an error.
+/// Like asynchronous channels, if the [`Receiver`] is disconnected while trying
+/// to [`send`] with the [`SyncSender`], the [`send`] method will return a
+/// [`SendError`]. Similarly, If the [`SyncSender`] is disconnected while trying
+/// to [`recv`], the [`recv`] method will return a [`RecvError`].
///
-/// [`send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send
-/// [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html
-/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+/// [`channel`]: fn.channel.html
+/// [`send`]: struct.SyncSender.html#method.send
+/// [`recv`]: struct.Receiver.html#method.recv
+/// [`SyncSender`]: struct.SyncSender.html
+/// [`Receiver`]: struct.Receiver.html
+/// [`SendError`]: struct.SendError.html
+/// [`RecvError`]: struct.RecvError.html
///
/// # Examples
///
/// use std::sync::mpsc::sync_channel;
/// use std::thread;
///
-/// let (tx, rx) = sync_channel(1);
+/// let (sender, receiver) = sync_channel(1);
///
/// // this returns immediately
-/// tx.send(1).unwrap();
+/// sender.send(1).unwrap();
///
/// thread::spawn(move|| {
/// // this will block until the previous message has been received
-/// tx.send(2).unwrap();
+/// sender.send(2).unwrap();
/// });
///
-/// assert_eq!(rx.recv().unwrap(), 1);
-/// assert_eq!(rx.recv().unwrap(), 2);
+/// assert_eq!(receiver.recv().unwrap(), 1);
+/// assert_eq!(receiver.recv().unwrap(), 2);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
/// let data = Arc::new(Mutex::new(0));
///
/// let (tx, rx) = channel();
-/// for _ in 0..10 {
+/// for _ in 0..N {
/// let (data, tx) = (data.clone(), tx.clone());
/// thread::spawn(move || {
/// // The shared state can only be accessed once the lock is held.
}
/// An enumeration of possible errors which can occur while calling the
-/// `try_lock` method.
+/// [`try_lock`] method.
+///
+/// [`try_lock`]: struct.Mutex.html#method.try_lock
#[stable(feature = "rust1", since = "1.0.0")]
pub enum TryLockError<T> {
/// The lock could not be acquired because another thread failed while holding
// Used to preserve symbols (see llvm.used)
(active, used, "1.18.0", Some(40289)),
+
+ // Hack to document `-Z linker-flavor` in The Unstable Book
+ (active, linker_flavor, "1.18.0", Some(41142)),
);
declare_features! (
} else {
label_sp
};
- err.span_label(sp, &label_exp);
- if !sp.source_equal(&self.span) {
+ if self.span.contains(sp) {
+ err.span_label(self.span, &label_exp);
+ } else {
+ err.span_label(sp, &label_exp);
err.span_label(self.span, &"unexpected token");
}
Err(err)
"#);
}
+
+#[test]
+fn long_snippet() {
+ test_harness(r#"
+fn foo() {
+ X0 Y0 Z0
+ X1 Y1 Z1
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+ X2 Y2 Z2
+ X3 Y3 Z3
+}
+"#,
+ vec![
+ SpanLabel {
+ start: Position {
+ string: "Y0",
+ count: 1,
+ },
+ end: Position {
+ string: "X1",
+ count: 1,
+ },
+ label: "`X` is a good letter",
+ },
+ SpanLabel {
+ start: Position {
+ string: "Z1",
+ count: 1,
+ },
+ end: Position {
+ string: "Z3",
+ count: 1,
+ },
+ label: "`Y` is a good letter too",
+ },
+ ],
+ r#"
+error: foo
+ --> test.rs:3:6
+ |
+3 | X0 Y0 Z0
+ | ______^ starting here...
+4 | | X1 Y1 Z1
+ | |____^____- starting here...
+ | ||____|
+ | | ...ending here: `X` is a good letter
+5 | | 1
+6 | | 2
+7 | | 3
+... |
+15 | | X2 Y2 Z2
+16 | | X3 Y3 Z3
+ | |___________- ...ending here: `Y` is a good letter too
+
+"#);
+}
+
+#[test]
+fn long_snippet_multiple_spans() {
+ test_harness(r#"
+fn foo() {
+ X0 Y0 Z0
+1
+2
+3
+ X1 Y1 Z1
+4
+5
+6
+ X2 Y2 Z2
+7
+8
+9
+10
+ X3 Y3 Z3
+}
+"#,
+ vec![
+ SpanLabel {
+ start: Position {
+ string: "Y0",
+ count: 1,
+ },
+ end: Position {
+ string: "Y3",
+ count: 1,
+ },
+ label: "`Y` is a good letter",
+ },
+ SpanLabel {
+ start: Position {
+ string: "Z1",
+ count: 1,
+ },
+ end: Position {
+ string: "Z2",
+ count: 1,
+ },
+ label: "`Z` is a good letter too",
+ },
+ ],
+ r#"
+error: foo
+ --> test.rs:3:6
+ |
+3 | X0 Y0 Z0
+ | ______^ starting here...
+4 | | 1
+5 | | 2
+6 | | 3
+7 | | X1 Y1 Z1
+ | |_________- starting here...
+8 | || 4
+9 | || 5
+10 | || 6
+11 | || X2 Y2 Z2
+ | ||__________- ...ending here: `Z` is a good letter too
+... |
+15 | | 10
+16 | | X3 Y3 Z3
+ | |_______^ ...ending here: `Y` is a good letter
+
+"#);
+}
+
/// Returns a new span representing the next character after the end-point of this span
pub fn next_point(self) -> Span {
let lo = cmp::max(self.hi.0, self.lo.0 + 1);
- Span { lo: BytePos(lo), hi: BytePos(lo + 1), ..self }
+ Span { lo: BytePos(lo), hi: BytePos(lo), ..self }
}
/// Returns `self` if `self` is not the dummy span, and `other` otherwise.
fn str(_: &[u8]) {
}
-// CHECK: @trait_borrow(i8* nonnull, void (i8*)** noalias nonnull readonly)
+// CHECK: @trait_borrow({}* nonnull, {}* noalias nonnull readonly)
// FIXME #25759 This should also have `nocapture`
#[no_mangle]
fn trait_borrow(_: &Drop) {
}
-// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** noalias nonnull readonly)
+// CHECK: @trait_box({}* noalias nonnull, {}* noalias nonnull readonly)
#[no_mangle]
fn trait_box(_: Box<Drop>) {
}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This is a fake compile fail test as there's no way to generate a
+// `#![feature(linker_flavor)]` error. The only reason we have a `linker_flavor`
+// feature gate is to be able to document `-Z linker-flavor` in the unstable
+// book
+
+#[used]
+fn foo() {}
+//~^^ ERROR the `#[used]` attribute is an experimental feature
+
+fn main() {}
#![feature(core_intrinsics)]
-use std::intrinsics::{init, forget};
+use std::intrinsics::{init};
// Test that the `forget` and `init` intrinsics are really unsafe
pub fn main() {
let stuff = init::<isize>(); //~ ERROR call to unsafe function requires unsafe
- forget(stuff); //~ ERROR call to unsafe function requires unsafe
}
+++ /dev/null
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(conservative_impl_trait, specialization)]
-
-trait Foo: Copy + ToString {}
-
-impl<T: Copy + ToString> Foo for T {}
-
-fn hide<T: Foo>(x: T) -> impl Foo {
- x
-}
-
-fn two(x: bool) -> impl Foo {
- if x {
- return 1_i32;
- }
- 0_u32
- //~^ ERROR mismatched types
- //~| expected i32, found u32
-}
-
-fn sum_to(n: u32) -> impl Foo {
- if n == 0 {
- 0
- } else {
- n + sum_to(n - 1)
- //~^ ERROR the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
- }
-}
-
-trait Leak: Sized {
- type T;
- fn leak(self) -> Self::T;
-}
-impl<T> Leak for T {
- default type T = ();
- default fn leak(self) -> Self::T { panic!() }
-}
-impl Leak for i32 {
- type T = i32;
- fn leak(self) -> i32 { self }
-}
-
-fn main() {
- let _: u32 = hide(0_u32);
- //~^ ERROR mismatched types
- //~| expected type `u32`
- //~| found type `impl Foo`
- //~| expected u32, found anonymized type
-
- let _: i32 = Leak::leak(hide(0_i32));
- //~^ ERROR mismatched types
- //~| expected type `i32`
- //~| found type `<impl Foo as Leak>::T`
- //~| expected i32, found associated type
-
- let mut x = (hide(0_u32), hide(0_i32));
- x = (x.1,
- //~^ ERROR mismatched types
- //~| expected u32, found i32
- x.0);
- //~^ ERROR mismatched types
- //~| expected i32, found u32
-}
{
"data-layout": "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128",
+ "linker-flavor": "gcc",
"llvm-target": "i686-unknown-linux-gnu",
"target-endian": "little",
"target-pointer-width": "32",
{
"data-layout": "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32",
+ "linker-flavor": "gcc",
"target-endian": "little",
"target-pointer-width": "32",
"arch": "x86",
{
"pre-link-args": ["-m64"],
"data-layout": "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128",
+ "linker-flavor": "gcc",
"llvm-target": "x86_64-unknown-linux-gnu",
"target-endian": "little",
"target-pointer-width": "64",
--- /dev/null
+// 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.
+
+#![crate_name="foo"]
+
+use std::mem::size_of;
+
+// compile-flags: -Z fuel=foo=0
+
+struct S1(u8, u16, u8);
+struct S2(u8, u16, u8);
+
+fn main() {
+ assert_eq!(size_of::<S1>(), 6);
+ assert_eq!(size_of::<S2>(), 6);
+}
+
--- /dev/null
+// 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.
+
+#![crate_name="foo"]
+
+use std::mem::size_of;
+
+// compile-flags: -Z fuel=foo=1
+
+struct S1(u8, u16, u8);
+struct S2(u8, u16, u8);
+
+fn main() {
+ let optimized = (size_of::<S1>() == 4) as usize
+ +(size_of::<S2>() == 4) as usize;
+ assert_eq!(optimized, 1);
+}
+
+
a([u16; 0], u8), b
}
+struct ReorderedStruct {
+ a: u8,
+ b: u16,
+ c: u8
+}
+
+enum ReorderedEnum {
+ A(u8, u16, u8),
+ B(u8, u16, u8),
+}
+
pub fn main() {
assert_eq!(size_of::<u8>(), 1 as usize);
assert_eq!(size_of::<u32>(), 4 as usize);
assert_eq!(size_of::<e1>(), 8 as usize);
assert_eq!(size_of::<e2>(), 8 as usize);
assert_eq!(size_of::<e3>(), 4 as usize);
+ assert_eq!(size_of::<ReorderedStruct>(), 4);
+ assert_eq!(size_of::<ReorderedEnum>(), 6);
}
pub struct Foo<T> { field: T }
// @has impl_parts/struct.Foo.html '//*[@class="impl"]//code' \
-// "impl<T: Clone> !AnOibit for Foo<T> where T: Sync"
+// "impl<T: Clone> !AnOibit for Foo<T> where T: Sync,"
// @has impl_parts/trait.AnOibit.html '//*[@class="item-list"]//code' \
-// "impl<T: Clone> !AnOibit for Foo<T> where T: Sync"
+// "impl<T: Clone> !AnOibit for Foo<T> where T: Sync,"
impl<T: Clone> !AnOibit for Foo<T> where T: Sync {}
pub mod reexport {
// @has issue_20727_4/reexport/trait.Index.html
- // @has - '//*[@class="rust trait"]' 'trait Index<Idx> where Idx: ?Sized {'
+ // @has - '//*[@class="rust trait"]' 'trait Index<Idx> where Idx: ?Sized, {'
// @has - '//*[@class="rust trait"]' 'type Output: ?Sized'
// @has - '//*[@class="rust trait"]' \
// 'fn index(&self, index: Idx) -> &Self::Output'
// @has issue_20727_4/reexport/trait.IndexMut.html
// @has - '//*[@class="rust trait"]' \
- // 'trait IndexMut<Idx>: Index<Idx> where Idx: ?Sized {'
+ // 'trait IndexMut<Idx>: Index<Idx> where Idx: ?Sized, {'
// @has - '//*[@class="rust trait"]' \
// 'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;'
pub use issue_20727::IndexMut;
impl<F> MyTrait for Foxtrot<F> where F: MyTrait {}
// @has foo/type.Golf.html '//pre[@class="rust typedef"]' \
-// "type Golf<T> where T: Clone = (T, T)"
+// "type Golf<T> where T: Clone, = (T, T)"
pub type Golf<T> where T: Clone = (T, T);
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(conservative_impl_trait, specialization)]
+
+trait Foo: Copy + ToString {}
+
+impl<T: Copy + ToString> Foo for T {}
+
+fn hide<T: Foo>(x: T) -> impl Foo {
+ x
+}
+
+fn two(x: bool) -> impl Foo {
+ if x {
+ return 1_i32;
+ }
+ 0_u32
+ //~^ ERROR mismatched types
+ //~| expected i32, found u32
+}
+
+fn sum_to(n: u32) -> impl Foo {
+ if n == 0 {
+ 0
+ } else {
+ n + sum_to(n - 1)
+ //~^ ERROR no implementation for `u32 + impl Foo`
+ }
+}
+
+trait Leak: Sized {
+ type T;
+ fn leak(self) -> Self::T;
+}
+impl<T> Leak for T {
+ default type T = ();
+ default fn leak(self) -> Self::T { panic!() }
+}
+impl Leak for i32 {
+ type T = i32;
+ fn leak(self) -> i32 { self }
+}
+
+fn main() {
+ let _: u32 = hide(0_u32);
+ //~^ ERROR mismatched types
+ //~| expected type `u32`
+ //~| found type `impl Foo`
+ //~| expected u32, found anonymized type
+
+ let _: i32 = Leak::leak(hide(0_i32));
+ //~^ ERROR mismatched types
+ //~| expected type `i32`
+ //~| found type `<impl Foo as Leak>::T`
+ //~| expected i32, found associated type
+
+ let mut x = (hide(0_u32), hide(0_i32));
+ x = (x.1,
+ //~^ ERROR mismatched types
+ //~| expected u32, found i32
+ x.0);
+ //~^ ERROR mismatched types
+ //~| expected i32, found u32
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/equality.rs:25:5
+ |
+25 | 0_u32
+ | ^^^^^ expected i32, found u32
+ |
+ = note: expected type `i32`
+ found type `u32`
+
+error[E0277]: the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
+ --> $DIR/equality.rs:34:9
+ |
+34 | n + sum_to(n - 1)
+ | ^^^^^^^^^^^^^^^^^ the trait `std::ops::Add<impl Foo>` is not implemented for `u32`
+ |
+ = note: no implementation for `u32 + impl Foo`
+
+error[E0308]: mismatched types
+ --> $DIR/equality.rs:53:18
+ |
+53 | let _: u32 = hide(0_u32);
+ | ^^^^^^^^^^^ expected u32, found anonymized type
+ |
+ = note: expected type `u32`
+ found type `impl Foo`
+
+error[E0308]: mismatched types
+ --> $DIR/equality.rs:59:18
+ |
+59 | let _: i32 = Leak::leak(hide(0_i32));
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found associated type
+ |
+ = note: expected type `i32`
+ found type `<impl Foo as Leak>::T`
+
+error[E0308]: mismatched types
+ --> $DIR/equality.rs:66:10
+ |
+66 | x = (x.1,
+ | ^^^ expected u32, found i32
+ |
+ = note: expected type `impl Foo` (u32)
+ found type `impl Foo` (i32)
+
+error[E0308]: mismatched types
+ --> $DIR/equality.rs:69:10
+ |
+69 | x.0);
+ | ^^^ expected i32, found u32
+ |
+ = note: expected type `impl Foo` (i32)
+ found type `impl Foo` (u32)
+
+error: aborting due to 6 previous errors
+
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ 1 + Some(1);
+ 2 as usize - Some(1);
+ 3 * ();
+ 4 / "";
+ 5 < String::new();
+ 6 == Ok(1);
+}
--- /dev/null
+error[E0277]: the trait bound `{integer}: std::ops::Add<std::option::Option<{integer}>>` is not satisfied
+ --> $DIR/binops.rs:12:5
+ |
+12 | 1 + Some(1);
+ | ^^^^^^^^^^^ the trait `std::ops::Add<std::option::Option<{integer}>>` is not implemented for `{integer}`
+ |
+ = note: no implementation for `{integer} + std::option::Option<{integer}>`
+
+error[E0277]: the trait bound `usize: std::ops::Sub<std::option::Option<{integer}>>` is not satisfied
+ --> $DIR/binops.rs:13:5
+ |
+13 | 2 as usize - Some(1);
+ | ^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Sub<std::option::Option<{integer}>>` is not implemented for `usize`
+ |
+ = note: no implementation for `usize - std::option::Option<{integer}>`
+
+error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied
+ --> $DIR/binops.rs:14:5
+ |
+14 | 3 * ();
+ | ^^^^^^ the trait `std::ops::Mul<()>` is not implemented for `{integer}`
+ |
+ = note: no implementation for `{integer} * ()`
+
+error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied
+ --> $DIR/binops.rs:15:5
+ |
+15 | 4 / "";
+ | ^^^^^^ the trait `std::ops::Div<&str>` is not implemented for `{integer}`
+ |
+ = note: no implementation for `{integer} / &str`
+
+error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::string::String>` is not satisfied
+ --> $DIR/binops.rs:16:5
+ |
+16 | 5 < String::new();
+ | ^^^^^^^^^^^^^^^^^ the trait `std::cmp::PartialEq<std::string::String>` is not implemented for `{integer}`
+ |
+ = note: can't compare `{integer}` with `std::string::String`
+
+error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd<std::string::String>` is not satisfied
+ --> $DIR/binops.rs:16:5
+ |
+16 | 5 < String::new();
+ | ^^^^^^^^^^^^^^^^^ the trait `std::cmp::PartialOrd<std::string::String>` is not implemented for `{integer}`
+ |
+ = note: can't compare `{integer}` with `std::string::String`
+
+error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::result::Result<{integer}, _>>` is not satisfied
+ --> $DIR/binops.rs:17:5
+ |
+17 | 6 == Ok(1);
+ | ^^^^^^^^^^ the trait `std::cmp::PartialEq<std::result::Result<{integer}, _>>` is not implemented for `{integer}`
+ |
+ = note: can't compare `{integer}` with `std::result::Result<{integer}, _>`
+
+error: aborting due to 7 previous errors
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name="foo"]
+#![allow(dead_code)]
+
+// compile-flags: -Z print-fuel=foo
+
+struct S1(u8, u16, u8);
+struct S2(u8, u16, u8);
+struct S3(u8, u16, u8);
+
+fn main() {
+}
--- /dev/null
+Fuel used by foo: 3
-print-type-size type: `IndirectNonZero<u32>`: 20 bytes, alignment: 4 bytes
-print-type-size field `.pre`: 1 bytes
-print-type-size padding: 3 bytes
-print-type-size field `.nested`: 12 bytes, alignment: 4 bytes
+print-type-size type: `IndirectNonZero<u32>`: 12 bytes, alignment: 4 bytes
+print-type-size field `.nested`: 8 bytes
print-type-size field `.post`: 2 bytes
-print-type-size end padding: 2 bytes
-print-type-size type: `MyOption<IndirectNonZero<u32>>`: 20 bytes, alignment: 4 bytes
-print-type-size variant `Some`: 20 bytes
-print-type-size field `.0`: 20 bytes
-print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes
-print-type-size variant `Record`: 10 bytes
-print-type-size field `.pre`: 1 bytes
-print-type-size padding: 3 bytes
-print-type-size field `.val`: 4 bytes, alignment: 4 bytes
-print-type-size field `.post`: 2 bytes
-print-type-size end padding: 2 bytes
-print-type-size type: `NestedNonZero<u32>`: 12 bytes, alignment: 4 bytes
print-type-size field `.pre`: 1 bytes
-print-type-size padding: 3 bytes
-print-type-size field `.val`: 4 bytes, alignment: 4 bytes
+print-type-size end padding: 1 bytes
+print-type-size type: `MyOption<IndirectNonZero<u32>>`: 12 bytes, alignment: 4 bytes
+print-type-size variant `Some`: 12 bytes
+print-type-size field `.0`: 12 bytes
+print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
+print-type-size variant `Record`: 7 bytes
+print-type-size field `.val`: 4 bytes
+print-type-size field `.post`: 2 bytes
+print-type-size field `.pre`: 1 bytes
+print-type-size end padding: 1 bytes
+print-type-size type: `NestedNonZero<u32>`: 8 bytes, alignment: 4 bytes
+print-type-size field `.val`: 4 bytes
print-type-size field `.post`: 2 bytes
-print-type-size end padding: 2 bytes
+print-type-size field `.pre`: 1 bytes
+print-type-size end padding: 1 bytes
print-type-size type: `MyOption<core::nonzero::NonZero<u32>>`: 4 bytes, alignment: 4 bytes
print-type-size variant `Some`: 4 bytes
print-type-size field `.0`: 4 bytes
-print-type-size type: `Padded`: 16 bytes, alignment: 4 bytes
+print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes
+print-type-size field `.g`: 4 bytes
+print-type-size field `.h`: 2 bytes
print-type-size field `.a`: 1 bytes
print-type-size field `.b`: 1 bytes
-print-type-size padding: 2 bytes
-print-type-size field `.g`: 4 bytes, alignment: 4 bytes
print-type-size field `.c`: 1 bytes
-print-type-size padding: 1 bytes
-print-type-size field `.h`: 2 bytes, alignment: 2 bytes
print-type-size field `.d`: 1 bytes
-print-type-size end padding: 3 bytes
+print-type-size end padding: 2 bytes
print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes
print-type-size field `.a`: 1 bytes
print-type-size field `.b`: 1 bytes
print-type-size type: `E1`: 12 bytes, alignment: 4 bytes
-print-type-size discriminant: 4 bytes
-print-type-size variant `A`: 5 bytes
-print-type-size field `.0`: 4 bytes
+print-type-size discriminant: 1 bytes
+print-type-size variant `A`: 7 bytes
print-type-size field `.1`: 1 bytes
-print-type-size variant `B`: 8 bytes
-print-type-size field `.0`: 8 bytes
+print-type-size padding: 2 bytes
+print-type-size field `.0`: 4 bytes, alignment: 4 bytes
+print-type-size variant `B`: 11 bytes
+print-type-size padding: 3 bytes
+print-type-size field `.0`: 8 bytes, alignment: 4 bytes
print-type-size type: `E2`: 12 bytes, alignment: 4 bytes
print-type-size discriminant: 1 bytes
print-type-size variant `A`: 7 bytes
print-type-size padding: 3 bytes
print-type-size field `.0`: 8 bytes, alignment: 4 bytes
print-type-size type: `S`: 8 bytes, alignment: 4 bytes
+print-type-size field `.g`: 4 bytes
print-type-size field `.a`: 1 bytes
print-type-size field `.b`: 1 bytes
-print-type-size padding: 2 bytes
-print-type-size field `.g`: 4 bytes, alignment: 4 bytes
+print-type-size end padding: 2 bytes
23 | | //~^ ERROR E0046
24 | | //~| NOTE missing `bar` in implementation
25 | | const bar: u64 = 1;
-26 | | //~^ ERROR E0323
-27 | | //~| NOTE does not match trait
+... |
28 | | const MY_CONST: u32 = 1;
29 | | }
| |_^ ...ending here: missing `bar` in implementation
34 | | //~^ ERROR E0046
35 | | //~| NOTE missing `MY_CONST` in implementation
36 | | fn bar(&self) {}
-37 | | fn MY_CONST() {}
-38 | | //~^ ERROR E0324
+... |
39 | | //~| NOTE does not match trait
40 | | }
| |_^ ...ending here: missing `MY_CONST` in implementation
45 | | //~^ ERROR E0046
46 | | //~| NOTE missing `bar` in implementation
47 | | type bar = u64;
-48 | | //~^ ERROR E0325
-49 | | //~| NOTE does not match trait
+... |
50 | | const MY_CONST: u32 = 1;
51 | | }
| |_^ ...ending here: missing `bar` in implementation
error[E0046]: not all trait items implemented, missing: `Item`
--> $DIR/issue-23729.rs:20:9
|
-20 | impl Iterator for Recurrence {
- | ^ missing `Item` in implementation
+20 | impl Iterator for Recurrence {
+ | _________^ starting here...
+21 | | //~^ ERROR E0046
+22 | | //~| NOTE missing `Item` in implementation
+23 | | //~| NOTE `Item` from trait: `type Item;`
+... |
+36 | | }
+37 | | }
+ | |_________^ ...ending here: missing `Item` in implementation
|
= note: `Item` from trait: `type Item;`
37 | | //~^ ERROR E0046
38 | | //~| NOTE missing `Output` in implementation
39 | | //~| NOTE `Output` from trait: `type Output;`
-40 | | extern "rust-call" fn call_once(self, (comp,): (C,)) -> Prototype {
-41 | | Fn::call(&self, (comp,))
+... |
42 | | }
43 | | }
| |_^ ...ending here: missing `Output` in implementation
27 | | y),
| |______________^ ...ending here: the trait `std::ops::Add<()>` is not implemented for `u32`
|
- = help: the following implementations were found:
- <u32 as std::ops::Add>
- <&'a u32 as std::ops::Add<u32>>
- <u32 as std::ops::Add<&'a u32>>
- <&'b u32 as std::ops::Add<&'a u32>>
+ = note: no implementation for `u32 + ()`
error: aborting due to previous error
--- /dev/null
+// Copyright 2017 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.
+
+impl S {
+ pub
+}
--- /dev/null
+error: expected one of `(`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found `}`
+ --> $DIR/issue-41155.rs:13:1
+ |
+12 | pub
+ | - expected one of 7 possible tokens here
+13 | }
+ | ^ unexpected token
+
+error: aborting due to previous error
+
});
let path_bytes = rel_path.as_os_str().as_bytes();
if output.status.success() && output.stdout.starts_with(path_bytes) {
- println!("binary checked into source: {}", file.display());
- *bad = true;
+ tidy_error!(bad, "binary checked into source: {}", file.display());
}
}
})
}
if !librs.contains(&format!("extern crate {}", krate)) {
- println!("{} doesn't have `extern crate {}`, but Cargo.toml \
- depends on it", libfile.display(), krate);
- *bad = true;
+ tidy_error!(bad, "{} doesn't have `extern crate {}`, but Cargo.toml \
+ depends on it", libfile.display(), krate);
}
}
}
continue
}
- println!("duplicate error code: {}", code);
+ tidy_error!(bad, "duplicate error code: {}", code);
for &(ref file, line_num, ref line) in entries.iter() {
- println!("{}:{}: {}", file.display(), line_num, line);
+ tidy_error!(bad, "{}:{}: {}", file.display(), line_num, line);
}
- *bad = true;
}
if !*bad {
for (i, line) in contents.lines().enumerate() {
let mut err = |msg: &str| {
- println!("{}:{}: {}", file.display(), i + 1, msg);
- *bad = true;
+ tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
};
let gate_test_str = "gate-test-";
}
if gate_untested.len() > 0 {
- println!("Found {} features without a gate test.", gate_untested.len());
- *bad = true;
+ tidy_error!(bad, "Found {} features without a gate test.", gate_untested.len());
}
if *bad {
for (i, line) in contents.lines().enumerate() {
let mut err = |msg: &str| {
- println!("{}:{}: {}", file.display(), i + 1, msg);
- *bad = true;
+ tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
};
let level = if line.contains("[unstable(") {
Status::Unstable
extern crate regex;
+use std::env;
use std::fs;
+use std::io::{self, Write};
use std::path::{PathBuf, Path};
-use std::env;
+use std::process;
macro_rules! t {
($e:expr, $p:expr) => (match $e {
})
}
+macro_rules! tidy_error {
+ ($bad:expr, $fmt:expr, $($arg:tt)*) => ({
+ use std::io::Write;
+ *$bad = true;
+ write!(::std::io::stderr(), "tidy error: ").expect("could not write to stderr");
+ writeln!(::std::io::stderr(), $fmt, $($arg)*).expect("could not write to stderr");
+ });
+}
+
mod bins;
mod style;
mod errors;
}
if bad {
- panic!("some tidy checks failed");
+ writeln!(io::stderr(), "some tidy checks failed").expect("could not write to stderr");
+ process::exit(1);
}
}
Ok(_) => unreachable!(),
Err(i) => i + 1
};
- println!("{}:{}: platform-specific cfg: {}", file.display(), line, cfg);
- *bad = true;
+ tidy_error!(bad, "{}:{}: platform-specific cfg: {}", file.display(), line, cfg);
};
for (idx, cfg) in cfgs.into_iter() {
let skip_end_whitespace = contents.contains("ignore-tidy-end-whitespace");
for (i, line) in contents.split("\n").enumerate() {
let mut err = |msg: &str| {
- println!("{}:{}: {}", file.display(), i + 1, msg);
- *bad = true;
+ tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
};
if !skip_length && line.chars().count() > COLS
&& !long_line_is_ok(line) {
}
}
if !licenseck(file, &contents) {
- println!("{}: incorrect license", file.display());
- *bad = true;
+ tidy_error!(bad, "{}: incorrect license", file.display());
}
})
}
use std::collections::HashSet;
use std::fs;
-use std::io::{self, BufRead, Write};
+use std::io::{self, BufRead};
use std::path;
use features::{collect_lang_features, collect_lib_features, Status};
// Check for Unstable Book section names with no corresponding SUMMARY.md link
for feature_name in &unstable_book_section_file_names - &unstable_book_links {
- *bad = true;
- writeln!(io::stderr(),
- "The Unstable Book section '{}' needs to have a link in SUMMARY.md",
- feature_name)
- .expect("could not write to stderr")
+ tidy_error!(
+ bad,
+ "The Unstable Book section '{}' needs to have a link in SUMMARY.md",
+ feature_name);
}
// Check for unstable features that don't have Unstable Book sections
for feature_name in &unstable_feature_names - &unstable_book_section_file_names {
- *bad = true;
- writeln!(io::stderr(),
- "Unstable feature '{}' needs to have a section in The Unstable Book",
- feature_name)
- .expect("could not write to stderr")
+ tidy_error!(
+ bad,
+ "Unstable feature '{}' needs to have a section in The Unstable Book",
+ feature_name);
}
// Check for Unstable Book sections that don't have a corresponding unstable feature
for feature_name in &unstable_book_section_file_names - &unstable_feature_names {
- *bad = true;
- writeln!(io::stderr(),
- "The Unstable Book has a section '{}' which doesn't correspond \
- to an unstable feature",
- feature_name)
- .expect("could not write to stderr")
+ tidy_error!(
+ bad,
+ "The Unstable Book has a section '{}' which doesn't correspond \
+ to an unstable feature",
+ feature_name)
}
}