]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #11904 : nick29581/rust/0filemap, r=alexcrichton
authorbors <bors@rust-lang.org>
Wed, 19 Feb 2014 19:36:48 +0000 (11:36 -0800)
committerbors <bors@rust-lang.org>
Wed, 19 Feb 2014 19:36:48 +0000 (11:36 -0800)
94 files changed:
Makefile.in
mk/main.mk
mk/tests.mk
src/compiler-rt
src/doc/guide-tasks.md
src/doc/lib/codemirror-node.js
src/doc/lib/codemirror-rust.js
src/doc/prep.js
src/doc/tutorial.md
src/etc/adb_run_wrapper.sh
src/etc/check-links.pl
src/etc/cmathconsts.c
src/etc/emacs/run_rust_emacs_tests.sh
src/etc/libc.c
src/etc/licenseck.py
src/etc/local_stage0.sh
src/etc/mingw-fix-include/bits/c++config.h
src/etc/mingw-fix-include/winbase.h
src/etc/mingw-fix-include/winsock2.h
src/etc/vim/syntax/rust.vim
src/libextra/json.rs
src/libextra/test.rs
src/libgreen/sched.rs
src/libnative/io/file.rs
src/libnative/io/mod.rs
src/libnative/io/pipe_unix.rs [new file with mode: 0644]
src/libnative/io/pipe_win32.rs [new file with mode: 0644]
src/libnum/complex.rs
src/librustc/back/archive.rs
src/librustc/middle/privacy.rs
src/librustc/middle/resolve.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check/_match.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/util/ppaux.rs
src/librustdoc/clean.rs
src/librustdoc/doctree.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.css
src/librustdoc/lib.rs
src/librustdoc/passes.rs
src/librustdoc/test.rs
src/librustdoc/visit_ast.rs
src/librustuv/idle.rs
src/librustuv/lib.rs
src/libstd/comm/select.rs
src/libstd/io/mod.rs
src/libstd/io/net/mod.rs
src/libstd/io/net/unix.rs
src/libstd/iter.rs
src/libstd/lib.rs
src/libstd/libc.rs
src/libstd/macros.rs
src/libstd/mem.rs
src/libstd/num/f32.rs
src/libstd/num/f64.rs
src/libstd/num/mod.rs
src/libstd/os.rs
src/libstd/prelude.rs
src/libstd/rand/distributions/exponential.rs
src/libstd/rand/distributions/gamma.rs
src/libstd/rand/distributions/normal.rs
src/libstd/rt/task.rs
src/libstd/rt/unwind.rs
src/libstd/str.rs
src/libstd/sync/mpsc_queue.rs
src/libstd/unstable/lang.rs
src/libsync/arc.rs
src/libsync/sync/mutex.rs
src/libsyntax/ext/asm.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/bytes.rs
src/libsyntax/ext/concat.rs
src/libsyntax/ext/concat_idents.rs
src/libsyntax/ext/env.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/format.rs
src/libsyntax/ext/source_util.rs
src/libsyntax/ext/trace_macros.rs
src/test/compile-fail/issue-11692.rs [new file with mode: 0644]
src/test/compile-fail/issue-4972.rs
src/test/compile-fail/issue-5100.rs
src/test/compile-fail/mutex-arc-nested.rs [deleted file]
src/test/compile-fail/privacy-ns1.rs [new file with mode: 0644]
src/test/compile-fail/privacy-ns2.rs [new file with mode: 0644]
src/test/run-make/rustdoc-json/Makefile [new file with mode: 0644]
src/test/run-make/rustdoc-json/foo.rs [new file with mode: 0644]
src/test/run-make/staticlib-blank-lib/Makefile [new file with mode: 0644]
src/test/run-make/staticlib-blank-lib/foo.rs [new file with mode: 0644]
src/test/run-pass/format-ref-cell.rs [new file with mode: 0644]
src/test/run-pass/issue-7660.rs [new file with mode: 0644]
src/test/run-pass/privacy-ns.rs [new file with mode: 0644]
src/test/run-pass/self-re-assign.rs [new file with mode: 0644]

index 5e6e8f310c7814e1a5078163d6299a80e5f87802..04ff606d0b93991c71f87a8870bffa372fcc2dfb 100644 (file)
 #
 # First, start with one of these build targets:
 #
-#   * all - The default. Builds a complete, bootstrapped compiler.
+#   * all - The default. Build a complete, bootstrapped compiler.
 #           `rustc` will be in `${target-triple}/stage2/bin/`. Run it
 #           directly from the build directory if you like. This also
 #           comes with docs in `doc/`.
 #
 #   * check - Run the complete test suite
 #
+#   * clean - Clean the build repertory. It is advised to run this
+#             command if you want to build Rust again, after an update
+#             of the git repository.
+#
 #   * install - Install Rust. Note that installation is not necessary
 #               to use the compiler.
 #
 #
 # </tips>
 #
-# <nittygritty>
+# <nitty-gritty>
 #
 # # The Rust Build System
 #
 # libraries are managed and versioned without polluting the common
 # areas of the filesystem.
 #
-# General rust binaries may stil live in the host bin directory; they
+# General rust binaries may still live in the host bin directory; they
 # will just link against the libraries in the target lib directory.
 #
 # Admittedly this is a little convoluted.
 #
-# </nittygritty>
+# </nitty-gritty>
 #
 
 ######################################################################
index 53ba07e65cbdd6ede725175eb9a0b6ec50d6262b..2c7c7c7cecd6d278248c64f27f11b527e3e81ab5 100644 (file)
@@ -446,13 +446,13 @@ all: $(ALL_TARGET_RULES) $(GENERATED) docs
 # $(1) is the name of the doc <section> in Makefile.in
 # pick everything between tags | remove first line | remove last line
 # | remove extra (?) line | strip leading `#` from lines
-SHOW_DOCS = $(Q)awk '/$(1)/,/<\/$(1)>/' $(S)/Makefile.in | sed '1d' | sed '$$d' | sed 's/^\# \?//'
+SHOW_DOCS = $(Q)awk '/<$(1)>/,/<\/$(1)>/' $(S)/Makefile.in | sed '1d' | sed '$$d' | sed 's/^\# \?//'
 
 help:
        $(call SHOW_DOCS,help)
 
-hot-tips:
-       $(call SHOW_DOCS,hottips)
+tips:
+       $(call SHOW_DOCS,tips)
 
 nitty-gritty:
-       $(call SHOW_DOCS,nittygritty)
+       $(call SHOW_DOCS,nitty-gritty)
index e1c4a4ccf94b46578e9fa7f2aad1b694f4f019e3..494588a1f91d17edde50a1f835fef179c1948196 100644 (file)
@@ -247,6 +247,16 @@ tidy:
                | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
                $(Q)find $(S)src/etc -name '*.py' \
                | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
+               $(Q)find $(S)src/doc -name '*.js' \
+               | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
+               $(Q)find $(S)src/etc -name '*.sh' \
+               | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
+               $(Q)find $(S)src/etc -name '*.pl' \
+               | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
+               $(Q)find $(S)src/etc -name '*.c' \
+               | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
+               $(Q)find $(S)src/etc -name '*.h' \
+               | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
                $(Q)echo $(ALL_CS) \
                | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
                $(Q)echo $(ALL_HS) \
index d4606f1818dd8dfeaa3e509cd1cbac4482c3513e..f4b221571ce6f05714c1f1c6fa48f1393499989c 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d4606f1818dd8dfeaa3e509cd1cbac4482c3513e
+Subproject commit f4b221571ce6f05714c1f1c6fa48f1393499989c
index 813b61dc8fb39f649a1aa5b6b5953e9e5b82146f..0d27071494fea1b2c7f4184e46c69d1c3795d2a6 100644 (file)
@@ -226,8 +226,7 @@ spawn(proc() {
 });
 ~~~
 
-Instead we can use a `SharedChan`, a type that allows a single
-`Chan` to be shared by multiple senders.
+Instead we can clone the `chan`, which allows for multiple senders.
 
 ~~~
 # use std::task::spawn;
@@ -246,16 +245,13 @@ let result = port.recv() + port.recv() + port.recv();
 # fn some_expensive_computation(_i: uint) -> int { 42 }
 ~~~
 
-Here we transfer ownership of the channel into a new `SharedChan` value.  Like
-`Chan`, `SharedChan` is a non-copyable, owned type (sometimes also referred to
-as an *affine* or *linear* type). Unlike with `Chan`, though, the programmer
-may duplicate a `SharedChan`, with the `clone()` method.  A cloned
-`SharedChan` produces a new handle to the same channel, allowing multiple
-tasks to send data to a single port.  Between `spawn`, `Chan` and
-`SharedChan`, we have enough tools to implement many useful concurrency
-patterns.
+Cloning a `Chan` produces a new handle to the same channel, allowing multiple
+tasks to send data to a single port. It also upgrades the channel internally in
+order to allow this functionality, which means that channels that are not
+cloned can avoid the overhead required to handle multiple senders. But this
+fact has no bearing on the channel's usage: the upgrade is transparent.
 
-Note that the above `SharedChan` example is somewhat contrived since
+Note that the above cloning example is somewhat contrived since
 you could also simply use three `Chan` pairs, but it serves to
 illustrate the point. For reference, written with multiple streams, it
 might look like the example below.
index 428ff2e576c085981bf4c4679bf182d834ca57ef..6818ae8b12597e0bcea017a71a19935ee77974ae 100644 (file)
@@ -1,3 +1,23 @@
+// Copyright (C) 2013 by Marijn Haverbeke <marijnh@gmail.com> and others
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
 exports.htmlEscape = function(text) {
   var replacements = {"<": "&lt;", ">": "&gt;",
                       "&": "&amp;", "\"": "&quot;"};
@@ -105,7 +125,8 @@ exports.runMode = function(string, modespec, callback) {
       if (string == "\n")
         accum.push("<br>");
       else if (style)
-        accum.push("<span class=\"cm-" + exports.htmlEscape(style) + "\">" + exports.htmlEscape(string) + "</span>");
+        accum.push("<span class=\"cm-" + exports.htmlEscape(style) + "\">" +
+                    exports.htmlEscape(string) + "</span>");
       else
         accum.push(exports.htmlEscape(string));
     }
index 052669be6f5fde2a79914dd8f5d9404d89337606..7f933d6b82ee71eafa0c8f2536e05dc29c69fe43 100644 (file)
@@ -1,3 +1,23 @@
+// Copyright (C) 2013 by Marijn Haverbeke <marijnh@gmail.com> and others
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
 CodeMirror.defineMode("rust", function() {
   var indentUnit = 4, altIndentUnit = 2;
   var valKeywords = {
@@ -422,7 +442,8 @@ CodeMirror.defineMode("rust", function() {
           type = lexical.type, closing = firstChar == type;
       if (type == "stat") return lexical.indented + indentUnit;
       if (lexical.align) return lexical.column + (closing ? 0 : 1);
-      return lexical.indented + (closing ? 0 : (lexical.info == "match" ? altIndentUnit : indentUnit));
+      return lexical.indented +
+        (closing ? 0 : (lexical.info == "match" ? altIndentUnit : indentUnit));
     },
 
     electricChars: "{}"
index 3a1e60ec42311f91da90401ddbdda2fb74ade2cd..850a0bc7db7ebe701e47ecea7c205ddd708ae6ae 100644 (file)
@@ -1,5 +1,15 @@
 #!/usr/local/bin/node
 
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
 /***
  * Pandoc-style markdown preprocessor that drops extra directives
  * included for running doc code, and that optionally, when
index d5181f4cea42946e0ad1de907b47b248ee851dd4..094771897f4f60aa2640387928e095e581e55d02 100644 (file)
@@ -1750,6 +1750,24 @@ closures, but they also own them: that is, no other code can access
 them. Owned closures are used in concurrent code, particularly
 for spawning [tasks][tasks].
 
+Closures can be used to spawn tasks.
+A practical example of this pattern is found when using the `spawn` function,
+which starts a new task.
+
+~~~~
+use std::task::spawn;
+
+// proc is the closure which will be spawned.
+spawn(proc() {
+    debug!("I'm a new task")
+});
+~~~~
+
+> ***Note:*** If you want to see the output of `debug!` statements, you will need to turn on
+> `debug!` logging.  To enable `debug!` logging, set the RUST_LOG environment
+> variable to the name of your crate, which, for a file named `foo.rs`, will be
+> `foo` (e.g., with bash, `export RUST_LOG=foo`).
+
 ## Closure compatibility
 
 Rust closures have a convenient subtyping property: you can pass any kind of
@@ -1771,45 +1789,6 @@ call_twice(function);
 > in small ways. At the moment they can be unsound in some
 > scenarios, particularly with non-copyable types.
 
-## Do syntax
-
-The `do` expression makes it easier to call functions that take procedures
-as arguments.
-
-Consider this function that takes a procedure:
-
-~~~~
-fn call_it(op: proc(v: int)) {
-    op(10)
-}
-~~~~
-
-As a caller, if we use a closure to provide the final operator
-argument, we can write it in a way that has a pleasant, block-like
-structure.
-
-~~~~
-# fn call_it(op: proc(v: int)) { }
-call_it(proc(n) {
-    println!("{}", n);
-});
-~~~~
-
-A practical example of this pattern is found when using the `spawn` function,
-which starts a new task.
-
-~~~~
-use std::task::spawn;
-spawn(proc() {
-    debug!("I'm a new task")
-});
-~~~~
-
-If you want to see the output of `debug!` statements, you will need to turn on
-`debug!` logging.  To enable `debug!` logging, set the RUST_LOG environment
-variable to the name of your crate, which, for a file named `foo.rs`, will be
-`foo` (e.g., with bash, `export RUST_LOG=foo`).
-
 # Methods
 
 Methods are like functions except that they always begin with a special argument,
index 81f086fdabd6121d40071265590d9268b1381ada..6b5220597e9d7ca4fb55129b77fe10fb894cdde6 100755 (executable)
@@ -1,3 +1,14 @@
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+#
+# ignore-tidy-linelength
 #
 # usage : adb_run_wrapper [test dir - where test executables exist] [test executable]
 #
index 3507e6ff788e1dd36fa75d196850dd4fba921e46..3818c0f840139d9aa02576388d682be0debf0fae 100755 (executable)
@@ -1,4 +1,13 @@
 #!/usr/bin/perl -w
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
 
 my $file = $ARGV[0];
 
index 21b1b377afa6339214821852b13606fbe6dd8641..f523b4c93858b36f255e8d663e3d7189c99de7e8 100644 (file)
@@ -1,3 +1,14 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+//
 // This is a helper C program for generating required math constants
 //
 // Should only be required when porting to a different target architecture
index afb98fde7b047282d80a8c3f679bf323bd809f66..770135c3d20e07543afdb096e2aa7c9bfd4fe8c6 100755 (executable)
@@ -1,3 +1,13 @@
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+#
 # This runs the test for emacs rust-mode.
 # It must be possible to find emacs via PATH.
 emacs -batch -l rust-mode.el -l rust-mode-tests.el -f ert-run-tests-batch-and-exit
index d86ed510361cc3fd0a1e048cd8201b46362270be..2bf919d7e2cce794e2378feb49cda5cfd2c31907 100644 (file)
@@ -1,3 +1,13 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
 /*
  * This calculates the platform-variable portion of the libc module.
  * Move code in here only as you discover it is platform-variable.
index 1e599125e89b7d60baa35c61cd70640cdf6f4b20..ec4c60c21ee7005c4c59396945f52213f2ccffa6 100644 (file)
@@ -33,6 +33,8 @@ license4 = """ The Rust Project Developers. See the COPYRIGHT
 """
 
 exceptions = [
+    "doc/lib/codemirror-node.js", # MIT
+    "doc/lib/codemirror-rust.js", # MIT
     "rt/rust_android_dummy.cpp", # BSD, chromium
     "rt/rust_android_dummy.h", # BSD, chromium
     "rt/isaac/randport.cpp", # public domain
index a0785cbad2b58e7b4cd2109343ceb2ed0c2ded0e..e78f231b9d78f850a316f47189029ed5ca89514e 100755 (executable)
@@ -1,4 +1,13 @@
 #!/bin/sh
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
 
 TARG_DIR=$1
 PREFIX=$2
@@ -10,22 +19,22 @@ LIB_PREFIX=lib
 OS=`uname -s`
 case $OS in
     ("Linux"|"FreeBSD")
-       BIN_SUF=
-       LIB_SUF=.so
-       break
-       ;;
+    BIN_SUF=
+    LIB_SUF=.so
+    break
+    ;;
     ("Darwin")
-       BIN_SUF=
-       LIB_SUF=.dylib
-       break
-       ;;
+    BIN_SUF=
+    LIB_SUF=.dylib
+    break
+    ;;
     (*)
-       BIN_SUF=.exe
-       LIB_SUF=.dll
-       LIB_DIR=bin
-       LIB_PREFIX=
-       break
-       ;;
+    BIN_SUF=.exe
+    LIB_SUF=.dll
+    LIB_DIR=bin
+    LIB_PREFIX=
+    break
+    ;;
 esac
 
 if [ -z $PREFIX ]; then
index 4520779e27531004aa98903acf5e1bb7aba32d17..57533ef52245588760a3547581f901ecf08ca7e9 100644 (file)
@@ -1,3 +1,13 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
 #ifndef _FIX_CXXCONFIG_H
 #define _FIX_CXXCONFIG_H 1
 
index 3be26d1cb34baf95b719f28e95e790761ee9008d..b1674f5f5673af924f39ac5087ffc3de3dcbbf89 100644 (file)
@@ -1,3 +1,13 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
 #ifndef _FIX_WINBASE_H
 #define _FIX_WINBASE_H 1
 
index 9fb32ca7ea5c72479e8ee54cac3ea35c2743073e..5096c2f67026c838f6bb24dda7de9e99955bef49 100644 (file)
@@ -1,3 +1,13 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
 #ifndef _FIX_WINSOCK2_H
 #define _FIX_WINSOCK2_H 1
 
index 03c67276049ec32fefa8ac3e633b5109737554c2..511e0c9f74cc35be5a132f6fa8ab3a4c9fb99533 100644 (file)
@@ -85,7 +85,7 @@ syn keyword rustTrait Iterator DoubleEndedIterator RandomAccessIterator Cloneabl
 syn keyword rustTrait OrdIterator MutableDoubleEndedIterator ExactSize
 
 syn keyword rustTrait Algebraic Trigonometric Exponential Hyperbolic
-syn keyword rustTrait Bitwise Bounded Integer Fractional Real RealExt
+syn keyword rustTrait Bitwise Bounded Integer
 syn keyword rustTrait Num NumCast CheckedAdd CheckedSub CheckedMul CheckedDiv
 syn keyword rustTrait Orderable Signed Unsigned Round
 syn keyword rustTrait Primitive Int Float ToStrRadix ToPrimitive FromPrimitive
index 4c6cd4218e7ae9b49fd12da9749dbb0bf2e0c52b..5043cad6f200cca9bb1d174584d0c53bc2f63684 100644 (file)
@@ -59,6 +59,7 @@
 To encode using Encodable :
 
 ```rust
+extern crate extra;
 extern crate serialize;
 use extra::json;
 use std::io;
@@ -98,6 +99,7 @@ fn main() {
 
 
 ```rust
+extern crate extra;
 extern crate collections;
 
 use extra::json;
@@ -125,9 +127,10 @@ fn main() {
 }
 ```
 
-To decode a json string using `Decodable` trait :
+To decode a JSON string using `Decodable` trait :
 
 ```rust
+extern crate extra;
 extern crate serialize;
 use serialize::Decodable;
 
@@ -154,6 +157,7 @@ fn main() {
 using the serialization API, using the derived serialization code.
 
 ```rust
+extern crate extra;
 extern crate serialize;
 use extra::json;
 use serialize::{Encodable, Decodable};
@@ -172,7 +176,7 @@ fn main() {
          {data_int: 1, data_str:~"toto", data_vector:~[2,3,4,5]};
     let encoded_str: ~str = json::Encoder::str_encode(&to_encode_object);
 
-    // To unserialize use the `extra::json::from_str` and `extra::json::Decoder`
+    // To deserialize use the `extra::json::from_str` and `extra::json::Decoder`
 
     let json_object = extra::json::from_str(encoded_str);
     let mut decoder = json::Decoder::new(json_object.unwrap());
@@ -182,10 +186,11 @@ fn main() {
 
 ## Using `ToJson`
 
-This example use the ToJson impl to unserialize the json string.
+This example use the ToJson impl to deserialize the JSON string.
 Example of `ToJson` trait implementation for TestStruct1.
 
 ```rust
+extern crate extra;
 extern crate serialize;
 extern crate collections;
 
@@ -212,13 +217,13 @@ fn to_json( &self ) -> json::Json {
 }
 
 fn main() {
-    // Seralization using our impl of to_json
+    // Serialization using our impl of to_json
 
     let test2: TestStruct1 = TestStruct1 {data_int: 1, data_str:~"toto", data_vector:~[2,3,4,5]};
     let tjson: json::Json = test2.to_json();
     let json_str: ~str = tjson.to_str();
 
-    // Unserialize like before.
+    // Deserialize like before.
 
     let mut decoder = json::Decoder::new(json::from_str(json_str).unwrap());
     // create the final object
index 8d85dc9b6ff2465d25d9f9da2e584b4874723789..fe397c30ab581f5921d3bf36af0a45ccf1edf050 100644 (file)
@@ -1110,7 +1110,7 @@ pub fn ratchet(&self, p: &Path, pct: Option<f64>) -> (MetricDiff, bool) {
 
 // Benchmarking
 
-/// A function that is opaque to the optimiser, to allow benchmarks to
+/// A function that is opaque to the optimizer, to allow benchmarks to
 /// pretend to use outputs to assist in avoiding dead-code
 /// elimination.
 ///
index ad32ba7ba6d1c8ff5dda82bef37ab754a4da3d7b..a966dff000ae0b2a3ae6047652ed012550a55e56 100644 (file)
@@ -86,7 +86,7 @@ pub struct Scheduler {
     /// A flag to tell the scheduler loop it needs to do some stealing
     /// in order to introduce randomness as part of a yield
     steal_for_yield: bool,
-    /// Bookeeping for the number of tasks which are currently running around
+    /// Bookkeeping for the number of tasks which are currently running around
     /// inside this pool of schedulers
     task_state: TaskState,
 
index e9c9f51966c60e0604a1fef365c266b478856837..6d3a156a2b01a9711e0e7a71136ebfe3cbe9bf0b 100644 (file)
@@ -571,7 +571,9 @@ unsafe fn get_list(p: &CString) -> IoResult<~[Path]> {
                         else {
                             let fp_vec = vec::from_buf(
                                 fp_buf, wcslen(fp_buf) as uint);
-                            let fp_str = str::from_utf16(fp_vec);
+                            let fp_trimmed = str::truncate_utf16_at_nul(fp_vec);
+                            let fp_str = str::from_utf16(fp_trimmed)
+                                    .expect("rust_list_dir_wfd_fp_buf returned invalid UTF-16");
                             paths.push(Path::new(fp_str));
                         }
                         more_files = FindNextFileW(find_handle, wfd_ptr as HANDLE);
index 69ef10ac11bea719dfc88c39f89a1084ff6ff2dc..0f9439b3eb5b83f32c77d6edc6caa6ee3eef1368 100644 (file)
 #[path = "timer_win32.rs"]
 pub mod timer;
 
+#[cfg(unix)]
+#[path = "pipe_unix.rs"]
+pub mod pipe;
+
+#[cfg(windows)]
+#[path = "pipe_win32.rs"]
+pub mod pipe;
+
 mod timer_helper;
 
 pub type IoResult<T> = Result<T, IoError>;
@@ -77,6 +85,9 @@ fn translate_error(errno: i32, detail: bool) -> IoError {
     fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
         match errno {
             libc::EOF => (io::EndOfFile, "end of file"),
+            libc::ERROR_NO_DATA => (io::BrokenPipe, "the pipe is being closed"),
+            libc::ERROR_FILE_NOT_FOUND => (io::FileNotFound, "file not found"),
+            libc::ERROR_INVALID_NAME => (io::InvalidInput, "invalid file name"),
             libc::WSAECONNREFUSED => (io::ConnectionRefused, "connection refused"),
             libc::WSAECONNRESET => (io::ConnectionReset, "connection reset"),
             libc::WSAEACCES => (io::PermissionDenied, "permission denied"),
@@ -86,6 +97,7 @@ fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
             libc::WSAECONNABORTED => (io::ConnectionAborted, "connection aborted"),
             libc::WSAEADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
             libc::WSAEADDRINUSE => (io::ConnectionRefused, "address in use"),
+            libc::ERROR_BROKEN_PIPE => (io::BrokenPipe, "the pipe has ended"),
 
             x => {
                 debug!("ignoring {}: {}", x, os::last_os_error());
@@ -108,6 +120,7 @@ fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
             libc::ECONNABORTED => (io::ConnectionAborted, "connection aborted"),
             libc::EADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
             libc::EADDRINUSE => (io::ConnectionRefused, "address in use"),
+            libc::ENOENT => (io::FileNotFound, "no such file or directory"),
 
             // These two constants can have the same value on some systems, but
             // different values on others, so we can't use a match clause
@@ -196,11 +209,11 @@ fn tcp_bind(&mut self, addr: SocketAddr) -> IoResult<~RtioTcpListener> {
     fn udp_bind(&mut self, addr: SocketAddr) -> IoResult<~RtioUdpSocket> {
         net::UdpSocket::bind(addr).map(|u| ~u as ~RtioUdpSocket)
     }
-    fn unix_bind(&mut self, _path: &CString) -> IoResult<~RtioUnixListener> {
-        Err(unimpl())
+    fn unix_bind(&mut self, path: &CString) -> IoResult<~RtioUnixListener> {
+        pipe::UnixListener::bind(path).map(|s| ~s as ~RtioUnixListener)
     }
-    fn unix_connect(&mut self, _path: &CString) -> IoResult<~RtioPipe> {
-        Err(unimpl())
+    fn unix_connect(&mut self, path: &CString) -> IoResult<~RtioPipe> {
+        pipe::UnixStream::connect(path).map(|s| ~s as ~RtioPipe)
     }
     fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
                           hint: Option<ai::Hint>) -> IoResult<~[ai::Info]> {
diff --git a/src/libnative/io/pipe_unix.rs b/src/libnative/io/pipe_unix.rs
new file mode 100644 (file)
index 0000000..a6d75d9
--- /dev/null
@@ -0,0 +1,285 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::c_str::CString;
+use std::cast;
+use std::io;
+use std::libc;
+use std::mem;
+use std::rt::rtio;
+use std::sync::arc::UnsafeArc;
+use std::unstable::intrinsics;
+
+use super::{IoResult, retry};
+use super::file::{keep_going, fd_t};
+
+fn unix_socket(ty: libc::c_int) -> IoResult<fd_t> {
+    match unsafe { libc::socket(libc::AF_UNIX, ty, 0) } {
+        -1 => Err(super::last_error()),
+        fd => Ok(fd)
+    }
+}
+
+fn addr_to_sockaddr_un(addr: &CString) -> IoResult<(libc::sockaddr_storage, uint)> {
+    // the sun_path length is limited to SUN_LEN (with null)
+    assert!(mem::size_of::<libc::sockaddr_storage>() >=
+            mem::size_of::<libc::sockaddr_un>());
+    let mut storage: libc::sockaddr_storage = unsafe { intrinsics::init() };
+    let s: &mut libc::sockaddr_un = unsafe { cast::transmute(&mut storage) };
+
+    let len = addr.len();
+    if len > s.sun_path.len() - 1 {
+        return Err(io::IoError {
+            kind: io::InvalidInput,
+            desc: "path must be smaller than SUN_LEN",
+            detail: None,
+        })
+    }
+    s.sun_family = libc::AF_UNIX as libc::sa_family_t;
+    for (slot, value) in s.sun_path.mut_iter().zip(addr.iter()) {
+        *slot = value;
+    }
+
+    // count the null terminator
+    let len = mem::size_of::<libc::sa_family_t>() + len + 1;
+    return Ok((storage, len));
+}
+
+fn sockaddr_to_unix(storage: &libc::sockaddr_storage,
+                    len: uint) -> IoResult<CString> {
+    match storage.ss_family as libc::c_int {
+        libc::AF_UNIX => {
+            assert!(len as uint <= mem::size_of::<libc::sockaddr_un>());
+            let storage: &libc::sockaddr_un = unsafe {
+                cast::transmute(storage)
+            };
+            unsafe {
+                Ok(CString::new(storage.sun_path.as_ptr(), false).clone())
+            }
+        }
+        _ => Err(io::standard_error(io::InvalidInput))
+    }
+}
+
+struct Inner {
+    fd: fd_t,
+}
+
+impl Drop for Inner {
+    fn drop(&mut self) { unsafe { let _ = libc::close(self.fd); } }
+}
+
+fn connect(addr: &CString, ty: libc::c_int) -> IoResult<Inner> {
+    let (addr, len) = if_ok!(addr_to_sockaddr_un(addr));
+    let inner = Inner { fd: if_ok!(unix_socket(ty)) };
+    let addrp = &addr as *libc::sockaddr_storage;
+    match retry(|| unsafe {
+        libc::connect(inner.fd, addrp as *libc::sockaddr,
+                      len as libc::socklen_t)
+    }) {
+        -1 => Err(super::last_error()),
+        _  => Ok(inner)
+    }
+}
+
+fn bind(addr: &CString, ty: libc::c_int) -> IoResult<Inner> {
+    let (addr, len) = if_ok!(addr_to_sockaddr_un(addr));
+    let inner = Inner { fd: if_ok!(unix_socket(ty)) };
+    let addrp = &addr as *libc::sockaddr_storage;
+    match unsafe {
+        libc::bind(inner.fd, addrp as *libc::sockaddr, len as libc::socklen_t)
+    } {
+        -1 => Err(super::last_error()),
+        _  => Ok(inner)
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Streams
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixStream {
+    priv inner: UnsafeArc<Inner>,
+}
+
+impl UnixStream {
+    pub fn connect(addr: &CString) -> IoResult<UnixStream> {
+        connect(addr, libc::SOCK_STREAM).map(|inner| {
+            UnixStream { inner: UnsafeArc::new(inner) }
+        })
+    }
+
+    fn fd(&self) -> fd_t { unsafe { (*self.inner.get()).fd } }
+}
+
+impl rtio::RtioPipe for UnixStream {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        let ret = retry(|| unsafe {
+            libc::recv(self.fd(),
+                       buf.as_ptr() as *mut libc::c_void,
+                       buf.len() as libc::size_t,
+                       0) as libc::c_int
+        });
+        if ret == 0 {
+            Err(io::standard_error(io::EndOfFile))
+        } else if ret < 0 {
+            Err(super::last_error())
+        } else {
+            Ok(ret as uint)
+        }
+    }
+
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        let ret = keep_going(buf, |buf, len| unsafe {
+            libc::send(self.fd(),
+                       buf as *mut libc::c_void,
+                       len as libc::size_t,
+                       0) as i64
+        });
+        if ret < 0 {
+            Err(super::last_error())
+        } else {
+            Ok(())
+        }
+    }
+
+    fn clone(&self) -> ~rtio::RtioPipe {
+        ~UnixStream { inner: self.inner.clone() } as ~rtio::RtioPipe
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Datagram
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixDatagram {
+    priv inner: UnsafeArc<Inner>,
+}
+
+impl UnixDatagram {
+    pub fn connect(addr: &CString) -> IoResult<UnixDatagram> {
+        connect(addr, libc::SOCK_DGRAM).map(|inner| {
+            UnixDatagram { inner: UnsafeArc::new(inner) }
+        })
+    }
+
+    pub fn bind(addr: &CString) -> IoResult<UnixDatagram> {
+        bind(addr, libc::SOCK_DGRAM).map(|inner| {
+            UnixDatagram { inner: UnsafeArc::new(inner) }
+        })
+    }
+
+    fn fd(&self) -> fd_t { unsafe { (*self.inner.get()).fd } }
+
+    pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, CString)> {
+        let mut storage: libc::sockaddr_storage = unsafe { intrinsics::init() };
+        let storagep = &mut storage as *mut libc::sockaddr_storage;
+        let mut addrlen: libc::socklen_t =
+                mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
+        let ret = retry(|| unsafe {
+            libc::recvfrom(self.fd(),
+                           buf.as_ptr() as *mut libc::c_void,
+                           buf.len() as libc::size_t,
+                           0,
+                           storagep as *mut libc::sockaddr,
+                           &mut addrlen) as libc::c_int
+        });
+        if ret < 0 { return Err(super::last_error()) }
+        sockaddr_to_unix(&storage, addrlen as uint).and_then(|addr| {
+            Ok((ret as uint, addr))
+        })
+    }
+
+    pub fn sendto(&mut self, buf: &[u8], dst: &CString) -> IoResult<()> {
+        let (dst, len) = if_ok!(addr_to_sockaddr_un(dst));
+        let dstp = &dst as *libc::sockaddr_storage;
+        let ret = retry(|| unsafe {
+            libc::sendto(self.fd(),
+                         buf.as_ptr() as *libc::c_void,
+                         buf.len() as libc::size_t,
+                         0,
+                         dstp as *libc::sockaddr,
+                         len as libc::socklen_t) as libc::c_int
+        });
+        match ret {
+            -1 => Err(super::last_error()),
+            n if n as uint != buf.len() => {
+                Err(io::IoError {
+                    kind: io::OtherIoError,
+                    desc: "couldn't send entire packet at once",
+                    detail: None,
+                })
+            }
+            _ => Ok(())
+        }
+    }
+
+    pub fn clone(&mut self) -> UnixDatagram {
+        UnixDatagram { inner: self.inner.clone() }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Listener
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixListener {
+    priv inner: Inner,
+}
+
+impl UnixListener {
+    pub fn bind(addr: &CString) -> IoResult<UnixListener> {
+        bind(addr, libc::SOCK_STREAM).map(|fd| UnixListener { inner: fd })
+    }
+
+    fn fd(&self) -> fd_t { self.inner.fd }
+
+    pub fn native_listen(self, backlog: int) -> IoResult<UnixAcceptor> {
+        match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } {
+            -1 => Err(super::last_error()),
+            _ => Ok(UnixAcceptor { listener: self })
+        }
+    }
+}
+
+impl rtio::RtioUnixListener for UnixListener {
+    fn listen(~self) -> IoResult<~rtio::RtioUnixAcceptor> {
+        self.native_listen(128).map(|a| ~a as ~rtio::RtioUnixAcceptor)
+    }
+}
+
+pub struct UnixAcceptor {
+    priv listener: UnixListener,
+}
+
+impl UnixAcceptor {
+    fn fd(&self) -> fd_t { self.listener.fd() }
+
+    pub fn native_accept(&mut self) -> IoResult<UnixStream> {
+        let mut storage: libc::sockaddr_storage = unsafe { intrinsics::init() };
+        let storagep = &mut storage as *mut libc::sockaddr_storage;
+        let size = mem::size_of::<libc::sockaddr_storage>();
+        let mut size = size as libc::socklen_t;
+        match retry(|| unsafe {
+            libc::accept(self.fd(),
+                         storagep as *mut libc::sockaddr,
+                         &mut size as *mut libc::socklen_t) as libc::c_int
+        }) {
+            -1 => Err(super::last_error()),
+            fd => Ok(UnixStream { inner: UnsafeArc::new(Inner { fd: fd }) })
+        }
+    }
+}
+
+impl rtio::RtioUnixAcceptor for UnixAcceptor {
+    fn accept(&mut self) -> IoResult<~rtio::RtioPipe> {
+        self.native_accept().map(|s| ~s as ~rtio::RtioPipe)
+    }
+}
diff --git a/src/libnative/io/pipe_win32.rs b/src/libnative/io/pipe_win32.rs
new file mode 100644 (file)
index 0000000..83731cc
--- /dev/null
@@ -0,0 +1,492 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Named pipes implementation for windows
+//!
+//! If are unfortunate enough to be reading this code, I would like to first
+//! apologize. This was my first encounter with windows named pipes, and it
+//! didn't exactly turn out very cleanly. If you, too, are new to named pipes,
+//! read on as I'll try to explain some fun things that I ran into.
+//!
+//! # Unix pipes vs Named pipes
+//!
+//! As with everything else, named pipes on windows are pretty different from
+//! unix pipes on unix. On unix, you use one "server pipe" to accept new client
+//! pipes. So long as this server pipe is active, new children pipes can
+//! connect. On windows, you instead have a number of "server pipes", and each
+//! of these server pipes can throughout their lifetime be attached to a client
+//! or not. Once attached to a client, a server pipe may then disconnect at a
+//! later date.
+//!
+//! # Accepting clients
+//!
+//! As with most other I/O interfaces, our Listener/Acceptor/Stream interfaces
+//! are built around the unix flavors. This means that we have one "server
+//! pipe" to which many clients can connect. In order to make this compatible
+//! with the windows model, each connected client consumes ownership of a server
+//! pipe, and then a new server pipe is created for the next client.
+//!
+//! Note that the server pipes attached to clients are never given back to the
+//! listener for recycling. This could possibly be implemented with a channel so
+//! the listener half can re-use server pipes, but for now I err'd on the simple
+//! side of things. Each stream accepted by a listener will destroy the server
+//! pipe after the stream is dropped.
+//!
+//! This model ends up having a small race or two, and you can find more details
+//! on the `native_accept` method.
+//!
+//! # Simultaneous reads and writes
+//!
+//! In testing, I found that two simultaneous writes and two simultaneous reads
+//! on a pipe ended up working out just fine, but problems were encountered when
+//! a read was executed simultaneously with a write. After some googling around,
+//! it sounded like named pipes just weren't built for this kind of interaction,
+//! and the suggested solution was to use overlapped I/O.
+//!
+//! I don't realy know what overlapped I/O is, but my basic understanding after
+//! reading about it is that you have an external Event which is used to signal
+//! I/O completion, passed around in some OVERLAPPED structures. As to what this
+//! is, I'm not exactly sure.
+//!
+//! This problem implies that all named pipes are created with the
+//! FILE_FLAG_OVERLAPPED option. This means that all of their I/O is
+//! asynchronous. Each I/O operation has an associated OVERLAPPED structure, and
+//! inside of this structure is a HANDLE from CreateEvent. After the I/O is
+//! determined to be pending (may complete in the future), the
+//! GetOverlappedResult function is used to block on the event, waiting for the
+//! I/O to finish.
+//!
+//! This scheme ended up working well enough. There were two snags that I ran
+//! into, however:
+//!
+//! * Each UnixStream instance needs its own read/write events to wait on. These
+//!   can't be shared among clones of the same stream because the documentation
+//!   states that it unsets the event when the I/O is started (would possibly
+//!   corrupt other events simultaneously waiting). For convenience's sake,
+//!   these events are lazily initialized.
+//!
+//! * Each server pipe needs to be created with FILE_FLAG_OVERLAPPED in addition
+//!   to all pipes created through `connect`. Notably this means that the
+//!   ConnectNamedPipe function is nonblocking, implying that the Listener needs
+//!   to have yet another event to do the actual blocking.
+//!
+//! # Conclusion
+//!
+//! The conclusion here is that I probably don't know the best way to work with
+//! windows named pipes, but the solution here seems to work well enough to get
+//! the test suite passing (the suite is in libstd), and that's good enough for
+//! me!
+
+use std::c_str::CString;
+use std::libc;
+use std::os::win32::as_utf16_p;
+use std::ptr;
+use std::rt::rtio;
+use std::sync::arc::UnsafeArc;
+use std::unstable::intrinsics;
+
+use super::IoResult;
+
+struct Event(libc::HANDLE);
+
+impl Event {
+    fn new(manual_reset: bool, initial_state: bool) -> IoResult<Event> {
+        let event = unsafe {
+            libc::CreateEventW(ptr::mut_null(),
+                               manual_reset as libc::BOOL,
+                               initial_state as libc::BOOL,
+                               ptr::null())
+        };
+        if event as uint == 0 {
+            Err(super::last_error())
+        } else {
+            Ok(Event(event))
+        }
+    }
+
+    fn handle(&self) -> libc::HANDLE { let Event(handle) = *self; handle }
+}
+
+impl Drop for Event {
+    fn drop(&mut self) {
+        unsafe { let _ = libc::CloseHandle(self.handle()); }
+    }
+}
+
+struct Inner {
+    handle: libc::HANDLE,
+}
+
+impl Drop for Inner {
+    fn drop(&mut self) {
+        unsafe {
+            let _ = libc::FlushFileBuffers(self.handle);
+            let _ = libc::CloseHandle(self.handle);
+        }
+    }
+}
+
+unsafe fn pipe(name: *u16, init: bool) -> libc::HANDLE {
+    libc::CreateNamedPipeW(
+        name,
+        libc::PIPE_ACCESS_DUPLEX |
+            if init {libc::FILE_FLAG_FIRST_PIPE_INSTANCE} else {0} |
+            libc::FILE_FLAG_OVERLAPPED,
+        libc::PIPE_TYPE_BYTE | libc::PIPE_READMODE_BYTE |
+            libc::PIPE_WAIT,
+        libc::PIPE_UNLIMITED_INSTANCES,
+        65536,
+        65536,
+        0,
+        ptr::mut_null()
+    )
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Streams
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixStream {
+    priv inner: UnsafeArc<Inner>,
+    priv write: Option<Event>,
+    priv read: Option<Event>,
+}
+
+impl UnixStream {
+    fn try_connect(p: *u16) -> Option<libc::HANDLE> {
+        // Note that most of this is lifted from the libuv implementation.
+        // The idea is that if we fail to open a pipe in read/write mode
+        // that we try afterwards in just read or just write
+        let mut result = unsafe {
+            libc::CreateFileW(p,
+                libc::GENERIC_READ | libc::GENERIC_WRITE,
+                0,
+                ptr::mut_null(),
+                libc::OPEN_EXISTING,
+                libc::FILE_FLAG_OVERLAPPED,
+                ptr::mut_null())
+        };
+        if result != libc::INVALID_HANDLE_VALUE as libc::HANDLE {
+            return Some(result)
+        }
+
+        let err = unsafe { libc::GetLastError() };
+        if err == libc::ERROR_ACCESS_DENIED as libc::DWORD {
+            result = unsafe {
+                libc::CreateFileW(p,
+                    libc::GENERIC_READ | libc::FILE_WRITE_ATTRIBUTES,
+                    0,
+                    ptr::mut_null(),
+                    libc::OPEN_EXISTING,
+                    libc::FILE_FLAG_OVERLAPPED,
+                    ptr::mut_null())
+            };
+            if result != libc::INVALID_HANDLE_VALUE as libc::HANDLE {
+                return Some(result)
+            }
+        }
+        let err = unsafe { libc::GetLastError() };
+        if err == libc::ERROR_ACCESS_DENIED as libc::DWORD {
+            result = unsafe {
+                libc::CreateFileW(p,
+                    libc::GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES,
+                    0,
+                    ptr::mut_null(),
+                    libc::OPEN_EXISTING,
+                    libc::FILE_FLAG_OVERLAPPED,
+                    ptr::mut_null())
+            };
+            if result != libc::INVALID_HANDLE_VALUE as libc::HANDLE {
+                return Some(result)
+            }
+        }
+        None
+    }
+
+    pub fn connect(addr: &CString) -> IoResult<UnixStream> {
+        as_utf16_p(addr.as_str().unwrap(), |p| {
+            loop {
+                match UnixStream::try_connect(p) {
+                    Some(handle) => {
+                        let inner = Inner { handle: handle };
+                        let mut mode = libc::PIPE_TYPE_BYTE |
+                                       libc::PIPE_READMODE_BYTE |
+                                       libc::PIPE_WAIT;
+                        let ret = unsafe {
+                            libc::SetNamedPipeHandleState(inner.handle,
+                                                          &mut mode,
+                                                          ptr::mut_null(),
+                                                          ptr::mut_null())
+                        };
+                        return if ret == 0 {
+                            Err(super::last_error())
+                        } else {
+                            Ok(UnixStream {
+                                inner: UnsafeArc::new(inner),
+                                read: None,
+                                write: None,
+                            })
+                        }
+                    }
+                    None => {}
+                }
+
+                // On windows, if you fail to connect, you may need to call the
+                // `WaitNamedPipe` function, and this is indicated with an error
+                // code of ERROR_PIPE_BUSY.
+                let code = unsafe { libc::GetLastError() };
+                if code as int != libc::ERROR_PIPE_BUSY as int {
+                    return Err(super::last_error())
+                }
+
+                // An example I found on microsoft's website used 20 seconds,
+                // libuv uses 30 seconds, hence we make the obvious choice of
+                // waiting for 25 seconds.
+                if unsafe { libc::WaitNamedPipeW(p, 25000) } == 0 {
+                    return Err(super::last_error())
+                }
+            }
+        })
+    }
+
+    fn handle(&self) -> libc::HANDLE { unsafe { (*self.inner.get()).handle } }
+}
+
+impl rtio::RtioPipe for UnixStream {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        if self.read.is_none() {
+            self.read = Some(if_ok!(Event::new(true, false)));
+        }
+
+        let mut bytes_read = 0;
+        let mut overlapped: libc::OVERLAPPED = unsafe { intrinsics::init() };
+        overlapped.hEvent = self.read.get_ref().handle();
+
+        let ret = unsafe {
+            libc::ReadFile(self.handle(),
+                           buf.as_ptr() as libc::LPVOID,
+                           buf.len() as libc::DWORD,
+                           &mut bytes_read,
+                           &mut overlapped)
+        };
+        if ret == 0 {
+            let err = unsafe { libc::GetLastError() };
+            if err == libc::ERROR_IO_PENDING as libc::DWORD {
+                let ret = unsafe {
+                    libc::GetOverlappedResult(self.handle(),
+                                              &mut overlapped,
+                                              &mut bytes_read,
+                                              libc::TRUE)
+                };
+                if ret == 0 {
+                    return Err(super::last_error())
+                }
+            } else {
+                return Err(super::last_error())
+            }
+        }
+
+        Ok(bytes_read as uint)
+    }
+
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        if self.write.is_none() {
+            self.write = Some(if_ok!(Event::new(true, false)));
+        }
+
+        let mut offset = 0;
+        let mut overlapped: libc::OVERLAPPED = unsafe { intrinsics::init() };
+        overlapped.hEvent = self.write.get_ref().handle();
+
+        while offset < buf.len() {
+            let mut bytes_written = 0;
+            let ret = unsafe {
+                libc::WriteFile(self.handle(),
+                                buf.slice_from(offset).as_ptr() as libc::LPVOID,
+                                (buf.len() - offset) as libc::DWORD,
+                                &mut bytes_written,
+                                &mut overlapped)
+            };
+            if ret == 0 {
+                let err = unsafe { libc::GetLastError() };
+                if err == libc::ERROR_IO_PENDING as libc::DWORD {
+                    let ret = unsafe {
+                        libc::GetOverlappedResult(self.handle(),
+                                                  &mut overlapped,
+                                                  &mut bytes_written,
+                                                  libc::TRUE)
+                    };
+                    if ret == 0 {
+                        return Err(super::last_error())
+                    }
+                } else {
+                    return Err(super::last_error())
+                }
+            }
+            offset += bytes_written as uint;
+        }
+        Ok(())
+    }
+
+    fn clone(&self) -> ~rtio::RtioPipe {
+        ~UnixStream {
+            inner: self.inner.clone(),
+            read: None,
+            write: None,
+        } as ~rtio::RtioPipe
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Listener
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixListener {
+    priv handle: libc::HANDLE,
+    priv name: CString,
+}
+
+impl UnixListener {
+    pub fn bind(addr: &CString) -> IoResult<UnixListener> {
+        // Although we technically don't need the pipe until much later, we
+        // create the initial handle up front to test the validity of the name
+        // and such.
+        as_utf16_p(addr.as_str().unwrap(), |p| {
+            let ret = unsafe { pipe(p, true) };
+            if ret == libc::INVALID_HANDLE_VALUE as libc::HANDLE {
+                Err(super::last_error())
+            } else {
+                Ok(UnixListener { handle: ret, name: addr.clone() })
+            }
+        })
+    }
+
+    pub fn native_listen(self) -> IoResult<UnixAcceptor> {
+        Ok(UnixAcceptor {
+            listener: self,
+            event: if_ok!(Event::new(true, false)),
+        })
+    }
+}
+
+impl Drop for UnixListener {
+    fn drop(&mut self) {
+        unsafe { let _ = libc::CloseHandle(self.handle); }
+    }
+}
+
+impl rtio::RtioUnixListener for UnixListener {
+    fn listen(~self) -> IoResult<~rtio::RtioUnixAcceptor> {
+        self.native_listen().map(|a| ~a as ~rtio::RtioUnixAcceptor)
+    }
+}
+
+pub struct UnixAcceptor {
+    priv listener: UnixListener,
+    priv event: Event,
+}
+
+impl UnixAcceptor {
+    pub fn native_accept(&mut self) -> IoResult<UnixStream> {
+        // This function has some funky implementation details when working with
+        // unix pipes. On windows, each server named pipe handle can be
+        // connected to a one or zero clients. To the best of my knowledge, a
+        // named server is considered active and present if there exists at
+        // least one server named pipe for it.
+        //
+        // The model of this function is to take the current known server
+        // handle, connect a client to it, and then transfer ownership to the
+        // UnixStream instance. The next time accept() is invoked, it'll need a
+        // different server handle to connect a client to.
+        //
+        // Note that there is a possible race here. Once our server pipe is
+        // handed off to a `UnixStream` object, the stream could be closed,
+        // meaning that there would be no active server pipes, hence even though
+        // we have a valid `UnixAcceptor`, no one can connect to it. For this
+        // reason, we generate the next accept call's server pipe at the end of
+        // this function call.
+        //
+        // This provides us an invariant that we always have at least one server
+        // connection open at a time, meaning that all connects to this acceptor
+        // should succeed while this is active.
+        //
+        // The actual implementation of doing this is a little tricky. Once a
+        // server pipe is created, a client can connect to it at any time. I
+        // assume that which server a client connects to is nondeterministic, so
+        // we also need to guarantee that the only server able to be connected
+        // to is the one that we're calling ConnectNamedPipe on. This means that
+        // we have to create the second server pipe *after* we've already
+        // accepted a connection. In order to at least somewhat gracefully
+        // handle errors, this means that if the second server pipe creation
+        // fails that we disconnect the connected client and then just keep
+        // using the original server pipe.
+        let handle = self.listener.handle;
+
+        // Once we've got a "server handle", we need to wait for a client to
+        // connect. The ConnectNamedPipe function will block this thread until
+        // someone on the other end connects. This function can "fail" if a
+        // client connects after we created the pipe but before we got down
+        // here. Thanks windows.
+        let mut overlapped: libc::OVERLAPPED = unsafe { intrinsics::init() };
+        overlapped.hEvent = self.event.handle();
+        if unsafe { libc::ConnectNamedPipe(handle, &mut overlapped) == 0 } {
+            let mut err = unsafe { libc::GetLastError() };
+            if err == libc::ERROR_IO_PENDING as libc::DWORD {
+                let ret = unsafe {
+                    let mut transfer = 0;
+                    libc::GetOverlappedResult(handle,
+                                              &mut overlapped,
+                                              &mut transfer,
+                                              libc::TRUE)
+                };
+                if ret == 0 {
+                    err = unsafe { libc::GetLastError() };
+                } else {
+                    // we succeeded, bypass the check below
+                    err = libc::ERROR_PIPE_CONNECTED as libc::DWORD;
+                }
+            }
+            if err != libc::ERROR_PIPE_CONNECTED as libc::DWORD {
+                return Err(super::last_error())
+            }
+        }
+
+        // Now that we've got a connected client to our handle, we need to
+        // create a second server pipe. If this fails, we disconnect the
+        // connected client and return an error (see comments above).
+        let new_handle = as_utf16_p(self.listener.name.as_str().unwrap(), |p| {
+            unsafe { pipe(p, false) }
+        });
+        if new_handle == libc::INVALID_HANDLE_VALUE as libc::HANDLE {
+            let ret = Err(super::last_error());
+            // If our disconnection fails, then there's not really a whole lot
+            // that we can do, so fail the task.
+            let err = unsafe { libc::DisconnectNamedPipe(handle) };
+            assert!(err != 0);
+            return ret;
+        } else {
+            self.listener.handle = new_handle;
+        }
+
+        // Transfer ownership of our handle into this stream
+        Ok(UnixStream {
+            inner: UnsafeArc::new(Inner { handle: handle }),
+            read: None,
+            write: None,
+        })
+    }
+}
+
+impl rtio::RtioUnixAcceptor for UnixAcceptor {
+    fn accept(&mut self) -> IoResult<~rtio::RtioPipe> {
+        self.native_accept().map(|s| ~s as ~rtio::RtioPipe)
+    }
+}
+
index a832834b8e4d613971149b9e0c1ee3e90bfa98e6..3755b2e43af1b4ea0362e28b625c2be928fb2485 100644 (file)
@@ -77,7 +77,7 @@ pub fn inv(&self) -> Cmplx<T> {
     }
 }
 
-impl<T: Clone + Real> Cmplx<T> {
+impl<T: Clone + Float> Cmplx<T> {
     /// Calculate |self|
     #[inline]
     pub fn norm(&self) -> T {
@@ -85,7 +85,7 @@ pub fn norm(&self) -> T {
     }
 }
 
-impl<T: Clone + Real> Cmplx<T> {
+impl<T: Clone + Float> Cmplx<T> {
     /// Calculate the principal Arg of self.
     #[inline]
     pub fn arg(&self) -> T {
@@ -192,7 +192,7 @@ mod test {
     #[allow(non_uppercase_statics)];
 
     use super::{Complex64, Cmplx};
-    use std::num::{Zero,One,Real};
+    use std::num::{Zero,One,Float};
 
     pub static _0_0i : Complex64 = Cmplx { re: 0.0, im: 0.0 };
     pub static _1_0i : Complex64 = Cmplx { re: 1.0, im: 0.0 };
@@ -270,9 +270,9 @@ fn test(c: Complex64, arg: f64) {
             assert!((c.arg() - arg).abs() < 1.0e-6)
         }
         test(_1_0i, 0.0);
-        test(_1_1i, 0.25 * Real::pi());
-        test(_neg1_1i, 0.75 * Real::pi());
-        test(_05_05i, 0.25 * Real::pi());
+        test(_1_1i, 0.25 * Float::pi());
+        test(_neg1_1i, 0.75 * Float::pi());
+        test(_05_05i, 0.25 * Float::pi());
     }
 
     #[test]
index 18aef17b9eb77031b3ff9cdfe745b236c98b1643..406c3026614dc8b84b4a21825a4c3073ec61e4cf 100644 (file)
@@ -173,6 +173,7 @@ fn add_archive(&mut self, archive: &Path, name: &str,
             if_ok!(fs::rename(file, &new_filename));
             inputs.push(new_filename);
         }
+        if inputs.len() == 0 { return Ok(()) }
 
         // Finally, add all the renamed files to this archive
         let mut args = ~[&self.dst];
index 8c5654d3fcecb0b8a8aec4c018ce7bcb8e7341ac..1ab5ebc6d61004b90f260cab2b39fd48432e610f 100644 (file)
 /// reexporting a public struct doesn't inline the doc).
 pub type PublicItems = HashSet<ast::NodeId>;
 
+/// Result of a checking operation - None => no errors were found. Some => an
+/// error and contains the span and message for reporting that error and
+/// optionally the same for a note about the error.
+type CheckResult = Option<(Span, ~str, Option<(Span, ~str)>)>;
+
 ////////////////////////////////////////////////////////////////////////////////
 /// The parent visitor, used to determine what's the parent of what (node-wise)
 ////////////////////////////////////////////////////////////////////////////////
@@ -510,40 +515,50 @@ fn private_accessible(&self, id: ast::NodeId) -> bool {
         }
     }
 
-    /// Guarantee that a particular definition is public, possibly emitting an
-    /// error message if it's not.
+    fn report_error(&self, result: CheckResult) -> bool {
+        match result {
+            None => true,
+            Some((span, msg, note)) => {
+                self.tcx.sess.span_err(span, msg);
+                match note {
+                    Some((span, msg)) => self.tcx.sess.span_note(span, msg),
+                    None => {},
+                }
+                false
+            },
+        }
+    }
+
+    /// Guarantee that a particular definition is public. Returns a CheckResult
+    /// which contains any errors found. These can be reported using `report_error`.
+    /// If the result is `None`, no errors were found.
     fn ensure_public(&self, span: Span, to_check: ast::DefId,
-                     source_did: Option<ast::DefId>, msg: &str) -> bool {
+                     source_did: Option<ast::DefId>, msg: &str) -> CheckResult {
         match self.def_privacy(to_check) {
-            ExternallyDenied => {
-                self.tcx.sess.span_err(span, format!("{} is private", msg))
-            }
+            ExternallyDenied => Some((span, format!("{} is private", msg), None)),
             DisallowedBy(id) => {
-                if id == source_did.unwrap_or(to_check).node {
-                    self.tcx.sess.span_err(span, format!("{} is private", msg));
-                    return false;
+                let (err_span, err_msg) = if id == source_did.unwrap_or(to_check).node {
+                    return Some((span, format!("{} is private", msg), None));
                 } else {
-                    self.tcx.sess.span_err(span, format!("{} is inaccessible",
-                                                         msg));
-                }
+                    (span, format!("{} is inaccessible", msg))
+                };
                 match self.tcx.map.find(id) {
                     Some(ast_map::NodeItem(item)) => {
                         let desc = match item.node {
                             ast::ItemMod(..) => "module",
                             ast::ItemTrait(..) => "trait",
-                            _ => return false,
+                            _ => return Some((err_span, err_msg, None)),
                         };
                         let msg = format!("{} `{}` is private",
                                           desc,
                                           token::get_ident(item.ident));
-                        self.tcx.sess.span_note(span, msg);
-                    }
-                    Some(..) | None => {}
+                        Some((err_span, err_msg, Some((span, msg))))
+                    },
+                    _ => Some((err_span, err_msg, None)),
                 }
-            }
-            Allowable => return true
+            },
+            Allowable => None,
         }
-        return false;
     }
 
     // Checks that a field is in scope.
@@ -613,34 +628,99 @@ fn check_static_method(&mut self, span: Span, method_id: ast::DefId,
         let method_id = ty::method(self.tcx, method_id).provided_source
                                                        .unwrap_or(method_id);
 
-        self.ensure_public(span,
-                           method_id,
-                           None,
-                           format!("method `{}`", token::get_ident(name)));
+        let string = token::get_ident(name);
+        self.report_error(self.ensure_public(span,
+                                             method_id,
+                                             None,
+                                             format!("method `{}`", string)));
     }
 
     // Checks that a path is in scope.
     fn check_path(&mut self, span: Span, path_id: ast::NodeId, path: &ast::Path) {
         debug!("privacy - path {}", self.nodestr(path_id));
         let def_map = self.tcx.def_map.borrow();
-        let def = def_map.get().get_copy(&path_id);
+        let orig_def = def_map.get().get_copy(&path_id);
         let ck = |tyname: &str| {
-            let origdid = def_id_of_def(def);
+            let ck_public = |def: ast::DefId| {
+                let name = token::get_ident(path.segments
+                                                .last()
+                                                .unwrap()
+                                                .identifier);
+                let origdid = def_id_of_def(orig_def);
+                self.ensure_public(span,
+                                   def,
+                                   Some(origdid),
+                                   format!("{} `{}`",
+                                           tyname,
+                                           name))
+            };
+
             match *self.last_private_map.get(&path_id) {
-                resolve::AllPublic => {},
-                resolve::DependsOn(def) => {
-                    let name = token::get_ident(path.segments
-                                                    .last()
-                                                    .unwrap()
-                                                    .identifier);
-                    self.ensure_public(span,
-                                       def,
-                                       Some(origdid),
-                                       format!("{} `{}`",
-                                               tyname, name));
-                }
+                resolve::LastMod(resolve::AllPublic) => {},
+                resolve::LastMod(resolve::DependsOn(def)) => {
+                    self.report_error(ck_public(def));
+                },
+                resolve::LastImport{value_priv: value_priv,
+                                    value_used: check_value,
+                                    type_priv: type_priv,
+                                    type_used: check_type} => {
+                    // This dance with found_error is because we don't want to report
+                    // a privacy error twice for the same directive.
+                    let found_error = match (type_priv, check_type) {
+                        (Some(resolve::DependsOn(def)), resolve::Used) => {
+                            !self.report_error(ck_public(def))
+                        },
+                        _ => false,
+                    };
+                    if !found_error {
+                        match (value_priv, check_value) {
+                            (Some(resolve::DependsOn(def)), resolve::Used) => {
+                                self.report_error(ck_public(def));
+                            },
+                            _ => {},
+                        }
+                    }
+                    // If an import is not used in either namespace, we still want to check
+                    // that it could be legal. Therefore we check in both namespaces and only
+                    // report an error if both would be illegal. We only report one error,
+                    // even if it is illegal to import from both namespaces.
+                    match (value_priv, check_value, type_priv, check_type) {
+                        (Some(p), resolve::Unused, None, _) |
+                        (None, _, Some(p), resolve::Unused) => {
+                            let p = match p {
+                                resolve::AllPublic => None,
+                                resolve::DependsOn(def) => ck_public(def),
+                            };
+                            if p.is_some() {
+                                self.report_error(p);
+                            }
+                        },
+                        (Some(v), resolve::Unused, Some(t), resolve::Unused) => {
+                            let v = match v {
+                                resolve::AllPublic => None,
+                                resolve::DependsOn(def) => ck_public(def),
+                            };
+                            let t = match t {
+                                resolve::AllPublic => None,
+                                resolve::DependsOn(def) => ck_public(def),
+                            };
+                            match (v, t) {
+                                (Some(_), Some(t)) => {
+                                    self.report_error(Some(t));
+                                },
+                                _ => {},
+                            }
+                        },
+                        _ => {},
+                    }
+                },
             }
         };
+        // FIXME(#12334) Imports can refer to definitions in both the type and
+        // value namespaces. The privacy information is aware of this, but the
+        // def map is not. Therefore the names we work out below will not always
+        // be accurate and we can get slightly wonky error messages (but type
+        // checking is always correct).
         let def_map = self.tcx.def_map.borrow();
         match def_map.get().get_copy(&path_id) {
             ast::DefStaticMethod(..) => ck("static method"),
@@ -668,7 +748,7 @@ fn check_method(&mut self, span: Span, origin: &method_origin,
             // is whether the trait itself is accessible or not.
             method_param(method_param { trait_id: trait_id, .. }) |
             method_object(method_object { trait_id: trait_id, .. }) => {
-                self.ensure_public(span, trait_id, None, "source trait");
+                self.report_error(self.ensure_public(span, trait_id, None, "source trait"));
             }
         }
     }
index 1d28c781ea0c80019d0326a85eb36e181a9ff55a..327001fcd27036ec38635f96adb9d8a80537e850 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
 use driver::session::Session;
 use metadata::csearch;
 use metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
@@ -64,14 +63,34 @@ pub struct Export2 {
 pub type LastPrivateMap = HashMap<NodeId, LastPrivate>;
 
 pub enum LastPrivate {
+    LastMod(PrivateDep),
+    // `use` directives (imports) can refer to two separate definitions in the
+    // type and value namespaces. We record here the last private node for each
+    // and whether the import is in fact used for each.
+    // If the Option<PrivateDep> fields are None, it means there is no defintion
+    // in that namespace.
+    LastImport{value_priv: Option<PrivateDep>,
+               value_used: ImportUse,
+               type_priv: Option<PrivateDep>,
+               type_used: ImportUse},
+}
+
+pub enum PrivateDep {
     AllPublic,
     DependsOn(DefId),
 }
 
+// How an import is used.
+#[deriving(Eq)]
+pub enum ImportUse {
+    Unused,       // The import is not used.
+    Used,         // The import is used.
+}
+
 impl LastPrivate {
     fn or(self, other: LastPrivate) -> LastPrivate {
         match (self, other) {
-            (me, AllPublic) => me,
+            (me, LastMod(AllPublic)) => me,
             (_, other) => other,
         }
     }
@@ -84,7 +103,7 @@ enum PatternBindingMode {
     ArgumentIrrefutableMode,
 }
 
-#[deriving(Eq)]
+#[deriving(Eq, IterBytes)]
 enum Namespace {
     TypeNS,
     ValueNS
@@ -869,7 +888,7 @@ struct Resolver {
     // so as to avoid printing duplicate errors
     emit_errors: bool,
 
-    used_imports: HashSet<NodeId>,
+    used_imports: HashSet<(NodeId, Namespace)>,
 }
 
 struct BuildReducedGraphVisitor<'a> {
@@ -904,7 +923,7 @@ fn visit_block(&mut self, block: &Block, context: ReducedGraphParent) {
 
 }
 
-struct UnusedImportCheckVisitor<'a> { resolver: &'a Resolver }
+struct UnusedImportCheckVisitor<'a> { resolver: &'a mut Resolver }
 
 impl<'a> Visitor<()> for UnusedImportCheckVisitor<'a> {
     fn visit_view_item(&mut self, vi: &ViewItem, _: ()) {
@@ -2152,7 +2171,7 @@ fn resolve_import_for_module(&mut self,
         // First, resolve the module path for the directive, if necessary.
         let container = if module_path.len() == 0 {
             // Use the crate root.
-            Some((self.graph_root.get_module(), AllPublic))
+            Some((self.graph_root.get_module(), LastMod(AllPublic)))
         } else {
             match self.resolve_module_path(module_,
                                            *module_path,
@@ -2257,6 +2276,12 @@ fn resolve_single_import(&mut self,
                directive.id,
                lp);
 
+        let lp = match lp {
+            LastMod(lp) => lp,
+            LastImport{..} => self.session.span_bug(directive.span,
+                                                    "Not expecting Import here, must be LastMod"),
+        };
+
         // We need to resolve both namespaces for this to succeed.
         //
 
@@ -2287,7 +2312,8 @@ fn resolve_single_import(&mut self,
 
         // Unless we managed to find a result in both namespaces (unlikely),
         // search imports as well.
-        let mut used_reexport = false;
+        let mut value_used_reexport = false;
+        let mut type_used_reexport = false;
         match (value_result, type_result) {
             (BoundResult(..), BoundResult(..)) => {} // Continue.
             _ => {
@@ -2342,7 +2368,7 @@ fn get_binding(this: &mut Resolver,
                                 }
                                 Some(target) => {
                                     let id = import_resolution.id(namespace);
-                                    this.used_imports.insert(id);
+                                    this.used_imports.insert((id, namespace));
                                     return BoundResult(target.target_module,
                                                        target.bindings);
                                 }
@@ -2354,12 +2380,12 @@ fn get_binding(this: &mut Resolver,
                         if value_result.is_unknown() {
                             value_result = get_binding(self, *import_resolution,
                                                        ValueNS);
-                            used_reexport = import_resolution.is_public.get();
+                            value_used_reexport = import_resolution.is_public.get();
                         }
                         if type_result.is_unknown() {
                             type_result = get_binding(self, *import_resolution,
                                                       TypeNS);
-                            used_reexport = import_resolution.is_public.get();
+                            type_used_reexport = import_resolution.is_public.get();
                         }
 
                     }
@@ -2375,7 +2401,8 @@ fn get_binding(this: &mut Resolver,
 
         // If we didn't find a result in the type namespace, search the
         // external modules.
-        let mut used_public = false;
+        let mut value_used_public = false;
+        let mut type_used_public = false;
         match type_result {
             BoundResult(..) => {}
             _ => {
@@ -2393,7 +2420,7 @@ fn get_binding(this: &mut Resolver,
                                 module);
                         type_result = BoundResult(containing_module,
                                                   name_bindings);
-                        used_public = true;
+                        type_used_public = true;
                     }
                 }
             }
@@ -2412,7 +2439,7 @@ fn get_binding(this: &mut Resolver,
                 import_resolution.value_target.set(
                     Some(Target::new(target_module, name_bindings)));
                 import_resolution.value_id.set(directive.id);
-                used_public = name_bindings.defined_in_public_namespace(ValueNS);
+                value_used_public = name_bindings.defined_in_public_namespace(ValueNS);
             }
             UnboundResult => { /* Continue. */ }
             UnknownResult => {
@@ -2426,7 +2453,7 @@ fn get_binding(this: &mut Resolver,
                 import_resolution.type_target.set(
                     Some(Target::new(target_module, name_bindings)));
                 import_resolution.type_id.set(directive.id);
-                used_public = name_bindings.defined_in_public_namespace(TypeNS);
+                type_used_public = name_bindings.defined_in_public_namespace(TypeNS);
             }
             UnboundResult => { /* Continue. */ }
             UnknownResult => {
@@ -2443,7 +2470,8 @@ fn get_binding(this: &mut Resolver,
             self.resolve_error(directive.span, msg);
             return Failed;
         }
-        let used_public = used_reexport || used_public;
+        let value_used_public = value_used_reexport || value_used_public;
+        let type_used_public = type_used_reexport || type_used_public;
 
         assert!(import_resolution.outstanding_references.get() >= 1);
         import_resolution.outstanding_references.set(
@@ -2452,28 +2480,33 @@ fn get_binding(this: &mut Resolver,
         // record what this import resolves to for later uses in documentation,
         // this may resolve to either a value or a type, but for documentation
         // purposes it's good enough to just favor one over the other.
-        match import_resolution.value_target.get() {
+        let value_private = match import_resolution.value_target.get() {
             Some(target) => {
                 let def = target.bindings.def_for_namespace(ValueNS).unwrap();
                 let mut def_map = self.def_map.borrow_mut();
                 def_map.get().insert(directive.id, def);
                 let did = def_id_of_def(def);
-                self.last_private.insert(directive.id,
-                    if used_public {lp} else {DependsOn(did)});
-            }
-            None => {}
-        }
-        match import_resolution.type_target.get() {
+                if value_used_public {Some(lp)} else {Some(DependsOn(did))}
+            },
+            // AllPublic here and below is a dummy value, it should never be used because
+            // _exists is false.
+            None => None,
+        };
+        let type_private = match import_resolution.type_target.get() {
             Some(target) => {
                 let def = target.bindings.def_for_namespace(TypeNS).unwrap();
                 let mut def_map = self.def_map.borrow_mut();
                 def_map.get().insert(directive.id, def);
                 let did = def_id_of_def(def);
-                self.last_private.insert(directive.id,
-                    if used_public {lp} else {DependsOn(did)});
-            }
-            None => {}
-        }
+                if type_used_public {Some(lp)} else {Some(DependsOn(did))}
+            },
+            None => None,
+        };
+
+        self.last_private.insert(directive.id, LastImport{value_priv: value_private,
+                                                          value_used: Used,
+                                                          type_priv: type_private,
+                                                          type_used: Used});
 
         debug!("(resolving single import) successfully resolved import");
         return Success(());
@@ -2732,7 +2765,7 @@ fn resolve_module_path_from_root(&mut self,
                                                                    .get() {
                                                     Some(did) => {
                                                         closest_private =
-                                                            DependsOn(did);
+                                                            LastMod(DependsOn(did));
                                                     }
                                                     None => {}
                                                 }
@@ -2817,7 +2850,7 @@ fn resolve_module_path(&mut self,
                         // resolution process at index zero.
                         search_module = self.graph_root.get_module();
                         start_index = 0;
-                        last_private = AllPublic;
+                        last_private = LastMod(AllPublic);
                     }
                     UseLexicalScope => {
                         // This is not a crate-relative path. We resolve the
@@ -2839,7 +2872,7 @@ fn resolve_module_path(&mut self,
                             Success(containing_module) => {
                                 search_module = containing_module;
                                 start_index = 1;
-                                last_private = AllPublic;
+                                last_private = LastMod(AllPublic);
                             }
                         }
                     }
@@ -2848,9 +2881,9 @@ fn resolve_module_path(&mut self,
             Success(PrefixFound(containing_module, index)) => {
                 search_module = containing_module;
                 start_index = index;
-                last_private = DependsOn(containing_module.def_id
-                                                          .get()
-                                                          .unwrap());
+                last_private = LastMod(DependsOn(containing_module.def_id
+                                                                  .get()
+                                                                  .unwrap()));
             }
         }
 
@@ -2914,7 +2947,7 @@ fn resolve_item_in_lexical_scope(&mut self,
                     Some(target) => {
                         debug!("(resolving item in lexical scope) using \
                                 import resolution");
-                        self.used_imports.insert(import_resolution.id(namespace));
+                        self.used_imports.insert((import_resolution.id(namespace), namespace));
                         return Success((target, false));
                     }
                 }
@@ -3199,7 +3232,7 @@ fn resolve_name_in_module(&mut self,
                     Some(target) => {
                         debug!("(resolving name in module) resolved to \
                                 import");
-                        self.used_imports.insert(import_resolution.id(namespace));
+                        self.used_imports.insert((import_resolution.id(namespace), namespace));
                         return Success((target, true));
                     }
                 }
@@ -3808,7 +3841,7 @@ fn with_type_parameter_rib(&mut self,
                     // Associate this type parameter with
                     // the item that bound it
                     self.record_def(type_parameter.id,
-                                    (DefTyParamBinder(node_id), AllPublic));
+                                    (DefTyParamBinder(node_id), LastMod(AllPublic)));
                     // plain insert (no renaming)
                     let mut bindings = function_type_rib.bindings
                                                         .borrow_mut();
@@ -4269,7 +4302,7 @@ fn resolve_type(&mut self, ty: &Ty) {
 
                         Some(&primitive_type) => {
                             result_def =
-                                Some((DefPrimTy(primitive_type), AllPublic));
+                                Some((DefPrimTy(primitive_type), LastMod(AllPublic)));
 
                             if path.segments
                                    .iter()
@@ -4438,7 +4471,7 @@ struct in scope",
                             // will be able to distinguish variants from
                             // locals in patterns.
 
-                            self.record_def(pattern.id, (def, AllPublic));
+                            self.record_def(pattern.id, (def, LastMod(AllPublic)));
 
                             // Add the binding to the local ribs, if it
                             // doesn't already exist in the bindings list. (We
@@ -4632,10 +4665,10 @@ fn resolve_bare_identifier_pattern(&mut self, name: Ident)
                         // the lookup happened only within the current module.
                         match def.def {
                             def @ DefVariant(..) | def @ DefStruct(..) => {
-                                return FoundStructOrEnumVariant(def, AllPublic);
+                                return FoundStructOrEnumVariant(def, LastMod(AllPublic));
                             }
                             def @ DefStatic(_, false) => {
-                                return FoundConst(def, AllPublic);
+                                return FoundConst(def, LastMod(AllPublic));
                             }
                             _ => {
                                 return BareIdentifierPatternUnresolved;
@@ -4711,7 +4744,7 @@ fn resolve_identifier(&mut self,
                                                       namespace,
                                                       span) {
                 Some(def) => {
-                    return Some((def, AllPublic));
+                    return Some((def, LastMod(AllPublic)));
                 }
                 None => {
                     // Continue.
@@ -4741,8 +4774,8 @@ fn resolve_definition_of_name_in_module(&mut self,
                             // Found it. Stop the search here.
                             let p = child_name_bindings.defined_in_public_namespace(
                                             namespace);
-                            let lp = if p {AllPublic} else {
-                                DependsOn(def_id_of_def(def))
+                            let lp = if p {LastMod(AllPublic)} else {
+                                LastMod(DependsOn(def_id_of_def(def)))
                             };
                             return ChildNameDefinition(def, lp);
                         }
@@ -4764,8 +4797,8 @@ fn resolve_definition_of_name_in_module(&mut self,
                             Some(def) => {
                                 // Found it.
                                 let id = import_resolution.id(namespace);
-                                self.used_imports.insert(id);
-                                return ImportNameDefinition(def, AllPublic);
+                                self.used_imports.insert((id, namespace));
+                                return ImportNameDefinition(def, LastMod(AllPublic));
                             }
                             None => {
                                 // This can happen with external impls, due to
@@ -4792,8 +4825,8 @@ fn resolve_definition_of_name_in_module(&mut self,
                     match module.def_id.get() {
                         None => {} // Continue.
                         Some(def_id) => {
-                            let lp = if module.is_public {AllPublic} else {
-                                DependsOn(def_id)
+                            let lp = if module.is_public {LastMod(AllPublic)} else {
+                                LastMod(DependsOn(def_id))
                             };
                             return ChildNameDefinition(DefMod(def_id), lp);
                         }
@@ -4887,7 +4920,7 @@ fn resolve_crate_relative_path(&mut self,
                                                  0,
                                                  path.span,
                                                  PathSearch,
-                                                 AllPublic) {
+                                                 LastMod(AllPublic)) {
             Failed => {
                 let msg = format!("use of undeclared module `::{}`",
                                   self.idents_to_str(module_path_idents));
@@ -4983,7 +5016,7 @@ fn resolve_item_by_identifier_in_lexical_scope(&mut self,
                         // This lookup is "all public" because it only searched
                         // for one identifier in the current module (couldn't
                         // have passed through reexports or anything like that.
-                        return Some((def, AllPublic));
+                        return Some((def, LastMod(AllPublic)));
                     }
                 }
             }
@@ -5194,8 +5227,8 @@ fn resolve_expr(&mut self, expr: &Expr) {
                                               format!("use of undeclared label `{}`",
                                                    token::get_name(label))),
                     Some(DlDef(def @ DefLabel(_))) => {
-                        // FIXME: is AllPublic correct?
-                        self.record_def(expr.id, (def, AllPublic))
+                        // Since this def is a label, it is never read.
+                        self.record_def(expr.id, (def, LastMod(AllPublic)))
                     }
                     Some(_) => {
                         self.session.span_bug(expr.span,
@@ -5353,7 +5386,7 @@ fn search_for_traits_containing_method(&mut self, name: Ident) -> ~[DefId] {
                     };
                     if candidate_traits.contains(&did) {
                         self.add_trait_info(&mut found_traits, did, name);
-                        self.used_imports.insert(import.type_id.get());
+                        self.used_imports.insert((import.type_id.get(), TypeNS));
                     }
                 }
 
@@ -5395,6 +5428,8 @@ fn add_fixed_trait_for_expr(&mut self,
     fn record_def(&mut self, node_id: NodeId, (def, lp): (Def, LastPrivate)) {
         debug!("(recording def) recording {:?} for {:?}, last private {:?}",
                 def, node_id, lp);
+        assert!(match lp {LastImport{..} => false, _ => true},
+                "Import should only be used for `use` directives");
         self.last_private.insert(node_id, lp);
         let mut def_map = self.def_map.borrow_mut();
         def_map.get().insert_or_update_with(node_id, def, |_, old_value| {
@@ -5426,16 +5461,17 @@ fn enforce_default_binding_mode(&mut self,
     //
     // Unused import checking
     //
-    // Although this is a lint pass, it lives in here because it depends on
-    // resolve data structures.
+    // Although this is mostly a lint pass, it lives in here because it depends on
+    // resolve data structures and because it finalises the privacy information for
+    // `use` directives.
     //
 
-    fn check_for_unused_imports(&self, krate: &ast::Crate) {
+    fn check_for_unused_imports(&mut self, krate: &ast::Crate) {
         let mut visitor = UnusedImportCheckVisitor{ resolver: self };
         visit::walk_crate(&mut visitor, krate, ());
     }
 
-    fn check_for_item_unused_imports(&self, vi: &ViewItem) {
+    fn check_for_item_unused_imports(&mut self, vi: &ViewItem) {
         // Ignore is_public import statements because there's no way to be sure
         // whether they're used or not. Also ignore imports with a dummy span
         // because this means that they were generated in some fashion by the
@@ -5448,29 +5484,73 @@ fn check_for_item_unused_imports(&self, vi: &ViewItem) {
             ViewItemUse(ref path) => {
                 for p in path.iter() {
                     match p.node {
-                        ViewPathSimple(_, _, id) | ViewPathGlob(_, id) => {
-                            if !self.used_imports.contains(&id) {
-                                self.session.add_lint(UnusedImports,
-                                                      id, p.span,
-                                                      ~"unused import");
-                            }
-                        }
-
+                        ViewPathSimple(_, _, id) => self.finalize_import(id, p.span),
                         ViewPathList(_, ref list, _) => {
                             for i in list.iter() {
-                                if !self.used_imports.contains(&i.node.id) {
-                                    self.session.add_lint(UnusedImports,
-                                                          i.node.id, i.span,
-                                                          ~"unused import");
-                                }
+                                self.finalize_import(i.node.id, i.span);
                             }
-                        }
+                        },
+                        ViewPathGlob(_, id) => {
+                            if !self.used_imports.contains(&(id, TypeNS)) &&
+                               !self.used_imports.contains(&(id, ValueNS)) {
+                                self.session.add_lint(UnusedImports, id, p.span, ~"unused import");
+                            }
+                        },
                     }
                 }
             }
         }
     }
 
+    // We have information about whether `use` (import) directives are actually used now.
+    // If an import is not used at all, we signal a lint error. If an import is only used
+    // for a single namespace, we remove the other namespace from the recorded privacy
+    // information. That means in privacy.rs, we will only check imports and namespaces
+    // which are used. In particular, this means that if an import could name either a
+    // public or private item, we will check the correct thing, dependent on how the import
+    // is used.
+    fn finalize_import(&mut self, id: NodeId, span: Span) {
+        debug!("finalizing import uses for {}", self.session.codemap.span_to_snippet(span));
+
+        if !self.used_imports.contains(&(id, TypeNS)) &&
+           !self.used_imports.contains(&(id, ValueNS)) {
+            self.session.add_lint(UnusedImports, id, span, ~"unused import");
+        }
+
+        let (v_priv, t_priv) = match self.last_private.find(&id) {
+            Some(&LastImport{value_priv: v,
+                             value_used: _,
+                             type_priv: t,
+                             type_used: _}) => (v, t),
+            Some(_) => fail!("We should only have LastImport for `use` directives"),
+            _ => return,
+        };
+
+        let mut v_used = if self.used_imports.contains(&(id, ValueNS)) {
+            Used
+        } else {
+            Unused
+        };
+        let t_used = if self.used_imports.contains(&(id, TypeNS)) {
+            Used
+        } else {
+            Unused
+        };
+
+        match (v_priv, t_priv) {
+            // Since some items may be both in the value _and_ type namespaces (e.g., structs)
+            // we might have two LastPrivates pointing at the same thing. There is no point
+            // checking both, so lets not check the value one.
+            (Some(DependsOn(def_v)), Some(DependsOn(def_t))) if def_v == def_t => v_used = Unused,
+            _ => {},
+        }
+
+        self.last_private.insert(id, LastImport{value_priv: v_priv,
+                                                value_used: v_used,
+                                                type_priv: t_priv,
+                                                type_used: t_used});
+    }
+
     //
     // Diagnostics
     //
index 0dcbfe491c312e3eb121bc4c0f23bfb660a875ec..5bc3d047c9fdfcabd9a230aa4f6414c275cd4daf 100644 (file)
@@ -4142,7 +4142,7 @@ pub fn enum_variants(cx: ctxt, id: ast::DefId) -> @~[@VariantInfo] {
                                           .span_err(e.span,
                                                     format!("expected \
                                                              constant: {}",
-                                                            (*err)));
+                                                            *err));
                                     }
                                 },
                                 None => {}
index 8117e816493853e41d412dc874cfb0882a50fb9f..d33afd8fd035c4ffc40959d18de4e584d4846252 100644 (file)
@@ -687,8 +687,8 @@ pub fn check_pointer_pat(pcx: &pat_ctxt,
                              e, actual)})},
                 Some(expected),
                 format!("{} pattern", match pointer_kind {
-                    Send => "a ~-box",
-                    Borrowed => "an &-pointer"
+                    Send => "a `~`-box",
+                    Borrowed => "an `&`-pointer"
                 }),
                 None);
             fcx.write_error(pat_id);
index 21877bda1c10be3e57636a4b37aeec29520f704b..9c43af4f13aa7bac7c6ff554608c95863a925fac 100644 (file)
@@ -1303,7 +1303,7 @@ fn report_static_candidate(&self, idx: uint, did: DefId) {
         self.tcx().sess.span_note(
             span,
             format!("candidate \\#{} is `{}`",
-                 (idx+1u),
+                 idx+1u,
                  ty::item_path_str(self.tcx(), did)));
     }
 
@@ -1311,7 +1311,7 @@ fn report_param_candidate(&self, idx: uint, did: DefId) {
         self.tcx().sess.span_note(
             self.expr.span,
             format!("candidate \\#{} derives from the bound `{}`",
-                 (idx+1u),
+                 idx+1u,
                  ty::item_path_str(self.tcx(), did)));
     }
 
@@ -1320,7 +1320,7 @@ fn report_trait_candidate(&self, idx: uint, did: DefId) {
             self.expr.span,
             format!("candidate \\#{} derives from the type of the receiver, \
                   which is the trait `{}`",
-                 (idx+1u),
+                 idx+1u,
                  ty::item_path_str(self.tcx(), did)));
     }
 
index 177eba5aa1b1ad0f9a116f6a03a8a2ef9deeea4c..eab34b560605184ee1e427ed4cf3f995298a9923 100644 (file)
@@ -3551,7 +3551,7 @@ fn do_check(ccx: @CrateCtxt,
                             ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
                         }
                         Err(ref err) => {
-                            ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", (*err)));
+                            ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", *err));
                         }
                     }
                 },
index dd270885b0e1bd1a1c23fa9036d0eb1a02f93b33..4608fa649b58785630a60a0864b8f22064dd770c 100644 (file)
@@ -49,11 +49,11 @@ pub fn note_and_explain_region(cx: ctxt,
       (ref str, Some(span)) => {
         cx.sess.span_note(
             span,
-            format!("{}{}{}", prefix, (*str), suffix));
+            format!("{}{}{}", prefix, *str, suffix));
       }
       (ref str, None) => {
         cx.sess.note(
-            format!("{}{}{}", prefix, (*str), suffix));
+            format!("{}{}{}", prefix, *str, suffix));
       }
     }
 }
index 22f9d2f9843b9ce0efb0a12c06ee90982f38930c..586323358c241234494ea2560f6e0954957208e5 100644 (file)
@@ -25,7 +25,6 @@
 use rustc::metadata::decoder;
 
 use std;
-use std::hashmap::HashMap;
 
 use doctree;
 use visit_ast;
@@ -68,7 +67,7 @@ fn clean(&self) -> ~[U] {
 pub struct Crate {
     name: ~str,
     module: Option<Item>,
-    externs: HashMap<ast::CrateNum, ExternalCrate>,
+    externs: ~[(ast::CrateNum, ExternalCrate)],
 }
 
 impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
@@ -76,9 +75,9 @@ fn clean(&self) -> Crate {
         use syntax::attr::find_crateid;
         let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
 
-        let mut externs = HashMap::new();
+        let mut externs = ~[];
         cx.sess.cstore.iter_crate_data(|n, meta| {
-            externs.insert(n, meta.clean());
+            externs.push((n, meta.clean()));
         });
 
         Crate {
@@ -181,6 +180,7 @@ pub enum ItemEnum {
     VariantItem(Variant),
     ForeignFunctionItem(Function),
     ForeignStaticItem(Static),
+    MacroItem(Macro),
 }
 
 #[deriving(Clone, Encodable, Decodable)]
@@ -206,7 +206,8 @@ fn clean(&self) -> Item {
                        self.fns.clean(), self.foreigns.clean().concat_vec(),
                        self.mods.clean(), self.typedefs.clean(),
                        self.statics.clean(), self.traits.clean(),
-                       self.impls.clean(), self.view_items.clean()].concat_vec()
+                       self.impls.clean(), self.view_items.clean(),
+                       self.macros.clean()].concat_vec()
             })
         }
     }
@@ -1263,3 +1264,23 @@ fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
         None => None
     }
 }
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Macro {
+    source: ~str,
+}
+
+impl Clean<Item> for doctree::Macro {
+    fn clean(&self) -> Item {
+        Item {
+            name: Some(self.name.clean()),
+            attrs: self.attrs.clean(),
+            source: self.where.clean(),
+            visibility: ast::Public.clean(),
+            id: self.id,
+            inner: MacroItem(Macro {
+                source: self.where.to_src(),
+            }),
+        }
+    }
+}
index f1bd3a62e01623ad7f8107ac4e75b88cbd18b269..03186c16733a52273061767e5ca381466f994891 100644 (file)
@@ -32,6 +32,7 @@ pub struct Module {
     impls: ~[Impl],
     foreigns: ~[ast::ForeignMod],
     view_items: ~[ast::ViewItem],
+    macros: ~[Macro],
 }
 
 impl Module {
@@ -52,6 +53,7 @@ pub fn new(name: Option<Ident>) -> Module {
             impls      : ~[],
             view_items : ~[],
             foreigns   : ~[],
+            macros     : ~[],
         }
     }
 }
@@ -157,6 +159,13 @@ pub struct Impl {
     id: ast::NodeId,
 }
 
+pub struct Macro {
+    name: Ident,
+    id: ast::NodeId,
+    attrs: ~[ast::Attribute],
+    where: Span,
+}
+
 pub fn struct_type_from_def(sd: &ast::StructDef) -> StructType {
     if sd.ctor_id.is_some() {
         // We are in a tuple-struct
index 11f801550856b019ee98b2d7b09b1ae4432726ff..649d5f592c5c58869b2a00dd6c11b77f959c4fe1 100644 (file)
@@ -157,6 +157,7 @@ pub struct Cache {
     priv parent_stack: ~[ast::NodeId],
     priv search_index: ~[IndexItem],
     priv privmod: bool,
+    priv public_items: HashSet<ast::NodeId>,
 }
 
 /// Helper struct to render all source code to HTML pages
@@ -231,18 +232,23 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
     }
 
     // Crawl the crate to build various caches used for the output
-    let mut cache = Cache {
-        impls: HashMap::new(),
-        typarams: HashMap::new(),
-        paths: HashMap::new(),
-        traits: HashMap::new(),
-        implementors: HashMap::new(),
-        stack: ~[],
-        parent_stack: ~[],
-        search_index: ~[],
-        extern_locations: HashMap::new(),
-        privmod: false,
-    };
+    let mut cache = local_data::get(::analysiskey, |analysis| {
+        let public_items = analysis.map(|a| a.public_items.clone());
+        let public_items = public_items.unwrap_or(HashSet::new());
+        Cache {
+            impls: HashMap::new(),
+            typarams: HashMap::new(),
+            paths: HashMap::new(),
+            traits: HashMap::new(),
+            implementors: HashMap::new(),
+            stack: ~[],
+            parent_stack: ~[],
+            search_index: ~[],
+            extern_locations: HashMap::new(),
+            privmod: false,
+            public_items: public_items,
+        }
+    });
     cache.stack.push(krate.name.clone());
     krate = cache.fold_crate(krate);
 
@@ -305,7 +311,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
         krate = folder.fold_crate(krate);
     }
 
-    for (&n, e) in krate.externs.iter() {
+    for &(n, ref e) in krate.externs.iter() {
         cache.extern_locations.insert(n, extern_location(e, &cx.dst));
     }
 
@@ -565,8 +571,24 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
             clean::StructItem(..) | clean::EnumItem(..) |
             clean::TypedefItem(..) | clean::TraitItem(..) |
             clean::FunctionItem(..) | clean::ModuleItem(..) |
-            clean::ForeignFunctionItem(..) | clean::VariantItem(..) => {
-                self.paths.insert(item.id, (self.stack.clone(), shortty(&item)));
+            clean::ForeignFunctionItem(..) => {
+                // Reexported items mean that the same id can show up twice in
+                // the rustdoc ast that we're looking at. We know, however, that
+                // a reexported item doesn't show up in the `public_items` map,
+                // so we can skip inserting into the paths map if there was
+                // already an entry present and we're not a public item.
+                if !self.paths.contains_key(&item.id) ||
+                   self.public_items.contains(&item.id) {
+                    self.paths.insert(item.id,
+                                      (self.stack.clone(), shortty(&item)));
+                }
+            }
+            // link variants to their parent enum because pages aren't emitted
+            // for each variant
+            clean::VariantItem(..) => {
+                let mut stack = self.stack.clone();
+                stack.pop();
+                self.paths.insert(item.id, (stack, "enum"));
             }
             _ => {}
         }
@@ -791,6 +813,7 @@ fn shortty(item: &clean::Item) -> &'static str {
         clean::VariantItem(..)         => "variant",
         clean::ForeignFunctionItem(..) => "ffi",
         clean::ForeignStaticItem(..)   => "ffs",
+        clean::MacroItem(..)           => "macro",
     }
 }
 
@@ -869,6 +892,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
             clean::StructItem(ref s) => item_struct(fmt.buf, self.item, s),
             clean::EnumItem(ref e) => item_enum(fmt.buf, self.item, e),
             clean::TypedefItem(ref t) => item_typedef(fmt.buf, self.item, t),
+            clean::MacroItem(ref m) => item_macro(fmt.buf, self.item, m),
             _ => Ok(())
         }
     }
@@ -937,6 +961,8 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
             (_, &clean::ViewItemItem(..)) => Greater,
             (&clean::ModuleItem(..), _) => Less,
             (_, &clean::ModuleItem(..)) => Greater,
+            (&clean::MacroItem(..), _) => Less,
+            (_, &clean::MacroItem(..)) => Greater,
             (&clean::StructItem(..), _) => Less,
             (_, &clean::StructItem(..)) => Greater,
             (&clean::EnumItem(..), _) => Less,
@@ -987,6 +1013,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
                 clean::VariantItem(..)         => "Variants",
                 clean::ForeignFunctionItem(..) => "Foreign Functions",
                 clean::ForeignStaticItem(..)   => "Foreign Statics",
+                clean::MacroItem(..)           => "Macros",
             }));
         }
 
@@ -1099,7 +1126,7 @@ fn item_trait(w: &mut Writer, it: &clean::Item,
         if_ok!(write!(w, "\\{\n"));
         for m in required.iter() {
             if_ok!(write!(w, "    "));
-            if_ok!(render_method(w, m.item(), true));
+            if_ok!(render_method(w, m.item()));
             if_ok!(write!(w, ";\n"));
         }
         if required.len() > 0 && provided.len() > 0 {
@@ -1107,7 +1134,7 @@ fn item_trait(w: &mut Writer, it: &clean::Item,
         }
         for m in provided.iter() {
             if_ok!(write!(w, "    "));
-            if_ok!(render_method(w, m.item(), true));
+            if_ok!(render_method(w, m.item()));
             if_ok!(write!(w, " \\{ ... \\}\n"));
         }
         if_ok!(write!(w, "\\}"));
@@ -1121,7 +1148,7 @@ fn meth(w: &mut Writer, m: &clean::TraitMethod) -> fmt::Result {
         if_ok!(write!(w, "<h3 id='{}.{}' class='method'><code>",
                       shortty(m.item()),
                       *m.item().name.get_ref()));
-        if_ok!(render_method(w, m.item(), false));
+        if_ok!(render_method(w, m.item()));
         if_ok!(write!(w, "</code></h3>"));
         if_ok!(document(w, m.item()));
         Ok(())
@@ -1176,16 +1203,12 @@ fn meth(w: &mut Writer, m: &clean::TraitMethod) -> fmt::Result {
     })
 }
 
-fn render_method(w: &mut Writer, meth: &clean::Item,
-                 withlink: bool) -> fmt::Result {
+fn render_method(w: &mut Writer, meth: &clean::Item) -> fmt::Result {
     fn fun(w: &mut Writer, it: &clean::Item, purity: ast::Purity,
-           g: &clean::Generics, selfty: &clean::SelfTy, d: &clean::FnDecl,
-           withlink: bool) -> fmt::Result {
-        write!(w, "{}fn {withlink, select,
-                            true{<a href='\\#{ty}.{name}'
-                                    class='fnname'>{name}</a>}
-                            other{<span class='fnname'>{name}</span>}
-                        }{generics}{decl}",
+           g: &clean::Generics, selfty: &clean::SelfTy,
+           d: &clean::FnDecl) -> fmt::Result {
+        write!(w, "{}fn <a href='\\#{ty}.{name}' class='fnname'>{name}</a>\
+                   {generics}{decl}",
                match purity {
                    ast::UnsafeFn => "unsafe ",
                    _ => "",
@@ -1193,15 +1216,14 @@ fn fun(w: &mut Writer, it: &clean::Item, purity: ast::Purity,
                ty = shortty(it),
                name = it.name.get_ref().as_slice(),
                generics = *g,
-               decl = Method(selfty, d),
-               withlink = if withlink {"true"} else {"false"})
+               decl = Method(selfty, d))
     }
     match meth.inner {
         clean::TyMethodItem(ref m) => {
-            fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink)
+            fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl)
         }
         clean::MethodItem(ref m) => {
-            fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink)
+            fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl)
         }
         _ => unreachable!()
     }
@@ -1432,7 +1454,7 @@ fn render_impl(w: &mut Writer, i: &clean::Impl,
     fn docmeth(w: &mut Writer, item: &clean::Item) -> io::IoResult<bool> {
         if_ok!(write!(w, "<h4 id='method.{}' class='method'><code>",
                       *item.name.get_ref()));
-        if_ok!(render_method(w, item, false));
+        if_ok!(render_method(w, item));
         if_ok!(write!(w, "</code></h4>\n"));
         match item.doc_value() {
             Some(s) => {
@@ -1609,3 +1631,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         Ok(())
     }
 }
+
+fn item_macro(w: &mut Writer, it: &clean::Item,
+              t: &clean::Macro) -> fmt::Result {
+    if_ok!(write!(w, "<pre class='macro'>{}</pre>", t.source));
+    document(w, it)
+}
index e0f4a9c167d2a541d0599d42ea2817ec38be34c8..8e1876bad036804fc286fffb6ecace8dd8077494 100644 (file)
@@ -301,3 +301,5 @@ a {
 .stability.Stable { border-color: #AEC516; color: #7c8b10; }
 .stability.Frozen { border-color: #009431; color: #007726; }
 .stability.Locked { border-color: #0084B6; color: #00668c; }
+
+:target { background: #FDFFD3; }
index 2c4d553a39f6477fa26243dcd75436a9a02075f5..4194f5e47293628610fe8eaf809c49e42c96ece5 100644 (file)
@@ -344,7 +344,7 @@ fn json_output(krate: clean::Crate, res: ~[plugins::PluginJson],
     };
     let crate_json = match json::from_str(crate_json_str) {
         Ok(j) => j,
-        Err(_) => fail!("Rust generated JSON is invalid??")
+        Err(e) => fail!("Rust generated JSON is invalid: {:?}", e)
     };
 
     json.insert(~"crate", crate_json);
index 6ebaf6eece82d4b27a0ae056ee4d89a3eb2af702..2b8f01cfac8cacd57c1ff204310e0e698193b3d0 100644 (file)
@@ -150,8 +150,8 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             }
             clean::ImplItem(..) => {}
 
-            // tymethods have no control over privacy
-            clean::TyMethodItem(..) => {}
+            // tymethods/macros have no control over privacy
+            clean::MacroItem(..) | clean::TyMethodItem(..) => {}
         }
 
         let fastreturn = match i.inner {
index 8b127b6079d9075f18110f41238e780dc3a3fc6d..db4842b79a04bbd23a7599d1f2b2755460418adf 100644 (file)
@@ -144,11 +144,13 @@ fn maketest(s: &str, cratename: &str) -> ~str {
 #[deny(warnings)];
 #[allow(unused_variable, dead_assignment, unused_mut, attribute_usage, dead_code)];
 ";
-    if s.contains("extra") {
-        prog.push_str("extern crate extra;\n");
-    }
-    if s.contains(cratename) {
-        prog.push_str(format!("extern crate {};\n", cratename));
+    if !s.contains("extern crate") {
+        if s.contains("extra") {
+            prog.push_str("extern crate extra;\n");
+        }
+        if s.contains(cratename) {
+            prog.push_str(format!("extern crate {};\n", cratename));
+        }
     }
     if s.contains("fn main") {
         prog.push_str(s);
index 5bf1aa3e91a6d4f67dc55ec7bf02b17f54366079..ef02d7345672154bb0951df944e363deb06db2da 100644 (file)
@@ -280,7 +280,14 @@ pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) {
             ast::ItemForeignMod(ref fm) => {
                 om.foreigns.push(fm.clone());
             }
-            _ => (),
+            ast::ItemMac(ref _m) => {
+                om.macros.push(Macro {
+                    id: item.id,
+                    attrs: item.attrs.clone(),
+                    name: item.ident,
+                    where: item.span,
+                })
+            }
         }
     }
 }
index 46de70c1746e7024d27ac6d99003a1c89c8729db..aae86b18512bf5224e3eec2c09df77d8e279b55e 100644 (file)
@@ -168,6 +168,18 @@ fn smoke_test() {
 
     #[test] #[should_fail]
     fn smoke_fail() {
+        // By default, the test harness is capturing our stderr output through a
+        // channel. This means that when we start failing and "print" our error
+        // message, we could be switched to running on another test. The
+        // IdleWatcher assumes that we're already running on the same task, so
+        // it can cause serious problems and internal race conditions.
+        //
+        // To fix this bug, we just set our stderr to a null writer which will
+        // never reschedule us, so we're guaranteed to stay on the same
+        // task/event loop.
+        use std::io;
+        drop(io::stdio::set_stderr(~io::util::NullWriter));
+
         let (mut idle, _chan) = mk(1);
         idle.resume();
         fail!();
index e44f65296f5cc7e96cc6d2a4bafeeff174fdc531..adbe4491886d45c6104ce8c12f0e901579ed75c4 100644 (file)
@@ -433,7 +433,6 @@ fn local_loop() -> &'static mut uvio::UvIoFactory {
 #[cfg(test)]
 mod test {
     use std::cast::transmute;
-    use std::ptr;
     use std::unstable::run_in_bare_thread;
 
     use super::{slice_to_uv_buf, Loop};
index e41fa60aa42e6c4c79d02ae8fa9329c37cf6e857..02066086ad7735d316c6d69b48fccd4198bcf932 100644 (file)
@@ -144,7 +144,7 @@ pub fn handle<'a, T: Send>(&'a self, port: &'a Port<T>) -> Handle<'a, T> {
         }
     }
 
-    /// Waits for an event on this port set. The returned valus is *not* and
+    /// Waits for an event on this port set. The returned value is *not* an
     /// index, but rather an id. This id can be queried against any active
     /// `Handle` structures (each one has an `id` method). The handle with
     /// the matching `id` will have some sort of event available on it. The
index c99fe587fc0d0b5b9e7e43fa8cdc40727023bc06..2eadf9a7f4fc69de81b22b493a5f39aba1fdc44a 100644 (file)
@@ -1287,7 +1287,7 @@ fn incoming<'r>(&'r mut self) -> IncomingConnections<'r, Self> {
 ///
 /// Since connection attempts can continue forever, this iterator always returns
 /// `Some`. The `Some` contains the `IoResult` representing whether the
-/// connection attempt was succesful.  A successful connection will be wrapped
+/// connection attempt was successful.  A successful connection will be wrapped
 /// in `Ok`. A failed connection is represented as an `Err`.
 pub struct IncomingConnections<'a, A> {
     priv inc: &'a mut A,
index cf109167089d40ca6581ce6bdade64927d65dfc0..436156a12190b4d0fc96ed1aeb34ad9d8885f7fa 100644 (file)
@@ -14,5 +14,5 @@
 pub mod tcp;
 pub mod udp;
 pub mod ip;
-#[cfg(unix)]
+// FIXME(#12093) - this should not be called unix
 pub mod unix;
index 23c01aa635444d4675789c0e1b9e72730ed3e0f2..a1f3cbbe326434b6ee826f3237b0bc824143774d 100644 (file)
@@ -134,7 +134,7 @@ mod tests {
     use io::*;
     use io::test::*;
 
-    fn smalltest(server: proc(UnixStream), client: proc(UnixStream)) {
+    pub fn smalltest(server: proc(UnixStream), client: proc(UnixStream)) {
         let path1 = next_test_unix();
         let path2 = path1.clone();
         let (port, chan) = Chan::new();
@@ -149,25 +149,32 @@ fn smalltest(server: proc(UnixStream), client: proc(UnixStream)) {
         server(acceptor.accept().unwrap());
     }
 
-    #[test]
-    fn bind_error() {
-        match UnixListener::bind(&("path/to/nowhere")) {
+    iotest!(fn bind_error() {
+        let path = "path/to/nowhere";
+        match UnixListener::bind(&path) {
             Ok(..) => fail!(),
-            Err(e) => assert_eq!(e.kind, PermissionDenied),
+            Err(e) => {
+                assert!(e.kind == PermissionDenied || e.kind == FileNotFound ||
+                        e.kind == InvalidInput);
+            }
         }
-    }
-
-    #[test]
-    fn connect_error() {
-        match UnixStream::connect(&("path/to/nowhere")) {
+    })
+
+    iotest!(fn connect_error() {
+        let path = if cfg!(windows) {
+            r"\\.\pipe\this_should_not_exist_ever"
+        } else {
+            "path/to/nowhere"
+        };
+        match UnixStream::connect(&path) {
             Ok(..) => fail!(),
-            Err(e) => assert_eq!(e.kind,
-                        if cfg!(windows) {OtherIoError} else {FileNotFound})
+            Err(e) => {
+                assert!(e.kind == FileNotFound || e.kind == OtherIoError);
+            }
         }
-    }
+    })
 
-    #[test]
-    fn smoke() {
+    iotest!(fn smoke() {
         smalltest(proc(mut server) {
             let mut buf = [0];
             server.read(buf).unwrap();
@@ -175,10 +182,9 @@ fn smoke() {
         }, proc(mut client) {
             client.write([99]).unwrap();
         })
-    }
+    })
 
-    #[test]
-    fn read_eof() {
+    iotest!(fn read_eof() {
         smalltest(proc(mut server) {
             let mut buf = [0];
             assert!(server.read(buf).is_err());
@@ -186,17 +192,18 @@ fn read_eof() {
         }, proc(_client) {
             // drop the client
         })
-    }
+    })
 
-    #[test]
-    fn write_begone() {
+    iotest!(fn write_begone() {
         smalltest(proc(mut server) {
             let buf = [0];
             loop {
                 match server.write(buf) {
                     Ok(..) => {}
                     Err(e) => {
-                        assert!(e.kind == BrokenPipe || e.kind == NotConnected,
+                        assert!(e.kind == BrokenPipe ||
+                                e.kind == NotConnected ||
+                                e.kind == ConnectionReset,
                                 "unknown error {:?}", e);
                         break;
                     }
@@ -205,10 +212,9 @@ fn write_begone() {
         }, proc(_client) {
             // drop the client
         })
-    }
+    })
 
-    #[test]
-    fn accept_lots() {
+    iotest!(fn accept_lots() {
         let times = 10;
         let path1 = next_test_unix();
         let path2 = path1.clone();
@@ -218,38 +224,49 @@ fn accept_lots() {
             port.recv();
             for _ in range(0, times) {
                 let mut stream = UnixStream::connect(&path2);
-                stream.write([100]).unwrap();
+                match stream.write([100]) {
+                    Ok(..) => {}
+                    Err(e) => fail!("failed write: {}", e)
+                }
             }
         });
 
-        let mut acceptor = UnixListener::bind(&path1).listen();
+        let mut acceptor = match UnixListener::bind(&path1).listen() {
+            Ok(a) => a,
+            Err(e) => fail!("failed listen: {}", e),
+        };
         chan.send(());
         for _ in range(0, times) {
             let mut client = acceptor.accept();
             let mut buf = [0];
-            client.read(buf).unwrap();
+            match client.read(buf) {
+                Ok(..) => {}
+                Err(e) => fail!("failed read/accept: {}", e),
+            }
             assert_eq!(buf[0], 100);
         }
-    }
+    })
 
-    #[test]
-    fn path_exists() {
+    #[cfg(unix)]
+    iotest!(fn path_exists() {
         let path = next_test_unix();
         let _acceptor = UnixListener::bind(&path).listen();
         assert!(path.exists());
-    }
+    })
 
-    #[test]
-    fn unix_clone_smoke() {
+    iotest!(fn unix_clone_smoke() {
         let addr = next_test_unix();
         let mut acceptor = UnixListener::bind(&addr).listen();
 
         spawn(proc() {
             let mut s = UnixStream::connect(&addr);
             let mut buf = [0, 0];
+            debug!("client reading");
             assert_eq!(s.read(buf), Ok(1));
             assert_eq!(buf[0], 1);
+            debug!("client writing");
             s.write([2]).unwrap();
+            debug!("client dropping");
         });
 
         let mut s1 = acceptor.accept().unwrap();
@@ -260,17 +277,20 @@ fn unix_clone_smoke() {
         spawn(proc() {
             let mut s2 = s2;
             p1.recv();
+            debug!("writer writing");
             s2.write([1]).unwrap();
+            debug!("writer done");
             c2.send(());
         });
         c1.send(());
         let mut buf = [0, 0];
+        debug!("reader reading");
         assert_eq!(s1.read(buf), Ok(1));
+        debug!("reader done");
         p2.recv();
-    }
+    })
 
-    #[test]
-    fn unix_clone_two_read() {
+    iotest!(fn unix_clone_two_read() {
         let addr = next_test_unix();
         let mut acceptor = UnixListener::bind(&addr).listen();
         let (p, c) = Chan::new();
@@ -300,10 +320,9 @@ fn unix_clone_two_read() {
         c.send(());
 
         p.recv();
-    }
+    })
 
-    #[test]
-    fn unix_clone_two_write() {
+    iotest!(fn unix_clone_two_write() {
         let addr = next_test_unix();
         let mut acceptor = UnixListener::bind(&addr).listen();
 
@@ -326,5 +345,5 @@ fn unix_clone_two_write() {
         s1.write([2]).unwrap();
 
         p.recv();
-    }
+    })
 }
index e5a89fc42e1521227a2029373d607ffdcafae7ef..7516a3ddf543eb1a802e3d5f10d7e603aff647a6 100644 (file)
@@ -883,7 +883,7 @@ pub trait OrdIterator<A> {
     /// ```
     fn min(&mut self) -> Option<A>;
 
-    /// `min_max` finds the mininum and maximum elements in the iterator.
+    /// `min_max` finds the minimum and maximum elements in the iterator.
     ///
     /// The return type `MinMaxResult` is an enum of three variants:
     /// - `NoElements` if the iterator is empty.
index 4452482b7e8ceee4c6c3ced6498d055de746c9ee..d3ddd9ae78380dfad3298b40b75b0f40329b7a3a 100644 (file)
@@ -77,7 +77,7 @@
 #[cfg(test)] pub use ops = realstd::ops;
 #[cfg(test)] pub use cmp = realstd::cmp;
 
-mod macros;
+pub mod macros;
 
 mod rtdeps;
 
index 7dc4c692f6319559909fb340fa295afd0f06d239..73bf4a1e69a88593ba59b11735a5abbb2b452918 100644 (file)
@@ -319,6 +319,10 @@ pub struct addrinfo {
                     ai_canonname: *c_char,
                     ai_next: *addrinfo
                 }
+                pub struct sockaddr_un {
+                    sun_family: sa_family_t,
+                    sun_path: [c_char, ..108]
+                }
             }
         }
 
@@ -691,6 +695,11 @@ pub struct addrinfo {
                     ai_addr: *sockaddr,
                     ai_next: *addrinfo
                 }
+                pub struct sockaddr_un {
+                    sun_len: u8,
+                    sun_family: sa_family_t,
+                    sun_path: [c_char, ..104]
+                }
             }
         }
 
@@ -884,6 +893,10 @@ pub struct addrinfo {
                     ai_addr: *sockaddr,
                     ai_next: *addrinfo
                 }
+                pub struct sockaddr_un {
+                    sun_family: sa_family_t,
+                    sun_path: [c_char, ..108]
+                }
             }
         }
 
@@ -1252,6 +1265,11 @@ pub struct addrinfo {
                     ai_addr: *sockaddr,
                     ai_next: *addrinfo
                 }
+                pub struct sockaddr_un {
+                    sun_len: u8,
+                    sun_family: sa_family_t,
+                    sun_path: [c_char, ..104]
+                }
             }
         }
 
@@ -1605,11 +1623,19 @@ pub mod extra {
             pub static O_NOINHERIT: c_int = 128;
 
             pub static ERROR_SUCCESS : c_int = 0;
+            pub static ERROR_FILE_NOT_FOUND: c_int = 2;
+            pub static ERROR_ACCESS_DENIED: c_int = 5;
             pub static ERROR_INVALID_HANDLE : c_int = 6;
+            pub static ERROR_BROKEN_PIPE: c_int = 109;
             pub static ERROR_DISK_FULL : c_int = 112;
             pub static ERROR_INSUFFICIENT_BUFFER : c_int = 122;
+            pub static ERROR_INVALID_NAME : c_int = 123;
             pub static ERROR_ALREADY_EXISTS : c_int = 183;
+            pub static ERROR_PIPE_BUSY: c_int = 231;
+            pub static ERROR_NO_DATA: c_int = 232;
             pub static ERROR_INVALID_ADDRESS : c_int = 487;
+            pub static ERROR_PIPE_CONNECTED: c_int = 535;
+            pub static ERROR_IO_PENDING: c_int = 997;
             pub static ERROR_FILE_INVALID : c_int = 1006;
             pub static INVALID_HANDLE_VALUE : c_int = -1;
 
@@ -1748,6 +1774,7 @@ pub mod extra {
             pub static FILE_FLAG_SESSION_AWARE: DWORD = 0x00800000;
             pub static FILE_FLAG_SEQUENTIAL_SCAN: DWORD = 0x08000000;
             pub static FILE_FLAG_WRITE_THROUGH: DWORD = 0x80000000;
+            pub static FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000;
 
             pub static FILE_NAME_NORMALIZED: DWORD = 0x0;
             pub static FILE_NAME_OPENED: DWORD = 0x8;
@@ -1761,6 +1788,8 @@ pub mod extra {
             pub static GENERIC_WRITE: DWORD = 0x40000000;
             pub static GENERIC_EXECUTE: DWORD = 0x20000000;
             pub static GENERIC_ALL: DWORD = 0x10000000;
+            pub static FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100;
+            pub static FILE_READ_ATTRIBUTES: DWORD = 0x00000080;
 
             pub static FILE_BEGIN: DWORD = 0;
             pub static FILE_CURRENT: DWORD = 1;
@@ -1772,6 +1801,19 @@ pub mod extra {
 
             pub static DETACHED_PROCESS: DWORD = 0x00000008;
             pub static CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200;
+
+            pub static PIPE_ACCESS_DUPLEX: DWORD = 0x00000003;
+            pub static PIPE_ACCESS_INBOUND: DWORD = 0x00000001;
+            pub static PIPE_ACCESS_OUTBOUND: DWORD = 0x00000002;
+            pub static PIPE_TYPE_BYTE: DWORD = 0x00000000;
+            pub static PIPE_TYPE_MESSAGE: DWORD = 0x00000004;
+            pub static PIPE_READMODE_BYTE: DWORD = 0x00000000;
+            pub static PIPE_READMODE_MESSAGE: DWORD = 0x00000002;
+            pub static PIPE_WAIT: DWORD = 0x00000000;
+            pub static PIPE_NOWAIT: DWORD = 0x00000001;
+            pub static PIPE_ACCEPT_REMOTE_CLIENTS: DWORD = 0x00000000;
+            pub static PIPE_REJECT_REMOTE_CLIENTS: DWORD = 0x00000008;
+            pub static PIPE_UNLIMITED_INSTANCES: DWORD = 255;
         }
         pub mod sysconf {
         }
@@ -2310,6 +2352,7 @@ pub mod bsd44 {
             pub static MADV_UNMERGEABLE : c_int = 13;
             pub static MADV_HWPOISON : c_int = 100;
 
+            pub static AF_UNIX: c_int = 1;
             pub static AF_INET: c_int = 2;
             pub static AF_INET6: c_int = 10;
             pub static SOCK_STREAM: c_int = 1;
@@ -2761,6 +2804,7 @@ pub mod bsd44 {
 
             pub static AF_INET: c_int = 2;
             pub static AF_INET6: c_int = 28;
+            pub static AF_UNIX: c_int = 1;
             pub static SOCK_STREAM: c_int = 1;
             pub static SOCK_DGRAM: c_int = 2;
             pub static IPPROTO_TCP: c_int = 6;
@@ -3137,6 +3181,7 @@ pub mod bsd44 {
             pub static MINCORE_REFERENCED_OTHER : c_int = 0x8;
             pub static MINCORE_MODIFIED_OTHER : c_int = 0x10;
 
+            pub static AF_UNIX: c_int = 1;
             pub static AF_INET: c_int = 2;
             pub static AF_INET6: c_int = 30;
             pub static SOCK_STREAM: c_int = 1;
@@ -4153,6 +4198,34 @@ pub fn QueryPerformanceCounter(
                             lpPerformanceCount: *mut LARGE_INTEGER) -> BOOL;
 
                 pub fn GetCurrentProcessId() -> DWORD;
+                pub fn CreateNamedPipeW(
+                            lpName: LPCWSTR,
+                            dwOpenMode: DWORD,
+                            dwPipeMode: DWORD,
+                            nMaxInstances: DWORD,
+                            nOutBufferSize: DWORD,
+                            nInBufferSize: DWORD,
+                            nDefaultTimeOut: DWORD,
+                            lpSecurityAttributes: LPSECURITY_ATTRIBUTES
+                            ) -> HANDLE;
+                pub fn ConnectNamedPipe(hNamedPipe: HANDLE,
+                                        lpOverlapped: LPOVERLAPPED) -> BOOL;
+                pub fn WaitNamedPipeW(lpNamedPipeName: LPCWSTR,
+                                      nTimeOut: DWORD) -> BOOL;
+                pub fn SetNamedPipeHandleState(hNamedPipe: HANDLE,
+                                               lpMode: LPDWORD,
+                                               lpMaxCollectionCount: LPDWORD,
+                                               lpCollectDataTimeout: LPDWORD)
+                                                            -> BOOL;
+                pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES,
+                                    bManualReset: BOOL,
+                                    bInitialState: BOOL,
+                                    lpName: LPCWSTR) -> HANDLE;
+                pub fn GetOverlappedResult(hFile: HANDLE,
+                                           lpOverlapped: LPOVERLAPPED,
+                                           lpNumberOfBytesTransferred: LPDWORD,
+                                           bWait: BOOL) -> BOOL;
+                pub fn DisconnectNamedPipe(hNamedPipe: HANDLE) -> BOOL;
             }
         }
 
index 14ae7c9900c4693651ee87cefe8bba317d259e8d..34b33003786e73b050108f5e7d4aab8dec5ca321 100644 (file)
@@ -7,8 +7,29 @@
 // <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.
+
+//! Standard library macros
+//!
+//! This modules contains a set of macros which are exported from the standard
+//! library. Each macro is available for use when linking against the standard
+//! library.
+
 #[macro_escape];
 
+/// The standard logging macro
+///
+/// This macro will generically log over a provided level (of type u32) with a
+/// format!-based argument list. See documentation in `std::fmt` for details on
+/// how to use the syntax, and documentation in `std::logging` for info about
+/// logging macros.
+///
+/// # Example
+///
+/// ```
+/// log!(::std::logging::DEBUG, "this is a debug message");
+/// log!(::std::logging::WARN, "this is a warning {}", "message");
+/// log!(6, "this is a custom logging level: {level}", level=6);
+/// ```
 #[macro_export]
 macro_rules! log(
     ($lvl:expr, $($arg:tt)+) => ({
@@ -21,26 +42,73 @@ macro_rules! log(
     })
 )
 
+/// A convenience macro for logging at the error log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// # let error = 3;
+/// error!("the build has failed with error code: {}", error);
+/// ```
 #[macro_export]
 macro_rules! error(
     ($($arg:tt)*) => (log!(1u32, $($arg)*))
 )
 
+/// A convenience macro for logging at the warning log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// # let code = 3;
+/// warn!("you may like to know that a process exited with: {}", code);
+/// ```
 #[macro_export]
 macro_rules! warn(
     ($($arg:tt)*) => (log!(2u32, $($arg)*))
 )
 
+/// A convenience macro for logging at the info log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// # let ret = 3;
+/// info!("this function is about to return: {}", ret);
+/// ```
 #[macro_export]
 macro_rules! info(
     ($($arg:tt)*) => (log!(3u32, $($arg)*))
 )
 
+/// A convenience macro for logging at the debug log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// debug!("x = {x}, y = {y}", x=10, y=20);
+/// ```
 #[macro_export]
 macro_rules! debug(
     ($($arg:tt)*) => (if cfg!(not(ndebug)) { log!(4u32, $($arg)*) })
 )
 
+/// A macro to test whether a log level is enabled for the current module.
+///
+/// # Example
+///
+/// ```
+/// # struct Point { x: int, y: int }
+/// # fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } }
+/// if log_enabled!(std::logging::DEBUG) {
+///     let x = some_expensive_computation();
+///     debug!("x.x = {}, x.y = {}", x.x, x.y);
+/// }
+/// ```
 #[macro_export]
 macro_rules! log_enabled(
     ($lvl:expr) => ({
@@ -49,6 +117,25 @@ macro_rules! log_enabled(
     })
 )
 
+/// The entry point for failure of rust tasks.
+///
+/// This macro is used to inject failure into a rust task, causing the task to
+/// unwind and fail entirely. Each task's failure can be reaped as the `~Any`
+/// type, and the single-argument form of the `fail!` macro will be the value
+/// which is transmitted.
+///
+/// The multi-argument form of this macro fails with a string and has the
+/// `format!` sytnax for building a string.
+///
+/// # Example
+///
+/// ```should_fail
+/// # #[allow(unreachable_code)];
+/// fail!();
+/// fail!("this is a terrible mistake!");
+/// fail!(4); // fail with the value of 4 to be collected elsewhere
+/// fail!("this is a {} {message}", "fancy", message = "message");
+/// ```
 #[macro_export]
 macro_rules! fail(
     () => (
@@ -70,6 +157,26 @@ fn run_fmt(fmt: &::std::fmt::Arguments) -> ! {
     });
 )
 
+/// Ensure that a boolean expression is `true` at runtime.
+///
+/// This will invoke the `fail!` macro if the provided expression cannot be
+/// evaluated to `true` at runtime.
+///
+/// # Example
+///
+/// ```
+/// // the failure message for these assertions is the stringified value of the
+/// // expression given.
+/// assert!(true);
+/// # fn some_computation() -> bool { true }
+/// assert!(some_computation());
+///
+/// // assert with a custom message
+/// # let x = true;
+/// assert!(x, "x wasn't true!");
+/// # let a = 3; let b = 27;
+/// assert!(a + b == 30, "a = {}, b = {}", a, b);
+/// ```
 #[macro_export]
 macro_rules! assert(
     ($cond:expr) => (
@@ -89,6 +196,18 @@ macro_rules! assert(
     );
 )
 
+/// Asserts that two expressions are equal to each other, testing equality in
+/// both directions.
+///
+/// On failure, this macro will print the values of the expressions.
+///
+/// # Example
+///
+/// ```
+/// let a = 3;
+/// let b = 1 + 2;
+/// assert_eq!(a, b);
+/// ```
 #[macro_export]
 macro_rules! assert_eq(
     ($given:expr , $expected:expr) => ({
@@ -110,13 +229,15 @@ macro_rules! assert_eq(
 /// # Example
 ///
 /// ~~~rust
+/// struct Item { weight: uint }
+///
 /// fn choose_weighted_item(v: &[Item]) -> Item {
 ///     assert!(!v.is_empty());
 ///     let mut so_far = 0u;
 ///     for item in v.iter() {
 ///         so_far += item.weight;
 ///         if so_far > 100 {
-///             return item;
+///             return *item;
 ///         }
 ///     }
 ///     // The above loop always returns, so we must hint to the
@@ -136,6 +257,16 @@ macro_rules! unimplemented(
     () => (fail!("not yet implemented"))
 )
 
+/// Use the syntax described in `std::fmt` to create a value of type `~str`.
+/// See `std::fmt` for more information.
+///
+/// # Example
+///
+/// ```
+/// format!("test");
+/// format!("hello {}", "world!");
+/// format!("x = {}, y = {y}", 10, y = 30);
+/// ```
 #[macro_export]
 macro_rules! format(
     ($($arg:tt)*) => (
@@ -143,6 +274,19 @@ macro_rules! format(
     )
 )
 
+/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`.
+/// See `std::fmt` for more information.
+///
+/// # Example
+///
+/// ```
+/// # #[allow(unused_must_use)];
+/// use std::io::MemWriter;
+///
+/// let mut w = MemWriter::new();
+/// write!(&mut w, "test");
+/// write!(&mut w, "formatted {}", "arguments");
+/// ```
 #[macro_export]
 macro_rules! write(
     ($dst:expr, $($arg:tt)*) => ({
@@ -151,6 +295,8 @@ macro_rules! write(
     })
 )
 
+/// Equivalent to the `write!` macro, except that a newline is appended after
+/// the message is written.
 #[macro_export]
 macro_rules! writeln(
     ($dst:expr, $($arg:tt)*) => ({
@@ -159,16 +305,42 @@ macro_rules! writeln(
     })
 )
 
+/// Equivalent to the `println!` macro except that a newline is not printed at
+/// the end of the message.
 #[macro_export]
 macro_rules! print(
     ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*))
 )
 
+/// Macro for printing to a task's stdout handle.
+///
+/// Each task can override its stdout handle via `std::io::stdio::set_stdout`.
+/// The syntax of this macro is the same as that used for `format!`. For more
+/// information, see `std::fmt` and `std::io::stdio`.
+///
+/// # Example
+///
+/// ```
+/// println!("hello there!");
+/// println!("format {} arguments", "some");
+/// ```
 #[macro_export]
 macro_rules! println(
     ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*))
 )
 
+/// Declare a task-local key with a specific type.
+///
+/// # Example
+///
+/// ```
+/// use std::local_data;
+///
+/// local_data_key!(my_integer: int)
+///
+/// local_data::set(my_integer, 2);
+/// local_data::get(my_integer, |val| println!("{}", val.map(|i| *i)));
+/// ```
 #[macro_export]
 macro_rules! local_data_key(
     ($name:ident: $ty:ty) => (
@@ -179,6 +351,9 @@ macro_rules! local_data_key(
     );
 )
 
+/// Helper macro for unwrapping `Result` values while returning early with an
+/// error if the value of the expression is `Err`. For more information, see
+/// `std::io`.
 #[macro_export]
 macro_rules! if_ok(
     ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
index ee05d6a704bedbc063efce390296ea8626cc5b2c..c322e9bf5726fb1a8f1f8ad05497c6504f72b8a6 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
 use unstable::intrinsics;
 use unstable::intrinsics::{bswap16, bswap32, bswap64};
 
-/// Returns the size of a type
+/// Returns the size of a type in bytes.
 #[inline]
 pub fn size_of<T>() -> uint {
     unsafe { intrinsics::size_of::<T>() }
 }
 
-/// Returns the size of the type that `_val` points to
+/// Returns the size of the type that `_val` points to in bytes.
 #[inline]
 pub fn size_of_val<T>(_val: &T) -> uint {
     size_of::<T>()
 }
 
-/// Returns the size of a type, or 1 if the actual size is zero.
+/// Returns the size of a type in bytes, or 1 if the actual size is zero.
 ///
 /// Useful for building structures containing variable-length arrays.
 #[inline]
@@ -41,7 +41,7 @@ pub fn nonzero_size_of<T>() -> uint {
     if s == 0 { 1 } else { s }
 }
 
-/// Returns the size of the type of the value that `_val` points to
+/// Returns the size in bytes of the type of the value that `_val` points to.
 #[inline]
 pub fn nonzero_size_of_val<T>(_val: &T) -> uint {
     nonzero_size_of::<T>()
index f418be262ed571b98e83c0c6d67cfb497d9d83c9..688e8347d9ad5e962545e4bde91febcd0618d2e6 100644 (file)
@@ -127,7 +127,7 @@ pub mod consts {
     // staticants from cmath.
 
     // FIXME(#11621): These constants should be deprecated once CTFE is
-    // implemented in favour of calling their respective functions in `Real`.
+    // implemented in favour of calling their respective functions in `Float`.
 
     /// Archimedes' constant
     pub static PI: f32 = 3.14159265358979323846264338327950288_f32;
@@ -300,7 +300,148 @@ fn trunc(&self) -> f32 { trunc(*self) }
     fn fract(&self) -> f32 { *self - self.trunc() }
 }
 
-impl Real for f32 {
+impl Bounded for f32 {
+    #[inline]
+    fn min_value() -> f32 { 1.17549435e-38 }
+
+    #[inline]
+    fn max_value() -> f32 { 3.40282347e+38 }
+}
+
+impl Primitive for f32 {}
+
+impl Float for f32 {
+    #[inline]
+    fn nan() -> f32 { 0.0 / 0.0 }
+
+    #[inline]
+    fn infinity() -> f32 { 1.0 / 0.0 }
+
+    #[inline]
+    fn neg_infinity() -> f32 { -1.0 / 0.0 }
+
+    #[inline]
+    fn neg_zero() -> f32 { -0.0 }
+
+    /// Returns `true` if the number is NaN
+    #[inline]
+    fn is_nan(&self) -> bool { *self != *self }
+
+    /// Returns `true` if the number is infinite
+    #[inline]
+    fn is_infinite(&self) -> bool {
+        *self == Float::infinity() || *self == Float::neg_infinity()
+    }
+
+    /// Returns `true` if the number is neither infinite or NaN
+    #[inline]
+    fn is_finite(&self) -> bool {
+        !(self.is_nan() || self.is_infinite())
+    }
+
+    /// Returns `true` if the number is neither zero, infinite, subnormal or NaN
+    #[inline]
+    fn is_normal(&self) -> bool {
+        self.classify() == FPNormal
+    }
+
+    /// Returns the floating point category of the number. If only one property is going to
+    /// be tested, it is generally faster to use the specific predicate instead.
+    fn classify(&self) -> FPCategory {
+        static EXP_MASK: u32 = 0x7f800000;
+        static MAN_MASK: u32 = 0x007fffff;
+
+        match (
+            unsafe { ::cast::transmute::<f32,u32>(*self) } & MAN_MASK,
+            unsafe { ::cast::transmute::<f32,u32>(*self) } & EXP_MASK,
+        ) {
+            (0, 0)        => FPZero,
+            (_, 0)        => FPSubnormal,
+            (0, EXP_MASK) => FPInfinite,
+            (_, EXP_MASK) => FPNaN,
+            _             => FPNormal,
+        }
+    }
+
+    #[inline]
+    fn mantissa_digits(_: Option<f32>) -> uint { 24 }
+
+    #[inline]
+    fn digits(_: Option<f32>) -> uint { 6 }
+
+    #[inline]
+    fn epsilon() -> f32 { 1.19209290e-07 }
+
+    #[inline]
+    fn min_exp(_: Option<f32>) -> int { -125 }
+
+    #[inline]
+    fn max_exp(_: Option<f32>) -> int { 128 }
+
+    #[inline]
+    fn min_10_exp(_: Option<f32>) -> int { -37 }
+
+    #[inline]
+    fn max_10_exp(_: Option<f32>) -> int { 38 }
+
+    /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
+    #[inline]
+    fn ldexp(x: f32, exp: int) -> f32 {
+        ldexp(x, exp as c_int)
+    }
+
+    /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
+    ///
+    /// - `self = x * pow(2, exp)`
+    /// - `0.5 <= abs(x) < 1.0`
+    #[inline]
+    fn frexp(&self) -> (f32, int) {
+        let mut exp = 0;
+        let x = frexp(*self, &mut exp);
+        (x, exp as int)
+    }
+
+    /// Returns the exponential of the number, minus `1`, in a way that is accurate
+    /// even if the number is close to zero
+    #[inline]
+    fn exp_m1(&self) -> f32 { exp_m1(*self) }
+
+    /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
+    /// than if the operations were performed separately
+    #[inline]
+    fn ln_1p(&self) -> f32 { ln_1p(*self) }
+
+    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
+    /// produces a more accurate result with better performance than a separate multiplication
+    /// operation followed by an add.
+    #[inline]
+    fn mul_add(&self, a: f32, b: f32) -> f32 {
+        mul_add(*self, a, b)
+    }
+
+    /// Returns the next representable floating-point value in the direction of `other`
+    #[inline]
+    fn next_after(&self, other: f32) -> f32 {
+        next_after(*self, other)
+    }
+
+    /// Returns the mantissa, exponent and sign as integers.
+    fn integer_decode(&self) -> (u64, i16, i8) {
+        let bits: u32 = unsafe {
+            ::cast::transmute(*self)
+        };
+        let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
+        let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
+        let mantissa = if exponent == 0 {
+            (bits & 0x7fffff) << 1
+        } else {
+            (bits & 0x7fffff) | 0x800000
+        };
+        // Exponent bias + mantissa shift
+        exponent -= 127 + 23;
+        (mantissa as u64, exponent, sign)
+    }
+
     /// Archimedes' constant
     #[inline]
     fn pi() -> f32 { 3.14159265358979323846264338327950288 }
@@ -495,159 +636,16 @@ fn atanh(&self) -> f32 {
 
     /// Converts to degrees, assuming the number is in radians
     #[inline]
-    fn to_degrees(&self) -> f32 { *self * (180.0f32 / Real::pi()) }
+    fn to_degrees(&self) -> f32 { *self * (180.0f32 / Float::pi()) }
 
     /// Converts to radians, assuming the number is in degrees
     #[inline]
     fn to_radians(&self) -> f32 {
-        let value: f32 = Real::pi();
+        let value: f32 = Float::pi();
         *self * (value / 180.0f32)
     }
 }
 
-impl Bounded for f32 {
-    #[inline]
-    fn min_value() -> f32 { 1.17549435e-38 }
-
-    #[inline]
-    fn max_value() -> f32 { 3.40282347e+38 }
-}
-
-impl Primitive for f32 {}
-
-impl Float for f32 {
-    #[inline]
-    fn nan() -> f32 { 0.0 / 0.0 }
-
-    #[inline]
-    fn infinity() -> f32 { 1.0 / 0.0 }
-
-    #[inline]
-    fn neg_infinity() -> f32 { -1.0 / 0.0 }
-
-    #[inline]
-    fn neg_zero() -> f32 { -0.0 }
-
-    /// Returns `true` if the number is NaN
-    #[inline]
-    fn is_nan(&self) -> bool { *self != *self }
-
-    /// Returns `true` if the number is infinite
-    #[inline]
-    fn is_infinite(&self) -> bool {
-        *self == Float::infinity() || *self == Float::neg_infinity()
-    }
-
-    /// Returns `true` if the number is neither infinite or NaN
-    #[inline]
-    fn is_finite(&self) -> bool {
-        !(self.is_nan() || self.is_infinite())
-    }
-
-    /// Returns `true` if the number is neither zero, infinite, subnormal or NaN
-    #[inline]
-    fn is_normal(&self) -> bool {
-        self.classify() == FPNormal
-    }
-
-    /// Returns the floating point category of the number. If only one property is going to
-    /// be tested, it is generally faster to use the specific predicate instead.
-    fn classify(&self) -> FPCategory {
-        static EXP_MASK: u32 = 0x7f800000;
-        static MAN_MASK: u32 = 0x007fffff;
-
-        match (
-            unsafe { ::cast::transmute::<f32,u32>(*self) } & MAN_MASK,
-            unsafe { ::cast::transmute::<f32,u32>(*self) } & EXP_MASK,
-        ) {
-            (0, 0)        => FPZero,
-            (_, 0)        => FPSubnormal,
-            (0, EXP_MASK) => FPInfinite,
-            (_, EXP_MASK) => FPNaN,
-            _             => FPNormal,
-        }
-    }
-
-    #[inline]
-    fn mantissa_digits(_: Option<f32>) -> uint { 24 }
-
-    #[inline]
-    fn digits(_: Option<f32>) -> uint { 6 }
-
-    #[inline]
-    fn epsilon() -> f32 { 1.19209290e-07 }
-
-    #[inline]
-    fn min_exp(_: Option<f32>) -> int { -125 }
-
-    #[inline]
-    fn max_exp(_: Option<f32>) -> int { 128 }
-
-    #[inline]
-    fn min_10_exp(_: Option<f32>) -> int { -37 }
-
-    #[inline]
-    fn max_10_exp(_: Option<f32>) -> int { 38 }
-
-    /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
-    #[inline]
-    fn ldexp(x: f32, exp: int) -> f32 {
-        ldexp(x, exp as c_int)
-    }
-
-    /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
-    ///
-    /// - `self = x * pow(2, exp)`
-    /// - `0.5 <= abs(x) < 1.0`
-    #[inline]
-    fn frexp(&self) -> (f32, int) {
-        let mut exp = 0;
-        let x = frexp(*self, &mut exp);
-        (x, exp as int)
-    }
-
-    /// Returns the exponential of the number, minus `1`, in a way that is accurate
-    /// even if the number is close to zero
-    #[inline]
-    fn exp_m1(&self) -> f32 { exp_m1(*self) }
-
-    /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
-    /// than if the operations were performed separately
-    #[inline]
-    fn ln_1p(&self) -> f32 { ln_1p(*self) }
-
-    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
-    /// produces a more accurate result with better performance than a separate multiplication
-    /// operation followed by an add.
-    #[inline]
-    fn mul_add(&self, a: f32, b: f32) -> f32 {
-        mul_add(*self, a, b)
-    }
-
-    /// Returns the next representable floating-point value in the direction of `other`
-    #[inline]
-    fn next_after(&self, other: f32) -> f32 {
-        next_after(*self, other)
-    }
-
-    /// Returns the mantissa, exponent and sign as integers.
-    fn integer_decode(&self) -> (u64, i16, i8) {
-        let bits: u32 = unsafe {
-            ::cast::transmute(*self)
-        };
-        let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
-        let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
-        let mantissa = if exponent == 0 {
-            (bits & 0x7fffff) << 1
-        } else {
-            (bits & 0x7fffff) | 0x800000
-        };
-        // Exponent bias + mantissa shift
-        exponent -= 127 + 23;
-        (mantissa as u64, exponent, sign)
-    }
-}
-
 //
 // Section: String Conversions
 //
@@ -1002,23 +1000,23 @@ fn test_atanh() {
 
     #[test]
     fn test_real_consts() {
-        let pi: f32 = Real::pi();
-        let two_pi: f32 = Real::two_pi();
-        let frac_pi_2: f32 = Real::frac_pi_2();
-        let frac_pi_3: f32 = Real::frac_pi_3();
-        let frac_pi_4: f32 = Real::frac_pi_4();
-        let frac_pi_6: f32 = Real::frac_pi_6();
-        let frac_pi_8: f32 = Real::frac_pi_8();
-        let frac_1_pi: f32 = Real::frac_1_pi();
-        let frac_2_pi: f32 = Real::frac_2_pi();
-        let frac_2_sqrtpi: f32 = Real::frac_2_sqrtpi();
-        let sqrt2: f32 = Real::sqrt2();
-        let frac_1_sqrt2: f32 = Real::frac_1_sqrt2();
-        let e: f32 = Real::e();
-        let log2_e: f32 = Real::log2_e();
-        let log10_e: f32 = Real::log10_e();
-        let ln_2: f32 = Real::ln_2();
-        let ln_10: f32 = Real::ln_10();
+        let pi: f32 = Float::pi();
+        let two_pi: f32 = Float::two_pi();
+        let frac_pi_2: f32 = Float::frac_pi_2();
+        let frac_pi_3: f32 = Float::frac_pi_3();
+        let frac_pi_4: f32 = Float::frac_pi_4();
+        let frac_pi_6: f32 = Float::frac_pi_6();
+        let frac_pi_8: f32 = Float::frac_pi_8();
+        let frac_1_pi: f32 = Float::frac_1_pi();
+        let frac_2_pi: f32 = Float::frac_2_pi();
+        let frac_2_sqrtpi: f32 = Float::frac_2_sqrtpi();
+        let sqrt2: f32 = Float::sqrt2();
+        let frac_1_sqrt2: f32 = Float::frac_1_sqrt2();
+        let e: f32 = Float::e();
+        let log2_e: f32 = Float::log2_e();
+        let log10_e: f32 = Float::log10_e();
+        let ln_2: f32 = Float::ln_2();
+        let ln_10: f32 = Float::ln_10();
 
         assert_approx_eq!(two_pi, 2f32 * pi);
         assert_approx_eq!(frac_pi_2, pi / 2f32);
index 1b1aaf684706494062a17e0dd2c80040163e685f..dafb3187ff8487ad5d0e10925dec228ba63943e2 100644 (file)
@@ -134,7 +134,7 @@ pub mod consts {
     // constants from cmath.
 
     // FIXME(#11621): These constants should be deprecated once CTFE is
-    // implemented in favour of calling their respective functions in `Real`.
+    // implemented in favour of calling their respective functions in `Float`.
 
     /// Archimedes' constant
     pub static PI: f64 = 3.14159265358979323846264338327950288_f64;
@@ -302,7 +302,148 @@ fn trunc(&self) -> f64 { trunc(*self) }
     fn fract(&self) -> f64 { *self - self.trunc() }
 }
 
-impl Real for f64 {
+impl Bounded for f64 {
+    #[inline]
+    fn min_value() -> f64 { 2.2250738585072014e-308 }
+
+    #[inline]
+    fn max_value() -> f64 { 1.7976931348623157e+308 }
+}
+
+impl Primitive for f64 {}
+
+impl Float for f64 {
+    #[inline]
+    fn nan() -> f64 { 0.0 / 0.0 }
+
+    #[inline]
+    fn infinity() -> f64 { 1.0 / 0.0 }
+
+    #[inline]
+    fn neg_infinity() -> f64 { -1.0 / 0.0 }
+
+    #[inline]
+    fn neg_zero() -> f64 { -0.0 }
+
+    /// Returns `true` if the number is NaN
+    #[inline]
+    fn is_nan(&self) -> bool { *self != *self }
+
+    /// Returns `true` if the number is infinite
+    #[inline]
+    fn is_infinite(&self) -> bool {
+        *self == Float::infinity() || *self == Float::neg_infinity()
+    }
+
+    /// Returns `true` if the number is neither infinite or NaN
+    #[inline]
+    fn is_finite(&self) -> bool {
+        !(self.is_nan() || self.is_infinite())
+    }
+
+    /// Returns `true` if the number is neither zero, infinite, subnormal or NaN
+    #[inline]
+    fn is_normal(&self) -> bool {
+        self.classify() == FPNormal
+    }
+
+    /// Returns the floating point category of the number. If only one property is going to
+    /// be tested, it is generally faster to use the specific predicate instead.
+    fn classify(&self) -> FPCategory {
+        static EXP_MASK: u64 = 0x7ff0000000000000;
+        static MAN_MASK: u64 = 0x000fffffffffffff;
+
+        match (
+            unsafe { ::cast::transmute::<f64,u64>(*self) } & MAN_MASK,
+            unsafe { ::cast::transmute::<f64,u64>(*self) } & EXP_MASK,
+        ) {
+            (0, 0)        => FPZero,
+            (_, 0)        => FPSubnormal,
+            (0, EXP_MASK) => FPInfinite,
+            (_, EXP_MASK) => FPNaN,
+            _             => FPNormal,
+        }
+    }
+
+    #[inline]
+    fn mantissa_digits(_: Option<f64>) -> uint { 53 }
+
+    #[inline]
+    fn digits(_: Option<f64>) -> uint { 15 }
+
+    #[inline]
+    fn epsilon() -> f64 { 2.2204460492503131e-16 }
+
+    #[inline]
+    fn min_exp(_: Option<f64>) -> int { -1021 }
+
+    #[inline]
+    fn max_exp(_: Option<f64>) -> int { 1024 }
+
+    #[inline]
+    fn min_10_exp(_: Option<f64>) -> int { -307 }
+
+    #[inline]
+    fn max_10_exp(_: Option<f64>) -> int { 308 }
+
+    /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
+    #[inline]
+    fn ldexp(x: f64, exp: int) -> f64 {
+        ldexp(x, exp as c_int)
+    }
+
+    /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
+    ///
+    /// - `self = x * pow(2, exp)`
+    /// - `0.5 <= abs(x) < 1.0`
+    #[inline]
+    fn frexp(&self) -> (f64, int) {
+        let mut exp = 0;
+        let x = frexp(*self, &mut exp);
+        (x, exp as int)
+    }
+
+    /// Returns the exponential of the number, minus `1`, in a way that is accurate
+    /// even if the number is close to zero
+    #[inline]
+    fn exp_m1(&self) -> f64 { exp_m1(*self) }
+
+    /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
+    /// than if the operations were performed separately
+    #[inline]
+    fn ln_1p(&self) -> f64 { ln_1p(*self) }
+
+    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
+    /// produces a more accurate result with better performance than a separate multiplication
+    /// operation followed by an add.
+    #[inline]
+    fn mul_add(&self, a: f64, b: f64) -> f64 {
+        mul_add(*self, a, b)
+    }
+
+    /// Returns the next representable floating-point value in the direction of `other`
+    #[inline]
+    fn next_after(&self, other: f64) -> f64 {
+        next_after(*self, other)
+    }
+
+    /// Returns the mantissa, exponent and sign as integers.
+    fn integer_decode(&self) -> (u64, i16, i8) {
+        let bits: u64 = unsafe {
+            ::cast::transmute(*self)
+        };
+        let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
+        let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
+        let mantissa = if exponent == 0 {
+            (bits & 0xfffffffffffff) << 1
+        } else {
+            (bits & 0xfffffffffffff) | 0x10000000000000
+        };
+        // Exponent bias + mantissa shift
+        exponent -= 1023 + 52;
+        (mantissa, exponent, sign)
+    }
+
     /// Archimedes' constant
     #[inline]
     fn pi() -> f64 { 3.14159265358979323846264338327950288 }
@@ -497,159 +638,16 @@ fn atanh(&self) -> f64 {
 
     /// Converts to degrees, assuming the number is in radians
     #[inline]
-    fn to_degrees(&self) -> f64 { *self * (180.0f64 / Real::pi()) }
+    fn to_degrees(&self) -> f64 { *self * (180.0f64 / Float::pi()) }
 
     /// Converts to radians, assuming the number is in degrees
     #[inline]
     fn to_radians(&self) -> f64 {
-        let value: f64 = Real::pi();
+        let value: f64 = Float::pi();
         *self * (value / 180.0)
     }
 }
 
-impl Bounded for f64 {
-    #[inline]
-    fn min_value() -> f64 { 2.2250738585072014e-308 }
-
-    #[inline]
-    fn max_value() -> f64 { 1.7976931348623157e+308 }
-}
-
-impl Primitive for f64 {}
-
-impl Float for f64 {
-    #[inline]
-    fn nan() -> f64 { 0.0 / 0.0 }
-
-    #[inline]
-    fn infinity() -> f64 { 1.0 / 0.0 }
-
-    #[inline]
-    fn neg_infinity() -> f64 { -1.0 / 0.0 }
-
-    #[inline]
-    fn neg_zero() -> f64 { -0.0 }
-
-    /// Returns `true` if the number is NaN
-    #[inline]
-    fn is_nan(&self) -> bool { *self != *self }
-
-    /// Returns `true` if the number is infinite
-    #[inline]
-    fn is_infinite(&self) -> bool {
-        *self == Float::infinity() || *self == Float::neg_infinity()
-    }
-
-    /// Returns `true` if the number is neither infinite or NaN
-    #[inline]
-    fn is_finite(&self) -> bool {
-        !(self.is_nan() || self.is_infinite())
-    }
-
-    /// Returns `true` if the number is neither zero, infinite, subnormal or NaN
-    #[inline]
-    fn is_normal(&self) -> bool {
-        self.classify() == FPNormal
-    }
-
-    /// Returns the floating point category of the number. If only one property is going to
-    /// be tested, it is generally faster to use the specific predicate instead.
-    fn classify(&self) -> FPCategory {
-        static EXP_MASK: u64 = 0x7ff0000000000000;
-        static MAN_MASK: u64 = 0x000fffffffffffff;
-
-        match (
-            unsafe { ::cast::transmute::<f64,u64>(*self) } & MAN_MASK,
-            unsafe { ::cast::transmute::<f64,u64>(*self) } & EXP_MASK,
-        ) {
-            (0, 0)        => FPZero,
-            (_, 0)        => FPSubnormal,
-            (0, EXP_MASK) => FPInfinite,
-            (_, EXP_MASK) => FPNaN,
-            _             => FPNormal,
-        }
-    }
-
-    #[inline]
-    fn mantissa_digits(_: Option<f64>) -> uint { 53 }
-
-    #[inline]
-    fn digits(_: Option<f64>) -> uint { 15 }
-
-    #[inline]
-    fn epsilon() -> f64 { 2.2204460492503131e-16 }
-
-    #[inline]
-    fn min_exp(_: Option<f64>) -> int { -1021 }
-
-    #[inline]
-    fn max_exp(_: Option<f64>) -> int { 1024 }
-
-    #[inline]
-    fn min_10_exp(_: Option<f64>) -> int { -307 }
-
-    #[inline]
-    fn max_10_exp(_: Option<f64>) -> int { 308 }
-
-    /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
-    #[inline]
-    fn ldexp(x: f64, exp: int) -> f64 {
-        ldexp(x, exp as c_int)
-    }
-
-    /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
-    ///
-    /// - `self = x * pow(2, exp)`
-    /// - `0.5 <= abs(x) < 1.0`
-    #[inline]
-    fn frexp(&self) -> (f64, int) {
-        let mut exp = 0;
-        let x = frexp(*self, &mut exp);
-        (x, exp as int)
-    }
-
-    /// Returns the exponential of the number, minus `1`, in a way that is accurate
-    /// even if the number is close to zero
-    #[inline]
-    fn exp_m1(&self) -> f64 { exp_m1(*self) }
-
-    /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
-    /// than if the operations were performed separately
-    #[inline]
-    fn ln_1p(&self) -> f64 { ln_1p(*self) }
-
-    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
-    /// produces a more accurate result with better performance than a separate multiplication
-    /// operation followed by an add.
-    #[inline]
-    fn mul_add(&self, a: f64, b: f64) -> f64 {
-        mul_add(*self, a, b)
-    }
-
-    /// Returns the next representable floating-point value in the direction of `other`
-    #[inline]
-    fn next_after(&self, other: f64) -> f64 {
-        next_after(*self, other)
-    }
-
-    /// Returns the mantissa, exponent and sign as integers.
-    fn integer_decode(&self) -> (u64, i16, i8) {
-        let bits: u64 = unsafe {
-            ::cast::transmute(*self)
-        };
-        let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
-        let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
-        let mantissa = if exponent == 0 {
-            (bits & 0xfffffffffffff) << 1
-        } else {
-            (bits & 0xfffffffffffff) | 0x10000000000000
-        };
-        // Exponent bias + mantissa shift
-        exponent -= 1023 + 52;
-        (mantissa, exponent, sign)
-    }
-}
-
 //
 // Section: String Conversions
 //
@@ -999,23 +997,23 @@ fn test_atanh() {
 
     #[test]
     fn test_real_consts() {
-        let pi: f64 = Real::pi();
-        let two_pi: f64 = Real::two_pi();
-        let frac_pi_2: f64 = Real::frac_pi_2();
-        let frac_pi_3: f64 = Real::frac_pi_3();
-        let frac_pi_4: f64 = Real::frac_pi_4();
-        let frac_pi_6: f64 = Real::frac_pi_6();
-        let frac_pi_8: f64 = Real::frac_pi_8();
-        let frac_1_pi: f64 = Real::frac_1_pi();
-        let frac_2_pi: f64 = Real::frac_2_pi();
-        let frac_2_sqrtpi: f64 = Real::frac_2_sqrtpi();
-        let sqrt2: f64 = Real::sqrt2();
-        let frac_1_sqrt2: f64 = Real::frac_1_sqrt2();
-        let e: f64 = Real::e();
-        let log2_e: f64 = Real::log2_e();
-        let log10_e: f64 = Real::log10_e();
-        let ln_2: f64 = Real::ln_2();
-        let ln_10: f64 = Real::ln_10();
+        let pi: f64 = Float::pi();
+        let two_pi: f64 = Float::two_pi();
+        let frac_pi_2: f64 = Float::frac_pi_2();
+        let frac_pi_3: f64 = Float::frac_pi_3();
+        let frac_pi_4: f64 = Float::frac_pi_4();
+        let frac_pi_6: f64 = Float::frac_pi_6();
+        let frac_pi_8: f64 = Float::frac_pi_8();
+        let frac_1_pi: f64 = Float::frac_1_pi();
+        let frac_2_pi: f64 = Float::frac_2_pi();
+        let frac_2_sqrtpi: f64 = Float::frac_2_sqrtpi();
+        let sqrt2: f64 = Float::sqrt2();
+        let frac_1_sqrt2: f64 = Float::frac_1_sqrt2();
+        let e: f64 = Float::e();
+        let log2_e: f64 = Float::log2_e();
+        let log10_e: f64 = Float::log10_e();
+        let ln_2: f64 = Float::ln_2();
+        let ln_10: f64 = Float::ln_10();
 
         assert_approx_eq!(two_pi, 2.0 * pi);
         assert_approx_eq!(frac_pi_2, pi / 2f64);
index 33690a5fddb0f5938cae488d39933ddf14c48c7b..026e7ebbd48d59aa003d9e7f02ad9a653ac065ff 100644 (file)
@@ -166,115 +166,6 @@ pub trait Round {
     fn fract(&self) -> Self;
 }
 
-/// Defines constants and methods common to real numbers
-pub trait Real: Signed
-              + Ord
-              + Round
-              + Div<Self,Self> {
-    // Common Constants
-    // FIXME (#5527): These should be associated constants
-    fn pi() -> Self;
-    fn two_pi() -> Self;
-    fn frac_pi_2() -> Self;
-    fn frac_pi_3() -> Self;
-    fn frac_pi_4() -> Self;
-    fn frac_pi_6() -> Self;
-    fn frac_pi_8() -> Self;
-    fn frac_1_pi() -> Self;
-    fn frac_2_pi() -> Self;
-    fn frac_2_sqrtpi() -> Self;
-    fn sqrt2() -> Self;
-    fn frac_1_sqrt2() -> Self;
-    fn e() -> Self;
-    fn log2_e() -> Self;
-    fn log10_e() -> Self;
-    fn ln_2() -> Self;
-    fn ln_10() -> Self;
-
-    // Fractional functions
-
-    /// Take the reciprocal (inverse) of a number, `1/x`.
-    fn recip(&self) -> Self;
-
-    // Algebraic functions
-    /// Raise a number to a power.
-    fn powf(&self, n: &Self) -> Self;
-
-    /// Take the square root of a number.
-    fn sqrt(&self) -> Self;
-    /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`.
-    fn rsqrt(&self) -> Self;
-    /// Take the cubic root of a number.
-    fn cbrt(&self) -> Self;
-    /// Calculate the length of the hypotenuse of a right-angle triangle given
-    /// legs of length `x` and `y`.
-    fn hypot(&self, other: &Self) -> Self;
-
-    // Trigonometric functions
-
-    /// Computes the sine of a number (in radians).
-    fn sin(&self) -> Self;
-    /// Computes the cosine of a number (in radians).
-    fn cos(&self) -> Self;
-    /// Computes the tangent of a number (in radians).
-    fn tan(&self) -> Self;
-
-    /// Computes the arcsine of a number. Return value is in radians in
-    /// the range [-pi/2, pi/2] or NaN if the number is outside the range
-    /// [-1, 1].
-    fn asin(&self) -> Self;
-    /// Computes the arccosine of a number. Return value is in radians in
-    /// the range [0, pi] or NaN if the number is outside the range
-    /// [-1, 1].
-    fn acos(&self) -> Self;
-    /// Computes the arctangent of a number. Return value is in radians in the
-    /// range [-pi/2, pi/2];
-    fn atan(&self) -> Self;
-    /// Computes the four quadrant arctangent of a number, `y`, and another
-    /// number `x`. Return value is in radians in the range [-pi, pi].
-    fn atan2(&self, other: &Self) -> Self;
-    /// Simultaneously computes the sine and cosine of the number, `x`. Returns
-    /// `(sin(x), cos(x))`.
-    fn sin_cos(&self) -> (Self, Self);
-
-    // Exponential functions
-
-    /// Returns `e^(self)`, (the exponential function).
-    fn exp(&self) -> Self;
-    /// Returns 2 raised to the power of the number, `2^(self)`.
-    fn exp2(&self) -> Self;
-    /// Returns the natural logarithm of the number.
-    fn ln(&self) -> Self;
-    /// Returns the logarithm of the number with respect to an arbitrary base.
-    fn log(&self, base: &Self) -> Self;
-    /// Returns the base 2 logarithm of the number.
-    fn log2(&self) -> Self;
-    /// Returns the base 10 logarithm of the number.
-    fn log10(&self) -> Self;
-
-    // Hyperbolic functions
-
-    /// Hyperbolic sine function.
-    fn sinh(&self) -> Self;
-    /// Hyperbolic cosine function.
-    fn cosh(&self) -> Self;
-    /// Hyperbolic tangent function.
-    fn tanh(&self) -> Self;
-    /// Inverse hyperbolic sine function.
-    fn asinh(&self) -> Self;
-    /// Inverse hyperbolic cosine function.
-    fn acosh(&self) -> Self;
-    /// Inverse hyperbolic tangent function.
-    fn atanh(&self) -> Self;
-
-    // Angular conversions
-
-    /// Convert radians to degrees.
-    fn to_degrees(&self) -> Self;
-    /// Convert degrees to radians.
-    fn to_radians(&self) -> Self;
-}
-
 /// Raises a value to the power of exp, using exponentiation by squaring.
 ///
 /// # Example
@@ -300,67 +191,6 @@ pub fn pow<T: One + Mul<T, T>>(mut base: T, mut exp: uint) -> T {
     }
 }
 
-/// Raise a number to a power.
-///
-/// # Example
-///
-/// ```rust
-/// use std::num;
-///
-/// let sixteen: f64 = num::powf(2.0, 4.0);
-/// assert_eq!(sixteen, 16.0);
-/// ```
-#[inline(always)] pub fn powf<T: Real>(value: T, n: T) -> T { value.powf(&n) }
-/// Take the square root of a number.
-#[inline(always)] pub fn sqrt<T: Real>(value: T) -> T { value.sqrt() }
-/// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`.
-#[inline(always)] pub fn rsqrt<T: Real>(value: T) -> T { value.rsqrt() }
-/// Take the cubic root of a number.
-#[inline(always)] pub fn cbrt<T: Real>(value: T) -> T { value.cbrt() }
-/// Calculate the length of the hypotenuse of a right-angle triangle given legs of length `x` and
-/// `y`.
-#[inline(always)] pub fn hypot<T: Real>(x: T, y: T) -> T { x.hypot(&y) }
-/// Sine function.
-#[inline(always)] pub fn sin<T: Real>(value: T) -> T { value.sin() }
-/// Cosine function.
-#[inline(always)] pub fn cos<T: Real>(value: T) -> T { value.cos() }
-/// Tangent function.
-#[inline(always)] pub fn tan<T: Real>(value: T) -> T { value.tan() }
-/// Compute the arcsine of the number.
-#[inline(always)] pub fn asin<T: Real>(value: T) -> T { value.asin() }
-/// Compute the arccosine of the number.
-#[inline(always)] pub fn acos<T: Real>(value: T) -> T { value.acos() }
-/// Compute the arctangent of the number.
-#[inline(always)] pub fn atan<T: Real>(value: T) -> T { value.atan() }
-/// Compute the arctangent with 2 arguments.
-#[inline(always)] pub fn atan2<T: Real>(x: T, y: T) -> T { x.atan2(&y) }
-/// Simultaneously computes the sine and cosine of the number.
-#[inline(always)] pub fn sin_cos<T: Real>(value: T) -> (T, T) { value.sin_cos() }
-/// Returns `e^(value)`, (the exponential function).
-#[inline(always)] pub fn exp<T: Real>(value: T) -> T { value.exp() }
-/// Returns 2 raised to the power of the number, `2^(value)`.
-#[inline(always)] pub fn exp2<T: Real>(value: T) -> T { value.exp2() }
-/// Returns the natural logarithm of the number.
-#[inline(always)] pub fn ln<T: Real>(value: T) -> T { value.ln() }
-/// Returns the logarithm of the number with respect to an arbitrary base.
-#[inline(always)] pub fn log<T: Real>(value: T, base: T) -> T { value.log(&base) }
-/// Returns the base 2 logarithm of the number.
-#[inline(always)] pub fn log2<T: Real>(value: T) -> T { value.log2() }
-/// Returns the base 10 logarithm of the number.
-#[inline(always)] pub fn log10<T: Real>(value: T) -> T { value.log10() }
-/// Hyperbolic sine function.
-#[inline(always)] pub fn sinh<T: Real>(value: T) -> T { value.sinh() }
-/// Hyperbolic cosine function.
-#[inline(always)] pub fn cosh<T: Real>(value: T) -> T { value.cosh() }
-/// Hyperbolic tangent function.
-#[inline(always)] pub fn tanh<T: Real>(value: T) -> T { value.tanh() }
-/// Inverse hyperbolic sine function.
-#[inline(always)] pub fn asinh<T: Real>(value: T) -> T { value.asinh() }
-/// Inverse hyperbolic cosine function.
-#[inline(always)] pub fn acosh<T: Real>(value: T) -> T { value.acosh() }
-/// Inverse hyperbolic tangent function.
-#[inline(always)] pub fn atanh<T: Real>(value: T) -> T { value.atanh() }
-
 pub trait Bounded {
     // FIXME (#5527): These should be associated constants
     fn min_value() -> Self;
@@ -492,8 +322,8 @@ pub enum FPCategory {
 }
 
 /// Primitive floating point numbers
-pub trait Float: Real
-               + Signed
+pub trait Float: Signed
+               + Round
                + Primitive {
     // FIXME (#5527): These should be associated constants
     fn nan() -> Self;
@@ -525,6 +355,109 @@ pub trait Float: Real
     fn next_after(&self, other: Self) -> Self;
 
     fn integer_decode(&self) -> (u64, i16, i8);
+
+    // Common Mathematical Constants
+    // FIXME (#5527): These should be associated constants
+    fn pi() -> Self;
+    fn two_pi() -> Self;
+    fn frac_pi_2() -> Self;
+    fn frac_pi_3() -> Self;
+    fn frac_pi_4() -> Self;
+    fn frac_pi_6() -> Self;
+    fn frac_pi_8() -> Self;
+    fn frac_1_pi() -> Self;
+    fn frac_2_pi() -> Self;
+    fn frac_2_sqrtpi() -> Self;
+    fn sqrt2() -> Self;
+    fn frac_1_sqrt2() -> Self;
+    fn e() -> Self;
+    fn log2_e() -> Self;
+    fn log10_e() -> Self;
+    fn ln_2() -> Self;
+    fn ln_10() -> Self;
+
+    // Fractional functions
+
+    /// Take the reciprocal (inverse) of a number, `1/x`.
+    fn recip(&self) -> Self;
+
+    // Algebraic functions
+    /// Raise a number to a power.
+    fn powf(&self, n: &Self) -> Self;
+
+    /// Take the square root of a number.
+    fn sqrt(&self) -> Self;
+    /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`.
+    fn rsqrt(&self) -> Self;
+    /// Take the cubic root of a number.
+    fn cbrt(&self) -> Self;
+    /// Calculate the length of the hypotenuse of a right-angle triangle given
+    /// legs of length `x` and `y`.
+    fn hypot(&self, other: &Self) -> Self;
+
+    // Trigonometric functions
+
+    /// Computes the sine of a number (in radians).
+    fn sin(&self) -> Self;
+    /// Computes the cosine of a number (in radians).
+    fn cos(&self) -> Self;
+    /// Computes the tangent of a number (in radians).
+    fn tan(&self) -> Self;
+
+    /// Computes the arcsine of a number. Return value is in radians in
+    /// the range [-pi/2, pi/2] or NaN if the number is outside the range
+    /// [-1, 1].
+    fn asin(&self) -> Self;
+    /// Computes the arccosine of a number. Return value is in radians in
+    /// the range [0, pi] or NaN if the number is outside the range
+    /// [-1, 1].
+    fn acos(&self) -> Self;
+    /// Computes the arctangent of a number. Return value is in radians in the
+    /// range [-pi/2, pi/2];
+    fn atan(&self) -> Self;
+    /// Computes the four quadrant arctangent of a number, `y`, and another
+    /// number `x`. Return value is in radians in the range [-pi, pi].
+    fn atan2(&self, other: &Self) -> Self;
+    /// Simultaneously computes the sine and cosine of the number, `x`. Returns
+    /// `(sin(x), cos(x))`.
+    fn sin_cos(&self) -> (Self, Self);
+
+    // Exponential functions
+
+    /// Returns `e^(self)`, (the exponential function).
+    fn exp(&self) -> Self;
+    /// Returns 2 raised to the power of the number, `2^(self)`.
+    fn exp2(&self) -> Self;
+    /// Returns the natural logarithm of the number.
+    fn ln(&self) -> Self;
+    /// Returns the logarithm of the number with respect to an arbitrary base.
+    fn log(&self, base: &Self) -> Self;
+    /// Returns the base 2 logarithm of the number.
+    fn log2(&self) -> Self;
+    /// Returns the base 10 logarithm of the number.
+    fn log10(&self) -> Self;
+
+    // Hyperbolic functions
+
+    /// Hyperbolic sine function.
+    fn sinh(&self) -> Self;
+    /// Hyperbolic cosine function.
+    fn cosh(&self) -> Self;
+    /// Hyperbolic tangent function.
+    fn tanh(&self) -> Self;
+    /// Inverse hyperbolic sine function.
+    fn asinh(&self) -> Self;
+    /// Inverse hyperbolic cosine function.
+    fn acosh(&self) -> Self;
+    /// Inverse hyperbolic tangent function.
+    fn atanh(&self) -> Self;
+
+    // Angular conversions
+
+    /// Convert radians to degrees.
+    fn to_degrees(&self) -> Self;
+    /// Convert degrees to radians.
+    fn to_radians(&self) -> Self;
 }
 
 /// Returns the exponential of the number, minus `1`, `exp(n) - 1`, in a way
@@ -539,6 +472,67 @@ pub trait Float: Real
 /// architectures) than a separate multiplication operation followed by an add.
 #[inline(always)] pub fn mul_add<T: Float>(a: T, b: T, c: T) -> T { a.mul_add(b, c) }
 
+/// Raise a number to a power.
+///
+/// # Example
+///
+/// ```rust
+/// use std::num;
+///
+/// let sixteen: f64 = num::powf(2.0, 4.0);
+/// assert_eq!(sixteen, 16.0);
+/// ```
+#[inline(always)] pub fn powf<T: Float>(value: T, n: T) -> T { value.powf(&n) }
+/// Take the square root of a number.
+#[inline(always)] pub fn sqrt<T: Float>(value: T) -> T { value.sqrt() }
+/// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`.
+#[inline(always)] pub fn rsqrt<T: Float>(value: T) -> T { value.rsqrt() }
+/// Take the cubic root of a number.
+#[inline(always)] pub fn cbrt<T: Float>(value: T) -> T { value.cbrt() }
+/// Calculate the length of the hypotenuse of a right-angle triangle given legs
+/// of length `x` and `y`.
+#[inline(always)] pub fn hypot<T: Float>(x: T, y: T) -> T { x.hypot(&y) }
+/// Sine function.
+#[inline(always)] pub fn sin<T: Float>(value: T) -> T { value.sin() }
+/// Cosine function.
+#[inline(always)] pub fn cos<T: Float>(value: T) -> T { value.cos() }
+/// Tangent function.
+#[inline(always)] pub fn tan<T: Float>(value: T) -> T { value.tan() }
+/// Compute the arcsine of the number.
+#[inline(always)] pub fn asin<T: Float>(value: T) -> T { value.asin() }
+/// Compute the arccosine of the number.
+#[inline(always)] pub fn acos<T: Float>(value: T) -> T { value.acos() }
+/// Compute the arctangent of the number.
+#[inline(always)] pub fn atan<T: Float>(value: T) -> T { value.atan() }
+/// Compute the arctangent with 2 arguments.
+#[inline(always)] pub fn atan2<T: Float>(x: T, y: T) -> T { x.atan2(&y) }
+/// Simultaneously computes the sine and cosine of the number.
+#[inline(always)] pub fn sin_cos<T: Float>(value: T) -> (T, T) { value.sin_cos() }
+/// Returns `e^(value)`, (the exponential function).
+#[inline(always)] pub fn exp<T: Float>(value: T) -> T { value.exp() }
+/// Returns 2 raised to the power of the number, `2^(value)`.
+#[inline(always)] pub fn exp2<T: Float>(value: T) -> T { value.exp2() }
+/// Returns the natural logarithm of the number.
+#[inline(always)] pub fn ln<T: Float>(value: T) -> T { value.ln() }
+/// Returns the logarithm of the number with respect to an arbitrary base.
+#[inline(always)] pub fn log<T: Float>(value: T, base: T) -> T { value.log(&base) }
+/// Returns the base 2 logarithm of the number.
+#[inline(always)] pub fn log2<T: Float>(value: T) -> T { value.log2() }
+/// Returns the base 10 logarithm of the number.
+#[inline(always)] pub fn log10<T: Float>(value: T) -> T { value.log10() }
+/// Hyperbolic sine function.
+#[inline(always)] pub fn sinh<T: Float>(value: T) -> T { value.sinh() }
+/// Hyperbolic cosine function.
+#[inline(always)] pub fn cosh<T: Float>(value: T) -> T { value.cosh() }
+/// Hyperbolic tangent function.
+#[inline(always)] pub fn tanh<T: Float>(value: T) -> T { value.tanh() }
+/// Inverse hyperbolic sine function.
+#[inline(always)] pub fn asinh<T: Float>(value: T) -> T { value.asinh() }
+/// Inverse hyperbolic cosine function.
+#[inline(always)] pub fn acosh<T: Float>(value: T) -> T { value.acosh() }
+/// Inverse hyperbolic tangent function.
+#[inline(always)] pub fn atanh<T: Float>(value: T) -> T { value.atanh() }
+
 /// A generic trait for converting a value to a number.
 pub trait ToPrimitive {
     /// Converts the value of `self` to an `int`.
index 719ed62d03d0aaa65707319c5696db53680088d4..74e2fceb6cae6d7854a93db3eb2f36a91fd3f6a5 100644 (file)
@@ -88,7 +88,8 @@ pub fn getcwd() -> Path {
             fail!();
         }
     }
-    Path::new(str::from_utf16(buf))
+    Path::new(str::from_utf16(str::truncate_utf16_at_nul(buf))
+              .expect("GetCurrentDirectoryW returned invalid UTF-16"))
 }
 
 #[cfg(windows)]
@@ -124,7 +125,12 @@ pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD)
                 }
                 if k != 0 && done {
                     let sub = buf.slice(0, k as uint);
-                    res = option::Some(str::from_utf16(sub));
+                    // We want to explicitly catch the case when the
+                    // closure returned invalid UTF-16, rather than
+                    // set `res` to None and continue.
+                    let s = str::from_utf16(sub)
+                        .expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
+                    res = option::Some(s)
                 }
             }
             return res;
@@ -739,7 +745,8 @@ fn FormatMessageW(flags: DWORD,
                 fail!("[{}] FormatMessage failure", errno());
             }
 
-            str::from_utf16(buf)
+            str::from_utf16(str::truncate_utf16_at_nul(buf))
+                .expect("FormatMessageW returned invalid UTF-16")
         }
     }
 
@@ -828,8 +835,10 @@ fn real_args() -> ~[~str] {
             while *ptr.offset(len as int) != 0 { len += 1; }
 
             // Push it onto the list.
-            args.push(vec::raw::buf_as_slice(ptr, len,
-                                             str::from_utf16));
+            let opt_s = vec::raw::buf_as_slice(ptr, len, |buf| {
+                    str::from_utf16(str::truncate_utf16_at_nul(buf))
+                });
+            args.push(opt_s.expect("CommandLineToArgvW returned invalid UTF-16"));
         }
     }
 
index bd21bb4e75444a5b5fd58ea0dfc3f8e51c1113c5..e2b627250432cc5d151ebc6bdba8bec08b889782 100644 (file)
@@ -58,7 +58,7 @@
 pub use iter::{FromIterator, Extendable};
 pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIterator};
 pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize};
-pub use num::{Integer, Real, Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
+pub use num::{Integer, Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
 pub use num::{Signed, Unsigned, Round};
 pub use num::{Primitive, Int, Float, ToStrRadix, ToPrimitive, FromPrimitive};
 pub use path::{GenericPath, Path, PosixPath, WindowsPath};
index 287a4a36293841c6c6d2ff7fc57778a2f20b5f4d..09c36d945eb1a19fd876494ebefdcd765181d180 100644 (file)
@@ -10,7 +10,7 @@
 
 //! The exponential distribution.
 
-use num::Real;
+use num::Float;
 use rand::{Rng, Rand};
 use rand::distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
 
index 0915d49945dc5a00835f33cf4463e710c9fd90a2..a14b58188bd784eef6c244204cb6d7b2bfe87bc1 100644 (file)
@@ -10,7 +10,7 @@
 
 //! The Gamma and derived distributions.
 
-use num::Real;
+use num::Float;
 use num;
 use rand::{Rng, Open01};
 use super::normal::StandardNormal;
index 074a181ca3c7ef646c46e4b06adbea4568f8cc7a..c9dc3c8abc1abc7ee00b6973f7894bba773ebfbf 100644 (file)
@@ -10,7 +10,7 @@
 
 //! The normal and derived distributions.
 
-use num::Real;
+use num::Float;
 use rand::{Rng, Rand, Open01};
 use rand::distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
 
index 0719523af775fd3058b1c5a82c3b9bcf8dbd4220..72ba98eab4f7dacdacd3c7e6e1480ed62e68f5bb 100644 (file)
@@ -254,7 +254,7 @@ pub fn deschedule(mut ~self, amt: uint,
         ops.deschedule(amt, self, f)
     }
 
-    /// Wakes up a previously blocked task, optionally specifiying whether the
+    /// Wakes up a previously blocked task, optionally specifying whether the
     /// current task can accept a change in scheduling. This function can only
     /// be called on tasks that were previously blocked in `deschedule`.
     pub fn reawaken(mut ~self) {
index 5718a27bfef2de8b709fe082a06fc928c5ffa0d8..ef8bd94c89766f1883ff51eb4bbfc2502eb2f652 100644 (file)
@@ -400,7 +400,7 @@ fn static_char_ptr(p: *u8) -> &'static str {
 /// The entry point for unwinding with a formatted message.
 ///
 /// This is designed to reduce the amount of code required at the call
-/// site as much as possible (so that `fail!()` has as low an implact
+/// site as much as possible (so that `fail!()` has as low an impact
 /// on (e.g.) the inlining of other functions as possible), by moving
 /// the actual formatting into this shared place.
 #[inline(never)] #[cold]
index 0a7f513581c0db0c31014cae742555b2d040711f..2ac3a9817872e24b0b08452cd90e9d245cf45350 100644 (file)
@@ -731,29 +731,38 @@ pub fn eq(a: &~str, b: &~str) -> bool {
 Section: Misc
 */
 
-/// Determines if a vector of bytes contains valid UTF-8
-pub fn is_utf8(v: &[u8]) -> bool {
-    first_non_utf8_index(v).is_none()
-}
-
+/// Walk through `iter` checking that it's a valid UTF-8 sequence,
+/// returning `true` in that case, or, if it is invalid, `false` with
+/// `iter` reset such that it is pointing at the first byte in the
+/// invalid sequence.
 #[inline(always)]
-fn first_non_utf8_index(v: &[u8]) -> Option<uint> {
-    let mut i = 0u;
-    let total = v.len();
-    fn unsafe_get(xs: &[u8], i: uint) -> u8 {
-        unsafe { *xs.unsafe_ref(i) }
-    }
-    while i < total {
-        let v_i = unsafe_get(v, i);
-        if v_i < 128u8 {
-            i += 1u;
-        } else {
-            let w = utf8_char_width(v_i);
-            if w == 0u { return Some(i); }
+fn run_utf8_validation_iterator(iter: &mut vec::Items<u8>) -> bool {
+    loop {
+        // save the current thing we're pointing at.
+        let old = *iter;
+
+        // restore the iterator we had at the start of this codepoint.
+        macro_rules! err ( () => { {*iter = old; return false} });
+        macro_rules! next ( () => {
+                match iter.next() {
+                    Some(a) => *a,
+                    // we needed data, but there was none: error!
+                    None => err!()
+                }
+            });
 
-            let nexti = i + w;
-            if nexti > total { return Some(i); }
+        let first = match iter.next() {
+            Some(&b) => b,
+            // we're at the end of the iterator and a codepoint
+            // boundary at the same time, so this string is valid.
+            None => return true
+        };
 
+        // ASCII characters are always valid, so only large
+        // bytes need more examination.
+        if first >= 128 {
+            let w = utf8_char_width(first);
+            let second = next!();
             // 2-byte encoding is for codepoints  \u0080 to  \u07ff
             //        first  C2 80        last DF BF
             // 3-byte encoding is for codepoints  \u0800 to  \uffff
@@ -772,93 +781,241 @@ fn unsafe_get(xs: &[u8], i: uint) -> u8 {
             //               %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
             // UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
             //               %xF4 %x80-8F 2( UTF8-tail )
-            // UTF8-tail   = %x80-BF
             match w {
-                2 => if unsafe_get(v, i + 1) & 192u8 != TAG_CONT_U8 {
-                    return Some(i)
-                },
-                3 => match (v_i,
-                            unsafe_get(v, i + 1),
-                            unsafe_get(v, i + 2) & 192u8) {
-                    (0xE0        , 0xA0 .. 0xBF, TAG_CONT_U8) => (),
-                    (0xE1 .. 0xEC, 0x80 .. 0xBF, TAG_CONT_U8) => (),
-                    (0xED        , 0x80 .. 0x9F, TAG_CONT_U8) => (),
-                    (0xEE .. 0xEF, 0x80 .. 0xBF, TAG_CONT_U8) => (),
-                    _ => return Some(i),
-                },
-                _ => match (v_i,
-                            unsafe_get(v, i + 1),
-                            unsafe_get(v, i + 2) & 192u8,
-                            unsafe_get(v, i + 3) & 192u8) {
-                    (0xF0        , 0x90 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) => (),
-                    (0xF1 .. 0xF3, 0x80 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) => (),
-                    (0xF4        , 0x80 .. 0x8F, TAG_CONT_U8, TAG_CONT_U8) => (),
-                    _ => return Some(i)
-                },
+                2 => if second & 192 != TAG_CONT_U8 {err!()},
+                3 => {
+                    match (first, second, next!() & 192) {
+                        (0xE0        , 0xA0 .. 0xBF, TAG_CONT_U8) |
+                        (0xE1 .. 0xEC, 0x80 .. 0xBF, TAG_CONT_U8) |
+                        (0xED        , 0x80 .. 0x9F, TAG_CONT_U8) |
+                        (0xEE .. 0xEF, 0x80 .. 0xBF, TAG_CONT_U8) => {}
+                        _ => err!()
+                    }
+                }
+                4 => {
+                    match (first, second, next!() & 192, next!() & 192) {
+                        (0xF0        , 0x90 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
+                        (0xF1 .. 0xF3, 0x80 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
+                        (0xF4        , 0x80 .. 0x8F, TAG_CONT_U8, TAG_CONT_U8) => {}
+                        _ => err!()
+                    }
+                }
+                _ => err!()
             }
-
-            i = nexti;
         }
     }
-    None
+}
+
+/// Determines if a vector of bytes contains valid UTF-8.
+pub fn is_utf8(v: &[u8]) -> bool {
+    run_utf8_validation_iterator(&mut v.iter())
+}
+
+#[inline(always)]
+fn first_non_utf8_index(v: &[u8]) -> Option<uint> {
+    let mut it = v.iter();
+
+    let ok = run_utf8_validation_iterator(&mut it);
+    if ok {
+        None
+    } else {
+        // work out how many valid bytes we've consumed
+        // (run_utf8_validation_iterator resets the iterator to just
+        // after the last good byte), which we can do because the
+        // vector iterator size_hint is exact.
+        let (remaining, _) = it.size_hint();
+        Some(v.len() - remaining)
+    }
 }
 
 /// Determines if a vector of `u16` contains valid UTF-16
 pub fn is_utf16(v: &[u16]) -> bool {
-    let len = v.len();
-    let mut i = 0u;
-    while i < len {
-        let u = v[i];
+    let mut it = v.iter();
+    macro_rules! next ( ($ret:expr) => {
+            match it.next() { Some(u) => *u, None => return $ret }
+        }
+    )
+    loop {
+        let u = next!(true);
 
-        if  u <= 0xD7FF_u16 || u >= 0xE000_u16 {
-            i += 1u;
+        match char::from_u32(u as u32) {
+            Some(_) => {}
+            None => {
+                let u2 = next!(false);
+                if u < 0xD7FF || u > 0xDBFF ||
+                    u2 < 0xDC00 || u2 > 0xDFFF { return false; }
+            }
+        }
+    }
+}
+
+/// An iterator that decodes UTF-16 encoded codepoints from a vector
+/// of `u16`s.
+#[deriving(Clone)]
+pub struct UTF16Items<'a> {
+    priv iter: vec::Items<'a, u16>
+}
+/// The possibilities for values decoded from a `u16` stream.
+#[deriving(Eq, TotalEq, Clone)]
+pub enum UTF16Item {
+    /// A valid codepoint.
+    ScalarValue(char),
+    /// An invalid surrogate without its pair.
+    LoneSurrogate(u16)
+}
 
+impl UTF16Item {
+    /// Convert `self` to a `char`, taking `LoneSurrogate`s to the
+    /// replacement character (U+FFFD).
+    #[inline]
+    pub fn to_char_lossy(&self) -> char {
+        match *self {
+            ScalarValue(c) => c,
+            LoneSurrogate(_) => '\uFFFD'
+        }
+    }
+}
+
+impl<'a> Iterator<UTF16Item> for UTF16Items<'a> {
+    fn next(&mut self) -> Option<UTF16Item> {
+        let u = match self.iter.next() {
+            Some(u) => *u,
+            None => return None
+        };
+
+        if u < 0xD800 || 0xDFFF < u {
+            // not a surrogate
+            Some(ScalarValue(unsafe {cast::transmute(u as u32)}))
+        } else if u >= 0xDC00 {
+            // a trailing surrogate
+            Some(LoneSurrogate(u))
         } else {
-            if i+1u < len { return false; }
-            let u2 = v[i+1u];
-            if u < 0xD7FF_u16 || u > 0xDBFF_u16 { return false; }
-            if u2 < 0xDC00_u16 || u2 > 0xDFFF_u16 { return false; }
-            i += 2u;
+            // preserve state for rewinding.
+            let old = self.iter;
+
+            let u2 = match self.iter.next() {
+                Some(u2) => *u2,
+                // eof
+                None => return Some(LoneSurrogate(u))
+            };
+            if u2 < 0xDC00 || u2 > 0xDFFF {
+                // not a trailing surrogate so we're not a valid
+                // surrogate pair, so rewind to redecode u2 next time.
+                self.iter = old;
+                return Some(LoneSurrogate(u))
+            }
+
+            // all ok, so lets decode it.
+            let c = ((u - 0xD800) as u32 << 10 | (u2 - 0xDC00) as u32) + 0x1_0000;
+            Some(ScalarValue(unsafe {cast::transmute(c)}))
         }
     }
-    return true;
+
+    #[inline]
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        let (low, high) = self.iter.size_hint();
+        // we could be entirely valid surrogates (2 elements per
+        // char), or entirely non-surrogates (1 element per char)
+        (low / 2, high)
+    }
 }
 
-/// Iterates over the utf-16 characters in the specified slice, yielding each
-/// decoded unicode character to the function provided.
+/// Create an iterator over the UTF-16 encoded codepoints in `v`,
+/// returning invalid surrogates as `LoneSurrogate`s.
 ///
-/// # Failures
+/// # Example
 ///
-/// * Fails on invalid utf-16 data
-pub fn utf16_chars(v: &[u16], f: |char|) {
-    let len = v.len();
-    let mut i = 0u;
-    while i < len && v[i] != 0u16 {
-        let u = v[i];
-
-        if  u <= 0xD7FF_u16 || u >= 0xE000_u16 {
-            f(unsafe { cast::transmute(u as u32) });
-            i += 1u;
+/// ```rust
+/// use std::str;
+/// use std::str::{ScalarValue, LoneSurrogate};
+///
+/// // 𝄞mus<invalid>ic<invalid>
+/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075,
+///          0x0073, 0xDD1E, 0x0069, 0x0063,
+///          0xD834];
+///
+/// assert_eq!(str::utf16_items(v).to_owned_vec(),
+///            ~[ScalarValue('𝄞'),
+///              ScalarValue('m'), ScalarValue('u'), ScalarValue('s'),
+///              LoneSurrogate(0xDD1E),
+///              ScalarValue('i'), ScalarValue('c'),
+///              LoneSurrogate(0xD834)]);
+/// ```
+pub fn utf16_items<'a>(v: &'a [u16]) -> UTF16Items<'a> {
+    UTF16Items { iter : v.iter() }
+}
 
-        } else {
-            let u2 = v[i+1u];
-            assert!(u >= 0xD800_u16 && u <= 0xDBFF_u16);
-            assert!(u2 >= 0xDC00_u16 && u2 <= 0xDFFF_u16);
-            let mut c: u32 = (u - 0xD800_u16) as u32;
-            c = c << 10;
-            c |= (u2 - 0xDC00_u16) as u32;
-            c |= 0x1_0000_u32;
-            f(unsafe { cast::transmute(c) });
-            i += 2u;
+/// Return a slice of `v` ending at (and not including) the first NUL
+/// (0).
+///
+/// # Example
+///
+/// ```rust
+/// use std::str;
+///
+/// // "abcd"
+/// let mut v = ['a' as u16, 'b' as u16, 'c' as u16, 'd' as u16];
+/// // no NULs so no change
+/// assert_eq!(str::truncate_utf16_at_nul(v), v.as_slice());
+///
+/// // "ab\0d"
+/// v[2] = 0;
+/// assert_eq!(str::truncate_utf16_at_nul(v),
+///            &['a' as u16, 'b' as u16]);
+/// ```
+pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] {
+    match v.iter().position(|c| *c == 0) {
+        // don't include the 0
+        Some(i) => v.slice_to(i),
+        None => v
+    }
+}
+
+/// Decode a UTF-16 encoded vector `v` into a string, returning `None`
+/// if `v` contains any invalid data.
+///
+/// # Example
+///
+/// ```rust
+/// use std::str;
+///
+/// // 𝄞music
+/// let mut v = [0xD834, 0xDD1E, 0x006d, 0x0075,
+///              0x0073, 0x0069, 0x0063];
+/// assert_eq!(str::from_utf16(v), Some(~"𝄞music"));
+///
+/// // 𝄞mu<invalid>ic
+/// v[4] = 0xD800;
+/// assert_eq!(str::from_utf16(v), None);
+/// ```
+pub fn from_utf16(v: &[u16]) -> Option<~str> {
+    let mut s = with_capacity(v.len() / 2);
+    for c in utf16_items(v) {
+        match c {
+            ScalarValue(c) => s.push_char(c),
+            LoneSurrogate(_) => return None
         }
     }
+    Some(s)
 }
 
-/// Allocates a new string from the utf-16 slice provided
-pub fn from_utf16(v: &[u16]) -> ~str {
-    let mut buf = with_capacity(v.len());
-    utf16_chars(v, |ch| buf.push_char(ch));
-    buf
+/// Decode a UTF-16 encoded vector `v` into a string, replacing
+/// invalid data with the replacement character (U+FFFD).
+///
+/// # Example
+/// ```rust
+/// use std::str;
+///
+/// // 𝄞mus<invalid>ic<invalid>
+/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075,
+///          0x0073, 0xDD1E, 0x0069, 0x0063,
+///          0xD834];
+///
+/// assert_eq!(str::from_utf16_lossy(v),
+///            ~"𝄞mus\uFFFDic\uFFFD");
+/// ```
+pub fn from_utf16_lossy(v: &[u16]) -> ~str {
+    utf16_items(v).map(|c| c.to_char_lossy()).collect()
 }
 
 /// Allocates a new string with the specified capacity. The string returned is
@@ -3511,6 +3668,65 @@ fn test_is_utf8() {
         assert!(is_utf8([0xF4, 0x8F, 0xBF, 0xBF]));
     }
 
+    #[test]
+    fn test_is_utf16() {
+        macro_rules! pos ( ($($e:expr),*) => { { $(assert!(is_utf16($e));)* } });
+
+        // non-surrogates
+        pos!([0x0000],
+             [0x0001, 0x0002],
+             [0xD7FF],
+             [0xE000]);
+
+        // surrogate pairs (randomly generated with Python 3's
+        // .encode('utf-16be'))
+        pos!([0xdb54, 0xdf16, 0xd880, 0xdee0, 0xdb6a, 0xdd45],
+             [0xd91f, 0xdeb1, 0xdb31, 0xdd84, 0xd8e2, 0xde14],
+             [0xdb9f, 0xdc26, 0xdb6f, 0xde58, 0xd850, 0xdfae]);
+
+        // mixtures (also random)
+        pos!([0xd921, 0xdcc2, 0x002d, 0x004d, 0xdb32, 0xdf65],
+             [0xdb45, 0xdd2d, 0x006a, 0xdacd, 0xddfe, 0x0006],
+             [0x0067, 0xd8ff, 0xddb7, 0x000f, 0xd900, 0xdc80]);
+
+        // negative tests
+        macro_rules! neg ( ($($e:expr),*) => { { $(assert!(!is_utf16($e));)* } });
+
+        neg!(
+            // surrogate + regular unit
+            [0xdb45, 0x0000],
+            // surrogate + lead surrogate
+            [0xd900, 0xd900],
+            // unterminated surrogate
+            [0xd8ff],
+            // trail surrogate without a lead
+            [0xddb7]);
+
+        // random byte sequences that Python 3's .decode('utf-16be')
+        // failed on
+        neg!([0x5b3d, 0x0141, 0xde9e, 0x8fdc, 0xc6e7],
+             [0xdf5a, 0x82a5, 0x62b9, 0xb447, 0x92f3],
+             [0xda4e, 0x42bc, 0x4462, 0xee98, 0xc2ca],
+             [0xbe00, 0xb04a, 0x6ecb, 0xdd89, 0xe278],
+             [0x0465, 0xab56, 0xdbb6, 0xa893, 0x665e],
+             [0x6b7f, 0x0a19, 0x40f4, 0xa657, 0xdcc5],
+             [0x9b50, 0xda5e, 0x24ec, 0x03ad, 0x6dee],
+             [0x8d17, 0xcaa7, 0xf4ae, 0xdf6e, 0xbed7],
+             [0xdaee, 0x2584, 0x7d30, 0xa626, 0x121a],
+             [0xd956, 0x4b43, 0x7570, 0xccd6, 0x4f4a],
+             [0x9dcf, 0x1b49, 0x4ba5, 0xfce9, 0xdffe],
+             [0x6572, 0xce53, 0xb05a, 0xf6af, 0xdacf],
+             [0x1b90, 0x728c, 0x9906, 0xdb68, 0xf46e],
+             [0x1606, 0xbeca, 0xbe76, 0x860f, 0xdfa5],
+             [0x8b4f, 0xde7a, 0xd220, 0x9fac, 0x2b6f],
+             [0xb8fe, 0xebbe, 0xda32, 0x1a5f, 0x8b8b],
+             [0x934b, 0x8956, 0xc434, 0x1881, 0xddf7],
+             [0x5a95, 0x13fc, 0xf116, 0xd89b, 0x93f9],
+             [0xd640, 0x71f1, 0xdd7d, 0x77eb, 0x1cd8],
+             [0x348b, 0xaef0, 0xdb2c, 0xebf1, 0x1282],
+             [0x50d7, 0xd824, 0x5010, 0xb369, 0x22ea]);
+    }
+
     #[test]
     fn test_raw_from_c_str() {
         unsafe {
@@ -3662,17 +3878,72 @@ fn test_utf16() {
                 0xdc9c_u16, 0xd801_u16, 0xdc92_u16, 0xd801_u16,
                 0xdc96_u16, 0xd801_u16, 0xdc86_u16, 0x0020_u16,
                 0xd801_u16, 0xdc95_u16, 0xd801_u16, 0xdc86_u16,
-                0x000a_u16 ]) ];
+                0x000a_u16 ]),
+             // Issue #12318, even-numbered non-BMP planes
+             (~"\U00020000",
+              ~[0xD840, 0xDC00])];
 
         for p in pairs.iter() {
             let (s, u) = (*p).clone();
-            assert!(s.to_utf16() == u);
-            assert!(from_utf16(u) == s);
-            assert!(from_utf16(s.to_utf16()) == s);
-            assert!(from_utf16(u).to_utf16() == u);
+            assert!(is_utf16(u));
+            assert_eq!(s.to_utf16(), u);
+
+            assert_eq!(from_utf16(u).unwrap(), s);
+            assert_eq!(from_utf16_lossy(u), s);
+
+            assert_eq!(from_utf16(s.to_utf16()).unwrap(), s);
+            assert_eq!(from_utf16(u).unwrap().to_utf16(), u);
         }
     }
 
+    #[test]
+    fn test_utf16_invalid() {
+        // completely positive cases tested above.
+        // lead + eof
+        assert_eq!(from_utf16([0xD800]), None);
+        // lead + lead
+        assert_eq!(from_utf16([0xD800, 0xD800]), None);
+
+        // isolated trail
+        assert_eq!(from_utf16([0x0061, 0xDC00]), None);
+
+        // general
+        assert_eq!(from_utf16([0xD800, 0xd801, 0xdc8b, 0xD800]), None);
+    }
+
+    #[test]
+    fn test_utf16_lossy() {
+        // completely positive cases tested above.
+        // lead + eof
+        assert_eq!(from_utf16_lossy([0xD800]), ~"\uFFFD");
+        // lead + lead
+        assert_eq!(from_utf16_lossy([0xD800, 0xD800]), ~"\uFFFD\uFFFD");
+
+        // isolated trail
+        assert_eq!(from_utf16_lossy([0x0061, 0xDC00]), ~"a\uFFFD");
+
+        // general
+        assert_eq!(from_utf16_lossy([0xD800, 0xd801, 0xdc8b, 0xD800]), ~"\uFFFD𐒋\uFFFD");
+    }
+
+    #[test]
+    fn test_truncate_utf16_at_nul() {
+        let v = [];
+        assert_eq!(truncate_utf16_at_nul(v), &[]);
+
+        let v = [0, 2, 3];
+        assert_eq!(truncate_utf16_at_nul(v), &[]);
+
+        let v = [1, 0, 3];
+        assert_eq!(truncate_utf16_at_nul(v), &[1]);
+
+        let v = [1, 2, 0];
+        assert_eq!(truncate_utf16_at_nul(v), &[1, 2]);
+
+        let v = [1, 2, 3];
+        assert_eq!(truncate_utf16_at_nul(v), &[1, 2, 3]);
+    }
+
     #[test]
     fn test_char_at() {
         let s = ~"ศไทย中华Việt Nam";
index b5a55f3f8c973c930acd682436ecf0ae9ffdc52f..2dc63380cb8902c39712cf3307024b21f56fd7f3 100644 (file)
@@ -104,7 +104,7 @@ pub fn push(&mut self, t: T) {
     ///
     /// Note that the current implementation means that this function cannot
     /// return `Option<T>`. It is possible for this queue to be in an
-    /// inconsistent state where many pushes have suceeded and completely
+    /// inconsistent state where many pushes have succeeded and completely
     /// finished, but pops cannot return `Some(t)`. This inconsistent state
     /// happens when a pusher is pre-empted at an inopportune moment.
     ///
@@ -203,4 +203,3 @@ fn test() {
         }
     }
 }
-
index 4648f149a9fed92c287939d30f67c5e02cce9a5f..8818cb0d270b6cc2c4bbfbe3e4f339a7240b5747 100644 (file)
 
 //! Runtime calls emitted by the compiler.
 
-use c_str::ToCStr;
+use c_str::CString;
+use libc::c_char;
+use cast;
+use option::Some;
 
 #[cold]
 #[lang="fail_"]
@@ -23,7 +26,14 @@ pub fn fail_(expr: *u8, file: *u8, line: uint) -> ! {
 pub fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! {
     let msg = format!("index out of bounds: the len is {} but the index is {}",
                       len as uint, index as uint);
-    msg.with_c_str(|buf| fail_(buf as *u8, file, line))
+
+    let file_str = match unsafe { CString::new(file as *c_char, false) }.as_str() {
+        // This transmute is safe because `file` is always stored in rodata.
+        Some(s) => unsafe { cast::transmute::<&str, &'static str>(s) },
+        None    => "file wasn't UTF-8 safe"
+    };
+
+    ::rt::begin_unwind(msg, file_str, line)
 }
 
 #[lang="malloc"]
index 0e53ecd416a7ab4beab4e4e0b98452b6263b7f65..db4260a30ee113886ae7f9274520746eb590f524 100644 (file)
@@ -192,12 +192,6 @@ pub fn new_with_condvars(user_data: T, num_condvars: uint) -> MutexArc<T> {
      * other tasks wishing to access the data will block until the closure
      * finishes running.
      *
-     * The reason this function is 'unsafe' is because it is possible to
-     * construct a circular reference among multiple Arcs by mutating the
-     * underlying data. This creates potential for deadlock, but worse, this
-     * will guarantee a memory leak of all involved Arcs. Using MutexArcs
-     * inside of other Arcs is safe in absence of circular references.
-     *
      * If you wish to nest MutexArcs, one strategy for ensuring safety at
      * runtime is to add a "nesting level counter" inside the stored data, and
      * when traversing the arcs, assert that they monotonically decrease.
@@ -210,63 +204,33 @@ pub fn new_with_condvars(user_data: T, num_condvars: uint) -> MutexArc<T> {
      * blocked on the mutex) will also fail immediately.
      */
     #[inline]
-    pub unsafe fn unsafe_access<U>(&self, blk: |x: &mut T| -> U) -> U {
+    pub fn access<U>(&self, blk: |x: &mut T| -> U) -> U {
         let state = self.x.get();
-        // Borrowck would complain about this if the function were
-        // not already unsafe. See borrow_rwlock, far below.
-        (&(*state).lock).lock(|| {
-            check_poison(true, (*state).failed);
-            let _z = PoisonOnFail::new(&mut (*state).failed);
-            blk(&mut (*state).data)
-        })
+        unsafe {
+            // Borrowck would complain about this if the code were
+            // not already unsafe. See borrow_rwlock, far below.
+            (&(*state).lock).lock(|| {
+                check_poison(true, (*state).failed);
+                let _z = PoisonOnFail::new(&mut (*state).failed);
+                blk(&mut (*state).data)
+            })
+        }
     }
 
-    /// As unsafe_access(), but with a condvar, as sync::mutex.lock_cond().
+    /// As access(), but with a condvar, as sync::mutex.lock_cond().
     #[inline]
-    pub unsafe fn unsafe_access_cond<U>(&self,
-                                        blk: |x: &mut T, c: &Condvar| -> U)
-                                        -> U {
+    pub fn access_cond<U>(&self, blk: |x: &mut T, c: &Condvar| -> U) -> U {
         let state = self.x.get();
-        (&(*state).lock).lock_cond(|cond| {
-            check_poison(true, (*state).failed);
-            let _z = PoisonOnFail::new(&mut (*state).failed);
-            blk(&mut (*state).data,
-                &Condvar {is_mutex: true,
-                          failed: &(*state).failed,
-                          cond: cond })
-        })
-    }
-}
-
-impl<T:Freeze + Send> MutexArc<T> {
-
-    /**
-     * As unsafe_access.
-     *
-     * The difference between access and unsafe_access is that the former
-     * forbids mutexes to be nested. While unsafe_access can be used on
-     * MutexArcs without freezable interiors, this safe version of access
-     * requires the Freeze bound, which prohibits access on MutexArcs which
-     * might contain nested MutexArcs inside.
-     *
-     * The purpose of this is to offer a safe implementation of MutexArc to be
-     * used instead of RWArc in cases where no readers are needed and slightly
-     * better performance is required.
-     *
-     * Both methods have the same failure behaviour as unsafe_access and
-     * unsafe_access_cond.
-     */
-    #[inline]
-    pub fn access<U>(&self, blk: |x: &mut T| -> U) -> U {
-        unsafe { self.unsafe_access(blk) }
-    }
-
-    /// As unsafe_access_cond but safe and Freeze.
-    #[inline]
-    pub fn access_cond<U>(&self,
-                          blk: |x: &mut T, c: &Condvar| -> U)
-                          -> U {
-        unsafe { self.unsafe_access_cond(blk) }
+        unsafe {
+            (&(*state).lock).lock_cond(|cond| {
+                check_poison(true, (*state).failed);
+                let _z = PoisonOnFail::new(&mut (*state).failed);
+                blk(&mut (*state).data,
+                    &Condvar {is_mutex: true,
+                            failed: &(*state).failed,
+                            cond: cond })
+            })
+        }
     }
 }
 
@@ -590,7 +554,6 @@ pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
 
 impl<T:Clone+Send+Freeze> Clone for CowArc<T> {
     /// Duplicate a Copy-on-write Arc. See arc::clone for more details.
-    #[inline]
     fn clone(&self) -> CowArc<T> {
         CowArc { x: self.x.clone() }
     }
@@ -692,20 +655,18 @@ fn test_mutex_arc_poison() {
     }
 
     #[test]
-    fn test_unsafe_mutex_arc_nested() {
-        unsafe {
-            // Tests nested mutexes and access
-            // to underlaying data.
-            let arc = ~MutexArc::new(1);
-            let arc2 = ~MutexArc::new(*arc);
-            task::spawn(proc() {
-                (*arc2).unsafe_access(|mutex| {
-                    (*mutex).access(|one| {
-                        assert!(*one == 1);
-                    })
+    fn test_mutex_arc_nested() {
+        // Tests nested mutexes and access
+        // to underlaying data.
+        let arc = ~MutexArc::new(1);
+        let arc2 = ~MutexArc::new(*arc);
+        task::spawn(proc() {
+            (*arc2).access(|mutex| {
+                (*mutex).access(|one| {
+                    assert!(*one == 1);
                 })
-            });
-        }
+            })
+        });
     }
 
     #[test]
index 9ca2f1fd7ffe32430756d4ea8bac5b8b0a9f39ed..923f12ed1d19aac4db99fd1eb296469782a0e548 100644 (file)
@@ -460,7 +460,7 @@ pub fn try_lock<'a>(&'a mut self) -> Option<Guard<'a>> {
 
     /// Acquires a mutex, blocking the current task until it is able to do so.
     ///
-    /// This function will block the local task until it is availble to acquire
+    /// This function will block the local task until it is available to acquire
     /// the mutex. Upon returning, the task is the only task with the mutex
     /// held. An RAII guard is returned to allow scoped unlock of the lock. When
     /// the guard goes out of scope, the mutex will be unlocked.
index 1a3ebf3ce5d1cccdbd04140d1ec338f59cebcc02..1bf82573c494909b7b2b8455b327f703d65ca791 100644 (file)
@@ -64,7 +64,7 @@ pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                                                    "inline assembly must be a string literal.") {
                     Some((s, st)) => (s, st),
                     // let compilation continue
-                    None => return MacResult::dummy_expr(),
+                    None => return MacResult::dummy_expr(sp),
                 };
                 asm = s;
                 asm_str_style = Some(style);
index 3dac82ae3b77f5e6ef0b57ebad59dde4cfbac2b4..e6fffe8b53f4817c11992b72d635f64c935da510 100644 (file)
@@ -101,6 +101,7 @@ pub trait AnyMacro {
     fn make_stmt(&self) -> @ast::Stmt;
 }
 
+
 pub enum MacResult {
     MRExpr(@ast::Expr),
     MRItem(@ast::Item),
@@ -112,10 +113,15 @@ impl MacResult {
     /// type signatures after emitting a non-fatal error (which stop
     /// compilation well before the validity (or otherwise)) of the
     /// expression are checked.
-    pub fn dummy_expr() -> MacResult {
-        MRExpr(@ast::Expr {
-                id: ast::DUMMY_NODE_ID, node: ast::ExprLogLevel, span: codemap::DUMMY_SP
-            })
+    pub fn raw_dummy_expr(sp: codemap::Span) -> @ast::Expr {
+        @ast::Expr {
+            id: ast::DUMMY_NODE_ID,
+            node: ast::ExprLogLevel,
+            span: sp
+        }
+    }
+    pub fn dummy_expr(sp: codemap::Span) -> MacResult {
+        MRExpr(MacResult::raw_dummy_expr(sp))
     }
 }
 
index 39bb870b969a0798489aa86390c1101a0d5432fd..68aa757c524fb3f9b32aecc12e36938fafa9188f 100644 (file)
@@ -21,7 +21,7 @@
 pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult {
     // Gather all argument expressions
     let exprs = match get_exprs_from_tts(cx, sp, tts) {
-        None => return MacResult::dummy_expr(),
+        None => return MacResult::dummy_expr(sp),
         Some(e) => e,
     };
     let mut bytes = ~[];
index c13f9bf92af022257248a152aa18b7ee090b5216..5316b8f721248d3a10613360cc477ade984edf97 100644 (file)
@@ -21,7 +21,7 @@ pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
                          tts: &[ast::TokenTree]) -> base::MacResult {
     let es = match base::get_exprs_from_tts(cx, sp, tts) {
         Some(e) => e,
-        None => return base::MacResult::dummy_expr()
+        None => return base::MacResult::dummy_expr(sp)
     };
     let mut accumulator = ~"";
     for e in es.move_iter() {
index 15e9d31daa00fc24c4841f131f6364647fe56356..85cfd4f61e414fc6f53a7ec23343d9c7769f32da 100644 (file)
@@ -25,7 +25,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                 ast::TTTok(_, token::COMMA) => (),
                 _ => {
                     cx.span_err(sp, "concat_idents! expecting comma.");
-                    return MacResult::dummy_expr();
+                    return MacResult::dummy_expr(sp);
                 }
             }
         } else {
@@ -35,7 +35,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                 }
                 _ => {
                     cx.span_err(sp, "concat_idents! requires ident args.");
-                    return MacResult::dummy_expr();
+                    return MacResult::dummy_expr(sp);
                 }
             }
         }
index c23a1ce1e28d5f8592ec559bec8a12323cf1b7bb..fec1e70af0735719cc8a8dcf8ac9acd9186229de 100644 (file)
@@ -26,7 +26,7 @@
 pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
     -> base::MacResult {
     let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") {
-        None => return MacResult::dummy_expr(),
+        None => return MacResult::dummy_expr(sp),
         Some(v) => v
     };
 
@@ -42,14 +42,14 @@ pub fn expand_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
     let exprs = match get_exprs_from_tts(cx, sp, tts) {
         Some([]) => {
             cx.span_err(sp, "env! takes 1 or 2 arguments");
-            return MacResult::dummy_expr();
+            return MacResult::dummy_expr(sp);
         }
-        None => return MacResult::dummy_expr(),
+        None => return MacResult::dummy_expr(sp),
         Some(exprs) => exprs
     };
 
     let var = match expr_to_str(cx, exprs[0], "expected string literal") {
-        None => return MacResult::dummy_expr(),
+        None => return MacResult::dummy_expr(sp),
         Some((v, _style)) => v
     };
     let msg = match exprs.len() {
@@ -60,13 +60,13 @@ pub fn expand_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
         }
         2 => {
             match expr_to_str(cx, exprs[1], "expected string literal") {
-                None => return MacResult::dummy_expr(),
+                None => return MacResult::dummy_expr(sp),
                 Some((s, _style)) => s
             }
         }
         _ => {
             cx.span_err(sp, "env! takes 1 or 2 arguments");
-            return MacResult::dummy_expr();
+            return MacResult::dummy_expr(sp);
         }
     };
 
index 97766e1a14b487fae56da4fa7b40bad6c3a9a9a2..4b81713f7d0c9a4b4cb22b97ab5b579d63894689 100644 (file)
@@ -51,7 +51,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
                             format!("expected macro name without module \
                                   separators"));
                         // let compilation continue
-                        return e;
+                        return MacResult::raw_dummy_expr(e.span);
                     }
                     let extname = pth.segments[0].identifier;
                     let extnamestr = token::get_ident(extname);
@@ -64,7 +64,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
                                         extnamestr.get()));
 
                             // let compilation continue
-                            return e;
+                            return MacResult::raw_dummy_expr(e.span);
                         }
                         Some(&NormalTT(ref expandfun, exp_span)) => {
                             fld.cx.bt_push(ExpnInfo {
@@ -98,7 +98,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
                                             extnamestr.get()
                                         )
                                     );
-                                    return e;
+                                    return MacResult::raw_dummy_expr(e.span);
                                 }
                             };
 
@@ -111,7 +111,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
                                 format!("'{}' is not a tt-style macro",
                                         extnamestr.get())
                             );
-                            return e;
+                            return MacResult::raw_dummy_expr(e.span);
                         }
                     };
 
index 01d348595b88c08d993c0b1804f048e364a8defd..d7a2647c34d07af9aaebdb7ae3800f16b4c97a3f 100644 (file)
@@ -607,6 +607,8 @@ fn to_expr(&self, extra: @ast::Expr) -> @ast::Expr {
         let mut lets = ~[];
         let mut locals = ~[];
         let mut names = vec::from_fn(self.name_positions.len(), |_| None);
+        let mut pats = ~[];
+        let mut heads = ~[];
 
         // First, declare all of our methods that are statics
         for &method in self.method_statics.iter() {
@@ -653,8 +655,8 @@ fn to_expr(&self, extra: @ast::Expr) -> @ast::Expr {
             if self.arg_types[i].is_none() { continue } // error already generated
 
             let name = self.ecx.ident_of(format!("__arg{}", i));
-            let e = self.ecx.expr_addr_of(e.span, e);
-            lets.push(self.ecx.stmt_let(e.span, false, name, e));
+            pats.push(self.ecx.pat_ident(e.span, name));
+            heads.push(self.ecx.expr_addr_of(e.span, e));
             locals.push(self.format_arg(e.span, Exact(i),
                                         self.ecx.expr_ident(e.span, name)));
         }
@@ -664,8 +666,8 @@ fn to_expr(&self, extra: @ast::Expr) -> @ast::Expr {
             }
 
             let lname = self.ecx.ident_of(format!("__arg{}", *name));
-            let e = self.ecx.expr_addr_of(e.span, e);
-            lets.push(self.ecx.stmt_let(e.span, false, lname, e));
+            pats.push(self.ecx.pat_ident(e.span, lname));
+            heads.push(self.ecx.expr_addr_of(e.span, e));
             names[*self.name_positions.get(name)] =
                 Some(self.format_arg(e.span,
                                      Named((*name).clone()),
@@ -706,8 +708,40 @@ fn to_expr(&self, extra: @ast::Expr) -> @ast::Expr {
         let res = self.ecx.expr_ident(self.fmtsp, resname);
         let result = self.ecx.expr_call(extra.span, extra, ~[
                             self.ecx.expr_addr_of(extra.span, res)]);
-        self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,
-                                           Some(result)))
+        let body = self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,
+                                                      Some(result)));
+
+        // Constructs an AST equivalent to:
+        //
+        //      match (&arg0, &arg1) {
+        //          (tmp0, tmp1) => body
+        //      }
+        //
+        // It was:
+        //
+        //      let tmp0 = &arg0;
+        //      let tmp1 = &arg1;
+        //      body
+        //
+        // Because of #11585 the new temporary lifetime rule, the enclosing
+        // statements for these temporaries become the let's themselves.
+        // If one or more of them are RefCell's, RefCell borrow() will also
+        // end there; they don't last long enough for body to use them. The
+        // match expression solves the scope problem.
+        //
+        // Note, it may also very well be transformed to:
+        //
+        //      match arg0 {
+        //          ref tmp0 => {
+        //              match arg1 => {
+        //                  ref tmp1 => body } } }
+        //
+        // But the nested match expression is proved to perform not as well
+        // as series of let's; the first approach does.
+        let pat = self.ecx.pat(self.fmtsp, ast::PatTup(pats));
+        let arm = self.ecx.arm(self.fmtsp, ~[pat], body);
+        let head = self.ecx.expr(self.fmtsp, ast::ExprTup(heads));
+        self.ecx.expr_match(self.fmtsp, head, ~[arm])
     }
 
     fn format_arg(&self, sp: Span, argno: Position, arg: @ast::Expr)
@@ -811,7 +845,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
                                 expr,
                                 "format argument must be a string literal.") {
         Some((fmt, _)) => fmt,
-        None => return efmt
+        None => return MacResult::raw_dummy_expr(sp)
     };
 
     let mut parser = parse::Parser::new(fmt.get());
@@ -829,7 +863,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
     match parser.errors.shift() {
         Some(error) => {
             cx.ecx.span_err(efmt.span, "invalid format string: " + error);
-            return efmt;
+            return MacResult::raw_dummy_expr(sp);
         }
         None => {}
     }
index 150f054b2afe4f43bf97bccab4c7c12189ff3101..c81ee55c23768aa75d1ec0eaf8a5f27432ee17fc 100644 (file)
@@ -83,7 +83,7 @@ pub fn expand_include(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
     -> base::MacResult {
     let file = match get_single_str_from_tts(cx, sp, tts, "include!") {
         Some(f) => f,
-        None => return MacResult::dummy_expr(),
+        None => return MacResult::dummy_expr(sp),
     };
     // The file will be added to the code map by the parser
     let mut p =
@@ -101,13 +101,13 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
     -> base::MacResult {
     let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") {
         Some(f) => f,
-        None => return MacResult::dummy_expr()
+        None => return MacResult::dummy_expr(sp)
     };
     let file = res_rel_file(cx, sp, &Path::new(file));
     let bytes = match File::open(&file).read_to_end() {
         Err(e) => {
             cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e));
-            return MacResult::dummy_expr();
+            return MacResult::dummy_expr(sp);
         }
         Ok(bytes) => bytes,
     };
@@ -123,7 +123,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
         }
         None => {
             cx.span_err(sp, format!("{} wasn't a utf-8 file", file.display()));
-            return MacResult::dummy_expr();
+            return MacResult::dummy_expr(sp);
         }
     }
 }
@@ -133,13 +133,13 @@ pub fn expand_include_bin(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
 {
     let file = match get_single_str_from_tts(cx, sp, tts, "include_bin!") {
         Some(f) => f,
-        None => return MacResult::dummy_expr()
+        None => return MacResult::dummy_expr(sp)
     };
     let file = res_rel_file(cx, sp, &Path::new(file));
     match File::open(&file).read_to_end() {
         Err(e) => {
             cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e));
-            return MacResult::dummy_expr();
+            return MacResult::dummy_expr(sp);
         }
         Ok(bytes) => {
             base::MRExpr(cx.expr_lit(sp, ast::LitBinary(Rc::new(bytes))))
index 4189ea6a967a82ec1c653b34236499425996cb0e..db2c9dcddb6dcdee3c439dc839c082a5d0ccc60f 100644 (file)
@@ -33,7 +33,7 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt,
         cx.set_trace_macros(false);
     } else {
         cx.span_err(sp, "trace_macros! only accepts `true` or `false`");
-        return base::MacResult::dummy_expr();
+        return base::MacResult::dummy_expr(sp);
     }
 
     rust_parser.bump();
diff --git a/src/test/compile-fail/issue-11692.rs b/src/test/compile-fail/issue-11692.rs
new file mode 100644 (file)
index 0000000..aed2c4d
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    print!(test!());
+    //~^ ERROR: macro undefined: 'test'
+    //~^^ ERROR: format argument must be a string literal
+
+    concat!(test!());
+    //~^ ERROR: macro undefined: 'test'
+    //~^^ ERROR: expected a literal
+}
index fcd15a2121931c37534dec8ff7ad85b56d89f0dc..8d281a0b174acc0fd54d0854569d51a00058a2aa 100644 (file)
@@ -16,7 +16,7 @@ pub enum TraitWrapper {
 
 fn get_tw_map<'lt>(tw: &'lt TraitWrapper) -> &'lt MyTrait {
     match *tw {
-        A(~ref map) => map, //~ ERROR found a ~-box pattern
+        A(~ref map) => map, //~ ERROR found a `~`-box pattern
     }
 }
 
index ae523e1a9c4742590c789a6152dbed9b523927d2..b7c440d30b3aee61527604bfc5e56060e71fa924 100644 (file)
@@ -24,12 +24,12 @@ fn main() {
 
     match (true, false) {
         ~(true, false) => ()
-        //~^ ERROR mismatched types: expected `(bool,bool)` but found a ~-box pattern
+        //~^ ERROR mismatched types: expected `(bool,bool)` but found a `~`-box pattern
     }
 
     match (true, false) {
         &(true, false) => ()
-        //~^ ERROR mismatched types: expected `(bool,bool)` but found an &-pointer pattern
+        //~^ ERROR mismatched types: expected `(bool,bool)` but found an `&`-pointer pattern
     }
 
 
diff --git a/src/test/compile-fail/mutex-arc-nested.rs b/src/test/compile-fail/mutex-arc-nested.rs
deleted file mode 100644 (file)
index 34c56f9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.
-
-extern crate sync;
-
-use std::task;
-use sync::MutexArc;
-
-fn test_mutex_arc_nested() {
-    let arc = ~MutexArc::new(1);
-    let arc2 = ~MutexArc::new(*arc);
-
-    task::spawn(proc() {
-        (*arc2).access(|mutex| { //~ ERROR instantiating a type parameter with an incompatible type
-        })
-    });
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/privacy-ns1.rs b/src/test/compile-fail/privacy-ns1.rs
new file mode 100644 (file)
index 0000000..541356f
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check we do the correct privacy checks when we import a name and there is an
+// item with that name in both the value and type namespaces.
+
+#[feature(globs)];
+#[allow(dead_code)];
+#[allow(unused_imports)];
+
+// public type, private value
+pub mod foo1 {
+    pub trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_glob1() {
+    use foo1::*;
+
+    Bar();  //~ ERROR unresolved name `Bar`.
+}
+
+// private type, public value
+pub mod foo2 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    pub fn Bar() { }
+}
+
+fn test_glob2() {
+    use foo2::*;
+
+    let _x: ~Bar;  //~ ERROR use of undeclared type name `Bar`
+}
+
+// neither public
+pub mod foo3 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_glob3() {
+    use foo3::*;
+
+    Bar();  //~ ERROR unresolved name `Bar`.
+    let _x: ~Bar;  //~ ERROR  use of undeclared type name `Bar`
+}
+
+fn main() {
+}
+
diff --git a/src/test/compile-fail/privacy-ns2.rs b/src/test/compile-fail/privacy-ns2.rs
new file mode 100644 (file)
index 0000000..e293153
--- /dev/null
@@ -0,0 +1,91 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check we do the correct privacy checks when we import a name and there is an
+// item with that name in both the value and type namespaces.
+
+#[feature(globs)];
+#[allow(dead_code)];
+#[allow(unused_imports)];
+
+// public type, private value
+pub mod foo1 {
+    pub trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_single1() {
+    // In an ideal world, these would be private instead of inaccessible.
+    use foo1::Bar;  //~ ERROR `Bar` is inaccessible
+
+    Bar();
+}
+
+fn test_list1() {
+    use foo1::{Bar,Baz};  //~ ERROR `Bar` is inaccessible
+
+    Bar();
+}
+
+// private type, public value
+pub mod foo2 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    pub fn Bar() { }
+}
+
+fn test_single2() {
+    use foo2::Bar;  //~ ERROR `Bar` is private
+
+    let _x : ~Bar;
+}
+
+fn test_list2() {
+    use foo2::{Bar,Baz};  //~ ERROR `Bar` is private
+
+    let _x: ~Bar;
+}
+
+// neither public
+pub mod foo3 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_unused3() {
+    use foo3::Bar;  //~ ERROR `Bar` is private
+    use foo3::{Bar,Baz};  //~ ERROR `Bar` is private
+}
+
+fn test_single3() {
+    use foo3::Bar;  //~ ERROR `Bar` is private
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn test_list3() {
+    use foo3::{Bar,Baz};  //~ ERROR `Bar` is private
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn main() {
+}
+
diff --git a/src/test/run-make/rustdoc-json/Makefile b/src/test/run-make/rustdoc-json/Makefile
new file mode 100644 (file)
index 0000000..5e6ab4b
--- /dev/null
@@ -0,0 +1,4 @@
+-include ../tools.mk
+all:
+       $(RUSTDOC) -w json -o $(TMPDIR)/doc.json foo.rs
+       $(RUSTDOC) -o $(TMPDIR)/doc $(TMPDIR)/doc.json
diff --git a/src/test/run-make/rustdoc-json/foo.rs b/src/test/run-make/rustdoc-json/foo.rs
new file mode 100644 (file)
index 0000000..818ec1e
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[crate_id = "foo#0.1"];
+
+//! Very docs
+
+pub mod bar {
+
+    /// So correct
+    pub mod baz {
+        /// Much detail
+        pub fn baz() { }
+    }
+
+    /// *wow*
+    pub trait Doge { }
+}
diff --git a/src/test/run-make/staticlib-blank-lib/Makefile b/src/test/run-make/staticlib-blank-lib/Makefile
new file mode 100644 (file)
index 0000000..c56d121
--- /dev/null
@@ -0,0 +1,6 @@
+-include ../tools.mk
+
+all:
+       ar crus libfoo.a foo.rs
+       ar d libfoo.a foo.rs
+       $(RUSTC) foo.rs
diff --git a/src/test/run-make/staticlib-blank-lib/foo.rs b/src/test/run-make/staticlib-blank-lib/foo.rs
new file mode 100644 (file)
index 0000000..b3d9c00
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[crate_type = "staticlib"];
+
+#[link(name = "foo", kind = "static")]
+extern {}
+
+fn main() {}
diff --git a/src/test/run-pass/format-ref-cell.rs b/src/test/run-pass/format-ref-cell.rs
new file mode 100644 (file)
index 0000000..6428d49
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cell::RefCell;
+
+pub fn main() {
+    let name = RefCell::new("rust");
+    let what = RefCell::new("rocks");
+    let msg = format!("{name:?} {:?}", what.borrow().get(), name=name.borrow().get());
+    assert_eq!(msg, ~"&\"rust\" &\"rocks\"");
+}
diff --git a/src/test/run-pass/issue-7660.rs b/src/test/run-pass/issue-7660.rs
new file mode 100644 (file)
index 0000000..7f1382c
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regresion test for issue 7660
+// rvalue lifetime too short when equivalent `match` works
+
+use std::hashmap::HashMap;
+
+struct A(int, int);
+
+pub fn main() {
+    let mut m: HashMap<int, A> = HashMap::new();
+    m.insert(1, A(0, 0));
+
+    let A(ref _a, ref _b) = *m.get(&1);
+    let (a, b) = match *m.get(&1) { A(ref _a, ref _b) => (_a, _b) };
+}
diff --git a/src/test/run-pass/privacy-ns.rs b/src/test/run-pass/privacy-ns.rs
new file mode 100644 (file)
index 0000000..c933e5b
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-fast
+
+// Check we do the correct privacy checks when we import a name and there is an
+// item with that name in both the value and type namespaces.
+
+#[feature(globs)];
+#[allow(dead_code)];
+#[allow(unused_imports)];
+
+// public type, private value
+pub mod foo1 {
+    pub trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_unused1() {
+    use foo1::Bar;
+    use foo1::{Bar,Baz};
+    use foo1::*;
+}
+
+fn test_single1() {
+    use foo1::Bar;
+
+    let _x: ~Bar;
+}
+
+fn test_list1() {
+    use foo1::{Bar,Baz};
+
+    let _x: ~Bar;
+}
+
+fn test_glob1() {
+    use foo1::*;
+
+    let _x: ~Bar;
+}
+
+// private type, public value
+pub mod foo2 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    pub fn Bar() { }
+}
+
+fn test_unused2() {
+    use foo2::Bar;
+    use foo2::{Bar,Baz};
+    use foo2::*;
+}
+
+fn test_single2() {
+    use foo2::Bar;
+
+    Bar();
+}
+
+fn test_list2() {
+    use foo2::{Bar,Baz};
+
+    Bar();
+}
+
+fn test_glob2() {
+    use foo2::*;
+
+    Bar();
+}
+
+// public type, public value
+pub mod foo3 {
+    pub trait Bar {
+    }
+    pub struct Baz;
+
+    pub fn Bar() { }
+}
+
+fn test_unused3() {
+    use foo3::Bar;
+    use foo3::{Bar,Baz};
+    use foo3::*;
+}
+
+fn test_single3() {
+    use foo3::Bar;
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn test_list3() {
+    use foo3::{Bar,Baz};
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn test_glob3() {
+    use foo3::*;
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn main() {
+}
+
diff --git a/src/test/run-pass/self-re-assign.rs b/src/test/run-pass/self-re-assign.rs
new file mode 100644 (file)
index 0000000..041c5cf
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Ensure assigning an owned or managed variable to itself works. In particular,
+// that we do not glue_drop before we glue_take (#3290).
+
+use std::rc::Rc;
+
+pub fn main() {
+   let mut x = ~3;
+   x = x;
+   assert!(*x == 3);
+
+   let mut x = Rc::new(3);
+   x = x;
+   assert!(*x.borrow() == 3);
+}