diff options
116 files changed, 1820 insertions, 1302 deletions
diff --git a/src/doc/book/syntax-index.md b/src/doc/book/syntax-index.md index 3e889f51f54..0259db221b6 100644 --- a/src/doc/book/syntax-index.md +++ b/src/doc/book/syntax-index.md @@ -94,7 +94,7 @@ * `|` (`|…| 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 @@ -231,6 +231,7 @@ [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 diff --git a/src/doc/book/trait-objects.md b/src/doc/book/trait-objects.md index b31a34a0425..b1aee579aab 100644 --- a/src/doc/book/trait-objects.md +++ b/src/doc/book/trait-objects.md @@ -123,7 +123,6 @@ dispatch with trait objects by casting: # 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(); } @@ -140,7 +139,6 @@ or by coercing: # 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(); } diff --git a/src/doc/nomicon/phantom-data.md b/src/doc/nomicon/phantom-data.md index d565532017a..189695716de 100644 --- a/src/doc/nomicon/phantom-data.md +++ b/src/doc/nomicon/phantom-data.md @@ -50,7 +50,7 @@ struct Vec<T> { } ``` -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! @@ -84,4 +84,3 @@ standard library made a utility for itself called `Unique<T>` which: * includes a `PhantomData<T>` * auto-derives Send/Sync as if T was contained * marks the pointer as NonZero for the null-pointer optimization - diff --git a/src/doc/reference.md b/src/doc/reference.md index b8509321e3d..a461023642a 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1653,14 +1653,43 @@ the Rust ABI and the foreign ABI. 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. diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index e762e4d8ce9..64b780413f8 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -21,6 +21,10 @@ //! //! 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; @@ -97,7 +101,8 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// 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; /// diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 1f8eea56fc6..ccef6c02f9d 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -691,15 +691,40 @@ impl<T> [T] { /// /// # 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] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 967baccd274..275f38b2f78 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -73,6 +73,7 @@ use core::mem; use core::ops::{Index, IndexMut}; use core::ops; use core::ptr; +use core::ptr::Shared; use core::slice; use super::SpecExtend; @@ -899,8 +900,8 @@ impl<T> Vec<T> { 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 _), } } } @@ -1806,8 +1807,8 @@ pub struct Drain<'a, T: 'a> { /// 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")] @@ -1845,7 +1846,7 @@ impl<'a, T> Drop for Drain<'a, T> { 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; diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 9e4428ec57d..9c3792afa2f 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -402,6 +402,8 @@ impl<T> VecDeque<T> { /// Retrieves an element in the `VecDeque` by index. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -425,6 +427,8 @@ impl<T> VecDeque<T> { /// Retrieves an element in the `VecDeque` mutably by index. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -456,6 +460,8 @@ impl<T> VecDeque<T> { /// /// Fails if there is no element with either index. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -1180,6 +1186,8 @@ impl<T> VecDeque<T> { /// /// Returns `None` if `index` is out of bounds. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -1214,6 +1222,8 @@ impl<T> VecDeque<T> { /// /// Returns `None` if `index` is out of bounds. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -1245,6 +1255,8 @@ impl<T> VecDeque<T> { /// 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 @@ -1472,6 +1484,8 @@ impl<T> VecDeque<T> { /// 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 /// /// ``` @@ -1651,6 +1665,8 @@ impl<T> VecDeque<T> { /// /// Note that the capacity of `self` does not change. /// + /// Element at index 0 is the front of the queue. + /// /// # Panics /// /// Panics if `at > len` diff --git a/src/libcollectionstest/binary_heap.rs b/src/libcollectionstest/binary_heap.rs index be933abe41f..e2a57bd8d38 100644 --- a/src/libcollectionstest/binary_heap.rs +++ b/src/libcollectionstest/binary_heap.rs @@ -9,6 +9,7 @@ // except according to those terms. use std::collections::BinaryHeap; +use std::collections::binary_heap::Drain; #[test] fn test_iterator() { @@ -292,3 +293,8 @@ fn test_extend_specialization() { 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 } +} diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index cb99659cc0e..7a6bd958a5f 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -11,6 +11,7 @@ use std::borrow::Cow; use std::iter::{FromIterator, repeat}; use std::mem::size_of; +use std::vec::Drain; use test::Bencher; @@ -510,6 +511,11 @@ fn test_cow_from() { } } +#[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(|| { diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1bdcc5bfe11..c645608dda7 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -277,17 +277,200 @@ extern "rust-intrinsic" { /// 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; diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 896d1c6f30b..292d72dd362 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -386,10 +386,11 @@ pub trait Extend<A> { /// ``` #[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 /// diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs index 32fdf5c2048..1e9e9e30f5c 100644 --- a/src/libpanic_unwind/dwarf/eh.rs +++ b/src/libpanic_unwind/dwarf/eh.rs @@ -108,10 +108,9 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction { } } } - // If ip is not present in the table, call terminate. This is for - // a destructor inside a cleanup, or a library routine the compiler - // was not expecting to throw - EHAction::Terminate + // 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: diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 96ecad629f5..511cc32d2e1 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -83,7 +83,7 @@ use hir::def_id::DefId; 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; @@ -462,52 +462,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - 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, @@ -550,42 +504,102 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + 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, @@ -1608,59 +1622,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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) => { @@ -1803,32 +1779,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -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> { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 2ea2978b294..87882c5528e 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -32,7 +32,7 @@ use ty::adjustment; 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}; @@ -196,12 +196,6 @@ pub enum TypeOrigin { // 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), @@ -219,16 +213,26 @@ pub enum TypeOrigin { // `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", @@ -238,13 +242,31 @@ impl TypeOrigin { &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", + } } } @@ -1468,104 +1490,50 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // 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, @@ -1833,14 +1801,16 @@ impl TypeOrigin { 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, } } } @@ -1891,3 +1861,50 @@ impl RegionVariableOrigin { } } } + +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) + } +} diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index fa9bc7c8368..5901c42b525 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -126,20 +126,14 @@ impl Session { 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) @@ -178,16 +172,10 @@ impl Session { } } 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) @@ -343,67 +331,6 @@ impl Session { } } -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>, diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 3b9ecb88258..67ad887530e 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -26,8 +26,9 @@ use super::{ 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}; @@ -107,24 +108,63 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 1e2920ca87e..16a54c20925 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -1018,3 +1018,16 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeScheme<'tcx> { 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) + } +} diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 2163a8a1689..99bc2684802 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -70,20 +70,18 @@ macro_rules! supported_targets { /// 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 + } } ) } diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 01872bbe3c0..8967672548b 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -14,6 +14,7 @@ serialize = { path = "../libserialize" } 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 diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 0de00d9d7f6..915a0cf0bdc 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal; 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}; @@ -42,6 +43,7 @@ use syntax_pos::{Span, DUMMY_SP}; 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 { @@ -279,13 +281,7 @@ fn check_for_static_nan(cx: &MatchCheckCtxt, 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(); } } } @@ -838,22 +834,19 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us } } -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>, @@ -965,13 +958,12 @@ pub fn specialize<'a, '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, } } } @@ -979,13 +971,12 @@ pub fn specialize<'a, 'b, 'tcx>( 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, } } diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index f2abdf831a3..45414c33c07 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -551,44 +551,46 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases. See also https://github.com/rust-lang/rust/issues/14587 "##, -E0306: r##" -In an array literal `[x; N]`, `N` is the number of elements in the array. This -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) } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 4643686786b..dd21bb17a2d 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -25,6 +25,7 @@ use rustc::hir::pat_util::def_to_path; 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; @@ -43,6 +44,7 @@ use std::cmp::Ordering; 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) => { @@ -338,20 +340,71 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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 }, } } @@ -400,6 +453,7 @@ pub enum ErrKind { IntermediateUnsignedNegative, /// Expected, Got TypeMismatch(String, ConstInt), + BadType(ConstVal), ErroneousReferencedConstant(Box<ConstEvalErr>), CharCast(ConstInt), @@ -411,57 +465,79 @@ impl From<ConstMathErr> for ErrKind { } } +#[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()) }, } } @@ -1199,8 +1275,10 @@ fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>, span: Span) -> ConstFl }) } -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)), @@ -1208,62 +1286,82 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> { (&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) } } } diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 726ba4fc192..a6714c178e7 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -36,6 +36,7 @@ #[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 diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index ab3b20e08c8..9a94cc16bfe 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -478,10 +478,6 @@ pub fn phase_1_parse_input<'a>(sess: &'a Session, 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); @@ -1298,3 +1294,11 @@ pub fn build_output_filenames(input: &Input, } } } + +// 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(); +} diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 6a48f65714c..610e5647d6d 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -531,10 +531,12 @@ impl Handler { 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(); } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 27ce03b2d93..b0ba38f1db6 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -40,6 +40,7 @@ use rustc::middle::mem_categorization as mc; 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; @@ -116,7 +117,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { _ => 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| { @@ -211,15 +212,6 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { } } } - - 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> { @@ -289,18 +281,14 @@ 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) @@ -429,7 +417,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { Err(msg) => { self.tcx.sess.add_lint(CONST_ERR, ex.id, msg.span, - msg.description().into_owned()) + msg.description().into_oneline().into_owned()) } } } diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 918e17d21ea..a616b95ef72 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -11,7 +11,7 @@ #![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 @@ -30,7 +30,7 @@ const FOO: i32 = { const X : i32 = 0; X }; 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 diff --git a/src/librustc_save_analysis/csv_dumper.rs b/src/librustc_save_analysis/csv_dumper.rs index e7cc534c5b5..0fd95500422 100644 --- a/src/librustc_save_analysis/csv_dumper.rs +++ b/src/librustc_save_analysis/csv_dumper.rs @@ -427,7 +427,7 @@ fn make_values_str(pairs: &[(&'static str, &str)]) -> String { } 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) diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index 08e894ffbcf..f7fd970f37f 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -190,7 +190,7 @@ use self::FailureHandler::*; 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; @@ -239,9 +239,9 @@ struct ConstantExpr<'a>(&'a hir::Expr); 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"), } } } @@ -288,7 +288,9 @@ impl<'a, 'b, 'tcx> Opt<'a, 'tcx> { 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)); @@ -297,11 +299,11 @@ impl<'a, 'b, 'tcx> Opt<'a, 'tcx> { 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)) } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 00feb2cd1de..f662ba75cc6 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -14,7 +14,7 @@ use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr}; 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; @@ -44,7 +44,6 @@ use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; 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}; @@ -250,10 +249,11 @@ impl ConstEvalFailure { 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, } } } @@ -274,7 +274,7 @@ fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, 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, @@ -526,12 +526,15 @@ pub fn const_err<T>(cx: &CrateContext, (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)) }, } @@ -875,7 +878,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, 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 { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index f033b278fe7..e657a086581 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -44,6 +44,7 @@ use syntax::ptr::P; 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; @@ -1414,7 +1415,10 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> // 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] diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index da72793abf6..1f3b1320316 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -925,7 +925,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } Err(ConstEvalFailure::Runtime(err)) => { span_bug!(constant.span, - "MIR constant {:?} results in runtime panic: {}", + "MIR constant {:?} results in runtime panic: {:?}", constant, err.description()) } } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 8b8e658533e..fc95d208f32 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -29,6 +29,7 @@ use rustc::hir::def_id::DefId; 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}; @@ -81,7 +82,11 @@ impl<'a, 'tcx> TransItem<'tcx> { 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") diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs index f5b9bef5313..92a2d3787bf 100644 --- a/src/librustc_trans/tvec.rs +++ b/src/librustc_trans/tvec.rs @@ -30,7 +30,7 @@ use value::Value; 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; @@ -218,7 +218,7 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, 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 => { @@ -268,7 +268,7 @@ fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize { }, 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") } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9ff30f9ede2..b642a712219 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -48,10 +48,7 @@ //! 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; @@ -70,7 +67,6 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, 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}; @@ -1741,33 +1737,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { 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) => { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index e90b32cd5df..aae6e3ad36d 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -103,15 +103,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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); @@ -120,6 +111,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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); diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 2c7e7d284fa..9c6727ebbfc 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -216,7 +216,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => { 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; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 22ac8bc5690..7a4cc09a7d5 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -149,7 +149,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'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", @@ -167,35 +167,35 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { 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(); } @@ -213,7 +213,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { 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 { @@ -484,4 +484,3 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span) } } - diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 35a5bc9c609..9844377d0bd 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -12,6 +12,7 @@ use middle::free_region::FreeRegionMap; 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; @@ -324,10 +325,19 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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 } @@ -437,10 +447,9 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // 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, @@ -473,11 +482,19 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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(); } }); } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index eeebd6a7f62..1f3a83ebc1d 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -33,7 +33,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } 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 @@ -54,16 +61,4 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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 - } - } } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 5a3268e9e44..8a53c59b4c7 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -12,6 +12,7 @@ //! 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}; @@ -56,10 +57,9 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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); } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f20dcdc35ae..346449d0a51 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -160,8 +160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fc1d2236f3f..6062bd048b3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -126,7 +126,7 @@ use rustc::hir::intravisit::{self, Visitor}; 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; @@ -2541,21 +2541,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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); @@ -2564,7 +2564,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { |t| { format!("can't pass `{}` to variadic \ function, cast to `{}`", t, ptr_ty) - }, arg_ty, None); + }, arg_ty); } _ => {} } @@ -2908,9 +2908,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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); @@ -2919,7 +2918,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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![]); } @@ -3019,7 +3018,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { actual) } }, - expr_t, None); + expr_t); self.write_error(expr.id); } @@ -3029,17 +3028,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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()); @@ -3272,7 +3272,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.type_error_message(expr.span, |actual| { format!("type `{}` cannot be \ dereferenced", actual) - }, oprnd_t, None); + }, oprnd_t); oprnd_t = tcx.types.err; } } @@ -3541,7 +3541,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } 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) => { @@ -3647,8 +3648,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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; @@ -4523,7 +4523,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 8604dadf46d..d02f87d0b9c 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -239,7 +239,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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 } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index d101381e256..907cb734c2f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -13,6 +13,7 @@ use constrained_type_params::{identify_constrained_type_params, Parameter}; 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}; @@ -157,7 +158,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } - 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; @@ -182,7 +186,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { 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) => { @@ -405,20 +410,15 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { 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, @@ -431,14 +431,23 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } 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, @@ -553,13 +562,21 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { 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) } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 41e7a467fa3..57602b55cc9 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -66,8 +66,7 @@ use constrained_type_params as ctp; 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}; @@ -1091,14 +1090,9 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }, // 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 } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 8769bc1a32b..500f624ea3f 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1079,25 +1079,6 @@ impl Foo { ``` "##, -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, @@ -2660,6 +2641,7 @@ For information on the design of the orphan rules, see [RFC 1023]. [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: @@ -2739,6 +2721,7 @@ impl Foo { } ``` "##, + */ E0214: r##" A generic type was described using parentheses rather than angle brackets. For @@ -2968,38 +2951,6 @@ not a distinct static type. Likewise, it's not legal to attempt to 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 @@ -4029,6 +3980,57 @@ impl SpaceLlama for i32 { ``` "##, +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! { @@ -4086,6 +4088,7 @@ 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 diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 84452589dfd..3b2d02dc861 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -186,28 +186,14 @@ fn require_c_abi_if_variadic(tcx: TyCtxt, } } -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 @@ -249,8 +235,11 @@ fn check_main_fn_ty(ccx: &CrateCtxt, }) })); - 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, @@ -298,8 +287,11 @@ fn check_start_fn_ty(ccx: &CrateCtxt, }), })); - 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, diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index ed5ac3bc0c1..fd7b0a2e6bb 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -877,7 +877,7 @@ impl<K, V, S> HashMap<K, V, S> /// } /// /// for val in map.values() { - /// print!("{}", val); + /// println!("{}", val); /// } /// ``` #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -1336,6 +1336,10 @@ impl<'a, K, V> InternalEntry<K, V, &'a mut RawTable<K, V>> { } /// 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. @@ -1366,6 +1370,9 @@ impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for Entry<'a, K, V> { } /// 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>, @@ -1383,6 +1390,9 @@ impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { } /// 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, @@ -1551,6 +1561,20 @@ impl<'a, K, V> Entry<'a, K, V> { #[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(), @@ -1561,6 +1585,19 @@ impl<'a, K, V> Entry<'a, K, V> { #[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(), @@ -1569,6 +1606,15 @@ impl<'a, K, V> Entry<'a, K, V> { } /// 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 { @@ -1580,37 +1626,130 @@ impl<'a, K, V> Entry<'a, K, V> { 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(); @@ -1618,7 +1757,23 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { 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 @@ -1634,20 +1789,58 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { 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 { diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 95aa6468dd9..d6d62ce79d4 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -625,6 +625,13 @@ impl ExactSizeIterator for Args { 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; @@ -637,6 +644,10 @@ impl ExactSizeIterator for ArgsOs { 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 { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index c28f70b8692..48753ccf1c3 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -58,28 +58,37 @@ pub struct File { /// 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 @@ -89,17 +98,23 @@ pub struct DirEntry(fs_imp::DirEntry); /// 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 /// @@ -131,10 +146,12 @@ pub struct OpenOptions(fs_imp::OpenOptions); /// 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); @@ -156,12 +173,14 @@ pub struct DirBuilder { 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 /// @@ -183,7 +202,9 @@ impl File { /// 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 /// @@ -224,7 +245,7 @@ impl File { 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 @@ -232,7 +253,9 @@ impl File { /// 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 /// @@ -304,6 +327,18 @@ impl File { /// 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 { @@ -829,6 +864,26 @@ impl DirEntry { /// 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) @@ -844,6 +899,26 @@ impl DirEntry { /// 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) @@ -851,6 +926,21 @@ impl DirEntry { /// 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() @@ -1397,6 +1487,14 @@ pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) 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 { @@ -1409,7 +1507,16 @@ impl 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; diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index bb90a977433..54340773a42 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -196,6 +196,22 @@ impl FileTypeExt for fs::FileType { 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; } @@ -239,6 +255,16 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> 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; } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index a784741c88c..6f1b70acb60 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -67,7 +67,7 @@ impl Socket { // 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) => {} @@ -87,7 +87,7 @@ impl Socket { 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])))); diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 63e13f0bb47..4c3558f91f5 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -317,6 +317,10 @@ impl ExactSizeIterator for Args { 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. diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 32ca32e76cb..0cea7f81e36 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -278,23 +278,30 @@ pub struct Args { 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() } } diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 7c0d10669f3..29a300b172e 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -14,7 +14,7 @@ use syntax_pos::{Span, DUMMY_SP}; 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}; @@ -278,9 +278,9 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { } // 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; @@ -292,14 +292,24 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { // (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(..) => { diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 0ad09fd0f7d..d38edf81688 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -135,6 +135,7 @@ impl TokenTree { } 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, @@ -197,6 +198,9 @@ impl TokenTree { 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"), } diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 4def60e485f..0b2287cf233 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -105,6 +105,7 @@ dependencies = [ "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", diff --git a/src/test/compile-fail/array_const_index-0.rs b/src/test/compile-fail/array_const_index-0.rs index e65230389f9..501c66e75cd 100644 --- a/src/test/compile-fail/array_const_index-0.rs +++ b/src/test/compile-fail/array_const_index-0.rs @@ -10,7 +10,8 @@ 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; diff --git a/src/test/compile-fail/array_const_index-1.rs b/src/test/compile-fail/array_const_index-1.rs index 69d84e24c49..d3b43e83bfe 100644 --- a/src/test/compile-fail/array_const_index-1.rs +++ b/src/test/compile-fail/array_const_index-1.rs @@ -10,7 +10,8 @@ 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; diff --git a/src/test/compile-fail/associated-const-array-len.rs b/src/test/compile-fail/associated-const-array-len.rs index 5d8007defc9..0239986f5ad 100644 --- a/src/test/compile-fail/associated-const-array-len.rs +++ b/src/test/compile-fail/associated-const-array-len.rs @@ -14,7 +14,7 @@ trait Foo { 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); diff --git a/src/test/compile-fail/associated-const-impl-wrong-type.rs b/src/test/compile-fail/associated-const-impl-wrong-type.rs index 4658d0f057d..95508a31044 100644 --- a/src/test/compile-fail/associated-const-impl-wrong-type.rs +++ b/src/test/compile-fail/associated-const-impl-wrong-type.rs @@ -18,9 +18,8 @@ struct SignedBar; 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() {} diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs index 2f687350f34..c3fa39659b9 100644 --- a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs +++ b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs @@ -25,7 +25,8 @@ impl Foo for Def { } 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() { diff --git a/src/test/compile-fail/associated-types-eq-3.rs b/src/test/compile-fail/associated-types-eq-3.rs index 8c66160e8a3..cb952f6534f 100644 --- a/src/test/compile-fail/associated-types-eq-3.rs +++ b/src/test/compile-fail/associated-types-eq-3.rs @@ -47,10 +47,8 @@ pub 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` } diff --git a/src/test/compile-fail/associated-types/higher-ranked-projection.rs b/src/test/compile-fail/associated-types/higher-ranked-projection.rs new file mode 100644 index 00000000000..12341fa8db3 --- /dev/null +++ b/src/test/compile-fail/associated-types/higher-ranked-projection.rs @@ -0,0 +1,38 @@ +// 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 +} diff --git a/src/test/compile-fail/const-array-oob.rs b/src/test/compile-fail/const-array-oob.rs index faabed4fd5e..b980bc02c85 100644 --- a/src/test/compile-fail/const-array-oob.rs +++ b/src/test/compile-fail/const-array-oob.rs @@ -16,7 +16,8 @@ const FOO: [u32; 3] = [1, 2, 3]; 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; diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs index 1143d3bd5cd..7e2eabf412d 100644 --- a/src/test/compile-fail/const-call.rs +++ b/src/test/compile-fail/const-call.rs @@ -15,5 +15,6 @@ fn f(x: usize) -> usize { } 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 } diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs index a1d3888e78e..f2079800cad 100644 --- a/src/test/compile-fail/const-err.rs +++ b/src/test/compile-fail/const-err.rs @@ -22,21 +22,29 @@ fn black_box<T>(_: T) { // 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); diff --git a/src/test/compile-fail/const-eval-overflow-2.rs b/src/test/compile-fail/const-eval-overflow-2.rs index 07e27a7dc9a..4749457da88 100644 --- a/src/test/compile-fail/const-eval-overflow-2.rs +++ b/src/test/compile-fail/const-eval-overflow-2.rs @@ -19,13 +19,16 @@ use std::{u8, u16, u32, u64, usize}; 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"), } } diff --git a/src/test/compile-fail/const-eval-overflow-3.rs b/src/test/compile-fail/const-eval-overflow-3.rs index c90ae045f96..c78c74e9e23 100644 --- a/src/test/compile-fail/const-eval-overflow-3.rs +++ b/src/test/compile-fail/const-eval-overflow-3.rs @@ -17,7 +17,7 @@ // 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)] diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs index 31e1a72967f..9e7a5ecae10 100644 --- a/src/test/compile-fail/const-eval-overflow-4b.rs +++ b/src/test/compile-fail/const-eval-overflow-4b.rs @@ -20,9 +20,8 @@ use std::{u8, u16, u32, u64, usize}; 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]; @@ -33,7 +32,8 @@ const A_CHAR_USIZE 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() {} diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs index 3dfcb5bb29a..c1c693544fa 100644 --- a/src/test/compile-fail/const-eval-overflow.rs +++ b/src/test/compile-fail/const-eval-overflow.rs @@ -21,86 +21,114 @@ use std::{u8, u16, u32, u64, usize}; 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() { diff --git a/src/test/compile-fail/const-eval-span.rs b/src/test/compile-fail/const-eval-span.rs index 9fdd24c42fd..73351429b50 100644 --- a/src/test/compile-fail/const-eval-span.rs +++ b/src/test/compile-fail/const-eval-span.rs @@ -14,7 +14,8 @@ 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, diff --git a/src/test/compile-fail/const-fn-error.rs b/src/test/compile-fail/const-fn-error.rs index 45a00de48e7..dd0f058f2c9 100644 --- a/src/test/compile-fail/const-fn-error.rs +++ b/src/test/compile-fail/const-fn-error.rs @@ -17,10 +17,11 @@ const fn f(x: usize) -> usize { 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 } diff --git a/src/test/compile-fail/const-index-feature-gate.rs b/src/test/compile-fail/const-index-feature-gate.rs index 09822e46cc1..4f92770df28 100644 --- a/src/test/compile-fail/const-index-feature-gate.rs +++ b/src/test/compile-fail/const-index-feature-gate.rs @@ -9,7 +9,8 @@ // 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() { } diff --git a/src/test/compile-fail/const-integer-bool-ops.rs b/src/test/compile-fail/const-integer-bool-ops.rs index 0d6cf3bab45..5dadd892f83 100644 --- a/src/test/compile-fail/const-integer-bool-ops.rs +++ b/src/test/compile-fail/const-integer-bool-ops.rs @@ -8,30 +8,34 @@ // 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; diff --git a/src/test/compile-fail/const-len-underflow-separate-spans.rs b/src/test/compile-fail/const-len-underflow-separate-spans.rs index 9c6b774b990..43375ee3d18 100644 --- a/src/test/compile-fail/const-len-underflow-separate-spans.rs +++ b/src/test/compile-fail/const-len-underflow-separate-spans.rs @@ -15,7 +15,8 @@ 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!(); diff --git a/src/test/compile-fail/const-len-underflow-subspans.rs b/src/test/compile-fail/const-len-underflow-subspans.rs index d51f31087d0..e338f206553 100644 --- a/src/test/compile-fail/const-len-underflow-subspans.rs +++ b/src/test/compile-fail/const-len-underflow-subspans.rs @@ -16,5 +16,6 @@ const TWO: usize = 2; 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 } diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs index 4567cd4a74b..d68d63683a7 100644 --- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs +++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs @@ -17,22 +17,26 @@ enum Cake { 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"), } diff --git a/src/test/compile-fail/const-slice-oob.rs b/src/test/compile-fail/const-slice-oob.rs index d63b0097e5a..b1b4bfe2d1c 100644 --- a/src/test/compile-fail/const-slice-oob.rs +++ b/src/test/compile-fail/const-slice-oob.rs @@ -10,7 +10,8 @@ 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; diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs index 9d3c432d148..6f095b3041f 100644 --- a/src/test/compile-fail/const-tup-index-span.rs +++ b/src/test/compile-fail/const-tup-index-span.rs @@ -11,7 +11,8 @@ // 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() { diff --git a/src/test/compile-fail/discrim-ill-typed.rs b/src/test/compile-fail/discrim-ill-typed.rs index 23106c99594..c73b7e831b3 100644 --- a/src/test/compile-fail/discrim-ill-typed.rs +++ b/src/test/compile-fail/discrim-ill-typed.rs @@ -25,7 +25,8 @@ fn f_i8() { Ok = i8::MAX - 1, Ok2, OhNo = 0_u8, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected i8, found u8 } let x = A::Ok; @@ -37,7 +38,8 @@ fn f_u8() { Ok = u8::MAX - 1, Ok2, OhNo = 0_i8, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected u8, found i8 } let x = A::Ok; @@ -49,7 +51,8 @@ fn f_i16() { Ok = i16::MAX - 1, Ok2, OhNo = 0_u16, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected i16, found u16 } let x = A::Ok; @@ -61,7 +64,8 @@ fn f_u16() { Ok = u16::MAX - 1, Ok2, OhNo = 0_i16, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected u16, found i16 } let x = A::Ok; @@ -73,7 +77,8 @@ fn f_i32() { Ok = i32::MAX - 1, Ok2, OhNo = 0_u32, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected i32, found u32 } let x = A::Ok; @@ -85,7 +90,8 @@ fn f_u32() { Ok = u32::MAX - 1, Ok2, OhNo = 0_i32, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected u32, found i32 } let x = A::Ok; @@ -97,7 +103,8 @@ fn f_i64() { Ok = i64::MAX - 1, Ok2, OhNo = 0_u64, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected i64, found u64 } let x = A::Ok; @@ -109,7 +116,8 @@ fn f_u64() { Ok = u64::MAX - 1, Ok2, OhNo = 0_i64, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected u64, found i64 } let x = A::Ok; diff --git a/src/test/compile-fail/enum-discrim-too-small.rs b/src/test/compile-fail/enum-discrim-too-small.rs index d6ba09bb4c5..bbdb3891d99 100644 --- a/src/test/compile-fail/enum-discrim-too-small.rs +++ b/src/test/compile-fail/enum-discrim-too-small.rs @@ -13,28 +13,32 @@ 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 diff --git a/src/test/compile-fail/eval-enum.rs b/src/test/compile-fail/eval-enum.rs index 7ca274b81e5..57db583aefe 100644 --- a/src/test/compile-fail/eval-enum.rs +++ b/src/test/compile-fail/eval-enum.rs @@ -9,9 +9,11 @@ // 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() {} diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs index b5432fafb1b..f8aa1ea95f0 100644 --- a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs +++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs @@ -14,15 +14,17 @@ struct Foo<'a,'b> { } 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() {} diff --git a/src/test/compile-fail/feature-gate-negate-unsigned0.rs b/src/test/compile-fail/feature-gate-negate-unsigned0.rs index 05b194345d4..89ae1a09bd3 100644 --- a/src/test/compile-fail/feature-gate-negate-unsigned0.rs +++ b/src/test/compile-fail/feature-gate-negate-unsigned0.rs @@ -18,14 +18,17 @@ impl std::ops::Neg for S { 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 } diff --git a/src/test/compile-fail/invalid-path-in-const.rs b/src/test/compile-fail/invalid-path-in-const.rs index 3c4ad5a56ec..9a9358b787f 100644 --- a/src/test/compile-fail/invalid-path-in-const.rs +++ b/src/test/compile-fail/invalid-path-in-const.rs @@ -10,5 +10,6 @@ fn main() { fn f(a: [u8; u32::DOESNOTEXIST]) {} - //~^ ERROR unresolved path in constant expression + //~^ ERROR constant evaluation error + //~| unresolved path in constant expression } diff --git a/src/test/compile-fail/issue-13033.rs b/src/test/compile-fail/issue-13033.rs index 43cf70e5bc3..3d9d81471cb 100644 --- a/src/test/compile-fail/issue-13033.rs +++ b/src/test/compile-fail/issue-13033.rs @@ -16,7 +16,9 @@ struct Baz; 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() {} diff --git a/src/test/compile-fail/issue-15094.rs b/src/test/compile-fail/issue-15094.rs index 42e3456b309..da48bbb3ecd 100644 --- a/src/test/compile-fail/issue-15094.rs +++ b/src/test/compile-fail/issue-15094.rs @@ -20,8 +20,8 @@ impl<T: fmt::Debug> ops::FnOnce<(),> for Debuger<T> { 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); } } diff --git a/src/test/compile-fail/issue-17740.rs b/src/test/compile-fail/issue-17740.rs index 6b9294b2038..664d62e87ae 100644 --- a/src/test/compile-fail/issue-17740.rs +++ b/src/test/compile-fail/issue-17740.rs @@ -14,11 +14,11 @@ struct Foo<'a> { 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 diff --git a/src/test/compile-fail/issue-21332.rs b/src/test/compile-fail/issue-21332.rs index b36918149fa..db3334834d4 100644 --- a/src/test/compile-fail/issue-21332.rs +++ b/src/test/compile-fail/issue-21332.rs @@ -14,8 +14,7 @@ impl Iterator for S { 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() {} diff --git a/src/test/compile-fail/issue-22933-2.rs b/src/test/compile-fail/issue-22933-2.rs index 7d619c270d3..54a24089354 100644 --- a/src/test/compile-fail/issue-22933-2.rs +++ b/src/test/compile-fail/issue-22933-2.rs @@ -12,10 +12,12 @@ enum Delicious { 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() {} diff --git a/src/test/compile-fail/issue-23217.rs b/src/test/compile-fail/issue-23217.rs index 32cdd6b5ed9..c2bcbb9d54a 100644 --- a/src/test/compile-fail/issue-23217.rs +++ b/src/test/compile-fail/issue-23217.rs @@ -10,7 +10,8 @@ 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() {} diff --git a/src/test/compile-fail/issue-24356.rs b/src/test/compile-fail/issue-24356.rs index 27d46be40fb..ede81bea32a 100644 --- a/src/test/compile-fail/issue-24356.rs +++ b/src/test/compile-fail/issue-24356.rs @@ -30,9 +30,6 @@ 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); diff --git a/src/test/compile-fail/issue-25145.rs b/src/test/compile-fail/issue-25145.rs index e8a9c8d2ea3..93f75e9bfed 100644 --- a/src/test/compile-fail/issue-25145.rs +++ b/src/test/compile-fail/issue-25145.rs @@ -17,6 +17,7 @@ impl S { } 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() {} diff --git a/src/test/compile-fail/issue-27008.rs b/src/test/compile-fail/issue-27008.rs index bdcbaf09177..ee6ec527612 100644 --- a/src/test/compile-fail/issue-27008.rs +++ b/src/test/compile-fail/issue-27008.rs @@ -16,5 +16,5 @@ 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 } diff --git a/src/test/compile-fail/issue-27895.rs b/src/test/compile-fail/issue-27895.rs index 3b3abc94a49..ca8d5a1f704 100644 --- a/src/test/compile-fail/issue-27895.rs +++ b/src/test/compile-fail/issue-27895.rs @@ -14,7 +14,8 @@ fn main() { 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"), } } diff --git a/src/test/compile-fail/issue-28586.rs b/src/test/compile-fail/issue-28586.rs index c8a1e424da2..1dfd146985f 100644 --- a/src/test/compile-fail/issue-28586.rs +++ b/src/test/compile-fail/issue-28586.rs @@ -11,6 +11,6 @@ // 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() { } diff --git a/src/test/compile-fail/issue-31173.rs b/src/test/compile-fail/issue-31173.rs new file mode 100644 index 00000000000..fb1e3cc87e8 --- /dev/null +++ b/src/test/compile-fail/issue-31173.rs @@ -0,0 +1,27 @@ +// 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() {} diff --git a/src/test/compile-fail/issue-3521.rs b/src/test/compile-fail/issue-3521.rs index 52375ef281a..1b6e4b1d289 100644 --- a/src/test/compile-fail/issue-3521.rs +++ b/src/test/compile-fail/issue-3521.rs @@ -15,7 +15,8 @@ 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); diff --git a/src/test/compile-fail/issue-8761.rs b/src/test/compile-fail/issue-8761.rs index 1c98abce030..91a07dd9ba6 100644 --- a/src/test/compile-fail/issue-8761.rs +++ b/src/test/compile-fail/issue-8761.rs @@ -10,13 +10,11 @@ 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() {} diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs index e34a3c4569d..6da87fca3f3 100644 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs +++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs @@ -49,7 +49,8 @@ struct Baz<'x> { 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 } diff --git a/src/test/compile-fail/macro-tt-matchers.rs b/src/test/compile-fail/macro-tt-matchers.rs new file mode 100644 index 00000000000..f41da77ee98 --- /dev/null +++ b/src/test/compile-fail/macro-tt-matchers.rs @@ -0,0 +1,20 @@ +// 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 diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index 526aa83dec7..2c4c2563021 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -27,6 +27,7 @@ fn main() { 'c' ... 100 => { } _ => { } }; - //~^^^ ERROR mismatched types in range - //~| expected char, found integral variable + //~^^^ ERROR mismatched types + //~| expected type `_` + //~| found type `char` } diff --git a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs index 9564a080b8e..cadfec5a38d 100644 --- a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs +++ b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs @@ -15,5 +15,6 @@ enum State { ST_NULL, ST_WHITESPACE } 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 } diff --git a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs index 3ce206ff7fb..a6f88a57b91 100644 --- a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs +++ b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs @@ -13,6 +13,8 @@ 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 } } diff --git a/src/test/compile-fail/non-constant-in-const-path.rs b/src/test/compile-fail/non-constant-in-const-path.rs index ee88168515d..737f80372de 100644 --- a/src/test/compile-fail/non-constant-in-const-path.rs +++ b/src/test/compile-fail/non-constant-in-const-path.rs @@ -12,6 +12,7 @@ fn main() { let x = 0; match 1 { 0 ... x => {} - //~^ ERROR non-constant path in constant expression + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression }; } diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs index ab5af64d95c..3a7e9cc4191 100644 --- a/src/test/compile-fail/repeat_count.rs +++ b/src/test/compile-fail/repeat_count.rs @@ -13,39 +13,38 @@ 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 { @@ -56,5 +55,5 @@ fn main() { //~| 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] } diff --git a/src/test/compile-fail/trait-impl-method-mismatch.rs b/src/test/compile-fail/trait-impl-method-mismatch.rs index f86d9b7648b..a05e007d6b7 100644 --- a/src/test/compile-fail/trait-impl-method-mismatch.rs +++ b/src/test/compile-fail/trait-impl-method-mismatch.rs @@ -17,8 +17,8 @@ impl Mumbo for usize { // 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() {} diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs index f14a3505cde..a98b7cd4309 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -41,14 +41,14 @@ trait SomeTrait { 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 diff --git a/src/test/compile-fail/unsafe-trait-impl.rs b/src/test/compile-fail/unsafe-trait-impl.rs index 51f876661f6..fb4652affd0 100644 --- a/src/test/compile-fail/unsafe-trait-impl.rs +++ b/src/test/compile-fail/unsafe-trait-impl.rs @@ -17,8 +17,8 @@ trait Foo { 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() { } diff --git a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs deleted file mode 100644 index b5b6ca75727..00000000000 --- a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs +++ /dev/null @@ -1,369 +0,0 @@ -// 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); -} diff --git a/src/test/run-make/issue-33329/Makefile b/src/test/run-make/issue-33329/Makefile new file mode 100644 index 00000000000..c53f51d5bf5 --- /dev/null +++ b/src/test/run-make/issue-33329/Makefile @@ -0,0 +1,5 @@ +-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" diff --git a/src/test/run-make/issue-33329/main.rs b/src/test/run-make/issue-33329/main.rs new file mode 100644 index 00000000000..e06c0a5ec2a --- /dev/null +++ b/src/test/run-make/issue-33329/main.rs @@ -0,0 +1,11 @@ +// 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() {} diff --git a/src/test/run-pass/env-args-reverse-iterator.rs b/src/test/run-pass/env-args-reverse-iterator.rs new file mode 100644 index 00000000000..d22fa6494f0 --- /dev/null +++ b/src/test/run-pass/env-args-reverse-iterator.rs @@ -0,0 +1,44 @@ +// 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"); +} |
