]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #8305 : huonw/rust/triage-fixes, r=cmr
authorbors <bors@rust-lang.org>
Wed, 7 Aug 2013 13:56:19 +0000 (06:56 -0700)
committerbors <bors@rust-lang.org>
Wed, 7 Aug 2013 13:56:19 +0000 (06:56 -0700)
The two deletions are because the test cases are very old (still using `class` and modes!), and, as far as I can tell (since they are so old), the areas they test are well tested by other rpass tests.

36 files changed:
Makefile.in
mk/target.mk
mk/tools.mk
src/compiletest/compiletest.rs
src/libextra/base64.rs
src/libextra/enum_set.rs [new file with mode: 0644]
src/libextra/extra.rs
src/libextra/hex.rs [new file with mode: 0644]
src/libextra/json.rs
src/librustc/driver/driver.rs
src/librustc/metadata/tyencode.rs
src/librustc/middle/cfg/construct.rs
src/librustc/middle/kind.rs
src/librustc/middle/trans/_match.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/foreign.rs
src/librustc/middle/ty.rs
src/librustc/rustc.rs
src/librustc/util/enum_set.rs [deleted file]
src/librustc/util/ppaux.rs
src/librusti/rusti.rs
src/libstd/borrow.rs
src/libstd/cmp.rs
src/libstd/iterator.rs
src/libstd/managed.rs
src/libstd/num/num.rs
src/libstd/owned.rs
src/libstd/rt/io/flate.rs
src/libstd/rt/kill.rs
src/libstd/str.rs
src/libstd/str/ascii.rs
src/libstd/task/spawn.rs
src/libsyntax/ast_map.rs
src/libsyntax/ast_util.rs
src/libsyntax/ext/deriving/cmp/totalord.rs
src/test/run-pass/deriving-cmp-shortcircuit.rs [new file with mode: 0644]

index d78176e569999ad162b0f03b0f59c0522454f744..a9a41a073d03366291a404187213a417cd608de6 100644 (file)
@@ -297,7 +297,7 @@ COMPILER_INPUTS := $(wildcard $(addprefix $(S)src/librustc/,      \
 
 LIBSYNTAX_CRATE := $(S)src/libsyntax/syntax.rs
 LIBSYNTAX_INPUTS := $(wildcard $(addprefix $(S)src/libsyntax/, \
-                           *.rs */*.rs */*/*.rs))
+                           *.rs */*.rs */*/*.rs */*/*/*.rs))
 
 DRIVER_CRATE := $(S)src/driver/driver.rs
 
index b9221a56b9d85ed331e46695de4e833b3b1f68c9..fce6e8a9e2fccf190bf34d8c1a51ec93e3202f7e 100644 (file)
@@ -48,7 +48,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)): \
                | $$(TLIB$(1)_T_$(2)_H_$(3))/
        @$$(call E, compile_and_link: $$@)
        $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(2)),$$(notdir $$@))
-       $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) -o $$@ $$< && touch $$@
+       $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
        $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(2)),$$(notdir $$@))
 
 $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)): \
@@ -58,7 +58,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)): \
                | $$(TLIB$(1)_T_$(2)_H_$(3))/
        @$$(call E, compile_and_link: $$@)
        $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(2)),$$(notdir $$@))
-       $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) -o $$@ $$< && touch $$@
+       $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
        $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(2)),$$(notdir $$@))
 
 $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \
@@ -69,7 +69,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \
                | $$(TLIB$(1)_T_$(2)_H_$(3))/
        @$$(call E, compile_and_link: $$@)
        $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(2)),$$(notdir $$@))
-       $$(STAGE$(1)_T_$(2)_H_$(3)) $(BORROWCK) -o $$@ $$< && touch $$@
+       $$(STAGE$(1)_T_$(2)_H_$(3)) $(BORROWCK) --out-dir $$(@D) $$< && touch $$@
        $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(2)),$$(notdir $$@))
 
 # Only build the compiler for host triples
@@ -90,7 +90,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)):              \
                | $$(TLIB$(1)_T_$(2)_H_$(3))/
        @$$(call E, compile_and_link: $$@)
        $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(2)),$$(notdir $$@))
-       $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@
+       $$(STAGE$(1)_T_$(2)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
        $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(2)),$$(notdir $$@))
 
 $$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(3)):                    \
index 56aad4f10a2594ed12c5ce5a379bd1d94cdc6718..32c034d878cb9671a5ef7ada47c308dd9be0e550 100644 (file)
@@ -49,7 +49,7 @@ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)):            \
                | $$(TLIB$(1)_T_$(4)_H_$(3))/
        @$$(call E, compile_and_link: $$@)
        $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTPKG_GLOB_$(4)),$$(notdir $$@))
-       $$(STAGE$(1)_T_$(4)_H_$(3)) $$(WFLAGS_ST$(1)) -o $$@ $$< && touch $$@
+       $$(STAGE$(1)_T_$(4)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
        $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTPKG_GLOB_$(4)),$$(notdir $$@))
 
 $$(TBIN$(1)_T_$(4)_H_$(3))/rustpkg$$(X_$(4)):                          \
@@ -67,7 +67,7 @@ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)):            \
                | $$(TLIB$(1)_T_$(4)_H_$(3))/
        @$$(call E, compile_and_link: $$@)
        $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOC_GLOB_$(4)),$$(notdir $$@))
-       $$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
+       $$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
        $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOC_GLOB_$(4)),$$(notdir $$@))
 
 $$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X_$(4)):                  \
@@ -85,7 +85,7 @@ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)):              \
                | $$(TLIB$(1)_T_$(4)_H_$(3))/
        @$$(call E, compile_and_link: $$@)
        $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTI_GLOB_$(4)),$$(notdir $$@))
-       $$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
+       $$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
        $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTI_GLOB_$(4)),$$(notdir $$@))
 
 $$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X_$(4)):                    \
@@ -106,7 +106,7 @@ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUST_$(4)):             \
                | $$(TLIB$(1)_T_$(4)_H_$(3))/
        @$$(call E, compile_and_link: $$@)
        $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUST_GLOB_$(4)),$$(notdir $$@))
-       $$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
+       $$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
        $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUST_GLOB_$(4)),$$(notdir $$@))
 
 $$(TBIN$(1)_T_$(4)_H_$(3))/rust$$(X_$(4)):                     \
index 094d176980b81d2ebafae44bcb9787cac23dc044..4e4261e8b2bbda8b8dd19dfc6a3d3704a941dd6d 100644 (file)
@@ -11,7 +11,6 @@
 #[crate_type = "bin"];
 
 #[allow(non_camel_case_types)];
-#[allow(unrecognized_lint)]; // NOTE: remove after snapshot
 #[deny(warnings)];
 
 extern mod extra;
index 550b891a4db16c22356d20be362f55ca7b06e6cb..b4431004bd74cff0dd38693c5093d4b590c479be 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 //! Base64 binary-to-text encoding
+use std::str;
 
 /// Available encoding character sets
 pub enum CharacterSet {
@@ -40,21 +41,13 @@ pub struct Config {
 pub static MIME: Config =
     Config {char_set: Standard, pad: true, line_length: Some(76)};
 
-static STANDARD_CHARS: [char, ..64] = [
-    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
-    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
-    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
-    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
-    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
-];
-
-static URLSAFE_CHARS: [char, ..64] = [
-    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
-    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
-    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
-    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
-    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
-];
+static STANDARD_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+                                             "abcdefghijklmnopqrstuvwxyz",
+                                             "0123456789+/");
+
+static URLSAFE_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+                                            "abcdefghijklmnopqrstuvwxyz",
+                                            "0123456789-_");
 
 /// A trait for converting a value to base64 encoding.
 pub trait ToBase64 {
@@ -80,12 +73,12 @@ impl<'self> ToBase64 for &'self [u8] {
      * ~~~
      */
     fn to_base64(&self, config: Config) -> ~str {
-        let chars = match config.char_set {
+        let bytes = match config.char_set {
             Standard => STANDARD_CHARS,
             UrlSafe => URLSAFE_CHARS
         };
 
-        let mut s = ~"";
+        let mut v: ~[u8] = ~[];
         let mut i = 0;
         let mut cur_length = 0;
         let len = self.len();
@@ -93,7 +86,8 @@ fn to_base64(&self, config: Config) -> ~str {
             match config.line_length {
                 Some(line_length) =>
                     if cur_length >= line_length {
-                        s.push_str("\r\n");
+                        v.push('\r' as u8);
+                        v.push('\n' as u8);
                         cur_length = 0;
                     },
                 None => ()
@@ -104,10 +98,10 @@ fn to_base64(&self, config: Config) -> ~str {
                     (self[i + 2] as u32);
 
             // This 24-bit number gets separated into four 6-bit numbers.
-            s.push_char(chars[(n >> 18) & 63]);
-            s.push_char(chars[(n >> 12) & 63]);
-            s.push_char(chars[(n >> 6 ) & 63]);
-            s.push_char(chars[n & 63]);
+            v.push(bytes[(n >> 18) & 63]);
+            v.push(bytes[(n >> 12) & 63]);
+            v.push(bytes[(n >> 6 ) & 63]);
+            v.push(bytes[n & 63]);
 
             cur_length += 4;
             i += 3;
@@ -117,7 +111,8 @@ fn to_base64(&self, config: Config) -> ~str {
             match config.line_length {
                 Some(line_length) =>
                     if cur_length >= line_length {
-                        s.push_str("\r\n");
+                        v.push('\r' as u8);
+                        v.push('\n' as u8);
                     },
                 None => ()
             }
@@ -129,48 +124,29 @@ fn to_base64(&self, config: Config) -> ~str {
             0 => (),
             1 => {
                 let n = (self[i] as u32) << 16;
-                s.push_char(chars[(n >> 18) & 63]);
-                s.push_char(chars[(n >> 12) & 63]);
+                v.push(bytes[(n >> 18) & 63]);
+                v.push(bytes[(n >> 12) & 63]);
                 if config.pad {
-                    s.push_str("==");
+                    v.push('=' as u8);
+                    v.push('=' as u8);
                 }
             }
             2 => {
                 let n = (self[i] as u32) << 16 |
                     (self[i + 1u] as u32) << 8;
-                s.push_char(chars[(n >> 18) & 63]);
-                s.push_char(chars[(n >> 12) & 63]);
-                s.push_char(chars[(n >> 6 ) & 63]);
+                v.push(bytes[(n >> 18) & 63]);
+                v.push(bytes[(n >> 12) & 63]);
+                v.push(bytes[(n >> 6 ) & 63]);
                 if config.pad {
-                    s.push_char('=');
+                    v.push('=' as u8);
                 }
             }
             _ => fail!("Algebra is broken, please alert the math police")
         }
-        s
-    }
-}
 
-impl<'self> ToBase64 for &'self str {
-    /**
-     * Convert any string (literal, `@`, `&`, or `~`) to base64 encoding.
-     *
-     *
-     * # Example
-     *
-     * ~~~ {.rust}
-     * extern mod extra;
-     * use extra::base64::{ToBase64, standard};
-     *
-     * fn main () {
-     *     let str = "Hello, World".to_base64(standard);
-     *     printfln!("%s", str);
-     * }
-     * ~~~
-     *
-     */
-    fn to_base64(&self, config: Config) -> ~str {
-        self.as_bytes().to_base64(config)
+        unsafe {
+            str::raw::from_bytes_owned(v)
+        }
     }
 }
 
@@ -181,22 +157,31 @@ pub trait FromBase64 {
     fn from_base64(&self) -> Result<~[u8], ~str>;
 }
 
-impl<'self> FromBase64 for &'self [u8] {
+impl<'self> FromBase64 for &'self str {
     /**
-     * Convert base64 `u8` vector into u8 byte values.
-     * Every 4 encoded characters is converted into 3 octets, modulo padding.
+     * Convert any base64 encoded string (literal, `@`, `&`, or `~`)
+     * to the byte values it encodes.
+     *
+     * You can use the `from_bytes` function in `std::str`
+     * to turn a `[u8]` into a string with characters corresponding to those
+     * values.
      *
      * # Example
      *
+     * This converts a string literal to base64 and back.
+     *
      * ~~~ {.rust}
      * extern mod extra;
      * use extra::base64::{ToBase64, FromBase64, standard};
+     * use std::str;
      *
      * fn main () {
-     *     let str = [52,32].to_base64(standard);
-     *     printfln!("%s", str);
-     *     let bytes = str.from_base64();
+     *     let hello_str = "Hello, World".to_base64(standard);
+     *     printfln!("%s", hello_str);
+     *     let bytes = hello_str.from_base64();
      *     printfln!("%?", bytes);
+     *     let result_str = str::from_bytes(bytes);
+     *     printfln!("%s", result_str);
      * }
      * ~~~
      */
@@ -205,12 +190,11 @@ fn from_base64(&self) -> Result<~[u8], ~str> {
         let mut buf: u32 = 0;
         let mut modulus = 0;
 
-        let mut it = self.iter();
-        for &byte in it {
-            let ch = byte as char;
+        let mut it = self.byte_iter().enumerate();
+        for (idx, byte) in it {
             let val = byte as u32;
 
-            match ch {
+            match byte as char {
                 'A'..'Z' => buf |= val - 0x41,
                 'a'..'z' => buf |= val - 0x47,
                 '0'..'9' => buf |= val + 0x04,
@@ -218,7 +202,8 @@ fn from_base64(&self) -> Result<~[u8], ~str> {
                 '/'|'_' => buf |= 0x3F,
                 '\r'|'\n' => loop,
                 '=' => break,
-                _ => return Err(~"Invalid Base64 character")
+                _ => return Err(fmt!("Invalid character '%c' at position %u",
+                                     self.char_at(idx), idx))
             }
 
             buf <<= 6;
@@ -231,8 +216,11 @@ fn from_base64(&self) -> Result<~[u8], ~str> {
             }
         }
 
-        if !it.all(|&byte| {byte as char == '='}) {
-            return Err(~"Invalid Base64 character");
+        for (idx, byte) in it {
+            if (byte as char) != '=' {
+                return Err(fmt!("Invalid character '%c' at position %u",
+                                self.char_at(idx), idx));
+            }
         }
 
         match modulus {
@@ -251,39 +239,6 @@ fn from_base64(&self) -> Result<~[u8], ~str> {
     }
 }
 
-impl<'self> FromBase64 for &'self str {
-    /**
-     * Convert any base64 encoded string (literal, `@`, `&`, or `~`)
-     * to the byte values it encodes.
-     *
-     * You can use the `from_bytes` function in `std::str`
-     * to turn a `[u8]` into a string with characters corresponding to those
-     * values.
-     *
-     * # Example
-     *
-     * This converts a string literal to base64 and back.
-     *
-     * ~~~ {.rust}
-     * extern mod extra;
-     * use extra::base64::{ToBase64, FromBase64, standard};
-     * use std::str;
-     *
-     * fn main () {
-     *     let hello_str = "Hello, World".to_base64(standard);
-     *     printfln!("%s", hello_str);
-     *     let bytes = hello_str.from_base64();
-     *     printfln!("%?", bytes);
-     *     let result_str = str::from_bytes(bytes);
-     *     printfln!("%s", result_str);
-     * }
-     * ~~~
-     */
-    fn from_base64(&self) -> Result<~[u8], ~str> {
-        self.as_bytes().from_base64()
-    }
-}
-
 #[cfg(test)]
 mod test {
     use test::BenchHarness;
@@ -291,27 +246,28 @@ mod test {
 
     #[test]
     fn test_to_base64_basic() {
-        assert_eq!("".to_base64(STANDARD), ~"");
-        assert_eq!("f".to_base64(STANDARD), ~"Zg==");
-        assert_eq!("fo".to_base64(STANDARD), ~"Zm8=");
-        assert_eq!("foo".to_base64(STANDARD), ~"Zm9v");
-        assert_eq!("foob".to_base64(STANDARD), ~"Zm9vYg==");
-        assert_eq!("fooba".to_base64(STANDARD), ~"Zm9vYmE=");
-        assert_eq!("foobar".to_base64(STANDARD), ~"Zm9vYmFy");
+        assert_eq!("".as_bytes().to_base64(STANDARD), ~"");
+        assert_eq!("f".as_bytes().to_base64(STANDARD), ~"Zg==");
+        assert_eq!("fo".as_bytes().to_base64(STANDARD), ~"Zm8=");
+        assert_eq!("foo".as_bytes().to_base64(STANDARD), ~"Zm9v");
+        assert_eq!("foob".as_bytes().to_base64(STANDARD), ~"Zm9vYg==");
+        assert_eq!("fooba".as_bytes().to_base64(STANDARD), ~"Zm9vYmE=");
+        assert_eq!("foobar".as_bytes().to_base64(STANDARD), ~"Zm9vYmFy");
     }
 
     #[test]
     fn test_to_base64_line_break() {
         assert!(![0u8, 1000].to_base64(Config {line_length: None, ..STANDARD})
                 .contains("\r\n"));
-        assert_eq!("foobar".to_base64(Config {line_length: Some(4), ..STANDARD}),
+        assert_eq!("foobar".as_bytes().to_base64(Config {line_length: Some(4),
+                                                         ..STANDARD}),
                    ~"Zm9v\r\nYmFy");
     }
 
     #[test]
     fn test_to_base64_padding() {
-        assert_eq!("f".to_base64(Config {pad: false, ..STANDARD}), ~"Zg");
-        assert_eq!("fo".to_base64(Config {pad: false, ..STANDARD}), ~"Zm8");
+        assert_eq!("f".as_bytes().to_base64(Config {pad: false, ..STANDARD}), ~"Zg");
+        assert_eq!("fo".as_bytes().to_base64(Config {pad: false, ..STANDARD}), ~"Zm8");
     }
 
     #[test]
@@ -345,7 +301,7 @@ fn test_from_base64_urlsafe() {
     #[test]
     fn test_from_base64_invalid_char() {
         assert!("Zm$=".from_base64().is_err())
-            assert!("Zg==$".from_base64().is_err());
+        assert!("Zg==$".from_base64().is_err());
     }
 
     #[test]
@@ -369,20 +325,20 @@ fn test_base64_random() {
     }
 
     #[bench]
-    pub fn to_base64(bh: & mut BenchHarness) {
+    pub fn bench_to_base64(bh: & mut BenchHarness) {
         let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
                  ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
         do bh.iter {
-            s.to_base64(STANDARD);
+            s.as_bytes().to_base64(STANDARD);
         }
         bh.bytes = s.len() as u64;
     }
 
     #[bench]
-    pub fn from_base64(bh: & mut BenchHarness) {
+    pub fn bench_from_base64(bh: & mut BenchHarness) {
         let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
                  ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
-        let b = s.to_base64(STANDARD);
+        let b = s.as_bytes().to_base64(STANDARD);
         do bh.iter {
             b.from_base64();
         }
diff --git a/src/libextra/enum_set.rs b/src/libextra/enum_set.rs
new file mode 100644 (file)
index 0000000..25501fa
--- /dev/null
@@ -0,0 +1,288 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::iterator::Iterator;
+
+#[deriving(Clone, Eq, IterBytes, ToStr)]
+/// A specialized Set implementation to use enum types.
+pub struct EnumSet<E> {
+    // We must maintain the invariant that no bits are set
+    // for which no variant exists
+    priv bits: uint
+}
+
+/// An iterface for casting C-like enum to uint and back.
+pub trait CLike {
+    /// Converts C-like enum to uint.
+    pub fn to_uint(&self) -> uint;
+    /// Converts uint to C-like enum.
+    pub fn from_uint(uint) -> Self;
+}
+
+fn bit<E:CLike>(e: E) -> uint {
+    1 << e.to_uint()
+}
+
+impl<E:CLike> EnumSet<E> {
+    /// Returns an empty EnumSet.
+    pub fn empty() -> EnumSet<E> {
+        EnumSet {bits: 0}
+    }
+
+    /// Returns true if an EnumSet is empty.
+    pub fn is_empty(&self) -> bool {
+        self.bits == 0
+    }
+
+    /// Returns true if an EnumSet contains any enum of a given EnumSet
+    pub fn intersects(&self, e: EnumSet<E>) -> bool {
+        (self.bits & e.bits) != 0
+    }
+
+    /// Returns an intersection of both EnumSets.
+    pub fn intersection(&self, e: EnumSet<E>) -> EnumSet<E> {
+        EnumSet {bits: self.bits & e.bits}
+    }
+
+    /// Returns true if a given EnumSet is included in an EnumSet.
+    pub fn contains(&self, e: EnumSet<E>) -> bool {
+        (self.bits & e.bits) == e.bits
+    }
+
+    /// Returns a union of both EnumSets.
+    pub fn union(&self, e: EnumSet<E>) -> EnumSet<E> {
+        EnumSet {bits: self.bits | e.bits}
+    }
+
+    /// Add an enum to an EnumSet
+    pub fn add(&mut self, e: E) {
+        self.bits |= bit(e);
+    }
+
+    /// Returns true if an EnumSet contains a given enum
+    pub fn contains_elem(&self, e: E) -> bool {
+        (self.bits & bit(e)) != 0
+    }
+
+    /// Returns an iterator over an EnumSet
+    pub fn iter(&self) -> EnumSetIterator<E> {
+        EnumSetIterator::new(self.bits)
+    }
+}
+
+impl<E:CLike> Sub<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
+    fn sub(&self, e: &EnumSet<E>) -> EnumSet<E> {
+        EnumSet {bits: self.bits & !e.bits}
+    }
+}
+
+impl<E:CLike> BitOr<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
+    fn bitor(&self, e: &EnumSet<E>) -> EnumSet<E> {
+        EnumSet {bits: self.bits | e.bits}
+    }
+}
+
+impl<E:CLike> BitAnd<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
+    fn bitand(&self, e: &EnumSet<E>) -> EnumSet<E> {
+        EnumSet {bits: self.bits & e.bits}
+    }
+}
+
+/// An iterator over an EnumSet
+pub struct EnumSetIterator<E> {
+    priv index: uint,
+    priv bits: uint,
+}
+
+impl<E:CLike> EnumSetIterator<E> {
+    fn new(bits: uint) -> EnumSetIterator<E> {
+        EnumSetIterator { index: 0, bits: bits }
+    }
+}
+
+impl<E:CLike> Iterator<E> for EnumSetIterator<E> {
+    fn next(&mut self) -> Option<E> {
+        if (self.bits == 0) {
+            return None;
+        }
+
+        while (self.bits & 1) == 0 {
+            self.index += 1;
+            self.bits >>= 1;
+        }
+        let elem = CLike::from_uint(self.index);
+        self.index += 1;
+        self.bits >>= 1;
+        Some(elem)
+    }
+
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        let exact = self.bits.population_count();
+        (exact, Some(exact))
+    }
+}
+
+#[cfg(test)]
+mod test {
+
+    use std::cast;
+
+    use enum_set::*;
+
+    #[deriving(Eq)]
+    enum Foo {
+        A, B, C
+    }
+
+    impl CLike for Foo {
+        pub fn to_uint(&self) -> uint {
+            *self as uint
+        }
+
+        pub fn from_uint(v: uint) -> Foo {
+            unsafe { cast::transmute(v) }
+        }
+    }
+
+    #[test]
+    fn test_empty() {
+        let e: EnumSet<Foo> = EnumSet::empty();
+        assert!(e.is_empty());
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // intersect
+
+    #[test]
+    fn test_two_empties_do_not_intersect() {
+        let e1: EnumSet<Foo> = EnumSet::empty();
+        let e2: EnumSet<Foo> = EnumSet::empty();
+        assert!(!e1.intersects(e2));
+    }
+
+    #[test]
+    fn test_empty_does_not_intersect_with_full() {
+        let e1: EnumSet<Foo> = EnumSet::empty();
+
+        let mut e2: EnumSet<Foo> = EnumSet::empty();
+        e2.add(A);
+        e2.add(B);
+        e2.add(C);
+
+        assert!(!e1.intersects(e2));
+    }
+
+    #[test]
+    fn test_disjoint_intersects() {
+        let mut e1: EnumSet<Foo> = EnumSet::empty();
+        e1.add(A);
+
+        let mut e2: EnumSet<Foo> = EnumSet::empty();
+        e2.add(B);
+
+        assert!(!e1.intersects(e2));
+    }
+
+    #[test]
+    fn test_overlapping_intersects() {
+        let mut e1: EnumSet<Foo> = EnumSet::empty();
+        e1.add(A);
+
+        let mut e2: EnumSet<Foo> = EnumSet::empty();
+        e2.add(A);
+        e2.add(B);
+
+        assert!(e1.intersects(e2));
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // contains and contains_elem
+
+    #[test]
+    fn test_contains() {
+        let mut e1: EnumSet<Foo> = EnumSet::empty();
+        e1.add(A);
+
+        let mut e2: EnumSet<Foo> = EnumSet::empty();
+        e2.add(A);
+        e2.add(B);
+
+        assert!(!e1.contains(e2));
+        assert!(e2.contains(e1));
+    }
+
+    #[test]
+    fn test_contains_elem() {
+        let mut e1: EnumSet<Foo> = EnumSet::empty();
+        e1.add(A);
+        assert!(e1.contains_elem(A));
+        assert!(!e1.contains_elem(B));
+        assert!(!e1.contains_elem(C));
+
+        e1.add(A);
+        e1.add(B);
+        assert!(e1.contains_elem(A));
+        assert!(e1.contains_elem(B));
+        assert!(!e1.contains_elem(C));
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // iter
+
+    #[test]
+    fn test_iterator() {
+        let mut e1: EnumSet<Foo> = EnumSet::empty();
+
+        let elems: ~[Foo] = e1.iter().collect();
+        assert_eq!(~[], elems)
+
+        e1.add(A);
+        let elems: ~[Foo] = e1.iter().collect();
+        assert_eq!(~[A], elems)
+
+        e1.add(C);
+        let elems: ~[Foo] = e1.iter().collect();
+        assert_eq!(~[A,C], elems)
+
+        e1.add(C);
+        let elems: ~[Foo] = e1.iter().collect();
+        assert_eq!(~[A,C], elems)
+
+        e1.add(B);
+        let elems: ~[Foo] = e1.iter().collect();
+        assert_eq!(~[A,B,C], elems)
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // operators
+
+    #[test]
+    fn test_operators() {
+        let mut e1: EnumSet<Foo> = EnumSet::empty();
+        e1.add(A);
+        e1.add(C);
+
+        let mut e2: EnumSet<Foo> = EnumSet::empty();
+        e2.add(B);
+        e2.add(C);
+
+        let e_union = e1 | e2;
+        let elems: ~[Foo] = e_union.iter().collect();
+        assert_eq!(~[A,B,C], elems)
+
+        let e_intersection = e1 & e2;
+        let elems: ~[Foo] = e_intersection.iter().collect();
+        assert_eq!(~[C], elems)
+
+        let e_subtract = e1 - e2;
+        let elems: ~[Foo] = e_subtract.iter().collect();
+        assert_eq!(~[A], elems)
+    }
+}
index e6134bb340cd8c45b708ab71d6f3539b45b4061d..44781a1fd19b632f0794802ae3d9ee8cbae167ce 100644 (file)
@@ -91,6 +91,7 @@
 pub mod base64;
 pub mod rl;
 pub mod workcache;
+pub mod enum_set;
 #[path="num/bigint.rs"]
 pub mod bigint;
 #[path="num/rational.rs"]
 pub mod semver;
 pub mod fileinput;
 pub mod flate;
+pub mod hex;
 
 #[cfg(unicode)]
 mod unicode;
diff --git a/src/libextra/hex.rs b/src/libextra/hex.rs
new file mode 100644 (file)
index 0000000..d5345cb
--- /dev/null
@@ -0,0 +1,193 @@
+// Copyright 2013 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.
+
+//! Hex binary-to-text encoding
+use std::str;
+use std::vec;
+
+/// A trait for converting a value to hexadecimal encoding
+pub trait ToHex {
+    /// Converts the value of `self` to a hex value, returning the owned
+    /// string.
+    fn to_hex(&self) -> ~str;
+}
+
+static CHARS: &'static[u8] = bytes!("0123456789abcdef");
+
+impl<'self> ToHex for &'self [u8] {
+    /**
+     * Turn a vector of `u8` bytes into a hexadecimal string.
+     *
+     * # Example
+     *
+     * ~~~ {.rust}
+     * extern mod extra;
+     * use extra::hex::ToHex;
+     *
+     * fn main () {
+     *     let str = [52,32].to_hex();
+     *     printfln!("%s", str);
+     * }
+     * ~~~
+     */
+    fn to_hex(&self) -> ~str {
+        let mut v = vec::with_capacity(self.len() * 2);
+        for &byte in self.iter() {
+            v.push(CHARS[byte >> 4]);
+            v.push(CHARS[byte & 0xf]);
+        }
+
+        unsafe {
+            str::raw::from_bytes_owned(v)
+        }
+    }
+}
+
+/// A trait for converting hexadecimal encoded values
+pub trait FromHex {
+    /// Converts the value of `self`, interpreted as hexadecimal encoded data,
+    /// into an owned vector of bytes, returning the vector.
+    fn from_hex(&self) -> Result<~[u8], ~str>;
+}
+
+impl<'self> FromHex for &'self str {
+    /**
+     * Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`)
+     * to the byte values it encodes.
+     *
+     * You can use the `from_bytes` function in `std::str`
+     * to turn a `[u8]` into a string with characters corresponding to those
+     * values.
+     *
+     * # Example
+     *
+     * This converts a string literal to hexadecimal and back.
+     *
+     * ~~~ {.rust}
+     * extern mod extra;
+     * use extra::hex::{FromHex, ToHex};
+     * use std::str;
+     *
+     * fn main () {
+     *     let hello_str = "Hello, World".to_hex();
+     *     printfln!("%s", hello_str);
+     *     let bytes = hello_str.from_hex().unwrap();
+     *     printfln!("%?", bytes);
+     *     let result_str = str::from_bytes(bytes);
+     *     printfln!("%s", result_str);
+     * }
+     * ~~~
+     */
+    fn from_hex(&self) -> Result<~[u8], ~str> {
+        // This may be an overestimate if there is any whitespace
+        let mut b = vec::with_capacity(self.len() / 2);
+        let mut modulus = 0;
+        let mut buf = 0u8;
+
+        for (idx, byte) in self.byte_iter().enumerate() {
+            buf <<= 4;
+
+            match byte as char {
+                'A'..'F' => buf |= byte - ('A' as u8) + 10,
+                'a'..'f' => buf |= byte - ('a' as u8) + 10,
+                '0'..'9' => buf |= byte - ('0' as u8),
+                ' '|'\r'|'\n'|'\t' => {
+                    buf >>= 4;
+                    loop
+                }
+                _ => return Err(fmt!("Invalid character '%c' at position %u",
+                                     self.char_at(idx), idx))
+            }
+
+            modulus += 1;
+            if modulus == 2 {
+                modulus = 0;
+                b.push(buf);
+            }
+        }
+
+        match modulus {
+            0 => Ok(b),
+            _ => Err(~"Invalid input length")
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use test::BenchHarness;
+    use hex::*;
+
+    #[test]
+    pub fn test_to_hex() {
+        assert_eq!("foobar".as_bytes().to_hex(), ~"666f6f626172");
+    }
+
+    #[test]
+    pub fn test_from_hex_okay() {
+        assert_eq!("666f6f626172".from_hex().unwrap(),
+                   "foobar".as_bytes().to_owned());
+        assert_eq!("666F6F626172".from_hex().unwrap(),
+                   "foobar".as_bytes().to_owned());
+    }
+
+    #[test]
+    pub fn test_from_hex_odd_len() {
+        assert!("666".from_hex().is_err());
+        assert!("66 6".from_hex().is_err());
+    }
+
+    #[test]
+    pub fn test_from_hex_invalid_char() {
+        assert!("66y6".from_hex().is_err());
+    }
+
+    #[test]
+    pub fn test_from_hex_ignores_whitespace() {
+        assert_eq!("666f 6f6\r\n26172 ".from_hex().unwrap(),
+                   "foobar".as_bytes().to_owned());
+    }
+
+    #[test]
+    pub fn test_to_hex_all_bytes() {
+        for i in range(0, 256) {
+            assert_eq!([i as u8].to_hex(), fmt!("%02x", i as uint));
+        }
+    }
+
+    #[test]
+    pub fn test_from_hex_all_bytes() {
+        for i in range(0, 256) {
+            assert_eq!(fmt!("%02x", i as uint).from_hex().unwrap(), ~[i as u8]);
+            assert_eq!(fmt!("%02X", i as uint).from_hex().unwrap(), ~[i as u8]);
+        }
+    }
+
+    #[bench]
+    pub fn bench_to_hex(bh: & mut BenchHarness) {
+        let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
+                 ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
+        do bh.iter {
+            s.as_bytes().to_hex();
+        }
+        bh.bytes = s.len() as u64;
+    }
+
+    #[bench]
+    pub fn bench_from_hex(bh: & mut BenchHarness) {
+        let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
+                 ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
+        let b = s.as_bytes().to_hex();
+        do bh.iter {
+            b.from_hex();
+        }
+        bh.bytes = b.len() as u64;
+    }
+}
index cd35cbdf30980faa2cd62e765835e0f69dddfe05..ec9cb902d3d29125229303677e178e4622145903 100644 (file)
@@ -26,7 +26,6 @@
 
 use serialize::Encodable;
 use serialize;
-use sort::Sort;
 use treemap::TreeMap;
 
 /// Represents a json value
@@ -1152,23 +1151,7 @@ fn lt(&self, other: &Json) -> bool {
             Object(ref d0) => {
                 match *other {
                     Number(_) | String(_) | Boolean(_) | List(_) => false,
-                    Object(ref d1) => {
-                        let mut d0_flat = ~[];
-                        let mut d1_flat = ~[];
-
-                        // FIXME #4430: this is horribly inefficient...
-                        for (k, v) in d0.iter() {
-                             d0_flat.push((@(*k).clone(), @(*v).clone()));
-                        }
-                        d0_flat.qsort();
-
-                        for (k, v) in d1.iter() {
-                            d1_flat.push((@(*k).clone(), @(*v).clone()));
-                        }
-                        d1_flat.qsort();
-
-                        d0_flat < d1_flat
-                    }
+                    Object(ref d1) => d0 < d1,
                     Null => true
                 }
             }
index 356820f8267fe990eb76bbaec7781ea56fc422bd..2c642d54253b6b79c4cf28d142ab5de3653d8042 100644 (file)
@@ -408,11 +408,10 @@ pub fn stop_after_phase_5(sess: Session) -> bool {
 #[fixed_stack_segment]
 pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
                      outdir: &Option<Path>, output: &Option<Path>) {
-    let outputs = build_output_filenames(input, outdir, output, [], sess);
     // We need nested scopes here, because the intermediate results can keep
     // large chunks of memory alive and we want to free them as soon as
     // possible to keep the peak memory usage low
-    let trans = {
+    let (outputs, trans) = {
         let expanded_crate = {
             let crate = phase_1_parse_input(sess, cfg.clone(), input);
             if stop_after_phase_1(sess) { return; }
@@ -420,7 +419,10 @@ pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
         };
         let analysis = phase_3_run_analysis_passes(sess, expanded_crate);
         if stop_after_phase_3(sess) { return; }
-        phase_4_translate_to_llvm(sess, expanded_crate, &analysis, outputs)
+        let outputs = build_output_filenames(input, outdir, output, [], sess);
+        let trans = phase_4_translate_to_llvm(sess, expanded_crate,
+                                              &analysis, outputs);
+        (outputs, trans)
     };
     phase_5_run_llvm_passes(sess, &trans, outputs);
     if stop_after_phase_5(sess) { return; }
@@ -957,10 +959,7 @@ pub fn build_output_filenames(input: &input,
         };
 
         if *sess.building_library {
-            // FIXME (#2401): We might want to warn here; we're actually not
-            // going to respect the user's choice of library name when it
-            // comes time to link, we'll be linking to
-            // lib<basename>-<hash>-<version>.so no matter what.
+            sess.warn("ignoring specified output filename for library.");
         }
 
         if *odir != None {
index ec50f564385c3a9d3f777d0f9073f2f785deef79..ffd79433b76930fe7186c138a71fdaaed995436a 100644 (file)
@@ -413,15 +413,14 @@ fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) {
 }
 
 fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: &ty::ParamBounds) {
-    do bs.builtin_bounds.each |bound| {
+    for bound in bs.builtin_bounds.iter() {
         match bound {
             ty::BoundSend => w.write_char('S'),
             ty::BoundFreeze => w.write_char('K'),
             ty::BoundStatic => w.write_char('O'),
             ty::BoundSized => w.write_char('Z'),
         }
-        true
-    };
+    }
 
     for &tp in bs.trait_bounds.iter() {
         w.write_char('I');
index f34b28e1642fca9f0f3e7977832824d8f3cee8ec..767c2b4ee2ed75ca0de10e269d49b1bdcd54e79b 100644 (file)
@@ -225,7 +225,7 @@ fn expr(&mut self, expr: @ast::expr, pred: CFGIndex) -> CFGIndex {
                 // Note that `break` and `loop` statements
                 // may cause additional edges.
 
-                // NOTE: Is the condition considered part of the loop?
+                // Is the condition considered part of the loop?
                 let loopback = self.add_dummy_node([pred]);           // 1
                 let cond_exit = self.expr(cond, loopback);            // 2
                 let expr_exit = self.add_node(expr.id, [cond_exit]);  // 3
index 3bdf0c0f6dcb84c32db21792a769cb9c923b17a4..84eb371d7b34ac49a51b99bbde139804bd918fbc 100644 (file)
@@ -338,12 +338,11 @@ pub fn check_builtin_bounds(cx: Context, ty: ty::t, bounds: ty::BuiltinBounds,
 {
     let kind = ty::type_contents(cx.tcx, ty);
     let mut missing = ty::EmptyBuiltinBounds();
-    do bounds.each |bound| {
+    for bound in bounds.iter() {
         if !kind.meets_bound(cx.tcx, bound) {
             missing.add(bound);
         }
-        true
-    };
+    }
     if !missing.is_empty() {
         any_missing(missing);
     }
index d77cebbf23e0be8b1c05eed1ed0bfb0b85d68836..9a0dc5f036c76b701fe192d9724b68559b6539e6 100644 (file)
 use middle::trans::type_of;
 use middle::ty;
 use util::common::indenter;
+use util::ppaux::{Repr, vec_map_to_str};
 
 use std::hashmap::HashMap;
 use std::vec;
 use syntax::ast_util::path_to_ident;
 use syntax::ast_util;
 use syntax::codemap::{span, dummy_sp};
-use syntax::print::pprust::pat_to_str;
 
 // An option identifying a literal: either a unit-like struct or an
 // expression.
@@ -353,19 +353,17 @@ pub struct Match<'self> {
     data: ArmData<'self>
 }
 
-pub fn match_to_str(bcx: @mut Block, m: &Match) -> ~str {
-    if bcx.sess().verbose() {
-        // for many programs, this just take too long to serialize
-        fmt!("%?", m.pats.map(|p| pat_to_str(*p, bcx.sess().intr())))
-    } else {
-        fmt!("%u pats", m.pats.len())
+impl<'self> Repr for Match<'self> {
+    fn repr(&self, tcx: ty::ctxt) -> ~str {
+        if tcx.sess.verbose() {
+            // for many programs, this just take too long to serialize
+            self.pats.repr(tcx)
+        } else {
+            fmt!("%u pats", self.pats.len())
+        }
     }
 }
 
-pub fn matches_to_str(bcx: @mut Block, m: &[Match]) -> ~str {
-    fmt!("%?", m.map(|n| match_to_str(bcx, n)))
-}
-
 pub fn has_nested_bindings(m: &[Match], col: uint) -> bool {
     for br in m.iter() {
         match br.pats[col].node {
@@ -381,9 +379,9 @@ pub fn expand_nested_bindings<'r>(bcx: @mut Block,
                                   col: uint,
                                   val: ValueRef)
                               -> ~[Match<'r>] {
-    debug!("expand_nested_bindings(bcx=%s, m=%s, col=%u, val=%?)",
+    debug!("expand_nested_bindings(bcx=%s, m=%s, col=%u, val=%s)",
            bcx.to_str(),
-           matches_to_str(bcx, m),
+           m.repr(bcx.tcx()),
            col,
            bcx.val_to_str(val));
     let _indenter = indenter();
@@ -416,7 +414,7 @@ pub fn assert_is_binding_or_wild(bcx: @mut Block, p: @ast::pat) {
         bcx.sess().span_bug(
             p.span,
             fmt!("Expected an identifier pattern but found p: %s",
-                 pat_to_str(p, bcx.sess().intr())));
+                 p.repr(bcx.tcx())));
     }
 }
 
@@ -429,9 +427,9 @@ pub fn enter_match<'r>(bcx: @mut Block,
                        val: ValueRef,
                        e: enter_pat)
                     -> ~[Match<'r>] {
-    debug!("enter_match(bcx=%s, m=%s, col=%u, val=%?)",
+    debug!("enter_match(bcx=%s, m=%s, col=%u, val=%s)",
            bcx.to_str(),
-           matches_to_str(bcx, m),
+           m.repr(bcx.tcx()),
            col,
            bcx.val_to_str(val));
     let _indenter = indenter();
@@ -467,7 +465,7 @@ pub fn enter_match<'r>(bcx: @mut Block,
         }
     }
 
-    debug!("result=%s", matches_to_str(bcx, result));
+    debug!("result=%s", result.repr(bcx.tcx()));
 
     return result;
 }
@@ -478,9 +476,9 @@ pub fn enter_default<'r>(bcx: @mut Block,
                          col: uint,
                          val: ValueRef)
                       -> ~[Match<'r>] {
-    debug!("enter_default(bcx=%s, m=%s, col=%u, val=%?)",
+    debug!("enter_default(bcx=%s, m=%s, col=%u, val=%s)",
            bcx.to_str(),
-           matches_to_str(bcx, m),
+           m.repr(bcx.tcx()),
            col,
            bcx.val_to_str(val));
     let _indenter = indenter();
@@ -525,9 +523,9 @@ pub fn enter_opt<'r>(bcx: @mut Block,
                      variant_size: uint,
                      val: ValueRef)
                   -> ~[Match<'r>] {
-    debug!("enter_opt(bcx=%s, m=%s, col=%u, val=%?)",
+    debug!("enter_opt(bcx=%s, m=%s, col=%u, val=%s)",
            bcx.to_str(),
-           matches_to_str(bcx, m),
+           m.repr(bcx.tcx()),
            col,
            bcx.val_to_str(val));
     let _indenter = indenter();
@@ -637,9 +635,9 @@ pub fn enter_rec_or_struct<'r>(bcx: @mut Block,
                                fields: &[ast::ident],
                                val: ValueRef)
                             -> ~[Match<'r>] {
-    debug!("enter_rec_or_struct(bcx=%s, m=%s, col=%u, val=%?)",
+    debug!("enter_rec_or_struct(bcx=%s, m=%s, col=%u, val=%s)",
            bcx.to_str(),
-           matches_to_str(bcx, m),
+           m.repr(bcx.tcx()),
            col,
            bcx.val_to_str(val));
     let _indenter = indenter();
@@ -672,9 +670,9 @@ pub fn enter_tup<'r>(bcx: @mut Block,
                      val: ValueRef,
                      n_elts: uint)
                   -> ~[Match<'r>] {
-    debug!("enter_tup(bcx=%s, m=%s, col=%u, val=%?)",
+    debug!("enter_tup(bcx=%s, m=%s, col=%u, val=%s)",
            bcx.to_str(),
-           matches_to_str(bcx, m),
+           m.repr(bcx.tcx()),
            col,
            bcx.val_to_str(val));
     let _indenter = indenter();
@@ -698,9 +696,9 @@ pub fn enter_tuple_struct<'r>(bcx: @mut Block,
                               val: ValueRef,
                               n_elts: uint)
                           -> ~[Match<'r>] {
-    debug!("enter_tuple_struct(bcx=%s, m=%s, col=%u, val=%?)",
+    debug!("enter_tuple_struct(bcx=%s, m=%s, col=%u, val=%s)",
            bcx.to_str(),
-           matches_to_str(bcx, m),
+           m.repr(bcx.tcx()),
            col,
            bcx.val_to_str(val));
     let _indenter = indenter();
@@ -723,9 +721,9 @@ pub fn enter_box<'r>(bcx: @mut Block,
                      col: uint,
                      val: ValueRef)
                  -> ~[Match<'r>] {
-    debug!("enter_box(bcx=%s, m=%s, col=%u, val=%?)",
+    debug!("enter_box(bcx=%s, m=%s, col=%u, val=%s)",
            bcx.to_str(),
-           matches_to_str(bcx, m),
+           m.repr(bcx.tcx()),
            col,
            bcx.val_to_str(val));
     let _indenter = indenter();
@@ -750,9 +748,9 @@ pub fn enter_uniq<'r>(bcx: @mut Block,
                       col: uint,
                       val: ValueRef)
                   -> ~[Match<'r>] {
-    debug!("enter_uniq(bcx=%s, m=%s, col=%u, val=%?)",
+    debug!("enter_uniq(bcx=%s, m=%s, col=%u, val=%s)",
            bcx.to_str(),
-           matches_to_str(bcx, m),
+           m.repr(bcx.tcx()),
            col,
            bcx.val_to_str(val));
     let _indenter = indenter();
@@ -777,9 +775,9 @@ pub fn enter_region<'r>(bcx: @mut Block,
                         col: uint,
                         val: ValueRef)
                     -> ~[Match<'r>] {
-    debug!("enter_region(bcx=%s, m=%s, col=%u, val=%?)",
+    debug!("enter_region(bcx=%s, m=%s, col=%u, val=%s)",
            bcx.to_str(),
-           matches_to_str(bcx, m),
+           m.repr(bcx.tcx()),
            col,
            bcx.val_to_str(val));
     let _indenter = indenter();
@@ -1213,11 +1211,11 @@ pub fn compile_guard(bcx: @mut Block,
                      vals: &[ValueRef],
                      chk: Option<mk_fail>)
                   -> @mut Block {
-    debug!("compile_guard(bcx=%s, guard_expr=%s, m=%s, vals=%?)",
+    debug!("compile_guard(bcx=%s, guard_expr=%s, m=%s, vals=%s)",
            bcx.to_str(),
            bcx.expr_to_str(guard_expr),
-           matches_to_str(bcx, m),
-           vals.map(|v| bcx.val_to_str(*v)));
+           m.repr(bcx.tcx()),
+           vec_map_to_str(vals, |v| bcx.val_to_str(*v)));
     let _indenter = indenter();
 
     let mut bcx = bcx;
@@ -1267,10 +1265,10 @@ pub fn compile_submatch(bcx: @mut Block,
                         m: &[Match],
                         vals: &[ValueRef],
                         chk: Option<mk_fail>) {
-    debug!("compile_submatch(bcx=%s, m=%s, vals=%?)",
+    debug!("compile_submatch(bcx=%s, m=%s, vals=%s)",
            bcx.to_str(),
-           matches_to_str(bcx, m),
-           vals.map(|v| bcx.val_to_str(*v)));
+           m.repr(bcx.tcx()),
+           vec_map_to_str(vals, |v| bcx.val_to_str(*v)));
     let _indenter = indenter();
 
     /*
@@ -1427,6 +1425,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
 
     // Decide what kind of branch we need
     let opts = get_options(bcx, m, col);
+    debug!("options=%?", opts);
     let mut kind = no_branch;
     let mut test_val = val;
     if opts.len() > 0u {
@@ -1914,12 +1913,12 @@ fn bind_irrefutable_pat(bcx: @mut Block,
 
     debug!("bind_irrefutable_pat(bcx=%s, pat=%s, binding_mode=%?)",
            bcx.to_str(),
-           pat_to_str(pat, bcx.sess().intr()),
+           pat.repr(bcx.tcx()),
            binding_mode);
 
     if bcx.sess().asm_comments() {
         add_comment(bcx, fmt!("bind_irrefutable_pat(pat=%s)",
-                              pat_to_str(pat, bcx.sess().intr())));
+                              pat.repr(bcx.tcx())));
     }
 
     let _indenter = indenter();
index 3fc6dbca9647533ec6a1f3f5ea6b604198381d41..2efed8f36d7fff216b0f26bbefc0e1f3ed5acff2 100644 (file)
@@ -2218,23 +2218,14 @@ pub fn trans_mod(ccx: @mut CrateContext, m: &ast::_mod) {
 pub fn register_fn(ccx: @mut CrateContext,
                    sp: span,
                    sym: ~str,
-                   node_id: ast::NodeId)
-                -> ValueRef {
-    let t = ty::node_id_to_type(ccx.tcx, node_id);
-    register_fn_full(ccx, sp, sym, node_id, t)
-}
-
-pub fn register_fn_full(ccx: @mut CrateContext,
-                        sp: span,
-                        sym: ~str,
-                        node_id: ast::NodeId,
-                        node_type: ty::t)
-                     -> ValueRef {
+                   node_id: ast::NodeId,
+                   node_type: ty::t)
+                   -> ValueRef {
     let llfty = type_of_fn_from_ty(ccx, node_type);
-    register_fn_fuller(ccx, sp, sym, node_id, lib::llvm::CCallConv, llfty)
+    register_fn_llvmty(ccx, sp, sym, node_id, lib::llvm::CCallConv, llfty)
 }
 
-pub fn register_fn_fuller(ccx: @mut CrateContext,
+pub fn register_fn_llvmty(ccx: @mut CrateContext,
                           sp: span,
                           sym: ~str,
                           node_id: ast::NodeId,
@@ -2449,7 +2440,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
 
                         ast::item_fn(_, purity, _, _, _) => {
                             let llfn = if purity != ast::extern_fn {
-                                register_fn_full(ccx, i.span, sym, i.id, ty)
+                                register_fn(ccx, i.span, sym, i.id, ty)
                             } else {
                                 foreign::register_foreign_fn(ccx, i.span, sym, i.id)
                             };
@@ -2499,7 +2490,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
                             let path = vec::append((*pth).clone(), [path_name(ni.ident)]);
                             let sym = exported_name(ccx, path, ty, ni.attrs);
 
-                            register_fn_full(ccx, ni.span, sym, ni.id, ty)
+                            register_fn(ccx, ni.span, sym, ni.id, ty)
                         }
                         ast::foreign_item_static(*) => {
                             let ident = token::ident_to_str(&ni.ident);
@@ -2527,7 +2518,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
 
                             llfn = match enm.node {
                                 ast::item_enum(_, _) => {
-                                    register_fn_full(ccx, (*v).span, sym, id, ty)
+                                    register_fn(ccx, (*v).span, sym, id, ty)
                                 }
                                 _ => fail!("node_variant, shouldn't happen")
                             };
@@ -2551,7 +2542,8 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
                             let ty = ty::node_id_to_type(ccx.tcx, ctor_id);
                             let sym = exported_name(ccx, (*struct_path).clone(), ty,
                                                     struct_item.attrs);
-                            let llfn = register_fn_full(ccx, struct_item.span, sym, ctor_id, ty);
+                            let llfn = register_fn(ccx, struct_item.span,
+                                                   sym, ctor_id, ty);
                             set_inline_hint(llfn);
                             llfn
                         }
@@ -2586,7 +2578,7 @@ pub fn register_method(ccx: @mut CrateContext,
 
     let sym = exported_name(ccx, path, mty, m.attrs);
 
-    let llfn = register_fn_full(ccx, m.span, sym, id, mty);
+    let llfn = register_fn(ccx, m.span, sym, id, mty);
     set_inline_hint_if_appr(m.attrs, llfn);
     llfn
 }
index 6d5934592ebcb71f28f7271549533d134c27e959..5153296337daed25055c7751d7d680c61abc37f5 100644 (file)
@@ -1157,6 +1157,6 @@ pub fn register_foreign_fn(ccx: @mut CrateContext,
 
     let tys = shim_types(ccx, node_id);
     do tys.fn_ty.decl_fn |fnty| {
-        register_fn_fuller(ccx, sp, sym.take(), node_id, lib::llvm::CCallConv, fnty)
+        register_fn_llvmty(ccx, sp, sym.take(), node_id, lib::llvm::CCallConv, fnty)
     }
 }
index 48a003ddaf157522b44e040584708362aeb56fb8..a53bdff85f9dc2cb4903f2ef47d67b2b69969ce0 100644 (file)
@@ -25,7 +25,6 @@
 use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str};
 use util::ppaux::{Repr, UserString};
 use util::common::{indenter};
-use util::enum_set::{EnumSet, CLike};
 
 use std::cast;
 use std::cmp;
@@ -48,6 +47,7 @@
 use syntax::opt_vec;
 use syntax::abi::AbiSet;
 use syntax;
+use extra::enum_set::{EnumSet, CLike};
 
 pub static INITIAL_DISCRIMINANT_VALUE: uint = 0;
 
@@ -2287,7 +2287,7 @@ fn trait_contents(store: TraitStore, mutbl: ast::mutability,
         // This is like with typarams below, but less "pessimistic" and also
         // dependent on the trait store.
         let mut bt = TC_NONE;
-        do (AllBuiltinBounds() - bounds).each |bound| {
+        for bound in (AllBuiltinBounds() - bounds).iter() {
             bt = bt + match bound {
                 BoundStatic if bounds.contains_elem(BoundSend)
                             => TC_NONE, // Send bound implies static bound.
@@ -2296,8 +2296,7 @@ fn trait_contents(store: TraitStore, mutbl: ast::mutability,
                 BoundFreeze => TC_MUTABLE,
                 BoundSized  => TC_NONE, // don't care if interior is sized
             };
-            true
-        };
+        }
         st + mt + bt
     }
 
@@ -2308,7 +2307,7 @@ fn type_param_def_to_contents(cx: ctxt,
         let _i = indenter();
 
         let mut tc = TC_ALL;
-        do type_param_def.bounds.builtin_bounds.each |bound| {
+        for bound in type_param_def.bounds.builtin_bounds.iter() {
             debug!("tc = %s, bound = %?", tc.to_str(), bound);
             tc = tc - match bound {
                 BoundStatic => TypeContents::nonstatic(cx),
@@ -2317,8 +2316,7 @@ fn type_param_def_to_contents(cx: ctxt,
                 // The dynamic-size bit can be removed at pointer-level, etc.
                 BoundSized => TypeContents::dynamically_sized(cx),
             };
-            true
-        };
+        }
 
         debug!("result = %s", tc.to_str());
         return tc;
index c48b30e81416439ad86c9e9217e8bfb10f43ee5a..46414a7a5e23e0cc13e0e886d94db7c872a2c20c 100644 (file)
@@ -96,7 +96,6 @@ pub mod back {
 pub mod util {
     pub mod common;
     pub mod ppaux;
-    pub mod enum_set;
 }
 
 pub mod lib {
diff --git a/src/librustc/util/enum_set.rs b/src/librustc/util/enum_set.rs
deleted file mode 100644 (file)
index ced29f1..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::iterator::Iterator;
-
-#[deriving(Clone, Eq, IterBytes, ToStr)]
-pub struct EnumSet<E> {
-    // We must maintain the invariant that no bits are set
-    // for which no variant exists
-    priv bits: uint
-}
-
-pub trait CLike {
-    pub fn to_uint(&self) -> uint;
-    pub fn from_uint(uint) -> Self;
-}
-
-fn bit<E:CLike>(e: E) -> uint {
-    1 << e.to_uint()
-}
-
-impl<E:CLike> EnumSet<E> {
-    pub fn empty() -> EnumSet<E> {
-        EnumSet {bits: 0}
-    }
-
-    pub fn is_empty(&self) -> bool {
-        self.bits == 0
-    }
-
-    pub fn intersects(&self, e: EnumSet<E>) -> bool {
-        (self.bits & e.bits) != 0
-    }
-
-    pub fn intersection(&self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {bits: self.bits & e.bits}
-    }
-
-    pub fn contains(&self, e: EnumSet<E>) -> bool {
-        (self.bits & e.bits) == e.bits
-    }
-
-    pub fn union(&self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {bits: self.bits | e.bits}
-    }
-
-    pub fn add(&mut self, e: E) {
-        self.bits |= bit(e);
-    }
-
-    pub fn contains_elem(&self, e: E) -> bool {
-        (self.bits & bit(e)) != 0
-    }
-
-    pub fn each(&self, f: &fn(E) -> bool) -> bool {
-        let mut bits = self.bits;
-        let mut index = 0;
-        while bits != 0 {
-            if (bits & 1) != 0 {
-                let e = CLike::from_uint(index);
-                if !f(e) {
-                    return false;
-                }
-            }
-            index += 1;
-            bits >>= 1;
-        }
-        return true;
-    }
-
-    pub fn iter(&self) -> EnumSetIterator<E> {
-        EnumSetIterator::new(self.bits)
-    }
-}
-
-impl<E:CLike> Sub<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
-    fn sub(&self, e: &EnumSet<E>) -> EnumSet<E> {
-        EnumSet {bits: self.bits & !e.bits}
-    }
-}
-
-impl<E:CLike> BitOr<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
-    fn bitor(&self, e: &EnumSet<E>) -> EnumSet<E> {
-        EnumSet {bits: self.bits | e.bits}
-    }
-}
-
-impl<E:CLike> BitAnd<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
-    fn bitand(&self, e: &EnumSet<E>) -> EnumSet<E> {
-        EnumSet {bits: self.bits & e.bits}
-    }
-}
-
-pub struct EnumSetIterator<E> {
-    priv index: uint,
-    priv bits: uint,
-}
-
-impl<E:CLike> EnumSetIterator<E> {
-    fn new(bits: uint) -> EnumSetIterator<E> {
-        EnumSetIterator { index: 0, bits: bits }
-    }
-}
-
-impl<E:CLike> Iterator<E> for EnumSetIterator<E> {
-    fn next(&mut self) -> Option<E> {
-        if (self.bits == 0) {
-            return None;
-        }
-
-        while (self.bits & 1) == 0 {
-            self.index += 1;
-            self.bits >>= 1;
-        }
-        let elem = CLike::from_uint(self.index);
-        self.index += 1;
-        self.bits >>= 1;
-        Some(elem)
-    }
-
-    fn size_hint(&self) -> (uint, Option<uint>) {
-        let exact = self.bits.population_count();
-        (exact, Some(exact))
-    }
-}
-
-#[cfg(test)]
-mod test {
-
-    use std::cast;
-
-    use util::enum_set::*;
-
-    #[deriving(Eq)]
-    enum Foo {
-        A, B, C
-    }
-
-    impl CLike for Foo {
-        pub fn to_uint(&self) -> uint {
-            *self as uint
-        }
-
-        pub fn from_uint(v: uint) -> Foo {
-            unsafe { cast::transmute(v) }
-        }
-    }
-
-    #[test]
-    fn test_empty() {
-        let e: EnumSet<Foo> = EnumSet::empty();
-        assert!(e.is_empty());
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // intersect
-
-    #[test]
-    fn test_two_empties_do_not_intersect() {
-        let e1: EnumSet<Foo> = EnumSet::empty();
-        let e2: EnumSet<Foo> = EnumSet::empty();
-        assert!(!e1.intersects(e2));
-    }
-
-    #[test]
-    fn test_empty_does_not_intersect_with_full() {
-        let e1: EnumSet<Foo> = EnumSet::empty();
-
-        let mut e2: EnumSet<Foo> = EnumSet::empty();
-        e2.add(A);
-        e2.add(B);
-        e2.add(C);
-
-        assert!(!e1.intersects(e2));
-    }
-
-    #[test]
-    fn test_disjoint_intersects() {
-        let mut e1: EnumSet<Foo> = EnumSet::empty();
-        e1.add(A);
-
-        let mut e2: EnumSet<Foo> = EnumSet::empty();
-        e2.add(B);
-
-        assert!(!e1.intersects(e2));
-    }
-
-    #[test]
-    fn test_overlapping_intersects() {
-        let mut e1: EnumSet<Foo> = EnumSet::empty();
-        e1.add(A);
-
-        let mut e2: EnumSet<Foo> = EnumSet::empty();
-        e2.add(A);
-        e2.add(B);
-
-        assert!(e1.intersects(e2));
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // contains and contains_elem
-
-    #[test]
-    fn test_contains() {
-        let mut e1: EnumSet<Foo> = EnumSet::empty();
-        e1.add(A);
-
-        let mut e2: EnumSet<Foo> = EnumSet::empty();
-        e2.add(A);
-        e2.add(B);
-
-        assert!(!e1.contains(e2));
-        assert!(e2.contains(e1));
-    }
-
-    #[test]
-    fn test_contains_elem() {
-        let mut e1: EnumSet<Foo> = EnumSet::empty();
-        e1.add(A);
-        assert!(e1.contains_elem(A));
-        assert!(!e1.contains_elem(B));
-        assert!(!e1.contains_elem(C));
-
-        e1.add(A);
-        e1.add(B);
-        assert!(e1.contains_elem(A));
-        assert!(e1.contains_elem(B));
-        assert!(!e1.contains_elem(C));
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // iter / each
-
-    #[test]
-    fn test_iterator() {
-        let mut e1: EnumSet<Foo> = EnumSet::empty();
-
-        let elems: ~[Foo] = e1.iter().collect();
-        assert_eq!(~[], elems)
-
-        e1.add(A);
-        let elems: ~[Foo] = e1.iter().collect();
-        assert_eq!(~[A], elems)
-
-        e1.add(C);
-        let elems: ~[Foo] = e1.iter().collect();
-        assert_eq!(~[A,C], elems)
-
-        e1.add(C);
-        let elems: ~[Foo] = e1.iter().collect();
-        assert_eq!(~[A,C], elems)
-
-        e1.add(B);
-        let elems: ~[Foo] = e1.iter().collect();
-        assert_eq!(~[A,B,C], elems)
-    }
-
-    #[test]
-    fn test_each() {
-        let mut e1: EnumSet<Foo> = EnumSet::empty();
-
-        assert_eq!(~[], collect(e1))
-
-        e1.add(A);
-        assert_eq!(~[A], collect(e1))
-
-        e1.add(C);
-        assert_eq!(~[A,C], collect(e1))
-
-        e1.add(C);
-        assert_eq!(~[A,C], collect(e1))
-
-        e1.add(B);
-        assert_eq!(~[A,B,C], collect(e1))
-    }
-
-    fn collect(e: EnumSet<Foo>) -> ~[Foo] {
-        let mut elems = ~[];
-        e.each(|elem| {
-           elems.push(elem);
-           true
-        });
-        elems
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // operators
-
-    #[test]
-    fn test_operators() {
-        let mut e1: EnumSet<Foo> = EnumSet::empty();
-        e1.add(A);
-        e1.add(C);
-
-        let mut e2: EnumSet<Foo> = EnumSet::empty();
-        e2.add(B);
-        e2.add(C);
-
-        let e_union = e1 | e2;
-        let elems: ~[Foo] = e_union.iter().collect();
-        assert_eq!(~[A,B,C], elems)
-
-        let e_intersection = e1 & e2;
-        let elems: ~[Foo] = e_intersection.iter().collect();
-        assert_eq!(~[C], elems)
-
-        let e_subtract = e1 - e2;
-        let elems: ~[Foo] = e_subtract.iter().collect();
-        assert_eq!(~[A], elems)
-    }
-}
index 8f0dd51457074c23bdd2e2a7cb219e4f8cd40301..1bea3003c63d292402bec46afef8cd578739a293 100644 (file)
@@ -280,9 +280,13 @@ pub fn vstore_ty_to_str(cx: ctxt, mt: &mt, vs: ty::vstore) -> ~str {
     }
 }
 
+pub fn vec_map_to_str<T>(ts: &[T], f: &fn(t: &T) -> ~str) -> ~str {
+    let tstrs = ts.map(f);
+    fmt!("[%s]", tstrs.connect(", "))
+}
+
 pub fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str {
-    let tstrs = ts.map(|t| ty_to_str(cx, *t));
-    fmt!("(%s)", tstrs.connect(", "))
+    vec_map_to_str(ts, |t| ty_to_str(cx, *t))
 }
 
 pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str {
@@ -529,7 +533,7 @@ fn repr(&self, tcx: ctxt) -> ~str {
 }
 
 fn repr_vec<T:Repr>(tcx: ctxt, v: &[T]) -> ~str {
-    fmt!("[%s]", v.map(|t| t.repr(tcx)).connect(","))
+    vec_map_to_str(v, |t| t.repr(tcx))
 }
 
 impl<'self, T:Repr> Repr for &'self [T] {
@@ -589,15 +593,14 @@ fn repr(&self, tcx: ctxt) -> ~str {
 impl Repr for ty::ParamBounds {
     fn repr(&self, tcx: ctxt) -> ~str {
         let mut res = ~[];
-        do self.builtin_bounds.each |b| {
+        for b in self.builtin_bounds.iter() {
             res.push(match b {
                 ty::BoundStatic => ~"'static",
                 ty::BoundSend => ~"Send",
                 ty::BoundFreeze => ~"Freeze",
                 ty::BoundSized => ~"Sized",
             });
-            true
-        };
+        }
         for t in self.trait_bounds.iter() {
             res.push(t.repr(tcx));
         }
@@ -833,10 +836,9 @@ impl UserString for ty::BuiltinBounds {
     fn user_string(&self, tcx: ctxt) -> ~str {
         if self.is_empty() { ~"<no-bounds>" } else {
             let mut result = ~[];
-            do self.each |bb| {
+            for bb in self.iter() {
                 result.push(bb.user_string(tcx));
-                true
-            };
+            }
             result.connect("+")
         }
     }
index 5d5518997f68f0252ab8e9c3acd276c0dec417f7..86290ea65b5646f939eed20204ae3a07b79c6bc4 100644 (file)
@@ -565,10 +565,7 @@ fn repl() -> Repl {
         }
     }
 
-    // FIXME: #7220 rusti on 32bit mac doesn't work.
-    // FIXME: #7641 rusti on 32bit linux cross compile doesn't work
-    // FIXME: #7115 re-enable once LLVM has been upgraded
-    #[cfg(thiswillneverbeacfgflag)]
+    #[cfg(not(target_word_size = "32"))]
     fn run_program(prog: &str) {
         let mut r = repl();
         for cmd in prog.split_iter('\n') {
@@ -577,6 +574,9 @@ fn run_program(prog: &str) {
                     "the command '%s' failed", cmd);
         }
     }
+    // FIXME: #7220 rusti on 32bit mac doesn't work
+    // FIXME: #7641 rusti on 32bit linux cross compile doesn't work
+    #[cfg(target_word_size = "32")]
     fn run_program(_: &str) {}
 
     #[test]
@@ -594,13 +594,12 @@ fn regression_5784() {
         run_program("let a = 3;");
     }
 
-    #[test] #[ignore]
+    #[test]
     fn new_tasks() {
-        // XXX: can't spawn new tasks because the JIT code is cleaned up
-        //      after the main function is done.
         run_program("
-            spawn( || println(\"Please don't segfault\") );
-            do spawn { println(\"Please?\"); }
+            use std::task::try;
+            try( || println(\"Please don't segfault\") );
+            do try { println(\"Please?\"); }
         ");
     }
 
index 9e3a3a28fe8cef39aa0b1020d8f548ca37e8cfdb..6c3d4c5f1fbeab4d82dec81c1543d7e4eeb74939 100644 (file)
@@ -58,3 +58,15 @@ fn gt(&self, other: & &'self T) -> bool {
         *(*self) > *(*other)
     }
 }
+
+#[cfg(not(test))]
+impl<'self, T: TotalOrd> TotalOrd for &'self T {
+    #[inline]
+    fn cmp(&self, other: & &'self T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<'self, T: TotalEq> TotalEq for &'self T {
+    #[inline]
+    fn equals(&self, other: & &'self T) -> bool { (**self).equals(*other) }
+}
index 43a632562b2b71b5db5697bf28a051c62df185e5..b66f89e83415e1b22ad0a575f950f1855057460f 100644 (file)
@@ -153,7 +153,6 @@ pub fn cmp2<A:TotalOrd,B:TotalOrd>(
 Return `o1` if it is not `Equal`, otherwise `o2`. Simulates the
 lexical ordering on a type `(int, int)`.
 */
-// used in deriving code in libsyntax
 #[inline]
 pub fn lexical_ordering(o1: Ordering, o2: Ordering) -> Ordering {
     match o1 {
index 56a0dca56679ccf3a34d89038944614d0c497263..e86f4d7a85e6f693f0034f0b7926a26c14616d67 100644 (file)
@@ -18,7 +18,7 @@
 */
 
 use cmp;
-use num::{Zero, One};
+use num::{Zero, One, Saturating};
 use option::{Option, Some, None};
 use ops::{Add, Mul};
 use cmp::Ord;
@@ -884,15 +884,10 @@ fn size_hint(&self) -> (uint, Option<uint>) {
         let (a_lower, a_upper) = self.a.size_hint();
         let (b_lower, b_upper) = self.b.size_hint();
 
-        let lower = if uint::max_value - a_lower < b_lower {
-            uint::max_value
-        } else {
-            a_lower + b_lower
-        };
+        let lower = a_lower.saturating_add(b_lower);
 
         let upper = match (a_upper, b_upper) {
-            (Some(x), Some(y)) if uint::max_value - x < y => Some(uint::max_value),
-            (Some(x), Some(y)) => Some(x + y),
+            (Some(x), Some(y)) => Some(x.saturating_add(y)),
             _ => None
         };
 
@@ -916,12 +911,7 @@ impl<A, T: RandomAccessIterator<A>, U: RandomAccessIterator<A>> RandomAccessIter
     #[inline]
     fn indexable(&self) -> uint {
         let (a, b) = (self.a.indexable(), self.b.indexable());
-        let total = a + b;
-        if total < a || total < b {
-            uint::max_value
-        } else {
-            total
-        }
+        a.saturating_add(b)
     }
 
     #[inline]
@@ -1273,11 +1263,10 @@ fn next(&mut self) -> Option<A> {
     fn size_hint(&self) -> (uint, Option<uint>) {
         let (lower, upper) = self.iter.size_hint();
 
-        let lower = if lower >= self.n { lower - self.n } else { 0 };
+        let lower = lower.saturating_sub(self.n);
 
         let upper = match upper {
-            Some(x) if x >= self.n => Some(x - self.n),
-            Some(_) => Some(0),
+            Some(x) => Some(x.saturating_sub(self.n)),
             None => None
         };
 
@@ -1288,12 +1277,7 @@ fn size_hint(&self) -> (uint, Option<uint>) {
 impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Skip<T> {
     #[inline]
     fn indexable(&self) -> uint {
-        let N = self.iter.indexable();
-        if N < self.n {
-            0
-        } else {
-            N - self.n
-        }
+        self.iter.indexable().saturating_sub(self.n)
     }
 
     #[inline]
@@ -1410,9 +1394,10 @@ fn next(&mut self) -> Option<B> {
     fn size_hint(&self) -> (uint, Option<uint>) {
         let (flo, fhi) = self.frontiter.map_default((0, Some(0)), |it| it.size_hint());
         let (blo, bhi) = self.backiter.map_default((0, Some(0)), |it| it.size_hint());
+        let lo = flo.saturating_add(blo);
         match (self.iter.size_hint(), fhi, bhi) {
-            ((0, Some(0)), Some(a), Some(b)) => (flo + blo, Some(a + b)),
-            _ => (flo + blo, None)
+            ((0, Some(0)), Some(a), Some(b)) => (lo, Some(a.saturating_add(b))),
+            _ => (lo, None)
         }
     }
 }
index bd4dc69537cb10c9969e19c0b5dc942af3383197..57230b2fd247d4e86d9a844dc6bc39c798056378 100644 (file)
@@ -12,7 +12,7 @@
 
 use ptr::to_unsafe_ptr;
 
-#[cfg(not(test))] use cmp::{Eq, Ord};
+#[cfg(not(test))] use cmp::*;
 
 pub static RC_MANAGED_UNIQUE : uint = (-2) as uint;
 pub static RC_IMMORTAL : uint = 0x77777777;
@@ -71,6 +71,29 @@ fn ge(&self, other: &@mut T) -> bool { *(*self) >= *(*other) }
     fn gt(&self, other: &@mut T) -> bool { *(*self) > *(*other) }
 }
 
+#[cfg(not(test))]
+impl<T: TotalOrd> TotalOrd for @T {
+    #[inline]
+    fn cmp(&self, other: &@T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalOrd> TotalOrd for @mut T {
+    #[inline]
+    fn cmp(&self, other: &@mut T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalEq> TotalEq for @T {
+    #[inline]
+    fn equals(&self, other: &@T) -> bool { (**self).equals(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalEq> TotalEq for @mut T {
+    #[inline]
+    fn equals(&self, other: &@mut T) -> bool { (**self).equals(*other) }
+}
 #[test]
 fn test() {
     let x = @3;
index 8b61a8a8734b9fb8f8df49193bc51db5756c5e56..bbadf1caca2413c4570460ac9040d28cc1940554 100644 (file)
@@ -466,6 +466,56 @@ fn zero() -> ~T { ~Zero::zero() }
     fn is_zero(&self) -> bool { (**self).is_zero() }
 }
 
+/// Saturating math operations
+pub trait Saturating: Int {
+    /// Saturating addition operator.
+    /// Returns a+b, saturating at the numeric bounds instead of overflowing.
+    #[inline]
+    fn saturating_add(self, v: Self) -> Self {
+        let x = self + v;
+        if v >= Zero::zero() {
+            if x < self {
+                // overflow
+                Bounded::max_value::<Self>()
+            } else { x }
+        } else {
+            if x > self {
+                // underflow
+                Bounded::min_value::<Self>()
+            } else { x }
+        }
+    }
+
+    /// Saturating subtraction operator.
+    /// Returns a-b, saturating at the numeric bounds instead of overflowing.
+    #[inline]
+    fn saturating_sub(self, v: Self) -> Self {
+        let x = self - v;
+        if v >= Zero::zero() {
+            if x > self {
+                // underflow
+                Bounded::min_value::<Self>()
+            } else { x }
+        } else {
+            if x < self {
+                // overflow
+                Bounded::max_value::<Self>()
+            } else { x }
+        }
+    }
+}
+
+impl Saturating for int {}
+impl Saturating for i8 {}
+impl Saturating for i16 {}
+impl Saturating for i32 {}
+impl Saturating for i64 {}
+impl Saturating for uint {}
+impl Saturating for u8 {}
+impl Saturating for u16 {}
+impl Saturating for u32 {}
+impl Saturating for u64 {}
+
 /// Helper function for testing numeric operations
 #[cfg(test)]
 pub fn test_num<T:Num + NumCast>(ten: T, two: T) {
@@ -482,64 +532,111 @@ pub fn test_num<T:Num + NumCast>(ten: T, two: T) {
     assert_eq!(ten.rem(&two),  ten % two);
 }
 
-macro_rules! test_cast_20(
-    ($_20:expr) => ({
-        let _20 = $_20;
-
-        assert_eq!(20u,   _20.to_uint());
-        assert_eq!(20u8,  _20.to_u8());
-        assert_eq!(20u16, _20.to_u16());
-        assert_eq!(20u32, _20.to_u32());
-        assert_eq!(20u64, _20.to_u64());
-        assert_eq!(20i,   _20.to_int());
-        assert_eq!(20i8,  _20.to_i8());
-        assert_eq!(20i16, _20.to_i16());
-        assert_eq!(20i32, _20.to_i32());
-        assert_eq!(20i64, _20.to_i64());
-        assert_eq!(20f,   _20.to_float());
-        assert_eq!(20f32, _20.to_f32());
-        assert_eq!(20f64, _20.to_f64());
-
-        assert_eq!(_20, NumCast::from(20u));
-        assert_eq!(_20, NumCast::from(20u8));
-        assert_eq!(_20, NumCast::from(20u16));
-        assert_eq!(_20, NumCast::from(20u32));
-        assert_eq!(_20, NumCast::from(20u64));
-        assert_eq!(_20, NumCast::from(20i));
-        assert_eq!(_20, NumCast::from(20i8));
-        assert_eq!(_20, NumCast::from(20i16));
-        assert_eq!(_20, NumCast::from(20i32));
-        assert_eq!(_20, NumCast::from(20i64));
-        assert_eq!(_20, NumCast::from(20f));
-        assert_eq!(_20, NumCast::from(20f32));
-        assert_eq!(_20, NumCast::from(20f64));
-
-        assert_eq!(_20, cast(20u));
-        assert_eq!(_20, cast(20u8));
-        assert_eq!(_20, cast(20u16));
-        assert_eq!(_20, cast(20u32));
-        assert_eq!(_20, cast(20u64));
-        assert_eq!(_20, cast(20i));
-        assert_eq!(_20, cast(20i8));
-        assert_eq!(_20, cast(20i16));
-        assert_eq!(_20, cast(20i32));
-        assert_eq!(_20, cast(20i64));
-        assert_eq!(_20, cast(20f));
-        assert_eq!(_20, cast(20f32));
-        assert_eq!(_20, cast(20f64));
-    })
-)
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    macro_rules! test_cast_20(
+        ($_20:expr) => ({
+            let _20 = $_20;
+
+            assert_eq!(20u,   _20.to_uint());
+            assert_eq!(20u8,  _20.to_u8());
+            assert_eq!(20u16, _20.to_u16());
+            assert_eq!(20u32, _20.to_u32());
+            assert_eq!(20u64, _20.to_u64());
+            assert_eq!(20i,   _20.to_int());
+            assert_eq!(20i8,  _20.to_i8());
+            assert_eq!(20i16, _20.to_i16());
+            assert_eq!(20i32, _20.to_i32());
+            assert_eq!(20i64, _20.to_i64());
+            assert_eq!(20f,   _20.to_float());
+            assert_eq!(20f32, _20.to_f32());
+            assert_eq!(20f64, _20.to_f64());
+
+            assert_eq!(_20, NumCast::from(20u));
+            assert_eq!(_20, NumCast::from(20u8));
+            assert_eq!(_20, NumCast::from(20u16));
+            assert_eq!(_20, NumCast::from(20u32));
+            assert_eq!(_20, NumCast::from(20u64));
+            assert_eq!(_20, NumCast::from(20i));
+            assert_eq!(_20, NumCast::from(20i8));
+            assert_eq!(_20, NumCast::from(20i16));
+            assert_eq!(_20, NumCast::from(20i32));
+            assert_eq!(_20, NumCast::from(20i64));
+            assert_eq!(_20, NumCast::from(20f));
+            assert_eq!(_20, NumCast::from(20f32));
+            assert_eq!(_20, NumCast::from(20f64));
+
+            assert_eq!(_20, cast(20u));
+            assert_eq!(_20, cast(20u8));
+            assert_eq!(_20, cast(20u16));
+            assert_eq!(_20, cast(20u32));
+            assert_eq!(_20, cast(20u64));
+            assert_eq!(_20, cast(20i));
+            assert_eq!(_20, cast(20i8));
+            assert_eq!(_20, cast(20i16));
+            assert_eq!(_20, cast(20i32));
+            assert_eq!(_20, cast(20i64));
+            assert_eq!(_20, cast(20f));
+            assert_eq!(_20, cast(20f32));
+            assert_eq!(_20, cast(20f64));
+        })
+    )
+
+    #[test] fn test_u8_cast()    { test_cast_20!(20u8)  }
+    #[test] fn test_u16_cast()   { test_cast_20!(20u16) }
+    #[test] fn test_u32_cast()   { test_cast_20!(20u32) }
+    #[test] fn test_u64_cast()   { test_cast_20!(20u64) }
+    #[test] fn test_uint_cast()  { test_cast_20!(20u)   }
+    #[test] fn test_i8_cast()    { test_cast_20!(20i8)  }
+    #[test] fn test_i16_cast()   { test_cast_20!(20i16) }
+    #[test] fn test_i32_cast()   { test_cast_20!(20i32) }
+    #[test] fn test_i64_cast()   { test_cast_20!(20i64) }
+    #[test] fn test_int_cast()   { test_cast_20!(20i)   }
+    #[test] fn test_f32_cast()   { test_cast_20!(20f32) }
+    #[test] fn test_f64_cast()   { test_cast_20!(20f64) }
+    #[test] fn test_float_cast() { test_cast_20!(20f)   }
+
+    #[test]
+    fn test_saturating_add_uint() {
+        use uint::max_value;
+        assert_eq!(3u.saturating_add(5u), 8u);
+        assert_eq!(3u.saturating_add(max_value-1), max_value);
+        assert_eq!(max_value.saturating_add(max_value), max_value);
+        assert_eq!((max_value-2).saturating_add(1), max_value-1);
+    }
+
+    #[test]
+    fn test_saturating_sub_uint() {
+        use uint::max_value;
+        assert_eq!(5u.saturating_sub(3u), 2u);
+        assert_eq!(3u.saturating_sub(5u), 0u);
+        assert_eq!(0u.saturating_sub(1u), 0u);
+        assert_eq!((max_value-1).saturating_sub(max_value), 0);
+    }
 
-#[test] fn test_u8_cast()    { test_cast_20!(20u8)  }
-#[test] fn test_u16_cast()   { test_cast_20!(20u16) }
-#[test] fn test_u32_cast()   { test_cast_20!(20u32) }
-#[test] fn test_u64_cast()   { test_cast_20!(20u64) }
-#[test] fn test_uint_cast()  { test_cast_20!(20u)   }
-#[test] fn test_i8_cast()    { test_cast_20!(20i8)  }
-#[test] fn test_i16_cast()   { test_cast_20!(20i16) }
-#[test] fn test_i32_cast()   { test_cast_20!(20i32) }
-#[test] fn test_i64_cast()   { test_cast_20!(20i64) }
-#[test] fn test_int_cast()   { test_cast_20!(20i)   }
-#[test] fn test_f32_cast()   { test_cast_20!(20f32) }
-#[test] fn test_f64_cast()   { test_cast_20!(20f64) }
-#[test] fn test_float_cast() { test_cast_20!(20f)   }
+    #[test]
+    fn test_saturating_add_int() {
+        use int::{min_value,max_value};
+        assert_eq!(3i.saturating_add(5i), 8i);
+        assert_eq!(3i.saturating_add(max_value-1), max_value);
+        assert_eq!(max_value.saturating_add(max_value), max_value);
+        assert_eq!((max_value-2).saturating_add(1), max_value-1);
+        assert_eq!(3i.saturating_add(-5i), -2i);
+        assert_eq!(min_value.saturating_add(-1i), min_value);
+        assert_eq!((-2i).saturating_add(-max_value), min_value);
+    }
+
+    #[test]
+    fn test_saturating_sub_int() {
+        use int::{min_value,max_value};
+        assert_eq!(3i.saturating_sub(5i), -2i);
+        assert_eq!(min_value.saturating_sub(1i), min_value);
+        assert_eq!((-2i).saturating_sub(max_value), min_value);
+        assert_eq!(3i.saturating_sub(-5i), 8i);
+        assert_eq!(3i.saturating_sub(-(max_value-1)), max_value);
+        assert_eq!(max_value.saturating_sub(-max_value), max_value);
+        assert_eq!((max_value-2).saturating_sub(-1), max_value-1);
+    }
+}
index e7a6e38fdb08874d5474806d66f346a9167e75ca..424c4fd6b2f44d0e4f4102e04e1827a62f667670 100644 (file)
@@ -10,7 +10,7 @@
 
 //! Operations on unique pointer types
 
-#[cfg(not(test))] use cmp::{Eq, Ord};
+#[cfg(not(test))] use cmp::*;
 
 #[cfg(not(test))]
 impl<T:Eq> Eq for ~T {
@@ -31,3 +31,15 @@ fn ge(&self, other: &~T) -> bool { *(*self) >= *(*other) }
     #[inline]
     fn gt(&self, other: &~T) -> bool { *(*self) > *(*other) }
 }
+
+#[cfg(not(test))]
+impl<T: TotalOrd> TotalOrd for ~T {
+    #[inline]
+    fn cmp(&self, other: &~T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalEq> TotalEq for ~T {
+    #[inline]
+    fn equals(&self, other: &~T) -> bool { (**self).equals(*other) }
+}
index bea62f7e28c193a8b3ef1116de78f2bd8ab250c3..16bca850fd2894d0b32dacb92b1e33a73a84170d 100644 (file)
@@ -10,7 +10,7 @@
 
 //! Some various other I/O types
 
-// NOTE: These ultimately belong somewhere else
+// FIXME(#3660): should move to libextra
 
 use prelude::*;
 use super::*;
index deec8dd37a600d1a484f02f909ae6fe0a9753c1e..3372c13b87703a72cdef5af13fa5b651cc2379fc 100644 (file)
@@ -193,6 +193,10 @@ pub fn wake(self) -> Option<~Task> {
 
     /// Create a blocked task, unless the task was already killed.
     pub fn try_block(mut task: ~Task) -> Either<~Task, BlockedTask> {
+        // NB: As an optimization, we could give a free pass to being unkillable
+        // to tasks whose taskgroups haven't been initialized yet, but that
+        // introduces complications with select() and with the test cases below,
+        // and it's not clear the uncommon performance boost is worth it.
         if task.death.unkillable > 0 {
             Right(Unkillable(task))
         } else {
@@ -205,11 +209,10 @@ pub fn try_block(mut task: ~Task) -> Either<~Task, BlockedTask> {
                 let flag_arc = match task.death.spare_kill_flag.take() {
                     Some(spare_flag) => spare_flag,
                     None => {
-                        // FIXME(#7544): Uncomment this when terminate_current_task
-                        // stops being *terrible*. That's the only place that violates
-                        // the assumption of "becoming unkillable will fail if the
-                        // task was killed".
-                        // rtassert!(task.unwinder.unwinding);
+                        // A task that kills us won't have a spare kill flag to
+                        // give back to us, so we restore it ourselves here. This
+                        // situation should only arise when we're already failing.
+                        rtassert!(task.unwinder.unwinding);
                         (*task.death.kill_handle.get_ref().get()).killed.clone()
                     }
                 };
index 55faf7e319295dec75ab0ce80f1f09a1d8f1078a..cd7aac020edef4440212f4917aaa9756734e7862 100644 (file)
@@ -885,7 +885,7 @@ pub unsafe fn c_str_to_static_slice(s: *libc::c_char) -> &'static str {
     /// If begin is greater than end.
     /// If end is greater than the length of the string.
     #[inline]
-    pub unsafe fn slice_bytes(s: &str, begin: uint, end: uint) -> &str {
+    pub unsafe fn slice_bytes<'a>(s: &'a str, begin: uint, end: uint) -> &'a str {
         do s.as_imm_buf |sbuf, n| {
              assert!((begin <= end));
              assert!((end <= n));
index dd730f2068973d67534586d69d03c4bacb99446e..1be4d07dfa477ccdf7056e1117362d7d2f6bab4c 100644 (file)
 use to_str::{ToStr,ToStrConsume};
 use str;
 use str::StrSlice;
+use str::OwnedStr;
+use container::Container;
 use cast;
+use ptr;
 use iterator::{Iterator, IteratorUtil};
 use vec::{CopyableVector, ImmutableVector, OwnedVector};
 use to_bytes::IterBytes;
@@ -39,27 +42,19 @@ pub fn to_char(self) -> char {
     /// Convert to lowercase.
     #[inline]
     pub fn to_lower(self) -> Ascii {
-        if self.chr >= 65 && self.chr <= 90 {
-            Ascii{chr: self.chr | 0x20 }
-        } else {
-            self
-        }
+        Ascii{chr: ASCII_LOWER_MAP[self.chr]}
     }
 
     /// Convert to uppercase.
     #[inline]
     pub fn to_upper(self) -> Ascii {
-        if self.chr >= 97 && self.chr <= 122 {
-            Ascii{chr: self.chr & !0x20 }
-        } else {
-            self
-        }
+        Ascii{chr: ASCII_UPPER_MAP[self.chr]}
     }
 
     /// Compares two ascii characters of equality, ignoring case.
     #[inline]
     pub fn eq_ignore_case(self, other: Ascii) -> bool {
-        self.to_lower().chr == other.to_lower().chr
+        ASCII_LOWER_MAP[self.chr] == ASCII_LOWER_MAP[other.chr]
     }
 }
 
@@ -261,10 +256,124 @@ fn into_bytes(self) -> ~[u8] {
     }
 }
 
+
+/// Convert the string to ASCII upper case:
+/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+/// but non-ASCII letters are unchanged.
+#[inline]
+pub fn to_ascii_upper(string: &str) -> ~str {
+    map_bytes(string, ASCII_UPPER_MAP)
+}
+
+/// Convert the string to ASCII lower case:
+/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+/// but non-ASCII letters are unchanged.
+#[inline]
+pub fn to_ascii_lower(string: &str) -> ~str {
+    map_bytes(string, ASCII_LOWER_MAP)
+}
+
+#[inline]
+priv fn map_bytes(string: &str, map: &'static [u8]) -> ~str {
+    let len = string.len();
+    let mut result = str::with_capacity(len);
+    unsafe {
+        do result.as_mut_buf |mut buf, _| {
+            for c in string.as_bytes().iter() {
+                *buf = map[*c];
+                buf = ptr::mut_offset(buf, 1)
+            }
+        }
+        str::raw::set_len(&mut result, len);
+    }
+    result
+}
+
+/// Check that two strings are an ASCII case-insensitive match.
+/// Same as `to_ascii_lower(a) == to_ascii_lower(b)`,
+/// but without allocating and copying temporary strings.
+#[inline]
+pub fn eq_ignore_ascii_case(a: &str, b: &str) -> bool {
+    a.len() == b.len() && a.as_bytes().iter().zip(b.as_bytes().iter()).all(
+        |(byte_a, byte_b)| ASCII_LOWER_MAP[*byte_a] == ASCII_LOWER_MAP[*byte_b])
+}
+
+priv static ASCII_LOWER_MAP: &'static [u8] = &[
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+    0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+    0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+    0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+    0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+    0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+priv static ASCII_UPPER_MAP: &'static [u8] = &[
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+    0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+    0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+    0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+
 #[cfg(test)]
 mod tests {
     use super::*;
     use to_bytes::ToBytes;
+    use str::from_char;
 
     macro_rules! v2ascii (
         ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
@@ -347,4 +456,53 @@ fn test_ascii_to_bytes() {
 
     #[test] #[should_fail]
     fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
+
+    #[test]
+    fn test_to_ascii_upper() {
+        assert_eq!(to_ascii_upper("url()URL()uRl()ürl"), ~"URL()URL()URL()üRL");
+        assert_eq!(to_ascii_upper("hıKß"), ~"HıKß");
+
+        let mut i = 0;
+        while i <= 500 {
+            let c = i as char;
+            let upper = if 'a' <= c && c <= 'z' { c + 'A' - 'a' } else { c };
+            assert_eq!(to_ascii_upper(from_char(i as char)), from_char(upper))
+            i += 1;
+        }
+    }
+
+    #[test]
+    fn test_to_ascii_lower() {
+        assert_eq!(to_ascii_lower("url()URL()uRl()Ürl"), ~"url()url()url()Ürl");
+        // Dotted capital I, Kelvin sign, Sharp S.
+        assert_eq!(to_ascii_lower("HİKß"), ~"hİKß");
+
+        let mut i = 0;
+        while i <= 500 {
+            let c = i as char;
+            let lower = if 'A' <= c && c <= 'Z' { c + 'a' - 'A' } else { c };
+            assert_eq!(to_ascii_lower(from_char(i as char)), from_char(lower))
+            i += 1;
+        }
+    }
+
+
+    #[test]
+    fn test_eq_ignore_ascii_case() {
+        assert!(eq_ignore_ascii_case("url()URL()uRl()Ürl", "url()url()url()Ürl"));
+        assert!(!eq_ignore_ascii_case("Ürl", "ürl"));
+        // Dotted capital I, Kelvin sign, Sharp S.
+        assert!(eq_ignore_ascii_case("HİKß", "hİKß"));
+        assert!(!eq_ignore_ascii_case("İ", "i"));
+        assert!(!eq_ignore_ascii_case("K", "k"));
+        assert!(!eq_ignore_ascii_case("ß", "s"));
+
+        let mut i = 0;
+        while i <= 500 {
+            let c = i as char;
+            let lower = if 'A' <= c && c <= 'Z' { c + 'a' - 'A' } else { c };
+            assert!(eq_ignore_ascii_case(from_char(i as char), from_char(lower)));
+            i += 1;
+        }
+    }
 }
index 3bf2f255f57511ab2bca818ec0a4edfe7f2086ad..527b20b0e9027312afc5d66244365fa54b5cb28f 100644 (file)
@@ -568,7 +568,8 @@ fn with_my_taskgroup<U>(blk: &fn(&Taskgroup) -> U) -> U {
                 let me = Local::unsafe_borrow::<Task>();
                 blk(match (*me).taskgroup {
                     None => {
-                        // Main task, doing first spawn ever. Lazily initialize.
+                        // First task in its (unlinked/unsupervised) taskgroup.
+                        // Lazily initialize.
                         let mut members = TaskSet::new();
                         let my_handle = (*me).death.kill_handle.get_ref().clone();
                         members.insert(NewTask(my_handle));
@@ -591,37 +592,46 @@ fn with_my_taskgroup<U>(blk: &fn(&Taskgroup) -> U) -> U {
     }
 }
 
+// Returns 'None' in the case where the child's TG should be lazily initialized.
 fn gen_child_taskgroup(linked: bool, supervised: bool)
-    -> (TaskGroupArc, AncestorList, bool) {
-    do RuntimeGlue::with_my_taskgroup |spawner_group| {
-        let ancestors = AncestorList(spawner_group.ancestors.map(|x| x.clone()));
-        if linked {
-            // Child is in the same group as spawner.
-            // Child's ancestors are spawner's ancestors.
-            // Propagate main-ness.
-            (spawner_group.tasks.clone(), ancestors, spawner_group.is_main)
-        } else {
-            // Child is in a separate group from spawner.
-            let g = Exclusive::new(Some(TaskGroupData {
-                members:     TaskSet::new(),
-                descendants: TaskSet::new(),
-            }));
-            let a = if supervised {
-                let new_generation = incr_generation(&ancestors);
-                assert!(new_generation < uint::max_value);
-                // Child's ancestors start with the spawner.
-                // Build a new node in the ancestor list.
-                AncestorList(Some(Exclusive::new(AncestorNode {
-                    generation: new_generation,
-                    parent_group: spawner_group.tasks.clone(),
-                    ancestors: ancestors,
-                })))
+    -> Option<(TaskGroupArc, AncestorList, bool)> {
+    // FIXME(#7544): Not safe to lazily initialize in the old runtime. Remove
+    // this context check once 'spawn_raw_oldsched' is gone.
+    if context() == OldTaskContext || linked || supervised {
+        // with_my_taskgroup will lazily initialize the parent's taskgroup if
+        // it doesn't yet exist. We don't want to call it in the unlinked case.
+        do RuntimeGlue::with_my_taskgroup |spawner_group| {
+            let ancestors = AncestorList(spawner_group.ancestors.map(|x| x.clone()));
+            if linked {
+                // Child is in the same group as spawner.
+                // Child's ancestors are spawner's ancestors.
+                // Propagate main-ness.
+                Some((spawner_group.tasks.clone(), ancestors, spawner_group.is_main))
             } else {
-                // Child has no ancestors.
-                AncestorList(None)
-            };
-            (g, a, false)
+                // Child is in a separate group from spawner.
+                let g = Exclusive::new(Some(TaskGroupData {
+                    members:     TaskSet::new(),
+                    descendants: TaskSet::new(),
+                }));
+                let a = if supervised {
+                    let new_generation = incr_generation(&ancestors);
+                    assert!(new_generation < uint::max_value);
+                    // Child's ancestors start with the spawner.
+                    // Build a new node in the ancestor list.
+                    AncestorList(Some(Exclusive::new(AncestorNode {
+                        generation: new_generation,
+                        parent_group: spawner_group.tasks.clone(),
+                        ancestors: ancestors,
+                    })))
+                } else {
+                    // Child has no ancestors.
+                    AncestorList(None)
+                };
+                Some((g, a, false))
+            }
         }
+    } else {
+        None
     }
 }
 
@@ -670,20 +680,24 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) {
 
     let child_wrapper: ~fn() = || {
         // Child task runs this code.
-        let child_data = Cell::new(child_data.take()); // :(
-        let enlist_success = do Local::borrow::<Task, bool> |me| {
-            let (child_tg, ancestors, is_main) = child_data.take();
-            let mut ancestors = ancestors;
-            // FIXME(#7544): Optimize out the xadd in this clone, somehow.
-            let handle = me.death.kill_handle.get_ref().clone();
-            // Atomically try to get into all of our taskgroups.
-            if enlist_many(NewTask(handle), &child_tg, &mut ancestors) {
-                // Got in. We can run the provided child body, and can also run
-                // the taskgroup's exit-time-destructor afterward.
-                me.taskgroup = Some(Taskgroup(child_tg, ancestors, is_main, None));
-                true
-            } else {
-                false
+
+        // If child data is 'None', the enlist is vacuously successful.
+        let enlist_success = do child_data.take().map_consume_default(true) |child_data| {
+            let child_data = Cell::new(child_data); // :(
+            do Local::borrow::<Task, bool> |me| {
+                let (child_tg, ancestors, is_main) = child_data.take();
+                let mut ancestors = ancestors;
+                // FIXME(#7544): Optimize out the xadd in this clone, somehow.
+                let handle = me.death.kill_handle.get_ref().clone();
+                // Atomically try to get into all of our taskgroups.
+                if enlist_many(NewTask(handle), &child_tg, &mut ancestors) {
+                    // Got in. We can run the provided child body, and can also run
+                    // the taskgroup's exit-time-destructor afterward.
+                    me.taskgroup = Some(Taskgroup(child_tg, ancestors, is_main, None));
+                    true
+                } else {
+                    false
+                }
             }
         };
         // Should be run after the local-borrowed task is returned.
@@ -749,7 +763,7 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) {
                 let join_task = join_task_cell.take();
 
                 let bootstrap_task = ~do Task::new_root(&mut new_sched.stack_pool) || {
-                    rtdebug!("boostraping a 1:1 scheduler");
+                    rtdebug!("bootstrapping a 1:1 scheduler");
                 };
                 new_sched.bootstrap(bootstrap_task);
 
@@ -793,7 +807,7 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) {
 fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) {
 
     let (child_tg, ancestors, is_main) =
-        gen_child_taskgroup(opts.linked, opts.supervised);
+        gen_child_taskgroup(opts.linked, opts.supervised).expect("old runtime needs TG");
 
     unsafe {
         let child_data = Cell::new((child_tg, ancestors, f));
index 5cba22a8e2375a69426df537a04133e23d1e645d..6b4da9671a9636a02641804fc2a0cb3e23672125 100644 (file)
@@ -466,11 +466,11 @@ pub fn node_id_to_str(map: map, id: NodeId, itr: @ident_interner) -> ~str {
       Some(&node_local(ident)) => {
         fmt!("local (id=%?, name=%s)", id, itr.get(ident.name))
       }
-      Some(&node_block(_)) => {
-        fmt!("block")
+      Some(&node_block(ref block)) => {
+        fmt!("block %s (id=%?)", pprust::block_to_str(block, itr), id)
       }
-      Some(&node_struct_ctor(*)) => {
-        fmt!("struct_ctor")
+      Some(&node_struct_ctor(_, _, path)) => {
+        fmt!("struct_ctor %s (id=%?)", path_to_str(*path, itr), id)
       }
     }
 }
index 11d3740be3f519bfc41850984367323e1e6483e3..84e6544f78092b56ca51416548ae9b03c1c47947 100644 (file)
@@ -410,7 +410,7 @@ fn visit_generics_helper(@mut self, generics: &Generics) {
 impl Visitor<()> for IdVisitor {
     fn visit_mod(@mut self,
                  module: &_mod,
-                 span: span,
+                 _span: span,
                  node_id: NodeId,
                  env: ()) {
         (self.visit_callback)(node_id);
index 01dacdfe453ee7cec2a5b186698b48468ba9442a..001e92355282f9d5f095dfab787c3afa9dd779d4 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use ast;
 use ast::{MetaItem, item, expr};
 use codemap::span;
 use ext::base::ExtCtxt;
@@ -40,40 +41,70 @@ pub fn expand_deriving_totalord(cx: @ExtCtxt,
 }
 
 
-pub fn ordering_const(cx: @ExtCtxt, span: span, cnst: Ordering) -> @expr {
+pub fn ordering_const(cx: @ExtCtxt, span: span, cnst: Ordering) -> ast::Path {
     let cnst = match cnst {
         Less => "Less",
         Equal => "Equal",
         Greater => "Greater"
     };
-    cx.expr_path(
-        cx.path_global(span,
-                       ~[cx.ident_of("std"),
-                         cx.ident_of("cmp"),
-                         cx.ident_of(cnst)]))
+    cx.path_global(span,
+                   ~[cx.ident_of("std"),
+                     cx.ident_of("cmp"),
+                     cx.ident_of(cnst)])
 }
 
 pub fn cs_cmp(cx: @ExtCtxt, span: span,
               substr: &Substructure) -> @expr {
+    let test_id = cx.ident_of("__test");
+    let equals_path = ordering_const(cx, span, Equal);
 
+    /*
+    Builds:
+
+    let __test = self_field1.cmp(&other_field2);
+    if other == ::std::cmp::Equal {
+        let __test = self_field2.cmp(&other_field2);
+        if __test == ::std::cmp::Equal {
+            ...
+        } else {
+            __test
+        }
+    } else {
+        __test
+    }
+
+    FIXME #6449: These `if`s could/should be `match`es.
+    */
     cs_same_method_fold(
-        // foldr (possibly) nests the matches in lexical_ordering better
+        // foldr nests the if-elses correctly, leaving the first field
+        // as the outermost one, and the last as the innermost.
         false,
         |cx, span, old, new| {
-            cx.expr_call_global(span,
-                                ~[cx.ident_of("std"),
-                                  cx.ident_of("cmp"),
-                                  cx.ident_of("lexical_ordering")],
-                                ~[old, new])
+            // let __test = new;
+            // if __test == ::std::cmp::Equal {
+            //    old
+            // } else {
+            //    __test
+            // }
+
+            let assign = cx.stmt_let(span, false, test_id, new);
+
+            let cond = cx.expr_binary(span, ast::eq,
+                                      cx.expr_ident(span, test_id),
+                                      cx.expr_path(equals_path.clone()));
+            let if_ = cx.expr_if(span,
+                                 cond,
+                                 old, Some(cx.expr_ident(span, test_id)));
+            cx.expr_block(cx.block(span, ~[assign], Some(if_)))
         },
-        ordering_const(cx, span, Equal),
+        cx.expr_path(equals_path.clone()),
         |cx, span, list, _| {
             match list {
                 // an earlier nonmatching variant is Less than a
-                // later one
+                // later one.
                 [(self_var, _, _),
-                 (other_var, _, _)] => ordering_const(cx, span,
-                                                      self_var.cmp(&other_var)),
+                 (other_var, _, _)] => cx.expr_path(ordering_const(cx, span,
+                                                                   self_var.cmp(&other_var))),
                 _ => cx.span_bug(span, "Not exactly 2 arguments in `deriving(TotalOrd)`")
             }
         },
diff --git a/src/test/run-pass/deriving-cmp-shortcircuit.rs b/src/test/run-pass/deriving-cmp-shortcircuit.rs
new file mode 100644 (file)
index 0000000..7f5c78c
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// check that the derived impls for the comparison traits shortcircuit
+// where possible, by having a type that fails when compared as the
+// second element, so this passes iff the instances shortcircuit.
+
+pub struct FailCmp;
+impl Eq for FailCmp {
+    fn eq(&self, _: &FailCmp) -> bool { fail!("eq") }
+}
+
+impl Ord for FailCmp {
+    fn lt(&self, _: &FailCmp) -> bool { fail!("lt") }
+}
+
+impl TotalEq for FailCmp {
+    fn equals(&self, _: &FailCmp) -> bool { fail!("equals") }
+}
+
+impl TotalOrd for FailCmp {
+    fn cmp(&self, _: &FailCmp) -> Ordering { fail!("cmp") }
+}
+
+#[deriving(Eq,Ord,TotalEq,TotalOrd)]
+struct ShortCircuit {
+    x: int,
+    y: FailCmp
+}
+
+fn main() {
+    let a = ShortCircuit { x: 1, y: FailCmp };
+    let b = ShortCircuit { x: 2, y: FailCmp };
+
+    assert!(a != b);
+    assert!(a < b);
+    assert!(!a.equals(&b));
+    assert_eq!(a.cmp(&b), ::std::cmp::Less);
+}