]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #34485 - tbu-:pr_unicode_debug_str, r=alexcrichton
authorbors <bors@rust-lang.org>
Thu, 28 Jul 2016 18:20:33 +0000 (11:20 -0700)
committerGitHub <noreply@github.com>
Thu, 28 Jul 2016 18:20:33 +0000 (11:20 -0700)
Escape fewer Unicode codepoints in `Debug` impl of `str`

Use the same procedure as Python to determine whether a character is
printable, described in [PEP 3138]. In particular, this means that the
following character classes are escaped:

- Cc (Other, Control)
- Cf (Other, Format)
- Cs (Other, Surrogate), even though they can't appear in Rust strings
- Co (Other, Private Use)
- Cn (Other, Not Assigned)
- Zl (Separator, Line)
- Zp (Separator, Paragraph)
- Zs (Separator, Space), except for the ASCII space `' '` `0x20`

This allows for user-friendly inspection of strings that are not
English (e.g. compare `"\u{e9}\u{e8}\u{ea}"` to `"éèê"`).

Fixes #34318.
CC #34422.

[PEP 3138]: https://www.python.org/dev/peps/pep-3138/

145 files changed:
src/doc/book/syntax-index.md
src/doc/book/trait-objects.md
src/doc/nomicon/phantom-data.md
src/doc/reference.md
src/liballoc/arc.rs
src/libcollections/slice.rs
src/libcollections/vec.rs
src/libcollections/vec_deque.rs
src/libcollectionstest/binary_heap.rs
src/libcollectionstest/vec.rs
src/libcore/hash/mod.rs
src/libcore/intrinsics.rs
src/libcore/iter/traits.rs
src/libpanic_unwind/dwarf/eh.rs
src/libpanic_unwind/gcc.rs
src/libpanic_unwind/lib.rs
src/libpanic_unwind/seh64_gnu.rs
src/librustc/infer/bivariate.rs
src/librustc/infer/combine.rs
src/librustc/infer/equate.rs
src/librustc/infer/error_reporting.rs
src/librustc/infer/glb.rs
src/librustc/infer/higher_ranked/mod.rs
src/librustc/infer/lattice.rs
src/librustc/infer/lub.rs
src/librustc/infer/mod.rs
src/librustc/infer/sub.rs
src/librustc/session/mod.rs
src/librustc/traits/error_reporting.rs
src/librustc/ty/structural_impls.rs
src/librustc_back/target/mod.rs
src/librustc_const_eval/Cargo.toml
src/librustc_const_eval/check_match.rs
src/librustc_const_eval/diagnostics.rs
src/librustc_const_eval/eval.rs
src/librustc_const_eval/lib.rs
src/librustc_driver/driver.rs
src/librustc_errors/lib.rs
src/librustc_passes/consts.rs
src/librustc_passes/diagnostics.rs
src/librustc_resolve/lib.rs
src/librustc_save_analysis/csv_dumper.rs
src/librustc_trans/_match.rs
src/librustc_trans/consts.rs
src/librustc_trans/intrinsic.rs
src/librustc_trans/mir/constant.rs
src/librustc_trans/trans_item.rs
src/librustc_trans/tvec.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/cast.rs
src/librustc_typeck/check/compare_method.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/method/suggest.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/op.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/diagnostics.rs
src/librustc_typeck/lib.rs
src/librustc_unicode/char.rs
src/librustdoc/html/render.rs
src/libstd/collections/hash/map.rs
src/libstd/env.rs
src/libstd/fs.rs
src/libstd/sys/unix/ext/fs.rs
src/libstd/sys/unix/net.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/windows/os.rs
src/libsyntax/config.rs
src/libsyntax/ext/tt/transcribe.rs
src/libsyntax/parse/parser.rs
src/libsyntax/tokenstream.rs
src/libsyntax_pos/lib.rs
src/libunwind/libunwind.rs
src/rustc/Cargo.lock
src/test/compile-fail/array_const_index-0.rs
src/test/compile-fail/array_const_index-1.rs
src/test/compile-fail/associated-const-array-len.rs
src/test/compile-fail/associated-const-impl-wrong-type.rs
src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
src/test/compile-fail/associated-types-eq-3.rs
src/test/compile-fail/associated-types/higher-ranked-projection.rs [new file with mode: 0644]
src/test/compile-fail/const-array-oob.rs
src/test/compile-fail/const-call.rs
src/test/compile-fail/const-err.rs
src/test/compile-fail/const-eval-overflow-2.rs
src/test/compile-fail/const-eval-overflow-3.rs
src/test/compile-fail/const-eval-overflow-4b.rs
src/test/compile-fail/const-eval-overflow.rs
src/test/compile-fail/const-eval-span.rs
src/test/compile-fail/const-fn-error.rs
src/test/compile-fail/const-index-feature-gate.rs
src/test/compile-fail/const-integer-bool-ops.rs
src/test/compile-fail/const-len-underflow-separate-spans.rs
src/test/compile-fail/const-len-underflow-subspans.rs
src/test/compile-fail/const-pattern-not-const-evaluable.rs
src/test/compile-fail/const-slice-oob.rs
src/test/compile-fail/const-tup-index-span.rs
src/test/compile-fail/discrim-ill-typed.rs
src/test/compile-fail/enum-discrim-too-small.rs
src/test/compile-fail/eval-enum.rs
src/test/compile-fail/explicit-self-lifetime-mismatch.rs
src/test/compile-fail/feature-gate-negate-unsigned0.rs
src/test/compile-fail/invalid-path-in-const.rs
src/test/compile-fail/issue-13033.rs
src/test/compile-fail/issue-15094.rs
src/test/compile-fail/issue-17740.rs
src/test/compile-fail/issue-21332.rs
src/test/compile-fail/issue-22933-2.rs
src/test/compile-fail/issue-23217.rs
src/test/compile-fail/issue-24356.rs
src/test/compile-fail/issue-25145.rs
src/test/compile-fail/issue-27008.rs
src/test/compile-fail/issue-27895.rs
src/test/compile-fail/issue-28586.rs
src/test/compile-fail/issue-31173.rs [new file with mode: 0644]
src/test/compile-fail/issue-3521.rs
src/test/compile-fail/issue-8761.rs
src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs
src/test/compile-fail/macro-tt-matchers.rs [new file with mode: 0644]
src/test/compile-fail/match-range-fail.rs
src/test/compile-fail/non-constant-enum-for-vec-repeat.rs
src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
src/test/compile-fail/non-constant-in-const-path.rs
src/test/compile-fail/repeat_count.rs
src/test/compile-fail/trait-impl-method-mismatch.rs
src/test/compile-fail/ufcs-explicit-self-bad.rs
src/test/compile-fail/unresolved-import-recovery.rs [new file with mode: 0644]
src/test/compile-fail/unsafe-trait-impl.rs
src/test/debuginfo/function-prologue-stepping-no-stack-check.rs [deleted file]
src/test/run-make/issue-33329/Makefile [new file with mode: 0644]
src/test/run-make/issue-33329/main.rs [new file with mode: 0644]
src/test/run-pass-valgrind/coerce-match-calls.rs [new file with mode: 0644]
src/test/run-pass-valgrind/coerce-match.rs [new file with mode: 0644]
src/test/run-pass/coerce-match-calls.rs [deleted file]
src/test/run-pass/coerce-match.rs [deleted file]
src/test/run-pass/const-byte-str-cast.rs
src/test/run-pass/env-args-reverse-iterator.rs [new file with mode: 0644]
src/test/run-pass/issue-34932.rs [new file with mode: 0644]
src/test/run-pass/macro-of-higher-order.rs
src/test/rustdoc/issue-34928.rs [new file with mode: 0644]
src/test/rustdoc/where.rs

index 3e889f51f542d2d7541933d62771d05942c3e6c6..0259db221b6bc0dbaa0a47c94e7386eec91d22a3 100644 (file)
@@ -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
 
 [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
index b31a34a0425a489f246f2616b499a93cf4f8c918..b1aee579aabc26ae560c72e7187532fc0fd95c00 100644 (file)
@@ -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();
 }
index d565532017a65982d518e2453b780743e609a266..189695716deb1bb776f46aee347699529bcd42c4 100644 (file)
@@ -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
-
index b8509321e3d19b0679ba7a29aea280336229dab2..a461023642afd6130df80eaf0b95de7c0cd32021 100644 (file)
@@ -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.
index e762e4d8ce9a26a2d3690a40839d6e47ae280bd5..64b780413f884f4a33045525a98d83717d6053e5 100644 (file)
 //!
 //! Sharing some immutable data between threads:
 //!
+// Note that we **do not** run these tests here. The windows builders get super
+// unhappy of a thread outlives the main thread and then exits at the same time
+// (something deadlocks) so we just avoid this entirely by not running these
+// tests.
 //! ```no_run
 //! use std::sync::Arc;
 //! use std::thread;
 /// by putting it inside `Mutex` and then share `Mutex` immutably
 /// with `Arc<T>` as shown below.
 ///
-/// ```
+// See comment at the top of this file for why the test is no_run
+/// ```no_run
 /// use std::sync::{Arc, Mutex};
 /// use std::thread;
 ///
index 2c54dc13c8d0b6440494bf927138dfec7a6b06fd..ccef6c02f9d22f4d15aa3aded94270d16d847a9e 100644 (file)
@@ -544,14 +544,21 @@ pub fn iter_mut(&mut self) -> IterMut<T> {
     ///
     /// # Example
     ///
-    /// Print the adjacent pairs of a slice (i.e. `[1,2]`, `[2,3]`,
-    /// `[3,4]`):
+    /// ```
+    /// let slice = ['r', 'u', 's', 't'];
+    /// let mut iter = slice.windows(2);
+    /// assert_eq!(iter.next().unwrap(), &['r', 'u']);
+    /// assert_eq!(iter.next().unwrap(), &['u', 's']);
+    /// assert_eq!(iter.next().unwrap(), &['s', 't']);
+    /// assert!(iter.next().is_none());
+    /// ```
+    ///
+    /// If the slice is shorter than `size`:
     ///
-    /// ```rust
-    /// let v = &[1, 2, 3, 4];
-    /// for win in v.windows(2) {
-    ///     println!("{:?}", win);
-    /// }
+    /// ```
+    /// let slice = ['f', 'o', 'o'];
+    /// let mut iter = slice.windows(4);
+    /// assert!(iter.next().is_none());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -684,15 +691,40 @@ pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [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]
index 2d77b38879b8eb8a959f4920b51abbf6bc66f57c..275f38b2f787d469a8596be0b0d6bcce64fc3b19 100644 (file)
@@ -73,6 +73,7 @@
 use core::ops::{Index, IndexMut};
 use core::ops;
 use core::ptr;
+use core::ptr::Shared;
 use core::slice;
 
 use super::SpecExtend;
@@ -593,11 +594,12 @@ pub fn as_mut_slice(&mut self) -> &mut [T] {
     /// ```
     ///
     /// In this example, there is a memory leak since the memory locations
-    /// owned by the vector were not freed prior to the `set_len` call:
+    /// owned by the inner vectors were not freed prior to the `set_len` call:
     ///
     /// ```
-    /// let mut vec = vec!['r', 'u', 's', 't'];
-    ///
+    /// let mut vec = vec![vec![1, 0, 0],
+    ///                    vec![0, 1, 0],
+    ///                    vec![0, 0, 1]];
     /// unsafe {
     ///     vec.set_len(0);
     /// }
@@ -898,8 +900,8 @@ pub fn drain<R>(&mut self, range: R) -> Drain<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 _),
             }
         }
     }
@@ -1805,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")]
@@ -1844,7 +1846,7 @@ fn drop(&mut self) {
 
         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;
index 9e4428ec57d50db1eaf6a1a95c725deeb921f28a..9c3792afa2f1c91b5e87e234f1258028d2dc5f30 100644 (file)
@@ -402,6 +402,8 @@ pub fn with_capacity(n: usize) -> 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 @@ pub fn get(&self, index: usize) -> Option<&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 @@ pub fn get_mut(&mut self, index: usize) -> Option<&mut 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 @@ fn is_contiguous(&self) -> bool {
     ///
     /// Returns `None` if `index` is out of bounds.
     ///
+    /// Element at index 0 is the front of the queue.
+    ///
     /// # Examples
     ///
     /// ```
@@ -1214,6 +1222,8 @@ pub fn swap_remove_back(&mut self, index: usize) -> Option<T> {
     ///
     /// Returns `None` if `index` is out of bounds.
     ///
+    /// Element at index 0 is the front of the queue.
+    ///
     /// # Examples
     ///
     /// ```
@@ -1245,6 +1255,8 @@ pub fn swap_remove_front(&mut self, index: usize) -> Option<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 @@ pub fn insert(&mut self, index: usize, value: 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 @@ pub fn remove(&mut self, index: usize) -> Option<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`
index be933abe41fe201f8d1c8be9efd9e88d1b708de0..e2a57bd8d3862df021cf5325a4c68a5b926901d8 100644 (file)
@@ -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 }
+}
index cb99659cc0ead7238fd30d75d49cdef095aea976..7a6bd958a5f8c7cb915c5756e055d1d25a65be78 100644 (file)
@@ -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(|| {
index 9e3f7a4a84a814b318a9833f18fb6352fca5b1e3..27fdbd383017f08ea3e38350b47e0a6b9c9a84aa 100644 (file)
@@ -234,6 +234,16 @@ pub trait BuildHasher {
     type Hasher: Hasher;
 
     /// Creates a new hasher.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::hash_map::RandomState;
+    /// use std::hash::BuildHasher;
+    ///
+    /// let s = RandomState::new();
+    /// let new_s = s.build_hasher();
+    /// ```
     #[stable(since = "1.7.0", feature = "build_hasher")]
     fn build_hasher(&self) -> Self::Hasher;
 }
index 1bdcc5bfe119dcce59a62e6fa9d4fe396d57d761..c645608dda7902ed3189dbe7ad6af7b948fdf1b4 100644 (file)
     /// 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;
index 896d1c6f30bf2cfe0509eb8103e05e89e7927a98..292d72dd362ad5c203497361cd9cda2febfaebc7 100644 (file)
@@ -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
     ///
index 0ad6a74d1013c60b562ed1d9ff7467b2bedd5075..1e9e9e30f5cfe08df94cebfce04b840e9f23fca5 100644 (file)
 pub const DW_EH_PE_indirect: u8 = 0x80;
 
 #[derive(Copy, Clone)]
-pub struct EHContext {
+pub struct EHContext<'a> {
     pub ip: usize, // Current instruction pointer
     pub func_start: usize, // Address of the current function
-    pub text_start: usize, // Address of the code section
-    pub data_start: usize, // Address of the data section
+    pub get_text_start: &'a Fn() -> usize, // Get address of the code section
+    pub get_data_start: &'a Fn() -> usize, // Get address of the data section
 }
 
-pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) -> Option<usize> {
+pub enum EHAction {
+    None,
+    Cleanup(usize),
+    Catch(usize),
+    Terminate,
+}
+
+pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));
+
+pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
     if lsda.is_null() {
-        return None;
+        return EHAction::None;
     }
 
     let func_start = context.func_start;
@@ -77,32 +86,61 @@ pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) -> Option<u
     let call_site_encoding = reader.read::<u8>();
     let call_site_table_length = reader.read_uleb128();
     let action_table = reader.ptr.offset(call_site_table_length as isize);
-    // Return addresses point 1 byte past the call instruction, which could
-    // be in the next IP range.
-    let ip = context.ip - 1;
-
-    while reader.ptr < action_table {
-        let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
-        let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
-        let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
-        let cs_action = reader.read_uleb128();
-        // Callsite table is sorted by cs_start, so if we've passed the ip, we
-        // may stop searching.
-        if ip < func_start + cs_start {
-            break;
+    let ip = context.ip;
+
+    if !USING_SJLJ_EXCEPTIONS {
+        while reader.ptr < action_table {
+            let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
+            let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
+            let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
+            let cs_action = reader.read_uleb128();
+            // Callsite table is sorted by cs_start, so if we've passed the ip, we
+            // may stop searching.
+            if ip < func_start + cs_start {
+                break;
+            }
+            if ip < func_start + cs_start + cs_len {
+                if cs_lpad == 0 {
+                    return EHAction::None;
+                } else {
+                    let lpad = lpad_base + cs_lpad;
+                    return interpret_cs_action(cs_action, lpad);
+                }
+            }
         }
-        if ip < func_start + cs_start + cs_len {
-            if cs_lpad != 0 {
-                return Some(lpad_base + cs_lpad);
-            } else {
-                return None;
+        // Ip is not present in the table.  This should not hapen... but it does: issie #35011.
+        // So rather than returning EHAction::Terminate, we do this.
+        EHAction::None
+    } else {
+        // SjLj version:
+        // The "IP" is an index into the call-site table, with two exceptions:
+        // -1 means 'no-action', and 0 means 'terminate'.
+        match ip as isize {
+           -1 => return EHAction::None,
+            0 => return EHAction::Terminate,
+            _ => (),
+        }
+        let mut idx = ip;
+        loop {
+            let cs_lpad = reader.read_uleb128();
+            let cs_action = reader.read_uleb128();
+            idx -= 1;
+            if idx == 0 {
+                // Can never have null landing pad for sjlj -- that would have
+                // been indicated by a -1 call site index.
+                let lpad = (cs_lpad + 1) as usize;
+                return interpret_cs_action(cs_action, lpad);
             }
         }
     }
-    // IP range not found: gcc's C++ personality calls terminate() here,
-    // however the rest of the languages treat this the same as cs_lpad == 0.
-    // We follow this suit.
-    None
+}
+
+fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
+    if cs_action == 0 {
+        EHAction::Cleanup(lpad)
+    } else {
+        EHAction::Catch(lpad)
+    }
 }
 
 #[inline]
@@ -140,18 +178,16 @@ unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
         DW_EH_PE_absptr => 0,
         // relative to address of the encoded value, despite the name
         DW_EH_PE_pcrel => reader.ptr as usize,
-        DW_EH_PE_textrel => {
-            assert!(context.text_start != 0);
-            context.text_start
-        }
-        DW_EH_PE_datarel => {
-            assert!(context.data_start != 0);
-            context.data_start
-        }
         DW_EH_PE_funcrel => {
             assert!(context.func_start != 0);
             context.func_start
         }
+        DW_EH_PE_textrel => {
+            (*context.get_text_start)()
+        }
+        DW_EH_PE_datarel => {
+            (*context.get_data_start)()
+        }
         _ => panic!(),
     };
 
index 3c46072e17e1a7753aa3939c7676efb8e54ff2bd..cdf772ad3b825481231305ff6ae887bbb9048566 100644 (file)
@@ -106,117 +106,96 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
     0x4d4f5a_00_52555354
 }
 
-// We could implement our personality routine in Rust, however exception
-// info decoding is tedious.  More importantly, personality routines have to
-// handle various platform quirks, which are not fun to maintain.  For this
-// reason, we attempt to reuse personality routine of the C language:
-// __gcc_personality_v0.
-//
-// Since C does not support exception catching, __gcc_personality_v0 simply
-// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
-// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
-//
-// This is pretty close to Rust's exception handling approach, except that Rust
-// does have a single "catch-all" handler at the bottom of each thread's stack.
-// So we have two versions of the personality routine:
-// - rust_eh_personality, used by all cleanup landing pads, which never catches,
-//   so the behavior of __gcc_personality_v0 is perfectly adequate there, and
-// - rust_eh_personality_catch, used only by rust_try(), which always catches.
-//
-// See also: rustc_trans::trans::intrinsic::trans_gnu_try
-
-#[cfg(all(not(target_arch = "arm"),
-          not(all(windows, target_arch = "x86_64"))))]
+// All targets, except ARM which uses a slightly different ABI (however, iOS goes here as it uses
+// SjLj unwinding).  Also, 64-bit Windows implementation lives in seh64_gnu.rs
+#[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))]
 pub mod eabi {
     use unwind as uw;
-    use libc::c_int;
+    use libc::{c_int, uintptr_t};
+    use dwarf::eh::{EHContext, EHAction, find_eh_action};
 
-    extern "C" {
-        fn __gcc_personality_v0(version: c_int,
-                                actions: uw::_Unwind_Action,
-                                exception_class: uw::_Unwind_Exception_Class,
-                                ue_header: *mut uw::_Unwind_Exception,
-                                context: *mut uw::_Unwind_Context)
-                                -> uw::_Unwind_Reason_Code;
-    }
+    // Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
+    // and TargetLowering::getExceptionSelectorRegister() for each architecture,
+    // then mapped to DWARF register numbers via register definition tables
+    // (typically <arch>RegisterInfo.td, search for "DwarfRegNum").
+    // See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
 
-    #[lang = "eh_personality"]
-    #[no_mangle]
-    extern "C" fn rust_eh_personality(version: c_int,
-                                      actions: uw::_Unwind_Action,
-                                      exception_class: uw::_Unwind_Exception_Class,
-                                      ue_header: *mut uw::_Unwind_Exception,
-                                      context: *mut uw::_Unwind_Context)
-                                      -> uw::_Unwind_Reason_Code {
-        unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) }
-    }
+    #[cfg(target_arch = "x86")]
+    const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX
 
-    #[lang = "eh_personality_catch"]
-    #[no_mangle]
-    pub extern "C" fn rust_eh_personality_catch(version: c_int,
-                                                actions: uw::_Unwind_Action,
-                                                exception_class: uw::_Unwind_Exception_Class,
-                                                ue_header: *mut uw::_Unwind_Exception,
-                                                context: *mut uw::_Unwind_Context)
-                                                -> uw::_Unwind_Reason_Code {
+    #[cfg(target_arch = "x86_64")]
+    const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
 
-        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 {
-            // search phase
-            uw::_URC_HANDLER_FOUND // catch!
-        } else {
-            // cleanup phase
-            unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) }
-        }
-    }
-}
-
-// iOS on armv7 is using SjLj exceptions and therefore requires to use
-// a specialized personality routine: __gcc_personality_sj0
+    #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+    const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
 
-#[cfg(all(target_os = "ios", target_arch = "arm"))]
-pub mod eabi {
-    use unwind as uw;
-    use libc::c_int;
+    #[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
+    const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
 
-    extern "C" {
-        fn __gcc_personality_sj0(version: c_int,
-                                 actions: uw::_Unwind_Action,
-                                 exception_class: uw::_Unwind_Exception_Class,
-                                 ue_header: *mut uw::_Unwind_Exception,
-                                 context: *mut uw::_Unwind_Context)
-                                 -> uw::_Unwind_Reason_Code;
-    }
+    #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+    const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4
 
+    // Based on GCC's C and C++ personality routines.  For reference, see:
+    // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
+    // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
     #[lang = "eh_personality"]
     #[no_mangle]
-    pub extern "C" fn rust_eh_personality(version: c_int,
-                                          actions: uw::_Unwind_Action,
-                                          exception_class: uw::_Unwind_Exception_Class,
-                                          ue_header: *mut uw::_Unwind_Exception,
-                                          context: *mut uw::_Unwind_Context)
-                                          -> uw::_Unwind_Reason_Code {
-        unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) }
+    #[allow(unused)]
+    unsafe extern "C" fn rust_eh_personality(version: c_int,
+                                             actions: uw::_Unwind_Action,
+                                             exception_class: uw::_Unwind_Exception_Class,
+                                             exception_object: *mut uw::_Unwind_Exception,
+                                             context: *mut uw::_Unwind_Context)
+                                             -> uw::_Unwind_Reason_Code {
+        if version != 1 {
+            return uw::_URC_FATAL_PHASE1_ERROR;
+        }
+        let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
+        let mut ip_before_instr: c_int = 0;
+        let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
+        let eh_context = EHContext {
+            // The return address points 1 byte past the call instruction,
+            // which could be in the next IP range in LSDA range table.
+            ip: if ip_before_instr != 0 { ip } else { ip - 1 },
+            func_start: uw::_Unwind_GetRegionStart(context),
+            get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
+            get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
+        };
+        let eh_action = find_eh_action(lsda, &eh_context);
+
+        if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
+            match eh_action {
+                EHAction::None | EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND,
+                EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
+                EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR,
+            }
+        } else {
+            match eh_action {
+                EHAction::None => return uw::_URC_CONTINUE_UNWIND,
+                EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
+                    uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
+                    uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
+                    uw::_Unwind_SetIP(context, lpad);
+                    return uw::_URC_INSTALL_CONTEXT;
+                }
+                EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR,
+            }
+        }
     }
 
+    #[cfg(stage0)]
     #[lang = "eh_personality_catch"]
     #[no_mangle]
-    pub extern "C" fn rust_eh_personality_catch(version: c_int,
-                                                actions: uw::_Unwind_Action,
-                                                exception_class: uw::_Unwind_Exception_Class,
-                                                ue_header: *mut uw::_Unwind_Exception,
-                                                context: *mut uw::_Unwind_Context)
-                                                -> uw::_Unwind_Reason_Code {
-        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 {
-            // search phase
-            uw::_URC_HANDLER_FOUND // catch!
-        } else {
-            // cleanup phase
-            unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) }
-        }
+    pub unsafe extern "C" fn rust_eh_personality_catch(version: c_int,
+                                                       actions: uw::_Unwind_Action,
+                                                       exception_class: uw::_Unwind_Exception_Class,
+                                                       ue_header: *mut uw::_Unwind_Exception,
+                                                       context: *mut uw::_Unwind_Context)
+                                                       -> uw::_Unwind_Reason_Code {
+        rust_eh_personality(version, actions, exception_class, ue_header, context)
     }
 }
 
-
 // ARM EHABI uses a slightly different personality routine signature,
 // but otherwise works the same.
 #[cfg(all(target_arch = "arm", not(target_os = "ios")))]
index b765ee6f81cf9a70468f9e02cfe3849c73a8ff08..11dd9befe0a82e940da630f68317591ef960187b 100644 (file)
 // Entry point for raising an exception, just delegates to the platform-specific
 // implementation.
 #[no_mangle]
+#[unwind]
 pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 {
     imp::panic(mem::transmute(raw::TraitObject {
         data: data as *mut (),
index 56801e8cb6bcf3d5583a7ca409a2aac4a8db965d..7dc428871b387f2e83792d468706fa8b6c99675f 100644 (file)
@@ -19,7 +19,7 @@
 use core::any::Any;
 use core::intrinsics;
 use core::ptr;
-use dwarf::eh;
+use dwarf::eh::{EHContext, EHAction, find_eh_action};
 use windows as c;
 
 // Define our exception codes:
@@ -81,6 +81,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
 // This is considered acceptable, because the behavior of throwing exceptions
 // through a C ABI boundary is undefined.
 
+#[cfg(stage0)]
 #[lang = "eh_personality_catch"]
 #[cfg(not(test))]
 unsafe extern "C" fn rust_eh_personality_catch(exceptionRecord: *mut c::EXCEPTION_RECORD,
@@ -132,11 +133,17 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
 }
 
 unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
-    let eh_ctx = eh::EHContext {
-        ip: dc.ControlPc as usize,
+    let eh_ctx = EHContext {
+        // The return address points 1 byte past the call instruction,
+        // which could be in the next IP range in LSDA range table.
+        ip: dc.ControlPc as usize - 1,
         func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
-        text_start: dc.ImageBase as usize,
-        data_start: 0,
+        get_text_start: &|| dc.ImageBase as usize,
+        get_data_start: &|| unimplemented!(),
     };
-    eh::find_landing_pad(dc.HandlerData, &eh_ctx)
+    match find_eh_action(dc.HandlerData, &eh_ctx) {
+        EHAction::None => None,
+        EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => Some(lpad),
+        EHAction::Terminate => intrinsics::abort(),
+    }
 }
index 96b14a6c321cd2a5d99fbc309416033f9927c932..125f815feda6fa6d902bea13a91be128cb1a603c 100644 (file)
 use ty::TyVar;
 use ty::relate::{Relate, RelateResult, TypeRelation};
 
-pub struct Bivariate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    fields: CombineFields<'a, 'gcx, 'tcx>
+pub struct Bivariate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+    fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+    a_is_expected: bool,
 }
 
-impl<'a, 'gcx, 'tcx> Bivariate<'a, 'gcx, 'tcx> {
-    pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Bivariate<'a, 'gcx, 'tcx> {
-        Bivariate { fields: fields }
+impl<'combine, 'infcx, 'gcx, 'tcx> Bivariate<'combine, 'infcx, 'gcx, 'tcx> {
+    pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+        -> Bivariate<'combine, 'infcx, 'gcx, 'tcx>
+    {
+        Bivariate { fields: fields, a_is_expected: a_is_expected }
     }
 }
 
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Bivariate<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+    for Bivariate<'combine, 'infcx, 'gcx, 'tcx>
+{
     fn tag(&self) -> &'static str { "Bivariate" }
 
-    fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
+    fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
 
-    fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+    fn a_is_expected(&self) -> bool { self.a_is_expected }
 
     fn relate_with_variance<T: Relate<'tcx>>(&mut self,
                                              variance: ty::Variance,
@@ -86,12 +91,12 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
             }
 
             (&ty::TyInfer(TyVar(a_id)), _) => {
-                self.fields.instantiate(b, BiTo, a_id)?;
+                self.fields.instantiate(b, BiTo, a_id, self.a_is_expected)?;
                 Ok(a)
             }
 
             (_, &ty::TyInfer(TyVar(b_id))) => {
-                self.fields.instantiate(a, BiTo, b_id)?;
+                self.fields.instantiate(a, BiTo, b_id, self.a_is_expected)?;
                 Ok(a)
             }
 
index c9235d063cba0981826648b5a7616d2ffd2c0998..b4818f963b3ba76e4b6ae71f2ad4f381dbbd1616 100644 (file)
 use syntax_pos::Span;
 
 #[derive(Clone)]
-pub struct CombineFields<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-    pub a_is_expected: bool,
+pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+    pub infcx: &'infcx InferCtxt<'infcx, 'gcx, 'tcx>,
     pub trace: TypeTrace<'tcx>,
     pub cause: Option<ty::relate::Cause>,
     pub obligations: PredicateObligations<'tcx>,
 }
 
-impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> {
     pub fn super_combine_tys<R>(&self,
                                 relation: &mut R,
                                 a: Ty<'tcx>,
                                 b: Ty<'tcx>)
                                 -> RelateResult<'tcx, Ty<'tcx>>
-        where R: TypeRelation<'a, 'gcx, 'tcx>
+        where R: TypeRelation<'infcx, 'gcx, 'tcx>
     {
         let a_is_expected = relation.a_is_expected();
 
@@ -150,42 +149,36 @@ fn unify_float_variable(&self,
     }
 }
 
-impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
-    pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
+impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
+    pub fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> {
         self.infcx.tcx
     }
 
-    pub fn switch_expected(&self) -> CombineFields<'a, 'gcx, 'tcx> {
-        CombineFields {
-            a_is_expected: !self.a_is_expected,
-            ..(*self).clone()
-        }
-    }
-
-    pub fn equate(&self) -> Equate<'a, 'gcx, 'tcx> {
-        Equate::new(self.clone())
+    pub fn equate<'a>(&'a mut self, a_is_expected: bool) -> Equate<'a, 'infcx, 'gcx, 'tcx> {
+        Equate::new(self, a_is_expected)
     }
 
-    pub fn bivariate(&self) -> Bivariate<'a, 'gcx, 'tcx> {
-        Bivariate::new(self.clone())
+    pub fn bivariate<'a>(&'a mut self, a_is_expected: bool) -> Bivariate<'a, 'infcx, 'gcx, 'tcx> {
+        Bivariate::new(self, a_is_expected)
     }
 
-    pub fn sub(&self) -> Sub<'a, 'gcx, 'tcx> {
-        Sub::new(self.clone())
+    pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'gcx, 'tcx> {
+        Sub::new(self, a_is_expected)
     }
 
-    pub fn lub(&self) -> Lub<'a, 'gcx, 'tcx> {
-        Lub::new(self.clone())
+    pub fn lub<'a>(&'a mut self, a_is_expected: bool) -> Lub<'a, 'infcx, 'gcx, 'tcx> {
+        Lub::new(self, a_is_expected)
     }
 
-    pub fn glb(&self) -> Glb<'a, 'gcx, 'tcx> {
-        Glb::new(self.clone())
+    pub fn glb<'a>(&'a mut self, a_is_expected: bool) -> Glb<'a, 'infcx, 'gcx, 'tcx> {
+        Glb::new(self, a_is_expected)
     }
 
-    pub fn instantiate(&self,
+    pub fn instantiate(&mut self,
                        a_ty: Ty<'tcx>,
                        dir: RelationDir,
-                       b_vid: ty::TyVid)
+                       b_vid: ty::TyVid,
+                       a_is_expected: bool)
                        -> RelateResult<'tcx, ()>
     {
         let mut stack = Vec::new();
@@ -255,10 +248,11 @@ pub fn instantiate(&self,
             // to associate causes/spans with each of the relations in
             // the stack to get this right.
             match dir {
-                BiTo => self.bivariate().relate(&a_ty, &b_ty),
-                EqTo => self.equate().relate(&a_ty, &b_ty),
-                SubtypeOf => self.sub().relate(&a_ty, &b_ty),
-                SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty),
+                BiTo => self.bivariate(a_is_expected).relate(&a_ty, &b_ty),
+                EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty),
+                SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty),
+                SupertypeOf => self.sub(a_is_expected).relate_with_variance(
+                    ty::Contravariant, &a_ty, &b_ty),
             }?;
         }
 
index 408f22cf15c77dfa46afb74826ca2e16b8672678..e06f7303acb2927ac99950a43b087c39f9c6c7ac 100644 (file)
 use ty::{self, Ty, TyCtxt};
 use ty::TyVar;
 use ty::relate::{Relate, RelateResult, TypeRelation};
-use traits::PredicateObligations;
 
 /// Ensures `a` is made equal to `b`. Returns `a` on success.
-pub struct Equate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    fields: CombineFields<'a, 'gcx, 'tcx>
+pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+    fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+    a_is_expected: bool,
 }
 
-impl<'a, 'gcx, 'tcx> Equate<'a, 'gcx, 'tcx> {
-    pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Equate<'a, 'gcx, 'tcx> {
-        Equate { fields: fields }
-    }
-
-    pub fn obligations(self) -> PredicateObligations<'tcx> {
-        self.fields.obligations
+impl<'combine, 'infcx, 'gcx, 'tcx> Equate<'combine, 'infcx, 'gcx, 'tcx> {
+    pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+        -> Equate<'combine, 'infcx, 'gcx, 'tcx>
+    {
+        Equate { fields: fields, a_is_expected: a_is_expected }
     }
 }
 
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Equate<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+    for Equate<'combine, 'infcx, 'gcx, 'tcx>
+{
     fn tag(&self) -> &'static str { "Equate" }
 
-    fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
+    fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
 
-    fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+    fn a_is_expected(&self) -> bool { self.a_is_expected }
 
     fn relate_with_variance<T: Relate<'tcx>>(&mut self,
                                              _: ty::Variance,
@@ -63,12 +63,12 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
             }
 
             (&ty::TyInfer(TyVar(a_id)), _) => {
-                self.fields.instantiate(b, EqTo, a_id)?;
+                self.fields.instantiate(b, EqTo, a_id, self.a_is_expected)?;
                 Ok(a)
             }
 
             (_, &ty::TyInfer(TyVar(b_id))) => {
-                self.fields.instantiate(a, EqTo, b_id)?;
+                self.fields.instantiate(a, EqTo, b_id, self.a_is_expected)?;
                 Ok(a)
             }
 
@@ -93,7 +93,7 @@ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
                   -> RelateResult<'tcx, ty::Binder<T>>
         where T: Relate<'tcx>
     {
-        self.fields.higher_ranked_sub(a, b)?;
-        self.fields.higher_ranked_sub(b, a)
+        self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
+        self.fields.higher_ranked_sub(b, a, self.a_is_expected)
     }
 }
index 96ecad629f543f24d7a7e586a351e7163375b4c1..511cc32d2e1e6cfeb47d00fa65076fba5445de64 100644 (file)
@@ -83,7 +83,7 @@
 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 @@ fn append_to_same_regions(same_regions: &mut Vec<SameRegions>,
         }
     }
 
-    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 @@ fn check_and_note_conflicting_crates(&self,
         }
     }
 
+    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 @@ fn report_inference_failure(&self,
     fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) {
         match *origin {
             infer::Subtype(ref trace) => {
-                let desc = match trace.origin {
-                    TypeOrigin::Misc(_) => {
-                        "types are compatible"
-                    }
-                    TypeOrigin::MethodCompatCheck(_) => {
-                        "method type is compatible with trait"
-                    }
-                    TypeOrigin::ExprAssignable(_) => {
-                        "expression is assignable"
-                    }
-                    TypeOrigin::RelateTraitRefs(_) => {
-                        "traits are compatible"
-                    }
-                    TypeOrigin::RelateSelfType(_) => {
-                        "self type matches impl self type"
-                    }
-                    TypeOrigin::RelateOutputImplTypes(_) => {
-                        "trait type parameters matches those \
-                                 specified on the impl"
-                    }
-                    TypeOrigin::MatchExpressionArm(_, _, _) => {
-                        "match arms have compatible types"
-                    }
-                    TypeOrigin::IfExpression(_) => {
-                        "if and else have compatible types"
-                    }
-                    TypeOrigin::IfExpressionWithNoElse(_) => {
-                        "if may be missing an else clause"
-                    }
-                    TypeOrigin::RangeExpression(_) => {
-                        "start and end of range have compatible types"
-                    }
-                    TypeOrigin::EquatePredicate(_) => {
-                        "equality where clause is satisfied"
-                    }
-                };
-
-                match self.values_str(&trace.values) {
-                    Some((expected, found)) => {
-                        err.span_note(
-                            trace.origin.span(),
-                            &format!("...so that {} (expected {}, found {})",
-                                    desc, expected, found));
-                    }
-                    None => {
-                        // Really should avoid printing this error at
-                        // all, since it is derived, but that would
-                        // require more refactoring than I feel like
-                        // doing right now. - nmatsakis
-                        err.span_note(
-                            trace.origin.span(),
-                            &format!("...so that {}", desc));
-                    }
+                if let Some((expected, found)) = self.values_str(&trace.values) {
+                    // FIXME: do we want a "the" here?
+                    err.span_note(
+                        trace.origin.span(),
+                        &format!("...so that {} (expected {}, found {})",
+                                 trace.origin.as_requirement_str(), expected, found));
+                } else {
+                    // FIXME: this really should be handled at some earlier stage. Our
+                    // handling of region checking when type errors are present is
+                    // *terrible*.
+
+                    err.span_note(
+                        trace.origin.span(),
+                        &format!("...so that {}",
+                                 trace.origin.as_requirement_str()));
                 }
             }
             infer::Reborrow(span) => {
@@ -1803,32 +1779,6 @@ fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrig
     }
 }
 
-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> {
index b7085f0829f8a51239eb35364e5c0e3dce1db454..5dd85a31a9a2087effd0487c3e1393c0b058107c 100644 (file)
 
 use ty::{self, Ty, TyCtxt};
 use ty::relate::{Relate, RelateResult, TypeRelation};
-use traits::PredicateObligations;
 
 /// "Greatest lower bound" (common subtype)
-pub struct Glb<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    fields: CombineFields<'a, 'gcx, 'tcx>
+pub struct Glb<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+    fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+    a_is_expected: bool,
 }
 
-impl<'a, 'gcx, 'tcx> Glb<'a, 'gcx, 'tcx> {
-    pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Glb<'a, 'gcx, 'tcx> {
-        Glb { fields: fields }
-    }
-
-    pub fn obligations(self) -> PredicateObligations<'tcx> {
-        self.fields.obligations
+impl<'combine, 'infcx, 'gcx, 'tcx> Glb<'combine, 'infcx, 'gcx, 'tcx> {
+    pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+        -> Glb<'combine, 'infcx, 'gcx, 'tcx>
+    {
+        Glb { fields: fields, a_is_expected: a_is_expected }
     }
 }
 
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+    for Glb<'combine, 'infcx, 'gcx, 'tcx>
+{
     fn tag(&self) -> &'static str { "Glb" }
 
-    fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
+    fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
 
-    fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+    fn a_is_expected(&self) -> bool { self.a_is_expected }
 
     fn relate_with_variance<T: Relate<'tcx>>(&mut self,
                                              variance: ty::Variance,
@@ -46,10 +46,10 @@ fn relate_with_variance<T: Relate<'tcx>>(&mut self,
                                              -> RelateResult<'tcx, T>
     {
         match variance {
-            ty::Invariant => self.fields.equate().relate(a, b),
+            ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
             ty::Covariant => self.relate(a, b),
-            ty::Bivariant => self.fields.bivariate().relate(a, b),
-            ty::Contravariant => self.fields.lub().relate(a, b),
+            ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b),
+            ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b),
         }
     }
 
@@ -71,17 +71,19 @@ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
                   -> RelateResult<'tcx, ty::Binder<T>>
         where T: Relate<'tcx>
     {
-        self.fields.higher_ranked_glb(a, b)
+        self.fields.higher_ranked_glb(a, b, self.a_is_expected)
     }
 }
 
-impl<'a, 'gcx, 'tcx> LatticeDir<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> {
-    fn infcx(&self) -> &'a InferCtxt<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx>
+    for Glb<'combine, 'infcx, 'gcx, 'tcx>
+{
+    fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> {
         self.fields.infcx
     }
 
-    fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
-        let mut sub = self.fields.sub();
+    fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
+        let mut sub = self.fields.sub(self.a_is_expected);
         sub.relate(&v, &a)?;
         sub.relate(&v, &b)?;
         Ok(())
index 03a09917c5343bd1fce8783e2c1a524565290531..743d6135fbb5b555a9c61b151a023626a2325dd1 100644 (file)
@@ -40,7 +40,7 @@ pub struct HrMatchResult<U> {
 }
 
 impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
-    pub fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
+    pub fn higher_ranked_sub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
                                 -> RelateResult<'tcx, Binder<T>>
         where T: Relate<'tcx>
     {
@@ -77,11 +77,11 @@ pub fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
             debug!("b_prime={:?}", b_prime);
 
             // Compare types now that bound regions have been replaced.
-            let result = self.sub().relate(&a_prime, &b_prime)?;
+            let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
 
             // Presuming type comparison succeeds, we need to check
             // that the skolemized regions do not "leak".
-            self.infcx.leak_check(!self.a_is_expected, span, &skol_map, snapshot)?;
+            self.infcx.leak_check(!a_is_expected, span, &skol_map, snapshot)?;
 
             // We are finished with the skolemized regions now so pop
             // them off.
@@ -106,10 +106,11 @@ pub fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
     /// NB. It should not happen that there are LBR appearing in `U`
     /// that do not appear in `T`. If that happens, those regions are
     /// unconstrained, and this routine replaces them with `'static`.
-    pub fn higher_ranked_match<T, U>(&self,
+    pub fn higher_ranked_match<T, U>(&mut self,
                                      span: Span,
                                      a_pair: &Binder<(T, U)>,
-                                     b_match: &T)
+                                     b_match: &T,
+                                     a_is_expected: bool)
                                      -> RelateResult<'tcx, HrMatchResult<U>>
         where T: Relate<'tcx>,
               U: TypeFoldable<'tcx>
@@ -129,7 +130,7 @@ pub fn higher_ranked_match<T, U>(&self,
             debug!("higher_ranked_match: skol_map={:?}", skol_map);
 
             // Equate types now that bound regions have been replaced.
-            try!(self.equate().relate(&a_match, &b_match));
+            try!(self.equate(a_is_expected).relate(&a_match, &b_match));
 
             // Map each skolemized region to a vector of other regions that it
             // must be equated with. (Note that this vector may include other
@@ -221,7 +222,7 @@ pub fn higher_ranked_match<T, U>(&self,
         });
     }
 
-    pub fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>)
+    pub fn higher_ranked_lub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
                                 -> RelateResult<'tcx, Binder<T>>
         where T: Relate<'tcx>
     {
@@ -239,7 +240,7 @@ pub fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>)
 
             // Collect constraints.
             let result0 =
-                self.lub().relate(&a_with_fresh, &b_with_fresh)?;
+                self.lub(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
             let result0 =
                 self.infcx.resolve_type_vars_if_possible(&result0);
             debug!("lub result0 = {:?}", result0);
@@ -311,7 +312,7 @@ fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
         }
     }
 
-    pub fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>)
+    pub fn higher_ranked_glb<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
                                 -> RelateResult<'tcx, Binder<T>>
         where T: Relate<'tcx>
     {
@@ -333,7 +334,7 @@ pub fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>)
 
             // Collect constraints.
             let result0 =
-                self.glb().relate(&a_with_fresh, &b_with_fresh)?;
+                self.glb(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
             let result0 =
                 self.infcx.resolve_type_vars_if_possible(&result0);
             debug!("glb result0 = {:?}", result0);
index 1a2bc4b5cf2e18b7690e2d942aec2a183260a06d..eda78428e61ad41c4690fccc8adf8668e8ad6ed2 100644 (file)
@@ -40,7 +40,7 @@ pub trait LatticeDir<'f, 'gcx: 'f+'tcx, 'tcx: 'f> : TypeRelation<'f, 'gcx, 'tcx>
 
     // Relates the type `v` to `a` and `b` such that `v` represents
     // the LUB/GLB of `a` and `b` as appropriate.
-    fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
+    fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
 }
 
 pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L,
index bd46f3a26a2def175852a5026a87d0e2ee8cf6f0..ad1b32ffaeb320ac18159277ee07d34df3a016c7 100644 (file)
 
 use ty::{self, Ty, TyCtxt};
 use ty::relate::{Relate, RelateResult, TypeRelation};
-use traits::PredicateObligations;
 
 /// "Least upper bound" (common supertype)
-pub struct Lub<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    fields: CombineFields<'a, 'gcx, 'tcx>
+pub struct Lub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+    fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+    a_is_expected: bool,
 }
 
-impl<'a, 'gcx, 'tcx> Lub<'a, 'gcx, 'tcx> {
-    pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Lub<'a, 'gcx, 'tcx> {
-        Lub { fields: fields }
-    }
-
-    pub fn obligations(self) -> PredicateObligations<'tcx> {
-        self.fields.obligations
+impl<'combine, 'infcx, 'gcx, 'tcx> Lub<'combine, 'infcx, 'gcx, 'tcx> {
+    pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+        -> Lub<'combine, 'infcx, 'gcx, 'tcx>
+    {
+        Lub { fields: fields, a_is_expected: a_is_expected }
     }
 }
 
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+    for Lub<'combine, 'infcx, 'gcx, 'tcx>
+{
     fn tag(&self) -> &'static str { "Lub" }
 
-    fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
+    fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
 
-    fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+    fn a_is_expected(&self) -> bool { self.a_is_expected }
 
     fn relate_with_variance<T: Relate<'tcx>>(&mut self,
                                              variance: ty::Variance,
@@ -46,10 +46,10 @@ fn relate_with_variance<T: Relate<'tcx>>(&mut self,
                                              -> RelateResult<'tcx, T>
     {
         match variance {
-            ty::Invariant => self.fields.equate().relate(a, b),
+            ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
             ty::Covariant => self.relate(a, b),
-            ty::Bivariant => self.fields.bivariate().relate(a, b),
-            ty::Contravariant => self.fields.glb().relate(a, b),
+            ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b),
+            ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b),
         }
     }
 
@@ -71,17 +71,19 @@ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
                   -> RelateResult<'tcx, ty::Binder<T>>
         where T: Relate<'tcx>
     {
-        self.fields.higher_ranked_lub(a, b)
+        self.fields.higher_ranked_lub(a, b, self.a_is_expected)
     }
 }
 
-impl<'a, 'gcx, 'tcx> LatticeDir<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> {
-    fn infcx(&self) -> &'a InferCtxt<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx>
+    for Lub<'combine, 'infcx, 'gcx, 'tcx>
+{
+    fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> {
         self.fields.infcx
     }
 
-    fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
-        let mut sub = self.fields.sub();
+    fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
+        let mut sub = self.fields.sub(self.a_is_expected);
         sub.relate(&a, &v)?;
         sub.relate(&b, &v)?;
         Ok(())
index 2ea2978b2940d858a482a408b98c424a4d2394b8..be9adf7085cd4aee2780ccc5fd00719f656ab1a7 100644 (file)
@@ -32,7 +32,7 @@
 use ty::{TyVid, IntVid, FloatVid};
 use ty::{self, Ty, TyCtxt};
 use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
-use ty::fold::TypeFoldable;
+use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use ty::relate::{Relate, RelateResult, TypeRelation};
 use traits::{self, PredicateObligations, ProjectionMode};
 use rustc_data_structures::unify::{self, UnificationTable};
 use self::region_inference::{RegionVarBindings, RegionSnapshot};
 use self::unify_key::ToType;
 
-pub mod bivariate;
-pub mod combine;
-pub mod equate;
+mod bivariate;
+mod combine;
+mod equate;
 pub mod error_reporting;
-pub mod glb;
+mod glb;
 mod higher_ranked;
 pub mod lattice;
-pub mod lub;
+mod lub;
 pub mod region_inference;
 pub mod resolve;
 mod freshen;
-pub mod sub;
+mod sub;
 pub mod type_variable;
 pub mod unify_key;
 
@@ -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 @@ fn as_str(&self) -> &'static str {
             &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",
+        }
     }
 }
 
@@ -799,11 +821,10 @@ pub fn unsolved_variables(&self) -> Vec<ty::Ty<'tcx>> {
         return variables;
     }
 
-    fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
+    fn combine_fields(&'a self, trace: TypeTrace<'tcx>)
                       -> CombineFields<'a, 'gcx, 'tcx> {
         CombineFields {
             infcx: self,
-            a_is_expected: a_is_expected,
             trace: trace,
             cause: None,
             obligations: PredicateObligations::new(),
@@ -814,36 +835,36 @@ pub fn equate<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b
         -> InferResult<'tcx, T>
         where T: Relate<'tcx>
     {
-        let mut equate = self.combine_fields(a_is_expected, trace).equate();
-        let result = equate.relate(a, b);
-        result.map(|t| InferOk { value: t, obligations: equate.obligations() })
+        let mut fields = self.combine_fields(trace);
+        let result = fields.equate(a_is_expected).relate(a, b);
+        result.map(move |t| InferOk { value: t, obligations: fields.obligations })
     }
 
     pub fn sub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
         -> InferResult<'tcx, T>
         where T: Relate<'tcx>
     {
-        let mut sub = self.combine_fields(a_is_expected, trace).sub();
-        let result = sub.relate(a, b);
-        result.map(|t| InferOk { value: t, obligations: sub.obligations() })
+        let mut fields = self.combine_fields(trace);
+        let result = fields.sub(a_is_expected).relate(a, b);
+        result.map(move |t| InferOk { value: t, obligations: fields.obligations })
     }
 
     pub fn lub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
         -> InferResult<'tcx, T>
         where T: Relate<'tcx>
     {
-        let mut lub = self.combine_fields(a_is_expected, trace).lub();
-        let result = lub.relate(a, b);
-        result.map(|t| InferOk { value: t, obligations: lub.obligations() })
+        let mut fields = self.combine_fields(trace);
+        let result = fields.lub(a_is_expected).relate(a, b);
+        result.map(move |t| InferOk { value: t, obligations: fields.obligations })
     }
 
     pub fn glb<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
         -> InferResult<'tcx, T>
         where T: Relate<'tcx>
     {
-        let mut glb = self.combine_fields(a_is_expected, trace).glb();
-        let result = glb.relate(a, b);
-        result.map(|t| InferOk { value: t, obligations: glb.obligations() })
+        let mut fields = self.combine_fields(trace);
+        let result = fields.glb(a_is_expected).relate(a, b);
+        result.map(move |t| InferOk { value: t, obligations: fields.obligations })
     }
 
     fn start_snapshot(&self) -> CombinedSnapshot {
@@ -1468,104 +1489,50 @@ pub fn fully_resolve<T:TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<T> {
     // 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,
@@ -1646,8 +1613,8 @@ pub fn match_poly_projection_predicate(&self,
         };
 
         let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty));
-        let combine = self.combine_fields(true, trace);
-        let result = combine.higher_ranked_match(span, &match_pair, &match_b)?;
+        let mut combine = self.combine_fields(trace);
+        let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?;
         Ok(InferOk { value: result, obligations: combine.obligations })
     }
 
@@ -1833,14 +1800,16 @@ pub fn span(&self) -> Span {
             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 +1860,50 @@ pub fn span(&self) -> Span {
         }
     }
 }
+
+impl<'tcx> TypeFoldable<'tcx> for TypeOrigin {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
+        self.clone()
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
+        false
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        match *self {
+            ValuePairs::Types(ref ef) => {
+                ValuePairs::Types(ef.fold_with(folder))
+            }
+            ValuePairs::TraitRefs(ref ef) => {
+                ValuePairs::TraitRefs(ef.fold_with(folder))
+            }
+            ValuePairs::PolyTraitRefs(ref ef) => {
+                ValuePairs::PolyTraitRefs(ef.fold_with(folder))
+            }
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match *self {
+            ValuePairs::Types(ref ef) => ef.visit_with(visitor),
+            ValuePairs::TraitRefs(ref ef) => ef.visit_with(visitor),
+            ValuePairs::PolyTraitRefs(ref ef) => ef.visit_with(visitor),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        TypeTrace {
+            origin: self.origin.fold_with(folder),
+            values: self.values.fold_with(folder)
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.origin.visit_with(visitor) || self.values.visit_with(visitor)
+    }
+}
index 680dd0d63556b6fe661f51fb2ff0a9d164b6dab1..2f7f5254727db15d1f245be227498b046bc307fc 100644 (file)
 use ty::{self, Ty, TyCtxt};
 use ty::TyVar;
 use ty::relate::{Cause, Relate, RelateResult, TypeRelation};
-use traits::PredicateObligations;
 use std::mem;
 
 /// Ensures `a` is made a subtype of `b`. Returns `a` on success.
-pub struct Sub<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    fields: CombineFields<'a, 'gcx, 'tcx>,
+pub struct Sub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+    fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+    a_is_expected: bool,
 }
 
-impl<'a, 'gcx, 'tcx> Sub<'a, 'gcx, 'tcx> {
-    pub fn new(f: CombineFields<'a, 'gcx, 'tcx>) -> Sub<'a, 'gcx, 'tcx> {
-        Sub { fields: f }
+impl<'combine, 'infcx, 'gcx, 'tcx> Sub<'combine, 'infcx, 'gcx, 'tcx> {
+    pub fn new(f: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+        -> Sub<'combine, 'infcx, 'gcx, 'tcx>
+    {
+        Sub { fields: f, a_is_expected: a_is_expected }
     }
 
-    pub fn obligations(self) -> PredicateObligations<'tcx> {
-        self.fields.obligations
+    fn with_expected_switched<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
+        self.a_is_expected = !self.a_is_expected;
+        let result = f(self);
+        self.a_is_expected = !self.a_is_expected;
+        result
     }
 }
 
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Sub<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+    for Sub<'combine, 'infcx, 'gcx, 'tcx>
+{
     fn tag(&self) -> &'static str { "Sub" }
-    fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.infcx.tcx }
-    fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+    fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx }
+    fn a_is_expected(&self) -> bool { self.a_is_expected }
 
     fn with_cause<F,R>(&mut self, cause: Cause, f: F) -> R
         where F: FnOnce(&mut Self) -> R
@@ -56,10 +63,10 @@ fn relate_with_variance<T: Relate<'tcx>>(&mut self,
                                              -> RelateResult<'tcx, T>
     {
         match variance {
-            ty::Invariant => self.fields.equate().relate(a, b),
+            ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
             ty::Covariant => self.relate(a, b),
-            ty::Bivariant => self.fields.bivariate().relate(a, b),
-            ty::Contravariant => self.fields.switch_expected().sub().relate(b, a),
+            ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b),
+            ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }),
         }
     }
 
@@ -80,12 +87,11 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
             }
             (&ty::TyInfer(TyVar(a_id)), _) => {
                 self.fields
-                    .switch_expected()
-                    .instantiate(b, SupertypeOf, a_id)?;
+                    .instantiate(b, SupertypeOf, a_id, !self.a_is_expected)?;
                 Ok(a)
             }
             (_, &ty::TyInfer(TyVar(b_id))) => {
-                self.fields.instantiate(a, SubtypeOf, b_id)?;
+                self.fields.instantiate(a, SubtypeOf, b_id, self.a_is_expected)?;
                 Ok(a)
             }
 
@@ -116,6 +122,6 @@ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
                   -> RelateResult<'tcx, ty::Binder<T>>
         where T: Relate<'tcx>
     {
-        self.fields.higher_ranked_sub(a, b)
+        self.fields.higher_ranked_sub(a, b, self.a_is_expected)
     }
 }
index fa9bc7c83680c45009f1bf09f72685b38d7e1f09..5901c42b525826881c2746a00e16c45c9bed4847 100644 (file)
@@ -126,20 +126,14 @@ pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
                                                    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 @@ pub fn span_err_or_warn<S: Into<MultiSpan>>(&self, is_warning: bool, sp: S, msg:
         }
     }
     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
-        match split_msg_into_multilines(msg) {
-            Some(msg) => self.diagnostic().span_err(sp, &msg),
-            None => self.diagnostic().span_err(sp, msg)
-        }
+        self.diagnostic().span_err(sp, msg)
     }
     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
-        match split_msg_into_multilines(msg) {
-            Some(msg) => self.diagnostic().span_err_with_code(sp, &msg, code),
-            None => self.diagnostic().span_err_with_code(sp, msg, code)
-        }
+        self.diagnostic().span_err_with_code(sp, &msg, code)
     }
     pub fn err(&self, msg: &str) {
         self.diagnostic().err(msg)
@@ -343,67 +331,6 @@ pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch {
     }
 }
 
-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>,
index 3b9ecb88258540cd011bb543b07be1a8bd5145e7..67ad887530eb318ccabe450784dc9480e11e5297 100644 (file)
@@ -26,8 +26,9 @@
 
 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 @@ fn report_projection_error(&self,
         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,
index 1e2920ca87ea6d712b3a2f64839160f1fcc7a542..16a54c20925deda7b8417a3747be29e6e0289bec 100644 (file)
@@ -1018,3 +1018,16 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         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)
+    }
+}
index 2163a8a1689b601e7240806ed25563cf88294852..99bc26848025ec0ec030a28776c5b3634226a455 100644 (file)
@@ -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
+            }
         }
     )
 }
index 01872bbe3c04996a87089b757b494c253dd42c3d..8967672548b101b3b35a01f04b8207ab8b5d1198 100644 (file)
@@ -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
index 0de00d9d7f631edc634f6b757ac106361f1a5062..915a0cf0bdc7301ecda143b9d51745a827453b37 100644 (file)
@@ -17,6 +17,7 @@
 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 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,
             }
         }
 
index f2abdf831a3b8fdbdae8c6033bbc17085e38b3cc..45414c33c075448640ef116443fcaf58f23d4e0d 100644 (file)
@@ -551,44 +551,46 @@ enum Method { GET, POST }
 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)
 }
index a3c707e82a0ff45e45be5c74e951c184296f8cb5..dd21bb17a2da95e810945c02d3f3f0323e2fcb15 100644 (file)
@@ -25,6 +25,7 @@
 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::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 @@ fn from(err: ConstMathErr) -> 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())
             },
         }
     }
@@ -1105,11 +1181,25 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty)
         Float(f) => cast_const_float(tcx, f, ty),
         Char(c) => cast_const_int(tcx, Infer(c as u64), ty),
         Function(_) => Err(UnimplementedConstVal("casting fn pointers")),
-        ByteStr(_) => match ty.sty {
+        ByteStr(b) => match ty.sty {
             ty::TyRawPtr(_) => {
                 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
             },
-            ty::TyRef(..) => Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice")),
+            ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
+                ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)),
+                ty::TySlice(_) => {
+                    Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
+                },
+                _ => Err(CannotCast),
+            },
+            _ => Err(CannotCast),
+        },
+        Str(s) => match ty.sty {
+            ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")),
+            ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
+                ty::TyStr => Ok(Str(s)),
+                _ => Err(CannotCast),
+            },
             _ => Err(CannotCast),
         },
         _ => Err(CannotCast),
@@ -1185,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)),
@@ -1194,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)
         }
     }
 }
index 726ba4fc1924fd48f3b3fc25b7c0d38df381c0f3..a6714c178e7cf68c46e750891dd39703f285c401 100644 (file)
@@ -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
index ab3b20e08c8099130c1b5c3a874a519f9b29fddb..9a94cc16bfe8ceda4709be95262b1a6ff4cdc001 100644 (file)
@@ -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();
+}
index 6a48f65714cc50d95e6463d337ec64af32233dd1..610e5647d6d12893547923c65d361474d0914c00 100644 (file)
@@ -531,10 +531,12 @@ pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
         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();
     }
index 27ce03b2d9390c8c250f921282b072a33e3961c0..b0ba38f1db67322d33aa51dac8e0d5fd41f26492 100644 (file)
@@ -40,6 +40,7 @@
 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 @@ fn global_expr(&mut self, mode: Mode, expr: &hir::Expr) -> ConstQualif {
                 _ => 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 @@ fn record_borrow(&mut self, id: ast::NodeId, mutbl: hir::Mutability) {
             }
         }
     }
-
-    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 @@ fn visit_pat(&mut self, p: &hir::Pat) {
                 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 @@ fn visit_expr(&mut self, ex: &hir::Expr) {
                 Err(msg) => {
                     self.tcx.sess.add_lint(CONST_ERR, ex.id,
                                            msg.span,
-                                           msg.description().into_owned())
+                                           msg.description().into_oneline().into_owned())
                 }
             }
         }
index 918e17d21ea998e35ca91df67c1115bd564d70a9..a616b95ef7203ad312ba54a6a6af4c127d907aca 100644 (file)
@@ -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 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
index aa8c706ea1e27b9cb73978f7248864c3627ee7e8..88cd29a3ccfa721b11e0dc0df3a1a988dbf09158 100644 (file)
@@ -2274,7 +2274,7 @@ fn resolve_pattern_path<ExpectedFn>(&mut self,
         let resolution = if let Some(resolution) = self.resolve_possibly_assoc_item(pat_id,
                                                                         qself, path, namespace) {
             if resolution.depth == 0 {
-                if expected_fn(resolution.base_def) {
+                if expected_fn(resolution.base_def) || resolution.base_def == Def::Err {
                     resolution
                 } else {
                     resolve_error(
@@ -2345,7 +2345,7 @@ fn resolve_pattern(&mut self,
                                 );
                                 None
                             }
-                            Def::Local(..) | Def::Upvar(..) | Def::Fn(..) => {
+                            Def::Local(..) | Def::Upvar(..) | Def::Fn(..) | Def::Err => {
                                 // These entities are explicitly allowed
                                 // to be shadowed by fresh bindings.
                                 None
index e7cc534c5b55537d45dce95db500d26e160e6625..0fd95500422ff193af8a29aa1f8ea615657eb775 100644 (file)
@@ -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)
index 08e894ffbcfd48c4e37fde4d75f6565713c79f80..f7fd970f37f2f89e1a4686f541ef9ea5984343bc 100644 (file)
 
 use llvm::{ValueRef, BasicBlockRef};
 use rustc_const_eval::check_match::{self, Constructor, StaticInliner};
-use rustc_const_eval::{compare_lit_exprs, eval_const_expr};
+use rustc_const_eval::{compare_lit_exprs, eval_const_expr, fatal_const_eval_err};
 use rustc::hir::def::{Def, DefMap};
 use rustc::hir::def_id::DefId;
 use middle::expr_use_visitor as euv;
 
 impl<'a> ConstantExpr<'a> {
     fn eq<'b, 'tcx>(self, other: ConstantExpr<'a>, tcx: TyCtxt<'b, 'tcx, 'tcx>) -> bool {
-        match compare_lit_exprs(tcx, self.0, other.0) {
-            Some(result) => result == Ordering::Equal,
-            None => bug!("compare_list_exprs: type mismatch"),
+        match compare_lit_exprs(tcx, self.0.span, self.0, other.0) {
+            Ok(result) => result == Ordering::Equal,
+            Err(_) => bug!("compare_list_exprs: type mismatch"),
         }
     }
 }
@@ -288,7 +288,9 @@ fn trans<'blk>(&self, mut bcx: Block<'blk, 'tcx>) -> OptResult<'blk, '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 @@ fn trans<'blk>(&self, mut bcx: Block<'blk, 'tcx>) -> OptResult<'blk, '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))
             }
index 00feb2cd1de0961f5ec1e97965ea1480d3ee3543..f662ba75cc6fea7c5e4f014d30e4c69ba67171f8 100644 (file)
@@ -14,7 +14,7 @@
 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::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 @@ fn into_inner(self) -> ConstEvalErr {
             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 {
index a721361fce0e3aecbbd152edb8fd663507383df3..e657a086581e2dadfff30deedc5c7a07288b6861 100644 (file)
@@ -44,6 +44,7 @@
 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;
@@ -1193,11 +1194,17 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         // managed by the standard library.
 
         attributes::emit_uwtable(bcx.fcx.llfn, true);
-        let catch_pers = match tcx.lang_items.eh_personality_catch() {
-            Some(did) => {
-                Callee::def(ccx, did, tcx.mk_substs(Substs::empty())).reify(ccx).val
+        let target = &bcx.sess().target.target;
+        let catch_pers = if target.arch == "arm" && target.target_os != "ios" {
+            // Only ARM still uses a separate catch personality (for now)
+            match tcx.lang_items.eh_personality_catch() {
+                Some(did) => {
+                    Callee::def(ccx, did, tcx.mk_substs(Substs::empty())).reify(ccx).val
+                }
+                None => bug!("eh_personality_catch not defined"),
             }
-            None => bug!("eh_personality_catch not defined"),
+        } else {
+            bcx.fcx.eh_personality()
         };
 
         let then = bcx.fcx.new_temp_block("then");
@@ -1408,7 +1415,10 @@ macro_rules! require_simd {
                                          // 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]
index da72793abf6dab869a558e9993e7362c342ef916..1f3b13203163f7fbf6cbab2ea681e6fea84572f7 100644 (file)
@@ -925,7 +925,7 @@ pub fn trans_constant(&mut self,
             }
             Err(ConstEvalFailure::Runtime(err)) => {
                 span_bug!(constant.span,
-                          "MIR constant {:?} results in runtime panic: {}",
+                          "MIR constant {:?} results in runtime panic: {:?}",
                           constant, err.description())
             }
         }
index 8b8e658533ed09db43dad823f5e6914d7901ef2c..fc95d208f32ccdda8c926e2be3a03e1a6c11eb95 100644 (file)
@@ -29,6 +29,7 @@
 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 @@ pub fn define(&self, ccx: &CrateContext<'a, '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")
index f5b9bef5313f23a34039747e79d6f0c634ffd88e..92a2d3787bfd6b60bc5184233f24893e10e91ab3 100644 (file)
@@ -30,7 +30,7 @@
 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")
     }
index 9ff30f9ede26295d85f4e94c853d817ce3bf3d84..b642a7122194de3059babc25f116b8725dbd31a1 100644 (file)
 //! 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 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 @@ pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
                 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) => {
index e90b32cd5dfc0192c5001b46a8dc2795acab7f39..aae6e3ad36dfe7ee2ba7b1ec173cd2d3f8193a82 100644 (file)
@@ -103,15 +103,6 @@ pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'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 @@ pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'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);
index 2c7e7d284fa160250de1ba5b9e7b71c37be092b7..9c6727ebbfcf955d30f6507ef5b1719b3b5314d5 100644 (file)
@@ -216,7 +216,7 @@ fn confirm_builtin_call(&self,
             _ => {
                 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;
index 22ac8bc56907bfd9578e94134ea0ea1ad3117c50..7a4cc09a7d5064d3a9ac408103df64cdf885dca3 100644 (file)
@@ -149,7 +149,7 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) {
                     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 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) {
             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 @@ fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'gcx, '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 @@ fn type_is_known_to_be_sized(&self,
         traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span)
     }
 }
-
index 35a5bc9c60967d69512b3b573d26b903e59ce187..9844377d0bd32f5241c1e0cb948f48597c1d5673 100644 (file)
@@ -12,6 +12,7 @@
 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();
         }
     });
 }
index eeebd6a7f626b74160e7c2d4c27d1844cc3bd5db..1f3a83ebc1d567da7a2ae7174213e62feaafd451 100644 (file)
@@ -33,7 +33,14 @@ pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'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 @@ pub fn demand_coerce(&self, expr: &hir::Expr, expected: Ty<'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
-        }
-    }
 }
index 5a3268e9e447b25a9165c02eec623c5f6164cedd..8a53c59b4c7fad08dafbe1215cb6d8bf52914885 100644 (file)
@@ -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);
     }
 }
 
index f20dcdc35aea5c7af46ded13c2b84800a42ddc63..346449d0a51331465bde2b99b5eec3048bb74e7c 100644 (file)
@@ -160,8 +160,7 @@ pub fn report_method_error(&self,
                                 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) {
index fc1d2236f3feaa07c63c5e99e424500bc5704b53..6062bd048b3d27f8972edfbdce5efa766c448aab 100644 (file)
 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 @@ fn parameter_count_error<'tcx>(sess: &Session, sp: Span, fn_inputs: &[Ty<'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 @@ fn parameter_count_error<'tcx>(sess: &Session, sp: Span, fn_inputs: &[Ty<'tcx>],
                                                 |t| {
                             format!("can't pass `{}` to variadic \
                                      function, cast to `{}`", t, ptr_ty)
-                        }, arg_ty, None);
+                        }, arg_ty);
                     }
                     _ => {}
                 }
@@ -2908,9 +2908,8 @@ fn check_field(&self,
             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 @@ fn check_field(&self,
                 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 @@ fn check_tup_field(&self,
                                     actual)
                 }
             },
-            expr_t, None);
+            expr_t);
 
         self.write_error(expr.id);
     }
@@ -3029,17 +3028,18 @@ fn report_unknown_field(&self,
                             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 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
                             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 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
           }
           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 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
                                   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 @@ fn structurally_resolve_type_or_else<F>(&self, sp: Span, ty: Ty<'tcx>, f: F)
                 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;
index 8604dadf46dff2f4011aa22f67fb948f0a634ea0..d02f87d0b9cd64236700279cd10bfc1744f0c7af 100644 (file)
@@ -239,7 +239,7 @@ pub fn check_user_unop(&self,
                 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
             }
         }
index d101381e2565c72823332aefc602e721c228bfb8..907cb734c2ff9f00128641761e20eb9543b323fe 100644 (file)
@@ -13,6 +13,7 @@
 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 @@ fn check_item_well_formed(&mut self, item: &hir::Item) {
         }
     }
 
-    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 @@ fn check_trait_or_impl_item(&mut self, item_id: ast::NodeId, span: Span) {
                     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 @@ fn check_fn_or_method<'fcx, 'tcx>(&mut self,
 
     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 @@ fn check_method_receiver<'fcx, 'tcx>(&mut self,
             }
             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 @@ fn visit_item(&mut self, i: &hir::Item) {
 
     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)
     }
 }
index 41e7a467fa33a89ff80aa890306ccdaf63d1b511..57602b55cc96f10e5bb4110692cd481c361bdf95 100644 (file)
@@ -66,8 +66,7 @@
 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 evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr)
             },
             // 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
             }
index 8769bc1a32b5080856297c7f7928c14e8b3eeb32..500f624ea3f72f870eece3b65108997dfc74f6f7 100644 (file)
@@ -1079,25 +1079,6 @@ fn get_str(&self) -> &'static str {
 ```
 "##,
 
-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 @@ impl<P1, ..., Pm> ForeignTrait<T1, ..., Tn> for T0 { ... }
 [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 @@ fn x(self: Box<Foo>) {} // ok!
 }
 ```
 "##,
+     */
 
 E0214: r##"
 A generic type was described using parentheses rather than angle brackets. For
@@ -2968,38 +2951,6 @@ fn do_something(x: Foo::Bar) { }
 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 @@ fn fly(&self) {} // And now that's ok!
 ```
 "##,
 
+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 @@ fn fly(&self) {} // And now that's ok!
     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
index 84452589dfda389a9bc7e708c55dc16f9f497e9f..3b2d02dc861c4c62c0b8542f0b3f0da67eddbef8 100644 (file)
@@ -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,
index 7e308684a25673cb49afe6b9fa690fecc62075ce..81856cb87c7c40cdb1debe42f633caaec0ad43f9 100644 (file)
@@ -427,7 +427,7 @@ pub fn len_utf16(self) -> usize {
         C::len_utf16(self)
     }
 
-    /// Returns an interator over the bytes of this character as UTF-8.
+    /// Returns an iterator over the bytes of this character as UTF-8.
     ///
     /// The returned iterator also has an `as_slice()` method to view the
     /// encoded bytes as a byte slice.
@@ -450,7 +450,7 @@ pub fn encode_utf8(self) -> EncodeUtf8 {
         C::encode_utf8(self)
     }
 
-    /// Returns an interator over the `u16` entries of this character as UTF-16.
+    /// Returns an iterator over the `u16` entries of this character as UTF-16.
     ///
     /// The returned iterator also has an `as_slice()` method to view the
     /// encoded form as a slice.
index 2e2fc011ddbe6c3198c0ac3dafb6e144e471769f..e4e886c85334771b60c5a655ca0340e6d5e38579 100644 (file)
@@ -2409,10 +2409,13 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
            if structhead {"struct "} else {""},
            it.name.as_ref().unwrap())?;
     if let Some(g) = g {
-        write!(w, "{}{}", *g, WhereClause(g))?
+        write!(w, "{}", g)?
     }
     match ty {
         doctree::Plain => {
+            if let Some(g) = g {
+                write!(w, "{}", WhereClause(g))?
+            }
             write!(w, " {{\n{}", tab)?;
             for field in fields {
                 if let clean::StructFieldItem(ref ty) = field.inner {
@@ -2445,9 +2448,17 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
                     _ => unreachable!()
                 }
             }
-            write!(w, ");")?;
+            write!(w, ")")?;
+            if let Some(g) = g {
+                write!(w, "{}", WhereClause(g))?
+            }
+            write!(w, ";")?;
         }
         doctree::Unit => {
+            // Needed for PhantomData.
+            if let Some(g) = g {
+                write!(w, "{}", WhereClause(g))?
+            }
             write!(w, ";")?;
         }
     }
index a03249e0063568b38ec49ee378e021a8d6b72c2f..fd7b0a2e6bbf6d9b0d8834c911e7dca320c7c298 100644 (file)
@@ -877,7 +877,7 @@ pub fn values(&self) -> Values<K, V> {
     /// }
     ///
     /// for val in map.values() {
-    ///     print!("{}", val);
+    ///     println!("{}", val);
     /// }
     /// ```
     #[stable(feature = "map_values_mut", since = "1.10.0")]
@@ -1336,6 +1336,10 @@ fn into_entry(self, key: K) -> Option<Entry<'a, 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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 /// 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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 /// 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 @@ pub fn or_insert(self, default: V) -> &'a mut 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 @@ pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut 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 @@ pub fn key(&self) -> &K {
 
 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 @@ pub fn insert(&mut self, mut value: V) -> 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 @@ fn take_key(&mut self) -> Option<K> {
 
 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 {
@@ -1699,6 +1892,17 @@ fn extend<T: IntoIterator<Item=(&'a K, &'a V)>>(&mut self, iter: T) {
 /// A particular instance `RandomState` will create the same instances of
 /// `Hasher`, but the hashers created by two different `RandomState`
 /// instances are unlikely to produce the same result for the same values.
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashMap;
+/// use std::collections::hash_map::RandomState;
+///
+/// let s = RandomState::new();
+/// let mut map = HashMap::with_hasher(s);
+/// map.insert(1, 2);
+/// ```
 #[derive(Clone)]
 #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
 pub struct RandomState {
@@ -1708,6 +1912,14 @@ pub struct RandomState {
 
 impl RandomState {
     /// Constructs a new `RandomState` that is initialized with random keys.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::hash_map::RandomState;
+    ///
+    /// let s = RandomState::new();
+    /// ```
     #[inline]
     #[allow(deprecated)] // rand
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
index 95aa6468dd9a6b9028612285b21fb3d6c204a864..d6d62ce79d4e6ff94aa780736adcce7d8b9da3ba 100644 (file)
@@ -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 {
index c28f70b8692ad7a739e1b8a83e3564bac642ba07..48753ccf1c353cfe8ba172dbb347cf47c54f4f5e 100644 (file)
@@ -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 File {
 
 /// 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 File {
 
 /// 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 @@ pub fn open<P: AsRef<Path>>(path: P) -> io::Result<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 @@ pub fn sync_all(&self) -> io::Result<()> {
         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 @@ pub fn sync_all(&self) -> io::Result<()> {
     /// 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 @@ pub fn metadata(&self) -> io::Result<Metadata> {
     /// 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 @@ pub fn path(&self) -> PathBuf { self.0.path() }
     /// 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 @@ pub fn metadata(&self) -> io::Result<Metadata> {
     /// On Windows and most Unix platforms this function is free (no extra
     /// system calls needed), but some Unix platforms may require the equivalent
     /// call to `symlink_metadata` to learn about the target file type.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fs;
+    ///
+    /// if let Ok(entries) = fs::read_dir(".") {
+    ///     for entry in entries {
+    ///         if let Ok(entry) = entry {
+    ///             // Here, `entry` is a `DirEntry`.
+    ///             if let Ok(file_type) = entry.file_type() {
+    ///                 // Now let's show our entry's file type!
+    ///                 println!("{:?}: {:?}", entry.path(), file_type);
+    ///             } else {
+    ///                 println!("Couldn't get file type for {:?}", entry.path());
+    ///             }
+    ///         }
+    ///     }
+    /// }
+    /// ```
     #[stable(feature = "dir_entry_ext", since = "1.1.0")]
     pub fn file_type(&self) -> io::Result<FileType> {
         self.0.file_type().map(FileType)
@@ -851,6 +926,21 @@ pub fn file_type(&self) -> io::Result<FileType> {
 
     /// Returns the bare file name of this directory entry without any other
     /// leading path component.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fs;
+    ///
+    /// if let Ok(entries) = fs::read_dir(".") {
+    ///     for entry in entries {
+    ///         if let Ok(entry) = entry {
+    ///             // Here, `entry` is a `DirEntry`.
+    ///             println!("{:?}", entry.file_name());
+    ///         }
+    ///     }
+    /// }
+    /// ```
     #[stable(feature = "dir_entry_ext", since = "1.1.0")]
     pub fn file_name(&self) -> OsString {
         self.0.file_name()
@@ -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 @@ pub fn new() -> 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;
index bb90a977433e0c5f2c37db74c1ffe8817e08c8d7..54340773a42b52e5bb672e41edde061cc487f769 100644 (file)
@@ -196,6 +196,22 @@ fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) }
 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;
 }
index a784741c88cc7f3536857065b6490db772e82dc1..6f1b70acb60bc35c3c9f5dfc0cc60c71403bcf76 100644 (file)
@@ -67,7 +67,7 @@ pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<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 @@ pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, 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]))));
index 63e13f0bb473849c6b8073190fcc8d8158fb9bc5..4c3558f91f5f22e65cf3c3892f45af47576e9a60 100644 (file)
@@ -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.
index 32ca32e76cb626aee457870c00020279bf5d5127..0cea7f81e363237fa745023505916db18df864fc 100644 (file)
@@ -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() }
 }
index ff75149f518abd8c1f16c65519abdb072bffb924..a825cf866a878309eeac575eca99db0a140c079d 100644 (file)
@@ -124,7 +124,7 @@ pub fn strip_unconfigured_items(mut krate: ast::Crate, sess: &ParseSess, should_
         };
 
         let err_count = sess.span_diagnostic.err_count();
-        let krate_attrs = strip_unconfigured.process_cfg_attrs(krate.attrs.clone());
+        let krate_attrs = strip_unconfigured.configure(krate.attrs.clone()).unwrap_or_default();
         features = get_features(&sess.span_diagnostic, &krate_attrs);
         if err_count < sess.span_diagnostic.err_count() {
             krate.attrs = krate_attrs.clone(); // Avoid reconfiguring malformed `cfg_attr`s
index 7c0d10669f30e108e6e173510ebbd2a9e8fc601c..29a300b172e7562972aa22a645dfbff63ee05999 100644 (file)
@@ -14,7 +14,7 @@
 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(..) => {
index 125f1abb062bf2966b17a31cb428edd4a8fe6620..c143e190c6fc16ce814c785d88aab8e0d5889974 100644 (file)
@@ -258,6 +258,7 @@ pub struct Parser<'a> {
     pub tokens_consumed: usize,
     pub restrictions: Restrictions,
     pub quote_depth: usize, // not (yet) related to the quasiquoter
+    parsing_token_tree: bool,
     pub reader: Box<Reader+'a>,
     /// The set of seen errors about obsolete syntax. Used to suppress
     /// extra detail when the same error is seen twice
@@ -374,6 +375,7 @@ pub fn new(sess: &'a ParseSess,
             tokens_consumed: 0,
             restrictions: Restrictions::empty(),
             quote_depth: 0,
+            parsing_token_tree: false,
             obsolete_set: HashSet::new(),
             mod_path_stack: Vec::new(),
             filename: filename,
@@ -2663,7 +2665,7 @@ fn parse_unquoted(&mut self) -> PResult<'a, TokenTree> {
     }
 
     pub fn check_unknown_macro_variable(&mut self) {
-        if self.quote_depth == 0 {
+        if self.quote_depth == 0 && !self.parsing_token_tree {
             match self.token {
                 token::SubstNt(name) =>
                     self.fatal(&format!("unknown macro variable `{}`", name)).emit(),
@@ -2723,6 +2725,7 @@ pub fn parse_token_tree(&mut self) -> PResult<'a, TokenTree> {
                 Err(err)
             },
             token::OpenDelim(delim) => {
+                let parsing_token_tree = ::std::mem::replace(&mut self.parsing_token_tree, true);
                 // The span for beginning of the delimited section
                 let pre_span = self.span;
 
@@ -2787,6 +2790,7 @@ pub fn parse_token_tree(&mut self) -> PResult<'a, TokenTree> {
                     _ => {}
                 }
 
+                self.parsing_token_tree = parsing_token_tree;
                 Ok(TokenTree::Delimited(span, Rc::new(Delimited {
                     delim: delim,
                     open_span: open_span,
index 0ad09fd0f7dfba492e8146a64a17ed0a25eb1f69..d38edf816880e1e44d9aa81ab93a4ba20b427257 100644 (file)
@@ -135,6 +135,7 @@ pub fn len(&self) -> usize {
             }
             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 @@ pub fn get_tt(&self, index: usize) -> 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"),
         }
index 7dfe19452a2a933a64cdd849e2a21ce535880f50..c96be8fec2b02abb4ffffecddaa0884187641303 100644 (file)
@@ -193,20 +193,6 @@ pub fn new() -> MultiSpan {
         }
     }
 
-    pub fn from_span(primary_span: Span) -> MultiSpan {
-        MultiSpan {
-            primary_spans: vec![primary_span],
-            span_labels: vec![]
-        }
-    }
-
-    pub fn from_spans(vec: Vec<Span>) -> MultiSpan {
-        MultiSpan {
-            primary_spans: vec,
-            span_labels: vec![]
-        }
-    }
-
     pub fn push_span_label(&mut self, span: Span, label: String) {
         self.span_labels.push((span, label));
     }
@@ -254,7 +240,10 @@ pub fn span_labels(&self) -> Vec<SpanLabel> {
 
 impl From<Span> for MultiSpan {
     fn from(span: Span) -> MultiSpan {
-        MultiSpan::from_span(span)
+        MultiSpan {
+            primary_spans: vec![span],
+            span_labels: vec![]
+        }
     }
 }
 
index aadfe202afe796ba6d05257e5df80196e0aff51d..d9b6c9ed74dd21b4fec9ec88ebbce37b27990ea3 100644 (file)
@@ -58,6 +58,7 @@ pub enum _Unwind_Reason_Code {
 pub type _Unwind_Exception_Class = u64;
 
 pub type _Unwind_Word = libc::uintptr_t;
+pub type _Unwind_Ptr = libc::uintptr_t;
 
 pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut libc::c_void)
                                           -> _Unwind_Reason_Code;
@@ -156,6 +157,13 @@ pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
                              ip_before_insn: *mut libc::c_int)
                              -> libc::uintptr_t;
 
+    pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+    pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+    pub fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+    pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+    pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: libc::c_int, value: _Unwind_Ptr);
+    pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Ptr);
+
     #[cfg(all(not(target_os = "android"),
               not(all(target_os = "linux", target_arch = "arm"))))]
     pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) -> *mut libc::c_void;
index 4def60e485f7e0a05635c3648f5edf0669ea535a..0b2287cf233d15becbf9d5da283d62194d473483 100644 (file)
@@ -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",
index e65230389f9c0412297a2d5fa95c25934e1ada3b..501c66e75cded115892fddfe02c0be9588b0c9c0 100644 (file)
@@ -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;
index 69d84e24c4982db2c7d5549461b425eb2f74a4b3..d3b43e83bfe5218ac914584e6424f6fd4ee4a9d4 100644 (file)
@@ -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;
index 5d8007defc9065d15bc3db1b33929f31ba56e11e..0239986f5ad3aef5dfe5886ed2f142bc93c902e1 100644 (file)
@@ -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);
index 4658d0f057d71c85aeeab2c9040bf4fd2c92bf40..95508a31044b87797dff021bc5a6a07b23cd2ff9 100644 (file)
@@ -18,9 +18,8 @@ trait Foo {
 
 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() {}
index 2f687350f34e0bcd30b266f42fd7fa05854ccc77..c3fa39659b968217fb83481c75edea49d0855a37 100644 (file)
@@ -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() {
index 8c66160e8a36f723c0a16c017d2956a83814f8fe..cb952f6534f0e57da26b0e45b6d91a14c64be083 100644 (file)
@@ -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 (file)
index 0000000..12341fa
--- /dev/null
@@ -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
+}
index faabed4fd5e422d5f73ba2a92fc8b705848d8c72..b980bc02c85a24fb22a4d7cb0e161768a0b858fa 100644 (file)
@@ -16,7 +16,8 @@
 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;
index 1143d3bd5cd96491e1e5c5116eef414e01843d5a..7e2eabf412d6c2683646b19a0bdb27c4e65c4a21 100644 (file)
@@ -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
 }
index a1d3888e78ea0dc16fe3d9cd6bd454a0764fc51e..f2079800cad311e624ee9ca644603877889353d1 100644 (file)
@@ -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);
index 07e27a7dc9a9a412b2eb14155044584b7980c325..4749457da8814ba89b294c624f1397770bb495ae 100644 (file)
 
 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"),
     }
 }
index c90ae045f96b4aa0430e2b3c020f47d33caeba1a..c78c74e9e231b5d8ccfdfbf1b2b250c6e1e4afba 100644 (file)
@@ -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)]
 
index 31e1a72967f4dcf4860574ce6f563503a3d2637d..9e7a5ecae105a2b123a51519f20a2944b26bfe6a 100644 (file)
@@ -20,9 +20,8 @@
 
 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_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() {}
index 3dfcb5bb29a24a68701b48d195f62aca3361240c..c1c693544fa96e7fd224ebdeceb01341a3894d2e 100644 (file)
 
 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() {
index 9fdd24c42fdbd48447d526393e541ac19312c354..73351429b50608b770bb11571880aa364e46d666 100644 (file)
@@ -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,
index 45a00de48e71210b697b9b820c00af3a973e8dc9..dd0f058f2c95c06909e2132d64902b6a1d5c7970 100644 (file)
@@ -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
 }
index 09822e46cc1abddae32cc258e101ce57e5c27989..4f92770df289c50c57c43c58e163158ddea6fdc7 100644 (file)
@@ -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() {
 }
index 0d6cf3bab453fac0892aca6ff79efa9986f75507..5dadd892f83520cca532436ce88986e7b4649476 100644 (file)
@@ -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;
index 9c6b774b99039811fb6482e80d2e98c649f5f6aa..43375ee3d18968e83645b150088189cdfef4a9ea 100644 (file)
@@ -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!();
index d51f31087d0df1494c5cce1005433e6839109a92..e338f206553b422110dc9086c5190878b02f91c5 100644 (file)
@@ -16,5 +16,6 @@
 
 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
 }
index 4567cd4a74bb2a3ae343d9aea7679b1c8324e0fa..d68d63683a79cc6b2db9beddf7f4ad236bb39ae0 100644 (file)
@@ -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"),
     }
index d63b0097e5a0ce3fe0dc5ae0bdc7a66d2fefc212..b1b4bfe2d1c39a1e2a08a9e76117699d1e1d854c 100644 (file)
@@ -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;
index 9d3c432d14878de269cf86ba9616dc7cc7c9d7af..6f095b3041ffedc833eef1b3ecc985f809ca60d9 100644 (file)
@@ -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() {
index 23106c99594a6f69e7f2c0ba3734453145a1df19..c73b7e831b3217051eb1eef9b64372af92abda81 100644 (file)
@@ -25,7 +25,8 @@ enum A {
         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 @@ enum A {
         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 @@ enum A {
         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 @@ enum A {
         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 @@ enum A {
         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 @@ enum A {
         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 @@ enum A {
         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 @@ enum A {
         Ok = u64::MAX - 1,
         Ok2,
         OhNo = 0_i64,
-        //~^ ERROR mismatched types
+        //~^ ERROR E0080
+        //~| expected u64, found i64
     }
 
     let x = A::Ok;
index d6ba09bb4c5bf072692b9677f3f4883dc99e4951..bbdb3891d99807dbd989d231ddbcdfbb3805993c 100644 (file)
 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
index 7ca274b81e574a5c6cf6962b926ddfb3ceff5b05..57db583aefe2355cb46bde8df1027c98637b18e7 100644 (file)
@@ -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() {}
index b5432fafb1b855f0b09cb6a1a2634b847673acc8..f8aa1ea95f0f66d51039d8bb09d1c11502bf1ec2 100644 (file)
@@ -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() {}
index 05b194345d40534692d57eaa4072262d765c46e7..89ae1a09bd3e47b2eca8b28e006031c79d1b5f72 100644 (file)
@@ -18,14 +18,17 @@ fn neg(self) -> u32 { 0 }
 
 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
 }
index 3c4ad5a56ec362ba221e64cf879cd5ea3acf2616..9a9358b787f5386cbebd0231958212dc4c61fc4d 100644 (file)
@@ -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
 }
index 43cf70e5bc3cf086cefb00fcac577b41ec5ac266..3d9d81471cb1e40da806c9348464d193ff9cfa98 100644 (file)
@@ -16,7 +16,9 @@ trait Foo {
 
 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() {}
index 42e3456b309be35585a6ed39181eaebbb63aa745..da48bbb3ecd711a99a730cf859ec74f17bc9cc06 100644 (file)
@@ -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);
     }
 }
index 6b9294b2038f18fff4070765df96e8d574a31605..664d62e87ae61cf2f61a5f45d308275ce6f60856 100644 (file)
@@ -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
index b36918149fa99008b7fd5d7560a63ad82081b759..db3334834d44ec97e5230755df303f1f2e0b4a65 100644 (file)
@@ -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() {}
index 7d619c270d32b962913e7999a206a1c0fa38762a..54a24089354614f05c4e90e04e1e3bdce16fba17 100644 (file)
@@ -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() {}
index 32cdd6b5ed9f20a5dc1e1d3ab74c915166331fd8..c2bcbb9d54a9a447c1f5c0bf873d8a8542226f4a 100644 (file)
@@ -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() {}
index 27d46be40fbeb69bbe96b617eff5dce36c28d484..ede81bea32ae3bfaea3db5168a4ea23f2ed19a1d 100644 (file)
@@ -30,9 +30,6 @@ fn deref(&self) -> &i8 { &self.0 }
         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);
index e8a9c8d2ea34bc06e6c6225e84419b2e2a9777ff..93f75e9bfed0dddc09f23fbcede1fcad238e351a 100644 (file)
@@ -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() {}
index bdcbaf09177fe8c2e53c0aeb82262de6890e0a98..ee6ec52761266607887eef14302a41e2102c6278 100644 (file)
@@ -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
 }
index 3b3abc94a4900f391d2746a17dab1e1d74398bac..ca8d5a1f70473563b3badf884ffd97d5ae67111a 100644 (file)
@@ -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"),
     }
 }
index c8a1e424da2e2c71a2f0e09d3acdc5583b39948a..1dfd146985ff48a8df17ee421986e27306637c67 100644 (file)
@@ -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 (file)
index 0000000..fb1e3cc
--- /dev/null
@@ -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() {}
index 52375ef281ace24513c5f70d46257acd5512d401..1b6e4b1d289e42d31c25c39983f188e578c87c18 100644 (file)
@@ -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);
index 1c98abce0304e149f092ea7e0a4137c0cac303d5..91a07dd9ba6dd68ede4d5bf9129a180f1d579d89 100644 (file)
 
 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() {}
index e34a3c4569d0a4c451d053ff13837bd0e9c7abad..6da87fca3f35606fe3398f127a626adc751dd763 100644 (file)
@@ -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 (file)
index 0000000..f41da77
--- /dev/null
@@ -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
index 526aa83dec7fd2410b4539818b2265c5cbf91256..2c4c2563021867ddbd6c305f1500b60c6971a5e4 100644 (file)
@@ -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`
 }
index 9564a080b8ee7d6ca7f8c8dbb04d125921408ba9..cadfec5a38d3d9fbdc27d1569013b31482708da2 100644 (file)
@@ -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
 }
index 3ce206ff7fb2c0c13b1a5a7b1079aa2e65e9a16d..a6f88a57b9125846a8f5ba8b52a91b18f7157736 100644 (file)
@@ -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
     }
 }
index ee88168515d39f5a7319f21a7527177c3584e985..737f80372debf55c8e99bba7cd5970b199dea579 100644 (file)
@@ -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
     };
 }
index ab5af64d95c1352d215b1757f29227c17360e458..3a7e9cc4191ec2af4de80bacf0579705aefe9bd8 100644 (file)
 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 @@ struct G {
     //~| expected type `usize`
     //~| found type `main::G`
     //~| expected usize, found struct `main::G`
-    //~| ERROR expected positive integer for repeat count, found struct [E0306]
+    //~| ERROR expected usize for repeat count, found struct [E0306]
 }
index f86d9b7648bbebfd19a2f9740fffdb0ad394c106..a05e007d6b7393e5774e44d76904c35b39fb3243 100644 (file)
@@ -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() {}
index f14a3505cdeb486510da18e7f6dd72d2184f8d58..a98b7cd43090f3768723cdc4fdb175eb4a91d410 100644 (file)
@@ -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/unresolved-import-recovery.rs b/src/test/compile-fail/unresolved-import-recovery.rs
new file mode 100644 (file)
index 0000000..8173f69
--- /dev/null
@@ -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.
+
+// Check that unresolved imports do not create additional errors and ICEs
+
+mod m {
+    pub use unresolved; //~ ERROR unresolved import `unresolved`
+
+    fn f() {
+        let unresolved = 0; // OK
+    }
+}
+
+fn main() {
+    match 0u8 {
+        m::unresolved => {} // OK
+        m::unresolved(..) => {} // OK
+        m::unresolved{..} => {} // OK
+    }
+}
index 51f876661f6510834a4dfd78ea2ea39a770b5440..fb4652affd0d8c3ce6c8ce7f7023b57f447c3137 100644 (file)
@@ -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 (file)
index b5b6ca7..0000000
+++ /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 (file)
index 0000000..c53f51d
--- /dev/null
@@ -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 (file)
index 0000000..e06c0a5
--- /dev/null
@@ -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-valgrind/coerce-match-calls.rs b/src/test/run-pass-valgrind/coerce-match-calls.rs
new file mode 100644 (file)
index 0000000..c2f6b4c
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that coercions are propagated through match and if expressions.
+
+// pretty-expanded FIXME #23616
+
+use std::boxed::Box;
+
+pub fn main() {
+    let _: Box<[isize]> = if true { Box::new([1, 2, 3]) } else { Box::new([1]) };
+
+    let _: Box<[isize]> = match true { true => Box::new([1, 2, 3]), false => Box::new([1]) };
+
+    // Check we don't get over-keen at propagating coercions in the case of casts.
+    let x = if true { 42 } else { 42u8 } as u16;
+    let x = match true { true => 42, false => 42u8 } as u16;
+}
diff --git a/src/test/run-pass-valgrind/coerce-match.rs b/src/test/run-pass-valgrind/coerce-match.rs
new file mode 100644 (file)
index 0000000..6bf5c4d
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that coercions are propagated through match and if expressions.
+
+// pretty-expanded FIXME #23616
+
+#![allow(unknown_features)]
+#![feature(box_syntax)]
+
+pub fn main() {
+    let _: Box<[isize]> =
+        if true { let b: Box<_> = box [1, 2, 3]; b } else { let b: Box<_> = box [1]; b };
+
+    let _: Box<[isize]> = match true {
+        true => { let b: Box<_> = box [1, 2, 3]; b }
+        false => { let b: Box<_> = box [1]; b }
+    };
+
+    // Check we don't get over-keen at propagating coercions in the case of casts.
+    let x = if true { 42 } else { 42u8 } as u16;
+    let x = match true { true => 42, false => 42u8 } as u16;
+}
diff --git a/src/test/run-pass/coerce-match-calls.rs b/src/test/run-pass/coerce-match-calls.rs
deleted file mode 100644 (file)
index c2f6b4c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Check that coercions are propagated through match and if expressions.
-
-// pretty-expanded FIXME #23616
-
-use std::boxed::Box;
-
-pub fn main() {
-    let _: Box<[isize]> = if true { Box::new([1, 2, 3]) } else { Box::new([1]) };
-
-    let _: Box<[isize]> = match true { true => Box::new([1, 2, 3]), false => Box::new([1]) };
-
-    // Check we don't get over-keen at propagating coercions in the case of casts.
-    let x = if true { 42 } else { 42u8 } as u16;
-    let x = match true { true => 42, false => 42u8 } as u16;
-}
diff --git a/src/test/run-pass/coerce-match.rs b/src/test/run-pass/coerce-match.rs
deleted file mode 100644 (file)
index 6bf5c4d..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Check that coercions are propagated through match and if expressions.
-
-// pretty-expanded FIXME #23616
-
-#![allow(unknown_features)]
-#![feature(box_syntax)]
-
-pub fn main() {
-    let _: Box<[isize]> =
-        if true { let b: Box<_> = box [1, 2, 3]; b } else { let b: Box<_> = box [1]; b };
-
-    let _: Box<[isize]> = match true {
-        true => { let b: Box<_> = box [1, 2, 3]; b }
-        false => { let b: Box<_> = box [1]; b }
-    };
-
-    // Check we don't get over-keen at propagating coercions in the case of casts.
-    let x = if true { 42 } else { 42u8 } as u16;
-    let x = match true { true => 42, false => 42u8 } as u16;
-}
index 2f265b9112b9809be21c450095f950cead56a0bc..7297c71a6d668b7aa2844d4f9714858166f53cd3 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -12,4 +12,7 @@
 
 pub fn main() {
     let _ = b"x" as &[u8];
+    let _ = b"y" as &[u8; 1];
+    let _ = b"z" as *const u8;
+    let _ = "ä" as *const str;
 }
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 (file)
index 0000000..d22fa64
--- /dev/null
@@ -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");
+}
diff --git a/src/test/run-pass/issue-34932.rs b/src/test/run-pass/issue-34932.rs
new file mode 100644 (file)
index 0000000..e83939e
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:--test
+// rustc-env:RUSTC_BOOTSTRAP_KEY=
+// ignore-pretty : (#23623) problems when  ending with // comments
+
+#![cfg(any())] // This test should be configured away
+#![feature(rustc_attrs)] // Test that this is allowed on stable/beta
+#![feature(iter_arith_traits)] // Test that this is not unused
+#![deny(unused_features)]
+
+#[test]
+fn dummy() {
+    let () = "this should not reach type-checking";
+}
index 52e19b37d7935659707399c89ba330b4b6a108c4..c982e8ac6f83e2927c8e81a63b11d4152786df34 100644 (file)
@@ -16,7 +16,16 @@ macro_rules! anon { $lhs => $rhs }
     });
 }
 
+macro_rules! outer {
+    ($x:expr; $fragment:ident) => {
+        macro_rules! inner { ($y:$fragment) => { $x + $y } }
+    }
+}
+
 fn main() {
     let val = higher_order!(subst ($x:expr, $y:expr, $foo:expr) => (($x + $y, $foo)));
     assert_eq!(val, (3, "foo"));
+
+    outer!(2; expr);
+    assert_eq!(inner!(3), 5);
 }
diff --git a/src/test/rustdoc/issue-34928.rs b/src/test/rustdoc/issue-34928.rs
new file mode 100644 (file)
index 0000000..b2104a0
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+
+pub trait Bar {}
+
+// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T) where T: Bar;'
+pub struct Foo<T>(pub T) where T: Bar;
index 91ec69d9a3cbbdbeaaff4adcd705862997122097..d8dc115abf91e1039fa8b30561540c43ed79a753 100644 (file)
@@ -12,7 +12,7 @@
 
 pub trait MyTrait { fn dummy(&self) { } }
 
-// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A> where A: MyTrait"
+// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait"
 pub struct Alpha<A>(A) where A: MyTrait;
 // @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B> where B: MyTrait"
 pub trait Bravo<B> where B: MyTrait { fn get(&self, B: B); }