* `|` (`|…| expr`): closures. See [Closures].
* `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`).
* `||` (`expr || expr`): logical or.
-* `_`: "ignored" pattern binding. See [Patterns (Ignoring bindings)].
+* `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]).
## Other Syntax
[Primitive Types (Tuples)]: primitive-types.html#tuples
[Raw Pointers]: raw-pointers.html
[Reference (Byte String Literals)]: ../reference.html#byte-string-literals
+[Reference (Integer literals)]: ../reference.html#integer-literals
[Reference (Raw Byte String Literals)]: ../reference.html#raw-byte-string-literals
[Reference (Raw String Literals)]: ../reference.html#raw-string-literals
[References and Borrowing]: references-and-borrowing.html
# trait Foo { fn method(&self) -> String; }
# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } }
# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } }
-
fn do_something(x: &Foo) {
x.method();
}
# trait Foo { fn method(&self) -> String; }
# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } }
# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } }
-
fn do_something(x: &Foo) {
x.method();
}
}
```
-Unlike the previous example it *appears* that everything is exactly as we
+Unlike the previous example, it *appears* that everything is exactly as we
want. Every generic argument to Vec shows up in at least one field.
Good to go!
* includes a `PhantomData<T>`
* auto-derives Send/Sync as if T was contained
* marks the pointer as NonZero for the null-pointer optimization
-
A number of [attributes](#ffi-attributes) control the behavior of external blocks.
By default external blocks assume that the library they are calling uses the
-standard C "cdecl" ABI. Other ABIs may be specified using an `abi` string, as
-shown here:
+standard C ABI on the specific platform. Other ABIs may be specified using an
+`abi` string, as shown here:
```ignore
// Interface to the Windows API
extern "stdcall" { }
```
+There are three ABI strings which are cross-platform, and which all compilers
+are guaranteed to support:
+
+* `extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any
+ Rust code.
+* `extern "C"` -- This is the same as `extern fn foo()`; whatever the default
+ your C compiler supports.
+* `extern "system"` -- Usually the same as `extern "C"`, except on Win32, in
+ which case it's `"stdcall"`, or what you should use to link to the Windows API
+ itself
+
+There are also some platform-specific ABI strings:
+
+* `extern "cdecl"` -- The default for x86\_32 C code.
+* `extern "stdcall"` -- The default for the Win32 API on x86\_32.
+* `extern "win64"` -- The default for C code on x86\_64 Windows.
+* `extern "aapcs"` -- The default for ARM.
+* `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's
+ `__fastcall` and GCC and clang's `__attribute__((fastcall))`
+* `extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's
+ `__vectorcall` and clang's `__attribute__((vectorcall))`
+
+Finally, there are some rustc-specific ABI strings:
+
+* `extern "rust-intrinsic"` -- The ABI of rustc intrinsics.
+* `extern "rust-call"` -- The ABI of the Fn::call trait functions.
+* `extern "platform-intrinsic"` -- Specific platform intrinsics -- like, for
+ example, `sqrt` -- have this ABI. You should never have to deal with it.
+
The `link` attribute allows the name of the library to be specified. When
specified the compiler will attempt to link against the native library of the
specified name.
//!
//! Sharing some immutable data between threads:
//!
+// Note that we **do not** run these tests here. The windows builders get super
+// unhappy of a thread outlives the main thread and then exits at the same time
+// (something deadlocks) so we just avoid this entirely by not running these
+// tests.
//! ```no_run
//! use std::sync::Arc;
//! use std::thread;
/// by putting it inside `Mutex` and then share `Mutex` immutably
/// with `Arc<T>` as shown below.
///
-/// ```
+// See comment at the top of this file for why the test is no_run
+/// ```no_run
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
///
/// # Example
///
- /// Print the adjacent pairs of a slice (i.e. `[1,2]`, `[2,3]`,
- /// `[3,4]`):
+ /// ```
+ /// let slice = ['r', 'u', 's', 't'];
+ /// let mut iter = slice.windows(2);
+ /// assert_eq!(iter.next().unwrap(), &['r', 'u']);
+ /// assert_eq!(iter.next().unwrap(), &['u', 's']);
+ /// assert_eq!(iter.next().unwrap(), &['s', 't']);
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// If the slice is shorter than `size`:
///
- /// ```rust
- /// let v = &[1, 2, 3, 4];
- /// for win in v.windows(2) {
- /// println!("{:?}", win);
- /// }
+ /// ```
+ /// let slice = ['f', 'o', 'o'];
+ /// let mut iter = slice.windows(4);
+ /// assert!(iter.next().is_none());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
///
/// # Examples
///
- /// Print the slice split by numbers divisible by 3 (i.e. `[10, 40]`,
- /// `[20]`, `[50]`):
+ /// ```
+ /// let slice = [10, 40, 33, 20];
+ /// let mut iter = slice.split(|num| num % 3 == 0);
///
+ /// assert_eq!(iter.next().unwrap(), &[10, 40]);
+ /// assert_eq!(iter.next().unwrap(), &[20]);
+ /// assert!(iter.next().is_none());
/// ```
- /// let v = [10, 40, 30, 20, 60, 50];
///
- /// for group in v.split(|num| *num % 3 == 0) {
- /// println!("{:?}", group);
- /// }
+ /// If the first element is matched, an empty slice will be the first item
+ /// returned by the iterator. Similarly, if the last element in the slice
+ /// is matched, an empty slice will be the last item returned by the
+ /// iterator:
+ ///
+ /// ```
+ /// let slice = [10, 40, 33];
+ /// let mut iter = slice.split(|num| num % 3 == 0);
+ ///
+ /// assert_eq!(iter.next().unwrap(), &[10, 40]);
+ /// assert_eq!(iter.next().unwrap(), &[]);
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// If two matched elements are directly adjacent, an empty slice will be
+ /// present between them:
+ ///
+ /// ```
+ /// let slice = [10, 6, 33, 20];
+ /// let mut iter = slice.split(|num| num % 3 == 0);
+ ///
+ /// assert_eq!(iter.next().unwrap(), &[10]);
+ /// assert_eq!(iter.next().unwrap(), &[]);
+ /// assert_eq!(iter.next().unwrap(), &[20]);
+ /// assert!(iter.next().is_none());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
use core::ops::{Index, IndexMut};
use core::ops;
use core::ptr;
+use core::ptr::Shared;
use core::slice;
use super::SpecExtend;
/// ```
///
/// In this example, there is a memory leak since the memory locations
- /// owned by the vector were not freed prior to the `set_len` call:
+ /// owned by the inner vectors were not freed prior to the `set_len` call:
///
/// ```
- /// let mut vec = vec!['r', 'u', 's', 't'];
- ///
+ /// let mut vec = vec![vec![1, 0, 0],
+ /// vec![0, 1, 0],
+ /// vec![0, 0, 1]];
/// unsafe {
/// vec.set_len(0);
/// }
Drain {
tail_start: end,
tail_len: len - end,
- iter: range_slice.iter_mut(),
- vec: self as *mut _,
+ iter: range_slice.iter(),
+ vec: Shared::new(self as *mut _),
}
}
}
/// Length of tail
tail_len: usize,
/// Current remaining range to remove
- iter: slice::IterMut<'a, T>,
- vec: *mut Vec<T>,
+ iter: slice::Iter<'a, T>,
+ vec: Shared<Vec<T>>,
}
#[stable(feature = "drain", since = "1.6.0")]
if self.tail_len > 0 {
unsafe {
- let source_vec = &mut *self.vec;
+ let source_vec = &mut **self.vec;
// memmove back untouched tail, update to new length
let start = source_vec.len();
let tail = self.tail_start;
/// Retrieves an element in the `VecDeque` by index.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Examples
///
/// ```
/// Retrieves an element in the `VecDeque` mutably by index.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Examples
///
/// ```
///
/// Fails if there is no element with either index.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Examples
///
/// ```
///
/// Returns `None` if `index` is out of bounds.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Examples
///
/// ```
///
/// Returns `None` if `index` is out of bounds.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Examples
///
/// ```
/// end is closer to the insertion point will be moved to make room,
/// and all the affected elements will be moved to new positions.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Panics
///
/// Panics if `index` is greater than `VecDeque`'s length
/// room, and all the affected elements will be moved to new positions.
/// Returns `None` if `index` is out of bounds.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Examples
///
/// ```
///
/// Note that the capacity of `self` does not change.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Panics
///
/// Panics if `at > len`
// except according to those terms.
use std::collections::BinaryHeap;
+use std::collections::binary_heap::Drain;
#[test]
fn test_iterator() {
assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
}
+
+#[allow(dead_code)]
+fn assert_covariance() {
+ fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }
+}
use std::borrow::Cow;
use std::iter::{FromIterator, repeat};
use std::mem::size_of;
+use std::vec::Drain;
use test::Bencher;
}
}
+#[allow(dead_code)]
+fn assert_covariance() {
+ fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }
+}
+
#[bench]
fn bench_new(b: &mut Bencher) {
b.iter(|| {
type Hasher: Hasher;
/// Creates a new hasher.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::hash_map::RandomState;
+ /// use std::hash::BuildHasher;
+ ///
+ /// let s = RandomState::new();
+ /// let new_s = s.build_hasher();
+ /// ```
#[stable(since = "1.7.0", feature = "build_hasher")]
fn build_hasher(&self) -> Self::Hasher;
}
/// Moves a value out of scope without running drop glue.
pub fn forget<T>(_: T) -> ();
- /// Unsafely transforms a value of one type into a value of another type.
+ /// 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, may be an
+ /// [invalid value] (../../nomicon/meet-safe-and-unsafe.html).
///
- /// Both types must have the same size.
+ /// `transmute` is semantically equivalent to a bitwise move of one type
+ /// into another. It copies the bits from the destination type into the
+ /// source type, then forgets the original. It's equivalent to C's `memcpy`
+ /// under the hood, just like `transmute_copy`.
+ ///
+ /// `transmute` is incredibly unsafe. There are a vast number of ways to
+ /// cause undefined behavior with this function. `transmute` should be
+ /// the absolute last resort.
+ ///
+ /// The [nomicon](../../nomicon/transmutes.html) has additional
+ /// documentation.
///
/// # Examples
///
+ /// There are a few things that `transmute` is really useful for.
+ ///
+ /// Getting the bitpattern of a floating point type (or, more generally,
+ /// type punning, when `T` and `U` aren't pointers):
+ ///
/// ```
- /// use std::mem;
+ /// let bitpattern = unsafe {
+ /// std::mem::transmute::<f32, u32>(1.0)
+ /// };
+ /// assert_eq!(bitpattern, 0x3F800000);
+ /// ```
+ ///
+ /// Turning a pointer into a function pointer:
+ ///
+ /// ```
+ /// fn foo() -> i32 {
+ /// 0
+ /// }
+ /// let pointer = foo as *const ();
+ /// let function = unsafe {
+ /// std::mem::transmute::<*const (), fn() -> i32>(pointer)
+ /// };
+ /// assert_eq!(function(), 0);
+ /// ```
+ ///
+ /// Extending a lifetime, or shortening an invariant lifetime; this is
+ /// advanced, very unsafe rust:
+ ///
+ /// ```
+ /// struct R<'a>(&'a i32);
+ /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> {
+ /// std::mem::transmute::<R<'b>, R<'static>>(r)
+ /// }
+ ///
+ /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>)
+ /// -> &'b mut R<'c> {
+ /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r)
+ /// }
+ /// ```
+ ///
+ /// # Alternatives
+ ///
+ /// However, many uses of `transmute` can be achieved through other means.
+ /// `transmute` can transform any type into any other, with just the caveat
+ /// that they're the same size, and often interesting results occur. Below
+ /// are common applications of `transmute` which can be replaced with safe
+ /// applications of `as`:
///
- /// let array: &[u8] = unsafe { mem::transmute("Rust") };
- /// assert_eq!(array, [82, 117, 115, 116]);
+ /// Turning a pointer into a `usize`:
+ ///
+ /// ```
+ /// let ptr = &0;
+ /// let ptr_num_transmute = unsafe {
+ /// std::mem::transmute::<&i32, usize>(ptr)
+ /// };
+ /// // Use an `as` cast instead
+ /// let ptr_num_cast = ptr as *const i32 as usize;
+ /// ```
+ ///
+ /// Turning a `*mut T` into an `&mut T`:
+ ///
+ /// ```
+ /// let ptr: *mut i32 = &mut 0;
+ /// let ref_transmuted = unsafe {
+ /// std::mem::transmute::<*mut i32, &mut i32>(ptr)
+ /// };
+ /// // Use a reborrow instead
+ /// let ref_casted = unsafe { &mut *ptr };
+ /// ```
+ ///
+ /// Turning an `&mut T` into an `&mut U`:
+ ///
+ /// ```
+ /// let ptr = &mut 0;
+ /// let val_transmuted = unsafe {
+ /// std::mem::transmute::<&mut i32, &mut u32>(ptr)
+ /// };
+ /// // Now, put together `as` and reborrowing - note the chaining of `as`
+ /// // `as` is not transitive
+ /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) };
+ /// ```
+ ///
+ /// Turning an `&str` into an `&[u8]`:
+ ///
+ /// ```
+ /// // this is not a good way to do this.
+ /// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") };
+ /// assert_eq!(slice, &[82, 117, 115, 116]);
+ /// // You could use `str::as_bytes`
+ /// let slice = "Rust".as_bytes();
+ /// assert_eq!(slice, &[82, 117, 115, 116]);
+ /// // Or, just use a byte string, if you have control over the string
+ /// // literal
+ /// assert_eq!(b"Rust", &[82, 117, 115, 116]);
+ /// ```
+ ///
+ /// Turning a `Vec<&T>` into a `Vec<Option<&T>>`:
+ ///
+ /// ```
+ /// let store = [0, 1, 2, 3];
+ /// let mut v_orig = store.iter().collect::<Vec<&i32>>();
+ /// // Using transmute: this is Undefined Behavior, and a bad idea.
+ /// // However, it is no-copy.
+ /// let v_transmuted = unsafe {
+ /// std::mem::transmute::<Vec<&i32>, Vec<Option<&i32>>>(
+ /// v_orig.clone())
+ /// };
+ /// // This is the suggested, safe way.
+ /// // It does copy the entire Vector, though, into a new array.
+ /// let v_collected = v_orig.clone()
+ /// .into_iter()
+ /// .map(|r| Some(r))
+ /// .collect::<Vec<Option<&i32>>>();
+ /// // The no-copy, unsafe way, still using transmute, but not UB.
+ /// // This is equivalent to the original, but safer, and reuses the
+ /// // same Vec internals. Therefore the new inner type must have the
+ /// // exact same size, and the same or lesser alignment, as the old
+ /// // type. The same caveats exist for this method as transmute, for
+ /// // the original inner type (`&i32`) to the converted inner type
+ /// // (`Option<&i32>`), so read the nomicon pages linked above.
+ /// let v_from_raw = unsafe {
+ /// Vec::from_raw_parts(v_orig.as_mut_ptr(),
+ /// v_orig.len(),
+ /// v_orig.capacity())
+ /// };
+ /// std::mem::forget(v_orig);
+ /// ```
+ ///
+ /// Implementing `split_at_mut`:
+ ///
+ /// ```
+ /// use std::{slice, mem};
+ /// // There are multiple ways to do this; and there are multiple problems
+ /// // with the following, transmute, way.
+ /// fn split_at_mut_transmute<T>(slice: &mut [T], mid: usize)
+ /// -> (&mut [T], &mut [T]) {
+ /// let len = slice.len();
+ /// assert!(mid <= len);
+ /// unsafe {
+ /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice);
+ /// // first: transmute is not typesafe; all it checks is that T and
+ /// // U are of the same size. Second, right here, you have two
+ /// // mutable references pointing to the same memory.
+ /// (&mut slice[0..mid], &mut slice2[mid..len])
+ /// }
+ /// }
+ /// // This gets rid of the typesafety problems; `&mut *` will *only* give
+ /// // you an `&mut T` from an `&mut T` or `*mut T`.
+ /// fn split_at_mut_casts<T>(slice: &mut [T], mid: usize)
+ /// -> (&mut [T], &mut [T]) {
+ /// let len = slice.len();
+ /// assert!(mid <= len);
+ /// unsafe {
+ /// let slice2 = &mut *(slice as *mut [T]);
+ /// // however, you still have two mutable references pointing to
+ /// // the same memory.
+ /// (&mut slice[0..mid], &mut slice2[mid..len])
+ /// }
+ /// }
+ /// // This is how the standard library does it. This is the best method, if
+ /// // you need to do something like this
+ /// fn split_at_stdlib<T>(slice: &mut [T], mid: usize)
+ /// -> (&mut [T], &mut [T]) {
+ /// let len = slice.len();
+ /// assert!(mid <= len);
+ /// unsafe {
+ /// let ptr = slice.as_mut_ptr();
+ /// // This now has three mutable references pointing at the same
+ /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1.
+ /// // `slice` is never used after `let ptr = ...`, and so one can
+ /// // treat it as "dead", and therefore, you only have two real
+ /// // mutable slices.
+ /// (slice::from_raw_parts_mut(ptr, mid),
+ /// slice::from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
+ /// }
+ /// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn transmute<T, U>(e: T) -> U;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait DoubleEndedIterator: Iterator {
- /// An iterator able to yield elements from both ends.
+ /// Removes and returns an element from the end of the iterator.
///
- /// As this is the only method for this trait, the [trait-level] docs
- /// contain more details.
+ /// Returns `None` when there are no more elements.
+ ///
+ /// The [trait-level] docs contain more details.
///
/// [trait-level]: trait.DoubleEndedIterator.html
///
pub const DW_EH_PE_indirect: u8 = 0x80;
#[derive(Copy, Clone)]
-pub struct EHContext {
+pub struct EHContext<'a> {
pub ip: usize, // Current instruction pointer
pub func_start: usize, // Address of the current function
- pub text_start: usize, // Address of the code section
- pub data_start: usize, // Address of the data section
+ pub get_text_start: &'a Fn() -> usize, // Get address of the code section
+ pub get_data_start: &'a Fn() -> usize, // Get address of the data section
}
-pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) -> Option<usize> {
+pub enum EHAction {
+ None,
+ Cleanup(usize),
+ Catch(usize),
+ Terminate,
+}
+
+pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));
+
+pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
if lsda.is_null() {
- return None;
+ return EHAction::None;
}
let func_start = context.func_start;
let call_site_encoding = reader.read::<u8>();
let call_site_table_length = reader.read_uleb128();
let action_table = reader.ptr.offset(call_site_table_length as isize);
- // Return addresses point 1 byte past the call instruction, which could
- // be in the next IP range.
- let ip = context.ip - 1;
-
- while reader.ptr < action_table {
- let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
- let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
- let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
- let cs_action = reader.read_uleb128();
- // Callsite table is sorted by cs_start, so if we've passed the ip, we
- // may stop searching.
- if ip < func_start + cs_start {
- break;
+ let ip = context.ip;
+
+ if !USING_SJLJ_EXCEPTIONS {
+ while reader.ptr < action_table {
+ let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
+ let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
+ let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
+ let cs_action = reader.read_uleb128();
+ // Callsite table is sorted by cs_start, so if we've passed the ip, we
+ // may stop searching.
+ if ip < func_start + cs_start {
+ break;
+ }
+ if ip < func_start + cs_start + cs_len {
+ if cs_lpad == 0 {
+ return EHAction::None;
+ } else {
+ let lpad = lpad_base + cs_lpad;
+ return interpret_cs_action(cs_action, lpad);
+ }
+ }
}
- if ip < func_start + cs_start + cs_len {
- if cs_lpad != 0 {
- return Some(lpad_base + cs_lpad);
- } else {
- return None;
+ // Ip is not present in the table. This should not hapen... but it does: issie #35011.
+ // So rather than returning EHAction::Terminate, we do this.
+ EHAction::None
+ } else {
+ // SjLj version:
+ // The "IP" is an index into the call-site table, with two exceptions:
+ // -1 means 'no-action', and 0 means 'terminate'.
+ match ip as isize {
+ -1 => return EHAction::None,
+ 0 => return EHAction::Terminate,
+ _ => (),
+ }
+ let mut idx = ip;
+ loop {
+ let cs_lpad = reader.read_uleb128();
+ let cs_action = reader.read_uleb128();
+ idx -= 1;
+ if idx == 0 {
+ // Can never have null landing pad for sjlj -- that would have
+ // been indicated by a -1 call site index.
+ let lpad = (cs_lpad + 1) as usize;
+ return interpret_cs_action(cs_action, lpad);
}
}
}
- // IP range not found: gcc's C++ personality calls terminate() here,
- // however the rest of the languages treat this the same as cs_lpad == 0.
- // We follow this suit.
- None
+}
+
+fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
+ if cs_action == 0 {
+ EHAction::Cleanup(lpad)
+ } else {
+ EHAction::Catch(lpad)
+ }
}
#[inline]
DW_EH_PE_absptr => 0,
// relative to address of the encoded value, despite the name
DW_EH_PE_pcrel => reader.ptr as usize,
- DW_EH_PE_textrel => {
- assert!(context.text_start != 0);
- context.text_start
- }
- DW_EH_PE_datarel => {
- assert!(context.data_start != 0);
- context.data_start
- }
DW_EH_PE_funcrel => {
assert!(context.func_start != 0);
context.func_start
}
+ DW_EH_PE_textrel => {
+ (*context.get_text_start)()
+ }
+ DW_EH_PE_datarel => {
+ (*context.get_data_start)()
+ }
_ => panic!(),
};
0x4d4f5a_00_52555354
}
-// We could implement our personality routine in Rust, however exception
-// info decoding is tedious. More importantly, personality routines have to
-// handle various platform quirks, which are not fun to maintain. For this
-// reason, we attempt to reuse personality routine of the C language:
-// __gcc_personality_v0.
-//
-// Since C does not support exception catching, __gcc_personality_v0 simply
-// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
-// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
-//
-// This is pretty close to Rust's exception handling approach, except that Rust
-// does have a single "catch-all" handler at the bottom of each thread's stack.
-// So we have two versions of the personality routine:
-// - rust_eh_personality, used by all cleanup landing pads, which never catches,
-// so the behavior of __gcc_personality_v0 is perfectly adequate there, and
-// - rust_eh_personality_catch, used only by rust_try(), which always catches.
-//
-// See also: rustc_trans::trans::intrinsic::trans_gnu_try
-
-#[cfg(all(not(target_arch = "arm"),
- not(all(windows, target_arch = "x86_64"))))]
+// All targets, except ARM which uses a slightly different ABI (however, iOS goes here as it uses
+// SjLj unwinding). Also, 64-bit Windows implementation lives in seh64_gnu.rs
+#[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))]
pub mod eabi {
use unwind as uw;
- use libc::c_int;
+ use libc::{c_int, uintptr_t};
+ use dwarf::eh::{EHContext, EHAction, find_eh_action};
- extern "C" {
- fn __gcc_personality_v0(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code;
- }
+ // Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
+ // and TargetLowering::getExceptionSelectorRegister() for each architecture,
+ // then mapped to DWARF register numbers via register definition tables
+ // (typically <arch>RegisterInfo.td, search for "DwarfRegNum").
+ // See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
- #[lang = "eh_personality"]
- #[no_mangle]
- extern "C" fn rust_eh_personality(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code {
- unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) }
- }
+ #[cfg(target_arch = "x86")]
+ const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX
- #[lang = "eh_personality_catch"]
- #[no_mangle]
- pub extern "C" fn rust_eh_personality_catch(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code {
+ #[cfg(target_arch = "x86_64")]
+ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
- if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 {
- // search phase
- uw::_URC_HANDLER_FOUND // catch!
- } else {
- // cleanup phase
- unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) }
- }
- }
-}
-
-// iOS on armv7 is using SjLj exceptions and therefore requires to use
-// a specialized personality routine: __gcc_personality_sj0
+ #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
-#[cfg(all(target_os = "ios", target_arch = "arm"))]
-pub mod eabi {
- use unwind as uw;
- use libc::c_int;
+ #[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
+ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
- extern "C" {
- fn __gcc_personality_sj0(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code;
- }
+ #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+ const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4
+ // Based on GCC's C and C++ personality routines. For reference, see:
+ // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
+ // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
#[lang = "eh_personality"]
#[no_mangle]
- pub extern "C" fn rust_eh_personality(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code {
- unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) }
+ #[allow(unused)]
+ unsafe extern "C" fn rust_eh_personality(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ exception_object: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code {
+ if version != 1 {
+ return uw::_URC_FATAL_PHASE1_ERROR;
+ }
+ let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
+ let mut ip_before_instr: c_int = 0;
+ let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
+ let eh_context = EHContext {
+ // The return address points 1 byte past the call instruction,
+ // which could be in the next IP range in LSDA range table.
+ ip: if ip_before_instr != 0 { ip } else { ip - 1 },
+ func_start: uw::_Unwind_GetRegionStart(context),
+ get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
+ get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
+ };
+ let eh_action = find_eh_action(lsda, &eh_context);
+
+ if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
+ match eh_action {
+ EHAction::None | EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND,
+ EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
+ EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR,
+ }
+ } else {
+ match eh_action {
+ EHAction::None => return uw::_URC_CONTINUE_UNWIND,
+ EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
+ uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
+ uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
+ uw::_Unwind_SetIP(context, lpad);
+ return uw::_URC_INSTALL_CONTEXT;
+ }
+ EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR,
+ }
+ }
}
+ #[cfg(stage0)]
#[lang = "eh_personality_catch"]
#[no_mangle]
- pub extern "C" fn rust_eh_personality_catch(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code {
- if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 {
- // search phase
- uw::_URC_HANDLER_FOUND // catch!
- } else {
- // cleanup phase
- unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) }
- }
+ pub unsafe extern "C" fn rust_eh_personality_catch(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code {
+ rust_eh_personality(version, actions, exception_class, ue_header, context)
}
}
-
// ARM EHABI uses a slightly different personality routine signature,
// but otherwise works the same.
#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
// Entry point for raising an exception, just delegates to the platform-specific
// implementation.
#[no_mangle]
+#[unwind]
pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 {
imp::panic(mem::transmute(raw::TraitObject {
data: data as *mut (),
use core::any::Any;
use core::intrinsics;
use core::ptr;
-use dwarf::eh;
+use dwarf::eh::{EHContext, EHAction, find_eh_action};
use windows as c;
// Define our exception codes:
// This is considered acceptable, because the behavior of throwing exceptions
// through a C ABI boundary is undefined.
+#[cfg(stage0)]
#[lang = "eh_personality_catch"]
#[cfg(not(test))]
unsafe extern "C" fn rust_eh_personality_catch(exceptionRecord: *mut c::EXCEPTION_RECORD,
}
unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
- let eh_ctx = eh::EHContext {
- ip: dc.ControlPc as usize,
+ let eh_ctx = EHContext {
+ // The return address points 1 byte past the call instruction,
+ // which could be in the next IP range in LSDA range table.
+ ip: dc.ControlPc as usize - 1,
func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
- text_start: dc.ImageBase as usize,
- data_start: 0,
+ get_text_start: &|| dc.ImageBase as usize,
+ get_data_start: &|| unimplemented!(),
};
- eh::find_landing_pad(dc.HandlerData, &eh_ctx)
+ match find_eh_action(dc.HandlerData, &eh_ctx) {
+ EHAction::None => None,
+ EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => Some(lpad),
+ EHAction::Terminate => intrinsics::abort(),
+ }
}
use ty::TyVar;
use ty::relate::{Relate, RelateResult, TypeRelation};
-pub struct Bivariate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- fields: CombineFields<'a, 'gcx, 'tcx>
+pub struct Bivariate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+ fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+ a_is_expected: bool,
}
-impl<'a, 'gcx, 'tcx> Bivariate<'a, 'gcx, 'tcx> {
- pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Bivariate<'a, 'gcx, 'tcx> {
- Bivariate { fields: fields }
+impl<'combine, 'infcx, 'gcx, 'tcx> Bivariate<'combine, 'infcx, 'gcx, 'tcx> {
+ pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+ -> Bivariate<'combine, 'infcx, 'gcx, 'tcx>
+ {
+ Bivariate { fields: fields, a_is_expected: a_is_expected }
}
}
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Bivariate<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+ for Bivariate<'combine, 'infcx, 'gcx, 'tcx>
+{
fn tag(&self) -> &'static str { "Bivariate" }
- fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
+ fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn a_is_expected(&self) -> bool { self.a_is_expected }
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
variance: ty::Variance,
}
(&ty::TyInfer(TyVar(a_id)), _) => {
- self.fields.instantiate(b, BiTo, a_id)?;
+ self.fields.instantiate(b, BiTo, a_id, self.a_is_expected)?;
Ok(a)
}
(_, &ty::TyInfer(TyVar(b_id))) => {
- self.fields.instantiate(a, BiTo, b_id)?;
+ self.fields.instantiate(a, BiTo, b_id, self.a_is_expected)?;
Ok(a)
}
use syntax_pos::Span;
#[derive(Clone)]
-pub struct CombineFields<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
- pub a_is_expected: bool,
+pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+ pub infcx: &'infcx InferCtxt<'infcx, 'gcx, 'tcx>,
pub trace: TypeTrace<'tcx>,
pub cause: Option<ty::relate::Cause>,
pub obligations: PredicateObligations<'tcx>,
}
-impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> {
pub fn super_combine_tys<R>(&self,
relation: &mut R,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> RelateResult<'tcx, Ty<'tcx>>
- where R: TypeRelation<'a, 'gcx, 'tcx>
+ where R: TypeRelation<'infcx, 'gcx, 'tcx>
{
let a_is_expected = relation.a_is_expected();
}
}
-impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
- pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
+impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
+ pub fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> {
self.infcx.tcx
}
- pub fn switch_expected(&self) -> CombineFields<'a, 'gcx, 'tcx> {
- CombineFields {
- a_is_expected: !self.a_is_expected,
- ..(*self).clone()
- }
- }
-
- pub fn equate(&self) -> Equate<'a, 'gcx, 'tcx> {
- Equate::new(self.clone())
+ pub fn equate<'a>(&'a mut self, a_is_expected: bool) -> Equate<'a, 'infcx, 'gcx, 'tcx> {
+ Equate::new(self, a_is_expected)
}
- pub fn bivariate(&self) -> Bivariate<'a, 'gcx, 'tcx> {
- Bivariate::new(self.clone())
+ pub fn bivariate<'a>(&'a mut self, a_is_expected: bool) -> Bivariate<'a, 'infcx, 'gcx, 'tcx> {
+ Bivariate::new(self, a_is_expected)
}
- pub fn sub(&self) -> Sub<'a, 'gcx, 'tcx> {
- Sub::new(self.clone())
+ pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'gcx, 'tcx> {
+ Sub::new(self, a_is_expected)
}
- pub fn lub(&self) -> Lub<'a, 'gcx, 'tcx> {
- Lub::new(self.clone())
+ pub fn lub<'a>(&'a mut self, a_is_expected: bool) -> Lub<'a, 'infcx, 'gcx, 'tcx> {
+ Lub::new(self, a_is_expected)
}
- pub fn glb(&self) -> Glb<'a, 'gcx, 'tcx> {
- Glb::new(self.clone())
+ pub fn glb<'a>(&'a mut self, a_is_expected: bool) -> Glb<'a, 'infcx, 'gcx, 'tcx> {
+ Glb::new(self, a_is_expected)
}
- pub fn instantiate(&self,
+ pub fn instantiate(&mut self,
a_ty: Ty<'tcx>,
dir: RelationDir,
- b_vid: ty::TyVid)
+ b_vid: ty::TyVid,
+ a_is_expected: bool)
-> RelateResult<'tcx, ()>
{
let mut stack = Vec::new();
// to associate causes/spans with each of the relations in
// the stack to get this right.
match dir {
- BiTo => self.bivariate().relate(&a_ty, &b_ty),
- EqTo => self.equate().relate(&a_ty, &b_ty),
- SubtypeOf => self.sub().relate(&a_ty, &b_ty),
- SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty),
+ BiTo => self.bivariate(a_is_expected).relate(&a_ty, &b_ty),
+ EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty),
+ SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty),
+ SupertypeOf => self.sub(a_is_expected).relate_with_variance(
+ ty::Contravariant, &a_ty, &b_ty),
}?;
}
use ty::{self, Ty, TyCtxt};
use ty::TyVar;
use ty::relate::{Relate, RelateResult, TypeRelation};
-use traits::PredicateObligations;
/// Ensures `a` is made equal to `b`. Returns `a` on success.
-pub struct Equate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- fields: CombineFields<'a, 'gcx, 'tcx>
+pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+ fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+ a_is_expected: bool,
}
-impl<'a, 'gcx, 'tcx> Equate<'a, 'gcx, 'tcx> {
- pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Equate<'a, 'gcx, 'tcx> {
- Equate { fields: fields }
- }
-
- pub fn obligations(self) -> PredicateObligations<'tcx> {
- self.fields.obligations
+impl<'combine, 'infcx, 'gcx, 'tcx> Equate<'combine, 'infcx, 'gcx, 'tcx> {
+ pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+ -> Equate<'combine, 'infcx, 'gcx, 'tcx>
+ {
+ Equate { fields: fields, a_is_expected: a_is_expected }
}
}
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Equate<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+ for Equate<'combine, 'infcx, 'gcx, 'tcx>
+{
fn tag(&self) -> &'static str { "Equate" }
- fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
+ fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn a_is_expected(&self) -> bool { self.a_is_expected }
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
_: ty::Variance,
}
(&ty::TyInfer(TyVar(a_id)), _) => {
- self.fields.instantiate(b, EqTo, a_id)?;
+ self.fields.instantiate(b, EqTo, a_id, self.a_is_expected)?;
Ok(a)
}
(_, &ty::TyInfer(TyVar(b_id))) => {
- self.fields.instantiate(a, EqTo, b_id)?;
+ self.fields.instantiate(a, EqTo, b_id, self.a_is_expected)?;
Ok(a)
}
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>
{
- self.fields.higher_ranked_sub(a, b)?;
- self.fields.higher_ranked_sub(b, a)
+ self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
+ self.fields.higher_ranked_sub(b, a, self.a_is_expected)
}
}
use infer::{self, TypeOrigin};
use middle::region;
use ty::subst;
-use ty::{self, Ty, TyCtxt, TypeFoldable};
+use ty::{self, TyCtxt, TypeFoldable};
use ty::{Region, ReFree};
use ty::error::TypeError;
}
}
- fn report_type_error(&self,
- trace: TypeTrace<'tcx>,
- terr: &TypeError<'tcx>)
- -> DiagnosticBuilder<'tcx> {
- let (expected, found) = match self.values_str(&trace.values) {
- Some(v) => v,
- None => {
- return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */
- }
- };
-
- let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
- values.expected.is_primitive() && values.found.is_primitive()
- } else {
- false
- };
-
- let mut err = struct_span_err!(self.tcx.sess,
- trace.origin.span(),
- E0308,
- "{}",
- trace.origin);
-
- if !is_simple_error || check_old_school() {
- err.note_expected_found(&"type", &expected, &found);
- }
-
- err.span_label(trace.origin.span(), &terr);
-
- self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span());
-
- match trace.origin {
- TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
- hir::MatchSource::IfLetDesugar{..} => {
- err.span_note(arm_span, "`if let` arm with an incompatible type");
- }
- _ => {
- err.span_note(arm_span, "match arm with an incompatible type");
- }
- },
- _ => ()
- }
-
- err
- }
-
/// Adds a note if the types come from similarly named crates
fn check_and_note_conflicting_crates(&self,
err: &mut DiagnosticBuilder,
}
}
+ fn note_error_origin(&self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ origin: &TypeOrigin)
+ {
+ match origin {
+ &TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
+ hir::MatchSource::IfLetDesugar {..} => {
+ err.span_note(arm_span, "`if let` arm with an incompatible type");
+ }
+ _ => {
+ err.span_note(arm_span, "match arm with an incompatible type");
+ }
+ },
+ _ => ()
+ }
+ }
+
+ pub fn note_type_err(&self,
+ diag: &mut DiagnosticBuilder<'tcx>,
+ origin: TypeOrigin,
+ values: Option<ValuePairs<'tcx>>,
+ terr: &TypeError<'tcx>)
+ {
+ let expected_found = match values {
+ None => None,
+ Some(values) => match self.values_str(&values) {
+ Some((expected, found)) => Some((expected, found)),
+ None => {
+ // Derived error. Cancel the emitter.
+ self.tcx.sess.diagnostic().cancel(diag);
+ return
+ }
+ }
+ };
+
+ let span = origin.span();
+
+ let mut is_simple_error = false;
+
+ if let Some((expected, found)) = expected_found {
+ is_simple_error = if let &TypeError::Sorts(ref values) = terr {
+ values.expected.is_primitive() && values.found.is_primitive()
+ } else {
+ false
+ };
+
+ if !is_simple_error || check_old_school() {
+ diag.note_expected_found(&"type", &expected, &found);
+ }
+ }
+
+ if !is_simple_error && check_old_school() {
+ diag.span_note(span, &format!("{}", terr));
+ } else {
+ diag.span_label(span, &terr);
+ }
+
+ self.note_error_origin(diag, &origin);
+ self.check_and_note_conflicting_crates(diag, terr, span);
+ self.tcx.note_and_explain_type_err(diag, terr, span);
+ }
+
pub fn report_and_explain_type_error(&self,
trace: TypeTrace<'tcx>,
terr: &TypeError<'tcx>)
- -> DiagnosticBuilder<'tcx> {
- let span = trace.origin.span();
- let mut err = self.report_type_error(trace, terr);
- self.tcx.note_and_explain_type_err(&mut err, terr, span);
- err
+ -> DiagnosticBuilder<'tcx>
+ {
+ // FIXME: do we want to use a different error code for each origin?
+ let mut diag = struct_span_err!(
+ self.tcx.sess, trace.origin.span(), E0308,
+ "{}", trace.origin.as_failure_str()
+ );
+ self.note_type_err(&mut diag, trace.origin, Some(trace.values), terr);
+ diag
}
- /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived
- /// error.
+ /// Returns a string of the form "expected `{}`, found `{}`".
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> {
match *values {
infer::Types(ref exp_found) => self.expected_found_str(exp_found),
infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
- infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found)
+ infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found),
}
}
- fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + TypeFoldable<'tcx>>(
+ fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
&self,
exp_found: &ty::error::ExpectedFound<T>)
-> Option<(String, String)>
{
- let expected = exp_found.expected.resolve(self);
- if expected.references_error() {
- return None;
- }
-
- let found = exp_found.found.resolve(self);
- if found.references_error() {
+ let exp_found = self.resolve_type_vars_if_possible(exp_found);
+ if exp_found.references_error() {
return None;
}
- Some((format!("{}", expected), format!("{}", found)))
+ Some((format!("{}", exp_found.expected), format!("{}", exp_found.found)))
}
fn report_generic_bound_failure(&self,
fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) {
match *origin {
infer::Subtype(ref trace) => {
- let desc = match trace.origin {
- TypeOrigin::Misc(_) => {
- "types are compatible"
- }
- TypeOrigin::MethodCompatCheck(_) => {
- "method type is compatible with trait"
- }
- TypeOrigin::ExprAssignable(_) => {
- "expression is assignable"
- }
- TypeOrigin::RelateTraitRefs(_) => {
- "traits are compatible"
- }
- TypeOrigin::RelateSelfType(_) => {
- "self type matches impl self type"
- }
- TypeOrigin::RelateOutputImplTypes(_) => {
- "trait type parameters matches those \
- specified on the impl"
- }
- TypeOrigin::MatchExpressionArm(_, _, _) => {
- "match arms have compatible types"
- }
- TypeOrigin::IfExpression(_) => {
- "if and else have compatible types"
- }
- TypeOrigin::IfExpressionWithNoElse(_) => {
- "if may be missing an else clause"
- }
- TypeOrigin::RangeExpression(_) => {
- "start and end of range have compatible types"
- }
- TypeOrigin::EquatePredicate(_) => {
- "equality where clause is satisfied"
- }
- };
-
- match self.values_str(&trace.values) {
- Some((expected, found)) => {
- err.span_note(
- trace.origin.span(),
- &format!("...so that {} (expected {}, found {})",
- desc, expected, found));
- }
- None => {
- // Really should avoid printing this error at
- // all, since it is derived, but that would
- // require more refactoring than I feel like
- // doing right now. - nmatsakis
- err.span_note(
- trace.origin.span(),
- &format!("...so that {}", desc));
- }
+ if let Some((expected, found)) = self.values_str(&trace.values) {
+ // FIXME: do we want a "the" here?
+ err.span_note(
+ trace.origin.span(),
+ &format!("...so that {} (expected {}, found {})",
+ trace.origin.as_requirement_str(), expected, found));
+ } else {
+ // FIXME: this really should be handled at some earlier stage. Our
+ // handling of region checking when type errors are present is
+ // *terrible*.
+
+ err.span_note(
+ trace.origin.span(),
+ &format!("...so that {}",
+ trace.origin.as_requirement_str()));
}
}
infer::Reborrow(span) => {
}
}
-pub trait Resolvable<'tcx> {
- fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self;
-}
-
-impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
- fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
- infcx.resolve_type_vars_if_possible(self)
- }
-}
-
-impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> {
- fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
- -> ty::TraitRef<'tcx> {
- infcx.resolve_type_vars_if_possible(self)
- }
-}
-
-impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> {
- fn resolve<'a, 'gcx>(&self,
- infcx: &InferCtxt<'a, 'gcx, 'tcx>)
- -> ty::PolyTraitRef<'tcx>
- {
- infcx.resolve_type_vars_if_possible(self)
- }
-}
-
fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
scope_id: ast::NodeId)
-> Vec<hir::LifetimeDef> {
use ty::{self, Ty, TyCtxt};
use ty::relate::{Relate, RelateResult, TypeRelation};
-use traits::PredicateObligations;
/// "Greatest lower bound" (common subtype)
-pub struct Glb<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- fields: CombineFields<'a, 'gcx, 'tcx>
+pub struct Glb<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+ fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+ a_is_expected: bool,
}
-impl<'a, 'gcx, 'tcx> Glb<'a, 'gcx, 'tcx> {
- pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Glb<'a, 'gcx, 'tcx> {
- Glb { fields: fields }
- }
-
- pub fn obligations(self) -> PredicateObligations<'tcx> {
- self.fields.obligations
+impl<'combine, 'infcx, 'gcx, 'tcx> Glb<'combine, 'infcx, 'gcx, 'tcx> {
+ pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+ -> Glb<'combine, 'infcx, 'gcx, 'tcx>
+ {
+ Glb { fields: fields, a_is_expected: a_is_expected }
}
}
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+ for Glb<'combine, 'infcx, 'gcx, 'tcx>
+{
fn tag(&self) -> &'static str { "Glb" }
- fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
+ fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn a_is_expected(&self) -> bool { self.a_is_expected }
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
variance: ty::Variance,
-> RelateResult<'tcx, T>
{
match variance {
- ty::Invariant => self.fields.equate().relate(a, b),
+ ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
ty::Covariant => self.relate(a, b),
- ty::Bivariant => self.fields.bivariate().relate(a, b),
- ty::Contravariant => self.fields.lub().relate(a, b),
+ ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b),
+ ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b),
}
}
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>
{
- self.fields.higher_ranked_glb(a, b)
+ self.fields.higher_ranked_glb(a, b, self.a_is_expected)
}
}
-impl<'a, 'gcx, 'tcx> LatticeDir<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> {
- fn infcx(&self) -> &'a InferCtxt<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx>
+ for Glb<'combine, 'infcx, 'gcx, 'tcx>
+{
+ fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> {
self.fields.infcx
}
- fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
- let mut sub = self.fields.sub();
+ fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
+ let mut sub = self.fields.sub(self.a_is_expected);
sub.relate(&v, &a)?;
sub.relate(&v, &b)?;
Ok(())
}
impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
- pub fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
+ pub fn higher_ranked_sub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
-> RelateResult<'tcx, Binder<T>>
where T: Relate<'tcx>
{
debug!("b_prime={:?}", b_prime);
// Compare types now that bound regions have been replaced.
- let result = self.sub().relate(&a_prime, &b_prime)?;
+ let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
// Presuming type comparison succeeds, we need to check
// that the skolemized regions do not "leak".
- self.infcx.leak_check(!self.a_is_expected, span, &skol_map, snapshot)?;
+ self.infcx.leak_check(!a_is_expected, span, &skol_map, snapshot)?;
// We are finished with the skolemized regions now so pop
// them off.
/// NB. It should not happen that there are LBR appearing in `U`
/// that do not appear in `T`. If that happens, those regions are
/// unconstrained, and this routine replaces them with `'static`.
- pub fn higher_ranked_match<T, U>(&self,
+ pub fn higher_ranked_match<T, U>(&mut self,
span: Span,
a_pair: &Binder<(T, U)>,
- b_match: &T)
+ b_match: &T,
+ a_is_expected: bool)
-> RelateResult<'tcx, HrMatchResult<U>>
where T: Relate<'tcx>,
U: TypeFoldable<'tcx>
debug!("higher_ranked_match: skol_map={:?}", skol_map);
// Equate types now that bound regions have been replaced.
- try!(self.equate().relate(&a_match, &b_match));
+ try!(self.equate(a_is_expected).relate(&a_match, &b_match));
// Map each skolemized region to a vector of other regions that it
// must be equated with. (Note that this vector may include other
});
}
- pub fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>)
+ pub fn higher_ranked_lub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
-> RelateResult<'tcx, Binder<T>>
where T: Relate<'tcx>
{
// Collect constraints.
let result0 =
- self.lub().relate(&a_with_fresh, &b_with_fresh)?;
+ self.lub(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
let result0 =
self.infcx.resolve_type_vars_if_possible(&result0);
debug!("lub result0 = {:?}", result0);
}
}
- pub fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>)
+ pub fn higher_ranked_glb<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
-> RelateResult<'tcx, Binder<T>>
where T: Relate<'tcx>
{
// Collect constraints.
let result0 =
- self.glb().relate(&a_with_fresh, &b_with_fresh)?;
+ self.glb(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
let result0 =
self.infcx.resolve_type_vars_if_possible(&result0);
debug!("glb result0 = {:?}", result0);
// Relates the type `v` to `a` and `b` such that `v` represents
// the LUB/GLB of `a` and `b` as appropriate.
- fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
+ fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
}
pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L,
use ty::{self, Ty, TyCtxt};
use ty::relate::{Relate, RelateResult, TypeRelation};
-use traits::PredicateObligations;
/// "Least upper bound" (common supertype)
-pub struct Lub<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- fields: CombineFields<'a, 'gcx, 'tcx>
+pub struct Lub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+ fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+ a_is_expected: bool,
}
-impl<'a, 'gcx, 'tcx> Lub<'a, 'gcx, 'tcx> {
- pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Lub<'a, 'gcx, 'tcx> {
- Lub { fields: fields }
- }
-
- pub fn obligations(self) -> PredicateObligations<'tcx> {
- self.fields.obligations
+impl<'combine, 'infcx, 'gcx, 'tcx> Lub<'combine, 'infcx, 'gcx, 'tcx> {
+ pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+ -> Lub<'combine, 'infcx, 'gcx, 'tcx>
+ {
+ Lub { fields: fields, a_is_expected: a_is_expected }
}
}
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+ for Lub<'combine, 'infcx, 'gcx, 'tcx>
+{
fn tag(&self) -> &'static str { "Lub" }
- fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
+ fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn a_is_expected(&self) -> bool { self.a_is_expected }
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
variance: ty::Variance,
-> RelateResult<'tcx, T>
{
match variance {
- ty::Invariant => self.fields.equate().relate(a, b),
+ ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
ty::Covariant => self.relate(a, b),
- ty::Bivariant => self.fields.bivariate().relate(a, b),
- ty::Contravariant => self.fields.glb().relate(a, b),
+ ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b),
+ ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b),
}
}
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>
{
- self.fields.higher_ranked_lub(a, b)
+ self.fields.higher_ranked_lub(a, b, self.a_is_expected)
}
}
-impl<'a, 'gcx, 'tcx> LatticeDir<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> {
- fn infcx(&self) -> &'a InferCtxt<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx>
+ for Lub<'combine, 'infcx, 'gcx, 'tcx>
+{
+ fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> {
self.fields.infcx
}
- fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
- let mut sub = self.fields.sub();
+ fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
+ let mut sub = self.fields.sub(self.a_is_expected);
sub.relate(&a, &v)?;
sub.relate(&b, &v)?;
Ok(())
use ty::{TyVid, IntVid, FloatVid};
use ty::{self, Ty, TyCtxt};
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
-use ty::fold::TypeFoldable;
+use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use ty::relate::{Relate, RelateResult, TypeRelation};
use traits::{self, PredicateObligations, ProjectionMode};
use rustc_data_structures::unify::{self, UnificationTable};
use self::region_inference::{RegionVarBindings, RegionSnapshot};
use self::unify_key::ToType;
-pub mod bivariate;
-pub mod combine;
-pub mod equate;
+mod bivariate;
+mod combine;
+mod equate;
pub mod error_reporting;
-pub mod glb;
+mod glb;
mod higher_ranked;
pub mod lattice;
-pub mod lub;
+mod lub;
pub mod region_inference;
pub mod resolve;
mod freshen;
-pub mod sub;
+mod sub;
pub mod type_variable;
pub mod unify_key;
// FIXME(eddyb) #11161 is the original Expr required?
ExprAssignable(Span),
- // Relating trait refs when resolving vtables
- RelateTraitRefs(Span),
-
- // Relating self types when resolving vtables
- RelateSelfType(Span),
-
// Relating trait type parameters to those found in impl etc
RelateOutputImplTypes(Span),
// `where a == b`
EquatePredicate(Span),
+
+ // `main` has wrong type
+ MainFunctionType(Span),
+
+ // `start` has wrong type
+ StartFunctionType(Span),
+
+ // intrinsic has wrong type
+ IntrinsicType(Span),
+
+ // method receiver
+ MethodReceiver(Span),
}
impl TypeOrigin {
- fn as_str(&self) -> &'static str {
+ fn as_failure_str(&self) -> &'static str {
match self {
&TypeOrigin::Misc(_) |
- &TypeOrigin::RelateSelfType(_) |
&TypeOrigin::RelateOutputImplTypes(_) |
&TypeOrigin::ExprAssignable(_) => "mismatched types",
- &TypeOrigin::RelateTraitRefs(_) => "mismatched traits",
&TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait",
&TypeOrigin::MatchExpressionArm(_, _, source) => match source {
hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
&TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause",
&TypeOrigin::RangeExpression(_) => "start and end of range have incompatible types",
&TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied",
+ &TypeOrigin::MainFunctionType(_) => "main function has wrong type",
+ &TypeOrigin::StartFunctionType(_) => "start function has wrong type",
+ &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type",
+ &TypeOrigin::MethodReceiver(_) => "mismatched method receiver",
}
}
-}
-impl fmt::Display for TypeOrigin {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> {
- fmt::Display::fmt(self.as_str(), f)
+ fn as_requirement_str(&self) -> &'static str {
+ match self {
+ &TypeOrigin::Misc(_) => "types are compatible",
+ &TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait",
+ &TypeOrigin::ExprAssignable(_) => "expression is assignable",
+ &TypeOrigin::RelateOutputImplTypes(_) => {
+ "trait type parameters matches those specified on the impl"
+ }
+ &TypeOrigin::MatchExpressionArm(_, _, _) => "match arms have compatible types",
+ &TypeOrigin::IfExpression(_) => "if and else have compatible types",
+ &TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()",
+ &TypeOrigin::RangeExpression(_) => "start and end of range have compatible types",
+ &TypeOrigin::EquatePredicate(_) => "equality where clause is satisfied",
+ &TypeOrigin::MainFunctionType(_) => "`main` function has the correct type",
+ &TypeOrigin::StartFunctionType(_) => "`start` function has the correct type",
+ &TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type",
+ &TypeOrigin::MethodReceiver(_) => "method receiver has the correct type",
+ }
}
}
return variables;
}
- fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
+ fn combine_fields(&'a self, trace: TypeTrace<'tcx>)
-> CombineFields<'a, 'gcx, 'tcx> {
CombineFields {
infcx: self,
- a_is_expected: a_is_expected,
trace: trace,
cause: None,
obligations: PredicateObligations::new(),
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
- let mut equate = self.combine_fields(a_is_expected, trace).equate();
- let result = equate.relate(a, b);
- result.map(|t| InferOk { value: t, obligations: equate.obligations() })
+ let mut fields = self.combine_fields(trace);
+ let result = fields.equate(a_is_expected).relate(a, b);
+ result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
pub fn sub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
- let mut sub = self.combine_fields(a_is_expected, trace).sub();
- let result = sub.relate(a, b);
- result.map(|t| InferOk { value: t, obligations: sub.obligations() })
+ let mut fields = self.combine_fields(trace);
+ let result = fields.sub(a_is_expected).relate(a, b);
+ result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
pub fn lub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
- let mut lub = self.combine_fields(a_is_expected, trace).lub();
- let result = lub.relate(a, b);
- result.map(|t| InferOk { value: t, obligations: lub.obligations() })
+ let mut fields = self.combine_fields(trace);
+ let result = fields.lub(a_is_expected).relate(a, b);
+ result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
pub fn glb<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
- let mut glb = self.combine_fields(a_is_expected, trace).glb();
- let result = glb.relate(a, b);
- result.map(|t| InferOk { value: t, obligations: glb.obligations() })
+ let mut fields = self.combine_fields(trace);
+ let result = fields.glb(a_is_expected).relate(a, b);
+ result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
fn start_snapshot(&self) -> CombinedSnapshot {
// error type, meaning that an error occurred when typechecking this expression),
// this is a derived error. The error cascaded from another error (that was already
// reported), so it's not useful to display it to the user.
- // The following four methods -- type_error_message_str, type_error_message_str_with_expected,
- // type_error_message, and report_mismatched_types -- implement this logic.
+ // The following methods implement this logic.
// They check if either the actual or expected type is TyError, and don't print the error
// in this case. The typechecker should only ever report type errors involving mismatched
- // types using one of these four methods, and should not call span_err directly for such
+ // types using one of these methods, and should not call span_err directly for such
// errors.
- pub fn type_error_message_str<M>(&self,
- sp: Span,
- mk_msg: M,
- actual_ty: String,
- err: Option<&TypeError<'tcx>>)
- where M: FnOnce(Option<String>, String) -> String,
- {
- self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err)
- }
-
- pub fn type_error_struct_str<M>(&self,
- sp: Span,
- mk_msg: M,
- actual_ty: String,
- err: Option<&TypeError<'tcx>>)
- -> DiagnosticBuilder<'tcx>
- where M: FnOnce(Option<String>, String) -> String,
- {
- self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err)
- }
-
- pub fn type_error_message_str_with_expected<M>(&self,
- sp: Span,
- mk_msg: M,
- expected_ty: Option<Ty<'tcx>>,
- actual_ty: String,
- err: Option<&TypeError<'tcx>>)
- where M: FnOnce(Option<String>, String) -> String,
- {
- self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err)
- .emit();
- }
-
- pub fn type_error_struct_str_with_expected<M>(&self,
- sp: Span,
- mk_msg: M,
- expected_ty: Option<Ty<'tcx>>,
- actual_ty: String,
- err: Option<&TypeError<'tcx>>)
- -> DiagnosticBuilder<'tcx>
- where M: FnOnce(Option<String>, String) -> String,
- {
- debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty);
-
- let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty));
-
- if !resolved_expected.references_error() {
- let error_str = err.map_or("".to_string(), |t_err| {
- format!(" ({})", t_err)
- });
-
- let mut db = self.tcx.sess.struct_span_err(sp, &format!("{}{}",
- mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty),
- error_str));
-
- if let Some(err) = err {
- self.tcx.note_and_explain_type_err(&mut db, err, sp);
- }
- db
- } else {
- self.tcx.sess.diagnostic().struct_dummy()
- }
- }
pub fn type_error_message<M>(&self,
sp: Span,
mk_msg: M,
- actual_ty: Ty<'tcx>,
- err: Option<&TypeError<'tcx>>)
+ actual_ty: Ty<'tcx>)
where M: FnOnce(String) -> String,
{
- self.type_error_struct(sp, mk_msg, actual_ty, err).emit();
+ self.type_error_struct(sp, mk_msg, actual_ty).emit();
}
+ // FIXME: this results in errors without an error code. Deprecate?
pub fn type_error_struct<M>(&self,
sp: Span,
mk_msg: M,
- actual_ty: Ty<'tcx>,
- err: Option<&TypeError<'tcx>>)
+ actual_ty: Ty<'tcx>)
-> DiagnosticBuilder<'tcx>
where M: FnOnce(String) -> String,
+ {
+ self.type_error_struct_with_diag(sp, |actual_ty| {
+ self.tcx.sess.struct_span_err(sp, &mk_msg(actual_ty))
+ }, actual_ty)
+ }
+
+ pub fn type_error_struct_with_diag<M>(&self,
+ sp: Span,
+ mk_diag: M,
+ actual_ty: Ty<'tcx>)
+ -> DiagnosticBuilder<'tcx>
+ where M: FnOnce(String) -> DiagnosticBuilder<'tcx>,
{
let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
+ debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
// Don't report an error if actual type is TyError.
if actual_ty.references_error() {
return self.tcx.sess.diagnostic().struct_dummy();
}
- self.type_error_struct_str(sp,
- move |_e, a| { mk_msg(a) },
- self.ty_to_string(actual_ty), err)
+ mk_diag(self.ty_to_string(actual_ty))
}
pub fn report_mismatched_types(&self,
};
let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty));
- let combine = self.combine_fields(true, trace);
- let result = combine.higher_ranked_match(span, &match_pair, &match_b)?;
+ let mut combine = self.combine_fields(trace);
+ let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?;
Ok(InferOk { value: result, obligations: combine.obligations })
}
TypeOrigin::MethodCompatCheck(span) => span,
TypeOrigin::ExprAssignable(span) => span,
TypeOrigin::Misc(span) => span,
- TypeOrigin::RelateTraitRefs(span) => span,
- TypeOrigin::RelateSelfType(span) => span,
TypeOrigin::RelateOutputImplTypes(span) => span,
TypeOrigin::MatchExpressionArm(match_span, _, _) => match_span,
TypeOrigin::IfExpression(span) => span,
TypeOrigin::IfExpressionWithNoElse(span) => span,
TypeOrigin::RangeExpression(span) => span,
TypeOrigin::EquatePredicate(span) => span,
+ TypeOrigin::MainFunctionType(span) => span,
+ TypeOrigin::StartFunctionType(span) => span,
+ TypeOrigin::IntrinsicType(span) => span,
+ TypeOrigin::MethodReceiver(span) => span,
}
}
}
}
}
}
+
+impl<'tcx> TypeFoldable<'tcx> for TypeOrigin {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
+ self.clone()
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
+ false
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ match *self {
+ ValuePairs::Types(ref ef) => {
+ ValuePairs::Types(ef.fold_with(folder))
+ }
+ ValuePairs::TraitRefs(ref ef) => {
+ ValuePairs::TraitRefs(ef.fold_with(folder))
+ }
+ ValuePairs::PolyTraitRefs(ref ef) => {
+ ValuePairs::PolyTraitRefs(ef.fold_with(folder))
+ }
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ match *self {
+ ValuePairs::Types(ref ef) => ef.visit_with(visitor),
+ ValuePairs::TraitRefs(ref ef) => ef.visit_with(visitor),
+ ValuePairs::PolyTraitRefs(ref ef) => ef.visit_with(visitor),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ TypeTrace {
+ origin: self.origin.fold_with(folder),
+ values: self.values.fold_with(folder)
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ self.origin.visit_with(visitor) || self.values.visit_with(visitor)
+ }
+}
use ty::{self, Ty, TyCtxt};
use ty::TyVar;
use ty::relate::{Cause, Relate, RelateResult, TypeRelation};
-use traits::PredicateObligations;
use std::mem;
/// Ensures `a` is made a subtype of `b`. Returns `a` on success.
-pub struct Sub<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- fields: CombineFields<'a, 'gcx, 'tcx>,
+pub struct Sub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+ fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+ a_is_expected: bool,
}
-impl<'a, 'gcx, 'tcx> Sub<'a, 'gcx, 'tcx> {
- pub fn new(f: CombineFields<'a, 'gcx, 'tcx>) -> Sub<'a, 'gcx, 'tcx> {
- Sub { fields: f }
+impl<'combine, 'infcx, 'gcx, 'tcx> Sub<'combine, 'infcx, 'gcx, 'tcx> {
+ pub fn new(f: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+ -> Sub<'combine, 'infcx, 'gcx, 'tcx>
+ {
+ Sub { fields: f, a_is_expected: a_is_expected }
}
- pub fn obligations(self) -> PredicateObligations<'tcx> {
- self.fields.obligations
+ fn with_expected_switched<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
+ self.a_is_expected = !self.a_is_expected;
+ let result = f(self);
+ self.a_is_expected = !self.a_is_expected;
+ result
}
}
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Sub<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+ for Sub<'combine, 'infcx, 'gcx, 'tcx>
+{
fn tag(&self) -> &'static str { "Sub" }
- fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.infcx.tcx }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx }
+ fn a_is_expected(&self) -> bool { self.a_is_expected }
fn with_cause<F,R>(&mut self, cause: Cause, f: F) -> R
where F: FnOnce(&mut Self) -> R
-> RelateResult<'tcx, T>
{
match variance {
- ty::Invariant => self.fields.equate().relate(a, b),
+ ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
ty::Covariant => self.relate(a, b),
- ty::Bivariant => self.fields.bivariate().relate(a, b),
- ty::Contravariant => self.fields.switch_expected().sub().relate(b, a),
+ ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b),
+ ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }),
}
}
}
(&ty::TyInfer(TyVar(a_id)), _) => {
self.fields
- .switch_expected()
- .instantiate(b, SupertypeOf, a_id)?;
+ .instantiate(b, SupertypeOf, a_id, !self.a_is_expected)?;
Ok(a)
}
(_, &ty::TyInfer(TyVar(b_id))) => {
- self.fields.instantiate(a, SubtypeOf, b_id)?;
+ self.fields.instantiate(a, SubtypeOf, b_id, self.a_is_expected)?;
Ok(a)
}
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>
{
- self.fields.higher_ranked_sub(a, b)
+ self.fields.higher_ranked_sub(a, b, self.a_is_expected)
}
}
sp: S,
msg: &str)
-> DiagnosticBuilder<'a> {
- match split_msg_into_multilines(msg) {
- Some(ref msg) => self.diagnostic().struct_span_err(sp, msg),
- None => self.diagnostic().struct_span_err(sp, msg),
- }
+ self.diagnostic().struct_span_err(sp, msg)
}
pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
msg: &str,
code: &str)
-> DiagnosticBuilder<'a> {
- match split_msg_into_multilines(msg) {
- Some(ref msg) => self.diagnostic().struct_span_err_with_code(sp, msg, code),
- None => self.diagnostic().struct_span_err_with_code(sp, msg, code),
- }
+ self.diagnostic().struct_span_err_with_code(sp, msg, code)
}
pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
self.diagnostic().struct_err(msg)
}
}
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
- match split_msg_into_multilines(msg) {
- Some(msg) => self.diagnostic().span_err(sp, &msg),
- None => self.diagnostic().span_err(sp, msg)
- }
+ self.diagnostic().span_err(sp, msg)
}
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
- match split_msg_into_multilines(msg) {
- Some(msg) => self.diagnostic().span_err_with_code(sp, &msg, code),
- None => self.diagnostic().span_err_with_code(sp, msg, code)
- }
+ self.diagnostic().span_err_with_code(sp, &msg, code)
}
pub fn err(&self, msg: &str) {
self.diagnostic().err(msg)
}
}
-fn split_msg_into_multilines(msg: &str) -> Option<String> {
- // Conditions for enabling multi-line errors:
- if !msg.contains("mismatched types") &&
- !msg.contains("type mismatch resolving") &&
- !msg.contains("if and else have incompatible types") &&
- !msg.contains("if may be missing an else clause") &&
- !msg.contains("match arms have incompatible types") &&
- !msg.contains("structure constructor specifies a structure of type") &&
- !msg.contains("has an incompatible type for trait") {
- return None
- }
- let first = msg.match_indices("expected").filter(|s| {
- let last = msg[..s.0].chars().rev().next();
- last == Some(' ') || last == Some('(')
- }).map(|(a, b)| (a - 1, a + b.len()));
- let second = msg.match_indices("found").filter(|s| {
- msg[..s.0].chars().rev().next() == Some(' ')
- }).map(|(a, b)| (a - 1, a + b.len()));
-
- let mut new_msg = String::new();
- let mut head = 0;
-
- // Insert `\n` before expected and found.
- for (pos1, pos2) in first.zip(second) {
- new_msg = new_msg +
- // A `(` may be preceded by a space and it should be trimmed
- msg[head..pos1.0].trim_right() + // prefix
- "\n" + // insert before first
- &msg[pos1.0..pos1.1] + // insert what first matched
- &msg[pos1.1..pos2.0] + // between matches
- "\n " + // insert before second
- // 123
- // `expected` is 3 char longer than `found`. To align the types,
- // `found` gets 3 spaces prepended.
- &msg[pos2.0..pos2.1]; // insert what second matched
-
- head = pos2.1;
- }
-
- let mut tail = &msg[head..];
- let third = tail.find("(values differ")
- .or(tail.find("(lifetime"))
- .or(tail.find("(cyclic type of infinite size"));
- // Insert `\n` before any remaining messages which match.
- if let Some(pos) = third {
- // The end of the message may just be wrapped in `()` without
- // `expected`/`found`. Push this also to a new line and add the
- // final tail after.
- new_msg = new_msg +
- // `(` is usually preceded by a space and should be trimmed.
- tail[..pos].trim_right() + // prefix
- "\n" + // insert before paren
- &tail[pos..]; // append the tail
-
- tail = "";
- }
-
- new_msg.push_str(tail);
- return Some(new_msg);
-}
-
pub fn build_session(sopts: config::Options,
dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
use fmt_macros::{Parser, Piece, Position};
use hir::def_id::DefId;
-use infer::{InferCtxt};
+use infer::{self, InferCtxt, TypeOrigin};
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
+use ty::error::ExpectedFound;
use ty::fast_reject;
use ty::fold::TypeFolder;
use ty::subst::{self, Subst, TypeSpace};
let predicate =
self.resolve_type_vars_if_possible(&obligation.predicate);
- if !predicate.references_error() {
- if let Some(warning_node_id) = warning_node_id {
- self.tcx.sess.add_lint(
- ::lint::builtin::UNSIZED_IN_TUPLE,
- warning_node_id,
+ if predicate.references_error() {
+ return
+ }
+ if let Some(warning_node_id) = warning_node_id {
+ self.tcx.sess.add_lint(
+ ::lint::builtin::UNSIZED_IN_TUPLE,
+ warning_node_id,
+ obligation.cause.span,
+ format!("type mismatch resolving `{}`: {}",
+ predicate,
+ error.err));
+ return
+ }
+ self.probe(|_| {
+ let origin = TypeOrigin::Misc(obligation.cause.span);
+ let err_buf;
+ let mut err = &error.err;
+ let mut values = None;
+
+ // try to find the mismatched types to report the error with.
+ //
+ // this can fail if the problem was higher-ranked, in which
+ // cause I have no idea for a good error message.
+ if let ty::Predicate::Projection(ref data) = predicate {
+ let mut selcx = SelectionContext::new(self);
+ let (data, _) = self.replace_late_bound_regions_with_fresh_var(
obligation.cause.span,
- format!("type mismatch resolving `{}`: {}",
- predicate,
- error.err));
- } else {
- let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271,
- "type mismatch resolving `{}`: {}",
- predicate,
- error.err);
- self.note_obligation_cause(&mut err, obligation);
- err.emit();
+ infer::LateBoundRegionConversionTime::HigherRankedType,
+ data);
+ let normalized = super::normalize_projection_type(
+ &mut selcx,
+ data.projection_ty,
+ obligation.cause.clone(),
+ 0
+ );
+ let origin = TypeOrigin::Misc(obligation.cause.span);
+ if let Err(error) = self.eq_types(
+ false, origin,
+ data.ty, normalized.value
+ ) {
+ values = Some(infer::ValuePairs::Types(ExpectedFound {
+ expected: normalized.value,
+ found: data.ty,
+ }));
+ err_buf = error;
+ err = &err_buf;
+ }
}
- }
+
+ let mut diag = struct_span_err!(
+ self.tcx.sess, origin.span(), E0271,
+ "type mismatch resolving `{}`", predicate
+ );
+ self.note_type_err(&mut diag, origin, values, err);
+ self.note_obligation_cause(&mut diag, obligation);
+ diag.emit();
+ });
}
fn impl_substs(&self,
self.generics.visit_with(visitor) || self.ty.visit_with(visitor)
}
}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound<T> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ ty::error::ExpectedFound {
+ expected: self.expected.fold_with(folder),
+ found: self.found.fold_with(folder),
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ self.expected.visit_with(visitor) || self.found.visit_with(visitor)
+ }
+}
/// List of supported targets
pub const TARGETS: &'static [&'static str] = &[$($triple),*];
- // this would use a match if stringify! were allowed in pattern position
fn load_specific(target: &str) -> Option<Target> {
- let target = target.replace("-", "_");
- if false { }
- $(
- else if target == stringify!($module) {
- let mut t = $module::target();
- t.options.is_builtin = true;
- debug!("Got builtin target: {:?}", t);
- return Some(t);
- }
- )*
-
- None
+ match target {
+ $(
+ $triple => {
+ let mut t = $module::target();
+ t.options.is_builtin = true;
+ debug!("Got builtin target: {:?}", t);
+ Some(t)
+ },
+ )+
+ _ => None
+ }
}
)
}
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_math = { path = "../librustc_const_math" }
+rustc_errors = { path = "../librustc_errors" }
syntax = { path = "../libsyntax" }
graphviz = { path = "../libgraphviz" }
syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
use ::{eval_const_expr, eval_const_expr_partial, compare_const_vals};
use ::{const_expr_to_pat, lookup_const_by_id};
use ::EvalHint::ExprTypeChecked;
+use eval::report_const_eval_err;
use rustc::hir::def::*;
use rustc::hir::def_id::{DefId};
use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
use rustc::hir::fold::{Folder, noop_fold_pat};
use rustc::hir::print::pat_to_string;
use syntax::ptr::P;
+use rustc::util::common::ErrorReported;
use rustc::util::nodemap::FnvHashMap;
pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
Ok(_) => {}
Err(err) => {
- let mut diag = struct_span_err!(cx.tcx.sess, err.span, E0471,
- "constant evaluation error: {}",
- err.description());
- if !p.span.contains(err.span) {
- diag.span_note(p.span, "in pattern here");
- }
- diag.emit();
+ report_const_eval_err(cx.tcx, &err, p.span, "pattern").emit();
}
}
}
}
}
-fn range_covered_by_constructor(ctor: &Constructor,
- from: &ConstVal, to: &ConstVal) -> Option<bool> {
+fn range_covered_by_constructor(tcx: TyCtxt, span: Span,
+ ctor: &Constructor,
+ from: &ConstVal, to: &ConstVal)
+ -> Result<bool, ErrorReported> {
let (c_from, c_to) = match *ctor {
ConstantValue(ref value) => (value, value),
ConstantRange(ref from, ref to) => (from, to),
- Single => return Some(true),
+ Single => return Ok(true),
_ => bug!()
};
- let cmp_from = compare_const_vals(c_from, from);
- let cmp_to = compare_const_vals(c_to, to);
- match (cmp_from, cmp_to) {
- (Some(cmp_from), Some(cmp_to)) => {
- Some(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
- }
- _ => None
- }
+ let cmp_from = compare_const_vals(tcx, span, c_from, from)?;
+ let cmp_to = compare_const_vals(tcx, span, c_to, to)?;
+ Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
}
fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
Some(vec![(pat, Some(mt.ty))])
} else {
let expr_value = eval_const_expr(cx.tcx, &expr);
- match range_covered_by_constructor(constructor, &expr_value, &expr_value) {
- Some(true) => Some(vec![]),
- Some(false) => None,
- None => {
- span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms");
- None
- }
+ match range_covered_by_constructor(
+ cx.tcx, expr.span, constructor, &expr_value, &expr_value
+ ) {
+ Ok(true) => Some(vec![]),
+ Ok(false) => None,
+ Err(ErrorReported) => None,
}
}
}
PatKind::Range(ref from, ref to) => {
let from_value = eval_const_expr(cx.tcx, &from);
let to_value = eval_const_expr(cx.tcx, &to);
- match range_covered_by_constructor(constructor, &from_value, &to_value) {
- Some(true) => Some(vec![]),
- Some(false) => None,
- None => {
- span_err!(cx.tcx.sess, pat_span, E0299, "mismatched types between arms");
- None
- }
+ match range_covered_by_constructor(
+ cx.tcx, pat_span, constructor, &from_value, &to_value
+ ) {
+ Ok(true) => Some(vec![]),
+ Ok(false) => None,
+ Err(ErrorReported) => None,
}
}
See also https://github.com/rust-lang/rust/issues/14587
"##,
-E0306: r##"
-In an array literal `[x; N]`, `N` is the number of elements in the array. This
-must be an unsigned integer. Erroneous code example:
+E0080: r##"
+This error indicates that the compiler was unable to sensibly evaluate an
+constant expression that had to be evaluated. Attempting to divide by 0
+or causing integer overflow are two ways to induce this error. For example:
```compile_fail
-let x = [0i32; true]; // error: expected positive integer for repeat count,
- // found boolean
+enum Enum {
+ X = (1 << 500),
+ Y = (1 / 0)
+}
```
-Working example:
+Ensure that the expressions given can be evaluated as the desired integer type.
+See the FFI section of the Reference for more information about using a custom
+integer type:
-```
-let x = [0i32; 2];
-```
+https://doc.rust-lang.org/reference.html#ffi-attributes
"##,
-E0307: r##"
-The length of an array is part of its type. For this reason, this length must
-be a compile-time constant. Erroneous code example:
+
+E0306: r##"
+In an array literal `[x; N]`, `N` is the number of elements in the array. This
+must be an unsigned integer. Erroneous code example:
```compile_fail
- let len = 10;
- let x = [0i32; len]; // error: expected constant integer for repeat count,
- // found variable
+let x = [0i32; true]; // error: expected positive integer for repeat count,
+ // found boolean
```
Working example:
```
-let x = [0i32; 10];
+let x = [0i32; 2];
```
"##,
-
}
register_diagnostics! {
-E0298, // mismatched types between arms
-E0299, // mismatched types between arms
-E0471, // constant evaluation error: ..
+ E0298, // cannot compare constants
+// E0299, // mismatched types between arms
+// E0471, // constant evaluation error (in pattern)
}
use rustc::ty::{self, Ty, TyCtxt, subst};
use rustc::ty::util::IntTypeExt;
use rustc::traits::ProjectionMode;
+use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
use rustc::lint;
use std::collections::hash_map::Entry::Vacant;
use rustc_const_math::*;
+use rustc_errors::{DiagnosticBuilder, check_old_school};
macro_rules! math {
($e:expr, $op:expr) => {
Ok(P(hir::Pat { id: expr.id, node: pat, span: span }))
}
+pub fn report_const_eval_err<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ err: &ConstEvalErr,
+ primary_span: Span,
+ primary_kind: &str)
+ -> DiagnosticBuilder<'tcx>
+{
+ let mut err = err;
+ while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err {
+ err = i_err;
+ }
+
+ let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
+ note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag);
+ diag
+}
+
+pub fn fatal_const_eval_err<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ err: &ConstEvalErr,
+ primary_span: Span,
+ primary_kind: &str)
+ -> !
+{
+ report_const_eval_err(tcx, err, primary_span, primary_kind).emit();
+ tcx.sess.abort_if_errors();
+ unreachable!()
+}
+
+pub fn note_const_eval_err<'a, 'tcx>(
+ _tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ err: &ConstEvalErr,
+ primary_span: Span,
+ primary_kind: &str,
+ diag: &mut DiagnosticBuilder)
+{
+ match err.description() {
+ ConstEvalErrDescription::Simple(message) => {
+ if check_old_school() {
+ diag.note(&message);
+ } else {
+ diag.span_label(err.span, &message);
+ }
+ }
+ }
+
+ if !primary_span.contains(err.span) {
+ diag.span_note(primary_span,
+ &format!("for {} here", primary_kind));
+ }
+}
+
pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
e: &Expr) -> ConstVal {
match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
Ok(r) => r,
// non-const path still needs to be a fatal error, because enums are funky
Err(s) => {
+ report_const_eval_err(tcx, &s, e.span, "expression").emit();
match s.kind {
NonConstPath |
- UnimplementedConstVal(_) => tcx.sess.span_fatal(s.span, &s.description()),
- _ => {
- tcx.sess.span_err(s.span, &s.description());
- Dummy
- }
+ UnimplementedConstVal(_) => tcx.sess.abort_if_errors(),
+ _ => {}
}
+ Dummy
},
}
}
IntermediateUnsignedNegative,
/// Expected, Got
TypeMismatch(String, ConstInt),
+
BadType(ConstVal),
ErroneousReferencedConstant(Box<ConstEvalErr>),
CharCast(ConstInt),
}
}
+#[derive(Clone, Debug)]
+pub enum ConstEvalErrDescription<'a> {
+ Simple(Cow<'a, str>),
+}
+
+impl<'a> ConstEvalErrDescription<'a> {
+ /// Return a one-line description of the error, for lints and such
+ pub fn into_oneline(self) -> Cow<'a, str> {
+ match self {
+ ConstEvalErrDescription::Simple(simple) => simple,
+ }
+ }
+}
+
impl ConstEvalErr {
- pub fn description(&self) -> Cow<str> {
+ pub fn description(&self) -> ConstEvalErrDescription {
use self::ErrKind::*;
+ use self::ConstEvalErrDescription::*;
+
+ macro_rules! simple {
+ ($msg:expr) => ({ Simple($msg.into_cow()) });
+ ($fmt:expr, $($arg:tt)+) => ({
+ Simple(format!($fmt, $($arg)+).into_cow())
+ })
+ }
match self.kind {
- CannotCast => "can't cast this type".into_cow(),
- CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(),
- InvalidOpForInts(_) => "can't do this op on integrals".into_cow(),
- InvalidOpForBools(_) => "can't do this op on bools".into_cow(),
- InvalidOpForFloats(_) => "can't do this op on floats".into_cow(),
- InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(),
- InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(),
- NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(),
- NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(),
- CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(),
-
- MissingStructField => "nonexistent struct field".into_cow(),
- NonConstPath => "non-constant path in constant expression".into_cow(),
+ CannotCast => simple!("can't cast this type"),
+ CannotCastTo(s) => simple!("can't cast this type to {}", s),
+ InvalidOpForInts(_) => simple!("can't do this op on integrals"),
+ InvalidOpForBools(_) => simple!("can't do this op on bools"),
+ InvalidOpForFloats(_) => simple!("can't do this op on floats"),
+ InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"),
+ InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"),
+ NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
+ NotOn(ref const_val) => simple!("not on {}", const_val.description()),
+ CallOn(ref const_val) => simple!("call on {}", const_val.description()),
+
+ MissingStructField => simple!("nonexistent struct field"),
+ NonConstPath => simple!("non-constant path in constant expression"),
UnimplementedConstVal(what) =>
- format!("unimplemented constant expression: {}", what).into_cow(),
- UnresolvedPath => "unresolved path in constant expression".into_cow(),
- ExpectedConstTuple => "expected constant tuple".into_cow(),
- ExpectedConstStruct => "expected constant struct".into_cow(),
- TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
- IndexedNonVec => "indexing is only supported for arrays".into_cow(),
- IndexNegative => "indices must be non-negative integers".into_cow(),
- IndexNotInt => "indices must be integers".into_cow(),
+ simple!("unimplemented constant expression: {}", what),
+ UnresolvedPath => simple!("unresolved path in constant expression"),
+ ExpectedConstTuple => simple!("expected constant tuple"),
+ ExpectedConstStruct => simple!("expected constant struct"),
+ TupleIndexOutOfBounds => simple!("tuple index out of bounds"),
+ IndexedNonVec => simple!("indexing is only supported for arrays"),
+ IndexNegative => simple!("indices must be non-negative integers"),
+ IndexNotInt => simple!("indices must be integers"),
IndexOutOfBounds { len, index } => {
- format!("index out of bounds: the len is {} but the index is {}",
- len, index).into_cow()
+ simple!("index out of bounds: the len is {} but the index is {}",
+ len, index)
}
- RepeatCountNotNatural => "repeat count must be a natural number".into_cow(),
- RepeatCountNotInt => "repeat count must be integers".into_cow(),
+ RepeatCountNotNatural => simple!("repeat count must be a natural number"),
+ RepeatCountNotInt => simple!("repeat count must be integers"),
- MiscBinaryOp => "bad operands for binary".into_cow(),
- MiscCatchAll => "unsupported constant expr".into_cow(),
- IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(),
- Math(ref err) => err.description().into_cow(),
+ MiscBinaryOp => simple!("bad operands for binary"),
+ MiscCatchAll => simple!("unsupported constant expr"),
+ IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
+ Math(ref err) => Simple(err.description().into_cow()),
- IntermediateUnsignedNegative => "during the computation of an unsigned a negative \
- number was encountered. This is most likely a bug in\
- the constant evaluator".into_cow(),
+ IntermediateUnsignedNegative => simple!(
+ "during the computation of an unsigned a negative \
+ number was encountered. This is most likely a bug in\
+ the constant evaluator"),
TypeMismatch(ref expected, ref got) => {
- format!("mismatched types: expected `{}`, found `{}`",
- expected, got.description()).into_cow()
+ simple!("expected {}, found {}", expected, got.description())
},
- BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(),
- ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(),
+ BadType(ref i) => simple!("value of wrong type: {:?}", i),
+ ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
CharCast(ref got) => {
- format!("only `u8` can be cast as `char`, not `{}`", got.description()).into_cow()
+ simple!("only `u8` can be cast as `char`, not `{}`", got.description())
},
}
}
Float(f) => cast_const_float(tcx, f, ty),
Char(c) => cast_const_int(tcx, Infer(c as u64), ty),
Function(_) => Err(UnimplementedConstVal("casting fn pointers")),
- ByteStr(_) => match ty.sty {
+ ByteStr(b) => match ty.sty {
ty::TyRawPtr(_) => {
Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
},
- ty::TyRef(..) => Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice")),
+ ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
+ ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)),
+ ty::TySlice(_) => {
+ Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
+ },
+ _ => Err(CannotCast),
+ },
+ _ => Err(CannotCast),
+ },
+ Str(s) => match ty.sty {
+ ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")),
+ ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
+ ty::TyStr => Ok(Str(s)),
+ _ => Err(CannotCast),
+ },
_ => Err(CannotCast),
},
_ => Err(CannotCast),
})
}
-pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
- match (a, b) {
+pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
+ -> Result<Ordering, ErrorReported>
+{
+ let result = match (a, b) {
(&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
(&Float(a), &Float(b)) => a.try_cmp(b).ok(),
(&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
(&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
(&Char(a), &Char(ref b)) => Some(a.cmp(b)),
_ => None,
+ };
+
+ match result {
+ Some(result) => Ok(result),
+ None => {
+ // FIXME: can this ever be reached?
+ span_err!(tcx.sess, span, E0298,
+ "type mismatch comparing {} and {}",
+ a.description(),
+ b.description());
+ Err(ErrorReported)
+ }
}
}
pub fn compare_lit_exprs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ span: Span,
a: &Expr,
- b: &Expr) -> Option<Ordering> {
+ b: &Expr) -> Result<Ordering, ErrorReported> {
let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) {
Ok(a) => a,
Err(e) => {
- tcx.sess.span_err(a.span, &e.description());
- return None;
+ report_const_eval_err(tcx, &e, a.span, "expression").emit();
+ return Err(ErrorReported);
}
};
let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) {
Ok(b) => b,
Err(e) => {
- tcx.sess.span_err(b.span, &e.description());
- return None;
+ report_const_eval_err(tcx, &e, b.span, "expression").emit();
+ return Err(ErrorReported);
}
};
- compare_const_vals(&a, &b)
+ compare_const_vals(tcx, span, &a, &b)
}
-/// Returns the repeat count for a repeating vector expression.
-pub fn eval_repeat_count<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- count_expr: &hir::Expr) -> usize {
+/// Returns the value of the length-valued expression
+pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ count_expr: &hir::Expr,
+ reason: &str)
+ -> Result<usize, ErrorReported>
+{
let hint = UncheckedExprHint(tcx.types.usize);
match eval_const_expr_partial(tcx, count_expr, hint, None) {
Ok(Integral(Usize(count))) => {
let val = count.as_u64(tcx.sess.target.uint_type);
assert_eq!(val as usize as u64, val);
- val as usize
+ Ok(val as usize)
},
Ok(const_val) => {
span_err!(tcx.sess, count_expr.span, E0306,
- "expected positive integer for repeat count, found {}",
+ "expected usize for {}, found {}",
+ reason,
const_val.description());
- 0
+ Err(ErrorReported)
}
Err(err) => {
- let err_msg = match count_expr.node {
+ let mut diag = report_const_eval_err(
+ tcx, &err, count_expr.span, reason);
+
+ match count_expr.node {
hir::ExprPath(None, hir::Path {
global: false,
ref segments,
..
- }) if segments.len() == 1 =>
- format!("found variable"),
- _ => match err.kind {
- MiscCatchAll => format!("but found {}", err.description()),
- _ => format!("but {}", err.description())
+ }) if segments.len() == 1 => {
+ if let Some(Def::Local(..)) = tcx.expect_def_or_none(count_expr.id) {
+ diag.note(&format!("`{}` is a variable", segments[0].name));
+ }
}
- };
- span_err!(tcx.sess, count_expr.span, E0307,
- "expected constant integer for repeat count, {}", err_msg);
- 0
+ _ => {}
+ }
+
+ diag.emit();
+ Err(ErrorReported)
}
}
}
#[macro_use] extern crate rustc;
extern crate rustc_back;
extern crate rustc_const_math;
+extern crate rustc_errors;
extern crate graphviz;
extern crate syntax_pos;
extern crate serialize as rustc_serialize; // used by deriving
cfg: ast::CrateConfig,
input: &Input)
-> PResult<'a, ast::Crate> {
- // These may be left in an incoherent state after a previous compile.
- syntax::ext::hygiene::reset_hygiene_data();
- // `clear_ident_interner` can be used to free memory, but it does not restore the initial state.
- token::reset_ident_interner();
let continue_after_error = sess.opts.continue_parse_after_error;
sess.diagnostic().set_continue_after_error(continue_after_error);
}
}
}
+
+// For use by the `rusti` project (https://github.com/murarth/rusti).
+pub fn reset_thread_local_state() {
+ // These may be left in an incoherent state after a previous compile.
+ syntax::ext::hygiene::reset_hygiene_data();
+ // `clear_ident_interner` can be used to free memory, but it does not restore the initial state.
+ token::reset_ident_interner();
+}
DiagnosticBuilder::new(self, Level::Fatal, msg)
}
- pub fn cancel(&mut self, err: &mut DiagnosticBuilder) {
+ pub fn cancel(&self, err: &mut DiagnosticBuilder) {
if err.level == Level::Error || err.level == Level::Fatal {
- assert!(self.has_errors());
- self.err_count.set(self.err_count.get() + 1);
+ self.err_count.set(
+ self.err_count.get().checked_sub(1)
+ .expect("cancelled an error but err_count is 0")
+ );
}
err.cancel();
}
use rustc::middle::mem_categorization::Categorization;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::traits::ProjectionMode;
+use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
use rustc::middle::const_qualif::ConstQualif;
use rustc::lint::builtin::CONST_ERR;
_ => self.tcx.sess.add_lint(CONST_ERR, expr.id, expr.span,
format!("constant evaluation error: {}. This will \
become a HARD ERROR in the future",
- err.description())),
+ err.description().into_oneline())),
}
}
self.with_mode(mode, |this| {
}
}
}
-
- fn msg(&self) -> &'static str {
- match self.mode {
- Mode::Const => "constant",
- Mode::ConstFn => "constant function",
- Mode::StaticMut | Mode::Static => "static",
- Mode::Var => bug!(),
- }
- }
}
impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
self.global_expr(Mode::Const, &start);
self.global_expr(Mode::Const, &end);
- match compare_lit_exprs(self.tcx, start, end) {
- Some(Ordering::Less) |
- Some(Ordering::Equal) => {}
- Some(Ordering::Greater) => {
+ match compare_lit_exprs(self.tcx, p.span, start, end) {
+ Ok(Ordering::Less) |
+ Ok(Ordering::Equal) => {}
+ Ok(Ordering::Greater) => {
span_err!(self.tcx.sess, start.span, E0030,
"lower range bound must be less than or equal to upper");
}
- None => {
- span_err!(self.tcx.sess, p.span, E0014,
- "paths in {}s may only refer to constants",
- self.msg());
- }
+ Err(ErrorReported) => {}
}
}
_ => intravisit::walk_pat(self, p)
Err(msg) => {
self.tcx.sess.add_lint(CONST_ERR, ex.id,
msg.span,
- msg.description().into_owned())
+ msg.description().into_oneline().into_owned())
}
}
}
#![allow(non_snake_case)]
register_long_diagnostics! {
-
+/*
E0014: r##"
Constants can only be initialized by a constant value or, in a future
version of Rust, a call to a const function. This error indicates the use
const FOO2: i32 = { 0 }; // but brackets are useless here
```
"##,
-
+*/
E0030: r##"
When matching against a range, the compiler verifies that the range is
non-empty. Range patterns include both end-points, so this is equivalent to
let resolution = if let Some(resolution) = self.resolve_possibly_assoc_item(pat_id,
qself, path, namespace) {
if resolution.depth == 0 {
- if expected_fn(resolution.base_def) {
+ if expected_fn(resolution.base_def) || resolution.base_def == Def::Err {
resolution
} else {
resolve_error(
);
None
}
- Def::Local(..) | Def::Upvar(..) | Def::Fn(..) => {
+ Def::Local(..) | Def::Upvar(..) | Def::Fn(..) | Def::Err => {
// These entities are explicitly allowed
// to be shadowed by fresh bindings.
None
}
fn span_extent_str(span: SpanData) -> String {
- format!("file_name,\"{}\",file_line,{},file_col,{},byte_start,{}\
+ format!("file_name,\"{}\",file_line,{},file_col,{},byte_start,{},\
file_line_end,{},file_col_end,{},byte_end,{}",
span.file_name, span.line_start, span.column_start, span.byte_start,
span.line_end, span.column_end, span.byte_end)
use llvm::{ValueRef, BasicBlockRef};
use rustc_const_eval::check_match::{self, Constructor, StaticInliner};
-use rustc_const_eval::{compare_lit_exprs, eval_const_expr};
+use rustc_const_eval::{compare_lit_exprs, eval_const_expr, fatal_const_eval_err};
use rustc::hir::def::{Def, DefMap};
use rustc::hir::def_id::DefId;
use middle::expr_use_visitor as euv;
impl<'a> ConstantExpr<'a> {
fn eq<'b, 'tcx>(self, other: ConstantExpr<'a>, tcx: TyCtxt<'b, 'tcx, 'tcx>) -> bool {
- match compare_lit_exprs(tcx, self.0, other.0) {
- Some(result) => result == Ordering::Equal,
- None => bug!("compare_list_exprs: type mismatch"),
+ match compare_lit_exprs(tcx, self.0.span, self.0, other.0) {
+ Ok(result) => result == Ordering::Equal,
+ Err(_) => bug!("compare_list_exprs: type mismatch"),
}
}
}
let expr = consts::const_expr(ccx, &lit_expr, bcx.fcx.param_substs, None, Yes);
let llval = match expr {
Ok((llval, _)) => llval,
- Err(err) => bcx.ccx().sess().span_fatal(lit_expr.span, &err.description()),
+ Err(err) => {
+ fatal_const_eval_err(bcx.tcx(), err.as_inner(), lit_expr.span, "pattern");
+ }
};
let lit_datum = immediate_rvalue(llval, lit_ty);
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => {
let l1 = match consts::const_expr(ccx, &l1, bcx.fcx.param_substs, None, Yes) {
Ok((l1, _)) => l1,
- Err(err) => bcx.ccx().sess().span_fatal(l1.span, &err.description()),
+ Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l1.span, "pattern"),
};
let l2 = match consts::const_expr(ccx, &l2, bcx.fcx.param_substs, None, Yes) {
Ok((l2, _)) => l2,
- Err(err) => bcx.ccx().sess().span_fatal(l2.span, &err.description()),
+ Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l2.span, "pattern"),
};
RangeResult(Result::new(bcx, l1), Result::new(bcx, l2))
}
use llvm::{InternalLinkage, ValueRef, Bool, True};
use middle::const_qualif::ConstQualif;
use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind};
-use rustc_const_eval::eval_repeat_count;
+use rustc_const_eval::{eval_length, report_const_eval_err, note_const_eval_err};
use rustc::hir::def::Def;
use rustc::hir::def_id::DefId;
use rustc::hir::map as hir_map;
use rustc::hir;
use std::ffi::{CStr, CString};
-use std::borrow::Cow;
use libc::c_uint;
use syntax::ast::{self, LitKind};
use syntax::attr::{self, AttrMetaMethods};
Compiletime(e) => e,
}
}
- pub fn description(&self) -> Cow<str> {
+
+ pub fn as_inner(&self) -> &ConstEvalErr {
match self {
- &Runtime(ref e) => e.description(),
- &Compiletime(ref e) => e.description(),
+ &Runtime(ref e) => e,
+ &Compiletime(ref e) => e,
}
}
}
let empty_substs = ccx.tcx().mk_substs(Substs::empty());
match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) {
Err(Runtime(err)) => {
- ccx.tcx().sess.span_err(expr.span, &err.description());
+ report_const_eval_err(ccx.tcx(), &err, expr.span, "expression").emit();
Err(Compiletime(err))
},
other => other,
(Ok(x), _) => Ok(x),
(Err(err), TrueConst::Yes) => {
let err = ConstEvalErr{ span: span, kind: err };
- cx.tcx().sess.span_err(span, &err.description());
+ report_const_eval_err(cx.tcx(), &err, span, "expression").emit();
Err(Compiletime(err))
},
(Err(err), TrueConst::No) => {
let err = ConstEvalErr{ span: span, kind: err };
- cx.tcx().sess.span_warn(span, &err.description());
+ let mut diag = cx.tcx().sess.struct_span_warn(
+ span, "this expression will panic at run-time");
+ note_const_eval_err(cx.tcx(), &err, span, "expression", &mut diag);
+ diag.emit();
Err(Runtime(err))
},
}
hir::ExprRepeat(ref elem, ref count) => {
let unit_ty = ety.sequence_element_type(cx.tcx());
let llunitty = type_of::type_of(cx, unit_ty);
- let n = eval_repeat_count(cx.tcx(), count);
+ let n = eval_length(cx.tcx(), count, "repeat count").unwrap();
let unit_val = const_expr(cx, &elem, param_substs, fn_args, trueconst)?.0;
let vs = vec![unit_val; n];
if val_ty(unit_val) != llunitty {
use syntax::parse::token;
use rustc::session::Session;
+use rustc_const_eval::fatal_const_eval_err;
use syntax_pos::{Span, DUMMY_SP};
use std::cmp::Ordering;
// managed by the standard library.
attributes::emit_uwtable(bcx.fcx.llfn, true);
- let catch_pers = match tcx.lang_items.eh_personality_catch() {
- Some(did) => {
- Callee::def(ccx, did, tcx.mk_substs(Substs::empty())).reify(ccx).val
+ let target = &bcx.sess().target.target;
+ let catch_pers = if target.arch == "arm" && target.target_os != "ios" {
+ // Only ARM still uses a separate catch personality (for now)
+ match tcx.lang_items.eh_personality_catch() {
+ Some(did) => {
+ Callee::def(ccx, did, tcx.mk_substs(Substs::empty())).reify(ccx).val
+ }
+ None => bug!("eh_personality_catch not defined"),
}
- None => bug!("eh_personality_catch not defined"),
+ } else {
+ bcx.fcx.eh_personality()
};
let then = bcx.fcx.new_temp_block("then");
// this should probably help simd error reporting
consts::TrueConst::Yes) {
Ok((vector, _)) => vector,
- Err(err) => bcx.sess().span_fatal(span, &err.description()),
+ Err(err) => {
+ fatal_const_eval_err(bcx.tcx(), err.as_inner(), span,
+ "shuffle indices");
+ }
}
}
None => llargs[2]
}
Err(ConstEvalFailure::Runtime(err)) => {
span_bug!(constant.span,
- "MIR constant {:?} results in runtime panic: {}",
+ "MIR constant {:?} results in runtime panic: {:?}",
constant, err.description())
}
}
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::subst;
use rustc::dep_graph::DepNode;
+use rustc_const_eval::fatal_const_eval_err;
use std::hash::{Hash, Hasher};
use syntax::ast::{self, NodeId};
use syntax::{attr,errors};
if let hir::ItemStatic(_, m, ref expr) = item.node {
match consts::trans_static(&ccx, m, expr, item.id, &item.attrs) {
Ok(_) => { /* Cool, everything's alright. */ },
- Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()),
+ Err(err) => {
+ // FIXME: shouldn't this be a `span_err`?
+ fatal_const_eval_err(
+ ccx.tcx(), &err, expr.span, "static");
+ }
};
} else {
span_bug!(item.span, "Mismatch between hir::Item type and TransItem type")
use rustc::ty::{self, Ty};
use rustc::hir;
-use rustc_const_eval::eval_repeat_count;
+use rustc_const_eval::eval_length;
use syntax::ast;
use syntax::parse::token::InternedString;
return expr::trans_into(bcx, &element, Ignore);
}
SaveIn(lldest) => {
- match eval_repeat_count(bcx.tcx(), &count_expr) {
+ match eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() {
0 => expr::trans_into(bcx, &element, Ignore),
1 => expr::trans_into(bcx, &element, SaveIn(lldest)),
count => {
},
hir::ExprVec(ref es) => es.len(),
hir::ExprRepeat(_, ref count_expr) => {
- eval_repeat_count(bcx.tcx(), &count_expr)
+ eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap()
}
_ => span_bug!(content_expr.span, "unexpected vec content")
}
//! case but `&a` in the second. Basically, defaults that appear inside
//! an rptr (`&r.T`) use the region `r` that appears in the rptr.
-use middle::const_val::ConstVal;
-use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
-use rustc_const_eval::EvalHint::UncheckedExprHint;
-use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
+use rustc_const_eval::eval_length;
use hir::{self, SelfKind};
use hir::def::{Def, PathResolution};
use hir::def_id::DefId;
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::{NodeMap, FnvHashSet};
-use rustc_const_math::ConstInt;
use std::cell::RefCell;
use syntax::{abi, ast};
use syntax::feature_gate::{GateIssue, emit_feature_err};
ty
}
hir::TyFixedLengthVec(ref ty, ref e) => {
- let hint = UncheckedExprHint(tcx.types.usize);
- match eval_const_expr_partial(tcx.global_tcx(), &e, hint, None) {
- Ok(ConstVal::Integral(ConstInt::Usize(i))) => {
- let i = i.as_u64(tcx.sess.target.uint_type);
- assert_eq!(i as usize as u64, i);
- tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), i as usize)
- },
- Ok(val) => {
- span_err!(tcx.sess, ast_ty.span, E0249,
- "expected usize value for array length, got {}",
- val.description());
- self.tcx().types.err
- },
- // array length errors happen before the global constant check
- // so we need to report the real error
- Err(ConstEvalErr { kind: ErroneousReferencedConstant(box r), ..}) |
- Err(r) => {
- let mut err = struct_span_err!(tcx.sess, r.span, E0250,
- "array length constant \
- evaluation error: {}",
- r.description());
- if !ast_ty.span.contains(r.span) {
- span_note!(&mut err, ast_ty.span, "for array length here")
- }
- err.emit();
- self.tcx().types.err
- }
+ if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") {
+ tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
+ } else {
+ self.tcx().types.err
}
}
hir::TyTypeof(ref _e) => {
return;
}
- // Check that the types of the end-points can be unified.
- let types_unify = self.require_same_types(pat.span, rhs_ty, lhs_ty,
- "mismatched types in range");
-
- // It's ok to return without a message as `require_same_types` prints an error.
- if !types_unify {
- return;
- }
-
// Now that we know the types can be unified we find the unified type and use
// it to type the entire expression.
let common_type = self.resolve_type_vars_if_possible(&lhs_ty);
// subtyping doesn't matter here, as the value is some kind of scalar
self.demand_eqtype(pat.span, expected, lhs_ty);
+ self.demand_eqtype(pat.span, expected, rhs_ty);
}
PatKind::Binding(bm, _, ref sub) => {
let typ = self.local_ty(pat.span, pat.id);
_ => {
let mut err = self.type_error_struct(call_expr.span, |actual| {
format!("expected function, found `{}`", actual)
- }, callee_ty, None);
+ }, callee_ty);
if let hir::ExprCall(ref expr, _) = call_expr.node {
let tcx = self.tcx;
format!("casting `{}` as `{}` is invalid",
actual,
fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty, None)
+ }, self.expr_ty)
.help(&format!("cast through {} first", match e {
CastError::NeedViaPtr => "a raw pointer",
CastError::NeedViaThinPtr => "a thin pointer",
CastError::CastToChar => {
fcx.type_error_message(self.span, |actual| {
format!("only `u8` can be cast as `char`, not `{}`", actual)
- }, self.expr_ty, None);
+ }, self.expr_ty);
}
CastError::NonScalar => {
fcx.type_error_message(self.span, |actual| {
format!("non-scalar cast: `{}` as `{}`",
actual,
fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty, None);
+ }, self.expr_ty);
}
CastError::IllegalCast => {
fcx.type_error_message(self.span, |actual| {
format!("casting `{}` as `{}` is invalid",
actual,
fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty, None);
+ }, self.expr_ty);
}
CastError::SizedUnsizedCast => {
fcx.type_error_message(self.span, |actual| {
format!("cannot cast thin pointer `{}` to fat pointer `{}`",
actual,
fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty, None)
+ }, self.expr_ty)
}
CastError::DifferingKinds => {
fcx.type_error_struct(self.span, |actual| {
format!("casting `{}` as `{}` is invalid",
actual,
fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty, None)
+ }, self.expr_ty)
.note("vtable kinds may not match")
.emit();
}
let tstr = fcx.ty_to_string(self.cast_ty);
let mut err = fcx.type_error_struct(self.span, |actual| {
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
- }, self.expr_ty, None);
+ }, self.expr_ty);
match self.expr_ty.sty {
ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => {
let mtstr = match mt {
traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span)
}
}
-
use rustc::infer::{self, InferOk, TypeOrigin};
use rustc::ty;
use rustc::traits::{self, ProjectionMode};
+use rustc::ty::error::ExpectedFound;
use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace};
use syntax::ast;
debug!("sub_types failed: impl ty {:?}, trait ty {:?}",
impl_fty,
trait_fty);
- span_err!(tcx.sess, impl_m_span, E0053,
- "method `{}` has an incompatible type for trait: {}",
- trait_m.name,
- terr);
+
+ let mut diag = struct_span_err!(
+ tcx.sess, origin.span(), E0053,
+ "method `{}` has an incompatible type for trait", trait_m.name
+ );
+ infcx.note_type_err(
+ &mut diag, origin,
+ Some(infer::ValuePairs::Types(ExpectedFound {
+ expected: trait_fty,
+ found: impl_fty
+ })), &terr
+ );
+ diag.emit();
return
}
// Compute skolemized form of impl and trait const tys.
let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs);
+ let origin = TypeOrigin::Misc(impl_c_span);
let err = infcx.commit_if_ok(|_| {
- let origin = TypeOrigin::Misc(impl_c_span);
-
// There is no "body" here, so just pass dummy id.
let impl_ty =
assoc::normalize_associated_types_in(&infcx,
debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
impl_ty,
trait_ty);
- span_err!(tcx.sess, impl_c_span, E0326,
- "implemented const `{}` has an incompatible type for \
- trait: {}",
- trait_c.name,
- terr);
+ let mut diag = struct_span_err!(
+ tcx.sess, origin.span(), E0326,
+ "implemented const `{}` has an incompatible type for trait",
+ trait_c.name
+ );
+ infcx.note_type_err(
+ &mut diag, origin,
+ Some(infer::ValuePairs::Types(ExpectedFound {
+ expected: trait_ty,
+ found: impl_ty
+ })), &terr
+ );
+ diag.emit();
}
});
}
}
pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
- let origin = TypeOrigin::Misc(sp);
+ self.demand_eqtype_with_origin(TypeOrigin::Misc(sp), expected, actual);
+ }
+
+ pub fn demand_eqtype_with_origin(&self,
+ origin: TypeOrigin,
+ expected: Ty<'tcx>,
+ actual: Ty<'tcx>)
+ {
match self.eq_types(false, origin, actual, expected) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
self.report_mismatched_types(origin, expected, expr_ty, e);
}
}
-
- pub fn require_same_types(&self, span: Span, t1: Ty<'tcx>, t2: Ty<'tcx>, msg: &str)
- -> bool {
- if let Err(err) = self.eq_types(false, TypeOrigin::Misc(span), t1, t2) {
- let found_ty = self.resolve_type_vars_if_possible(&t1);
- let expected_ty = self.resolve_type_vars_if_possible(&t2);
- ::emit_type_err(self.tcx, span, found_ty, expected_ty, &err, msg);
- false
- } else {
- true
- }
- }
}
//! intrinsics that the compiler exposes.
use intrinsics;
+use rustc::infer::TypeOrigin;
use rustc::ty::subst::{self, Substs};
use rustc::ty::FnSig;
use rustc::ty::{self, Ty};
i_n_tps, n_tps);
} else {
require_same_types(ccx,
- it.span,
+ TypeOrigin::IntrinsicType(it.span),
i_ty.ty,
- fty,
- "intrinsic has wrong type");
+ fty);
}
}
item_name,
actual)
},
- rcvr_ty,
- None);
+ rcvr_ty);
// If the item has the name of a field, give a help note
if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) {
use rustc::hir::{self, PatKind};
use rustc::hir::print as pprust;
use rustc_back::slice;
-use rustc_const_eval::eval_repeat_count;
+use rustc_const_eval::eval_length;
mod assoc;
mod autoderef;
self.type_error_message(arg.span, |t| {
format!("can't pass an `{}` to variadic \
function, cast to `c_double`", t)
- }, arg_ty, None);
+ }, arg_ty);
}
ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => {
self.type_error_message(arg.span, |t| {
format!("can't pass `{}` to variadic \
function, cast to `c_int`",
t)
- }, arg_ty, None);
+ }, arg_ty);
}
ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => {
self.type_error_message(arg.span, |t| {
format!("can't pass `{}` to variadic \
function, cast to `c_uint`",
t)
- }, arg_ty, None);
+ }, arg_ty);
}
ty::TyFnDef(_, _, f) => {
let ptr_ty = self.tcx.mk_fn_ptr(f);
|t| {
format!("can't pass `{}` to variadic \
function, cast to `{}`", t, ptr_ty)
- }, arg_ty, None);
+ }, arg_ty);
}
_ => {}
}
self.type_error_struct(field.span, |actual| {
format!("attempted to take value of method `{}` on type \
`{}`", field.node, actual)
- }, expr_t, None)
- .help(
- "maybe a `()` to call it is missing? \
+ }, expr_t)
+ .help("maybe a `()` to call it is missing? \
If not, try an anonymous function")
.emit();
self.write_error(expr.id);
format!("attempted access of field `{}` on type `{}`, \
but no field with that name was found",
field.node, actual)
- }, expr_t, None);
+ }, expr_t);
if let ty::TyStruct(def, _) = expr_t.sty {
Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
}
actual)
}
},
- expr_t, None);
+ expr_t);
self.write_error(expr.id);
}
variant: ty::VariantDef<'tcx>,
field: &hir::Field,
skip_fields: &[hir::Field]) {
- let mut err = self.type_error_struct(
+ let mut err = self.type_error_struct_with_diag(
field.name.span,
|actual| if let ty::TyEnum(..) = ty.sty {
- format!("struct variant `{}::{}` has no field named `{}`",
- actual, variant.name.as_str(), field.name.node)
+ struct_span_err!(self.tcx.sess, field.name.span, E0559,
+ "struct variant `{}::{}` has no field named `{}`",
+ actual, variant.name.as_str(), field.name.node)
} else {
- format!("structure `{}` has no field named `{}`",
- actual, field.name.node)
+ struct_span_err!(self.tcx.sess, field.name.span, E0560,
+ "structure `{}` has no field named `{}`",
+ actual, field.name.node)
},
- ty,
- None);
+ ty);
// prevent all specified fields from being suggested
let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str());
Self::suggest_field_names(&mut err, variant, &field.name, skip_fields.collect());
self.type_error_message(expr.span, |actual| {
format!("type `{}` cannot be \
dereferenced", actual)
- }, oprnd_t, None);
+ }, oprnd_t);
oprnd_t = tcx.types.err;
}
}
}
hir::ExprRepeat(ref element, ref count_expr) => {
self.check_expr_has_type(&count_expr, tcx.types.usize);
- let count = eval_repeat_count(self.tcx.global_tcx(), &count_expr);
+ let count = eval_length(self.tcx.global_tcx(), &count_expr, "repeat count")
+ .unwrap_or(0);
let uty = match expected {
ExpectHasType(uty) => {
format!("cannot index a value of type `{}`",
actual)
},
- base_t,
- None);
+ base_t);
// Try to give some advice about indexing tuples.
if let ty::TyTuple(_) = base_t.sty {
let mut needs_note = true;
if !self.is_tainted_by_errors() {
self.type_error_message(sp, |_actual| {
"the type of this value must be known in this context".to_string()
- }, ty, None);
+ }, ty);
}
self.demand_suptype(sp, self.tcx.types.err, ty);
ty = self.tcx.types.err;
self.type_error_message(ex.span, |actual| {
format!("cannot apply unary operator `{}` to type `{}`",
op_str, actual)
- }, operand_ty, None);
+ }, operand_ty);
self.tcx.types.err
}
}
use CrateCtxt;
use hir::def_id::DefId;
use middle::region::{CodeExtent};
+use rustc::infer::TypeOrigin;
use rustc::ty::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt};
}
}
- fn check_trait_or_impl_item(&mut self, item_id: ast::NodeId, span: Span) {
+ fn check_trait_or_impl_item(&mut self,
+ item_id: ast::NodeId,
+ span: Span,
+ sig_if_method: Option<&hir::MethodSig>) {
let code = self.code.clone();
self.for_id(item_id, span).with_fcx(|fcx, this| {
let free_substs = &fcx.parameter_environment.free_substs;
let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates);
this.check_fn_or_method(fcx, span, &method_ty, &predicates,
free_id_outlive, &mut implied_bounds);
- this.check_method_receiver(fcx, span, &method,
+ let sig_if_method = sig_if_method.expect("bad signature for method");
+ this.check_method_receiver(fcx, sig_if_method, &method,
free_id_outlive, self_ty);
}
ty::TypeTraitItem(assoc_type) => {
fn check_method_receiver<'fcx, 'tcx>(&mut self,
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
- span: Span,
+ method_sig: &hir::MethodSig,
method: &ty::Method<'tcx>,
free_id_outlive: CodeExtent,
self_ty: ty::Ty<'tcx>)
{
// check that the type of the method's receiver matches the
// method's first parameter.
-
- let free_substs = &fcx.parameter_environment.free_substs;
- let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
- let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
-
- debug!("check_method_receiver({:?},cat={:?},self_ty={:?},sig={:?})",
- method.name, method.explicit_self, self_ty, sig);
+ debug!("check_method_receiver({:?},cat={:?},self_ty={:?})",
+ method.name, method.explicit_self, self_ty);
let rcvr_ty = match method.explicit_self {
ty::ExplicitSelfCategory::Static => return,
}
ty::ExplicitSelfCategory::ByBox => fcx.tcx.mk_box(self_ty)
};
+
+ let span = method_sig.decl.inputs[0].pat.span;
+
+ let free_substs = &fcx.parameter_environment.free_substs;
+ let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
+ let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
+
+ debug!("check_method_receiver: sig={:?}", sig);
+
let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty);
let rcvr_ty = fcx.tcx.liberate_late_bound_regions(free_id_outlive,
&ty::Binder(rcvr_ty));
debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
- fcx.require_same_types(span, sig.inputs[0], rcvr_ty,
- "mismatched method receiver");
+ let origin = TypeOrigin::MethodReceiver(span);
+ fcx.demand_eqtype_with_origin(origin, rcvr_ty, sig.inputs[0]);
}
fn check_variances_for_type_defn(&self,
fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
debug!("visit_trait_item: {:?}", trait_item);
- self.check_trait_or_impl_item(trait_item.id, trait_item.span);
+ let method_sig = match trait_item.node {
+ hir::TraitItem_::MethodTraitItem(ref sig, _) => Some(sig),
+ _ => None
+ };
+ self.check_trait_or_impl_item(trait_item.id, trait_item.span, method_sig);
intravisit::walk_trait_item(self, trait_item)
}
fn visit_impl_item(&mut self, impl_item: &'v hir::ImplItem) {
debug!("visit_impl_item: {:?}", impl_item);
- self.check_trait_or_impl_item(impl_item.id, impl_item.span);
+ let method_sig = match impl_item.node {
+ hir::ImplItemKind::Method(ref sig, _) => Some(sig),
+ _ => None
+ };
+ self.check_trait_or_impl_item(impl_item.id, impl_item.span, method_sig);
intravisit::walk_impl_item(self, impl_item)
}
}
use middle::lang_items::SizedTraitLangItem;
use middle::const_val::ConstVal;
use rustc_const_eval::EvalHint::UncheckedExprHint;
-use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
-use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
+use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err};
use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme};
},
// enum variant evaluation happens before the global constant check
// so we need to report the real error
- Err(ConstEvalErr { kind: ErroneousReferencedConstant(box err), ..}) |
Err(err) => {
- let mut diag = struct_span_err!(ccx.tcx.sess, err.span, E0080,
- "constant evaluation error: {}",
- err.description());
- if !e.span.contains(err.span) {
- diag.span_note(e.span, "for enum discriminant here");
- }
+ let mut diag = report_const_eval_err(
+ ccx.tcx, &err, e.span, "enum discriminant");
diag.emit();
None
}
```
"##,
-E0080: r##"
-This error indicates that the compiler was unable to sensibly evaluate an
-integer expression provided as an enum discriminant. Attempting to divide by 0
-or causing integer overflow are two ways to induce this error. For example:
-
-```compile_fail
-enum Enum {
- X = (1 << 500),
- Y = (1 / 0)
-}
-```
-
-Ensure that the expressions given can be evaluated as the desired integer type.
-See the FFI section of the Reference for more information about using a custom
-integer type:
-
-https://doc.rust-lang.org/reference.html#ffi-attributes
-"##,
-
E0081: r##"
Enum discriminants are used to differentiate enum variants stored in memory.
This error indicates that the same value was used for two or more variants,
[RFC 1023]: https://github.com/rust-lang/rfcs/pull/1023
"##,
+/*
E0211: r##"
You used a function or type which doesn't fit the requirements for where it was
used. Erroneous code examples:
}
```
"##,
+ */
E0214: r##"
A generic type was described using parentheses rather than angle brackets. For
behavior for specific enum variants.
"##,
-E0249: r##"
-This error indicates a constant expression for the array length was found, but
-it was not an integer (signed or unsigned) expression.
-
-Some examples of code that produces this error are:
-
-```compile_fail
-const A: [u32; "hello"] = []; // error
-const B: [u32; true] = []; // error
-const C: [u32; 0.0] = []; // error
-"##,
-
-E0250: r##"
-There was an error while evaluating the expression for the length of a fixed-
-size array type.
-
-Some examples of this error are:
-
-```compile_fail
-// divide by zero in the length expression
-const A: [u32; 1/0] = [];
-
-// Rust currently will not evaluate the function `foo` at compile time
-fn foo() -> usize { 12 }
-const B: [u32; foo()] = [];
-
-// it is an error to try to add `u8` and `f64`
-use std::{f64, u8};
-const C: [u32; u8::MAX + f64::EPSILON] = [];
-```
-"##,
-
E0318: r##"
Default impls for a trait must be located in the same crate where the trait was
defined. For more information see the [opt-in builtin traits RFC](https://github
```
"##,
+E0559: r##"
+An unknown field was specified into an enum's structure variant.
+
+Erroneous code example:
+
+```compile_fail,E0559
+enum Field {
+ Fool { x: u32 },
+}
+
+let s = Field::Fool { joke: 0 };
+// error: struct variant `Field::Fool` has no field named `joke`
+```
+
+Verify you didn't misspell the field's name or that the field exists. Example:
+
+```
+enum Field {
+ Fool { joke: u32 },
+}
+
+let s = Field::Fool { joke: 0 }; // ok!
+```
+"##,
+
+E0560: r##"
+An unknown field was specified into a structure.
+
+Erroneous code example:
+
+```compile_fail,E0560
+struct Simba {
+ mother: u32,
+}
+
+let s = Simba { mother: 1, father: 0 };
+// error: structure `Simba` has no field named `father`
+```
+
+Verify you didn't misspell the field's name or that the field exists. Example:
+
+```
+struct Simba {
+ mother: u32,
+ father: u32,
+}
+
+let s = Simba { mother: 1, father: 0 }; // ok!
+```
+"##,
+
}
register_diagnostics! {
E0245, // not a trait
// E0246, // invalid recursive type
// E0247,
+// E0249,
// E0319, // trait impls for defaulted traits allowed just for structs/enums
E0320, // recursive overflow during dropck
E0328, // cannot implement Unsize explicitly
}
}
-pub fn emit_type_err<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- span: Span,
- found_ty: Ty<'tcx>,
- expected_ty: Ty<'tcx>,
- terr: &ty::error::TypeError<'tcx>,
- msg: &str) {
- let mut err = struct_span_err!(tcx.sess, span, E0211, "{}", msg);
- err.span_label(span, &terr);
- err.note_expected_found(&"type", &expected_ty, &found_ty);
- tcx.note_and_explain_type_err(&mut err, terr, span);
- err.emit();
-}
-
fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- span: Span,
+ origin: TypeOrigin,
t1: Ty<'tcx>,
- t2: Ty<'tcx>,
- msg: &str)
+ t2: Ty<'tcx>)
-> bool {
ccx.tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
- if let Err(err) = infcx.eq_types(false, TypeOrigin::Misc(span), t1, t2) {
- emit_type_err(infcx.tcx, span, t1, t2, &err, msg);
+ if let Err(err) = infcx.eq_types(false, origin.clone(), t1, t2) {
+ infcx.report_mismatched_types(origin, t1, t2, err);
false
} else {
true
})
}));
- require_same_types(ccx, main_span, main_t, se_ty,
- "main function has wrong type");
+ require_same_types(
+ ccx,
+ TypeOrigin::MainFunctionType(main_span),
+ main_t,
+ se_ty);
}
_ => {
span_bug!(main_span,
}),
}));
- require_same_types(ccx, start_span, start_t, se_ty,
- "start function has wrong type");
+ require_same_types(
+ ccx,
+ TypeOrigin::StartFunctionType(start_span),
+ start_t,
+ se_ty);
}
_ => {
span_bug!(start_span,
C::len_utf16(self)
}
- /// Returns an interator over the bytes of this character as UTF-8.
+ /// Returns an iterator over the bytes of this character as UTF-8.
///
/// The returned iterator also has an `as_slice()` method to view the
/// encoded bytes as a byte slice.
C::encode_utf8(self)
}
- /// Returns an interator over the `u16` entries of this character as UTF-16.
+ /// Returns an iterator over the `u16` entries of this character as UTF-16.
///
/// The returned iterator also has an `as_slice()` method to view the
/// encoded form as a slice.
if structhead {"struct "} else {""},
it.name.as_ref().unwrap())?;
if let Some(g) = g {
- write!(w, "{}{}", *g, WhereClause(g))?
+ write!(w, "{}", g)?
}
match ty {
doctree::Plain => {
+ if let Some(g) = g {
+ write!(w, "{}", WhereClause(g))?
+ }
write!(w, " {{\n{}", tab)?;
for field in fields {
if let clean::StructFieldItem(ref ty) = field.inner {
_ => unreachable!()
}
}
- write!(w, ");")?;
+ write!(w, ")")?;
+ if let Some(g) = g {
+ write!(w, "{}", WhereClause(g))?
+ }
+ write!(w, ";")?;
}
doctree::Unit => {
+ // Needed for PhantomData.
+ if let Some(g) = g {
+ write!(w, "{}", WhereClause(g))?
+ }
write!(w, ";")?;
}
}
/// }
///
/// for val in map.values() {
- /// print!("{}", val);
+ /// println!("{}", val);
/// }
/// ```
#[stable(feature = "map_values_mut", since = "1.10.0")]
}
/// A view into a single location in a map, which may be vacant or occupied.
+/// This enum is constructed from the [`entry`] method on [`HashMap`].
+///
+/// [`HashMap`]: struct.HashMap.html
+/// [`entry`]: struct.HashMap.html#method.entry
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Entry<'a, K: 'a, V: 'a> {
/// An occupied Entry.
}
/// A view into a single occupied location in a HashMap.
+/// It is part of the [`Entry`] enum.
+///
+/// [`Entry`]: enum.Entry.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
key: Option<K>,
}
/// A view into a single empty location in a HashMap.
+/// It is part of the [`Entry`] enum.
+///
+/// [`Entry`]: enum.Entry.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct VacantEntry<'a, K: 'a, V: 'a> {
hash: SafeHash,
#[stable(feature = "rust1", since = "1.0.0")]
/// Ensures a value is in the entry by inserting the default if empty, and returns
/// a mutable reference to the value in the entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ ///
+ /// assert_eq!(map["poneyland"], 12);
+ ///
+ /// *map.entry("poneyland").or_insert(12) += 10;
+ /// assert_eq!(map["poneyland"], 22);
+ /// ```
pub fn or_insert(self, default: V) -> &'a mut V {
match self {
Occupied(entry) => entry.into_mut(),
#[stable(feature = "rust1", since = "1.0.0")]
/// Ensures a value is in the entry by inserting the result of the default function if empty,
/// and returns a mutable reference to the value in the entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, String> = HashMap::new();
+ /// let s = "hoho".to_owned();
+ ///
+ /// map.entry("poneyland").or_insert_with(|| s);
+ ///
+ /// assert_eq!(map["poneyland"], "hoho".to_owned());
+ /// ```
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
match self {
Occupied(entry) => entry.into_mut(),
}
/// Returns a reference to this entry's key.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+ /// ```
#[stable(feature = "map_entry_keys", since = "1.10.0")]
pub fn key(&self) -> &K {
match *self {
impl<'a, K, V> OccupiedEntry<'a, K, V> {
/// Gets a reference to the key in the entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+ /// ```
#[stable(feature = "map_entry_keys", since = "1.10.0")]
pub fn key(&self) -> &K {
self.elem.read().0
}
/// Take the ownership of the key and value from the map.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(map_entry_recover_keys)]
+ ///
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ ///
+ /// if let Entry::Occupied(o) = map.entry("poneyland") {
+ /// // We delete the entry from the map.
+ /// o.remove_pair();
+ /// }
+ ///
+ /// assert_eq!(map.contains_key("poneyland"), false);
+ /// ```
#[unstable(feature = "map_entry_recover_keys", issue = "34285")]
pub fn remove_pair(self) -> (K, V) {
pop_internal(self.elem)
}
/// Gets a reference to the value in the entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ ///
+ /// if let Entry::Occupied(o) = map.entry("poneyland") {
+ /// assert_eq!(o.get(), &12);
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get(&self) -> &V {
self.elem.read().1
}
/// Gets a mutable reference to the value in the entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ ///
+ /// assert_eq!(map["poneyland"], 12);
+ /// if let Entry::Occupied(mut o) = map.entry("poneyland") {
+ /// *o.get_mut() += 10;
+ /// }
+ ///
+ /// assert_eq!(map["poneyland"], 22);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self) -> &mut V {
self.elem.read_mut().1
}
/// Converts the OccupiedEntry into a mutable reference to the value in the entry
- /// with a lifetime bound to the map itself
+ /// with a lifetime bound to the map itself.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ ///
+ /// assert_eq!(map["poneyland"], 12);
+ /// if let Entry::Occupied(o) = map.entry("poneyland") {
+ /// *o.into_mut() += 10;
+ /// }
+ ///
+ /// assert_eq!(map["poneyland"], 22);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_mut(self) -> &'a mut V {
self.elem.into_mut_refs().1
}
- /// Sets the value of the entry, and returns the entry's old value
+ /// Sets the value of the entry, and returns the entry's old value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ ///
+ /// if let Entry::Occupied(mut o) = map.entry("poneyland") {
+ /// assert_eq!(o.insert(15), 12);
+ /// }
+ ///
+ /// assert_eq!(map["poneyland"], 15);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn insert(&mut self, mut value: V) -> V {
let old_value = self.get_mut();
value
}
- /// Takes the value out of the entry, and returns it
+ /// Takes the value out of the entry, and returns it.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ ///
+ /// if let Entry::Occupied(o) = map.entry("poneyland") {
+ /// assert_eq!(o.remove(), 12);
+ /// }
+ ///
+ /// assert_eq!(map.contains_key("poneyland"), false);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn remove(self) -> V {
pop_internal(self.elem).1
impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
/// Gets a reference to the key that would be used when inserting a value
- /// through the VacantEntry.
+ /// through the `VacantEntry`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+ /// ```
#[stable(feature = "map_entry_keys", since = "1.10.0")]
pub fn key(&self) -> &K {
&self.key
}
/// Take ownership of the key.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(map_entry_recover_keys)]
+ ///
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ ///
+ /// if let Entry::Vacant(v) = map.entry("poneyland") {
+ /// v.into_key();
+ /// }
+ /// ```
#[unstable(feature = "map_entry_recover_keys", issue = "34285")]
pub fn into_key(self) -> K {
self.key
}
/// Sets the value of the entry with the VacantEntry's key,
- /// and returns a mutable reference to it
+ /// and returns a mutable reference to it.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ ///
+ /// if let Entry::Vacant(o) = map.entry("poneyland") {
+ /// o.insert(37);
+ /// }
+ /// assert_eq!(map["poneyland"], 37);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn insert(self, value: V) -> &'a mut V {
match self.elem {
/// A particular instance `RandomState` will create the same instances of
/// `Hasher`, but the hashers created by two different `RandomState`
/// instances are unlikely to produce the same result for the same values.
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashMap;
+/// use std::collections::hash_map::RandomState;
+///
+/// let s = RandomState::new();
+/// let mut map = HashMap::with_hasher(s);
+/// map.insert(1, 2);
+/// ```
#[derive(Clone)]
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub struct RandomState {
impl RandomState {
/// Constructs a new `RandomState` that is initialized with random keys.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::hash_map::RandomState;
+ ///
+ /// let s = RandomState::new();
+ /// ```
#[inline]
#[allow(deprecated)] // rand
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
fn len(&self) -> usize { self.inner.len() }
}
+#[stable(feature = "env_iterators", since = "1.11.0")]
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<String> {
+ self.inner.next_back().map(|s| s.into_string().unwrap())
+ }
+}
+
#[stable(feature = "env", since = "1.0.0")]
impl Iterator for ArgsOs {
type Item = OsString;
fn len(&self) -> usize { self.inner.len() }
}
+#[stable(feature = "env_iterators", since = "1.11.0")]
+impl DoubleEndedIterator for ArgsOs {
+ fn next_back(&mut self) -> Option<OsString> { self.inner.next_back() }
+}
/// Constants associated with the current target
#[stable(feature = "env", since = "1.0.0")]
pub mod consts {
/// Metadata information about a file.
///
-/// This structure is returned from the `metadata` function or method and
+/// This structure is returned from the [`metadata`] function or method and
/// represents known metadata about a file such as its permissions, size,
/// modification times, etc.
+///
+/// [`metadata`]: fn.metadata.html
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct Metadata(fs_imp::FileAttr);
/// Iterator over the entries in a directory.
///
-/// This iterator is returned from the `read_dir` function of this module and
-/// will yield instances of `io::Result<DirEntry>`. Through a `DirEntry`
+/// This iterator is returned from the [`read_dir`] function of this module and
+/// will yield instances of `io::Result<DirEntry>`. Through a [`DirEntry`]
/// information like the entry's path and possibly other metadata can be
/// learned.
///
+/// [`read_dir`]: fn.read_dir.html
+/// [`DirEntry`]: struct.DirEntry.html
+///
/// # Errors
///
-/// This `io::Result` will be an `Err` if there's some sort of intermittent
+/// This [`io::Result`] will be an `Err` if there's some sort of intermittent
/// IO error during iteration.
+///
+/// [`io::Result`]: ../io/type.Result.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct ReadDir(fs_imp::ReadDir);
-/// Entries returned by the `ReadDir` iterator.
+/// Entries returned by the [`ReadDir`] iterator.
+///
+/// [`ReadDir`]: struct.ReadDir.html
///
/// An instance of `DirEntry` represents an entry inside of a directory on the
/// filesystem. Each entry can be inspected via methods to learn about the full
/// Options and flags which can be used to configure how a file is opened.
///
-/// This builder exposes the ability to configure how a `File` is opened and
-/// what operations are permitted on the open file. The `File::open` and
-/// `File::create` methods are aliases for commonly used options using this
+/// This builder exposes the ability to configure how a [`File`] is opened and
+/// what operations are permitted on the open file. The [`File::open`] and
+/// [`File::create`] methods are aliases for commonly used options using this
/// builder.
///
-/// Generally speaking, when using `OpenOptions`, you'll first call `new()`,
-/// then chain calls to methods to set each option, then call `open()`, passing
-/// the path of the file you're trying to open. This will give you a
+/// [`File`]: struct.File.html
+/// [`File::open`]: struct.File.html#method.open
+/// [`File::create`]: struct.File.html#method.create
+///
+/// Generally speaking, when using `OpenOptions`, you'll first call [`new()`],
+/// then chain calls to methods to set each option, then call [`open()`],
+/// passing the path of the file you're trying to open. This will give you a
/// [`io::Result`][result] with a [`File`][file] inside that you can further
/// operate on.
///
+/// [`new()`]: struct.OpenOptions.html#method.new
+/// [`open()`]: struct.OpenOptions.html#method.open
/// [result]: ../io/type.Result.html
/// [file]: struct.File.html
///
/// Representation of the various permissions on a file.
///
-/// This module only currently provides one bit of information, `readonly`,
+/// This module only currently provides one bit of information, [`readonly`],
/// which is exposed on all currently supported platforms. Unix-specific
/// functionality, such as mode bits, is available through the
/// `os::unix::PermissionsExt` trait.
+///
+/// [`readonly`]: struct.Permissions.html#method.readonly
#[derive(Clone, PartialEq, Eq, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Permissions(fs_imp::FilePermissions);
impl File {
/// Attempts to open a file in read-only mode.
///
- /// See the `OpenOptions::open` method for more details.
+ /// See the [`OpenOptions::open`] method for more details.
///
/// # Errors
///
/// This function will return an error if `path` does not already exist.
- /// Other errors may also be returned according to `OpenOptions::open`.
+ /// Other errors may also be returned according to [`OpenOptions::open`].
+ ///
+ /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
///
/// # Examples
///
/// This function will create a file if it does not exist,
/// and will truncate it if it does.
///
- /// See the `OpenOptions::open` function for more details.
+ /// See the [`OpenOptions::open`] function for more details.
+ ///
+ /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
///
/// # Examples
///
self.inner.fsync()
}
- /// This function is similar to `sync_all`, except that it may not
+ /// This function is similar to [`sync_all`], except that it may not
/// synchronize file metadata to the filesystem.
///
/// This is intended for use cases that must synchronize content, but don't
/// operations.
///
/// Note that some platforms may simply implement this in terms of
- /// `sync_all`.
+ /// [`sync_all`].
+ ///
+ /// [`sync_all`]: struct.File.html#method.sync_all
///
/// # Examples
///
/// The returned `File` is a reference to the same state that this object
/// references. Both handles will read and write with the same cursor
/// position.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::open("foo.txt"));
+ /// let file_copy = try!(f.try_clone());
+ /// # Ok(())
+ /// # }
+ /// ```
#[stable(feature = "file_try_clone", since = "1.9.0")]
pub fn try_clone(&self) -> io::Result<File> {
Ok(File {
/// On Windows this function is cheap to call (no extra system calls
/// needed), but on Unix platforms this function is the equivalent of
/// calling `symlink_metadata` on the path.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ ///
+ /// if let Ok(entries) = fs::read_dir(".") {
+ /// for entry in entries {
+ /// if let Ok(entry) = entry {
+ /// // Here, `entry` is a `DirEntry`.
+ /// if let Ok(metadata) = entry.metadata() {
+ /// // Now let's show our entry's permissions!
+ /// println!("{:?}: {:?}", entry.path(), metadata.permissions());
+ /// } else {
+ /// println!("Couldn't get metadata for {:?}", entry.path());
+ /// }
+ /// }
+ /// }
+ /// }
+ /// ```
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
pub fn metadata(&self) -> io::Result<Metadata> {
self.0.metadata().map(Metadata)
/// On Windows and most Unix platforms this function is free (no extra
/// system calls needed), but some Unix platforms may require the equivalent
/// call to `symlink_metadata` to learn about the target file type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ ///
+ /// if let Ok(entries) = fs::read_dir(".") {
+ /// for entry in entries {
+ /// if let Ok(entry) = entry {
+ /// // Here, `entry` is a `DirEntry`.
+ /// if let Ok(file_type) = entry.file_type() {
+ /// // Now let's show our entry's file type!
+ /// println!("{:?}: {:?}", entry.path(), file_type);
+ /// } else {
+ /// println!("Couldn't get file type for {:?}", entry.path());
+ /// }
+ /// }
+ /// }
+ /// }
+ /// ```
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
pub fn file_type(&self) -> io::Result<FileType> {
self.0.file_type().map(FileType)
/// Returns the bare file name of this directory entry without any other
/// leading path component.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ ///
+ /// if let Ok(entries) = fs::read_dir(".") {
+ /// for entry in entries {
+ /// if let Ok(entry) = entry {
+ /// // Here, `entry` is a `DirEntry`.
+ /// println!("{:?}", entry.file_name());
+ /// }
+ /// }
+ /// }
+ /// ```
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
pub fn file_name(&self) -> OsString {
self.0.file_name()
impl DirBuilder {
/// Creates a new set of options with default mode/security settings for all
/// platforms and also non-recursive.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::DirBuilder;
+ ///
+ /// let builder = DirBuilder::new();
+ /// ```
#[stable(feature = "dir_builder", since = "1.6.0")]
pub fn new() -> DirBuilder {
DirBuilder {
/// all parent directories if they do not exist with the same security and
/// permissions settings.
///
- /// This option defaults to `false`
+ /// This option defaults to `false`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::DirBuilder;
+ ///
+ /// let mut builder = DirBuilder::new();
+ /// builder.recursive(true);
+ /// ```
#[stable(feature = "dir_builder", since = "1.6.0")]
pub fn recursive(&mut self, recursive: bool) -> &mut Self {
self.recursive = recursive;
pub trait DirEntryExt {
/// Returns the underlying `d_ino` field in the contained `dirent`
/// structure.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::unix::fs::DirEntryExt;
+ ///
+ /// if let Ok(entries) = fs::read_dir(".") {
+ /// for entry in entries {
+ /// if let Ok(entry) = entry {
+ /// // Here, `entry` is a `DirEntry`.
+ /// println!("{:?}: {}", entry.file_name(), entry.ino());
+ /// }
+ /// }
+ /// }
+ /// ```
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
fn ino(&self) -> u64;
}
pub trait DirBuilderExt {
/// Sets the mode to create new directories with. This option defaults to
/// 0o777.
+ ///
+ /// # Examples
+ ///
+ /// ```ignore
+ /// use std::fs::DirBuilder;
+ /// use std::os::unix::fs::DirBuilderExt;
+ ///
+ /// let mut builder = DirBuilder::new();
+ /// builder.mode(0o755);
+ /// ```
#[stable(feature = "dir_builder", since = "1.6.0")]
fn mode(&mut self, mode: u32) -> &mut Self;
}
// this option, however, was added in 2.6.27, and we still support
// 2.6.18 as a kernel, so if the returned error is EINVAL we
// fallthrough to the fallback.
- if cfg!(linux) {
+ if cfg!(target_os = "linux") {
match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) {
Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
let mut fds = [0, 0];
// Like above, see if we can set cloexec atomically
- if cfg!(linux) {
+ if cfg!(target_os = "linux") {
match cvt(libc::socketpair(fam, ty | SOCK_CLOEXEC, 0, fds.as_mut_ptr())) {
Ok(_) => {
return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))));
fn len(&self) -> usize { self.iter.len() }
}
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
+}
+
/// Returns the command line arguments
///
/// Returns a list of the command line arguments.
cur: *mut *mut u16,
}
+unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString {
+ let mut len = 0;
+ while *ptr.offset(len) != 0 { len += 1; }
+
+ // Push it onto the list.
+ let ptr = ptr as *const u16;
+ let buf = slice::from_raw_parts(ptr, len as usize);
+ OsStringExt::from_wide(buf)
+}
+
impl Iterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<OsString> {
- self.range.next().map(|i| unsafe {
- let ptr = *self.cur.offset(i);
- let mut len = 0;
- while *ptr.offset(len) != 0 { len += 1; }
-
- // Push it onto the list.
- let ptr = ptr as *const u16;
- let buf = slice::from_raw_parts(ptr, len as usize);
- OsStringExt::from_wide(buf)
- })
+ self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
}
fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
}
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> {
+ self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
+ }
+}
+
impl ExactSizeIterator for Args {
fn len(&self) -> usize { self.range.len() }
}
};
let err_count = sess.span_diagnostic.err_count();
- let krate_attrs = strip_unconfigured.process_cfg_attrs(krate.attrs.clone());
+ let krate_attrs = strip_unconfigured.configure(krate.attrs.clone()).unwrap_or_default();
features = get_features(&sess.span_diagnostic, &krate_attrs);
if err_count < sess.span_diagnostic.err_count() {
krate.attrs = krate_attrs.clone(); // Avoid reconfiguring malformed `cfg_attr`s
use errors::{Handler, DiagnosticBuilder};
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
use parse::token::{DocComment, MatchNt, SubstNt};
-use parse::token::{Token, NtIdent, SpecialMacroVar};
+use parse::token::{Token, Interpolated, NtIdent, NtTT, SpecialMacroVar};
use parse::token;
use parse::lexer::TokenAndSpan;
use tokenstream::{self, TokenTree};
}
// FIXME #2887: think about span stuff here
TokenTree::Token(sp, SubstNt(ident)) => {
- r.stack.last_mut().unwrap().idx += 1;
match lookup_cur_matched(r, ident) {
None => {
+ r.stack.last_mut().unwrap().idx += 1;
r.cur_span = sp;
r.cur_tok = SubstNt(ident);
return ret_val;
// (a) idents can be in lots of places, so it'd be a pain
// (b) we actually can, since it's a token.
MatchedNonterminal(NtIdent(ref sn)) => {
+ r.stack.last_mut().unwrap().idx += 1;
r.cur_span = sn.span;
r.cur_tok = token::Ident(sn.node);
return ret_val;
}
+ MatchedNonterminal(NtTT(ref tt)) => {
+ r.stack.push(TtFrame {
+ forest: TokenTree::Token(sp, Interpolated(NtTT(tt.clone()))),
+ idx: 0,
+ dotdotdoted: false,
+ sep: None,
+ });
+ }
MatchedNonterminal(ref other_whole_nt) => {
+ r.stack.last_mut().unwrap().idx += 1;
// FIXME(pcwalton): Bad copy.
r.cur_span = sp;
- r.cur_tok = token::Interpolated((*other_whole_nt).clone());
+ r.cur_tok = Interpolated((*other_whole_nt).clone());
return ret_val;
}
MatchedSeq(..) => {
pub tokens_consumed: usize,
pub restrictions: Restrictions,
pub quote_depth: usize, // not (yet) related to the quasiquoter
+ parsing_token_tree: bool,
pub reader: Box<Reader+'a>,
/// The set of seen errors about obsolete syntax. Used to suppress
/// extra detail when the same error is seen twice
tokens_consumed: 0,
restrictions: Restrictions::empty(),
quote_depth: 0,
+ parsing_token_tree: false,
obsolete_set: HashSet::new(),
mod_path_stack: Vec::new(),
filename: filename,
}
pub fn check_unknown_macro_variable(&mut self) {
- if self.quote_depth == 0 {
+ if self.quote_depth == 0 && !self.parsing_token_tree {
match self.token {
token::SubstNt(name) =>
self.fatal(&format!("unknown macro variable `{}`", name)).emit(),
Err(err)
},
token::OpenDelim(delim) => {
+ let parsing_token_tree = ::std::mem::replace(&mut self.parsing_token_tree, true);
// The span for beginning of the delimited section
let pre_span = self.span;
_ => {}
}
+ self.parsing_token_tree = parsing_token_tree;
Ok(TokenTree::Delimited(span, Rc::new(Delimited {
delim: delim,
open_span: open_span,
}
TokenTree::Token(_, token::SpecialVarNt(..)) => 2,
TokenTree::Token(_, token::MatchNt(..)) => 3,
+ TokenTree::Token(_, token::Interpolated(Nonterminal::NtTT(..))) => 1,
TokenTree::Delimited(_, ref delimed) => delimed.tts.len() + 2,
TokenTree::Sequence(_, ref seq) => seq.tts.len(),
TokenTree::Token(..) => 0,
TokenTree::Token(sp, token::Ident(kind))];
v[index].clone()
}
+ (&TokenTree::Token(_, token::Interpolated(Nonterminal::NtTT(ref tt))), _) => {
+ tt.clone().unwrap()
+ }
(&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(),
_ => panic!("Cannot expand a token tree"),
}
}
}
- pub fn from_span(primary_span: Span) -> MultiSpan {
- MultiSpan {
- primary_spans: vec![primary_span],
- span_labels: vec![]
- }
- }
-
- pub fn from_spans(vec: Vec<Span>) -> MultiSpan {
- MultiSpan {
- primary_spans: vec,
- span_labels: vec![]
- }
- }
-
pub fn push_span_label(&mut self, span: Span, label: String) {
self.span_labels.push((span, label));
}
impl From<Span> for MultiSpan {
fn from(span: Span) -> MultiSpan {
- MultiSpan::from_span(span)
+ MultiSpan {
+ primary_spans: vec![span],
+ span_labels: vec![]
+ }
}
}
pub type _Unwind_Exception_Class = u64;
pub type _Unwind_Word = libc::uintptr_t;
+pub type _Unwind_Ptr = libc::uintptr_t;
pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut libc::c_void)
-> _Unwind_Reason_Code;
ip_before_insn: *mut libc::c_int)
-> libc::uintptr_t;
+ pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+ pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+ pub fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+ pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+ pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: libc::c_int, value: _Unwind_Ptr);
+ pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Ptr);
+
#[cfg(all(not(target_os = "android"),
not(all(target_os = "linux", target_arch = "arm"))))]
pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) -> *mut libc::c_void;
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_const_math 0.0.0",
+ "rustc_errors 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
const A: &'static [i32] = &[];
const B: i32 = (&A)[1];
-//~^ ERROR index out of bounds: the len is 0 but the index is 1
+//~^ ERROR constant evaluation error
+//~| index out of bounds: the len is 0 but the index is 1
fn main() {
let _ = B;
const A: [i32; 0] = [];
const B: i32 = A[1];
-//~^ ERROR index out of bounds: the len is 0 but the index is 1
+//~^ ERROR constant evaluation error
+//~| index out of bounds: the len is 0 but the index is 1
fn main() {
let _ = B;
const ID: usize;
}
-const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0250
+const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0080
fn main() {
assert_eq!(1, X);
impl Foo for SignedBar {
const BAR: i32 = -1;
- //~^ ERROR implemented const `BAR` has an incompatible type for trait
- //~| expected u32,
- //~| found i32 [E0326]
+ //~^ ERROR implemented const `BAR` has an incompatible type for trait [E0326]
+ //~| expected u32, found i32
}
fn main() {}
}
pub fn test<A: Foo, B: Foo>() {
- let _array = [4; <A as Foo>::Y]; //~ error: expected constant integer
+ let _array = [4; <A as Foo>::Y]; //~ ERROR E0080
+ //~| non-constant path in constant
}
fn main() {
let a = 42;
foo1(a);
//~^ ERROR type mismatch resolving
- //~| expected usize
- //~| found struct `Bar`
+ //~| expected usize, found struct `Bar`
baz(&a);
//~^ ERROR type mismatch resolving
- //~| expected usize
- //~| found struct `Bar`
+ //~| expected usize, found struct `Bar`
}
--- /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(rustc_attrs)]
+
+// revisions: good bad
+
+trait Mirror {
+ type Image;
+}
+
+impl<T> Mirror for T {
+ type Image = T;
+}
+
+#[cfg(bad)]
+fn foo<U, T>(_t: T)
+ where for<'a> &'a T: Mirror<Image=U>
+{}
+
+#[cfg(good)]
+fn foo<U, T>(_t: T)
+ where for<'a> &'a T: Mirror<Image=&'a U>
+{}
+
+#[rustc_error]
+fn main() { //[good]~ ERROR compilation successful
+ foo(());
+ //[bad]~^ ERROR type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
+ //[bad]~| expected bound lifetime parameter 'a, found concrete lifetime
+}
const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval
const BLUB: [u32; FOO[4]] = [5, 6];
-//~^ ERROR array length constant evaluation error: index out of bounds: the len is 3 but the index is 4 [E0250]
+//~^ ERROR constant evaluation error [E0080]
+//~| index out of bounds: the len is 3 but the index is 4
fn main() {
let _ = BAR;
}
fn main() {
- let _ = [0; f(2)]; //~ ERROR: non-constant path in constant expression [E0307]
+ let _ = [0; f(2)]; //~ ERROR constant evaluation error [E0080]
+ //~| non-constant path in constant expression
}
// Make sure that the two uses get two errors.
const FOO: u8 = [5u8][1];
-//~^ ERROR index out of bounds: the len is 1 but the index is 1
-//~^^ ERROR index out of bounds: the len is 1 but the index is 1
+//~^ ERROR constant evaluation error
+//~| index out of bounds: the len is 1 but the index is 1
+//~^^^ ERROR constant evaluation error
+//~| index out of bounds: the len is 1 but the index is 1
fn main() {
let a = -std::i8::MIN;
- //~^ WARN attempted to negate with overflow
+ //~^ WARN this expression will panic at run-time
+ //~| attempted to negate with overflow
let b = 200u8 + 200u8 + 200u8;
- //~^ WARN attempted to add with overflow
- //~| WARN attempted to add with overflow
+ //~^ WARN this expression will panic at run-time
+ //~| attempted to add with overflow
+ //~^^^ WARN this expression will panic at run-time
+ //~| attempted to add with overflow
let c = 200u8 * 4;
- //~^ WARN attempted to multiply with overflow
+ //~^ WARN this expression will panic at run-time
+ //~| attempted to multiply with overflow
let d = 42u8 - (42u8 + 1);
- //~^ WARN attempted to subtract with overflow
+ //~^ WARN this expression will panic at run-time
+ //~| attempted to subtract with overflow
let _e = [5u8][1];
- //~^ WARN index out of bounds: the len is 1 but the index is 1
+ //~^ WARN this expression will panic at run-time
+ //~| index out of bounds: the len is 1 but the index is 1
black_box(a);
black_box(b);
black_box(c);
const NEG_128: i8 = -128;
const NEG_NEG_128: i8 = -NEG_128;
-//~^ ERROR constant evaluation error: attempted to negate with overflow
-//~| ERROR attempted to negate with overflow
-//~| ERROR attempted to negate with overflow
+//~^ ERROR constant evaluation error
+//~| attempted to negate with overflow
+//~| ERROR constant evaluation error
+//~| attempted to negate with overflow
+//~| ERROR constant evaluation error
+//~| attempted to negate with overflow
fn main() {
match -128i8 {
- NEG_NEG_128 => println!("A"), //~ NOTE in pattern here
+ NEG_NEG_128 => println!("A"), //~ NOTE for pattern here
_ => println!("B"),
}
}
// self-hosted and a cross-compiled setup; therefore resorting to
// error-pattern for now.
-// error-pattern: expected constant integer for repeat count, but attempted to add with overflow
+// error-pattern: attempted to add with overflow
#![allow(unused_imports)]
const A_I8_T
: [u32; (i8::MAX as i8 + 1u8) as usize]
- //~^ ERROR mismatched types:
- //~| expected `i8`,
- //~| found `u8` [E0250]
+ //~^ ERROR constant evaluation error [E0080]
+ //~| expected i8, found u8
= [0; (i8::MAX as usize) + 1];
const A_BAD_CHAR_USIZE
: [u32; 5i8 as char as usize]
- //~^ ERROR only `u8` can be cast as `char`, not `i8`
+ //~^ ERROR constant evaluation error
+ //~| only `u8` can be cast as `char`, not `i8`
= [0; 5];
fn main() {}
const VALS_I8: (i8, i8, i8, i8) =
(-i8::MIN,
- //~^ ERROR attempted to negate with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to negate with overflow
i8::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
i8::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
i8::MIN * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_I16: (i16, i16, i16, i16) =
(-i16::MIN,
- //~^ ERROR attempted to negate with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to negate with overflow
i16::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
i16::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
i16::MIN * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_I32: (i32, i32, i32, i32) =
(-i32::MIN,
- //~^ ERROR attempted to negate with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to negate with overflow
i32::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
i32::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
i32::MIN * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_I64: (i64, i64, i64, i64) =
(-i64::MIN,
- //~^ ERROR attempted to negate with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to negate with overflow
i64::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
i64::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
i64::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_U8: (u8, u8, u8, u8) =
(-(u8::MIN as i8) as u8,
u8::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
u8::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
u8::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_U16: (u16, u16, u16, u16) =
(-(u16::MIN as i16) as u16,
u16::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
u16::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
u16::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_U32: (u32, u32, u32, u32) =
(-(u32::MIN as i32) as u32,
u32::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
u32::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
u32::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_U64: (u64, u64, u64, u64) =
(-(u64::MIN as i64) as u64,
u64::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
u64::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
u64::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
fn main() {
struct S(i32);
const CONSTANT: S = S(0);
-//~^ ERROR: unimplemented constant expression: tuple struct constructors [E0080]
+//~^ ERROR E0080
+//~| unimplemented constant expression: tuple struct constructors
enum E {
V = CONSTANT,
for i in 0..x {
sum += i;
}
- sum //~ ERROR: E0250
+ sum //~ ERROR E0080
+ //~| non-constant path in constant
}
#[allow(unused_variables)]
fn main() {
- let a : [i32; f(X)];
+ let a : [i32; f(X)]; //~ NOTE for array length here
}
// except according to those terms.
const ARR: [usize; 1] = [2];
-const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR unstable
+const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR E0080
+ //~| unstable
fn main() {
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-const X: usize = 42 && 39; //~ ERROR: can't do this op on integrals
+const X: usize = 42 && 39; //~ ERROR E0080
+ //~| can't do this op on integrals
const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here
-const X1: usize = 42 || 39; //~ ERROR: can't do this op on integrals
+const X1: usize = 42 || 39; //~ ERROR E0080
+ //~| can't do this op on integrals
const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here
-const X2: usize = -42 || -39; //~ ERROR: unary negation of unsigned integer
+const X2: usize = -42 || -39; //~ ERROR E0080
+ //~| unary negation of unsigned integer
const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
-const X3: usize = -42 && -39; //~ ERROR: unary negation of unsigned integer
+const X3: usize = -42 && -39; //~ ERROR E0080
+ //~| unary negation of unsigned integer
const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
const Y: usize = 42.0 == 42.0;
-const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
+const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length
const Y1: usize = 42.0 >= 42.0;
-const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
+const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length
const Y2: usize = 42.0 <= 42.0;
-const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
+const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length
const Y3: usize = 42.0 > 42.0;
-const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
+const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length
const Y4: usize = 42.0 < 42.0;
-const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
+const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length
const Y5: usize = 42.0 != 42.0;
-const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
+const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length
fn main() {
let _ = ARR;
const ONE: usize = 1;
const TWO: usize = 2;
const LEN: usize = ONE - TWO;
-//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
+//~^ ERROR E0080
+//~| attempted to subtract with overflow
fn main() {
let a: [i8; LEN] = unimplemented!();
fn main() {
let a: [i8; ONE - TWO] = unimplemented!();
- //~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
+ //~^ ERROR constant evaluation error [E0080]
+ //~| attempted to subtract with overflow
}
use Cake::*;
const BOO: (Cake, Cake) = (Marmor, BlackForest);
-//~^ ERROR: constant evaluation error: unimplemented constant expression: enum variants [E0471]
+//~^ ERROR: constant evaluation error [E0080]
+//~| unimplemented constant expression: enum variants
const FOO: Cake = BOO.1;
const fn foo() -> Cake {
- Marmor //~ ERROR: constant evaluation error: unimplemented constant expression: enum variants
- //~^ ERROR: unimplemented constant expression: enum variants
+ Marmor
+ //~^ ERROR: constant evaluation error [E0080]
+ //~| unimplemented constant expression: enum variants
+ //~^^^ ERROR: constant evaluation error [E0080]
+ //~| unimplemented constant expression: enum variants
}
const WORKS: Cake = Marmor;
-const GOO: Cake = foo();
+const GOO: Cake = foo(); //~ NOTE for expression here
fn main() {
match BlackForest {
- FOO => println!("hi"), //~ NOTE: in pattern here
- GOO => println!("meh"), //~ NOTE: in pattern here
+ FOO => println!("hi"), //~ NOTE: for pattern here
+ GOO => println!("meh"), //~ NOTE: for pattern here
WORKS => println!("möp"),
_ => println!("bye"),
}
const FOO: &'static[u32] = &[1, 2, 3];
const BAR: u32 = FOO[5];
-//~^ ERROR index out of bounds: the len is 3 but the index is 5
+//~^ ERROR constant evaluation error [E0080]
+//~| index out of bounds: the len is 3 but the index is 5
fn main() {
let _ = BAR;
// Test spans of errors
const TUP: (usize,) = 5 << 64;
-//~^ ERROR: attempted to shift left with overflow [E0250]
+//~^ ERROR E0080
+//~| attempted to shift left with overflow
const ARR: [i32; TUP.0] = [];
fn main() {
Ok = i8::MAX - 1,
Ok2,
OhNo = 0_u8,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected i8, found u8
}
let x = A::Ok;
Ok = u8::MAX - 1,
Ok2,
OhNo = 0_i8,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected u8, found i8
}
let x = A::Ok;
Ok = i16::MAX - 1,
Ok2,
OhNo = 0_u16,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected i16, found u16
}
let x = A::Ok;
Ok = u16::MAX - 1,
Ok2,
OhNo = 0_i16,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected u16, found i16
}
let x = A::Ok;
Ok = i32::MAX - 1,
Ok2,
OhNo = 0_u32,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected i32, found u32
}
let x = A::Ok;
Ok = u32::MAX - 1,
Ok2,
OhNo = 0_i32,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected u32, found i32
}
let x = A::Ok;
Ok = i64::MAX - 1,
Ok2,
OhNo = 0_u64,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected i64, found u64
}
let x = A::Ok;
Ok = u64::MAX - 1,
Ok2,
OhNo = 0_i64,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected u64, found i64
}
let x = A::Ok;
enum Eu8 {
Au8 = 23,
Bu8 = 223,
- Cu8 = -23, //~ ERROR unary negation of unsigned integer
+ Cu8 = -23, //~ ERROR E0080
+ //~| unary negation of unsigned integer
}
#[repr(u16)]
enum Eu16 {
Au16 = 23,
Bu16 = 55555,
- Cu16 = -22333, //~ ERROR unary negation of unsigned integer
+ Cu16 = -22333, //~ ERROR E0080
+ //~| unary negation of unsigned integer
}
#[repr(u32)]
enum Eu32 {
Au32 = 23,
Bu32 = 3_000_000_000,
- Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
+ Cu32 = -2_000_000_000, //~ ERROR E0080
+ //~| unary negation of unsigned integer
}
#[repr(u64)]
enum Eu64 {
Au32 = 23,
Bu32 = 3_000_000_000,
- Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
+ Cu32 = -2_000_000_000, //~ ERROR E0080
+ //~| unary negation of unsigned integer
}
// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a
// except according to those terms.
enum test {
- div_zero = 1/0, //~ERROR constant evaluation error: attempted to divide by zero
+ div_zero = 1/0, //~ ERROR E0080
+ //~| attempted to divide by zero
rem_zero = 1%0,
-//~^ ERROR constant evaluation error: attempted to calculate the remainder with a divisor of zero
+ //~^ ERROR E0080
+ //~| attempted to calculate the remainder with a divisor of zero
}
fn main() {}
}
impl<'a,'b> Foo<'a,'b> {
- fn bar(self: Foo<'b,'a>) {}
- //~^ ERROR mismatched types
+ fn bar(
+ self
+ //~^ ERROR mismatched method receiver
//~| expected type `Foo<'a, 'b>`
//~| found type `Foo<'b, 'a>`
//~| lifetime mismatch
- //~| ERROR mismatched types
+ //~| ERROR mismatched method receiver
//~| expected type `Foo<'a, 'b>`
//~| found type `Foo<'b, 'a>`
//~| lifetime mismatch
+ : Foo<'b,'a>) {}
}
fn main() {}
fn main() {
let a = -1;
- //~^ ERROR unary negation of unsigned integer
+ //~^ ERROR E0080
+ //~| unary negation of unsigned integer
let _b : u8 = a; // for infering variable a to u8.
let _d = -1u8;
- //~^ ERROR unary negation of unsigned integer
+ //~^ ERROR E0080
+ //~| unary negation of unsigned integer
for _ in -10..10u8 {}
- //~^ ERROR unary negation of unsigned integer
+ //~^ ERROR E0080
+ //~| unary negation of unsigned integer
-S; // should not trigger the gate; issue 26840
}
fn main() {
fn f(a: [u8; u32::DOESNOTEXIST]) {}
- //~^ ERROR unresolved path in constant expression
+ //~^ ERROR constant evaluation error
+ //~| unresolved path in constant expression
}
impl Foo for Baz {
fn bar(&mut self, other: &Foo) {}
- //~^ ERROR method `bar` has an incompatible type for trait: values differ in mutability [E0053]
+ //~^ ERROR method `bar` has an incompatible type for trait
+ //~| expected type `fn(&mut Baz, &mut Foo)`
+ //~| found type `fn(&mut Baz, &Foo)`
}
fn main() {}
type Output = ();
fn call_once(self, _args: ()) {
//~^ ERROR `call_once` has an incompatible type for trait
- //~| expected "rust-call" fn,
- //~| found "Rust" fn
+ //~| expected type `extern "rust-call" fn
+ //~| found type `fn
println!("{:?}", self.x);
}
}
impl <'a> Foo<'a>{
fn bar(self: &mut Foo) {
- //~^ mismatched types
+ //~^ mismatched method receiver
//~| expected type `&mut Foo<'a>`
//~| found type `&mut Foo<'_>`
//~| lifetime mismatch
- //~| mismatched types
+ //~| mismatched method receiver
//~| expected type `&mut Foo<'a>`
//~| found type `&mut Foo<'_>`
//~| lifetime mismatch
type Item = i32;
fn next(&mut self) -> Result<i32, i32> { Ok(7) }
//~^ ERROR method `next` has an incompatible type for trait
- //~| expected enum `std::option::Option`
- //~| found enum `std::result::Result` [E0053]
+ //~| expected enum `std::option::Option`, found enum `std::result::Result`
}
fn main() {}
Pie = 0x1,
Apple = 0x2,
ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
- //~^ ERROR constant evaluation error: unresolved path in constant expression
+ //~^ ERROR constant evaluation error
+ //~| unresolved path in constant expression
}
const FOO: [u32; u8::MIN as usize] = [];
-//~^ ERROR array length constant evaluation error: unresolved path in constant expression
+//~^ ERROR constant evaluation error
+//~| unresolved path in constant expression
fn main() {}
pub enum SomeEnum {
B = SomeEnum::A,
- //~^ ERROR constant evaluation error: unresolved path in constant expression
+ //~^ ERROR constant evaluation error
+ //~| unresolved path in constant expression
}
fn main() {}
impl Deref for Thing {
//~^ ERROR not all trait items implemented, missing: `Target` [E0046]
fn deref(&self) -> i8 { self.0 }
- //~^ ERROR method `deref` has an incompatible type for trait
- //~| expected &-ptr
- //~| found i8 [E0053]
}
let thing = Thing(72);
}
static STUFF: [u8; S::N] = [0; S::N];
-//~^ ERROR array length constant evaluation error: unresolved path in constant expression
+//~^ ERROR constant evaluation error
+//~| unresolved path in constant expression
fn main() {}
//~| expected type `usize`
//~| found type `S`
//~| expected usize, found struct `S`
- //~| ERROR expected positive integer for repeat count, found struct
+ //~| ERROR expected usize for repeat count, found struct
}
match i {
0...index => println!("winner"),
- //~^ ERROR non-constant path in constant expression
+ //~^ ERROR constant evaluation error
+ //~| non-constant path in constant expression
_ => println!("hello"),
}
}
// Regression test for issue #28586
pub trait Foo {}
-impl Foo for [u8; usize::BYTES] {} //~ ERROR E0250
+impl Foo for [u8; usize::BYTES] {} //~ ERROR E0080
fn main() { }
--- /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.
+
+use std::vec::IntoIter;
+
+pub fn get_tok(it: &mut IntoIter<u8>) {
+ let mut found_e = false;
+
+ let temp: Vec<u8> = it.take_while(|&x| {
+ found_e = true;
+ false
+ })
+ .cloned()
+ //~^ ERROR type mismatch resolving
+ //~| expected type `u8`
+ //~| found type `&_`
+ .collect(); //~ ERROR no method named `collect`
+}
+
+fn main() {}
enum Stuff {
Bar = foo
//~^ ERROR attempt to use a non-constant value in a constant
- //~^^ ERROR constant evaluation error: non-constant path in constant expression
+ //~^^ ERROR constant evaluation error
+ //~| non-constant path in constant expression
}
println!("{}", Stuff::Bar);
enum Foo {
A = 1i64,
- //~^ ERROR mismatched types:
- //~| expected `isize`,
- //~| found `i64` [E0080]
+ //~^ ERROR constant evaluation error
+ //~| expected isize, found i64
B = 2u8
- //~^ ERROR mismatched types:
- //~| expected `isize`,
- //~| found `u8` [E0080]
+ //~^ ERROR constant evaluation error
+ //~| expected isize, found u8
}
fn main() {}
impl<'a> Baz<'a> {
fn baz2<'b>(&self, x: &isize) -> (&'b isize, &'b isize) {
- //~^ HELP consider using an explicit lifetime parameter as shown: fn baz2<'b>(&self, x: &'a isize) -> (&'a isize, &'a isize)
+ //~^ HELP consider using an explicit lifetime parameter as shown: fn baz2<'b>(&self, x: &'
+ // FIXME #35038: The above suggestion is different on Linux and Mac.
(self.bar, x) //~ ERROR E0312
//~^ ERROR E0312
}
--- /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(rustc_attrs)]
+
+macro_rules! foo {
+ ($x:tt) => (type Alias = $x<i32>;)
+}
+
+foo!(Box);
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
'c' ... 100 => { }
_ => { }
};
- //~^^^ ERROR mismatched types in range
- //~| expected char, found integral variable
+ //~^^^ ERROR mismatched types
+ //~| expected type `_`
+ //~| found type `char`
}
fn main() {
[State::ST_NULL; (State::ST_WHITESPACE as usize)];
- //~^ ERROR expected constant integer for repeat count, but unimplemented constant expression
+ //~^ ERROR constant evaluation error
+ //~| unimplemented constant expression: enum variants
}
fn main() {
fn bar(n: usize) {
let _x = [0; n];
- //~^ ERROR expected constant integer for repeat count, found variable
+ //~^ ERROR constant evaluation error
+ //~| non-constant path in constant expression
+ //~| NOTE `n` is a variable
}
}
let x = 0;
match 1 {
0 ... x => {}
- //~^ ERROR non-constant path in constant expression
+ //~^ ERROR constant evaluation error
+ //~| non-constant path in constant expression
};
}
fn main() {
let n = 1;
let a = [0; n];
- //~^ ERROR expected constant integer for repeat count, found variable [E0307]
+ //~^ ERROR constant evaluation error
+ //~| non-constant path in constant expression
let b = [0; ()];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `()`
//~| expected usize, found ()
- //~| ERROR expected positive integer for repeat count, found tuple [E0306]
+ //~| ERROR expected usize for repeat count, found tuple [E0306]
let c = [0; true];
//~^ ERROR mismatched types
//~| expected usize, found bool
- //~| ERROR expected positive integer for repeat count, found boolean [E0306]
+ //~| ERROR expected usize for repeat count, found boolean [E0306]
let d = [0; 0.5];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `_`
//~| expected usize, found floating-point variable
- //~| ERROR expected positive integer for repeat count, found float [E0306]
+ //~| ERROR expected usize for repeat count, found float [E0306]
let e = [0; "foo"];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `&'static str`
//~| expected usize, found &-ptr
- //~| ERROR expected positive integer for repeat count, found string literal [E0306]
+ //~| ERROR expected usize for repeat count, found string literal [E0306]
let f = [0; -4_isize];
- //~^ ERROR mismatched types
- //~| expected `usize`
- //~| found `isize`
- //~| ERROR mismatched types:
+ //~^ ERROR constant evaluation error
+ //~| expected usize, found isize
+ //~| ERROR mismatched types
//~| expected usize, found isize
let f = [0_usize; -1_isize];
- //~^ ERROR mismatched types
- //~| expected `usize`
- //~| found `isize`
+ //~^ ERROR constant evaluation error
+ //~| expected usize, found isize
//~| ERROR mismatched types
//~| expected usize, found isize
struct G {
//~| expected type `usize`
//~| found type `main::G`
//~| expected usize, found struct `main::G`
- //~| ERROR expected positive integer for repeat count, found struct [E0306]
+ //~| ERROR expected usize for repeat count, found struct [E0306]
}
// Cannot have a larger effect than the trait:
unsafe fn jumbo(&self, x: &usize) { *self + *x; }
//~^ ERROR method `jumbo` has an incompatible type for trait
- //~| expected normal fn,
- //~| found unsafe fn
+ //~| expected type `fn
+ //~| found type `unsafe fn
}
fn main() {}
impl<'a, T> SomeTrait for &'a Bar<T> {
fn dummy1(self: &&'a Bar<T>) { }
- fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched types
- //~^ ERROR mismatched types
+ fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched method receiver
+ //~^ ERROR mismatched method receiver
fn dummy3(self: &&Bar<T>) {}
- //~^ ERROR mismatched types
+ //~^ ERROR mismatched method receiver
//~| expected type `&&'a Bar<T>`
//~| found type `&&Bar<T>`
//~| lifetime mismatch
- //~| ERROR mismatched types
+ //~| ERROR mismatched method receiver
//~| expected type `&&'a Bar<T>`
//~| found type `&&Bar<T>`
//~| lifetime mismatch
--- /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.
+
+// Check that unresolved imports do not create additional errors and ICEs
+
+mod m {
+ pub use unresolved; //~ ERROR unresolved import `unresolved`
+
+ fn f() {
+ let unresolved = 0; // OK
+ }
+}
+
+fn main() {
+ match 0u8 {
+ m::unresolved => {} // OK
+ m::unresolved(..) => {} // OK
+ m::unresolved{..} => {} // OK
+ }
+}
impl Foo for u32 {
fn len(&self) -> u32 { *self }
//~^ ERROR method `len` has an incompatible type for trait
- //~| expected unsafe fn,
- //~| found normal fn
+ //~| expected type `unsafe fn(&u32) -> u32`
+ //~| found type `fn(&u32) -> u32`
}
fn main() { }
+++ /dev/null
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-android: FIXME(#10381)
-// min-lldb-version: 310
-
-// This test case checks if function arguments already have the correct value
-// when breaking at the beginning of a function. Functions with the
-// #[no_stack_check] attribute have the same prologue as regular C functions
-// compiled with GCC or Clang and therefore are better handled by GDB. As a
-// consequence, and as opposed to regular Rust functions, we can set the
-// breakpoints via the function name (and don't have to fall back on using line
-// numbers). For LLDB this shouldn't make a difference because it can handle
-// both cases.
-
-// compile-flags:-g
-
-// === GDB TESTS ===================================================================================
-
-// gdb-command:rbreak immediate_args
-// gdb-command:rbreak binding
-// gdb-command:rbreak assignment
-// gdb-command:rbreak function_call
-// gdb-command:rbreak identifier
-// gdb-command:rbreak return_expr
-// gdb-command:rbreak arithmetic_expr
-// gdb-command:rbreak if_expr
-// gdb-command:rbreak while_expr
-// gdb-command:rbreak loop_expr
-// gdb-command:run
-
-// IMMEDIATE ARGS
-// gdb-command:print a
-// gdb-check:$1 = 1
-// gdb-command:print b
-// gdb-check:$2 = true
-// gdb-command:print c
-// gdb-check:$3 = 2.5
-// gdb-command:continue
-
-// NON IMMEDIATE ARGS
-// gdb-command:print a
-// gdb-check:$4 = {a = 3, b = 4, c = 5, d = 6, e = 7, f = 8, g = 9, h = 10}
-// gdb-command:print b
-// gdb-check:$5 = {a = 11, b = 12, c = 13, d = 14, e = 15, f = 16, g = 17, h = 18}
-// gdb-command:continue
-
-// BINDING
-// gdb-command:print a
-// gdb-check:$6 = 19
-// gdb-command:print b
-// gdb-check:$7 = 20
-// gdb-command:print c
-// gdb-check:$8 = 21.5
-// gdb-command:continue
-
-// ASSIGNMENT
-// gdb-command:print a
-// gdb-check:$9 = 22
-// gdb-command:print b
-// gdb-check:$10 = 23
-// gdb-command:print c
-// gdb-check:$11 = 24.5
-// gdb-command:continue
-
-// FUNCTION CALL
-// gdb-command:print x
-// gdb-check:$12 = 25
-// gdb-command:print y
-// gdb-check:$13 = 26
-// gdb-command:print z
-// gdb-check:$14 = 27.5
-// gdb-command:continue
-
-// EXPR
-// gdb-command:print x
-// gdb-check:$15 = 28
-// gdb-command:print y
-// gdb-check:$16 = 29
-// gdb-command:print z
-// gdb-check:$17 = 30.5
-// gdb-command:continue
-
-// RETURN EXPR
-// gdb-command:print x
-// gdb-check:$18 = 31
-// gdb-command:print y
-// gdb-check:$19 = 32
-// gdb-command:print z
-// gdb-check:$20 = 33.5
-// gdb-command:continue
-
-// ARITHMETIC EXPR
-// gdb-command:print x
-// gdb-check:$21 = 34
-// gdb-command:print y
-// gdb-check:$22 = 35
-// gdb-command:print z
-// gdb-check:$23 = 36.5
-// gdb-command:continue
-
-// IF EXPR
-// gdb-command:print x
-// gdb-check:$24 = 37
-// gdb-command:print y
-// gdb-check:$25 = 38
-// gdb-command:print z
-// gdb-check:$26 = 39.5
-// gdb-command:continue
-
-// WHILE EXPR
-// gdb-command:print x
-// gdb-check:$27 = 40
-// gdb-command:print y
-// gdb-check:$28 = 41
-// gdb-command:print z
-// gdb-check:$29 = 42
-// gdb-command:continue
-
-// LOOP EXPR
-// gdb-command:print x
-// gdb-check:$30 = 43
-// gdb-command:print y
-// gdb-check:$31 = 44
-// gdb-command:print z
-// gdb-check:$32 = 45
-// gdb-command:continue
-
-
-// === LLDB TESTS ==================================================================================
-
-// lldb-command:breakpoint set --name immediate_args
-// lldb-command:breakpoint set --name non_immediate_args
-// lldb-command:breakpoint set --name binding
-// lldb-command:breakpoint set --name assignment
-// lldb-command:breakpoint set --name function_call
-// lldb-command:breakpoint set --name identifier
-// lldb-command:breakpoint set --name return_expr
-// lldb-command:breakpoint set --name arithmetic_expr
-// lldb-command:breakpoint set --name if_expr
-// lldb-command:breakpoint set --name while_expr
-// lldb-command:breakpoint set --name loop_expr
-// lldb-command:run
-
-// IMMEDIATE ARGS
-// lldb-command:print a
-// lldb-check:[...]$0 = 1
-// lldb-command:print b
-// lldb-check:[...]$1 = true
-// lldb-command:print c
-// lldb-check:[...]$2 = 2.5
-// lldb-command:continue
-
-// NON IMMEDIATE ARGS
-// lldb-command:print a
-// lldb-check:[...]$3 = BigStruct { a: 3, b: 4, c: 5, d: 6, e: 7, f: 8, g: 9, h: 10 }
-// lldb-command:print b
-// lldb-check:[...]$4 = BigStruct { a: 11, b: 12, c: 13, d: 14, e: 15, f: 16, g: 17, h: 18 }
-// lldb-command:continue
-
-// BINDING
-// lldb-command:print a
-// lldb-check:[...]$5 = 19
-// lldb-command:print b
-// lldb-check:[...]$6 = 20
-// lldb-command:print c
-// lldb-check:[...]$7 = 21.5
-// lldb-command:continue
-
-// ASSIGNMENT
-// lldb-command:print a
-// lldb-check:[...]$8 = 22
-// lldb-command:print b
-// lldb-check:[...]$9 = 23
-// lldb-command:print c
-// lldb-check:[...]$10 = 24.5
-// lldb-command:continue
-
-// FUNCTION CALL
-// lldb-command:print x
-// lldb-check:[...]$11 = 25
-// lldb-command:print y
-// lldb-check:[...]$12 = 26
-// lldb-command:print z
-// lldb-check:[...]$13 = 27.5
-// lldb-command:continue
-
-// EXPR
-// lldb-command:print x
-// lldb-check:[...]$14 = 28
-// lldb-command:print y
-// lldb-check:[...]$15 = 29
-// lldb-command:print z
-// lldb-check:[...]$16 = 30.5
-// lldb-command:continue
-
-// RETURN EXPR
-// lldb-command:print x
-// lldb-check:[...]$17 = 31
-// lldb-command:print y
-// lldb-check:[...]$18 = 32
-// lldb-command:print z
-// lldb-check:[...]$19 = 33.5
-// lldb-command:continue
-
-// ARITHMETIC EXPR
-// lldb-command:print x
-// lldb-check:[...]$20 = 34
-// lldb-command:print y
-// lldb-check:[...]$21 = 35
-// lldb-command:print z
-// lldb-check:[...]$22 = 36.5
-// lldb-command:continue
-
-// IF EXPR
-// lldb-command:print x
-// lldb-check:[...]$23 = 37
-// lldb-command:print y
-// lldb-check:[...]$24 = 38
-// lldb-command:print z
-// lldb-check:[...]$25 = 39.5
-// lldb-command:continue
-
-// WHILE EXPR
-// lldb-command:print x
-// lldb-check:[...]$26 = 40
-// lldb-command:print y
-// lldb-check:[...]$27 = 41
-// lldb-command:print z
-// lldb-check:[...]$28 = 42
-// lldb-command:continue
-
-// LOOP EXPR
-// lldb-command:print x
-// lldb-check:[...]$29 = 43
-// lldb-command:print y
-// lldb-check:[...]$30 = 44
-// lldb-command:print z
-// lldb-check:[...]$31 = 45
-// lldb-command:continue
-
-#![allow(dead_code, unused_assignments, unused_variables)]
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-#[no_stack_check]
-fn immediate_args(a: isize, b: bool, c: f64) {
- println!("");
-}
-
-struct BigStruct {
- a: u64,
- b: u64,
- c: u64,
- d: u64,
- e: u64,
- f: u64,
- g: u64,
- h: u64
-}
-
-#[no_stack_check]
-fn non_immediate_args(a: BigStruct, b: BigStruct) {
- println!("");
-}
-
-#[no_stack_check]
-fn binding(a: i64, b: u64, c: f64) {
- let x = 0;
- println!("");
-}
-
-#[no_stack_check]
-fn assignment(mut a: u64, b: u64, c: f64) {
- a = b;
- println!("");
-}
-
-#[no_stack_check]
-fn function_call(x: u64, y: u64, z: f64) {
- println!("Hi!")
-}
-
-#[no_stack_check]
-fn identifier(x: u64, y: u64, z: f64) -> u64 {
- x
-}
-
-#[no_stack_check]
-fn return_expr(x: u64, y: u64, z: f64) -> u64 {
- return x;
-}
-
-#[no_stack_check]
-fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 {
- x + y
-}
-
-#[no_stack_check]
-fn if_expr(x: u64, y: u64, z: f64) -> u64 {
- if x + y < 1000 {
- x
- } else {
- y
- }
-}
-
-#[no_stack_check]
-fn while_expr(mut x: u64, y: u64, z: u64) -> u64 {
- while x + y < 1000 {
- x += z
- }
- return x;
-}
-
-#[no_stack_check]
-fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 {
- loop {
- x += z;
-
- if x + y > 1000 {
- return x;
- }
- }
-}
-
-fn main() {
- immediate_args(1, true, 2.5);
-
- non_immediate_args(
- BigStruct {
- a: 3,
- b: 4,
- c: 5,
- d: 6,
- e: 7,
- f: 8,
- g: 9,
- h: 10
- },
- BigStruct {
- a: 11,
- b: 12,
- c: 13,
- d: 14,
- e: 15,
- f: 16,
- g: 17,
- h: 18
- }
- );
-
- binding(19, 20, 21.5);
- assignment(22, 23, 24.5);
- function_call(25, 26, 27.5);
- identifier(28, 29, 30.5);
- return_expr(31, 32, 33.5);
- arithmetic_expr(34, 35, 36.5);
- if_expr(37, 38, 39.5);
- while_expr(40, 41, 42);
- loop_expr(43, 44, 45);
-}
--- /dev/null
+-include ../tools.mk
+
+all:
+ $(RUSTC) --target x86_64_unknown-linux-musl main.rs 2>&1 | \
+ grep "error: Error loading target specification: Could not find specification for target"
--- /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.
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that coercions are propagated through match and if expressions.
+
+// pretty-expanded FIXME #23616
+
+use std::boxed::Box;
+
+pub fn main() {
+ let _: Box<[isize]> = if true { Box::new([1, 2, 3]) } else { Box::new([1]) };
+
+ let _: Box<[isize]> = match true { true => Box::new([1, 2, 3]), false => Box::new([1]) };
+
+ // Check we don't get over-keen at propagating coercions in the case of casts.
+ let x = if true { 42 } else { 42u8 } as u16;
+ let x = match true { true => 42, false => 42u8 } as u16;
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that coercions are propagated through match and if expressions.
+
+// pretty-expanded FIXME #23616
+
+#![allow(unknown_features)]
+#![feature(box_syntax)]
+
+pub fn main() {
+ let _: Box<[isize]> =
+ if true { let b: Box<_> = box [1, 2, 3]; b } else { let b: Box<_> = box [1]; b };
+
+ let _: Box<[isize]> = match true {
+ true => { let b: Box<_> = box [1, 2, 3]; b }
+ false => { let b: Box<_> = box [1]; b }
+ };
+
+ // Check we don't get over-keen at propagating coercions in the case of casts.
+ let x = if true { 42 } else { 42u8 } as u16;
+ let x = match true { true => 42, false => 42u8 } as u16;
+}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Check that coercions are propagated through match and if expressions.
-
-// pretty-expanded FIXME #23616
-
-use std::boxed::Box;
-
-pub fn main() {
- let _: Box<[isize]> = if true { Box::new([1, 2, 3]) } else { Box::new([1]) };
-
- let _: Box<[isize]> = match true { true => Box::new([1, 2, 3]), false => Box::new([1]) };
-
- // Check we don't get over-keen at propagating coercions in the case of casts.
- let x = if true { 42 } else { 42u8 } as u16;
- let x = match true { true => 42, false => 42u8 } as u16;
-}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Check that coercions are propagated through match and if expressions.
-
-// pretty-expanded FIXME #23616
-
-#![allow(unknown_features)]
-#![feature(box_syntax)]
-
-pub fn main() {
- let _: Box<[isize]> =
- if true { let b: Box<_> = box [1, 2, 3]; b } else { let b: Box<_> = box [1]; b };
-
- let _: Box<[isize]> = match true {
- true => { let b: Box<_> = box [1, 2, 3]; b }
- false => { let b: Box<_> = box [1]; b }
- };
-
- // Check we don't get over-keen at propagating coercions in the case of casts.
- let x = if true { 42 } else { 42u8 } as u16;
- let x = match true { true => 42, false => 42u8 } as u16;
-}
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// 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.
//
pub fn main() {
let _ = b"x" as &[u8];
+ let _ = b"y" as &[u8; 1];
+ let _ = b"z" as *const u8;
+ let _ = "ä" as *const str;
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::env::args;
+use std::process::Command;
+
+fn assert_reverse_iterator_for_program_arguments(program_name: &str) {
+ let args: Vec<_> = args().rev().collect();
+
+ assert!(args.len() == 4);
+ assert_eq!(args[0], "c");
+ assert_eq!(args[1], "b");
+ assert_eq!(args[2], "a");
+ assert_eq!(args[3], program_name);
+
+ println!("passed");
+}
+
+fn main() {
+ let mut args = args();
+ let me = args.next().unwrap();
+
+ if let Some(_) = args.next() {
+ assert_reverse_iterator_for_program_arguments(&me);
+ return
+ }
+
+ let output = Command::new(&me)
+ .arg("a")
+ .arg("b")
+ .arg("c")
+ .output()
+ .unwrap();
+ assert!(output.status.success());
+ assert!(output.stderr.is_empty());
+ assert_eq!(output.stdout, b"passed\n");
+}
--- /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.
+
+// compile-flags:--test
+// rustc-env:RUSTC_BOOTSTRAP_KEY=
+// ignore-pretty : (#23623) problems when ending with // comments
+
+#![cfg(any())] // This test should be configured away
+#![feature(rustc_attrs)] // Test that this is allowed on stable/beta
+#![feature(iter_arith_traits)] // Test that this is not unused
+#![deny(unused_features)]
+
+#[test]
+fn dummy() {
+ let () = "this should not reach type-checking";
+}
});
}
+macro_rules! outer {
+ ($x:expr; $fragment:ident) => {
+ macro_rules! inner { ($y:$fragment) => { $x + $y } }
+ }
+}
+
fn main() {
let val = higher_order!(subst ($x:expr, $y:expr, $foo:expr) => (($x + $y, $foo)));
assert_eq!(val, (3, "foo"));
+
+ outer!(2; expr);
+ assert_eq!(inner!(3), 5);
}
--- /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"]
+
+pub trait Bar {}
+
+// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T) where T: Bar;'
+pub struct Foo<T>(pub T) where T: Bar;
pub trait MyTrait { fn dummy(&self) { } }
-// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A> where A: MyTrait"
+// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait"
pub struct Alpha<A>(A) where A: MyTrait;
// @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B> where B: MyTrait"
pub trait Bravo<B> where B: MyTrait { fn get(&self, B: B); }