]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #15650 : jakub-/rust/patterns-statics, r=pcwalton
authorbors <bors@rust-lang.org>
Sat, 19 Jul 2014 21:46:37 +0000 (21:46 +0000)
committerbors <bors@rust-lang.org>
Sat, 19 Jul 2014 21:46:37 +0000 (21:46 +0000)
This is accomplished by rewriting static expressions into equivalent patterns.
This way, patterns referencing static variables can both participate
in exhaustiveness analysis as well as be compiled down into the appropriate
branch of the decision trees that match expressions are codegened to.

Fixes #6533.
Fixes #13626.
Fixes #13731.
Fixes #14576.
Fixes #15393.

39 files changed:
mk/docs.mk
src/doc/guide-strings.md
src/doc/index.md
src/libcollections/dlist.rs
src/libcollections/str.rs
src/libcore/str.rs
src/librustc/back/link.rs
src/librustc/back/lto.rs
src/librustc/diagnostics.rs
src/librustc/driver/driver.rs
src/librustc/metadata/encoder.rs
src/librustc/middle/effect.rs
src/librustc/middle/entry.rs
src/librustc/middle/intrinsicck.rs
src/librustc/middle/kind.rs
src/librustc/middle/lang_items.rs
src/librustc/middle/resolve.rs
src/librustc/middle/trans/adt.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/callee.rs
src/librustc/middle/trans/closure.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/typeck/astconv.rs
src/librustc/middle/typeck/check/vtable.rs
src/librustc/middle/typeck/check/writeback.rs
src/librustc/middle/typeck/coherence.rs
src/librustc/middle/typeck/collect.rs
src/librustc/middle/typeck/mod.rs
src/libserialize/json.rs
src/libstd/collections/hashmap.rs
src/libsyntax/diagnostics/macros.rs
src/test/bench/shootout-mandelbrot.rs
src/test/compile-fail/crate-name-mismatch.rs [new file with mode: 0644]
src/test/compile-fail/multiple-main-2.rs
src/test/compile-fail/multiple-main-3.rs
src/test/run-make/crate-name-priority/Makefile
src/test/run-make/extra-filename-with-temp-outputs/Makefile [new file with mode: 0644]
src/test/run-make/extra-filename-with-temp-outputs/foo.rs [new file with mode: 0644]
src/test/run-pass/crate-name-attr-used.rs

index 213565b09ac27d0633a81cbdb6fde4cc5cf61b5d..933a0bdc717cafb6fb2726b0876438deabb4cdc1 100644 (file)
@@ -30,7 +30,7 @@ DOCS := index intro tutorial guide guide-ffi guide-macros guide-lifetimes \
        guide-tasks guide-container guide-pointers guide-testing \
        guide-runtime complement-bugreport \
        complement-lang-faq complement-design-faq complement-project-faq rust \
-    rustdoc guide-unsafe
+    rustdoc guide-unsafe guide-strings
 
 PDF_DOCS := tutorial rust
 
index 6f301afc8498d45068ba7ee49836974c944eebe4..4fea8b8039e008ad5d6d9dfda701fef8cd2f0b8a 100644 (file)
@@ -1,7 +1,5 @@
 % The Strings Guide
 
-# Strings
-
 Strings are an important concept to master in any programming language. If you
 come from a managed language background, you may be surprised at the complexity
 of string handling in a systems programming language. Efficient access and
@@ -14,7 +12,7 @@ Additionally, strings are not null-terminated and can contain null bytes.
 
 Rust has two main types of strings: `&str` and `String`.
 
-## &str
+# &str
 
 The first kind is a `&str`. This is pronounced a 'string slice.' String literals
 are of the type `&str`:
@@ -38,7 +36,7 @@ Like vector slices, string slices are simply a pointer plus a length. This
 means that they're a 'view' into an already-allocated string, such as a
 `&'static str` or a `String`.
 
-## String
+# String
 
 A `String` is a heap-allocated string. This string is growable, and is also
 guaranteed to be UTF-8.
@@ -73,9 +71,9 @@ let x: &[u8] = &[b'a', b'b'];
 let stack_str: &str = str::from_utf8(x).unwrap();
 ```
 
-## Best Practices
+# Best Practices
 
-### `String` vs. `&str`
+## `String` vs. `&str`
 
 In general, you should prefer `String` when you need ownership, and `&str` when
 you just need to borrow a string. This is very similar to using `Vec<T>` vs. `&[T]`,
@@ -98,7 +96,7 @@ need, and it can make your lifetimes more complex. Furthermore, you can pass
 either kind of string into `foo` by using `.as_slice()` on any `String` you
 need to pass in, so the `&str` version is more flexible.
 
-### Comparisons
+## Comparisons
 
 To compare a String to a constant string, prefer `as_slice()`...
 
@@ -123,7 +121,7 @@ fn compare(string: String) {
 Converting a `String` to a `&str` is cheap, but converting the `&str` to a
 `String` involves an allocation.
 
-## Other Documentation
+# Other Documentation
 
 * [the `&str` API documentation](/std/str/index.html)
 * [the `String` API documentation](std/string/index.html)
index eb8c59ac030ee17eeebbe407d1c11b2569cf816d..c54f4e00905de66048cea0a7c7eb55fd8acb7fa6 100644 (file)
@@ -13,6 +13,7 @@ li {list-style-type: none; }
 
 # Guides
 
+* [Strings](guide-strings.html)
 * [Pointers](guide-pointers.html)
 * [References and Lifetimes](guide-lifetimes.html)
 * [Containers and Iterators](guide-container.html)
index 226dd5a2356c93415db75bc49d2aa0b7d6a7b22c..226fbbe7f941b31b6a81c9c56f968881c6461bf9 100644 (file)
@@ -278,6 +278,23 @@ pub fn new() -> DList<T> {
     /// Move the last element to the front of the list.
     ///
     /// If the list is empty, do nothing.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::collections::{DList, Deque};
+    ///
+    /// let mut dl = DList::new();
+    /// dl.push_back(1i);
+    /// dl.push_back(2);
+    /// dl.push_back(3);
+    ///
+    /// dl.rotate_forward();
+    ///
+    /// for e in dl.iter() {
+    ///     println!("{}", e); // prints 3, then 1, then 2
+    /// }
+    /// ```
     #[inline]
     pub fn rotate_forward(&mut self) {
         self.pop_back_node().map(|tail| {
@@ -288,6 +305,23 @@ pub fn rotate_forward(&mut self) {
     /// Move the first element to the back of the list.
     ///
     /// If the list is empty, do nothing.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::collections::{DList, Deque};
+    ///
+    /// let mut dl = DList::new();
+    /// dl.push_back(1i);
+    /// dl.push_back(2);
+    /// dl.push_back(3);
+    ///
+    /// dl.rotate_backward();
+    ///
+    /// for e in dl.iter() {
+    ///     println!("{}", e); // prints 2, then 3, then 1
+    /// }
+    /// ```
     #[inline]
     pub fn rotate_backward(&mut self) {
         self.pop_front_node().map(|head| {
@@ -298,6 +332,25 @@ pub fn rotate_backward(&mut self) {
     /// Add all elements from `other` to the end of the list
     ///
     /// O(1)
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::collections::{DList, Deque};
+    ///
+    /// let mut a = DList::new();
+    /// let mut b = DList::new();
+    /// a.push_back(1i);
+    /// a.push_back(2);
+    /// b.push_back(3i);
+    /// b.push_back(4);
+    ///
+    /// a.append(b);
+    ///
+    /// for e in a.iter() {
+    ///     println!("{}", e); // prints 1, then 2, then 3, then 4
+    /// }
+    /// ```
     pub fn append(&mut self, mut other: DList<T>) {
         match self.list_tail.resolve() {
             None => *self = other,
@@ -320,6 +373,25 @@ pub fn append(&mut self, mut other: DList<T>) {
     /// Add all elements from `other` to the beginning of the list
     ///
     /// O(1)
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::collections::{DList, Deque};
+    ///
+    /// let mut a = DList::new();
+    /// let mut b = DList::new();
+    /// a.push_back(1i);
+    /// a.push_back(2);
+    /// b.push_back(3i);
+    /// b.push_back(4);
+    ///
+    /// a.prepend(b);
+    ///
+    /// for e in a.iter() {
+    ///     println!("{}", e); // prints 3, then 4, then 1, then 2
+    /// }
+    /// ```
     #[inline]
     pub fn prepend(&mut self, mut other: DList<T>) {
         mem::swap(self, &mut other);
@@ -330,6 +402,25 @@ pub fn prepend(&mut self, mut other: DList<T>) {
     /// or at the end.
     ///
     /// O(N)
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::collections::{DList, Deque};
+    ///
+    /// let mut a: DList<int> = DList::new();
+    /// a.push_back(2i);
+    /// a.push_back(4);
+    /// a.push_back(7);
+    /// a.push_back(8);
+    ///
+    /// // insert 11 before the first odd number in the list
+    /// a.insert_when(11, |&e, _| e % 2 == 1);
+    ///
+    /// for e in a.iter() {
+    ///     println!("{}", e); // prints 2, then 4, then 11, then 7, then 8
+    /// }
+    /// ```
     pub fn insert_when(&mut self, elt: T, f: |&T, &T| -> bool) {
         {
             let mut it = self.mut_iter();
index bd6a13ae2e3ed7c28c273d7c16f6c6d4df1bc030..1e29679f8a79ec61c363c6f5ef68e846927ec5e6 100644 (file)
@@ -808,6 +808,7 @@ fn append(mut self, rhs: &str) -> String {
 #[cfg(test)]
 mod tests {
     use std::iter::AdditiveIterator;
+    use std::iter::range;
     use std::default::Default;
     use std::char::Char;
     use std::clone::Clone;
@@ -1610,6 +1611,30 @@ fn test_rev_iterator() {
         assert_eq!(pos, v.len());
     }
 
+    #[test]
+    fn test_chars_decoding() {
+        let mut bytes = [0u8, ..4];
+        for c in range(0u32, 0x110000).filter_map(|c| ::core::char::from_u32(c)) {
+            let len = c.encode_utf8(bytes);
+            let s = ::core::str::from_utf8(bytes.slice_to(len)).unwrap();
+            if Some(c) != s.chars().next() {
+                fail!("character {:x}={} does not decode correctly", c as u32, c);
+            }
+        }
+    }
+
+    #[test]
+    fn test_chars_rev_decoding() {
+        let mut bytes = [0u8, ..4];
+        for c in range(0u32, 0x110000).filter_map(|c| ::core::char::from_u32(c)) {
+            let len = c.encode_utf8(bytes);
+            let s = ::core::str::from_utf8(bytes.slice_to(len)).unwrap();
+            if Some(c) != s.chars().rev().next() {
+                fail!("character {:x}={} does not decode correctly", c as u32, c);
+            }
+        }
+    }
+
     #[test]
     fn test_iterator_clone() {
         let s = "ศไทย中华Việt Nam";
@@ -2240,16 +2265,26 @@ fn test_into_maybe_owned() {
 #[cfg(test)]
 mod bench {
     use test::Bencher;
+    use test::black_box;
     use super::*;
+    use std::option::{None, Some};
     use std::iter::{Iterator, DoubleEndedIterator};
     use std::collections::Collection;
 
     #[bench]
     fn char_iterator(b: &mut Bencher) {
         let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
-        let len = s.char_len();
 
-        b.iter(|| assert_eq!(s.chars().count(), len));
+        b.iter(|| s.chars().count());
+    }
+
+    #[bench]
+    fn char_iterator_for(b: &mut Bencher) {
+        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+
+        b.iter(|| {
+            for ch in s.chars() { black_box(ch) }
+        });
     }
 
     #[bench]
@@ -2260,17 +2295,24 @@ fn char_iterator_ascii(b: &mut Bencher) {
         Mary had a little lamb, Little lamb
         Mary had a little lamb, Little lamb
         Mary had a little lamb, Little lamb";
-        let len = s.char_len();
 
-        b.iter(|| assert_eq!(s.chars().count(), len));
+        b.iter(|| s.chars().count());
     }
 
     #[bench]
     fn char_iterator_rev(b: &mut Bencher) {
         let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
-        let len = s.char_len();
 
-        b.iter(|| assert_eq!(s.chars().rev().count(), len));
+        b.iter(|| s.chars().rev().count());
+    }
+
+    #[bench]
+    fn char_iterator_rev_for(b: &mut Bencher) {
+        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+
+        b.iter(|| {
+            for ch in s.chars().rev() { black_box(ch) }
+        });
     }
 
     #[bench]
index aa2050dacf1aa46da39ff1872e6b89c9f20eb661..c6aff9c8bdac8c58147e17131ea3a491080cca38 100644 (file)
@@ -97,47 +97,110 @@ fn only_ascii(&self) -> bool {
 Section: Iterators
 */
 
-/// External iterator for a string's characters.
-/// Use with the `std::iter` module.
+/// Iterator for the char (representing *Unicode Scalar Values*) of a string
+///
+/// Created with the method `.chars()`.
 #[deriving(Clone)]
 pub struct Chars<'a> {
-    /// The slice remaining to be iterated
-    string: &'a str,
+    iter: slice::Items<'a, u8>
+}
+
+// Return the initial codepoint accumulator for the first byte.
+// The first byte is special, only want bottom 5 bits for width 2, 4 bits
+// for width 3, and 3 bits for width 4
+macro_rules! utf8_first_byte(
+    ($byte:expr, $width:expr) => (($byte & (0x7F >> $width)) as u32)
+)
+
+// return the value of $ch updated with continuation byte $byte
+macro_rules! utf8_acc_cont_byte(
+    ($ch:expr, $byte:expr) => (($ch << 6) | ($byte & CONT_MASK) as u32)
+)
+
+macro_rules! utf8_is_cont_byte(
+    ($byte:expr) => (($byte & !CONT_MASK) == TAG_CONT_U8)
+)
+
+#[inline]
+fn unwrap_or_0(opt: Option<&u8>) -> u8 {
+    match opt {
+        Some(&byte) => byte,
+        None => 0,
+    }
 }
 
 impl<'a> Iterator<char> for Chars<'a> {
     #[inline]
     fn next(&mut self) -> Option<char> {
-        // Decode the next codepoint, then update
-        // the slice to be just the remaining part
-        if self.string.len() != 0 {
-            let CharRange {ch, next} = self.string.char_range_at(0);
-            unsafe {
-                self.string = raw::slice_unchecked(self.string, next, self.string.len());
+        // Decode UTF-8, using the valid UTF-8 invariant
+        let x = match self.iter.next() {
+            None => return None,
+            Some(&next_byte) if next_byte < 128 => return Some(next_byte as char),
+            Some(&next_byte) => next_byte,
+        };
+
+        // Multibyte case follows
+        // Decode from a byte combination out of: [[[x y] z] w]
+        // NOTE: Performance is sensitive to the exact formulation here
+        let init = utf8_first_byte!(x, 2);
+        let y = unwrap_or_0(self.iter.next());
+        let mut ch = utf8_acc_cont_byte!(init, y);
+        if x >= 0xE0 {
+            // [[x y z] w] case
+            // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid
+            let z = unwrap_or_0(self.iter.next());
+            let y_z = utf8_acc_cont_byte!((y & CONT_MASK) as u32, z);
+            ch = init << 12 | y_z;
+            if x >= 0xF0 {
+                // [x y z w] case
+                // use only the lower 3 bits of `init`
+                let w = unwrap_or_0(self.iter.next());
+                ch = (init & 7) << 18 | utf8_acc_cont_byte!(y_z, w);
             }
-            Some(ch)
-        } else {
-            None
+        }
+
+        // str invariant says `ch` is a valid Unicode Scalar Value
+        unsafe {
+            Some(mem::transmute(ch))
         }
     }
 
     #[inline]
     fn size_hint(&self) -> (uint, Option<uint>) {
-        (self.string.len().saturating_add(3)/4, Some(self.string.len()))
+        let (len, _) = self.iter.size_hint();
+        (len.saturating_add(3) / 4, Some(len))
     }
 }
 
 impl<'a> DoubleEndedIterator<char> for Chars<'a> {
     #[inline]
     fn next_back(&mut self) -> Option<char> {
-        if self.string.len() != 0 {
-            let CharRange {ch, next} = self.string.char_range_at_reverse(self.string.len());
-            unsafe {
-                self.string = raw::slice_unchecked(self.string, 0, next);
+        let w = match self.iter.next_back() {
+            None => return None,
+            Some(&back_byte) if back_byte < 128 => return Some(back_byte as char),
+            Some(&back_byte) => back_byte,
+        };
+
+        // Multibyte case follows
+        // Decode from a byte combination out of: [x [y [z w]]]
+        let mut ch;
+        let z = unwrap_or_0(self.iter.next_back());
+        ch = utf8_first_byte!(z, 2);
+        if utf8_is_cont_byte!(z) {
+            let y = unwrap_or_0(self.iter.next_back());
+            ch = utf8_first_byte!(y, 3);
+            if utf8_is_cont_byte!(y) {
+                let x = unwrap_or_0(self.iter.next_back());
+                ch = utf8_first_byte!(x, 4);
+                ch = utf8_acc_cont_byte!(ch, y);
             }
-            Some(ch)
-        } else {
-            None
+            ch = utf8_acc_cont_byte!(ch, z);
+        }
+        ch = utf8_acc_cont_byte!(ch, w);
+
+        // str invariant says `ch` is a valid Unicode Scalar Value
+        unsafe {
+            Some(mem::transmute(ch))
         }
     }
 }
@@ -146,18 +209,23 @@ fn next_back(&mut self) -> Option<char> {
 /// Use with the `std::iter` module.
 #[deriving(Clone)]
 pub struct CharOffsets<'a> {
-    /// The original string to be iterated
-    string: &'a str,
+    front_offset: uint,
     iter: Chars<'a>,
 }
 
 impl<'a> Iterator<(uint, char)> for CharOffsets<'a> {
     #[inline]
     fn next(&mut self) -> Option<(uint, char)> {
-        // Compute the byte offset by using the pointer offset between
-        // the original string slice and the iterator's remaining part
-        let offset = self.iter.string.as_ptr() as uint - self.string.as_ptr() as uint;
-        self.iter.next().map(|ch| (offset, ch))
+        let (pre_len, _) = self.iter.iter.size_hint();
+        match self.iter.next() {
+            None => None,
+            Some(ch) => {
+                let index = self.front_offset;
+                let (len, _) = self.iter.iter.size_hint();
+                self.front_offset += pre_len - len;
+                Some((index, ch))
+            }
+        }
     }
 
     #[inline]
@@ -169,11 +237,14 @@ fn size_hint(&self) -> (uint, Option<uint>) {
 impl<'a> DoubleEndedIterator<(uint, char)> for CharOffsets<'a> {
     #[inline]
     fn next_back(&mut self) -> Option<(uint, char)> {
-        self.iter.next_back().map(|ch| {
-            let offset = self.iter.string.len() +
-                    self.iter.string.as_ptr() as uint - self.string.as_ptr() as uint;
-            (offset, ch)
-        })
+        match self.iter.next_back() {
+            None => None,
+            Some(ch) => {
+                let (len, _) = self.iter.iter.size_hint();
+                let index = self.front_offset + len;
+                Some((index, ch))
+            }
+        }
     }
 }
 
@@ -672,9 +743,9 @@ macro_rules! next ( () => {
             // UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
             //               %xF4 %x80-8F 2( UTF8-tail )
             match w {
-                2 => if second & 192 != TAG_CONT_U8 {err!()},
+                2 => if second & !CONT_MASK != TAG_CONT_U8 {err!()},
                 3 => {
-                    match (first, second, next!() & 192) {
+                    match (first, second, next!() & !CONT_MASK) {
                         (0xE0        , 0xA0 .. 0xBF, TAG_CONT_U8) |
                         (0xE1 .. 0xEC, 0x80 .. 0xBF, TAG_CONT_U8) |
                         (0xED        , 0x80 .. 0x9F, TAG_CONT_U8) |
@@ -683,7 +754,7 @@ macro_rules! next ( () => {
                     }
                 }
                 4 => {
-                    match (first, second, next!() & 192, next!() & 192) {
+                    match (first, second, next!() & !CONT_MASK, next!() & !CONT_MASK) {
                         (0xF0        , 0x90 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
                         (0xF1 .. 0xF3, 0x80 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
                         (0xF4        , 0x80 .. 0x8F, TAG_CONT_U8, TAG_CONT_U8) => {}
@@ -880,19 +951,10 @@ pub struct CharRange {
     pub next: uint,
 }
 
-// Return the initial codepoint accumulator for the first byte.
-// The first byte is special, only want bottom 5 bits for width 2, 4 bits
-// for width 3, and 3 bits for width 4
-macro_rules! utf8_first_byte(
-    ($byte:expr, $width:expr) => (($byte & (0x7F >> $width)) as u32)
-)
-
-// return the value of $ch updated with continuation byte $byte
-macro_rules! utf8_acc_cont_byte(
-    ($ch:expr, $byte:expr) => (($ch << 6) | ($byte & 63u8) as u32)
-)
-
-static TAG_CONT_U8: u8 = 128u8;
+/// Mask of the value bits of a continuation byte
+static CONT_MASK: u8 = 0b0011_1111u8;
+/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte
+static TAG_CONT_U8: u8 = 0b1000_0000u8;
 
 /// Unsafe operations
 pub mod raw {
@@ -1608,7 +1670,7 @@ fn contains_char(&self, needle: char) -> bool {
 
     #[inline]
     fn chars(&self) -> Chars<'a> {
-        Chars{string: *self}
+        Chars{iter: self.as_bytes().iter()}
     }
 
     #[inline]
@@ -1618,7 +1680,7 @@ fn bytes(&self) -> Bytes<'a> {
 
     #[inline]
     fn char_indices(&self) -> CharOffsets<'a> {
-        CharOffsets{string: *self, iter: self.chars()}
+        CharOffsets{front_offset: 0, iter: self.chars()}
     }
 
     #[inline]
@@ -1828,7 +1890,7 @@ fn char_range_at_reverse(&self, start: uint) -> CharRange {
         // Multibyte case is a fn to allow char_range_at_reverse to inline cleanly
         fn multibyte_char_range_at_reverse(s: &str, mut i: uint) -> CharRange {
             // while there is a previous byte == 10......
-            while i > 0 && s.as_bytes()[i] & 192u8 == TAG_CONT_U8 {
+            while i > 0 && s.as_bytes()[i] & !CONT_MASK == TAG_CONT_U8 {
                 i -= 1u;
             }
 
index 88b42dba8e99d1adf18473c70afbc7eb1f83e973..cc73cdce6a8c3f8fc44f5f48e31aa3c923ce517f 100644 (file)
@@ -571,15 +571,27 @@ pub fn find_crate_name(sess: Option<&Session>,
     };
 
     // Look in attributes 100% of the time to make sure the attribute is marked
-    // as used. After doing this, however, favor crate names from the command
-    // line.
+    // as used. After doing this, however, we still prioritize a crate name from
+    // the command line over one found in the #[crate_name] attribute. If we
+    // find both we ensure that they're the same later on as well.
     let attr_crate_name = attrs.iter().find(|at| at.check_name("crate_name"))
                                .and_then(|at| at.value_str().map(|s| (at, s)));
 
     match sess {
         Some(sess) => {
             match sess.opts.crate_name {
-                Some(ref s) => return validate(s.clone(), None),
+                Some(ref s) => {
+                    match attr_crate_name {
+                        Some((attr, ref name)) if s.as_slice() != name.get() => {
+                            let msg = format!("--crate-name and #[crate_name] \
+                                               are required to match, but `{}` \
+                                               != `{}`", s, name);
+                            sess.span_err(attr.span, msg.as_slice());
+                        }
+                        _ => {},
+                    }
+                    return validate(s.clone(), None);
+                }
                 None => {}
             }
         }
@@ -1547,7 +1559,7 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
                 add_dynamic_crate(cmd, sess, src.dylib.unwrap())
             }
             cstore::RequireStatic => {
-                add_static_crate(cmd, sess, tmpdir, cnum, src.rlib.unwrap())
+                add_static_crate(cmd, sess, tmpdir, src.rlib.unwrap())
             }
         }
 
@@ -1564,7 +1576,7 @@ fn unlib<'a>(config: &config::Config, stem: &'a [u8]) -> &'a [u8] {
 
     // Adds the static "rlib" versions of all crates to the command line.
     fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path,
-                        cnum: ast::CrateNum, cratepath: Path) {
+                        cratepath: Path) {
         // When performing LTO on an executable output, all of the
         // bytecode from the upstream libraries has already been
         // included in our object file output. We need to modify all of
@@ -1580,7 +1592,8 @@ fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path,
         // If we're not doing LTO, then our job is simply to just link
         // against the archive.
         if sess.lto() {
-            let name = sess.cstore.get_crate_data(cnum).name.clone();
+            let name = cratepath.filename_str().unwrap();
+            let name = name.slice(3, name.len() - 5); // chop off lib/.rlib
             time(sess.time_passes(),
                  format!("altering {}.rlib", name).as_slice(),
                  (), |()| {
index 6184ea4591f084ae5041f04c56372e6cd516d8f5..c51f1615d59806eff4f24011747e7f3f76fb7bfe 100644 (file)
@@ -54,17 +54,19 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
         };
 
         let archive = ArchiveRO::open(&path).expect("wanted an rlib");
-        debug!("reading {}", name);
+        let file = path.filename_str().unwrap();
+        let file = file.slice(3, file.len() - 5); // chop off lib/.rlib
+        debug!("reading {}", file);
         let bc = time(sess.time_passes(),
                       format!("read {}.bytecode.deflate", name).as_slice(),
                       (),
                       |_| {
                           archive.read(format!("{}.bytecode.deflate",
-                                               name).as_slice())
+                                               file).as_slice())
                       });
         let bc = bc.expect("missing compressed bytecode in archive!");
         let bc = time(sess.time_passes(),
-                      format!("inflate {}.bc", name).as_slice(),
+                      format!("inflate {}.bc", file).as_slice(),
                       (),
                       |_| {
                           match flate::inflate_bytes(bc) {
index 5f3bbf481056a4dc5662e616f39e7a4c58b55171..1b806e1c257dc6805ffe2fd3beeb63e421f8e904 100644 (file)
     E0091,
     E0092,
     E0093,
-    E0094
+    E0094,
+    E0095,
+    E0096,
+    E0097,
+    E0098,
+    E0099,
+    E0100,
+    E0101,
+    E0102,
+    E0103,
+    E0104,
+    E0105,
+    E0106,
+    E0107,
+    E0108,
+    E0109,
+    E0110,
+    E0111,
+    E0112,
+    E0113,
+    E0114,
+    E0115,
+    E0116,
+    E0117,
+    E0118,
+    E0119,
+    E0120,
+    E0121,
+    E0122,
+    E0123,
+    E0124,
+    E0125,
+    E0126,
+    E0127,
+    E0128,
+    E0129,
+    E0130,
+    E0131,
+    E0132,
+    E0133,
+    E0134,
+    E0135,
+    E0136,
+    E0137,
+    E0138,
+    E0139,
+    E0140,
+    E0141,
+    E0142,
+    E0143,
+    E0144,
+    E0145,
+    E0146,
+    E0147,
+    E0148,
+    E0149,
+    E0150,
+    E0151,
+    E0152,
+    E0153,
+    E0154,
+    E0155,
+    E0156,
+    E0157
 )
index 43aa3f9041fd97d146bbbad40a8a22fe1a6bd835..81ace4d015c8576101d566fb499694e4856eb5f7 100644 (file)
@@ -936,6 +936,7 @@ pub struct OutputFilenames {
     pub out_directory: Path,
     pub out_filestem: String,
     pub single_output_file: Option<Path>,
+    extra: String,
 }
 
 impl OutputFilenames {
@@ -948,7 +949,7 @@ pub fn path(&self, flavor: link::OutputType) -> Path {
     }
 
     pub fn temp_path(&self, flavor: link::OutputType) -> Path {
-        let base = self.out_directory.join(self.out_filestem.as_slice());
+        let base = self.out_directory.join(self.filestem());
         match flavor {
             link::OutputTypeBitcode => base.with_extension("bc"),
             link::OutputTypeAssembly => base.with_extension("s"),
@@ -959,8 +960,11 @@ pub fn temp_path(&self, flavor: link::OutputType) -> Path {
     }
 
     pub fn with_extension(&self, extension: &str) -> Path {
-        let stem = self.out_filestem.as_slice();
-        self.out_directory.join(stem).with_extension(extension)
+        self.out_directory.join(self.filestem()).with_extension(extension)
+    }
+
+    fn filestem(&self) -> String {
+        format!("{}{}", self.out_filestem, self.extra)
     }
 }
 
@@ -1000,6 +1004,7 @@ pub fn build_output_filenames(input: &Input,
                 out_directory: dirpath,
                 out_filestem: stem,
                 single_output_file: None,
+                extra: sess.opts.cg.extra_filename.clone(),
             }
         }
 
@@ -1018,6 +1023,7 @@ pub fn build_output_filenames(input: &Input,
                 out_directory: out_file.dir_path(),
                 out_filestem: out_file.filestem_str().unwrap().to_string(),
                 single_output_file: ofile,
+                extra: sess.opts.cg.extra_filename.clone(),
             }
         }
     }
index b86f5ee6cc2bc8fc6a9f146f302a82c0801bd95f..439455ff3d15ce3291c07acd9955b1fd852266bd 100644 (file)
@@ -314,8 +314,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
                             ebml_w: &mut Encoder,
                             id: NodeId,
                             variants: &[P<Variant>],
-                            index: &mut Vec<entry<i64>>,
-                            generics: &ast::Generics) {
+                            index: &mut Vec<entry<i64>>) {
     debug!("encode_enum_variant_info(id={:?})", id);
 
     let mut disr_val = 0;
@@ -343,10 +342,6 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
         encode_stability(ebml_w, stab);
 
         match variant.node.kind {
-            ast::TupleVariantKind(ref args)
-                    if args.len() > 0 && generics.ty_params.len() == 0 => {
-                encode_symbol(ecx, ebml_w, variant.node.id);
-            }
             ast::TupleVariantKind(_) => {},
             ast::StructVariantKind(_) => {
                 let fields = ty::lookup_struct_fields(ecx.tcx, def_id);
@@ -1019,7 +1014,7 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
         encode_stability(ebml_w, stab);
         ebml_w.end_tag();
       }
-      ItemEnum(ref enum_definition, ref generics) => {
+      ItemEnum(ref enum_definition, _) => {
         add_to_index(item, ebml_w, index);
 
         ebml_w.start_tag(tag_items_data_item);
@@ -1046,8 +1041,7 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
                                  ebml_w,
                                  item.id,
                                  (*enum_definition).variants.as_slice(),
-                                 index,
-                                 generics);
+                                 index);
       }
       ItemStruct(struct_def, _) => {
         let fields = ty::lookup_struct_fields(tcx, def_id);
index fed2f91ce098601ccb5f6b5e3d7dfd141f3a7acc..e6160038b1d8c29662a7e57268ec423730713541 100644 (file)
@@ -49,10 +49,9 @@ fn require_unsafe(&mut self, span: Span, description: &str) {
         match self.unsafe_context {
             SafeContext => {
                 // Report an error.
-                self.tcx.sess.span_err(span,
-                                  format!("{} requires unsafe function or \
-                                           block",
-                                          description).as_slice())
+                span_err!(self.tcx.sess, span, E0133,
+                          "{} requires unsafe function or block",
+                          description);
             }
             UnsafeBlock(block_id) => {
                 // OK, but record this.
@@ -73,14 +72,14 @@ fn check_str_index(&mut self, e: &ast::Expr) {
         match ty::get(base_type).sty {
             ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
                 ty::ty_str => {
-                    self.tcx.sess.span_err(e.span,
-                        "modification of string types is not allowed");
+                    span_err!(self.tcx.sess, e.span, E0134,
+                              "modification of string types is not allowed");
                 }
                 _ => {}
             },
             ty::ty_str => {
-                self.tcx.sess.span_err(e.span,
-                    "modification of string types is not allowed");
+                span_err!(self.tcx.sess, e.span, E0135,
+                          "modification of string types is not allowed");
             }
             _ => {}
         }
index 9a5f226bb73ceaf5546fcaf9718945d3c430b563..3debdc158fe26c0d8c64f33cb454c1f0452284bd 100644 (file)
@@ -87,9 +87,8 @@ fn find_item(item: &Item, ctxt: &mut EntryContext) {
                             if ctxt.main_fn.is_none() {
                                 ctxt.main_fn = Some((item.id, item.span));
                             } else {
-                                ctxt.session.span_err(
-                                    item.span,
-                                    "multiple 'main' functions");
+                                span_err!(ctxt.session, item.span, E0136,
+                                          "multiple 'main' functions");
                             }
                         } else {
                             // This isn't main
@@ -102,9 +101,8 @@ fn find_item(item: &Item, ctxt: &mut EntryContext) {
                 if ctxt.attr_main_fn.is_none() {
                     ctxt.attr_main_fn = Some((item.id, item.span));
                 } else {
-                    ctxt.session.span_err(
-                        item.span,
-                        "multiple 'main' functions");
+                    span_err!(ctxt.session, item.span, E0137,
+                              "multiple functions with a #[main] attribute");
                 }
             }
 
@@ -112,9 +110,8 @@ fn find_item(item: &Item, ctxt: &mut EntryContext) {
                 if ctxt.start_fn.is_none() {
                     ctxt.start_fn = Some((item.id, item.span));
                 } else {
-                    ctxt.session.span_err(
-                        item.span,
-                        "multiple 'start' functions");
+                    span_err!(ctxt.session, item.span, E0138,
+                              "multiple 'start' functions");
                 }
             }
         }
index 93913f842711197bc6e032975920dfb15a3edd40..6669147b0dcacebf70cd721a5ebaf8faa8169dfe 100644 (file)
@@ -94,14 +94,12 @@ fn def_id_is_transmute(&self, def_id: DefId) -> bool {
 
     fn check_transmute(&self, span: Span, from: ty::t, to: ty::t) {
         if type_size_is_affected_by_type_parameters(self.tcx, from) {
-            self.tcx.sess.span_err(span,
-                                   "cannot transmute from a type that \
-                                    contains type parameters");
+            span_err!(self.tcx.sess, span, E0139,
+                      "cannot transmute from a type that contains type parameters");
         }
         if type_size_is_affected_by_type_parameters(self.tcx, to) {
-            self.tcx.sess.span_err(span,
-                                   "cannot transmute to a type that contains \
-                                    type parameters");
+            span_err!(self.tcx.sess, span, E0140,
+                      "cannot transmute to a type that contains type parameters");
         }
 
         let restriction = TransmuteRestriction {
index a45bb69a53ee1da04dfc46fba957807680dbf818..d2a5342c17ee86a8a83b9ae1d320a854b32dadbb 100644 (file)
@@ -92,22 +92,20 @@ fn check_struct_safe_for_destructor(cx: &mut Context,
         let struct_ty = ty::mk_struct(cx.tcx, struct_did,
                                       subst::Substs::empty());
         if !ty::type_is_sendable(cx.tcx, struct_ty) {
-            cx.tcx.sess.span_err(span,
-                                 "cannot implement a destructor on a \
-                                  structure that does not satisfy Send");
-            cx.tcx.sess.span_note(span,
-                                  "use \"#[unsafe_destructor]\" on the \
-                                   implementation to force the compiler to \
-                                   allow this");
+            span_err!(cx.tcx.sess, span, E0125,
+                      "cannot implement a destructor on a \
+                       structure that does not satisfy Send");
+            span_note!(cx.tcx.sess, span,
+                       "use \"#[unsafe_destructor]\" on the implementation \
+                        to force the compiler to allow this");
         }
     } else {
-        cx.tcx.sess.span_err(span,
-                             "cannot implement a destructor on a structure \
-                              with type parameters");
-        cx.tcx.sess.span_note(span,
-                              "use \"#[unsafe_destructor]\" on the \
-                               implementation to force the compiler to \
-                               allow this");
+        span_err!(cx.tcx.sess, span, E0141,
+                  "cannot implement a destructor on a structure \
+                   with type parameters");
+        span_note!(cx.tcx.sess, span,
+                   "use \"#[unsafe_destructor]\" on the implementation \
+                    to force the compiler to allow this");
     }
 }
 
@@ -124,14 +122,12 @@ fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_t
     let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
     debug!("checking impl with self type {}", ty::get(self_ty).sty);
     check_builtin_bounds(cx, self_ty, trait_def.bounds, |missing| {
-        cx.tcx.sess.span_err(self_type.span,
-            format!("the type `{}', which does not fulfill `{}`, cannot implement this \
-                    trait",
-                    ty_to_string(cx.tcx, self_ty),
-                    missing.user_string(cx.tcx)).as_slice());
-        cx.tcx.sess.span_note(self_type.span,
-            format!("types implementing this trait must fulfill `{}`",
-                    trait_def.bounds.user_string(cx.tcx)).as_slice());
+        span_err!(cx.tcx.sess, self_type.span, E0142,
+                  "the type `{}', which does not fulfill `{}`, cannot implement this trait",
+                  ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx));
+        span_note!(cx.tcx.sess, self_type.span,
+                   "types implementing this trait must fulfill `{}`",
+                   trait_def.bounds.user_string(cx.tcx));
     });
 
     // If this is a destructor, check kinds.
@@ -191,10 +187,9 @@ fn check_for_block(cx: &Context, fv: &freevar_entry,
     }
 
     fn check_for_bare(cx: &Context, fv: &freevar_entry) {
-        cx.tcx.sess.span_err(
-            fv.span,
-            "can't capture dynamic environment in a fn item; \
-            use the || { ... } closure form instead");
+        span_err!(cx.tcx.sess, fv.span, E0143,
+                  "can't capture dynamic environment in a fn item; \
+                   use the || {} closure form instead", "{ ... }");
     } // same check is done in resolve.rs, but shouldn't be done
 
     let fty = ty::node_id_to_type(cx.tcx, id);
@@ -494,12 +489,11 @@ pub fn check_typaram_bounds(cx: &Context,
                          ty,
                          type_param_def.bounds.builtin_bounds,
                          |missing| {
-        cx.tcx.sess.span_err(
-            sp,
-            format!("instantiating a type parameter with an incompatible type \
-                     `{}`, which does not fulfill `{}`",
-                    ty_to_string(cx.tcx, ty),
-                    missing.user_string(cx.tcx)).as_slice());
+        span_err!(cx.tcx.sess, sp, E0144,
+                  "instantiating a type parameter with an incompatible type \
+                   `{}`, which does not fulfill `{}`",
+                   ty_to_string(cx.tcx, ty),
+                   missing.user_string(cx.tcx));
     });
 }
 
@@ -511,36 +505,32 @@ pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t,
         // Emit a less mysterious error message in this case.
         match referenced_ty {
             Some(rty) => {
-                cx.tcx.sess.span_err(sp,
-                format!("cannot implicitly borrow variable of type `{}` in a \
-                         bounded stack closure (implicit reference does not \
-                         fulfill `{}`)",
-                        ty_to_string(cx.tcx, rty),
-                        missing.user_string(cx.tcx)).as_slice())
+                span_err!(cx.tcx.sess, sp, E0145,
+                    "cannot implicitly borrow variable of type `{}` in a \
+                     bounded stack closure (implicit reference does not fulfill `{}`)",
+                    ty_to_string(cx.tcx, rty), missing.user_string(cx.tcx));
             }
             None => {
-                cx.tcx.sess.span_err(sp,
-                format!("cannot capture variable of type `{}`, which does \
-                         not fulfill `{}`, in a bounded closure",
-                        ty_to_string(cx.tcx, ty),
-                        missing.user_string(cx.tcx)).as_slice())
+                span_err!(cx.tcx.sess, sp, E0146,
+                    "cannot capture variable of type `{}`, which does \
+                     not fulfill `{}`, in a bounded closure",
+                    ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx));
             }
         }
-        cx.tcx.sess.span_note(
-            sp,
-            format!("this closure's environment must satisfy `{}`",
-                    bounds.user_string(cx.tcx)).as_slice());
+        span_note!(cx.tcx.sess, sp,
+            "this closure's environment must satisfy `{}`",
+            bounds.user_string(cx.tcx));
     });
 }
 
 pub fn check_trait_cast_bounds(cx: &Context, sp: Span, ty: ty::t,
                                bounds: ty::BuiltinBounds) {
     check_builtin_bounds(cx, ty, bounds, |missing| {
-        cx.tcx.sess.span_err(sp,
-            format!("cannot pack type `{}`, which does not fulfill \
-                     `{}`, as a trait bounded by {}",
-                    ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx),
-                    bounds.user_string(cx.tcx)).as_slice());
+        span_err!(cx.tcx.sess, sp, E0147,
+            "cannot pack type `{}`, which does not fulfill `{}`, as a trait bounded by {}",
+            ty_to_string(cx.tcx, ty),
+            missing.user_string(cx.tcx),
+            bounds.user_string(cx.tcx));
     });
 }
 
@@ -549,26 +539,26 @@ fn check_copy(cx: &Context, ty: ty::t, sp: Span, reason: &str) {
            ty_to_string(cx.tcx, ty),
            ty::type_contents(cx.tcx, ty).to_string());
     if ty::type_moves_by_default(cx.tcx, ty) {
-        cx.tcx.sess.span_err(
-            sp,
-            format!("copying a value of non-copyable type `{}`",
-                    ty_to_string(cx.tcx, ty)).as_slice());
-        cx.tcx.sess.span_note(sp, format!("{}", reason).as_slice());
+        span_err!(cx.tcx.sess, sp, E0148,
+            "copying a value of non-copyable type `{}`",
+            ty_to_string(cx.tcx, ty));
+        span_note!(cx.tcx.sess, sp, "{}", reason.as_slice());
     }
 }
 
 pub fn check_static(tcx: &ty::ctxt, ty: ty::t, sp: Span) -> bool {
     if !ty::type_is_static(tcx, ty) {
         match ty::get(ty).sty {
-          ty::ty_param(..) => {
-            tcx.sess.span_err(sp,
-                format!("value may contain references; \
-                         add `'static` bound to `{}`",
-                        ty_to_string(tcx, ty)).as_slice());
-          }
-          _ => {
-            tcx.sess.span_err(sp, "value may contain references");
-          }
+            ty::ty_param(..) => {
+                span_err!(tcx.sess, sp, E0149,
+                    "value may contain references; \
+                     add `'static` bound to `{}`",
+                     ty_to_string(tcx, ty));
+            }
+            _ => {
+                span_err!(tcx.sess, sp, E0150,
+                    "value may contain references");
+            }
         }
         false
     } else {
@@ -685,11 +675,9 @@ fn is_ReScope(r: ty::Region) -> bool {
 // Ensure that `ty` has a statically known size (i.e., it has the `Sized` bound).
 fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) {
     if !ty::type_is_sized(tcx, ty) {
-        tcx.sess.span_err(sp,
-                          format!("variable `{}` has dynamically sized type \
-                                   `{}`",
-                                  name,
-                                  ty_to_string(tcx, ty)).as_slice());
+        span_err!(tcx.sess, sp, E0151,
+            "variable `{}` has dynamically sized type `{}`",
+            name, ty_to_string(tcx, ty));
     }
 }
 
index 1a1d47b254770bd87293fea411963c95af53abc0..9abc9226c136456ade077a9f22b1e4fbb46d43c8 100644 (file)
@@ -27,6 +27,7 @@
 use syntax::ast;
 use syntax::ast_util::local_def;
 use syntax::attr::AttrMetaMethods;
+use syntax::codemap::{DUMMY_SP, Span};
 use syntax::parse::token::InternedString;
 use syntax::visit::Visitor;
 use syntax::visit;
@@ -122,7 +123,7 @@ fn visit_item(&mut self, item: &ast::Item, _: ()) {
 
                 match item_index {
                     Some(item_index) => {
-                        self.collect_item(item_index, local_def(item.id))
+                        self.collect_item(item_index, local_def(item.id), item.span)
                     }
                     None => {}
                 }
@@ -147,13 +148,13 @@ pub fn new(session: &'a Session) -> LanguageItemCollector<'a> {
         }
     }
 
-    pub fn collect_item(&mut self, item_index: uint, item_def_id: ast::DefId) {
+    pub fn collect_item(&mut self, item_index: uint,
+                        item_def_id: ast::DefId, span: Span) {
         // Check for duplicates.
         match self.items.items.get(item_index) {
             &Some(original_def_id) if original_def_id != item_def_id => {
-                self.session.err(format!("duplicate entry for `{}`",
-                                         LanguageItems::item_name(
-                                             item_index)).as_slice());
+                span_err!(self.session, span, E0152,
+                    "duplicate entry for `{}`", LanguageItems::item_name(item_index));
             }
             &Some(_) | &None => {
                 // OK.
@@ -173,7 +174,7 @@ pub fn collect_external_language_items(&mut self) {
         crate_store.iter_crate_data(|crate_number, _crate_metadata| {
             each_lang_item(crate_store, crate_number, |node_id, item_index| {
                 let def_id = ast::DefId { krate: crate_number, node: node_id };
-                self.collect_item(item_index, def_id);
+                self.collect_item(item_index, def_id, DUMMY_SP);
                 true
             });
         })
index cd736197a24cd317849066a8ed411d94281d5602..a0adbf6e920ea935ab6a9a45655b72c6f4e23491 100644 (file)
@@ -4016,14 +4016,17 @@ fn resolve_struct(&mut self,
                                 this.record_def(path_id, (def, lp));
                             }
                             Some((DefStruct(_), _)) => {
-                                this.session.span_err(t.span,
-                                                      "super-struct is defined \
-                                                       in a different crate")
+                                span_err!(this.session, t.span, E0154,
+                                    "super-struct is defined in a different crate");
                             },
-                            Some(_) => this.session.span_err(t.span,
-                                                             "super-struct is not a struct type"),
-                            None => this.session.span_err(t.span,
-                                                          "super-struct could not be resolved"),
+                            Some(_) => {
+                                span_err!(this.session, t.span, E0155,
+                                    "super-struct is not a struct type");
+                            }
+                            None => {
+                                span_err!(this.session, t.span, E0156,
+                                    "super-struct could not be resolved");
+                            }
                         }
                     },
                     _ => this.session.span_bug(t.span, "path not mapped to a TyPath")
@@ -4297,17 +4300,13 @@ fn resolve_type(&mut self, ty: &Ty) {
                             if path.segments
                                    .iter()
                                    .any(|s| !s.lifetimes.is_empty()) {
-                                self.session.span_err(path.span,
-                                                      "lifetime parameters \
-                                                       are not allowed on \
-                                                       this type")
+                                span_err!(self.session, path.span, E0157,
+                                    "lifetime parameters are not allowed on this type");
                             } else if path.segments
                                           .iter()
                                           .any(|s| s.types.len() > 0) {
-                                self.session.span_err(path.span,
-                                                      "type parameters are \
-                                                       not allowed on this \
-                                                       type")
+                                span_err!(self.session, path.span, E0153,
+                                    "type parameters are not allowed on this type");
                             }
                         }
                         None => {
index 1d0108fa3f7f29e2dce5cbbc42be861e4f023fb6..54c30e721548d4b93073bbe58db8f9691b1ef84d 100644 (file)
@@ -674,11 +674,10 @@ pub fn trans_case<'a>(bcx: &'a Block<'a>, r: &Repr, discr: Disr)
 }
 
 /**
- * Begin initializing a new value of the given case of the given
- * representation.  The fields, if any, should then be initialized via
- * `trans_field_ptr`.
+ * Set the discriminant for a new value of the given case of the given
+ * representation.
  */
-pub fn trans_start_init(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
+pub fn trans_set_discr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
     match *r {
         CEnum(ity, min, max) => {
             assert_discr_in_range(ity, min, max, discr);
index 98342bfbcdc320643aa0d804544d3d7e6c46887a..7d7922ebfa90c56be16c22103456a4ac6b9f7c02 100644 (file)
@@ -80,7 +80,6 @@
 use std::cell::{Cell, RefCell};
 use std::rc::Rc;
 use std::{i8, i16, i32, i64};
-use std::gc::Gc;
 use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel, Rust, RustCall};
 use syntax::abi::{RustIntrinsic, Abi};
 use syntax::ast_util::{local_def, is_local};
@@ -1704,6 +1703,59 @@ pub fn trans_enum_variant(ccx: &CrateContext,
         llfndecl);
 }
 
+pub fn trans_named_tuple_constructor<'a>(mut bcx: &'a Block<'a>,
+                                         ctor_ty: ty::t,
+                                         disr: ty::Disr,
+                                         args: callee::CallArgs,
+                                         dest: expr::Dest) -> Result<'a> {
+
+    let ccx = bcx.fcx.ccx;
+    let tcx = &ccx.tcx;
+
+    let result_ty = match ty::get(ctor_ty).sty {
+        ty::ty_bare_fn(ref bft) => bft.sig.output,
+        _ => ccx.sess().bug(
+            format!("trans_enum_variant_constructor: \
+                     unexpected ctor return type {}",
+                     ctor_ty.repr(tcx)).as_slice())
+    };
+
+    // Get location to store the result. If the user does not care about
+    // the result, just make a stack slot
+    let llresult = match dest {
+        expr::SaveIn(d) => d,
+        expr::Ignore => {
+            if !type_is_zero_size(ccx, result_ty) {
+                alloc_ty(bcx, result_ty, "constructor_result")
+            } else {
+                C_undef(type_of::type_of(ccx, result_ty))
+            }
+        }
+    };
+
+    if !type_is_zero_size(ccx, result_ty) {
+        let repr = adt::represent_type(ccx, result_ty);
+
+        match args {
+            callee::ArgExprs(exprs) => {
+                let fields = exprs.iter().map(|x| *x).enumerate().collect::<Vec<_>>();
+                bcx = expr::trans_adt(bcx, &*repr, disr, fields.as_slice(),
+                                      None, expr::SaveIn(llresult));
+            }
+            _ => ccx.sess().bug("expected expr as arguments for variant/struct tuple constructor")
+        }
+    }
+
+    // If the caller doesn't care about the result
+    // drop the temporary we made
+    let bcx = match dest {
+        expr::SaveIn(_) => bcx,
+        expr::Ignore => glue::drop_ty(bcx, llresult, result_ty)
+    };
+
+    Result::new(bcx, llresult)
+}
+
 pub fn trans_tuple_struct(ccx: &CrateContext,
                           _fields: &[ast::StructField],
                           ctor_id: ast::NodeId,
@@ -1746,7 +1798,6 @@ fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext,
 
     if !type_is_zero_size(fcx.ccx, result_ty) {
         let repr = adt::represent_type(ccx, result_ty);
-        adt::trans_start_init(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
         for (i, arg_datum) in arg_datums.move_iter().enumerate() {
             let lldestptr = adt::trans_field_ptr(bcx,
                                                  &*repr,
@@ -1755,36 +1806,12 @@ fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext,
                                                  i);
             arg_datum.store_to(bcx, lldestptr);
         }
+        adt::trans_set_discr(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
     }
 
     finish_fn(&fcx, bcx, result_ty);
 }
 
-fn trans_enum_def(ccx: &CrateContext, enum_definition: &ast::EnumDef,
-                  sp: Span, id: ast::NodeId, vi: &[Rc<ty::VariantInfo>],
-                  i: &mut uint) {
-    for variant in enum_definition.variants.iter() {
-        let disr_val = vi[*i].disr_val;
-        *i += 1;
-
-        match variant.node.kind {
-            ast::TupleVariantKind(ref args) if args.len() > 0 => {
-                let llfn = get_item_val(ccx, variant.node.id);
-                trans_enum_variant(ccx, id, &**variant, args.as_slice(),
-                                   disr_val, &param_substs::empty(), llfn);
-            }
-            ast::TupleVariantKind(_) => {
-                // Nothing to do.
-            }
-            ast::StructVariantKind(struct_def) => {
-                trans_struct_def(ccx, struct_def);
-            }
-        }
-    }
-
-    enum_variant_size_lint(ccx, enum_definition, sp, id);
-}
-
 fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span, id: ast::NodeId) {
     let mut sizes = Vec::new(); // does no allocation if no pushes, thankfully
 
@@ -1877,12 +1904,8 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
       ast::ItemMod(ref m) => {
         trans_mod(ccx, m);
       }
-      ast::ItemEnum(ref enum_definition, ref generics) => {
-        if !generics.is_type_parameterized() {
-            let vi = ty::enum_variants(ccx.tcx(), local_def(item.id));
-            let mut i = 0;
-            trans_enum_def(ccx, enum_definition, item.span, item.id, vi.as_slice(), &mut i);
-        }
+      ast::ItemEnum(ref enum_definition, _) => {
+        enum_variant_size_lint(ccx, enum_definition, item.span, item.id);
       }
       ast::ItemStatic(_, m, ref expr) => {
           // Recurse on the expression to catch items in blocks
@@ -1909,11 +1932,6 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
       ast::ItemForeignMod(ref foreign_mod) => {
         foreign::trans_foreign_mod(ccx, foreign_mod);
       }
-      ast::ItemStruct(struct_def, ref generics) => {
-        if !generics.is_type_parameterized() {
-            trans_struct_def(ccx, struct_def);
-        }
-      }
       ast::ItemTrait(..) => {
         // Inside of this trait definition, we won't be actually translating any
         // functions, but the trait still needs to be walked. Otherwise default
@@ -1926,20 +1944,6 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
     }
 }
 
-pub fn trans_struct_def(ccx: &CrateContext, struct_def: Gc<ast::StructDef>) {
-    // If this is a tuple-like struct, translate the constructor.
-    match struct_def.ctor_id {
-        // We only need to translate a constructor if there are fields;
-        // otherwise this is a unit-like struct.
-        Some(ctor_id) if struct_def.fields.len() > 0 => {
-            let llfndecl = get_item_val(ccx, ctor_id);
-            trans_tuple_struct(ccx, struct_def.fields.as_slice(),
-                               ctor_id, &param_substs::empty(), llfndecl);
-        }
-        Some(_) | None => {}
-    }
-}
-
 // Translate a module. Doing this amounts to translating the items in the
 // module; there ends up being no artifact (aside from linkage names) of
 // separate modules in the compiled program.  That's because modules exist
index 8eab227ad16f7793da3e69836a979a58faf15fcf..e2ad8b4fd4680a6891587f6b76d42b3a23181707 100644 (file)
@@ -19,6 +19,7 @@
 use arena::TypedArena;
 use back::abi;
 use back::link;
+use driver::session;
 use llvm::{ValueRef, get_param};
 use llvm;
 use metadata::csearch;
@@ -54,6 +55,7 @@
 
 use std::gc::Gc;
 use syntax::ast;
+use syntax::ast_map;
 use synabi = syntax::abi;
 
 pub struct MethodData {
@@ -64,6 +66,10 @@ pub struct MethodData {
 pub enum CalleeData {
     Closure(Datum<Lvalue>),
 
+    // Constructor for enum variant/tuple-like-struct
+    // i.e. Some, Ok
+    NamedTupleConstructor(subst::Substs, ty::Disr),
+
     // Represents a (possibly monomorphized) top-level fn item or method
     // item. Note that this is just the fn-ptr and is not a Rust closure
     // value (which is a pair).
@@ -134,6 +140,23 @@ fn trans_def<'a>(bcx: &'a Block<'a>, def: def::Def, ref_expr: &ast::Expr)
         debug!("trans_def(def={}, ref_expr={})", def.repr(bcx.tcx()), ref_expr.repr(bcx.tcx()));
         let expr_ty = node_id_type(bcx, ref_expr.id);
         match def {
+            def::DefFn(did, _) if {
+                let def_id = if did.krate != ast::LOCAL_CRATE {
+                    inline::maybe_instantiate_inline(bcx.ccx(), did)
+                } else {
+                    did
+                };
+                match bcx.tcx().map.find(def_id.node) {
+                    Some(ast_map::NodeStructCtor(_)) => true,
+                    _ => false
+                }
+            } => {
+                let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+                Callee {
+                    bcx: bcx,
+                    data: NamedTupleConstructor(substs, 0)
+                }
+            }
             def::DefFn(did, _) if match ty::get(expr_ty).sty {
                 ty::ty_bare_fn(ref f) => f.abi == synabi::RustIntrinsic,
                 _ => false
@@ -158,14 +181,23 @@ fn trans_def<'a>(bcx: &'a Block<'a>, def: def::Def, ref_expr: &ast::Expr)
                                                                 ref_expr.id))
             }
             def::DefVariant(tid, vid, _) => {
-                // nullary variants are not callable
-                assert!(ty::enum_variant_with_id(bcx.tcx(),
-                                                      tid,
-                                                      vid).args.len() > 0u);
-                fn_callee(bcx, trans_fn_ref(bcx, vid, ExprId(ref_expr.id)))
+                let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
+                let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+
+                // Nullary variants are not callable
+                assert!(vinfo.args.len() > 0u);
+
+                Callee {
+                    bcx: bcx,
+                    data: NamedTupleConstructor(substs, vinfo.disr_val)
+                }
             }
-            def::DefStruct(def_id) => {
-                fn_callee(bcx, trans_fn_ref(bcx, def_id, ExprId(ref_expr.id)))
+            def::DefStruct(_) => {
+                let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+                Callee {
+                    bcx: bcx,
+                    data: NamedTupleConstructor(substs, 0)
+                }
             }
             def::DefStatic(..) |
             def::DefArg(..) |
@@ -490,8 +522,27 @@ pub fn trans_fn_ref_with_vtables(
         }
     };
 
-    // We must monomorphise if the fn has type parameters or is a default method.
-    let must_monomorphise = !substs.types.is_empty() || is_default;
+    // We must monomorphise if the fn has type parameters, is a default method,
+    // or is a named tuple constructor.
+    let must_monomorphise = if !substs.types.is_empty() || is_default {
+        true
+    } else if def_id.krate == ast::LOCAL_CRATE {
+        let map_node = session::expect(
+            ccx.sess(),
+            tcx.map.find(def_id.node),
+            || "local item should be in ast map".to_string());
+
+        match map_node {
+            ast_map::NodeVariant(v) => match v.node.kind {
+                ast::TupleVariantKind(ref args) => args.len() > 0,
+                _ => false
+            },
+            ast_map::NodeStructCtor(_) => true,
+            _ => false
+        }
+    } else {
+        false
+    };
 
     // Create a monomorphic version of generic functions
     if must_monomorphise {
@@ -710,6 +761,14 @@ pub fn trans_call_inner<'a>(
                                                    arg_cleanup_scope, args,
                                                    dest.unwrap(), substs);
         }
+        NamedTupleConstructor(substs, disr) => {
+            assert!(dest.is_some());
+            fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
+
+            let ctor_ty = callee_ty.subst(bcx.tcx(), &substs);
+            return base::trans_named_tuple_constructor(bcx, ctor_ty, disr,
+                                                       args, dest.unwrap());
+        }
     };
 
     // Intrinsics should not become actual functions.
index a3d8ab1733f97cbe39409ca1001eba86f01bbd15..ed6050b6543bc40c5235c4a624d6736e2600e1bb 100644 (file)
@@ -502,7 +502,6 @@ pub fn trans_unboxed_closure<'a>(
     let repr = adt::represent_type(bcx.ccx(), node_id_type(bcx, id));
 
     // Create the closure.
-    adt::trans_start_init(bcx, &*repr, dest_addr, 0);
     for freevar in freevars_ptr.iter() {
         let datum = expr::trans_local_var(bcx, freevar.def);
         let upvar_slot_dest = adt::trans_field_ptr(bcx,
@@ -512,6 +511,7 @@ pub fn trans_unboxed_closure<'a>(
                                                    0);
         bcx = datum.store_to(bcx, upvar_slot_dest);
     }
+    adt::trans_set_discr(bcx, &*repr, dest_addr, 0);
 
     bcx
 }
index e7bde00b3ded9d1ae2c5c771bc1a448ba3d6f456..68f577faefed0521a7295b3ea8d552153e7bf22c 100644 (file)
@@ -876,8 +876,8 @@ fn trans_def_dps_unadjusted<'a>(
                 // Nullary variant.
                 let ty = expr_ty(bcx, ref_expr);
                 let repr = adt::represent_type(bcx.ccx(), ty);
-                adt::trans_start_init(bcx, &*repr, lldest,
-                                      variant_info.disr_val);
+                adt::trans_set_discr(bcx, &*repr, lldest,
+                                     variant_info.disr_val);
                 return bcx;
             }
         }
@@ -886,7 +886,7 @@ fn trans_def_dps_unadjusted<'a>(
             match ty::get(ty).sty {
                 ty::ty_struct(did, _) if ty::has_dtor(bcx.tcx(), did) => {
                     let repr = adt::represent_type(bcx.ccx(), ty);
-                    adt::trans_start_init(bcx, &*repr, lldest, 0);
+                    adt::trans_set_discr(bcx, &*repr, lldest, 0);
                 }
                 _ => {}
             }
@@ -1098,7 +1098,7 @@ fn trans_rec_or_struct<'a>(
  * Note that `fields` may be empty; the base expression must always be
  * evaluated for side-effects.
  */
-struct StructBaseInfo {
+pub struct StructBaseInfo {
     /// The base expression; will be evaluated after all explicit fields.
     expr: Gc<ast::Expr>,
     /// The indices of fields to copy paired with their types.
@@ -1114,14 +1114,12 @@ struct StructBaseInfo {
  * - `optbase` contains information on the base struct (if any) from
  * which remaining fields are copied; see comments on `StructBaseInfo`.
  */
-fn trans_adt<'a>(
-             bcx: &'a Block<'a>,
-             repr: &adt::Repr,
-             discr: ty::Disr,
-             fields: &[(uint, Gc<ast::Expr>)],
-             optbase: Option<StructBaseInfo>,
-             dest: Dest)
-             -> &'a Block<'a> {
+pub fn trans_adt<'a>(bcx: &'a Block<'a>,
+                     repr: &adt::Repr,
+                     discr: ty::Disr,
+                     fields: &[(uint, Gc<ast::Expr>)],
+                     optbase: Option<StructBaseInfo>,
+                     dest: Dest) -> &'a Block<'a> {
     let _icx = push_ctxt("trans_adt");
     let fcx = bcx.fcx;
     let mut bcx = bcx;
@@ -1143,8 +1141,6 @@ fn trans_adt<'a>(
     // failure occur before the ADT as a whole is ready.
     let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
 
-    adt::trans_start_init(bcx, repr, addr, discr);
-
     for &(i, ref e) in fields.iter() {
         let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
         let e_ty = expr_ty_adjusted(bcx, &**e);
@@ -1166,6 +1162,8 @@ fn trans_adt<'a>(
         }
     }
 
+    adt::trans_set_discr(bcx, repr, addr, discr);
+
     fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
 
     return bcx;
index 56fda065796778ea7b330c8f872c3984ad5a2330..de169a886cfd3beca65652b51a19e0c3c217e90f 100644 (file)
@@ -129,8 +129,8 @@ pub fn opt_ast_region_to_region<AC:AstConv,RS:RegionScope>(
             match rscope.anon_regions(default_span, 1) {
                 Err(()) => {
                     debug!("optional region in illegal location");
-                    this.tcx().sess.span_err(
-                        default_span, "missing lifetime specifier");
+                    span_err!(this.tcx().sess, default_span, E0106,
+                        "missing lifetime specifier");
                     ty::ReStatic
                 }
 
@@ -187,12 +187,9 @@ fn ast_path_substs<AC:AstConv,RS:RegionScope>(
             rscope.anon_regions(path.span, expected_num_region_params);
 
         if supplied_num_region_params != 0 || anon_regions.is_err() {
-            tcx.sess.span_err(
-                path.span,
-                format!("wrong number of lifetime parameters: \
-                        expected {} but found {}",
-                        expected_num_region_params,
-                        supplied_num_region_params).as_slice());
+            span_err!(tcx.sess, path.span, E0107,
+                "wrong number of lifetime parameters: expected {} but found {}",
+                expected_num_region_params, supplied_num_region_params);
         }
 
         match anon_regions {
@@ -235,10 +232,10 @@ fn ast_path_substs<AC:AstConv,RS:RegionScope>(
 
     if supplied_ty_param_count > required_ty_param_count
         && !this.tcx().sess.features.default_type_params.get() {
-        this.tcx().sess.span_err(path.span, "default type parameters are \
-                                             experimental and possibly buggy");
-        this.tcx().sess.span_note(path.span, "add #![feature(default_type_params)] \
-                                              to the crate attributes to enable");
+        span_err!(this.tcx().sess, path.span, E0108,
+            "default type parameters are experimental and possibly buggy");
+        span_note!(this.tcx().sess, path.span,
+            "add #![feature(default_type_params)] to the crate attributes to enable");
     }
 
     let tps = path.segments.iter().flat_map(|s| s.types.iter())
@@ -309,16 +306,14 @@ fn check_path_args(tcx: &ty::ctxt,
                    flags: uint) {
     if (flags & NO_TPS) != 0u {
         if !path.segments.iter().all(|s| s.types.is_empty()) {
-            tcx.sess.span_err(
-                path.span,
+            span_err!(tcx.sess, path.span, E0109,
                 "type parameters are not allowed on this type");
         }
     }
 
     if (flags & NO_REGIONS) != 0u {
         if !path.segments.last().unwrap().lifetimes.is_empty() {
-            tcx.sess.span_err(
-                path.span,
+            span_err!(tcx.sess, path.span, E0110,
                 "region parameters are not allowed on this type");
         }
     }
@@ -359,8 +354,8 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> {
                             Some(ty::mk_mach_float(ft))
                         }
                         ast::TyStr => {
-                            tcx.sess.span_err(ast_ty.span,
-                                              "bare `str` is not a type");
+                            span_err!(tcx.sess, ast_ty.span, E0037,
+                                      "bare `str` is not a type");
                             // return /something/ so they can at least get more errors
                             Some(ty::mk_uniq(tcx, ty::mk_str(tcx)))
                         }
@@ -408,10 +403,8 @@ pub fn ast_ty_to_builtin_ty<AC:AstConv,
                            .iter()
                            .flat_map(|s| s.types.iter())
                            .count() > 1 {
-                        this.tcx()
-                            .sess
-                            .span_err(path.span,
-                                      "`Box` has only one type parameter")
+                        span_err!(this.tcx().sess, path.span, E0047,
+                                  "`Box` has only one type parameter");
                     }
 
                     for inner_ast_type in path.segments
@@ -428,16 +421,12 @@ pub fn ast_ty_to_builtin_ty<AC:AstConv,
                                                |typ| {
                             match ty::get(typ).sty {
                                 ty::ty_str => {
-                                    this.tcx()
-                                        .sess
-                                        .span_err(path.span,
-                                                  "`Box<str>` is not a type");
+                                    span_err!(this.tcx().sess, path.span, E0111,
+                                              "`Box<str>` is not a type");
                                     ty::mk_err()
                                 }
                                 ty::ty_vec(_, None) => {
-                                    this.tcx()
-                                        .sess
-                                        .span_err(path.span,
+                                        span_err!(this.tcx().sess, path.span, E0112,
                                                   "`Box<[T]>` is not a type");
                                     ty::mk_err()
                                 }
@@ -445,9 +434,8 @@ pub fn ast_ty_to_builtin_ty<AC:AstConv,
                             }
                         }))
                     }
-                    this.tcx().sess.span_err(path.span,
-                                             "not enough type parameters \
-                                              supplied to `Box<T>`");
+                    span_err!(this.tcx().sess, path.span, E0113,
+                              "not enough type parameters supplied to `Box<T>`");
                     Some(ty::mk_err())
                 }
                 def::DefTy(did) | def::DefStruct(did)
@@ -456,10 +444,8 @@ pub fn ast_ty_to_builtin_ty<AC:AstConv,
                            .iter()
                            .flat_map(|s| s.types.iter())
                            .count() > 1 {
-                        this.tcx()
-                            .sess
-                            .span_err(path.span,
-                                      "`Gc` has only one type parameter")
+                        span_err!(this.tcx().sess, path.span, E0048,
+                                  "`Gc` has only one type parameter");
                     }
 
                     for inner_ast_type in path.segments
@@ -476,17 +462,13 @@ pub fn ast_ty_to_builtin_ty<AC:AstConv,
                                                |typ| {
                             match ty::get(typ).sty {
                                 ty::ty_str => {
-                                    this.tcx()
-                                        .sess
-                                        .span_err(path.span,
-                                                  "`Gc<str>` is not a type");
+                                    span_err!(this.tcx().sess, path.span, E0114,
+                                              "`Gc<str>` is not a type");
                                     ty::mk_err()
                                 }
                                 ty::ty_vec(_, None) => {
-                                    this.tcx()
-                                        .sess
-                                        .span_err(path.span,
-                                                  "`Gc<[T]>` is not a type");
+                                    span_err!(this.tcx().sess, path.span, E0115,
+                                              "`Gc<[T]>` is not a type");
                                     ty::mk_err()
                                 }
                                 _ => ty::mk_box(this.tcx(), typ),
index ea82a62d6c684f39b58c6683fe3ec2e740a743b1..c176054b3aed0e0d289cd3c8f767730e09d4e91e 100644 (file)
@@ -206,11 +206,10 @@ fn relate_trait_refs(vcx: &VtableContext,
                 !ty::trait_ref_contains_error(&r_exp_trait_ref)
             {
                 let tcx = vcx.tcx();
-                tcx.sess.span_err(span,
-                    format!("expected {}, but found {} ({})",
-                            ppaux::trait_ref_to_string(tcx, &r_exp_trait_ref),
-                            ppaux::trait_ref_to_string(tcx, &r_act_trait_ref),
-                            ty::type_err_to_str(tcx, err)).as_slice());
+                span_err!(tcx.sess, span, E0095, "expected {}, but found {} ({})",
+                          ppaux::trait_ref_to_string(tcx, &r_exp_trait_ref),
+                          ppaux::trait_ref_to_string(tcx, &r_act_trait_ref),
+                          ty::type_err_to_str(tcx, err));
             }
         }
     }
@@ -536,7 +535,8 @@ fn search_for_vtable(vcx: &VtableContext,
         1 => return Some(found.get(0).clone()),
         _ => {
             if !is_early {
-                vcx.tcx().sess.span_err(span, "multiple applicable methods in scope");
+                span_err!(vcx.tcx().sess, span, E0096,
+                          "multiple applicable methods in scope");
             }
             return Some(found.get(0).clone());
         }
@@ -631,9 +631,7 @@ fn mutability_allowed(a_mutbl: ast::Mutability,
             if !mutability_allowed(mt.mutbl, mutbl) => {
               match ty::get(ty).sty {
                   ty::ty_trait(..) => {
-                      fcx.tcx()
-                         .sess
-                         .span_err(ex.span, "types differ in mutability");
+                      span_err!(fcx.tcx().sess, ex.span, E0097, "types differ in mutability");
                   }
                   _ => {}
               }
@@ -709,11 +707,9 @@ fn mutability_allowed(a_mutbl: ast::Mutability,
           (&ty::ty_uniq(ty), _) => {
               match ty::get(ty).sty {
                   ty::ty_trait(..) => {
-                      fcx.ccx.tcx.sess.span_err(
-                          ex.span,
-                          format!("can only cast an boxed pointer \
-                                   to a boxed object, not a {}",
-                               ty::ty_sort_string(fcx.tcx(), src_ty)).as_slice());
+                      span_err!(fcx.ccx.tcx.sess, ex.span, E0098,
+                                "can only cast an boxed pointer to a boxed object, not a {}",
+                                ty::ty_sort_string(fcx.tcx(), src_ty));
                   }
                   _ => {}
               }
@@ -722,11 +718,9 @@ fn mutability_allowed(a_mutbl: ast::Mutability,
           (&ty::ty_rptr(_, ty::mt{ty, ..}), _) => {
               match ty::get(ty).sty {
                   ty::ty_trait(..) => {
-                      fcx.ccx.tcx.sess.span_err(
-                          ex.span,
-                          format!("can only cast an &-pointer \
-                                   to an &-object, not a {}",
-                                  ty::ty_sort_string(fcx.tcx(), src_ty)).as_slice());
+                      span_err!(fcx.ccx.tcx.sess, ex.span, E0099,
+                                "can only cast an &-pointer to an &-object, not a {}",
+                                ty::ty_sort_string(fcx.tcx(), src_ty));
                   }
                   _ => {}
               }
index d802e3d14433c3590a10e319b7d328e0ca95af56..c3e7d06f3f896dd28a458b41955237442946da0c 100644 (file)
@@ -261,9 +261,8 @@ fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
                             Some(&def::DefStruct(_)) => {
                             }
                             _ => {
-                                self.tcx().sess.span_err(
-                                    reason.span(self.tcx()),
-                                    "cannot coerce non-statically resolved bare fn")
+                                span_err!(self.tcx().sess, reason.span(self.tcx()), E0100,
+                                    "cannot coerce non-statically resolved bare fn");
                             }
                         }
 
@@ -431,47 +430,34 @@ fn report_error(&self, e: infer::fixup_err) {
         if !self.tcx.sess.has_errors() {
             match self.reason {
                 ResolvingExpr(span) => {
-                    self.tcx.sess.span_err(
-                        span,
-                        format!("cannot determine a type for \
-                                 this expression: {}",
-                                infer::fixup_err_to_string(e)).as_slice())
+                    span_err!(self.tcx.sess, span, E0101,
+                        "cannot determine a type for this expression: {}",
+                        infer::fixup_err_to_string(e));
                 }
 
                 ResolvingLocal(span) => {
-                    self.tcx.sess.span_err(
-                        span,
-                        format!("cannot determine a type for \
-                                 this local variable: {}",
-                                infer::fixup_err_to_string(e)).as_slice())
+                    span_err!(self.tcx.sess, span, E0102,
+                        "cannot determine a type for this local variable: {}",
+                        infer::fixup_err_to_string(e));
                 }
 
                 ResolvingPattern(span) => {
-                    self.tcx.sess.span_err(
-                        span,
-                        format!("cannot determine a type for \
-                                 this pattern binding: {}",
-                                infer::fixup_err_to_string(e)).as_slice())
+                    span_err!(self.tcx.sess, span, E0103,
+                        "cannot determine a type for this pattern binding: {}",
+                        infer::fixup_err_to_string(e));
                 }
 
                 ResolvingUpvar(upvar_id) => {
                     let span = self.reason.span(self.tcx);
-                    self.tcx.sess.span_err(
-                        span,
-                        format!("cannot resolve lifetime for \
-                                 captured variable `{}`: {}",
-                                ty::local_var_name_str(
-                                    self.tcx,
-                                    upvar_id.var_id).get().to_string(),
-                                infer::fixup_err_to_string(e)).as_slice());
+                    span_err!(self.tcx.sess, span, E0104,
+                        "cannot resolve lifetime for captured variable `{}`: {}",
+                        ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_string(),
+                        infer::fixup_err_to_string(e));
                 }
 
                 ResolvingImplRes(span) => {
-                    self.tcx
-                        .sess
-                        .span_err(span,
-                                  "cannot determine a type for impl \
-                                   supertrait");
+                    span_err!(self.tcx.sess, span, E0105,
+                        "cannot determine a type for impl supertrait");
                 }
 
                 ResolvingUnboxedClosure(_) => {
index 9e6d059650cc5b0aede25a72194cde54fcc340d2..fe140cf2c97c28e9fd1d3eee9d14a06828bfd182 100644 (file)
@@ -224,10 +224,10 @@ fn visit_item(&mut self, item: &Item, _: ()) {
                 if !self.cc.ast_type_is_defined_in_local_crate(&**ast_ty) {
                     // This is an error.
                     let session = &self.cc.crate_context.tcx.sess;
-                    session.span_err(item.span,
-                                     "cannot associate methods with a type outside the \
-                                     crate the type is defined in; define and implement \
-                                     a trait or new type instead");
+                    span_err!(session, item.span, E0116,
+                              "cannot associate methods with a type outside the \
+                               crate the type is defined in; define and implement \
+                               a trait or new type instead");
                 }
             }
             ItemImpl(_, Some(ref trait_ref), _, _) => {
@@ -244,9 +244,9 @@ fn visit_item(&mut self, item: &Item, _: ()) {
 
                     if trait_def_id.krate != LOCAL_CRATE {
                         let session = &self.cc.crate_context.tcx.sess;
-                        session.span_err(item.span,
-                                "cannot provide an extension implementation \
-                                where both trait and type are not defined in this crate");
+                        span_err!(session, item.span, E0117,
+                                  "cannot provide an extension implementation \
+                                   where both trait and type are not defined in this crate");
                     }
                 }
 
@@ -302,9 +302,9 @@ fn check_implementation(&self, item: &Item,
                                        self_type.ty) {
                 None => {
                     let session = &self.crate_context.tcx.sess;
-                    session.span_err(item.span,
-                                     "no base type found for inherent implementation; \
-                                      implement a trait or new type instead");
+                    span_err!(session, item.span, E0118,
+                              "no base type found for inherent implementation; \
+                               implement a trait or new type instead");
                 }
                 Some(_) => {
                     // Nothing to do.
@@ -441,22 +441,18 @@ fn check_implementation_coherence_of(&self, trait_def_id: DefId) {
 
                     if self.polytypes_unify(polytype_a.clone(), polytype_b) {
                         let session = &self.crate_context.tcx.sess;
-                        session.span_err(
-                            self.span_of_impl(impl_a),
-                            format!("conflicting implementations for trait `{}`",
-                                    ty::item_path_str(
-                                        self.crate_context.tcx,
-                                        trait_def_id)).as_slice());
+                        span_err!(session, self.span_of_impl(impl_a), E0119,
+                                  "conflicting implementations for trait `{}`",
+                                  ty::item_path_str(self.crate_context.tcx, trait_def_id));
                         if impl_b.krate == LOCAL_CRATE {
-                            session.span_note(self.span_of_impl(impl_b),
-                                              "note conflicting implementation here");
+                            span_note!(session, self.span_of_impl(impl_b),
+                                       "note conflicting implementation here");
                         } else {
                             let crate_store = &self.crate_context.tcx.sess.cstore;
                             let cdata = crate_store.get_crate_data(impl_b.krate);
-                            session.note(
-                                format!("conflicting implementation in crate \
-                                         `{}`",
-                                        cdata.name).as_slice());
+                            span_note!(session, self.span_of_impl(impl_a),
+                                       "conflicting implementation in crate `{}`",
+                                       cdata.name);
                         }
                     }
                 }
@@ -706,10 +702,8 @@ fn populate_destructor_table(&self) {
                         {
                             match tcx.map.find(impl_did.node) {
                                 Some(ast_map::NodeItem(item)) => {
-                                    tcx.sess.span_err((*item).span,
-                                                      "the Drop trait may \
-                                                       only be implemented \
-                                                       on structures");
+                                    span_err!(tcx.sess, item.span, E0120,
+                                        "the Drop trait may only be implemented on structures");
                                 }
                                 _ => {
                                     tcx.sess.bug("didn't find impl in ast \
index 5fd9b85d69aa044f960dffc965d0bb9e81ebc2e5..780faddb88639c8e384bc46882da01caa7dbdb09 100644 (file)
@@ -140,9 +140,8 @@ fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef> {
     }
 
     fn ty_infer(&self, span: Span) -> ty::t {
-        self.tcx.sess.span_err(span, "the type placeholder `_` is not \
-                                      allowed within types on item \
-                                      signatures.");
+        span_err!(self.tcx.sess, span, E0121,
+                  "the type placeholder `_` is not allowed within types on item signatures.");
         ty::mk_err()
     }
 }
@@ -439,10 +438,8 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
                                  thing: &'static str) {
     for ty_param in generics.ty_params.iter() {
         if ty_param.bounds.len() > 0 {
-            ccx.tcx.sess.span_err(
-                span,
-                format!("trait bounds are not allowed in {} definitions",
-                        thing).as_slice());
+            span_err!(ccx.tcx.sess, span, E0122,
+                      "trait bounds are not allowed in {} definitions", thing);
         }
     }
 }
@@ -453,8 +450,8 @@ fn ensure_generics_abi(ccx: &CrateCtxt,
                        generics: &ast::Generics) {
     if generics.ty_params.len() > 0 &&
        !(abi == abi::Rust || abi == abi::RustIntrinsic) {
-        ccx.tcx.sess.span_err(span,
-                              "foreign functions may not use type parameters");
+        span_err!(ccx.tcx.sess, span, E0123,
+                  "foreign functions may not use type parameters");
     }
 }
 
@@ -607,12 +604,10 @@ pub fn convert_struct(ccx: &CrateCtxt,
         if result.name != special_idents::unnamed_field.name {
             let dup = match seen_fields.find(&result.name) {
                 Some(prev_span) => {
-                    tcx.sess.span_err(
-                        f.span,
-                        format!("field `{}` is already declared",
-                                token::get_name(result.name)).as_slice());
-                    tcx.sess.span_note(*prev_span,
-                                       "previously declared here");
+                    span_err!(tcx.sess, f.span, E0124,
+                              "field `{}` is already declared",
+                              token::get_name(result.name));
+                    span_note!(tcx.sess, *prev_span, "previously declared here");
                     true
                 },
                 None => false,
@@ -641,9 +636,9 @@ pub fn convert_struct(ccx: &CrateCtxt,
                             Some(ast_map::NodeItem(i)) => match i.node {
                                 ast::ItemStruct(struct_def, _) => {
                                     if !struct_def.is_virtual {
-                                        tcx.sess.span_err(t.span,
-                                            "struct inheritance is only \
-                                             allowed from virtual structs");
+                                        span_err!(tcx.sess, t.span, E0126,
+                                                  "struct inheritance is only \
+                                                   allowed from virtual structs");
                                     }
                                 },
                                 _ => {},
@@ -862,8 +857,8 @@ fn ensure_supertraits(ccx: &CrateCtxt,
                 {
                     // This means a trait inherited from the same
                     // supertrait more than once.
-                    tcx.sess.span_err(sp, "duplicate supertrait in \
-                                           trait declaration");
+                    span_err!(tcx.sess, sp, E0127,
+                              "duplicate supertrait in trait declaration");
                     break;
                 } else {
                     ty_trait_refs.push(trait_ref);
@@ -1129,10 +1124,9 @@ fn get_or_create_type_parameter_def(ccx: &CrateCtxt,
             ty::walk_ty(ty, |t| {
                 match ty::get(t).sty {
                     ty::ty_param(p) => if p.idx > cur_idx {
-                        ccx.tcx.sess.span_err(
-                            path.span,
-                            "type parameters with a default cannot use \
-                             forward declared identifiers")
+                    span_err!(ccx.tcx.sess, path.span, E0128,
+                              "type parameters with a default cannot use \
+                               forward declared identifiers");
                     },
                     _ => {}
                 }
@@ -1239,12 +1233,11 @@ fn check_bounds_compatible(tcx: &ty::ctxt,
                                                  |trait_ref| {
                 let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id);
                 if trait_def.bounds.contains_elem(ty::BoundSized) {
-                    tcx.sess.span_err(span,
-                        format!("incompatible bounds on type parameter {}, \
-                                 bound {} does not allow unsized type",
-                        token::get_ident(ident),
-                        ppaux::trait_ref_to_string(tcx,
-                                                &*trait_ref)).as_slice());
+                    span_err!(tcx.sess, span, E0129,
+                              "incompatible bounds on type parameter {}, \
+                               bound {} does not allow unsized type",
+                              token::get_ident(ident),
+                              ppaux::trait_ref_to_string(tcx, &*trait_ref));
                 }
                 true
             });
@@ -1263,8 +1256,10 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
         match (*i).pat.node {
             ast::PatIdent(_, _, _) => (),
             ast::PatWild => (),
-            _ => ccx.tcx.sess.span_err((*i).pat.span,
-                    "patterns aren't allowed in foreign function declarations")
+            _ => {
+                span_err!(ccx.tcx.sess, (*i).pat.span, E0130,
+                          "patterns aren't allowed in foreign function declarations");
+            }
         }
     }
 
index aebdb5943826afe1a4724df70914a9d28df24448..4000807ec1b8e87cd7e6b2fc74c27203adfc17e5 100644 (file)
@@ -372,9 +372,8 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                     match it.node {
                         ast::ItemFn(_, _, _, ref ps, _)
                         if ps.is_parameterized() => {
-                            tcx.sess.span_err(
-                                main_span,
-                                "main function is not allowed to have type parameters");
+                            span_err!(ccx.tcx.sess, main_span, E0131,
+                                      "main function is not allowed to have type parameters");
                             return;
                         }
                         _ => ()
@@ -421,9 +420,8 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                     match it.node {
                         ast::ItemFn(_,_,_,ref ps,_)
                         if ps.is_parameterized() => {
-                            tcx.sess.span_err(
-                                start_span,
-                                "start function is not allowed to have type parameters");
+                            span_err!(tcx.sess, start_span, E0132,
+                                      "start function is not allowed to have type parameters");
                             return;
                         }
                         _ => ()
index e28c51d517ea3488775f09ca7dac7f98de5931f1..a56904c9ef4db700d0c2917d7f5b531082327488 100644 (file)
@@ -2795,6 +2795,7 @@ fn check_err<T: Decodable<Decoder, DecoderError>>(to_parse: &'static str,
         }
     }
     #[test]
+    #[ignore] // FIXME(#15763)
     fn test_decode_errors_struct() {
         check_err::<DecodeStruct>("[]", ExpectedError("Object".to_string(), "[]".to_string()));
         check_err::<DecodeStruct>("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}",
index 9a53c941377e44be6bc29810d392bdc92711825e..14027bc1f544fd868dbd0fd3df90742d36dae616 100644 (file)
@@ -1514,54 +1514,44 @@ fn extend<T: Iterator<(K, V)>>(&mut self, mut iter: T) {
 ///     println!("{}", *book);
 /// }
 /// ```
+///
+/// The easiest way to use `HashSet` with a custom type is to derive
+/// `Eq` and `Hash`. We must also derive `PartialEq`, this will in the
+/// future be implied by `Eq`.
+///
+/// ```rust
+/// use std::collections::HashSet;
+///
+/// #[deriving(Hash, Eq, PartialEq, Show)]
+/// struct Viking<'a> {
+///     name: &'a str,
+///     power: uint,
+/// }
+///
+/// let mut vikings = HashSet::new();
+///
+/// vikings.insert(Viking { name: "Einar", power: 9u });
+/// vikings.insert(Viking { name: "Einar", power: 9u });
+/// vikings.insert(Viking { name: "Olaf", power: 4u });
+/// vikings.insert(Viking { name: "Harald", power: 8u });
+///
+/// // Use derived implementation to print the vikings.
+/// for x in vikings.iter() {
+///     println!("{}", x);
+/// }
+/// ```
 #[deriving(Clone)]
 pub struct HashSet<T, H = RandomSipHasher> {
     map: HashMap<T, (), H>
 }
 
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> {
-    fn eq(&self, other: &HashSet<T, H>) -> bool {
-        if self.len() != other.len() { return false; }
-
-        self.iter().all(|key| other.contains(key))
-    }
-}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> Eq for HashSet<T, H> {}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> Collection for HashSet<T, H> {
-    fn len(&self) -> uint { self.map.len() }
-}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> Mutable for HashSet<T, H> {
-    fn clear(&mut self) { self.map.clear() }
-}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> Set<T> for HashSet<T, H> {
-    fn contains(&self, value: &T) -> bool { self.map.contains_key(value) }
-
-    fn is_disjoint(&self, other: &HashSet<T, H>) -> bool {
-        self.iter().all(|v| !other.contains(v))
-    }
-
-    fn is_subset(&self, other: &HashSet<T, H>) -> bool {
-        self.iter().all(|v| other.contains(v))
-    }
-}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> MutableSet<T> for HashSet<T, H> {
-    fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) }
-
-    fn remove(&mut self, value: &T) -> bool { self.map.remove(value) }
-}
-
 impl<T: Hash + Eq> HashSet<T, RandomSipHasher> {
-    /// Create an empty HashSet
+    /// Create an empty HashSet.
     ///
     /// # Example
     ///
     /// ```rust
-    /// use std::collections::HashSet;
+    /// use std::collections::HashSet;
     /// let mut set: HashSet<int> = HashSet::new();
     /// ```
     #[inline]
@@ -1575,7 +1565,7 @@ pub fn new() -> HashSet<T, RandomSipHasher> {
     /// # Example
     ///
     /// ```rust
-    /// use std::collections::HashSet;
+    /// use std::collections::HashSet;
     /// let mut set: HashSet<int> = HashSet::with_capacity(10);
     /// ```
     #[inline]
@@ -1589,6 +1579,17 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
     /// keys.
     ///
     /// The hash set is also created with the default initial capacity.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::collections::HashSet;
+    /// use std::hash::sip::SipHasher;
+    ///
+    /// let h = SipHasher::new();
+    /// let mut set = HashSet::with_hasher(h);
+    /// set.insert(2u);
+    /// ```
     #[inline]
     pub fn with_hasher(hasher: H) -> HashSet<T, H> {
         HashSet::with_capacity_and_hasher(INITIAL_CAPACITY, hasher)
@@ -1601,6 +1602,17 @@ pub fn with_hasher(hasher: H) -> HashSet<T, H> {
     /// is designed to allow `HashSet`s to be resistant to attacks that
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::collections::HashSet;
+    /// use std::hash::sip::SipHasher;
+    ///
+    /// let h = SipHasher::new();
+    /// let mut set = HashSet::with_capacity_and_hasher(10u, h);
+    /// set.insert(1i);
+    /// ```
     #[inline]
     pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashSet<T, H> {
         HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) }
@@ -1611,7 +1623,7 @@ pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashSet<T, H> {
     /// # Example
     ///
     /// ```rust
-    /// use std::collections::HashSet;
+    /// use std::collections::HashSet;
     /// let mut set: HashSet<int> = HashSet::new();
     /// set.reserve(10);
     /// ```
@@ -1621,6 +1633,45 @@ pub fn reserve(&mut self, n: uint) {
 
     /// Returns true if the hash set contains a value equivalent to the
     /// given query value.
+    ///
+    /// # Example
+    ///
+    /// This is a slightly silly example where we define the number's
+    /// parity as the equivilance class. It is important that the
+    /// values hash the same, which is why we implement `Hash`.
+    ///
+    /// ```rust
+    /// use std::collections::HashSet;
+    /// use std::hash::Hash;
+    /// use std::hash::sip::SipState;
+    ///
+    /// #[deriving(Eq, PartialEq)]
+    /// struct EvenOrOdd {
+    ///     num: uint
+    /// };
+    ///
+    /// impl Hash for EvenOrOdd {
+    ///     fn hash(&self, state: &mut SipState) {
+    ///         let parity = self.num % 2;
+    ///         parity.hash(state);
+    ///     }
+    /// }
+    ///
+    /// impl Equiv<EvenOrOdd> for EvenOrOdd {
+    ///     fn equiv(&self, other: &EvenOrOdd) -> bool {
+    ///         self.num % 2 == other.num % 2
+    ///     }
+    /// }
+    ///
+    /// let mut set = HashSet::new();
+    /// set.insert(EvenOrOdd { num: 3u });
+    ///
+    /// assert!(set.contains_equiv(&EvenOrOdd { num: 3u }));
+    /// assert!(set.contains_equiv(&EvenOrOdd { num: 5u }));
+    /// assert!(!set.contains_equiv(&EvenOrOdd { num: 4u }));
+    /// assert!(!set.contains_equiv(&EvenOrOdd { num: 2u }));
+    ///
+    /// ```
     pub fn contains_equiv<Q: Hash<S> + Equiv<T>>(&self, value: &Q) -> bool {
       self.map.contains_key_equiv(value)
     }
@@ -1631,7 +1682,8 @@ pub fn contains_equiv<Q: Hash<S> + Equiv<T>>(&self, value: &Q) -> bool {
     /// # Example
     ///
     /// ```rust
-    /// # use std::collections::HashSet;
+    /// use std::collections::HashSet;
+    ///
     /// let mut set = HashSet::new();
     /// set.insert("a");
     /// set.insert("b");
@@ -1652,7 +1704,8 @@ pub fn iter<'a>(&'a self) -> SetItems<'a, T> {
     /// # Example
     ///
     /// ```rust
-    /// # use std::collections::HashSet;
+    /// use std::collections::HashSet;
+    ///
     /// let mut set = HashSet::new();
     /// set.insert("a".to_string());
     /// set.insert("b".to_string());
@@ -1674,7 +1727,8 @@ pub fn move_iter(self) -> SetMoveItems<T> {
     /// # Example
     ///
     /// ```rust
-    /// # use std::collections::HashSet;
+    /// use std::collections::HashSet;
+    ///
     /// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
     /// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
     ///
@@ -1703,7 +1757,8 @@ pub fn difference<'a>(&'a self, other: &'a HashSet<T, H>) -> SetAlgebraItems<'a,
     /// # Example
     ///
     /// ```rust
-    /// # use std::collections::HashSet;
+    /// use std::collections::HashSet;
+    ///
     /// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
     /// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
     ///
@@ -1728,7 +1783,8 @@ pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet<T, H>)
     /// # Example
     ///
     /// ```rust
-    /// # use std::collections::HashSet;
+    /// use std::collections::HashSet;
+    ///
     /// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
     /// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
     ///
@@ -1753,7 +1809,8 @@ pub fn intersection<'a>(&'a self, other: &'a HashSet<T, H>)
     /// # Example
     ///
     /// ```rust
-    /// # use std::collections::HashSet;
+    /// use std::collections::HashSet;
+    ///
     /// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
     /// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
     ///
@@ -1771,6 +1828,43 @@ pub fn union<'a>(&'a self, other: &'a HashSet<T, H>)
     }
 }
 
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> {
+    fn eq(&self, other: &HashSet<T, H>) -> bool {
+        if self.len() != other.len() { return false; }
+
+        self.iter().all(|key| other.contains(key))
+    }
+}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> Eq for HashSet<T, H> {}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> Collection for HashSet<T, H> {
+    fn len(&self) -> uint { self.map.len() }
+}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> Mutable for HashSet<T, H> {
+    fn clear(&mut self) { self.map.clear() }
+}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> Set<T> for HashSet<T, H> {
+    fn contains(&self, value: &T) -> bool { self.map.contains_key(value) }
+
+    fn is_disjoint(&self, other: &HashSet<T, H>) -> bool {
+        self.iter().all(|v| !other.contains(v))
+    }
+
+    fn is_subset(&self, other: &HashSet<T, H>) -> bool {
+        self.iter().all(|v| other.contains(v))
+    }
+}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> MutableSet<T> for HashSet<T, H> {
+    fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) }
+
+    fn remove(&mut self, value: &T) -> bool { self.map.remove(value) }
+}
+
+
 impl<T: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         try!(write!(f, "{{"));
index b4af7205c42068fae0ea49c8ec5f5427887bf85b..4db5b93862f96360bd0c794bd511ea9fbe921064 100644 (file)
@@ -44,24 +44,24 @@ macro_rules! __diagnostic_used(
 
 #[macro_export]
 macro_rules! span_err(
-    ($session:expr, $span:expr, $code:ident, $($arg:expr),*) => ({
+    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
         __diagnostic_used!($code);
-        ($session).span_err_with_code($span, format!($($arg),*).as_slice(), stringify!($code))
+        $session.span_err_with_code($span, format!($($message)*).as_slice(), stringify!($code))
     })
 )
 
 #[macro_export]
 macro_rules! span_warn(
-    ($session:expr, $span:expr, $code:ident, $($arg:expr),*) => ({
+    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
         __diagnostic_used!($code);
-        ($session).span_warn_with_code($span, format!($($arg),*).as_slice(), stringify!($code))
+        $session.span_warn_with_code($span, format!($($message)*).as_slice(), stringify!($code))
     })
 )
 
 #[macro_export]
 macro_rules! span_note(
-    ($session:expr, $span:expr, $($arg:expr),*) => ({
-        ($session).span_note($span, format!($($arg),*).as_slice())
+    ($session:expr, $span:expr, $($message:tt)*) => ({
+        ($session).span_note($span, format!($($message)*).as_slice())
     })
 )
 
index 2d98668496cdb52e08c17a2a7d201ce41914106a..b0e23983192f23a8aaf0ae6a20aa6445e056fb22 100644 (file)
@@ -64,7 +64,7 @@ fn mandelbrot<W: io::Writer>(w: uint, mut out: W) -> io::IoResult<()> {
     let chunk_size = h / WORKERS;
 
     // Account for remainders in workload division, e.g. 1000 / 16 = 62.5
-    let first_chunk_size = if h % WORKERS != 0 {
+    let last_chunk_size = if h % WORKERS != 0 {
         chunk_size + h % WORKERS
     } else {
         chunk_size
@@ -87,8 +87,8 @@ fn mandelbrot<W: io::Writer>(w: uint, mut out: W) -> io::IoResult<()> {
             let mut is = Vec::with_capacity(w / WORKERS);
 
             let start = i * chunk_size;
-            let end = if i == 0 {
-                first_chunk_size
+            let end = if i == (WORKERS - 1) {
+                start + last_chunk_size
             } else {
                 (i + 1) * chunk_size
             };
diff --git a/src/test/compile-fail/crate-name-mismatch.rs b/src/test/compile-fail/crate-name-mismatch.rs
new file mode 100644 (file)
index 0000000..589c0be
--- /dev/null
@@ -0,0 +1,16 @@
+// 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.
+
+// compile-flags: --crate-name foo
+
+#![crate_name = "bar"]
+//~^ ERROR: --crate-name and #[crate_name] are required to match, but `foo` != `bar`
+
+fn main() {}
index 723aefb91cb9cd3506b30ca99ed00729faf41214..e3dbc67b7a9ef7fee3a591ed967642797ab1a08e 100644 (file)
@@ -13,5 +13,5 @@ fn bar() {
 }
 
 #[main]
-fn foo() { //~ ERROR multiple 'main' functions
+fn foo() { //~ ERROR multiple functions with a #[main] attribute
 }
index 36da3e6e84a22dcc10e37a7492757d6c9d9a3837..58cc148568ee6dfeb75acf4bc425d29be57bcb85 100644 (file)
@@ -14,6 +14,6 @@ fn main1() {
 
 mod foo {
     #[main]
-    fn main2() { //~ ERROR multiple 'main' functions
+    fn main2() { //~ ERROR multiple functions with a #[main] attribute
     }
 }
index 250602710f57d7c7b8cdd46018c62fd28d8d169b..2fe518324336171c97d0c4bfb37e314979fafd39 100644 (file)
@@ -7,7 +7,5 @@ all:
        rm $(TMPDIR)/$(call BIN,bar)
        $(RUSTC) foo1.rs
        rm $(TMPDIR)/$(call BIN,foo)
-       $(RUSTC) foo1.rs --crate-name bar
-       rm $(TMPDIR)/$(call BIN,bar)
-       $(RUSTC) foo1.rs --crate-name bar -o $(TMPDIR)/bar1
+       $(RUSTC) foo1.rs -o $(TMPDIR)/bar1
        rm $(TMPDIR)/$(call BIN,bar1)
diff --git a/src/test/run-make/extra-filename-with-temp-outputs/Makefile b/src/test/run-make/extra-filename-with-temp-outputs/Makefile
new file mode 100644 (file)
index 0000000..28c22a1
--- /dev/null
@@ -0,0 +1,6 @@
+-include ../tools.mk
+
+all:
+       $(RUSTC) -C extra-filename=bar foo.rs -C save-temps
+       rm $(TMPDIR)/foobar.o
+       rm $(TMPDIR)/$(call BIN,foobar)
diff --git a/src/test/run-make/extra-filename-with-temp-outputs/foo.rs b/src/test/run-make/extra-filename-with-temp-outputs/foo.rs
new file mode 100644 (file)
index 0000000..8ae3d07
--- /dev/null
@@ -0,0 +1,11 @@
+// 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.
+
+fn main() {}
index abc565d31758f29ef7b61aa855e6dfe7e3b5f6ec..95c7d331264e128b04e5dc45af7556173ab5f160 100644 (file)
@@ -10,6 +10,6 @@
 
 // compile-flags:--crate-name crate-name-attr-used -F unused-attribute
 
-#![crate_name = "test"]
+#![crate_name = "crate-name-attr-used"]
 
 fn main() {}