]> git.lizzy.rs Git - rust.git/commitdiff
rollup merge of #18356 : jakub-/const-pattern-suptype
authorAlex Crichton <alex@alexcrichton.com>
Mon, 27 Oct 2014 16:08:10 +0000 (09:08 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Mon, 27 Oct 2014 22:12:47 +0000 (15:12 -0700)
93 files changed:
.mailmap
configure
mk/docs.mk
src/compiletest/compiletest.rs
src/doc/guide-crates.md
src/doc/guide-plugin.md
src/doc/guide-strings.md
src/doc/guide.md
src/doc/index.md
src/doc/po4a.conf
src/etc/emacs/rust-mode-tests.el
src/liballoc/arc.rs
src/liballoc/heap.rs
src/liballoc/lib.rs
src/liballoc/libc_heap.rs [deleted file]
src/libcollections/btree/map.rs
src/libcollections/btree/node.rs
src/libcollections/slice.rs
src/libcollections/string.rs
src/libcollections/vec.rs
src/libcore/cell.rs
src/libcore/raw.rs
src/libcoretest/cell.rs
src/librand/chacha.rs
src/librustc/back/write.rs
src/librustc/diagnostics.rs
src/librustc/middle/borrowck/check_loans.rs
src/librustc/middle/borrowck/gather_loans/gather_moves.rs
src/librustc/middle/borrowck/gather_loans/lifetime.rs
src/librustc/middle/borrowck/gather_loans/mod.rs
src/librustc/middle/borrowck/gather_loans/restrictions.rs
src/librustc/middle/borrowck/mod.rs
src/librustc/middle/check_const.rs
src/librustc/middle/check_static.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/traits/doc.rs
src/librustc/middle/traits/select.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/check/regionck.rs
src/librustc/middle/typeck/check/vtable.rs [new file with mode: 0644]
src/librustc/middle/typeck/check/vtable2.rs [deleted file]
src/librustc/middle/typeck/check/wf.rs
src/librustrt/c_str.rs
src/librustrt/mutex.rs
src/libstd/c_vec.rs
src/libstd/collections/hashmap/set.rs
src/libstd/io/mem.rs
src/libstd/io/net/udp.rs
src/libstd/rt/mod.rs
src/libsyntax/ast.rs
src/libsyntax/config.rs
src/libsyntax/diagnostics/plugin.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/concat_idents.rs
src/libsyntax/ext/log_syntax.rs
src/libsyntax/ext/quote.rs
src/libsyntax/ext/trace_macros.rs
src/libsyntax/ext/tt/macro_parser.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/ext/tt/transcribe.rs
src/libsyntax/fold.rs
src/libsyntax/owned_slice.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libterm/win.rs
src/test/auxiliary/roman_numerals.rs
src/test/bench/shootout-reverse-complement.rs
src/test/compile-fail/issue-12863.rs [new file with mode: 0644]
src/test/compile-fail/issue-14721.rs [new file with mode: 0644]
src/test/compile-fail/issue-16683.rs [new file with mode: 0644]
src/test/compile-fail/issue-17551.rs [new file with mode: 0644]
src/test/compile-fail/issue-18118.rs [new file with mode: 0644]
src/test/compile-fail/issue-18252.rs [new file with mode: 0644]
src/test/compile-fail/issue-18294.rs [new file with mode: 0644]
src/test/compile-fail/issue-18343.rs [new file with mode: 0644]
src/test/compile-fail/issue-6991.rs [new file with mode: 0644]
src/test/compile-fail/issue-7867.rs [new file with mode: 0644]
src/test/compile-fail/unboxed-closure-immutable-capture.rs [new file with mode: 0644]
src/test/run-pass/closure-syntax.rs
src/test/run-pass/dst-coercions.rs
src/test/run-pass/issue-12028.rs [new file with mode: 0644]
src/test/run-pass/issue-14901.rs [new file with mode: 0644]
src/test/run-pass/issue-16560.rs [new file with mode: 0644]
src/test/run-pass/issue-16668.rs [new file with mode: 0644]
src/test/run-pass/out-pointer-aliasing.rs [new file with mode: 0644]
src/test/run-pass/realloc-16687.rs
src/test/run-pass/trait-cache-issue-18209.rs [new file with mode: 0644]
src/test/run-pass/unboxed-closures-move-mutable.rs [new file with mode: 0644]
src/test/run-pass/vec-dst.rs

index 637b9ec8c4efb78e6751cf39aae7c0555e8b44a6..f529fe1bb78c3e6b9643e2f4e6d318bbaf12a2b7 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -5,8 +5,104 @@
 # email addresses.
 #
 
-Elly Jones <elly@leptoquark.net>
-ILyoan <ilyoan@gmail.com>
+Aaron Todd <github@opprobrio.us>
+Ahmed Charles <ahmedcharles@gmail.com> <acharles@outlook.com>
+Alex Lyon <arcterus@mail.com> <Arcterus@mail.com>
+Alex Rønne Petersen <alex@lycus.org>
+Andreas Gal <gal@mozilla.com> <andreas.gal@gmail.com>
+Andrew Poelstra <asp11@sfu.ca> <apoelstra@wpsoftware.net>
+Anton Löfgren <anton.lofgren@gmail.com> <alofgren@op5.com>
+Ariel Ben-Yehuda <arielb1@mail.tau.ac.il> <ariel.byd@gmail.com>
+Austin Seipp <mad.one@gmail.com> <as@hacks.yi.org>
+Ben Alpert <ben@benalpert.com> <spicyjalapeno@gmail.com>
+Benjamin Jackman <ben@jackman.biz>
+Björn Steinbrink <bsteinbr@gmail.com> <B.Steinbrink@gmx.de>
+blake2-ppc <ulrik.sverdrup@gmail.com> <blake2-ppc>
+Boris Egorov <jightuse@gmail.com> <egorov@linux.com>
+Brian Anderson <banderson@mozilla.com> <andersrb@gmail.com>
+Brian Dawn <brian.t.dawn@gmail.com>
+Carl-Anton Ingmarsson <mail@carlanton.se> <ca.ingmarsson@gmail.com>
+Carol Willing <carolcode@willingconsulting.com>
+Chris Pressey <cpressey@gmail.com>
+Clark Gaebel <cg.wowus.cg@gmail.com> <cgaebel@mozilla.com>
+David Klein <david.klein@baesystemsdetica.com>
+David Manescu <david.manescu@gmail.com> <dman2626@uni.sydney.edu.au>
+Damien Schoof <damien.schoof@gmail.com>
+Derek Chiang <derekchiang93@gmail.com> Derek Chiang (Enchi Jiang) <derekchiang93@gmail.com>
+Dylan Braithwaite <dylanbraithwaite1@gmail.com> <mail@dylanb.me>
+Eduardo Bautista <me@eduardobautista.com> <mail@eduardobautista.com>
+Eduardo Bautista <me@eduardobautista.com> <=>
+Elliott Slaughter <elliottslaughter@gmail.com> <eslaughter@mozilla.com>
+Elly Fong-Jones <elly@leptoquark.net>
+Eric Holk <eric.holk@gmail.com> <eholk@mozilla.com>
+Eric Holk <eric.holk@gmail.com> <eholk@cs.indiana.edu>
+Eric Holmes <eric@ejholmes.net>
+Eric Reed <ecreed@cs.washington.edu> <ereed@mozilla.com>
+Erick Tryzelaar <erick.tryzelaar@gmail.com> <etryzelaar@iqt.org>
+Evgeny Sologubov
+Falco Hirschenberger <falco.hirschenberger@gmail.com> <hirschen@itwm.fhg.de>
+Gareth Daniel Smith <garethdanielsmith@gmail.com>
+Georges Dubus <georges.dubus@gmail.com> <georges.dubus@compiletoi.net>
+Graham Fawcett <fawcett@uwindsor.ca> <graham.fawcett@gmail.com>
+Graydon Hoare <graydon@mozilla.com> <graydon@pobox.com>
+Heather <heather@cynede.net> <Heather@cynede.net>
+Heather <heather@cynede.net> <Cynede@Gentoo.org>
+Ilyong Cho <ilyoan@gmail.com>
+J. J. Weber <jjweber@gmail.com>
+Jakub Bukaj <jakub@jakub.cc>
+Jakub Bukaj <jakub@jakub.cc> <jakubw@jakubw.net>
+James Deng <cnjamesdeng@gmail.com> <cnJamesDeng@gmail.com>
+James Miller <bladeon@gmail.com> <james@aatch.net>
+Jason Orendorff <jorendorff@mozilla.com> <jason@mozmac-2.local>
+Jason Orendorff <jorendorff@mozilla.com> <jason.orendorff@gmail.com>
+Jeremy Letang <letang.jeremy@gmail.com>
+Jihyun Yu <jihyun@nclab.kaist.ac.kr> jihyun <jihyun@nablecomm.com>
+Jihyun Yu <jihyun@nclab.kaist.ac.kr> <yjh0502@gmail.com>
+John Clements <clements@racket-lang.org> <clements@brinckerhoff.org>
+Jorge Aparicio <japaric@linux.com> <japaricious@gmail.com>
+Jonathan Bailey <jbailey@mozilla.com> <jbailey@jbailey-20809.local>
 Junyoung Cho <june0.cho@samsung.com>
+Jyun-Yan You <jyyou.tw@gmail.com> <jyyou@cs.nctu.edu.tw>
+Kang Seonghoon <kang.seonghoon@mearie.org> <public+git@mearie.org>
+Keegan McAllister <kmcallister@mozilla.com> <mcallister.keegan@gmail.com>
+Kyeongwoon Lee <kyeongwoon.lee@samsung.com>
+Lee Wondong <wdlee91@gmail.com>
+Lennart Kudling <github@kudling.de>
+Lindsey Kuper <lindsey@composition.al> <lindsey@rockstargirl.org>
+Lindsey Kuper <lindsey@composition.al> <lkuper@mozilla.com>
+Luqman Aden <me@luqman.ca> <laden@mozilla.com>
+Luqman Aden <me@luqman.ca> <laden@csclub.uwaterloo.ca>
+Luke Metz <luke.metz@students.olin.edu>
+Makoto Nakashima <makoto.nksm+github@gmail.com> <makoto.nksm@gmail.com>
+Makoto Nakashima <makoto.nksm+github@gmail.com> gifnksm <makoto.nksm+github@gmail.com>
+Margaret Meyerhofer <mmeyerho@andrew.cmu.edu> <mmeyerho@andrew>
+Mark Sinclair <mark.edward.x@gmail.com>
+Mark Sinclair <mark.edward.x@gmail.com> =Mark Sinclair <=125axel125@gmail.com>
+Matt Brubeck <mbrubeck@limpet.net> <mbrubeck@cs.hmc.edu>
+Matthew Auld <matthew.auld@intel.com>
+Matthew McPherrin <matthew@mcpherrin.ca> <matt@mcpherrin.ca>
 Matthijs Hofstra <thiezz@gmail.com>
+Michael Williams <m.t.williams@live.com>
+Michael Woerister <michaelwoerister@gmail> <michaelwoerister@gmail.com>
+Michael Woerister <michaelwoerister@gmail> <michaelwoerister@posteo>
+Neil Pankey <npankey@gmail.com> <neil@wire.im>
+Philipp Brüschweiler <blei42@gmail.com> <blei42@gmail.com>
+Philipp Brüschweiler <blei42@gmail.com> <bruphili@student.ethz.ch>
+Pradeep Kumar <gohanpra@gmail.com>
+Richard Diamond <wichard@vitalitystudios.com> <wichard@hahbee.co>
 Rob Arnold <robarnold@cs.cmu.edu>
+Robert Gawdzik <rgawdzik@hotmail.com> Robert Gawdzik â˜¢ <rgawdzik@hotmail.com>
+Robert Millar <robert.millar@cantab.net>
+Ryan Scheel <ryan.havvy@gmail.com>
+Seonghyun Kim <sh8281.kim@samsung.com>
+Simon Barber-Dueck <sbarberdueck@gmail.com> Simon BD <simon@server>
+Simon Sapin <simon@exyr.org> <simon.sapin@exyr.org>
+startling <tdixon51793@gmail.com>
+Steven Fackler <sfackler@gmail.com> <sfackler@palantir.com>
+Steven Stewart-Gallus <sstewartgallus00@langara.bc.ca> <sstewartgallus00@mylangara.bc.ca>
+Tim Chevalier <chevalier@alum.wellesley.edu> <catamorphism@gmail.com>
+Torsten Weber <TorstenWeber12@gmail.com> <torstenweber12@gmail.com>
+William Ting <io@williamting.com> <william.h.ting@gmail.com>
+Youngsoo Son <ysson83@gmail.com> <ysoo.son@samsung.com>
+Zack Corr <zack@z0w0.me> <zackcorr95@gmail.com>
+Zack Slayton <zack.slayton@gmail.com>
index 05bfdb3e9fd8a528efc4ab7a019003d0279e5fe4..89b11daf93863831d9bd1aaf35e909ccd286aacb 100755 (executable)
--- a/configure
+++ b/configure
@@ -151,11 +151,22 @@ validate_opt () {
     done
 }
 
-valopt() {
-    VAL_OPTIONS="$VAL_OPTIONS $1"
+# `valopt OPTION_NAME DEFAULT DOC` extracts a string-valued option
+# from command line, using provided default value for the option if
+# not present, and saves it to the generated config.mk.
+#
+# `valopt_nosave` is much the same, except that it does not save the
+# result to config.mk (instead the script should use `putvar` itself
+# later on to save it).  `valopt_core` is the core upon which the
+# other two are built.
 
-    local OP=$1
-    local DEFAULT=$2
+valopt_core() {
+    VAL_OPTIONS="$VAL_OPTIONS $2"
+
+    local SAVE=$1
+    local OP=$2
+    local DEFAULT=$3
+    shift
     shift
     shift
     local DOC="$*"
@@ -172,7 +183,10 @@ valopt() {
                 eval $V=$val
             fi
         done
-        putvar $V
+        if [ "$SAVE" = "save" ]
+        then
+            putvar $V
+        fi
     else
         if [ -z "$DEFAULT" ]
         then
@@ -183,11 +197,30 @@ valopt() {
     fi
 }
 
-opt() {
-    BOOL_OPTIONS="$BOOL_OPTIONS $1"
+valopt_nosave() {
+    valopt_core nosave "$@"
+}
+
+valopt() {
+    valopt_core save "$@"
+}
 
-    local OP=$1
-    local DEFAULT=$2
+# `opt OPTION_NAME DEFAULT DOC` extracts a boolean-valued option from
+# command line, using the provided default value (0/1) for the option
+# if not present, and saves it to the generated config.mk.
+#
+# `opt_nosave` is much the same, except that it does not save the
+# result to config.mk (instead the script should use `putvar` itself
+# later on to save it).  `opt_core` is the core upon which the other
+# two are built.
+
+opt_core() {
+    BOOL_OPTIONS="$BOOL_OPTIONS $2"
+
+    local SAVE=$1
+    local OP=$2
+    local DEFAULT=$3
+    shift
     shift
     shift
     local DOC="$*"
@@ -211,7 +244,10 @@ opt() {
                 FLAG=$(echo $FLAG | tr 'a-z' 'A-Z')
                 local V="CFG_${FLAG}_${OP}"
                 eval $V=1
-                putvar $V
+                if [ "$SAVE" = "save" ]
+                then
+                   putvar $V
+                fi
             fi
         done
     else
@@ -223,6 +259,14 @@ opt() {
      fi
 }
 
+opt_nosave() {
+    opt_core nosave "$@"
+}
+
+opt() {
+    opt_core save "$@"
+}
+
 envopt() {
     local NAME=$1
     local V="CFG_${NAME}"
@@ -422,38 +466,40 @@ opt llvm-assertions 1 "build LLVM with assertions"
 opt debug 1 "build with extra debug fun"
 opt ratchet-bench 0 "ratchet benchmarks"
 opt fast-make 0 "use .gitmodules as timestamp for submodule deps"
-opt manage-submodules 1 "let the build manage the git submodules"
 opt mingw-cross 0 "cross-compile for win32 using mingw"
-opt clang 0 "prefer clang to gcc for building the runtime"
 opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds"
 opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
-opt inject-std-version 1 "inject the current compiler version of libstd into programs"
 opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM"
 opt rpath 0 "build rpaths into rustc itself"
 opt nightly 0 "build nightly packages"
 opt verify-install 1 "verify installed binaries work"
-opt jemalloc 1 "build liballoc with jemalloc"
 # This is used by the automation to produce single-target nightlies
 opt dist-host-only 0 "only install bins for the host architecture"
-valopt prefix "/usr/local" "set installation prefix"
-valopt local-rust-root "/usr/local" "set prefix for local rust binary"
-valopt llvm-root "" "set LLVM root"
-valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
-valopt android-cross-path "/opt/ndk_standalone" "Android NDK standalone path"
-valopt mingw32-cross-path "" "MinGW32 cross compiler path"
-
-valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
-valopt host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples"
-valopt target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples"
+opt inject-std-version 1 "inject the current compiler version of libstd into programs"
+opt jemalloc 1 "build liballoc with jemalloc"
 
 valopt localstatedir "/var/lib" "local state directory"
 valopt sysconfdir "/etc" "install system configuration files"
 
 valopt datadir "${CFG_PREFIX}/share" "install data"
 valopt infodir "${CFG_PREFIX}/share/info" "install additional info"
-valopt mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
+valopt llvm-root "" "set LLVM root"
+valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
+valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
+valopt android-cross-path "/opt/ndk_standalone" "Android NDK standalone path"
+valopt mingw32-cross-path "" "MinGW32 cross compiler path"
+
+# Many of these are saved below during the "writing configuration" step
+# (others are conditionally saved).
+opt_nosave manage-submodules 1 "let the build manage the git submodules"
+opt_nosave clang 0 "prefer clang to gcc for building the runtime"
 
-valopt release-channel "dev" "the name of the release channel to build"
+valopt_nosave prefix "/usr/local" "set installation prefix"
+valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary"
+valopt_nosave host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples"
+valopt_nosave target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples"
+valopt_nosave mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
+valopt_nosave release-channel "dev" "the name of the release channel to build"
 
 # On windows we just store the libraries in the bin directory because
 # there's no rpath. This is where the build system itself puts libraries;
@@ -491,8 +537,8 @@ esac
 if [ ! -z "$CFG_ENABLE_NIGHTLY" ]
 then
     CFG_RELEASE_CHANNEL=nightly
-    putvar CFG_RELEASE_CHANNEL
 fi
+putvar CFG_RELEASE_CHANNEL
 
 step_msg "looking for build programs"
 
@@ -605,9 +651,20 @@ then
         err "no local rust to use"
     fi
 
-    LRV=`${CFG_LOCAL_RUST_ROOT}/bin/rustc${BIN_SUF} --version`
+    CMD="${CFG_LOCAL_RUST_ROOT}/bin/rustc${BIN_SUF}"
+    LRV=`$CMD --version`
+    if [ $? -ne 0 ]
+    then
+        step_msg "failure while running $CMD --version"
+        exit 1
+    fi
     step_msg "using rustc at: ${CFG_LOCAL_RUST_ROOT} with version: $LRV"
     putvar CFG_LOCAL_RUST_ROOT
+else
+    if [ ! -z "$CFG_LOCAL_RUST_ROOT" ]
+    then
+       warn "Use of --local-rust-root without --enable-local-rust"
+    fi
 fi
 
 # Force freebsd to build with clang; gcc doesn't like us there
@@ -615,7 +672,6 @@ if [ $CFG_OSTYPE = unknown-freebsd ]
 then
     step_msg "on FreeBSD, forcing use of clang"
     CFG_ENABLE_CLANG=1
-    putvar CFG_ENABLE_CLANG
 fi
 
 if [ -z "$CFG_ENABLE_CLANG" -a -z "$CFG_GCC" ]
@@ -632,12 +688,10 @@ then
     then
         step_msg "on OS X 10.9, forcing use of clang"
         CFG_ENABLE_CLANG=1
-        putvar CFG_ENABLE_CLANG
     else
         if [ $("$CFG_GCC" --version 2>&1 | grep -c ' 4\.[0-6]') -ne 0 ]; then
             step_msg "older GCC found, using clang instead"
             CFG_ENABLE_CLANG=1
-            putvar CFG_ENABLE_CLANG
         else
             # on OS X, with xcode 5 and newer, certain developers may have
             # cc, gcc and g++ point to a  mixture of clang and gcc
@@ -663,6 +717,13 @@ then
     fi
 fi
 
+# Okay, at this point, we have made up our minds about whether we are
+# going to force CFG_ENABLE_CLANG or not; save the setting if so.
+if [ ! -z "$CFG_ENABLE_CLANG" ]
+then
+    putvar CFG_ENABLE_CLANG
+fi
+
 if [ ! -z "$CFG_LLVM_ROOT" -a -e "$CFG_LLVM_ROOT/bin/llvm-config" ]
 then
     step_msg "using custom LLVM at $CFG_LLVM_ROOT"
@@ -928,6 +989,7 @@ do
     make_dir $h/test/doc-guide-container
     make_dir $h/test/doc-guide-tasks
     make_dir $h/test/doc-guide-plugin
+    make_dir $h/test/doc-guide-crates
     make_dir $h/test/doc-rust
 done
 
@@ -1203,18 +1265,11 @@ putvar CFG_OSTYPE
 putvar CFG_CPUTYPE
 putvar CFG_CONFIGURE_ARGS
 putvar CFG_PREFIX
-putvar CFG_BUILD
 putvar CFG_HOST
 putvar CFG_TARGET
-putvar CFG_LIBDIR
 putvar CFG_LIBDIR_RELATIVE
 putvar CFG_DISABLE_MANAGE_SUBMODULES
-putvar CFG_ANDROID_CROSS_PATH
-putvar CFG_MINGW32_CROSS_PATH
 putvar CFG_MANDIR
-putvar CFG_DISABLE_INJECT_STD_VERSION
-putvar CFG_JEMALLOC_ROOT
-putvar CFG_DISABLE_JEMALLOC
 
 # Avoid spurious warnings from clang by feeding it original source on
 # ccache-miss rather than preprocessed input.
@@ -1237,7 +1292,6 @@ then
     putvar CFG_PANDOC
 fi
 
-putvar CFG_LLVM_ROOT
 putvar CFG_LLVM_SRC_DIR
 
 for t in $CFG_HOST
index ab73a72f00a83af1caea333fd202d8bff06fd554..9dbcb2c9bbcd567f56ff905d890e7d8db61cbd9c 100644 (file)
@@ -27,7 +27,7 @@
 ######################################################################
 DOCS := index intro tutorial guide guide-ffi guide-macros guide-lifetimes \
        guide-tasks guide-container guide-pointers guide-testing \
-       guide-plugin complement-bugreport \
+       guide-plugin guide-crates complement-bugreport \
        complement-lang-faq complement-design-faq complement-project-faq rust \
     rustdoc guide-unsafe guide-strings reference
 
index 7af25de1f6f97cd36bf429d72f6538d01be8189c..018d77b67cdd6b8d95bfc608ace968a2b7455590 100644 (file)
@@ -25,7 +25,7 @@
 use std::from_str::FromStr;
 use getopts::{optopt, optflag, reqopt};
 use common::Config;
-use common::{Pretty, DebugInfoGdb, Codegen};
+use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen};
 use util::logv;
 use regex::Regex;
 
@@ -244,6 +244,16 @@ pub fn run_tests(config: &Config) {
         os::setenv("RUST_TEST_TASKS","1");
     }
 
+    match config.mode {
+        DebugInfoLldb => {
+            // Some older versions of LLDB seem to have problems with multiple
+            // instances running in parallel, so only run one test task at a
+            // time.
+            os::setenv("RUST_TEST_TASKS", "1");
+        }
+        _ => { /* proceed */ }
+    }
+
     let opts = test_opts(config);
     let tests = make_tests(config);
     // sadly osx needs some file descriptor limits raised for running tests in
index 8705bdd278ec7b384eb5a54bd0290e4d69d71ea2..50d76371cc51e3ce760e83ba17ccf7815e8b6e80 100644 (file)
@@ -452,7 +452,7 @@ fn main() {
 
 Rust will give us a compile-time error:
 
-```{rust,ignore}
+```{notrust,ignore}
    Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
 /home/you/projects/phrases/src/main.rs:4:5: 4:40 error: a value named `hello` has already been imported in this module
 /home/you/projects/phrases/src/main.rs:4 use phrases::japanese::greetings::hello;
index 3830a2126e172709ac58831657891e65a1d3b22e..1145235c5f899fdaf21eac5a22bede3695322625 100644 (file)
@@ -56,7 +56,7 @@ extern crate rustc;
 
 use syntax::codemap::Span;
 use syntax::parse::token::{IDENT, get_ident};
-use syntax::ast::{TokenTree, TTTok};
+use syntax::ast::{TokenTree, TtToken};
 use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacExpr};
 use syntax::ext::build::AstBuilder;  // trait for expr_uint
 use rustc::plugin::Registry;
@@ -71,7 +71,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
         ("I",    1)];
 
     let text = match args {
-        [TTTok(_, IDENT(s, _))] => get_ident(s).to_string(),
+        [TtToken(_, IDENT(s, _))] => get_ident(s).to_string(),
         _ => {
             cx.span_err(sp, "argument should be a single identifier");
             return DummyResult::any(sp);
@@ -151,8 +151,7 @@ higher-level syntax elements like expressions:
 fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
         -> Box<MacResult+'static> {
 
-    let mut parser =
-        parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), args.to_slice())
+    let mut parser = cx.new_parser_from_tts(args);
 
     let expr: P<Expr> = parser.parse_expr();
 ```
index 44fc0d830447513daaf0b1a29fd51baff71a7756..1c7cb1a3b4eb9e80890014cbbc8c8a357deef584 100644 (file)
@@ -14,8 +14,8 @@ Rust has two main types of strings: `&str` and `String`.
 
 # &str
 
-The first kind is a `&str`. This is pronounced a 'string slice.' String literals
-are of the type `&str`:
+The first kind is a `&str`. This is pronounced a 'string slice'.
+String literals are of the type `&str`:
 
 ```{rust}
 let string = "Hello there.";
@@ -121,8 +121,8 @@ Both of these lines will print `12`.
 To compare a String to a constant string, prefer `as_slice()`...
 
 ```{rust}
-fn compare(string: String) {
-    if string.as_slice() == "Hello" {
+fn compare(x: String) {
+    if x.as_slice() == "Hello" {
         println!("yes");
     }
 }
@@ -131,8 +131,8 @@ fn compare(string: String) {
 ... over `to_string()`:
 
 ```{rust}
-fn compare(string: String) {
-    if string == "Hello".to_string() {
+fn compare(x: String) {
+    if x == "Hello".to_string() {
         println!("yes");
     }
 }
index c7b8e42b28cde24c6f10f488cb32c14910d01e2b..842157bb51998fe661b4350b07562fb47925e618 100644 (file)
@@ -1130,12 +1130,12 @@ fn main() {
     let y = Missing;
 
     match x {
-        Value(n) => println!("x is {:d}", n),
+        Value(n) => println!("x is {}", n),
         Missing  => println!("x is missing!"),
     }
 
     match y {
-        Value(n) => println!("y is {:d}", n),
+        Value(n) => println!("y is {}", n),
         Missing  => println!("y is missing!"),
     }
 }
@@ -1301,7 +1301,7 @@ Instead, it looks like this:
 
 ```{rust}
 for x in range(0i, 10i) {
-    println!("{:d}", x);
+    println!("{}", x);
 }
 ```
 
@@ -1408,7 +1408,7 @@ iteration: This will only print the odd numbers:
 for x in range(0i, 10i) {
     if x % 2 == 0 { continue; }
 
-    println!("{:d}", x);
+    println!("{}", x);
 }
 ```
 
@@ -1677,12 +1677,12 @@ fn main() {
     let y = Missing;
 
     match x {
-        Value(n) => println!("x is {:d}", n),
+        Value(n) => println!("x is {}", n),
         Missing  => println!("x is missing!"),
     }
 
     match y {
-        Value(n) => println!("y is {:d}", n),
+        Value(n) => println!("y is {}", n),
         Missing  => println!("y is missing!"),
     }
 }
@@ -1793,7 +1793,7 @@ Finally, Cargo generated a hello, world for us. Check out `src/main.rs`:
 
 ```{rust}
 fn main() {
-    println!("Hello, world!");
+    println!("Hello, world!")
 }
 ```
 
@@ -2682,12 +2682,12 @@ like this:
 
 ```
 fn main() {
-    println!("Hello, world!");
+    println!("Hello, world!")
 }
 
 mod hello {
     fn print_hello() {
-        println!("Hello, world!");
+        println!("Hello, world!")
     }
 }
 ```
@@ -2721,7 +2721,7 @@ fn main() {
 
 mod hello {
     fn print_hello() {
-        println!("Hello, world!");
+        println!("Hello, world!")
     }
 }
 ```
@@ -2744,7 +2744,7 @@ fn main() {
 
 mod hello {
     pub fn print_hello() {
-        println!("Hello, world!");
+        println!("Hello, world!")
     }
 }
 ```
@@ -2921,15 +2921,11 @@ it `false`, so this test should fail. Let's try it!
 ```{notrust,ignore}
 $ cargo test
    Compiling testing v0.0.1 (file:///home/you/projects/testing)
-/home/you/projects/testing/src/main.rs:1:1: 3:2 warning: code is never used: `main`, #[warn(dead_code)] on by default
+/home/you/projects/testing/src/main.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
 /home/you/projects/testing/src/main.rs:1 fn main() {
-/home/you/projects/testing/src/main.rs:2     println!("Hello, world");
+/home/you/projects/testing/src/main.rs:2     println!("Hello, world!")
 /home/you/projects/testing/src/main.rs:3 }
-
-running 0 tests
-
-test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
-
+     Running target/lib-654ce120f310a3a5
 
 running 1 test
 test foo ... FAILED
@@ -2946,7 +2942,7 @@ failures:
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
 
-task '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:242
+task '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243
 ```
 
 Lots of output! Let's break this down:
@@ -2960,9 +2956,9 @@ You can run all of your tests with `cargo test`. This runs both your tests in
 `tests`, as well as the tests you put inside of your crate.
 
 ```{notrust,ignore}
-/home/you/projects/testing/src/main.rs:1:1: 3:2 warning: code is never used: `main`, #[warn(dead_code)] on by default
+/home/you/projects/testing/src/main.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
 /home/you/projects/testing/src/main.rs:1 fn main() {
-/home/you/projects/testing/src/main.rs:2     println!("Hello, world");
+/home/you/projects/testing/src/main.rs:2     println!("Hello, world!")
 /home/you/projects/testing/src/main.rs:3 }
 ```
 
@@ -2974,18 +2970,8 @@ We'll turn this lint off for just this function soon. For now, just ignore this
 output.
 
 ```{notrust,ignore}
-running 0 tests
-
-test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
-```
+     Running target/lib-654ce120f310a3a5
 
-Wait a minute, zero tests? Didn't we define one? Yup. This output is from
-attempting to run the tests in our crate, of which we don't have any.
-You'll note that Rust reports on several kinds of tests: passed, failed,
-ignored, and measured. The 'measured' tests refer to benchmark tests, which
-we'll cover soon enough!
-
-```{notrust,ignore}
 running 1 test
 test foo ... FAILED
 ```
@@ -3008,7 +2994,7 @@ failures:
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
 
-task '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:242
+task '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243
 ```
 
 After all the tests run, Rust will show us any output from our failed tests.
@@ -3029,29 +3015,30 @@ And then try to run our tests again:
 ```{notrust,ignore}
 $ cargo test
    Compiling testing v0.0.1 (file:///home/you/projects/testing)
-/home/you/projects/testing/src/main.rs:1:1: 3:2 warning: code is never used: `main`, #[warn(dead_code)] on by default
-/home/you/projects/testing/src/main.rs:1 fn main() {
-/home/you/projects/testing/src/main.rs:2     println!("Hello, world");
-/home/you/projects/testing/src/main.rs:3 }
-
-running 0 tests
-
-test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
-
+     Running target/lib-654ce120f310a3a5
 
 running 1 test
 test foo ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+     Running target/testing-6d7518593c7c3ee5
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
 ```
 
-Nice! Our test passes, as we expected. Let's get rid of that warning for our `main`
-function. Change your `src/main.rs` to look like this:
+Nice! Our test passes, as we expected. Note how we didn't get the
+`main` warning this time? This is because `src/main.rs` didn't
+need recompiling, but we'll get that warning again if we
+change (and recompile) that file. Let's get rid of that
+warning; change your `src/main.rs` to look like this:
 
 ```{rust}
 #[cfg(not(test))]
 fn main() {
-    println!("Hello, world");
+    println!("Hello, world!")
 }
 ```
 
@@ -3062,21 +3049,24 @@ our tests, it sets things up so that `cfg(test)` is true. But we want to only
 include `main` when it's _not_ true. So we use `not` to negate things:
 `cfg(not(test))` will only compile our code when the `cfg(test)` is false.
 
-With this attribute, we won't get the warning:
+With this attribute we won't get the warning (even
+though `src/main.rs` gets recompiled this time):
 
 ```{notrust,ignore}
 $ cargo test
    Compiling testing v0.0.1 (file:///home/you/projects/testing)
-
-running 0 tests
-
-test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
-
+     Running target/lib-654ce120f310a3a5
 
 running 1 test
 test foo ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+     Running target/testing-6d7518593c7c3ee5
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
 ```
 
 Nice. Okay, let's write a real test now. Change your `tests/lib.rs`
@@ -3133,7 +3123,7 @@ extern crate testing;
 
 #[cfg(not(test))]
 fn main() {
-    println!("Hello, world");
+    println!("Hello, world!")
 }
 ```
 
@@ -3156,21 +3146,30 @@ Let's give it a run:
 ```{ignore,notrust}
 $ cargo test
    Compiling testing v0.0.1 (file:///home/you/projects/testing)
+     Running target/lib-654ce120f310a3a5
+
+running 1 test
+test math_checks_out ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+     Running target/testing-6d7518593c7c3ee5
 
 running 0 tests
 
 test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
 
+     Running target/testing-8a94b31f7fd2e8fe
 
 running 0 tests
 
 test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
 
+   Doc-tests testing
 
-running 1 test
-test math_checks_out ... ok
+running 0 tests
 
-test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
 ```
 
 Great! One test passed. We've got an integration test showing that our public
@@ -3196,21 +3195,30 @@ If you run `cargo test`, you should get the same output:
 ```{ignore,notrust}
 $ cargo test
    Compiling testing v0.0.1 (file:///home/you/projects/testing)
+     Running target/lib-654ce120f310a3a5
+
+running 1 test
+test math_checks_out ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+     Running target/testing-6d7518593c7c3ee5
 
 running 0 tests
 
 test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
 
+     Running target/testing-8a94b31f7fd2e8fe
 
 running 0 tests
 
 test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
 
+   Doc-tests testing
 
-running 1 test
-test math_checks_out ... ok
+running 0 tests
 
-test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
 ```
 
 If we tried to write a test for these two new functions, it wouldn't
@@ -3283,6 +3291,20 @@ Let's give it a shot:
 ```{ignore,notrust}
 $ cargo test
    Compiling testing v0.0.1 (file:///home/you/projects/testing)
+     Running target/lib-654ce120f310a3a5
+
+running 1 test
+test math_checks_out ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+     Running target/testing-6d7518593c7c3ee5
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
+
+     Running target/testing-8a94b31f7fd2e8fe
 
 running 2 tests
 test test::test_times_four ... ok
@@ -3290,16 +3312,11 @@ test test::test_add_three ... ok
 
 test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured
 
+   Doc-tests testing
 
 running 0 tests
 
 test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
-
-
-running 1 test
-test math_checks_out ... ok
-
-test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
 ```
 
 Cool! We now have two tests of our internal functions. You'll note that there
@@ -3637,40 +3654,72 @@ pub fn as_maybe_owned(&self) -> MaybeOwned<'a> { ... }
 
 ## Boxes
 
-All of our references so far have been to variables we've created on the stack.
-In Rust, the simplest way to allocate heap variables is using a *box*.  To
-create a box, use the `box` keyword:
+Most of the types we've seen so far have a fixed size or number of components.
+The compiler needs this fact to lay out values in memory. However, some data
+structures, such as a linked list, do not have a fixed size. You might think to
+implement a linked list with an enum that's either a `Node` or the end of the
+list (`Nil`), like this:
+
+```{rust,ignore}
+enum List {             // error: illegal recursive enum type
+    Node(u32, List),
+    Nil
+}
+```
+
+But the compiler complains that the type is recursive, that is, it could be
+arbitrarily large. To remedy this, Rust provides a fixed-size container called
+a **box** that can hold any type. You can box up any value with the `box`
+keyword. Our boxed List gets the type `Box<List>` (more on the notation when we
+get to generics):
 
 ```{rust}
-let x = box 5i;
+enum List {
+    Node(u32, Box<List>),
+    Nil
+}
+
+fn main() {
+    let list = Node(0, box Node(1, box Nil));
+}
 ```
 
-This allocates an integer `5` on the heap, and creates a binding `x` that
-refers to it. The great thing about boxed pointers is that we don't have to
-manually free this allocation! If we write
+A box dynamically allocates memory to hold its contents. The great thing about
+Rust is that that memory is *automatically*, *efficiently*, and *predictably*
+deallocated when you're done with the box.
+
+A box is a pointer type, and you access what's inside using the `*` operator,
+just like regular references. This (rather silly) example dynamically allocates
+an integer `5` and makes `x` a pointer to it:
 
 ```{rust}
 {
     let x = box 5i;
-    // do stuff
+    println!("{}", *x);     // Prints 5
 }
 ```
 
-then Rust will automatically free `x` at the end of the block. This isn't
-because Rust has a garbage collector -- it doesn't. Instead, when `x` goes out
-of scope, Rust `free`s `x`. This Rust code will do the same thing as the
-following C code:
+The great thing about boxes is that we don't have to manually free this
+allocation! Instead, when `x` reaches the end of its lifetime -- in this case,
+when it goes out of scope at the end of the block -- Rust `free`s `x`. This
+isn't because Rust has a garbage collector (it doesn't). Instead, by tracking
+the ownership and lifetime of a variable (with a little help from you, the
+programmer), the compiler knows precisely when it is no longer used.
+
+The Rust code above will do the same thing as the following C code:
 
 ```{c,ignore}
 {
     int *x = (int *)malloc(sizeof(int));
-    // do stuff
+    if (!x) abort();
+    *x = 5;
+    printf("%d\n", *x);
     free(x);
 }
 ```
 
-This means we get the benefits of manual memory management, but the compiler
-ensures that we don't do something wrong. We can't forget to `free` our memory.
+We get the benefits of manual memory management, while ensuring we don't
+introduce any bugs. We can't forget to `free` our memory.
 
 Boxes are the sole owner of their contents, so you cannot take a mutable
 reference to them and then use the original box:
@@ -3706,48 +3755,50 @@ let mut x = box 5i;
 *x;
 ```
 
-## Rc and Arc
-
-Sometimes, you need to allocate something on the heap, but give out multiple
-references to the memory. Rust's `Rc<T>` (pronounced 'arr cee tee') and
-`Arc<T>` types (again, the `T` is for generics, we'll learn more later) provide
-you with this ability.  **Rc** stands for 'reference counted,' and **Arc** for
-'atomically reference counted.' This is how Rust keeps track of the multiple
-owners: every time we make a new reference to the `Rc<T>`, we add one to its
-internal 'reference count.' Every time a reference goes out of scope, we
-subtract one from the count. When the count is zero, the `Rc<T>` can be safely
-deallocated. `Arc<T>` is almost identical to `Rc<T>`, except for one thing: The
-'atomically' in 'Arc' means that increasing and decreasing the count uses a
-thread-safe mechanism to do so. Why two types? `Rc<T>` is faster, so if you're
-not in a multi-threaded scenario, you can have that advantage. Since we haven't
-talked about threading yet in Rust, we'll show you `Rc<T>` for the rest of this
-section.
+Boxes are simple and efficient pointers to dynamically allocated values with a
+single owner. They are useful for tree-like structures where the lifetime of a
+child depends solely on the lifetime of its (single) parent. If you need a
+value that must persist as long as any of several referrers, read on.
 
-To create an `Rc<T>`, use `Rc::new()`:
+## Rc and Arc
 
-```{rust}
-use std::rc::Rc;
+Sometimes, you need a variable that is referenced from multiple places
+(immutably!), lasting as long as any of those places, and disappearing when it
+is no longer referenced. For instance, in a graph-like data structure, a node
+might be referenced from all of its neighbors. In this case, it is not possible
+for the compiler to determine ahead of time when the value can be freed -- it
+needs a little run-time support.
 
-let x = Rc::new(5i);
-```
+Rust's **Rc** type provides shared ownership of a dynamically allocated value
+that is automatically freed at the end of its last owner's lifetime. (`Rc`
+stands for 'reference counted,' referring to the way these library types are
+implemented.) This provides more flexibility than single-owner boxes, but has
+some runtime overhead.
 
-To create a second reference, use the `.clone()` method:
+To create an `Rc` value, use `Rc::new()`. To create a second owner, use the
+`.clone()` method:
 
 ```{rust}
 use std::rc::Rc;
 
 let x = Rc::new(5i);
 let y = x.clone();
+
+println!("{} {}", *x, *y);      // Prints 5 5
 ```
 
-The `Rc<T>` will live as long as any of its references are alive. After they
-all go out of scope, the memory will be `free`d.
+The `Rc` will live as long as any of its owners are alive. After that, the
+memory will be `free`d.
+
+**Arc** is an 'atomically reference counted' value, identical to `Rc` except
+that ownership can be safely shared among multiple threads. Why two types?
+`Arc` has more overhead, so if you're not in a multi-threaded scenario, you
+don't have to pay the price.
 
-If you use `Rc<T>` or `Arc<T>`, you have to be careful about introducing
-cycles. If you have two `Rc<T>`s that point to each other, the reference counts
-will never drop to zero, and you'll have a memory leak. To learn more, check
-out [the section on `Rc<T>` and `Arc<T>` in the pointers
-guide](guide-pointers.html#rc-and-arc).
+If you use `Rc` or `Arc`, you have to be careful about introducing cycles. If
+you have two `Rc`s that point to each other, they will happily keep each other
+alive forever, creating a memory leak. To learn more, check out [the section on
+`Rc` and `Arc` in the pointers guide](guide-pointers.html#rc-and-arc).
 
 # Patterns
 
@@ -4220,7 +4271,7 @@ Remember Rust's `for` loop? Here's an example:
 
 ```{rust}
 for x in range(0i, 10i) {
-    println!("{:d}", x);
+    println!("{}", x);
 }
 ```
 
@@ -4353,7 +4404,7 @@ is one:
 
 ```{rust}
 let greater_than_forty_two = range(0i, 100i)
-                             .find(|x| *x >= 42);
+                             .find(|x| *x > 42);
 
 match greater_than_forty_two {
     Some(_) => println!("We got some numbers!"),
@@ -4474,7 +4525,7 @@ range(1i, 100i).map(|x| x + 1i);
 
 `map` is called upon another iterator, and produces a new iterator where each
 element reference has the closure it's been given as an argument called on it.
-So this would give us the numbers from `2-101`. Well, almost! If you
+So this would give us the numbers from `2-100`. Well, almost! If you
 compile the example, you'll get a warning:
 
 ```{notrust,ignore}
@@ -5288,9 +5339,9 @@ There are two circumstances where Rust's safety provisions don't work well.
 The first is when interfacing with C code, and the second is when building
 certain kinds of abstractions.
 
-Rust has support for FFI (which you can read about in the [FFI
-Guide](guide-ffi.html)), but can't guarantee that the C code will be safe.
-Therefore, Rust marks such functions with the `unsafe`
+Rust has support for [FFI](http://en.wikipedia.org/wiki/Foreign_function_interface)
+(which you can read about in the [FFI Guide](guide-ffi.html)), but can't guarantee
+that the C code will be safe. Therefore, Rust marks such functions with the `unsafe`
 keyword, which indicates that the function may not behave properly.
 
 Second, if you'd like to create some sort of shared-memory data structure, Rust
index ad548d3a8f93c331c0d64928087cccdece7c1a8e..8d54550a9f988d7e62f1d307e84f72d71db515ba 100644 (file)
@@ -57,6 +57,7 @@ a guide that can help you out:
 * [Strings](guide-strings.html)
 * [Pointers](guide-pointers.html)
 * [References and Lifetimes](guide-lifetimes.html)
+* [Crates and modules](guide-crates.html)
 * [Tasks and Communication](guide-tasks.html)
 * [Foreign Function Interface](guide-ffi.html)
 * [Writing Unsafe and Low-Level Code](guide-unsafe.html)
index 6fd4c95794ee7e96b72b1b79b7271a0abc275ac1..25f1a5fd3e2e40582b2c8c6d5890c5c9caabeda7 100644 (file)
@@ -19,6 +19,7 @@
 [type: text] src/doc/guide-tasks.md $lang:doc/l10n/$lang/guide-tasks.md
 [type: text] src/doc/guide-testing.md $lang:doc/l10n/$lang/guide-testing.md
 [type: text] src/doc/guide-unsafe.md $lang:doc/l10n/$lang/guide-unsafe.md
+[type: text] src/doc/guide-unsafe.md $lang:doc/l10n/$lang/guide-crates.md
 [type: text] src/doc/guide.md $lang:doc/l10n/$lang/guide.md
 [type: text] src/doc/index.md $lang:doc/l10n/$lang/index.md
 [type: text] src/doc/intro.md $lang:doc/l10n/$lang/intro.md
index 1b6794e77f9f45484d7071eb760c5c77e5256996..f255dbf15071b6dc3852bace3c21aa7d706ab759 100644 (file)
@@ -376,7 +376,7 @@ fn bar(   a:int,
           -> int
 { }
 
-fn baz(   a:int,  // shoudl work with a comment here
+fn baz(   a:int,  // should work with a comment here
           b:char)
           -> int
 { }
index c447cb46c532a81c07b76849d4386f01b70d4620..0e62fbb01441dcc1eee788fbdcc51a7a07a0d431 100644 (file)
@@ -15,6 +15,7 @@
 
 use core::atomic;
 use core::clone::Clone;
+use core::fmt::{mod, Show};
 use core::kinds::{Sync, Send};
 use core::mem::{min_align_of, size_of, drop};
 use core::mem;
@@ -147,6 +148,12 @@ fn deref(&self) -> &T {
     }
 }
 
+impl<T: Send + Sync + Show> Show for Arc<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
 impl<T: Send + Sync + Clone> Arc<T> {
     /// Acquires a mutable pointer to the inner contents by guaranteeing that
     /// the reference count is one (no sharing is possible).
@@ -280,6 +287,7 @@ mod tests {
     use std::mem::drop;
     use std::ops::Drop;
     use std::option::{Option, Some, None};
+    use std::str::Str;
     use std::sync::atomic;
     use std::task;
     use std::vec::Vec;
@@ -426,4 +434,10 @@ fn drop_arc_weak() {
         assert!(canary.load(atomic::Acquire) == 1);
         drop(arc_weak);
     }
+
+    #[test]
+    fn show_arc() {
+        let a = Arc::new(5u32);
+        assert!(format!("{}", a).as_slice() == "5")
+    }
 }
index 5a0f860ff844ef74278d244c83dc8437262a3278..c780170d47aaf0b7320efab683deecb01c876f53 100644 (file)
@@ -28,8 +28,8 @@ pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
 /// size on the platform.
 ///
 /// The `old_size` and `align` parameters are the parameters that were used to
-/// create the allocation referenced by `ptr`. The `old_size` parameter may also
-/// be the value returned by `usable_size` for the requested size.
+/// create the allocation referenced by `ptr`. The `old_size` parameter may be
+/// any value in range_inclusive(requested_size, usable_size).
 #[inline]
 pub unsafe fn reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> *mut u8 {
     imp::reallocate(ptr, old_size, size, align)
@@ -38,8 +38,8 @@ pub unsafe fn reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint)
 /// Extends or shrinks the allocation referenced by `ptr` to `size` bytes of
 /// memory in-place.
 ///
-/// Returns true if successful, otherwise false if the allocation was not
-/// altered.
+/// If the operation succeeds, it returns `usable_size(size, align)` and if it
+/// fails (or is a no-op) it returns `usable_size(old_size, align)`.
 ///
 /// Behavior is undefined if the requested size is 0 or the alignment is not a
 /// power of 2. The alignment must be no larger than the largest supported page
@@ -49,7 +49,7 @@ pub unsafe fn reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint)
 /// create the allocation referenced by `ptr`. The `old_size` parameter may be
 /// any value in range_inclusive(requested_size, usable_size).
 #[inline]
-pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> bool {
+pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> uint {
     imp::reallocate_inplace(ptr, old_size, size, align)
 }
 
@@ -57,12 +57,12 @@ pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint, align
 ///
 /// The `ptr` parameter must not be null.
 ///
-/// The `size` and `align` parameters are the parameters that were used to
-/// create the allocation referenced by `ptr`. The `size` parameter may also be
-/// the value returned by `usable_size` for the requested size.
+/// The `old_size` and `align` parameters are the parameters that were used to
+/// create the allocation referenced by `ptr`. The `old_size` parameter may be
+/// any value in range_inclusive(requested_size, usable_size).
 #[inline]
-pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) {
-    imp::deallocate(ptr, size, align)
+pub unsafe fn deallocate(ptr: *mut u8, old_size: uint, align: uint) {
+    imp::deallocate(ptr, old_size, align)
 }
 
 /// Returns the usable size of an allocation created with the specified the
@@ -102,8 +102,8 @@ unsafe fn exchange_malloc(size: uint, align: uint) -> *mut u8 {
 #[cfg(not(test))]
 #[lang="exchange_free"]
 #[inline]
-unsafe fn exchange_free(ptr: *mut u8, size: uint, align: uint) {
-    deallocate(ptr, size, align);
+unsafe fn exchange_free(ptr: *mut u8, old_size: uint, align: uint) {
+    deallocate(ptr, old_size, align);
 }
 
 // The minimum alignment guaranteed by the architecture. This value is used to
@@ -112,10 +112,10 @@ unsafe fn exchange_free(ptr: *mut u8, size: uint, align: uint) {
 #[cfg(any(target_arch = "arm",
           target_arch = "mips",
           target_arch = "mipsel"))]
-static MIN_ALIGN: uint = 8;
+const MIN_ALIGN: uint = 8;
 #[cfg(any(target_arch = "x86",
           target_arch = "x86_64"))]
-static MIN_ALIGN: uint = 16;
+const MIN_ALIGN: uint = 16;
 
 #[cfg(jemalloc)]
 mod imp {
@@ -178,22 +178,16 @@ pub unsafe fn reallocate(ptr: *mut u8, _old_size: uint, size: uint, align: uint)
     }
 
     #[inline]
-    pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint,
-                                     align: uint) -> bool {
+    pub unsafe fn reallocate_inplace(ptr: *mut u8, _old_size: uint, size: uint,
+                                     align: uint) -> uint {
         let flags = align_to_flags(align);
-        let new_size = je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) as uint;
-        // checking for failure to shrink is tricky
-        if size < old_size {
-            usable_size(size, align) == new_size as uint
-        } else {
-            new_size >= size
-        }
+        je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) as uint
     }
 
     #[inline]
-    pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) {
+    pub unsafe fn deallocate(ptr: *mut u8, old_size: uint, align: uint) {
         let flags = align_to_flags(align);
-        je_sdallocx(ptr as *mut c_void, size as size_t, flags)
+        je_sdallocx(ptr as *mut c_void, old_size as size_t, flags)
     }
 
     #[inline]
@@ -213,8 +207,8 @@ pub fn stats_print() {
 mod imp {
     use core::cmp;
     use core::ptr;
+    use core::ptr::RawPtr;
     use libc;
-    use libc_heap;
     use super::MIN_ALIGN;
 
     extern {
@@ -226,7 +220,11 @@ fn posix_memalign(memptr: *mut *mut libc::c_void,
     #[inline]
     pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
         if align <= MIN_ALIGN {
-            libc_heap::malloc_raw(size)
+            let ptr = libc::malloc(size as libc::size_t);
+            if ptr.is_null() {
+                ::oom();
+            }
+            ptr as *mut u8
         } else {
             let mut out = 0 as *mut libc::c_void;
             let ret = posix_memalign(&mut out,
@@ -242,7 +240,11 @@ pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
     #[inline]
     pub unsafe fn reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> *mut u8 {
         if align <= MIN_ALIGN {
-            libc_heap::realloc_raw(ptr, size)
+            let ptr = libc::realloc(ptr as *mut libc::c_void, size as libc::size_t);
+            if ptr.is_null() {
+                ::oom();
+            }
+            ptr as *mut u8
         } else {
             let new_ptr = allocate(size, align);
             ptr::copy_memory(new_ptr, ptr as *const u8, cmp::min(size, old_size));
@@ -252,13 +254,13 @@ pub unsafe fn reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint)
     }
 
     #[inline]
-    pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: uint, size: uint,
-                                     _align: uint) -> bool {
-        size == old_size
+    pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: uint, _size: uint,
+                                     _align: uint) -> uint {
+        old_size
     }
 
     #[inline]
-    pub unsafe fn deallocate(ptr: *mut u8, _size: uint, _align: uint) {
+    pub unsafe fn deallocate(ptr: *mut u8, _old_size: uint, _align: uint) {
         libc::free(ptr as *mut libc::c_void)
     }
 
@@ -274,7 +276,6 @@ pub fn stats_print() {}
 mod imp {
     use libc::{c_void, size_t};
     use libc;
-    use libc_heap;
     use core::ptr::RawPtr;
     use super::MIN_ALIGN;
 
@@ -288,7 +289,11 @@ fn _aligned_realloc(block: *mut c_void, size: size_t,
     #[inline]
     pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
         if align <= MIN_ALIGN {
-            libc_heap::malloc_raw(size)
+            let ptr = libc::malloc(size as size_t);
+            if ptr.is_null() {
+                ::oom();
+            }
+            ptr as *mut u8
         } else {
             let ptr = _aligned_malloc(size as size_t, align as size_t);
             if ptr.is_null() {
@@ -301,7 +306,11 @@ pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
     #[inline]
     pub unsafe fn reallocate(ptr: *mut u8, _old_size: uint, size: uint, align: uint) -> *mut u8 {
         if align <= MIN_ALIGN {
-            libc_heap::realloc_raw(ptr, size)
+            let ptr = libc::realloc(ptr as *mut c_void, size as size_t);
+            if ptr.is_null() {
+                ::oom();
+            }
+            ptr as *mut u8
         } else {
             let ptr = _aligned_realloc(ptr as *mut c_void, size as size_t,
                                        align as size_t);
@@ -313,13 +322,13 @@ pub unsafe fn reallocate(ptr: *mut u8, _old_size: uint, size: uint, align: uint)
     }
 
     #[inline]
-    pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: uint, size: uint,
-                                     _align: uint) -> bool {
-        size == old_size
+    pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: uint, _size: uint,
+                                     _align: uint) -> uint {
+        old_size
     }
 
     #[inline]
-    pub unsafe fn deallocate(ptr: *mut u8, _size: uint, align: uint) {
+    pub unsafe fn deallocate(ptr: *mut u8, _old_size: uint, align: uint) {
         if align <= MIN_ALIGN {
             libc::free(ptr as *mut libc::c_void)
         } else {
@@ -348,7 +357,7 @@ fn basic_reallocate_inplace_noop() {
             let ptr = heap::allocate(size, 8);
             let ret = heap::reallocate_inplace(ptr, size, size, 8);
             heap::deallocate(ptr, size, 8);
-            assert!(ret);
+            assert_eq!(ret, heap::usable_size(size, 8));
         }
     }
 
index 2df9a585fec994ff01a178163f4244e6632f15a1..c721649ca9d4fbc659638dbe46f682056db014b2 100644 (file)
 //!
 //! ## Heap interfaces
 //!
-//! The [`heap`](heap/index.html) and [`libc_heap`](libc_heap/index.html)
-//! modules are the unsafe interfaces to the underlying allocation systems. The
-//! `heap` module is considered the default heap, and is not necessarily backed
-//! by libc malloc/free.  The `libc_heap` module is defined to be wired up to
-//! the system malloc/free.
+//! The [`heap`](heap/index.html) module defines the low-level interface to the
+//! default global allocator. It is not compatible with the libc allocator API.
 
 #![crate_name = "alloc"]
 #![experimental]
@@ -90,7 +87,6 @@
 // Heaps provided for low-level allocation strategies
 
 pub mod heap;
-pub mod libc_heap;
 
 // Primitive types using the heaps above
 
diff --git a/src/liballoc/libc_heap.rs b/src/liballoc/libc_heap.rs
deleted file mode 100644 (file)
index 4f64006..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.
-
-
-//! The global (exchange) heap.
-
-use libc::{c_void, size_t, free, malloc, realloc};
-use core::ptr::{RawPtr, null_mut};
-
-/// A wrapper around libc::malloc, aborting on out-of-memory.
-#[inline]
-pub unsafe fn malloc_raw(size: uint) -> *mut u8 {
-    // `malloc(0)` may allocate, but it may also return a null pointer
-    // http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html
-    if size == 0 {
-        null_mut()
-    } else {
-        let p = malloc(size as size_t);
-        if p.is_null() {
-            ::oom();
-        }
-        p as *mut u8
-    }
-}
-
-/// A wrapper around libc::realloc, aborting on out-of-memory.
-#[inline]
-pub unsafe fn realloc_raw(ptr: *mut u8, size: uint) -> *mut u8 {
-    // `realloc(ptr, 0)` may allocate, but it may also return a null pointer
-    // http://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html
-    if size == 0 {
-        free(ptr as *mut c_void);
-        null_mut()
-    } else {
-        let p = realloc(ptr as *mut c_void, size as size_t);
-        if p.is_null() {
-            ::oom();
-        }
-        p as *mut u8
-    }
-}
index dbbff61b8dd50c139154eb800a05892f7a6843d3..77fb6d4a1203b360fa4e624cb382168fed73f62f 100644 (file)
 /// the BST strategy.
 ///
 /// A B-Tree instead makes each node contain B-1 to 2B-1 elements in a contiguous array. By doing
-/// this, we reduce the number of allocations by a factor of B, and improve cache effeciency in
+/// this, we reduce the number of allocations by a factor of B, and improve cache efficiency in
 /// searches. However, this does mean that searches will have to do *more* comparisons on average.
 /// The precise number of comparisons depends on the node search strategy used. For optimal cache
-/// effeciency, one could search the nodes linearly. For optimal comparisons, one could search
+/// efficiency, one could search the nodes linearly. For optimal comparisons, one could search
 /// the node using binary search. As a compromise, one could also perform a linear search
 /// that initially only checks every i<sup>th</sup> element for some choice of i.
 ///
index e30b29f8767d3aa26d7857de2f8a187ab83875c3..4da362952b67c8fadec70ee436f7897644944da8 100644 (file)
@@ -53,7 +53,7 @@ pub struct Node<K, V> {
     // hard. For now, we accept this cost in the name of correctness and simplicity.
     //
     // As a compromise, keys and vals could be merged into one Vec<(K, V)>, which would shave
-    // off 3 words, but possibly hurt our cache effeciency during search, which only cares about
+    // off 3 words, but possibly hurt our cache efficiency during search, which only cares about
     // keys. This would also avoid the Zip we use in our iterator implementations. This is
     // probably worth investigating.
     //
@@ -72,7 +72,7 @@ impl<K: Ord, V> Node<K, V> {
     /// `GoDown` will be yielded with the index of the subtree the key must lie in.
     pub fn search(&self, key: &K) -> SearchResult {
         // FIXME(Gankro): Tune when to search linear or binary based on B (and maybe K/V).
-        // For the B configured as of this writing (B = 6), binary search was *singnificantly*
+        // For the B configured as of this writing (B = 6), binary search was *significantly*
         // worse for uints.
         self.search_linear(key)
     }
@@ -375,7 +375,7 @@ unsafe fn handle_underflow_to_right(&mut self, underflowed_child_index: uint) {
         }
     }
 
-    /// Steal! Stealing is roughly analagous to a binary tree rotation.
+    /// Steal! Stealing is roughly analogous to a binary tree rotation.
     /// In this case, we're "rotating" right.
     unsafe fn steal_to_left(&mut self, underflowed_child_index: uint) {
         // Take the biggest stuff off left
@@ -387,7 +387,7 @@ unsafe fn steal_to_left(&mut self, underflowed_child_index: uint) {
             }
         };
 
-        // Swap the parent's seperating key-value pair with left's
+        // Swap the parent's separating key-value pair with left's
         self.unsafe_swap(underflowed_child_index - 1, &mut key, &mut val);
 
         // Put them at the start of right
@@ -402,7 +402,7 @@ unsafe fn steal_to_left(&mut self, underflowed_child_index: uint) {
         }
     }
 
-    /// Steal! Stealing is roughly analagous to a binary tree rotation.
+    /// Steal! Stealing is roughly analogous to a binary tree rotation.
     /// In this case, we're "rotating" left.
     unsafe fn steal_to_right(&mut self, underflowed_child_index: uint) {
         // Take the smallest stuff off right
@@ -414,7 +414,7 @@ unsafe fn steal_to_right(&mut self, underflowed_child_index: uint) {
             }
         };
 
-        // Swap the parent's seperating key-value pair with right's
+        // Swap the parent's separating key-value pair with right's
         self.unsafe_swap(underflowed_child_index, &mut key, &mut val);
 
         // Put them at the end of left
@@ -430,9 +430,9 @@ unsafe fn steal_to_right(&mut self, underflowed_child_index: uint) {
     }
 
     /// Merge! Left and right will be smooshed into one node, along with the key-value
-    /// pair that seperated them in their parent.
+    /// pair that separated them in their parent.
     unsafe fn merge_children(&mut self, left_index: uint) {
-        // Permanently remove right's index, and the key-value pair that seperates
+        // Permanently remove right's index, and the key-value pair that separates
         // left and right
         let (key, val, right) = {
             match (self.keys.remove(left_index),
@@ -448,7 +448,7 @@ unsafe fn merge_children(&mut self, left_index: uint) {
         left.absorb(key, val, right);
     }
 
-    /// Take all the values from right, seperated by the given key and value
+    /// Take all the values from right, separated by the given key and value
     fn absorb(&mut self, key: K, val: V, right: Node<K, V>) {
         // Just as a sanity check, make sure we can fit this guy in
         debug_assert!(self.len() + right.len() <= self.capacity())
index d061e60a42265d95f97e298a2c34f377225a8897..d4115df7da4787e13e9c43e219d90d4606ea1c02 100644 (file)
@@ -292,7 +292,7 @@ impl<T> BoxedSlice<T> for Box<[T]> {
     #[experimental]
     fn into_vec(mut self) -> Vec<T> {
         unsafe {
-            let xs = Vec::from_raw_parts(self.len(), self.len(), self.as_mut_ptr());
+            let xs = Vec::from_raw_parts(self.as_mut_ptr(), self.len(), self.len());
             mem::forget(self);
             xs
         }
index fa45dee7cdea7c2756b692add3cf3ef9d5d59ec9..c44a03b05cd35d7f3f6664dc68f0d871e1757cb6 100644 (file)
@@ -780,7 +780,7 @@ pub mod raw {
     #[inline]
     pub unsafe fn from_parts(buf: *mut u8, length: uint, capacity: uint) -> String {
         String {
-            vec: Vec::from_raw_parts(length, capacity, buf),
+            vec: Vec::from_raw_parts(buf, length, capacity),
         }
     }
 
index e608a7d22dcf5e8a8fe33bf3fbf969974157ae93..c57a465df3780e085b7fd07cc01be1fad37eafb2 100644 (file)
 #[unsafe_no_drop_flag]
 #[stable]
 pub struct Vec<T> {
+    ptr: *mut T,
     len: uint,
     cap: uint,
-    ptr: *mut T
 }
 
 impl<T> Vec<T> {
@@ -125,7 +125,7 @@ pub fn new() -> Vec<T> {
         // non-null value which is fine since we never call deallocate on the ptr
         // if cap is 0. The reason for this is because the pointer of a slice
         // being NULL would break the null pointer optimization for enums.
-        Vec { len: 0, cap: 0, ptr: EMPTY as *mut T }
+        Vec { ptr: EMPTY as *mut T, len: 0, cap: 0 }
     }
 
     /// Constructs a new, empty `Vec` with the specified capacity.
@@ -159,14 +159,14 @@ pub fn new() -> Vec<T> {
     #[stable]
     pub fn with_capacity(capacity: uint) -> Vec<T> {
         if mem::size_of::<T>() == 0 {
-            Vec { len: 0, cap: uint::MAX, ptr: EMPTY as *mut T }
+            Vec { ptr: EMPTY as *mut T, len: 0, cap: uint::MAX }
         } else if capacity == 0 {
             Vec::new()
         } else {
             let size = capacity.checked_mul(&mem::size_of::<T>())
                                .expect("capacity overflow");
             let ptr = unsafe { allocate(size, mem::min_align_of::<T>()) };
-            Vec { len: 0, cap: capacity, ptr: ptr as *mut T }
+            Vec { ptr: ptr as *mut T, len: 0, cap: capacity }
         }
     }
 
@@ -237,9 +237,9 @@ pub fn from_fn(length: uint, op: |uint| -> T) -> Vec<T> {
     /// }
     /// ```
     #[experimental]
-    pub unsafe fn from_raw_parts(length: uint, capacity: uint,
-                                 ptr: *mut T) -> Vec<T> {
-        Vec { len: length, cap: capacity, ptr: ptr }
+    pub unsafe fn from_raw_parts(ptr: *mut T, length: uint,
+                                 capacity: uint) -> Vec<T> {
+        Vec { ptr: ptr, len: length, cap: capacity }
     }
 
     /// Consumes the `Vec`, partitioning it based on a predicate.
@@ -1680,7 +1680,7 @@ fn drop(&mut self) {
 pub fn as_vec<'a, T>(x: &'a [T]) -> DerefVec<'a, T> {
     unsafe {
         DerefVec {
-            x: Vec::from_raw_parts(x.len(), x.len(), x.as_ptr() as *mut T),
+            x: Vec::from_raw_parts(x.as_ptr() as *mut T, x.len(), x.len()),
             l: ContravariantLifetime::<'a>
         }
     }
@@ -1929,7 +1929,7 @@ pub fn map_in_place<U>(self, f: |T| -> U) -> Vec<U> {
                 let vec_cap = pv.vec.capacity();
                 let vec_ptr = pv.vec.as_mut_ptr() as *mut U;
                 mem::forget(pv);
-                Vec::from_raw_parts(vec_len, vec_cap, vec_ptr)
+                Vec::from_raw_parts(vec_ptr, vec_len, vec_cap)
             }
         } else {
             // Put the `Vec` into the `PartialVecZeroSized` structure and
index d644fd0063ed34ae24d4e552665e3f36d407108d..8a4b9f6e51b60bef2cec0cf3714d826bbc540277 100644 (file)
@@ -191,6 +191,17 @@ pub fn set(&self, value: T) {
             *self.value.get() = value;
         }
     }
+
+    /// Get a reference to the underlying `UnsafeCell`.
+    ///
+    /// This can be used to circumvent `Cell`'s safety checks.
+    ///
+    /// This function is `unsafe` because `UnsafeCell`'s field is public.
+    #[inline]
+    #[experimental]
+    pub unsafe fn as_unsafe_cell<'a>(&'a self) -> &'a UnsafeCell<T> {
+        &self.value
+    }
 }
 
 #[unstable = "waiting for `Clone` trait to become stable"]
@@ -306,6 +317,17 @@ pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
             None => fail!("RefCell<T> already borrowed")
         }
     }
+
+    /// Get a reference to the underlying `UnsafeCell`.
+    ///
+    /// This can be used to circumvent `RefCell`'s safety checks.
+    ///
+    /// This function is `unsafe` because `UnsafeCell`'s field is public.
+    #[inline]
+    #[experimental]
+    pub unsafe fn as_unsafe_cell<'a>(&'a self) -> &'a UnsafeCell<T> {
+        &self.value
+    }
 }
 
 #[unstable = "waiting for `Clone` to become stable"]
index a62e2ecdca0328d9e22b392b7dd7904acbdb986d..fe365b43ca6d1838e860f0254e2de10ce92b0c1b 100644 (file)
 use mem;
 
 /// The representation of a Rust slice
+#[repr(C)]
 pub struct Slice<T> {
     pub data: *const T,
     pub len: uint,
 }
 
 /// The representation of a Rust closure
+#[repr(C)]
 pub struct Closure {
     pub code: *mut (),
     pub env: *mut (),
 }
 
 /// The representation of a Rust procedure (`proc()`)
+#[repr(C)]
 pub struct Procedure {
     pub code: *mut (),
     pub env: *mut (),
@@ -42,6 +45,7 @@ pub struct Procedure {
 ///
 /// This struct does not have a `Repr` implementation
 /// because there is no way to refer to all trait objects generically.
+#[repr(C)]
 pub struct TraitObject {
     pub data: *mut (),
     pub vtable: *mut (),
@@ -60,4 +64,3 @@ fn repr(&self) -> T { unsafe { mem::transmute_copy(self) } }
 
 impl<'a, T> Repr<Slice<T>> for &'a [T] {}
 impl<'a> Repr<Slice<u8>> for &'a str {}
-
index b3ae110363cb56e357ddcf3adfded634a6673cda..59365045f43807cfb027c02fe3df316e92cdf289 100644 (file)
@@ -127,3 +127,22 @@ fn clone_ref_updates_flag() {
     }
     assert!(x.try_borrow_mut().is_some());
 }
+
+#[test]
+fn as_unsafe_cell() {
+    let c1: Cell<uint> = Cell::new(0u);
+    c1.set(1u);
+    assert_eq!(1u, unsafe { *c1.as_unsafe_cell().get() });
+
+    let c2: Cell<uint> = Cell::new(0u);
+    unsafe { *c2.as_unsafe_cell().get() = 1u; }
+    assert_eq!(1u, c2.get());
+
+    let r1: RefCell<uint> = RefCell::new(0u);
+    *r1.borrow_mut() = 1u;
+    assert_eq!(1u, unsafe { *r1.as_unsafe_cell().get() });
+
+    let r2: RefCell<uint> = RefCell::new(0u);
+    unsafe { *r2.as_unsafe_cell().get() = 1u; }
+    assert_eq!(1u, *r2.borrow());
+}
index 83d03bb265e95f87208eb333b91963d4f1099662..97e68bcbb2c6ca52d0c316b8e6cebc199152f7c6 100644 (file)
@@ -173,7 +173,7 @@ impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {
     fn reseed(&mut self, seed: &'a [u32]) {
         // reset state
         self.init(&[0u32, ..KEY_WORDS]);
-        // set key inplace
+        // set key in place
         let key = self.state.slice_mut(4, 4+KEY_WORDS);
         for (k, s) in key.iter_mut().zip(seed.iter()) {
             *k = *s;
index f1cd8b52e5ed3103fa8e2b0a09c87dcecfdae0d0..474e8e45d94c265893097b637c6f5566e9ab9c0f 100644 (file)
@@ -714,7 +714,13 @@ pub fn run_passes(sess: &Session,
            .stdout(::std::io::process::InheritFd(1))
            .stderr(::std::io::process::InheritFd(2));
         match cmd.status() {
-            Ok(_) => {},
+            Ok(status) => {
+                if !status.success() {
+                    sess.err(format!("linking of {} with `{}` failed",
+                                     output_path.display(), cmd).as_slice());
+                    sess.abort_if_errors();
+                }
+            },
             Err(e) => {
                 sess.err(format!("could not exec the linker `{}`: {}",
                                  pname,
index 601a9a73c3d3aa67035021e54e92d579b8931dcd..9db79074d1fd12b0b0a62fb6901a7ba6541dd344 100644 (file)
@@ -36,6 +36,7 @@
     E0015,
     E0016,
     E0017,
+    E0018,
     E0019,
     E0020,
     E0022,
index 5f09cafb5e26eb4201de364a00253073f5bab8b8..de61f4f2b404c78a46b7defe3b9d719c2e572e9c 100644 (file)
@@ -777,13 +777,28 @@ fn check_assignment(&self,
         // Otherwise, just a plain error.
         match assignee_cmt.note {
             mc::NoteClosureEnv(upvar_id) => {
-                self.bccx.span_err(
-                    assignment_span,
-                    format!("cannot assign to {}",
-                            self.bccx.cmt_to_string(&*assignee_cmt)).as_slice());
-                self.bccx.span_note(
-                    self.tcx().map.span(upvar_id.closure_expr_id),
-                    "consider changing this closure to take self by mutable reference");
+                // If this is an `Fn` closure, it simply can't mutate upvars.
+                // If it's an `FnMut` closure, the original variable was declared immutable.
+                // We need to determine which is the case here.
+                let kind = match assignee_cmt.upvar().unwrap().cat {
+                    mc::cat_upvar(mc::Upvar { kind, .. }) => kind,
+                    _ => unreachable!()
+                };
+                if kind == ty::FnUnboxedClosureKind {
+                    self.bccx.span_err(
+                        assignment_span,
+                        format!("cannot assign to {}",
+                                self.bccx.cmt_to_string(&*assignee_cmt)).as_slice());
+                    self.bccx.span_note(
+                        self.tcx().map.span(upvar_id.closure_expr_id),
+                        "consider changing this closure to take self by mutable reference");
+                } else {
+                    self.bccx.span_err(
+                        assignment_span,
+                        format!("cannot assign to {} {}",
+                                assignee_cmt.mutbl.to_user_str(),
+                                self.bccx.cmt_to_string(&*assignee_cmt)).as_slice());
+                }
             }
             _ => match opt_loan_path(&assignee_cmt) {
                 Some(lp) => {
@@ -825,13 +840,20 @@ fn mark_variable_as_used_mut(this: &CheckLoanCtxt,
                     mc::cat_rvalue(..) |
                     mc::cat_static_item |
                     mc::cat_deref(_, _, mc::UnsafePtr(..)) |
-                    mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
                     mc::cat_deref(_, _, mc::Implicit(..)) => {
                         assert_eq!(cmt.mutbl, mc::McDeclared);
                         return;
                     }
 
-                    mc::cat_discr(b, _) |
+                    mc::cat_deref(_, _, mc::BorrowedPtr(..)) => {
+                        assert_eq!(cmt.mutbl, mc::McDeclared);
+                        // We need to drill down to upvar if applicable
+                        match cmt.upvar() {
+                            Some(b) => cmt = b,
+                            None => return
+                        }
+                    }
+
                     mc::cat_deref(b, _, mc::OwnedPtr) => {
                         assert_eq!(cmt.mutbl, mc::McInherited);
                         cmt = b;
index 7c037cf50ff29e5104b2ac2e08aa397a1dbb20d8..a1c02b85e8f51cd085764f98fbac2e09597a192f 100644 (file)
@@ -159,8 +159,7 @@ fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt,
             }
         }
 
-        mc::cat_deref(ref b, _, mc::OwnedPtr) |
-        mc::cat_discr(ref b, _) => {
+        mc::cat_deref(ref b, _, mc::OwnedPtr) => {
             check_and_get_illegal_move_origin(bccx, b)
         }
     }
index 5018fe0f96e076982fae2e85ab6119015d0291b6..41fe77d5197fd5b6325b2ab102eb364c78c59abb 100644 (file)
@@ -84,62 +84,6 @@ fn check(&self, cmt: &mc::cmt, discr_scope: Option<ast::NodeId>) -> R {
             mc::cat_interior(ref base, _) => {             // L-Field
                 self.check(base, discr_scope)
             }
-
-            mc::cat_discr(ref base, new_discr_scope) => {
-                // Subtle: in a match, we must ensure that each binding
-                // variable remains valid for the duration of the arm in
-                // which it appears, presuming that this arm is taken.
-                // But it is inconvenient in trans to root something just
-                // for one arm.  Therefore, we insert a cat_discr(),
-                // basically a special kind of category that says "if this
-                // value must be dynamically rooted, root it for the scope
-                // `match_id`".
-                //
-                // As an example, consider this scenario:
-                //
-                //    let mut x = @Some(3);
-                //    match *x { Some(y) {...} None {...} }
-                //
-                // Technically, the value `x` need only be rooted
-                // in the `some` arm.  However, we evaluate `x` in trans
-                // before we know what arm will be taken, so we just
-                // always root it for the duration of the match.
-                //
-                // As a second example, consider *this* scenario:
-                //
-                //    let x = @@Some(3);
-                //    match x { @@Some(y) {...} @@None {...} }
-                //
-                // Here again, `x` need only be rooted in the `some` arm.
-                // In this case, the value which needs to be rooted is
-                // found only when checking which pattern matches: but
-                // this check is done before entering the arm.  Therefore,
-                // even in this case we just choose to keep the value
-                // rooted for the entire match.  This means the value will be
-                // rooted even if the none arm is taken.  Oh well.
-                //
-                // At first, I tried to optimize the second case to only
-                // root in one arm, but the result was suboptimal: first,
-                // it interfered with the construction of phi nodes in the
-                // arm, as we were adding code to root values before the
-                // phi nodes were added.  This could have been addressed
-                // with a second basic block.  However, the naive approach
-                // also yielded suboptimal results for patterns like:
-                //
-                //    let x = @@...;
-                //    match x { @@some_variant(y) | @@some_other_variant(y) =>
-                //
-                // The reason is that we would root the value once for
-                // each pattern and not once per arm.  This is also easily
-                // fixed, but it's yet more code for what is really quite
-                // the corner case.
-                //
-                // Nonetheless, if you decide to optimize this case in the
-                // future, you need only adjust where the cat_discr()
-                // node appears to draw the line between what will be rooted
-                // in the *arm* vs the *match*.
-                self.check(base, Some(new_discr_scope))
-            }
         }
     }
 
@@ -182,8 +126,7 @@ fn scope(&self, cmt: &mc::cmt) -> ty::Region {
             }
             mc::cat_downcast(ref cmt) |
             mc::cat_deref(ref cmt, _, mc::OwnedPtr) |
-            mc::cat_interior(ref cmt, _) |
-            mc::cat_discr(ref cmt, _) => {
+            mc::cat_interior(ref cmt, _) => {
                 self.scope(cmt)
             }
         }
index d28baf48ddcdf5825043068a26a56dad2e0be9a8..1a12828922cbf58088e16d8b910773fc629ec044 100644 (file)
@@ -213,9 +213,7 @@ fn guarantee_valid(&mut self,
         /*!
          * Guarantees that `addr_of(cmt)` will be valid for the duration of
          * `static_scope_r`, or reports an error.  This may entail taking
-         * out loans, which will be added to the `req_loan_map`.  This can
-         * also entail "rooting" GC'd pointers, which means ensuring
-         * dynamically that they are not freed.
+         * out loans, which will be added to the `req_loan_map`.
          */
 
         debug!("guarantee_valid(borrow_id={}, cmt={}, \
index 15a7437b6a87a4b1701b65b7385afb2e3e2d3e36..6a6fc1760f2bb3b25fa22069c95be5cf558f4788 100644 (file)
@@ -96,46 +96,27 @@ fn restrict(&self,
                 self.extend(result, cmt.mutbl, LpInterior(i))
             }
 
-            mc::cat_deref(cmt_base, _, pk @ mc::OwnedPtr) => {
-                // R-Deref-Send-Pointer
-                //
-                // When we borrow the interior of an owned pointer, we
-                // cannot permit the base to be mutated, because that
-                // would cause the unique pointer to be freed.
-                //
-                // Eventually we should make these non-special and
-                // just rely on Deref<T> implementation.
-                let result = self.restrict(cmt_base);
-                self.extend(result, cmt.mutbl, LpDeref(pk))
-            }
 
             mc::cat_static_item(..) => {
                 Safe
             }
 
-            mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) |
-            mc::cat_deref(cmt_base, _, mc::Implicit(ty::ImmBorrow, lt)) => {
-                // R-Deref-Imm-Borrowed
-                if !self.bccx.is_subregion_of(self.loan_region, lt) {
-                    self.bccx.report(
-                        BckError {
-                            span: self.span,
-                            cause: self.cause,
-                            cmt: cmt_base,
-                            code: err_borrowed_pointer_too_short(
-                                self.loan_region, lt)});
-                    return Safe;
-                }
-                Safe
-            }
-
             mc::cat_deref(cmt_base, _, pk) => {
                 match pk {
-                    mc::BorrowedPtr(ty::MutBorrow, lt) |
-                    mc::BorrowedPtr(ty::UniqueImmBorrow, lt) |
-                    mc::Implicit(ty::MutBorrow, lt) |
-                    mc::Implicit(ty::UniqueImmBorrow, lt) => {
-                        // R-Deref-Mut-Borrowed
+                    mc::OwnedPtr => {
+                        // R-Deref-Send-Pointer
+                        //
+                        // When we borrow the interior of an owned pointer, we
+                        // cannot permit the base to be mutated, because that
+                        // would cause the unique pointer to be freed.
+                        //
+                        // Eventually we should make these non-special and
+                        // just rely on Deref<T> implementation.
+                        let result = self.restrict(cmt_base);
+                        self.extend(result, cmt.mutbl, LpDeref(pk))
+                    }
+                    mc::Implicit(bk, lt) | mc::BorrowedPtr(bk, lt) => {
+                        // R-Deref-[Mut-]Borrowed
                         if !self.bccx.is_subregion_of(self.loan_region, lt) {
                             self.bccx.report(
                                 BckError {
@@ -147,25 +128,23 @@ fn restrict(&self,
                             return Safe;
                         }
 
-                        let result = self.restrict(cmt_base);
-                        self.extend(result, cmt.mutbl, LpDeref(pk))
-                    }
-                    mc::UnsafePtr(..) => {
-                        // We are very trusting when working with unsafe
-                        // pointers.
-                        Safe
-                    }
-                    _ => {
-                        self.bccx.tcx.sess.span_bug(self.span,
-                                                    "unhandled memcat in \
-                                                     cat_deref")
+                        match bk {
+                            ty::ImmBorrow => Safe,
+                            ty::MutBorrow | ty::UniqueImmBorrow => {
+                                // R-Deref-Mut-Borrowed
+                                //
+                                // The referent can be aliased after the
+                                // references lifetime ends (by a newly-unfrozen
+                                // borrow).
+                                let result = self.restrict(cmt_base);
+                                self.extend(result, cmt.mutbl, LpDeref(pk))
+                            }
+                        }
                     }
+                    // Borrowck is not relevant for unsafe pointers
+                    mc::UnsafePtr(..) => Safe
                 }
             }
-
-            mc::cat_discr(cmt_base, _) => {
-                self.restrict(cmt_base)
-            }
         }
     }
 
index 850c6008706c88eee2226ab2d031ca11c2abbe5e..b09e9105f3f6be4102905f05b1fd38fc56bc8329 100644 (file)
@@ -379,8 +379,7 @@ pub fn opt_loan_path(cmt: &mc::cmt) -> Option<Rc<LoanPath>> {
             })
         }
 
-        mc::cat_downcast(ref cmt_base) |
-        mc::cat_discr(ref cmt_base, _) => {
+        mc::cat_downcast(ref cmt_base) => {
             opt_loan_path(cmt_base)
         }
     }
@@ -626,7 +625,7 @@ pub fn bckerr_to_string(&self, err: &BckError) -> String {
         match err.code {
             err_mutbl => {
                 let descr = match err.cmt.note {
-                    mc::NoteClosureEnv(_) => {
+                    mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => {
                         self.cmt_to_string(&*err.cmt)
                     }
                     _ => match opt_loan_path(&err.cmt) {
@@ -762,11 +761,20 @@ pub fn note_and_explain_bckerr(&self, err: BckError) {
         match code {
             err_mutbl(..) => {
                 match err.cmt.note {
-                    mc::NoteClosureEnv(upvar_id) => {
-                        self.tcx.sess.span_note(
-                            self.tcx.map.span(upvar_id.closure_expr_id),
-                            "consider changing this closure to take \
-                             self by mutable reference");
+                    mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => {
+                        // If this is an `Fn` closure, it simply can't mutate upvars.
+                        // If it's an `FnMut` closure, the original variable was declared immutable.
+                        // We need to determine which is the case here.
+                        let kind = match err.cmt.upvar().unwrap().cat {
+                            mc::cat_upvar(mc::Upvar { kind, .. }) => kind,
+                            _ => unreachable!()
+                        };
+                        if kind == ty::FnUnboxedClosureKind {
+                            self.tcx.sess.span_note(
+                                self.tcx.map.span(upvar_id.closure_expr_id),
+                                "consider changing this closure to take \
+                                 self by mutable reference");
+                        }
                     }
                     _ => {}
                 }
index d6b9bbded4ff89e7050b85770ee1e1ad56302523..6cf1a93b40b7b85d52eeb276653c1d1ce019646a 100644 (file)
@@ -119,12 +119,18 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) -> bool {
             }
         }
         ExprLit(_) => (),
-        ExprCast(_, _) => {
-            let ety = ty::expr_ty(v.tcx, e);
-            if !ty::type_is_numeric(ety) && !ty::type_is_unsafe_ptr(ety) {
+        ExprCast(ref from, _) => {
+            let toty = ty::expr_ty(v.tcx, e);
+            let fromty = ty::expr_ty(v.tcx, &**from);
+            if !ty::type_is_numeric(toty) && !ty::type_is_unsafe_ptr(toty) {
                 span_err!(v.tcx.sess, e.span, E0012,
                           "can not cast to `{}` in a constant expression",
-                          ppaux::ty_to_string(v.tcx, ety));
+                          ppaux::ty_to_string(v.tcx, toty));
+            }
+            if ty::type_is_unsafe_ptr(fromty) && ty::type_is_numeric(toty) {
+                span_err!(v.tcx.sess, e.span, E0018,
+                          "can not cast a pointer to an integer in a constant \
+                           expression");
             }
         }
         ExprPath(ref pth) => {
index 42bc645200337cbf0eb9eb672d70eb49c9ecd0d8..dd862d53c475b6c7fab88b89d09b58047532477d 100644 (file)
@@ -269,7 +269,6 @@ fn consume(&mut self,
                     break
                 }
                 mc::cat_deref(ref cmt, _, _) |
-                mc::cat_discr(ref cmt, _) |
                 mc::cat_downcast(ref cmt) |
                 mc::cat_interior(ref cmt, _) => cur = cmt,
 
@@ -307,7 +306,6 @@ fn borrow(&mut self,
                 }
 
                 mc::cat_downcast(..) |
-                mc::cat_discr(..) |
                 mc::cat_upvar(..) => unreachable!(),
 
                 mc::cat_local(..) => {
@@ -331,4 +329,3 @@ fn consume_pat(&mut self,
                    _cmt: mc::cmt,
                    _mode: euv::ConsumeMode) {}
 }
-
index ebca401ecf4ebcd4b418f545796d45866d262019..08e14e8034e9eff6d57ee30005978d76ce31b263 100644 (file)
@@ -87,7 +87,6 @@ pub enum categorization {
     cat_deref(cmt, uint, PointerKind), // deref of a ptr
     cat_interior(cmt, InteriorKind),   // something interior: field, tuple, etc
     cat_downcast(cmt),                 // selects a particular enum variant (*1)
-    cat_discr(cmt, ast::NodeId),       // match discriminant (see preserve())
 
     // (*1) downcast is only required if the enum has more than one variant
 }
@@ -656,51 +655,54 @@ fn cat_upvar(&self,
         // FnOnce         | copied               | upvar -> &'up bk
         // old stack      | N/A                  | upvar -> &'env mut -> &'up bk
         // old proc/once  | copied               | N/A
+        let var_ty = if_ok!(self.node_ty(var_id));
+
         let upvar_id = ty::UpvarId { var_id: var_id,
                                      closure_expr_id: fn_node_id };
 
-        // Do we need to deref through an env reference?
-        let has_env_deref = kind != ty::FnOnceUnboxedClosureKind;
-
         // Mutability of original variable itself
         let var_mutbl = MutabilityCategory::from_local(self.tcx(), var_id);
 
-        // Mutability of environment dereference
-        let env_mutbl = match kind {
-            ty::FnOnceUnboxedClosureKind => var_mutbl,
-            ty::FnMutUnboxedClosureKind => McInherited,
-            ty::FnUnboxedClosureKind => McImmutable
+        // Construct information about env pointer dereference, if any
+        let mutbl = match kind {
+            ty::FnOnceUnboxedClosureKind => None, // None, env is by-value
+            ty::FnMutUnboxedClosureKind => match mode { // Depends on capture type
+                ast::CaptureByValue => Some(var_mutbl), // Mutable if the original var is
+                ast::CaptureByRef => Some(McDeclared) // Mutable regardless
+            },
+            ty::FnUnboxedClosureKind => Some(McImmutable) // Never mutable
         };
+        let env_info = mutbl.map(|env_mutbl| {
+            // Look up the node ID of the closure body so we can construct
+            // a free region within it
+            let fn_body_id = {
+                let fn_expr = match self.tcx().map.find(fn_node_id) {
+                    Some(ast_map::NodeExpr(e)) => e,
+                    _ => unreachable!()
+                };
 
-        // Look up the node ID of the closure body so we can construct
-        // a free region within it
-        let fn_body_id = {
-            let fn_expr = match self.tcx().map.find(fn_node_id) {
-                Some(ast_map::NodeExpr(e)) => e,
-                _ => unreachable!()
+                match fn_expr.node {
+                    ast::ExprFnBlock(_, _, ref body) |
+                    ast::ExprProc(_, ref body) |
+                    ast::ExprUnboxedFn(_, _, _, ref body) => body.id,
+                    _ => unreachable!()
+                }
             };
 
-            match fn_expr.node {
-                ast::ExprFnBlock(_, _, ref body) |
-                ast::ExprProc(_, ref body) |
-                ast::ExprUnboxedFn(_, _, _, ref body) => body.id,
-                _ => unreachable!()
-            }
-        };
-
-        // Region of environment pointer
-        let env_region = ty::ReFree(ty::FreeRegion {
-            scope_id: fn_body_id,
-            bound_region: ty::BrEnv
-        });
+            // Region of environment pointer
+            let env_region = ty::ReFree(ty::FreeRegion {
+                scope_id: fn_body_id,
+                bound_region: ty::BrEnv
+            });
 
-        let env_ptr = BorrowedPtr(if env_mutbl.is_mutable() {
-            ty::MutBorrow
-        } else {
-            ty::ImmBorrow
-        }, env_region);
+            let env_ptr = BorrowedPtr(if env_mutbl.is_mutable() {
+                ty::MutBorrow
+            } else {
+                ty::ImmBorrow
+            }, env_region);
 
-        let var_ty = if_ok!(self.node_ty(var_id));
+            (env_mutbl, env_ptr)
+        });
 
         // First, switch by capture mode
         Ok(match mode {
@@ -718,25 +720,27 @@ fn cat_upvar(&self,
                     note: NoteNone
                 };
 
-                if has_env_deref {
-                    // We need to add the env deref.  This means that
-                    // the above is actually immutable and has a ref
-                    // type.  However, nothing should actually look at
-                    // the type, so we can get away with stuffing a
-                    // `ty_err` in there instead of bothering to
-                    // construct a proper one.
-                    base.mutbl = McImmutable;
-                    base.ty = ty::mk_err();
-                    Rc::new(cmt_ {
-                        id: id,
-                        span: span,
-                        cat: cat_deref(Rc::new(base), 0, env_ptr),
-                        mutbl: env_mutbl,
-                        ty: var_ty,
-                        note: NoteClosureEnv(upvar_id)
-                    })
-                } else {
-                    Rc::new(base)
+                match env_info {
+                    Some((env_mutbl, env_ptr)) => {
+                        // We need to add the env deref.  This means
+                        // that the above is actually immutable and
+                        // has a ref type.  However, nothing should
+                        // actually look at the type, so we can get
+                        // away with stuffing a `ty_err` in there
+                        // instead of bothering to construct a proper
+                        // one.
+                        base.mutbl = McImmutable;
+                        base.ty = ty::mk_err();
+                        Rc::new(cmt_ {
+                            id: id,
+                            span: span,
+                            cat: cat_deref(Rc::new(base), 0, env_ptr),
+                            mutbl: env_mutbl,
+                            ty: var_ty,
+                            note: NoteClosureEnv(upvar_id)
+                        })
+                    }
+                    None => Rc::new(base)
                 }
             },
             ast::CaptureByRef => {
@@ -756,16 +760,18 @@ fn cat_upvar(&self,
                     note: NoteNone
                 };
 
-                // As in the by-value case, add env deref if needed
-                if has_env_deref {
-                    base = cmt_ {
-                        id: id,
-                        span: span,
-                        cat: cat_deref(Rc::new(base), 0, env_ptr),
-                        mutbl: env_mutbl,
-                        ty: ty::mk_err(),
-                        note: NoteClosureEnv(upvar_id)
-                    };
+                match env_info {
+                    Some((env_mutbl, env_ptr)) => {
+                        base = cmt_ {
+                            id: id,
+                            span: span,
+                            cat: cat_deref(Rc::new(base), 0, env_ptr),
+                            mutbl: env_mutbl,
+                            ty: ty::mk_err(),
+                            note: NoteClosureEnv(upvar_id)
+                        };
+                    }
+                    None => {}
                 }
 
                 // Look up upvar borrow so we can get its region
@@ -1339,9 +1345,6 @@ fn upvar_to_string(upvar: &Upvar, is_copy: bool) -> String {
           cat_upvar(ref var) => {
               upvar_to_string(var, true)
           }
-          cat_discr(ref cmt, _) => {
-            self.cmt_to_string(&**cmt)
-          }
           cat_downcast(ref cmt) => {
             self.cmt_to_string(&**cmt)
           }
@@ -1379,7 +1382,6 @@ pub fn guarantor(&self) -> cmt {
                 Rc::new((*self).clone())
             }
             cat_downcast(ref b) |
-            cat_discr(ref b, _) |
             cat_interior(ref b, _) |
             cat_deref(ref b, _, OwnedPtr) => {
                 b.guarantor()
@@ -1404,8 +1406,7 @@ pub fn freely_aliasable(&self, ctxt: &ty::ctxt) -> Option<AliasableReason> {
             cat_deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
             cat_downcast(ref b) |
             cat_deref(ref b, _, OwnedPtr) |
-            cat_interior(ref b, _) |
-            cat_discr(ref b, _) => {
+            cat_interior(ref b, _) => {
                 // Aliasability depends on base cmt
                 b.freely_aliasable(ctxt)
             }
@@ -1490,9 +1491,6 @@ fn repr(&self, tcx: &ty::ctxt) -> String {
             cat_downcast(ref cmt) => {
                 format!("{}->(enum)", cmt.cat.repr(tcx))
             }
-            cat_discr(ref cmt, _) => {
-                cmt.cat.repr(tcx)
-            }
         }
     }
 }
index f24121d9a3a5f8b5521aac54c71adb64349757f6..c014bc0c164f206dce9b7c1180382c215b0d846f 100644 (file)
@@ -279,4 +279,132 @@ impl Bar<uint> for int { ... }
 type of the receiver and various other complications. The procedure is
 described in `select.rs` in the "METHOD MATCHING" section.
 
+# Caching and subtle considerations therewith
+
+In general we attempt to cache the results of trait selection.  This
+is a somewhat complex process. Part of the reason for this is that we
+want to be able to cache results even when all the types in the trait
+reference are not fully known. In that case, it may happen that the
+trait selection process is also influencing type variables, so we have
+to be able to not only cache the *result* of the selection process,
+but *replay* its effects on the type variables.
+
+## An example
+
+The high-level idea of how the cache works is that we first replace
+all unbound inference variables with skolemized versions. Therefore,
+if we had a trait reference `uint : Foo<$1>`, where `$n` is an unbound
+inference variable, we might replace it with `uint : Foo<%0>`, where
+`%n` is a skolemized type. We would then look this up in the cache.
+If we found a hit, the hit would tell us the immediate next step to
+take in the selection process: i.e., apply impl #22, or apply where
+clause `X : Foo<Y>`. Let's say in this case there is no hit.
+Therefore, we search through impls and where clauses and so forth, and
+we come to the conclusion that the only possible impl is this one,
+with def-id 22:
+
+    impl Foo<int> for uint { ... } // Impl #22
+
+We would then record in the cache `uint : Foo<%0> ==>
+ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which
+would (as a side-effect) unify `$1` with `int`.
+
+Now, at some later time, we might come along and see a `uint :
+Foo<$3>`.  When skolemized, this would yield `uint : Foo<%0>`, just as
+before, and hence the cache lookup would succeed, yielding
+`ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would
+(as a side-effect) unify `$3` with `int`.
+
+## Where clauses and the local vs global cache
+
+One subtle interaction is that the results of trait lookup will vary
+depending on what where clauses are in scope. Therefore, we actually
+have *two* caches, a local and a global cache. The local cache is
+attached to the `ParameterEnvironment` and the global cache attached
+to the `tcx`. We use the local cache whenever the result might depend
+on the where clauses that are in scope. The determination of which
+cache to use is done by the method `pick_candidate_cache` in
+`select.rs`.
+
+There are two cases where we currently use the local cache. The
+current rules are probably more conservative than necessary.
+
+### Trait references that involve parameter types
+
+The most obvious case where you need the local environment is
+when the trait reference includes parameter types. For example,
+consider the following function:
+
+    impl<T> Vec<T> {
+        fn foo(x: T)
+            where T : Foo
+        { ... }
+
+        fn bar(x: T)
+        { ... }
+    }
+
+If there is an obligation `T : Foo`, or `int : Bar<T>`, or whatever,
+clearly the results from `foo` and `bar` are potentially different,
+since the set of where clauses in scope are different.
+
+### Trait references with unbound variables when where clauses are in scope
+
+There is another less obvious interaction which involves unbound variables
+where *only* where clauses are in scope (no impls). This manifested as
+issue #18209 (`run-pass/trait-cache-issue-18209.rs`). Consider
+this snippet:
+
+```
+pub trait Foo {
+    fn load_from() -> Box<Self>;
+    fn load() -> Box<Self> {
+        Foo::load_from()
+    }
+}
+```
+
+The default method will incur an obligation `$0 : Foo` from the call
+to `load_from`. If there are no impls, this can be eagerly resolved to
+`VtableParam(Self : Foo)` and cached. Because the trait reference
+doesn't involve any parameters types (only the resolution does), this
+result was stored in the global cache, causing later calls to
+`Foo::load_from()` to get nonsense.
+
+To fix this, we always use the local cache if there are unbound
+variables and where clauses in scope. This is more conservative than
+necessary as far as I can tell. However, it still seems to be a simple
+rule and I observe ~99% hit rate on rustc, so it doesn't seem to hurt
+us in particular.
+
+Here is an example of the kind of subtle case that I would be worried
+about with a more complex rule (although this particular case works
+out ok). Imagine the trait reference doesn't directly reference a
+where clause, but the where clause plays a role in the winnowing
+phase. Something like this:
+
+```
+pub trait Foo<T> { ... }
+pub trait Bar { ... }
+impl<U,T:Bar> Foo<U> for T { ... } // Impl A
+impl Foo<char> for uint { ... }    // Impl B
+```
+
+Now, in some function, we have no where clauses in scope, and we have
+an obligation `$1 : Foo<$0>`. We might then conclude that `$0=char`
+and `$1=uint`: this is because for impl A to apply, `uint:Bar` would
+have to hold, and we know it does not or else the coherence check
+would have failed.  So we might enter into our global cache: `$1 :
+Foo<$0> => Impl B`.  Then we come along in a different scope, where a
+generic type `A` is around with the bound `A:Bar`. Now suddenly the
+impl is viable.
+
+The flaw in this imaginary DOOMSDAY SCENARIO is that we would not
+currently conclude that `$1 : Foo<$0>` implies that `$0 == uint` and
+`$1 == char`, even though it is true that (absent type parameters)
+there is no other type the user could enter. However, it is not
+*completely* implausible that we *could* draw this conclusion in the
+future; we wouldn't have to guess types, in particular, we could be
+led by the impls.
+
 */
index 23257912b8264f457970d5af15db82b7b06508ac..8f1fcf77ee38a6f565793d0c1abb03bf35bef809 100644 (file)
@@ -211,7 +211,7 @@ pub fn select_inherent_impl(&mut self,
     // can be applied to particular types. It skips the "confirmation"
     // step and hence completely ignores output type parameters.
     //
-    // The result is "true" if the obliation *may* hold and "false" if
+    // The result is "true" if the obligation *may* hold and "false" if
     // we can be sure it does not.
 
     pub fn evaluate_obligation_intercrate(&mut self,
@@ -844,19 +844,36 @@ fn pick_candidate_cache(&self,
                             cache_skol_trait_ref: &Rc<ty::TraitRef>)
                             -> &SelectionCache
     {
+        // High-level idea: we have to decide whether to consult the
+        // cache that is specific to this scope, or to consult the
+        // global cache. We want the cache that is specific to this
+        // scope whenever where clauses might affect the result.
+
         // If the trait refers to any parameters in scope, then use
-        // the cache of the param-environment. This is because the
-        // result will depend on the where clauses that are in
-        // scope. Otherwise, use the generic tcx cache, since the
-        // result holds across all environments.
+        // the cache of the param-environment.
         if
             cache_skol_trait_ref.input_types().iter().any(
                 |&t| ty::type_has_self(t) || ty::type_has_params(t))
         {
-            &self.param_env.selection_cache
-        } else {
-            &self.tcx().selection_cache
+            return &self.param_env.selection_cache;
         }
+
+        // If the trait refers to unbound type variables, and there
+        // are where clauses in scope, then use the local environment.
+        // If there are no where clauses in scope, which is a very
+        // common case, then we can use the global environment.
+        // See the discussion in doc.rs for more details.
+        if
+            !self.param_env.caller_obligations.is_empty()
+            &&
+            cache_skol_trait_ref.input_types().iter().any(
+                |&t| ty::type_has_ty_infer(t))
+        {
+            return &self.param_env.selection_cache;
+        }
+
+        // Otherwise, we can use the global cache.
+        &self.tcx().selection_cache
     }
 
     fn check_candidate_cache(&mut self,
@@ -1935,26 +1952,6 @@ fn impl_obligations(&self,
         util::obligations_for_generics(self.tcx(), cause, recursion_depth,
                                        &impl_generics, impl_substs)
     }
-
-    fn contains_skolemized_types(&self,
-                                 ty: ty::t)
-                                 -> bool
-    {
-        /*!
-         * True if the type contains skolemized variables.
-         */
-
-        let mut found_skol = false;
-
-        ty::walk_ty(ty, |t| {
-            match ty::get(t).sty {
-                ty::ty_infer(ty::SkolemizedTy(_)) => { found_skol = true; }
-                _ => { }
-            }
-        });
-
-        found_skol
-    }
 }
 
 impl Repr for Candidate {
index 834441d4430b0d4ddf9a118be82c95f9e22b90a0..622da4840b047bee4eccf44f8602b8d809a208a8 100644 (file)
@@ -940,6 +940,7 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             controlflow::trans_loop(bcx, expr.id, &**body)
         }
         ast::ExprAssign(ref dst, ref src) => {
+            let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
             let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &**dst, "assign"));
 
             if ty::type_needs_drop(bcx.tcx(), dst_datum.ty) {
@@ -960,7 +961,6 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 // We could avoid this intermediary with some analysis
                 // to determine whether `dst` may possibly own `src`.
                 debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
-                let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
                 let src_datum = unpack_datum!(
                     bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign"));
                 bcx = glue::drop_ty(bcx,
@@ -969,7 +969,7 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                     Some(NodeInfo { id: expr.id, span: expr.span }));
                 src_datum.store_to(bcx, dst_datum.val)
             } else {
-                trans_into(bcx, &**src, SaveIn(dst_datum.to_llref()))
+                src_datum.store_to(bcx, dst_datum.val)
             }
         }
         ast::ExprAssignOp(op, ref dst, ref src) => {
@@ -2117,7 +2117,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 deref_owned_pointer(bcx, expr, datum, content_ty)
             } else {
                 // A fat pointer and an opened DST value have the same
-                // represenation just different types. Since there is no
+                // representation just different types. Since there is no
                 // temporary for `*e` here (because it is unsized), we cannot
                 // emulate the sized object code path for running drop glue and
                 // free. Instead, we schedule cleanup for `e`, turning it into
@@ -2142,7 +2142,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 // owner (or, in the case of *T, by the user).
                 DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr))
             } else {
-                // A fat pointer and an opened DST value have the same represenation
+                // A fat pointer and an opened DST value have the same representation
                 // just different types.
                 DatumBlock::new(bcx, Datum::new(datum.val,
                                                 ty::mk_open(bcx.tcx(), content_ty),
index 8c602548f33f6ceaccde3763e148368d75a20803..569c256a738b13966c8a7e6537c89401c160fbc6 100644 (file)
@@ -585,17 +585,22 @@ pub struct ctxt<'tcx> {
     pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
 }
 
-pub enum tbox_flag {
-    has_params = 1,
-    has_self = 2,
-    needs_infer = 4,
-    has_regions = 8,
-    has_ty_err = 16,
-    has_ty_bot = 32,
-
-    // a meta-pub flag: subst may be required if the type has parameters, a self
-    // type, or references bound regions
-    needs_subst = 1 | 2 | 8
+// Flags that we track on types. These flags are propagated upwards
+// through the type during type construction, so that we can quickly
+// check whether the type has various kinds of types in it without
+// recursing over the type itself.
+bitflags! {
+    flags TypeFlags: u32 {
+        const NO_TYPE_FLAGS = 0b0,
+        const HAS_PARAMS    = 0b1,
+        const HAS_SELF      = 0b10,
+        const HAS_TY_INFER  = 0b100,
+        const HAS_RE_INFER  = 0b1000,
+        const HAS_REGIONS   = 0b10000,
+        const HAS_TY_ERR    = 0b100000,
+        const HAS_TY_BOT    = 0b1000000,
+        const NEEDS_SUBST   = HAS_PARAMS.bits | HAS_SELF.bits | HAS_REGIONS.bits,
+    }
 }
 
 pub type t_box = &'static t_box_;
@@ -604,7 +609,13 @@ pub enum tbox_flag {
 pub struct t_box_ {
     pub sty: sty,
     pub id: uint,
-    pub flags: uint,
+    pub flags: TypeFlags,
+}
+
+impl fmt::Show for TypeFlags {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.bits)
+    }
 }
 
 // To reduce refcounting cost, we're representing types as unsafe pointers
@@ -631,15 +642,16 @@ pub fn get(t: t) -> t_box {
     }
 }
 
-pub fn tbox_has_flag(tb: t_box, flag: tbox_flag) -> bool {
-    (tb.flags & (flag as uint)) != 0u
+fn tbox_has_flag(tb: t_box, flag: TypeFlags) -> bool {
+    tb.flags.intersects(flag)
 }
 pub fn type_has_params(t: t) -> bool {
-    tbox_has_flag(get(t), has_params)
+    tbox_has_flag(get(t), HAS_PARAMS)
 }
-pub fn type_has_self(t: t) -> bool { tbox_has_flag(get(t), has_self) }
+pub fn type_has_self(t: t) -> bool { tbox_has_flag(get(t), HAS_SELF) }
+pub fn type_has_ty_infer(t: t) -> bool { tbox_has_flag(get(t), HAS_TY_INFER) }
 pub fn type_needs_infer(t: t) -> bool {
-    tbox_has_flag(get(t), needs_infer)
+    tbox_has_flag(get(t), HAS_TY_INFER | HAS_RE_INFER)
 }
 pub fn type_id(t: t) -> uint { get(t).id }
 
@@ -886,7 +898,7 @@ macro_rules! def_prim_ty(
             pub static $name: t_box_ = t_box_ {
                 sty: $sty,
                 id: $id,
-                flags: 0,
+                flags: super::NO_TYPE_FLAGS,
             };
         )
     )
@@ -910,13 +922,13 @@ macro_rules! def_prim_ty(
     pub static TY_BOT: t_box_ = t_box_ {
         sty: super::ty_bot,
         id: 16,
-        flags: super::has_ty_bot as uint,
+        flags: super::HAS_TY_BOT,
     };
 
     pub static TY_ERR: t_box_ = t_box_ {
         sty: super::ty_err,
         id: 17,
-        flags: super::has_ty_err as uint,
+        flags: super::HAS_TY_ERR,
     };
 
     pub const LAST_PRIMITIVE_ID: uint = 18;
@@ -1577,32 +1589,32 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
         _ => ()
     }
 
-    let mut flags = 0u;
-    fn rflags(r: Region) -> uint {
-        (has_regions as uint) | {
+    let mut flags = NO_TYPE_FLAGS;
+    fn rflags(r: Region) -> TypeFlags {
+        HAS_REGIONS | {
             match r {
-              ty::ReInfer(_) => needs_infer as uint,
-              _ => 0u
+              ty::ReInfer(_) => HAS_RE_INFER,
+              _ => NO_TYPE_FLAGS,
             }
         }
     }
-    fn sflags(substs: &Substs) -> uint {
-        let mut f = 0u;
+    fn sflags(substs: &Substs) -> TypeFlags {
+        let mut f = NO_TYPE_FLAGS;
         let mut i = substs.types.iter();
         for tt in i {
-            f |= get(*tt).flags;
+            f = f | get(*tt).flags;
         }
         match substs.regions {
             subst::ErasedRegions => {}
             subst::NonerasedRegions(ref regions) => {
                 for r in regions.iter() {
-                    f |= rflags(*r)
+                    f = f | rflags(*r)
                 }
             }
         }
         return f;
     }
-    fn flags_for_bounds(bounds: &ExistentialBounds) -> uint {
+    fn flags_for_bounds(bounds: &ExistentialBounds) -> TypeFlags {
         rflags(bounds.region_bound)
     }
     match &st {
@@ -1610,58 +1622,58 @@ fn flags_for_bounds(bounds: &ExistentialBounds) -> uint {
       &ty_str => {}
       // You might think that we could just return ty_err for
       // any type containing ty_err as a component, and get
-      // rid of the has_ty_err flag -- likewise for ty_bot (with
+      // rid of the HAS_TY_ERR flag -- likewise for ty_bot (with
       // the exception of function types that return bot).
       // But doing so caused sporadic memory corruption, and
       // neither I (tjc) nor nmatsakis could figure out why,
       // so we're doing it this way.
-      &ty_bot => flags |= has_ty_bot as uint,
-      &ty_err => flags |= has_ty_err as uint,
+      &ty_bot => flags = flags | HAS_TY_BOT,
+      &ty_err => flags = flags | HAS_TY_ERR,
       &ty_param(ref p) => {
           if p.space == subst::SelfSpace {
-              flags |= has_self as uint;
+              flags = flags | HAS_SELF;
           } else {
-              flags |= has_params as uint;
+              flags = flags | HAS_PARAMS;
           }
       }
-      &ty_unboxed_closure(_, ref region) => flags |= rflags(*region),
-      &ty_infer(_) => flags |= needs_infer as uint,
+      &ty_unboxed_closure(_, ref region) => flags = flags | rflags(*region),
+      &ty_infer(_) => flags = flags | HAS_TY_INFER,
       &ty_enum(_, ref substs) | &ty_struct(_, ref substs) => {
-          flags |= sflags(substs);
+          flags = flags | sflags(substs);
       }
       &ty_trait(box TyTrait { ref substs, ref bounds, .. }) => {
-          flags |= sflags(substs);
-          flags |= flags_for_bounds(bounds);
+          flags = flags | sflags(substs);
+          flags = flags | flags_for_bounds(bounds);
       }
       &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => {
-        flags |= get(tt).flags
+        flags = flags | get(tt).flags
       }
       &ty_ptr(ref m) => {
-        flags |= get(m.ty).flags;
+        flags = flags | get(m.ty).flags;
       }
       &ty_rptr(r, ref m) => {
-        flags |= rflags(r);
-        flags |= get(m.ty).flags;
+        flags = flags | rflags(r);
+        flags = flags | get(m.ty).flags;
       }
-      &ty_tup(ref ts) => for tt in ts.iter() { flags |= get(*tt).flags; },
+      &ty_tup(ref ts) => for tt in ts.iter() { flags = flags | get(*tt).flags; },
       &ty_bare_fn(ref f) => {
-        for a in f.sig.inputs.iter() { flags |= get(*a).flags; }
-        flags |= get(f.sig.output).flags;
+        for a in f.sig.inputs.iter() { flags = flags | get(*a).flags; }
+        flags = flags | get(f.sig.output).flags;
         // T -> _|_ is *not* _|_ !
-        flags &= !(has_ty_bot as uint);
+        flags = flags - HAS_TY_BOT;
       }
       &ty_closure(ref f) => {
         match f.store {
             RegionTraitStore(r, _) => {
-                flags |= rflags(r);
+                flags = flags | rflags(r);
             }
             _ => {}
         }
-        for a in f.sig.inputs.iter() { flags |= get(*a).flags; }
-        flags |= get(f.sig.output).flags;
+        for a in f.sig.inputs.iter() { flags = flags | get(*a).flags; }
+        flags = flags | get(f.sig.output).flags;
         // T -> _|_ is *not* _|_ !
-        flags &= !(has_ty_bot as uint);
-        flags |= flags_for_bounds(&f.bounds);
+        flags = flags - HAS_TY_BOT;
+        flags = flags | flags_for_bounds(&f.bounds);
       }
     }
 
@@ -1976,18 +1988,20 @@ pub fn is_noop(&self) -> bool {
 
 // Type utilities
 
-pub fn type_is_nil(ty: t) -> bool { get(ty).sty == ty_nil }
+pub fn type_is_nil(ty: t) -> bool {
+    get(ty).sty == ty_nil
+}
 
 pub fn type_is_bot(ty: t) -> bool {
-    (get(ty).flags & (has_ty_bot as uint)) != 0
+    get(ty).flags.intersects(HAS_TY_BOT)
 }
 
 pub fn type_is_error(ty: t) -> bool {
-    (get(ty).flags & (has_ty_err as uint)) != 0
+    get(ty).flags.intersects(HAS_TY_ERR)
 }
 
 pub fn type_needs_subst(ty: t) -> bool {
-    tbox_has_flag(get(ty), needs_subst)
+    tbox_has_flag(get(ty), NEEDS_SUBST)
 }
 
 pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool {
@@ -3605,7 +3619,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
 
                 // Special case: A unit like struct's constructor must be called without () at the
                 // end (like `UnitStruct`) which means this is an ExprPath to a DefFn. But in case
-                // of unit structs this is should not be interpretet as function pointer but as
+                // of unit structs this is should not be interpreted as function pointer but as
                 // call to the constructor.
                 def::DefFn(_, _, true) => RvalueDpsExpr,
 
@@ -5409,7 +5423,7 @@ pub fn to_mutbl_lossy(self) -> ast::Mutability {
             MutBorrow => ast::MutMutable,
             ImmBorrow => ast::MutImmutable,
 
-            // We have no type correponding to a unique imm borrow, so
+            // We have no type corresponding to a unique imm borrow, so
             // use `&mut`. It gives all the capabilities of an `&uniq`
             // and hence is a safe "over approximation".
             UniqueImmBorrow => ast::MutMutable,
index cb2f1e010ac6e6ed719557f56569a850b311a34f..66693224c87794241cb53d5a6198df18f85ffb93 100644 (file)
@@ -88,7 +88,7 @@ trait `ToString` imported, and I call `to_string()` on a value of type `T`,
 use middle::typeck::astconv::AstConv;
 use middle::typeck::check::{FnCtxt, NoPreference, PreferMutLvalue};
 use middle::typeck::check::{impl_self_ty};
-use middle::typeck::check::vtable2::select_fcx_obligations_where_possible;
+use middle::typeck::check::vtable::select_fcx_obligations_where_possible;
 use middle::typeck::check;
 use middle::typeck::infer;
 use middle::typeck::{MethodCall, MethodCallee};
@@ -223,17 +223,37 @@ pub fn report_error(fcx: &FnCtxt,
 {
     match error {
         NoMatch(static_sources) => {
+            let cx = fcx.tcx();
+            let method_ustring = method_name.user_string(cx);
+
+            // True if the type is a struct and contains a field with
+            // the same name as the not-found method
+            let is_field = match ty::get(rcvr_ty).sty {
+                ty_struct(did, _) =>
+                    ty::lookup_struct_fields(cx, did)
+                        .iter()
+                        .any(|f| f.name.user_string(cx) == method_ustring),
+                _ => false
+            };
+
             fcx.type_error_message(
                 span,
                 |actual| {
                     format!("type `{}` does not implement any \
                              method in scope named `{}`",
                             actual,
-                            method_name.user_string(fcx.tcx()))
+                            method_ustring)
                 },
                 rcvr_ty,
                 None);
 
+            // If the method has the name of a field, give a help note
+            if is_field {
+                cx.sess.span_note(span,
+                    format!("use `(s.{0})(...)` if you meant to call the \
+                            function stored in the `{0}` field", method_ustring).as_slice());
+            }
+
             if static_sources.len() > 0 {
                 fcx.tcx().sess.fileline_note(
                     span,
index 5ad68544570d168646c5d6b7dbb66544028d718b..3d1385bac3bf52f369b315d9b036dec8c2b70a03 100644 (file)
 use syntax;
 
 pub mod _match;
-pub mod vtable2; // New trait code
+pub mod vtable;
 pub mod writeback;
 pub mod regionmanip;
 pub mod regionck;
@@ -409,7 +409,7 @@ fn check_bare_fn(ccx: &CrateCtxt,
             let fcx = check_fn(ccx, fn_ty.fn_style, id, &fn_ty.sig,
                                decl, id, body, &inh);
 
-            vtable2::select_all_fcx_obligations_or_error(&fcx);
+            vtable::select_all_fcx_obligations_or_error(&fcx);
             regionck::regionck_fn(&fcx, id, body);
             writeback::resolve_type_vars_in_fn(&fcx, decl, body);
         }
@@ -1372,7 +1372,7 @@ fn check_cast(fcx: &FnCtxt,
 
     if ty::type_is_trait(t_1) {
         // This will be looked up later on.
-        vtable2::check_object_cast(fcx, cast_expr, e, t_1);
+        vtable::check_object_cast(fcx, cast_expr, e, t_1);
         fcx.write_ty(id, t_1);
         return
     }
@@ -1677,7 +1677,7 @@ fn register_unsize_obligations(&self,
             ty::UnsizeVtable(ref ty_trait, self_ty) => {
                 // If the type is `Foo+'a`, ensures that the type
                 // being cast to `Foo+'a` implements `Foo`:
-                vtable2::register_object_cast_obligations(self,
+                vtable::register_object_cast_obligations(self,
                                                           span,
                                                           ty_trait,
                                                           self_ty);
@@ -2564,7 +2564,7 @@ fn check_argument_types<'a>(fcx: &FnCtxt,
         // an "opportunistic" vtable resolution of any trait
         // bounds on the call.
         if check_blocks {
-            vtable2::select_fcx_obligations_where_possible(fcx);
+            vtable::select_fcx_obligations_where_possible(fcx);
         }
 
         // For variadic functions, we don't have a declared type for all of
@@ -4036,7 +4036,7 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
       ast::ExprForLoop(ref pat, ref head, ref block, _) => {
         check_expr(fcx, &**head);
         let typ = lookup_method_for_for_loop(fcx, &**head, expr.id);
-        vtable2::select_fcx_obligations_where_possible(fcx);
+        vtable::select_fcx_obligations_where_possible(fcx);
 
         let pcx = pat_ctxt {
             fcx: fcx,
@@ -4743,7 +4743,7 @@ pub fn check_const_with_ty(fcx: &FnCtxt,
 
     check_expr_with_hint(fcx, e, declty);
     demand::coerce(fcx, e.span, declty, e);
-    vtable2::select_all_fcx_obligations_or_error(fcx);
+    vtable::select_all_fcx_obligations_or_error(fcx);
     regionck::regionck_expr(fcx, e);
     writeback::resolve_type_vars_in_expr(fcx, e);
 }
index 31fe30fc9f857c756cd38754aa1cec4f8b687055..deeee67ac6eab5174a98df261e5b7537523dc737 100644 (file)
@@ -126,7 +126,7 @@ fn get_i(x: &'a Bar) -> &'a int {
 use middle::typeck::astconv::AstConv;
 use middle::typeck::check::FnCtxt;
 use middle::typeck::check::regionmanip;
-use middle::typeck::check::vtable2;
+use middle::typeck::check::vtable;
 use middle::typeck::infer::resolve_and_force_all_but_regions;
 use middle::typeck::infer::resolve_type;
 use middle::typeck::infer;
@@ -172,7 +172,7 @@ pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) {
 
     // Region checking a fn can introduce new trait obligations,
     // particularly around closure bounds.
-    vtable2::select_all_fcx_obligations_or_error(fcx);
+    vtable::select_all_fcx_obligations_or_error(fcx);
 
     fcx.infcx().resolve_regions_and_report_errors();
 }
@@ -1494,7 +1494,6 @@ fn link_region(rcx: &Rcx,
                 }
             }
 
-            mc::cat_discr(cmt_base, _) |
             mc::cat_downcast(cmt_base) |
             mc::cat_deref(cmt_base, _, mc::OwnedPtr) |
             mc::cat_interior(cmt_base, _) => {
@@ -1675,7 +1674,7 @@ fn link_reborrowed_region(rcx: &Rcx,
             //
             // If mutability was inferred from an upvar, we may be
             // forced to revisit this decision later if processing
-            // another borrow or nested closure ends up coverting the
+            // another borrow or nested closure ends up converting the
             // upvar borrow kind to mutable/unique.  Record the
             // information needed to perform the recursive link in the
             // maybe link map.
@@ -1736,8 +1735,7 @@ fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
         match cmt.cat.clone() {
             mc::cat_deref(base, _, mc::OwnedPtr) |
             mc::cat_interior(base, _) |
-            mc::cat_downcast(base) |
-            mc::cat_discr(base, _) => {
+            mc::cat_downcast(base) => {
                 // Interior or owned data is mutable if base is
                 // mutable, so iterate to the base.
                 cmt = base;
@@ -1788,8 +1786,7 @@ fn adjust_upvar_borrow_kind_for_unique(rcx: &Rcx, cmt: mc::cmt) {
         match cmt.cat.clone() {
             mc::cat_deref(base, _, mc::OwnedPtr) |
             mc::cat_interior(base, _) |
-            mc::cat_downcast(base) |
-            mc::cat_discr(base, _) => {
+            mc::cat_downcast(base) => {
                 // Interior or owned data is unique if base is
                 // unique.
                 cmt = base;
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
new file mode 100644 (file)
index 0000000..d557a2b
--- /dev/null
@@ -0,0 +1,415 @@
+// 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 middle::subst::{SelfSpace};
+use middle::traits;
+use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented};
+use middle::traits::{Obligation, obligation_for_builtin_bound};
+use middle::traits::{FulfillmentError, CodeSelectionError, CodeAmbiguity};
+use middle::traits::{ObligationCause};
+use middle::ty;
+use middle::typeck::check::{FnCtxt,
+                            structurally_resolved_type};
+use middle::typeck::infer;
+use std::rc::Rc;
+use syntax::ast;
+use syntax::codemap::Span;
+use util::ppaux::UserString;
+use util::ppaux::Repr;
+
+pub fn check_object_cast(fcx: &FnCtxt,
+                         cast_expr: &ast::Expr,
+                         source_expr: &ast::Expr,
+                         target_object_ty: ty::t)
+{
+    debug!("check_object_cast(cast_expr={}, target_object_ty={})",
+           cast_expr.repr(fcx.tcx()),
+           target_object_ty.repr(fcx.tcx()));
+
+    // Look up vtables for the type we're casting to,
+    // passing in the source and target type.  The source
+    // must be a pointer type suitable to the object sigil,
+    // e.g.: `&x as &Trait` or `box x as Box<Trait>`
+    let source_ty = fcx.expr_ty(source_expr);
+    let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty);
+    debug!("source_ty={}", source_ty.repr(fcx.tcx()));
+    match (&ty::get(source_ty).sty, &ty::get(target_object_ty).sty) {
+        (&ty::ty_uniq(referent_ty), &ty::ty_uniq(object_trait_ty)) => {
+            let object_trait = object_trait(&object_trait_ty);
+
+            // Ensure that if ~T is cast to ~Trait, then T : Trait
+            push_cast_obligation(fcx, cast_expr, object_trait, referent_ty);
+        }
+
+        (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty,
+                                                mutbl: referent_mutbl }),
+         &ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty,
+                                              mutbl: target_mutbl })) =>
+        {
+            let object_trait = object_trait(&object_trait_ty);
+            if !mutability_allowed(referent_mutbl, target_mutbl) {
+                fcx.tcx().sess.span_err(source_expr.span,
+                                        "types differ in mutability");
+            } else {
+                // Ensure that if &'a T is cast to &'b Trait, then T : Trait
+                push_cast_obligation(fcx, cast_expr,
+                                     object_trait,
+                                     referent_ty);
+
+                // Ensure that if &'a T is cast to &'b Trait, then 'b <= 'a
+                infer::mk_subr(fcx.infcx(),
+                               infer::RelateObjectBound(source_expr.span),
+                               target_region,
+                               referent_region);
+            }
+        }
+
+        (_, &ty::ty_uniq(..)) => {
+            fcx.ccx.tcx.sess.span_err(
+                source_expr.span,
+                format!("can only cast an boxed pointer \
+                         to a boxed object, not a {}",
+                        ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice());
+        }
+
+        (_, &ty::ty_rptr(..)) => {
+            fcx.ccx.tcx.sess.span_err(
+                source_expr.span,
+                format!("can only cast a &-pointer \
+                         to an &-object, not a {}",
+                        ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice());
+        }
+
+        _ => {
+            fcx.tcx().sess.span_bug(
+                source_expr.span,
+                "expected object type");
+        }
+    }
+
+    // Because we currently give unsound lifetimes to the "t_box", I
+    // could have written &'static ty::TyTrait here, but it seems
+    // gratuitously unsafe.
+    fn object_trait<'a>(t: &'a ty::t) -> &'a ty::TyTrait {
+        match ty::get(*t).sty {
+            ty::ty_trait(ref ty_trait) => &**ty_trait,
+            _ => fail!("expected ty_trait")
+        }
+    }
+
+    fn mutability_allowed(a_mutbl: ast::Mutability,
+                          b_mutbl: ast::Mutability)
+                          -> bool {
+        a_mutbl == b_mutbl ||
+            (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
+    }
+
+    fn push_cast_obligation(fcx: &FnCtxt,
+                            cast_expr: &ast::Expr,
+                            object_trait: &ty::TyTrait,
+                            referent_ty: ty::t) {
+        let object_trait_ref =
+            register_object_cast_obligations(fcx,
+                                             cast_expr.span,
+                                             object_trait,
+                                             referent_ty);
+
+        // Finally record the object_trait_ref for use during trans
+        // (it would prob be better not to do this, but it's just kind
+        // of a pain to have to reconstruct it).
+        fcx.write_object_cast(cast_expr.id, object_trait_ref);
+    }
+}
+
+pub fn register_object_cast_obligations(fcx: &FnCtxt,
+                                        span: Span,
+                                        object_trait: &ty::TyTrait,
+                                        referent_ty: ty::t)
+                                        -> Rc<ty::TraitRef>
+{
+    // This is just for better error reporting. Kinda goofy. The object type stuff
+    // needs some refactoring so there is a more convenient type to pass around.
+    let object_trait_ty =
+        ty::mk_trait(fcx.tcx(),
+                     object_trait.def_id,
+                     object_trait.substs.clone(),
+                     object_trait.bounds);
+
+    debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}",
+           referent_ty.repr(fcx.tcx()),
+           object_trait_ty.repr(fcx.tcx()));
+
+    // Take the type parameters from the object type, but set
+    // the Self type (which is unknown, for the object type)
+    // to be the type we are casting from.
+    let mut object_substs = object_trait.substs.clone();
+    assert!(object_substs.self_ty().is_none());
+    object_substs.types.push(SelfSpace, referent_ty);
+
+    // Create the obligation for casting from T to Trait.
+    let object_trait_ref =
+        Rc::new(ty::TraitRef { def_id: object_trait.def_id,
+                               substs: object_substs });
+    let object_obligation =
+        Obligation::new(
+            ObligationCause::new(span,
+                                 traits::ObjectCastObligation(object_trait_ty)),
+            object_trait_ref.clone());
+    fcx.register_obligation(object_obligation);
+
+    // Create additional obligations for all the various builtin
+    // bounds attached to the object cast. (In other words, if the
+    // object type is Foo+Send, this would create an obligation
+    // for the Send check.)
+    for builtin_bound in object_trait.bounds.builtin_bounds.iter() {
+            let obligation = obligation_for_builtin_bound(
+                fcx.tcx(),
+                ObligationCause::new(span,
+                                     traits::ObjectCastObligation(object_trait_ty)),
+                referent_ty,
+                builtin_bound);
+            match obligation {
+                Ok(obligation) => fcx.register_obligation(obligation),
+                _ => {}
+            }
+    }
+
+    object_trait_ref
+}
+
+pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
+    debug!("select_all_fcx_obligations_or_error");
+
+    let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
+    let r = fulfillment_cx.select_all_or_error(fcx.infcx(),
+                                               &fcx.inh.param_env,
+                                               fcx);
+    match r {
+        Ok(()) => { }
+        Err(errors) => { report_fulfillment_errors(fcx, &errors); }
+    }
+}
+
+fn resolve_trait_ref(fcx: &FnCtxt, obligation: &Obligation)
+                     -> (ty::TraitRef, ty::t)
+{
+    let trait_ref =
+        fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
+            &*obligation.trait_ref);
+    let self_ty =
+        trait_ref.substs.self_ty().unwrap();
+    (trait_ref, self_ty)
+}
+
+pub fn report_fulfillment_errors(fcx: &FnCtxt,
+                                 errors: &Vec<FulfillmentError>) {
+    for error in errors.iter() {
+        report_fulfillment_error(fcx, error);
+    }
+}
+
+pub fn report_fulfillment_error(fcx: &FnCtxt,
+                                error: &FulfillmentError) {
+    match error.code {
+        CodeSelectionError(ref e) => {
+            report_selection_error(fcx, &error.obligation, e);
+        }
+        CodeAmbiguity => {
+            maybe_report_ambiguity(fcx, &error.obligation);
+        }
+    }
+}
+
+pub fn report_selection_error(fcx: &FnCtxt,
+                              obligation: &Obligation,
+                              error: &SelectionError)
+{
+    match *error {
+        Overflow => {
+            let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
+            fcx.tcx().sess.span_err(
+                obligation.cause.span,
+                format!(
+                    "overflow evaluating the trait `{}` for the type `{}`",
+                    trait_ref.user_string(fcx.tcx()),
+                    self_ty.user_string(fcx.tcx())).as_slice());
+            note_obligation_cause(fcx, obligation);
+        }
+        Unimplemented => {
+            let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
+            if !ty::type_is_error(self_ty) {
+                fcx.tcx().sess.span_err(
+                    obligation.cause.span,
+                    format!(
+                        "the trait `{}` is not implemented for the type `{}`",
+                        trait_ref.user_string(fcx.tcx()),
+                        self_ty.user_string(fcx.tcx())).as_slice());
+                note_obligation_cause(fcx, obligation);
+            }
+        }
+        OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => {
+            let expected_trait_ref =
+                fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
+                    &**expected_trait_ref);
+            let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
+            if !ty::type_is_error(self_ty) {
+                fcx.tcx().sess.span_err(
+                    obligation.cause.span,
+                    format!(
+                        "type mismatch: the type `{}` implements the trait `{}`, \
+                         but the trait `{}` is required ({})",
+                        self_ty.user_string(fcx.tcx()),
+                        expected_trait_ref.user_string(fcx.tcx()),
+                        trait_ref.user_string(fcx.tcx()),
+                        ty::type_err_to_str(fcx.tcx(), e)).as_slice());
+                note_obligation_cause(fcx, obligation);
+            }
+        }
+    }
+}
+
+pub fn maybe_report_ambiguity(fcx: &FnCtxt, obligation: &Obligation) {
+    // Unable to successfully determine, probably means
+    // insufficient type information, but could mean
+    // ambiguous impls. The latter *ought* to be a
+    // coherence violation, so we don't report it here.
+    let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
+    debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})",
+           trait_ref.repr(fcx.tcx()),
+           self_ty.repr(fcx.tcx()),
+           obligation.repr(fcx.tcx()));
+    let all_types = &trait_ref.substs.types;
+    if all_types.iter().any(|&t| ty::type_is_error(t)) {
+    } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) {
+        // This is kind of a hack: it frequently happens that some earlier
+        // error prevents types from being fully inferred, and then we get
+        // a bunch of uninteresting errors saying something like "<generic
+        // #0> doesn't implement Sized".  It may even be true that we
+        // could just skip over all checks where the self-ty is an
+        // inference variable, but I was afraid that there might be an
+        // inference variable created, registered as an obligation, and
+        // then never forced by writeback, and hence by skipping here we'd
+        // be ignoring the fact that we don't KNOW the type works
+        // out. Though even that would probably be harmless, given that
+        // we're only talking about builtin traits, which are known to be
+        // inhabited. But in any case I just threw in this check for
+        // has_errors() to be sure that compilation isn't happening
+        // anyway. In that case, why inundate the user.
+        if !fcx.tcx().sess.has_errors() {
+            fcx.tcx().sess.span_err(
+                obligation.cause.span,
+                format!(
+                    "unable to infer enough type information to \
+                     locate the impl of the trait `{}` for \
+                     the type `{}`; type annotations required",
+                    trait_ref.user_string(fcx.tcx()),
+                    self_ty.user_string(fcx.tcx())).as_slice());
+            note_obligation_cause(fcx, obligation);
+        }
+    } else if !fcx.tcx().sess.has_errors() {
+         // Ambiguity. Coherence should have reported an error.
+        fcx.tcx().sess.span_bug(
+            obligation.cause.span,
+            format!(
+                "coherence failed to report ambiguity: \
+                 cannot locate the impl of the trait `{}` for \
+                 the type `{}`",
+                trait_ref.user_string(fcx.tcx()),
+                self_ty.user_string(fcx.tcx())).as_slice());
+    }
+}
+
+pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) {
+    /*! Select as many obligations as we can at present. */
+
+    match
+        fcx.inh.fulfillment_cx
+        .borrow_mut()
+        .select_where_possible(fcx.infcx(), &fcx.inh.param_env, fcx)
+    {
+        Ok(()) => { }
+        Err(errors) => { report_fulfillment_errors(fcx, &errors); }
+    }
+}
+
+fn note_obligation_cause(fcx: &FnCtxt,
+                         obligation: &Obligation) {
+    let tcx = fcx.tcx();
+    let trait_name = ty::item_path_str(tcx, obligation.trait_ref.def_id);
+    match obligation.cause.code {
+        traits::MiscObligation => { }
+        traits::ItemObligation(item_def_id) => {
+            let item_name = ty::item_path_str(tcx, item_def_id);
+            tcx.sess.span_note(
+                obligation.cause.span,
+                format!(
+                    "the trait `{}` must be implemented because it is required by `{}`",
+                    trait_name,
+                    item_name).as_slice());
+        }
+        traits::ObjectCastObligation(object_ty) => {
+            tcx.sess.span_note(
+                obligation.cause.span,
+                format!(
+                    "the trait `{}` must be implemented for the cast \
+                     to the object type `{}`",
+                    trait_name,
+                    fcx.infcx().ty_to_string(object_ty)).as_slice());
+        }
+        traits::RepeatVec => {
+            tcx.sess.span_note(
+                obligation.cause.span,
+                "the `Copy` trait is required because the \
+                 repeated element will be copied");
+        }
+        traits::VariableType(_) => {
+            tcx.sess.span_note(
+                obligation.cause.span,
+                "all local variables must have a statically known size");
+        }
+        traits::ReturnType => {
+            tcx.sess.span_note(
+                obligation.cause.span,
+                "the return type of a function must have a \
+                 statically known size");
+        }
+        traits::AssignmentLhsSized => {
+            tcx.sess.span_note(
+                obligation.cause.span,
+                "the left-hand-side of an assignment must have a statically known size");
+        }
+        traits::StructInitializerSized => {
+            tcx.sess.span_note(
+                obligation.cause.span,
+                "structs must have a statically known size to be initialized");
+        }
+        traits::DropTrait => {
+            span_note!(tcx.sess, obligation.cause.span,
+                      "cannot implement a destructor on a \
+                      structure or enumeration that does not satisfy Send");
+            span_note!(tcx.sess, obligation.cause.span,
+                       "use \"#[unsafe_destructor]\" on the implementation \
+                       to force the compiler to allow this");
+        }
+        traits::ClosureCapture(var_id, closure_span) => {
+            let name = ty::local_var_name_str(tcx, var_id);
+            span_note!(tcx.sess, closure_span,
+                       "the closure that captures `{}` requires that all captured variables \"
+                       implement the trait `{}`",
+                       name,
+                       trait_name);
+        }
+        traits::FieldSized => {
+            span_note!(tcx.sess, obligation.cause.span,
+                       "only the last field of a struct or enum variant \
+                       may have a dynamically sized type")
+        }
+    }
+}
diff --git a/src/librustc/middle/typeck/check/vtable2.rs b/src/librustc/middle/typeck/check/vtable2.rs
deleted file mode 100644 (file)
index d557a2b..0000000
+++ /dev/null
@@ -1,415 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use middle::subst::{SelfSpace};
-use middle::traits;
-use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented};
-use middle::traits::{Obligation, obligation_for_builtin_bound};
-use middle::traits::{FulfillmentError, CodeSelectionError, CodeAmbiguity};
-use middle::traits::{ObligationCause};
-use middle::ty;
-use middle::typeck::check::{FnCtxt,
-                            structurally_resolved_type};
-use middle::typeck::infer;
-use std::rc::Rc;
-use syntax::ast;
-use syntax::codemap::Span;
-use util::ppaux::UserString;
-use util::ppaux::Repr;
-
-pub fn check_object_cast(fcx: &FnCtxt,
-                         cast_expr: &ast::Expr,
-                         source_expr: &ast::Expr,
-                         target_object_ty: ty::t)
-{
-    debug!("check_object_cast(cast_expr={}, target_object_ty={})",
-           cast_expr.repr(fcx.tcx()),
-           target_object_ty.repr(fcx.tcx()));
-
-    // Look up vtables for the type we're casting to,
-    // passing in the source and target type.  The source
-    // must be a pointer type suitable to the object sigil,
-    // e.g.: `&x as &Trait` or `box x as Box<Trait>`
-    let source_ty = fcx.expr_ty(source_expr);
-    let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty);
-    debug!("source_ty={}", source_ty.repr(fcx.tcx()));
-    match (&ty::get(source_ty).sty, &ty::get(target_object_ty).sty) {
-        (&ty::ty_uniq(referent_ty), &ty::ty_uniq(object_trait_ty)) => {
-            let object_trait = object_trait(&object_trait_ty);
-
-            // Ensure that if ~T is cast to ~Trait, then T : Trait
-            push_cast_obligation(fcx, cast_expr, object_trait, referent_ty);
-        }
-
-        (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty,
-                                                mutbl: referent_mutbl }),
-         &ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty,
-                                              mutbl: target_mutbl })) =>
-        {
-            let object_trait = object_trait(&object_trait_ty);
-            if !mutability_allowed(referent_mutbl, target_mutbl) {
-                fcx.tcx().sess.span_err(source_expr.span,
-                                        "types differ in mutability");
-            } else {
-                // Ensure that if &'a T is cast to &'b Trait, then T : Trait
-                push_cast_obligation(fcx, cast_expr,
-                                     object_trait,
-                                     referent_ty);
-
-                // Ensure that if &'a T is cast to &'b Trait, then 'b <= 'a
-                infer::mk_subr(fcx.infcx(),
-                               infer::RelateObjectBound(source_expr.span),
-                               target_region,
-                               referent_region);
-            }
-        }
-
-        (_, &ty::ty_uniq(..)) => {
-            fcx.ccx.tcx.sess.span_err(
-                source_expr.span,
-                format!("can only cast an boxed pointer \
-                         to a boxed object, not a {}",
-                        ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice());
-        }
-
-        (_, &ty::ty_rptr(..)) => {
-            fcx.ccx.tcx.sess.span_err(
-                source_expr.span,
-                format!("can only cast a &-pointer \
-                         to an &-object, not a {}",
-                        ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice());
-        }
-
-        _ => {
-            fcx.tcx().sess.span_bug(
-                source_expr.span,
-                "expected object type");
-        }
-    }
-
-    // Because we currently give unsound lifetimes to the "t_box", I
-    // could have written &'static ty::TyTrait here, but it seems
-    // gratuitously unsafe.
-    fn object_trait<'a>(t: &'a ty::t) -> &'a ty::TyTrait {
-        match ty::get(*t).sty {
-            ty::ty_trait(ref ty_trait) => &**ty_trait,
-            _ => fail!("expected ty_trait")
-        }
-    }
-
-    fn mutability_allowed(a_mutbl: ast::Mutability,
-                          b_mutbl: ast::Mutability)
-                          -> bool {
-        a_mutbl == b_mutbl ||
-            (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
-    }
-
-    fn push_cast_obligation(fcx: &FnCtxt,
-                            cast_expr: &ast::Expr,
-                            object_trait: &ty::TyTrait,
-                            referent_ty: ty::t) {
-        let object_trait_ref =
-            register_object_cast_obligations(fcx,
-                                             cast_expr.span,
-                                             object_trait,
-                                             referent_ty);
-
-        // Finally record the object_trait_ref for use during trans
-        // (it would prob be better not to do this, but it's just kind
-        // of a pain to have to reconstruct it).
-        fcx.write_object_cast(cast_expr.id, object_trait_ref);
-    }
-}
-
-pub fn register_object_cast_obligations(fcx: &FnCtxt,
-                                        span: Span,
-                                        object_trait: &ty::TyTrait,
-                                        referent_ty: ty::t)
-                                        -> Rc<ty::TraitRef>
-{
-    // This is just for better error reporting. Kinda goofy. The object type stuff
-    // needs some refactoring so there is a more convenient type to pass around.
-    let object_trait_ty =
-        ty::mk_trait(fcx.tcx(),
-                     object_trait.def_id,
-                     object_trait.substs.clone(),
-                     object_trait.bounds);
-
-    debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}",
-           referent_ty.repr(fcx.tcx()),
-           object_trait_ty.repr(fcx.tcx()));
-
-    // Take the type parameters from the object type, but set
-    // the Self type (which is unknown, for the object type)
-    // to be the type we are casting from.
-    let mut object_substs = object_trait.substs.clone();
-    assert!(object_substs.self_ty().is_none());
-    object_substs.types.push(SelfSpace, referent_ty);
-
-    // Create the obligation for casting from T to Trait.
-    let object_trait_ref =
-        Rc::new(ty::TraitRef { def_id: object_trait.def_id,
-                               substs: object_substs });
-    let object_obligation =
-        Obligation::new(
-            ObligationCause::new(span,
-                                 traits::ObjectCastObligation(object_trait_ty)),
-            object_trait_ref.clone());
-    fcx.register_obligation(object_obligation);
-
-    // Create additional obligations for all the various builtin
-    // bounds attached to the object cast. (In other words, if the
-    // object type is Foo+Send, this would create an obligation
-    // for the Send check.)
-    for builtin_bound in object_trait.bounds.builtin_bounds.iter() {
-            let obligation = obligation_for_builtin_bound(
-                fcx.tcx(),
-                ObligationCause::new(span,
-                                     traits::ObjectCastObligation(object_trait_ty)),
-                referent_ty,
-                builtin_bound);
-            match obligation {
-                Ok(obligation) => fcx.register_obligation(obligation),
-                _ => {}
-            }
-    }
-
-    object_trait_ref
-}
-
-pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
-    debug!("select_all_fcx_obligations_or_error");
-
-    let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
-    let r = fulfillment_cx.select_all_or_error(fcx.infcx(),
-                                               &fcx.inh.param_env,
-                                               fcx);
-    match r {
-        Ok(()) => { }
-        Err(errors) => { report_fulfillment_errors(fcx, &errors); }
-    }
-}
-
-fn resolve_trait_ref(fcx: &FnCtxt, obligation: &Obligation)
-                     -> (ty::TraitRef, ty::t)
-{
-    let trait_ref =
-        fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
-            &*obligation.trait_ref);
-    let self_ty =
-        trait_ref.substs.self_ty().unwrap();
-    (trait_ref, self_ty)
-}
-
-pub fn report_fulfillment_errors(fcx: &FnCtxt,
-                                 errors: &Vec<FulfillmentError>) {
-    for error in errors.iter() {
-        report_fulfillment_error(fcx, error);
-    }
-}
-
-pub fn report_fulfillment_error(fcx: &FnCtxt,
-                                error: &FulfillmentError) {
-    match error.code {
-        CodeSelectionError(ref e) => {
-            report_selection_error(fcx, &error.obligation, e);
-        }
-        CodeAmbiguity => {
-            maybe_report_ambiguity(fcx, &error.obligation);
-        }
-    }
-}
-
-pub fn report_selection_error(fcx: &FnCtxt,
-                              obligation: &Obligation,
-                              error: &SelectionError)
-{
-    match *error {
-        Overflow => {
-            let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
-            fcx.tcx().sess.span_err(
-                obligation.cause.span,
-                format!(
-                    "overflow evaluating the trait `{}` for the type `{}`",
-                    trait_ref.user_string(fcx.tcx()),
-                    self_ty.user_string(fcx.tcx())).as_slice());
-            note_obligation_cause(fcx, obligation);
-        }
-        Unimplemented => {
-            let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
-            if !ty::type_is_error(self_ty) {
-                fcx.tcx().sess.span_err(
-                    obligation.cause.span,
-                    format!(
-                        "the trait `{}` is not implemented for the type `{}`",
-                        trait_ref.user_string(fcx.tcx()),
-                        self_ty.user_string(fcx.tcx())).as_slice());
-                note_obligation_cause(fcx, obligation);
-            }
-        }
-        OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => {
-            let expected_trait_ref =
-                fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
-                    &**expected_trait_ref);
-            let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
-            if !ty::type_is_error(self_ty) {
-                fcx.tcx().sess.span_err(
-                    obligation.cause.span,
-                    format!(
-                        "type mismatch: the type `{}` implements the trait `{}`, \
-                         but the trait `{}` is required ({})",
-                        self_ty.user_string(fcx.tcx()),
-                        expected_trait_ref.user_string(fcx.tcx()),
-                        trait_ref.user_string(fcx.tcx()),
-                        ty::type_err_to_str(fcx.tcx(), e)).as_slice());
-                note_obligation_cause(fcx, obligation);
-            }
-        }
-    }
-}
-
-pub fn maybe_report_ambiguity(fcx: &FnCtxt, obligation: &Obligation) {
-    // Unable to successfully determine, probably means
-    // insufficient type information, but could mean
-    // ambiguous impls. The latter *ought* to be a
-    // coherence violation, so we don't report it here.
-    let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
-    debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})",
-           trait_ref.repr(fcx.tcx()),
-           self_ty.repr(fcx.tcx()),
-           obligation.repr(fcx.tcx()));
-    let all_types = &trait_ref.substs.types;
-    if all_types.iter().any(|&t| ty::type_is_error(t)) {
-    } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) {
-        // This is kind of a hack: it frequently happens that some earlier
-        // error prevents types from being fully inferred, and then we get
-        // a bunch of uninteresting errors saying something like "<generic
-        // #0> doesn't implement Sized".  It may even be true that we
-        // could just skip over all checks where the self-ty is an
-        // inference variable, but I was afraid that there might be an
-        // inference variable created, registered as an obligation, and
-        // then never forced by writeback, and hence by skipping here we'd
-        // be ignoring the fact that we don't KNOW the type works
-        // out. Though even that would probably be harmless, given that
-        // we're only talking about builtin traits, which are known to be
-        // inhabited. But in any case I just threw in this check for
-        // has_errors() to be sure that compilation isn't happening
-        // anyway. In that case, why inundate the user.
-        if !fcx.tcx().sess.has_errors() {
-            fcx.tcx().sess.span_err(
-                obligation.cause.span,
-                format!(
-                    "unable to infer enough type information to \
-                     locate the impl of the trait `{}` for \
-                     the type `{}`; type annotations required",
-                    trait_ref.user_string(fcx.tcx()),
-                    self_ty.user_string(fcx.tcx())).as_slice());
-            note_obligation_cause(fcx, obligation);
-        }
-    } else if !fcx.tcx().sess.has_errors() {
-         // Ambiguity. Coherence should have reported an error.
-        fcx.tcx().sess.span_bug(
-            obligation.cause.span,
-            format!(
-                "coherence failed to report ambiguity: \
-                 cannot locate the impl of the trait `{}` for \
-                 the type `{}`",
-                trait_ref.user_string(fcx.tcx()),
-                self_ty.user_string(fcx.tcx())).as_slice());
-    }
-}
-
-pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) {
-    /*! Select as many obligations as we can at present. */
-
-    match
-        fcx.inh.fulfillment_cx
-        .borrow_mut()
-        .select_where_possible(fcx.infcx(), &fcx.inh.param_env, fcx)
-    {
-        Ok(()) => { }
-        Err(errors) => { report_fulfillment_errors(fcx, &errors); }
-    }
-}
-
-fn note_obligation_cause(fcx: &FnCtxt,
-                         obligation: &Obligation) {
-    let tcx = fcx.tcx();
-    let trait_name = ty::item_path_str(tcx, obligation.trait_ref.def_id);
-    match obligation.cause.code {
-        traits::MiscObligation => { }
-        traits::ItemObligation(item_def_id) => {
-            let item_name = ty::item_path_str(tcx, item_def_id);
-            tcx.sess.span_note(
-                obligation.cause.span,
-                format!(
-                    "the trait `{}` must be implemented because it is required by `{}`",
-                    trait_name,
-                    item_name).as_slice());
-        }
-        traits::ObjectCastObligation(object_ty) => {
-            tcx.sess.span_note(
-                obligation.cause.span,
-                format!(
-                    "the trait `{}` must be implemented for the cast \
-                     to the object type `{}`",
-                    trait_name,
-                    fcx.infcx().ty_to_string(object_ty)).as_slice());
-        }
-        traits::RepeatVec => {
-            tcx.sess.span_note(
-                obligation.cause.span,
-                "the `Copy` trait is required because the \
-                 repeated element will be copied");
-        }
-        traits::VariableType(_) => {
-            tcx.sess.span_note(
-                obligation.cause.span,
-                "all local variables must have a statically known size");
-        }
-        traits::ReturnType => {
-            tcx.sess.span_note(
-                obligation.cause.span,
-                "the return type of a function must have a \
-                 statically known size");
-        }
-        traits::AssignmentLhsSized => {
-            tcx.sess.span_note(
-                obligation.cause.span,
-                "the left-hand-side of an assignment must have a statically known size");
-        }
-        traits::StructInitializerSized => {
-            tcx.sess.span_note(
-                obligation.cause.span,
-                "structs must have a statically known size to be initialized");
-        }
-        traits::DropTrait => {
-            span_note!(tcx.sess, obligation.cause.span,
-                      "cannot implement a destructor on a \
-                      structure or enumeration that does not satisfy Send");
-            span_note!(tcx.sess, obligation.cause.span,
-                       "use \"#[unsafe_destructor]\" on the implementation \
-                       to force the compiler to allow this");
-        }
-        traits::ClosureCapture(var_id, closure_span) => {
-            let name = ty::local_var_name_str(tcx, var_id);
-            span_note!(tcx.sess, closure_span,
-                       "the closure that captures `{}` requires that all captured variables \"
-                       implement the trait `{}`",
-                       name,
-                       trait_name);
-        }
-        traits::FieldSized => {
-            span_note!(tcx.sess, obligation.cause.span,
-                       "only the last field of a struct or enum variant \
-                       may have a dynamically sized type")
-        }
-    }
-}
index dc79fd4aa328c151fdf75d200069f08f96ae2630..3c594fbf2d3661ea4277cdfe79dd34d41092b48e 100644 (file)
@@ -14,7 +14,7 @@
 use middle::ty;
 use middle::ty_fold::{TypeFolder, TypeFoldable};
 use middle::typeck::astconv::AstConv;
-use middle::typeck::check::{FnCtxt, Inherited, blank_fn_ctxt, vtable2, regionck};
+use middle::typeck::check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck};
 use middle::typeck::check::regionmanip::replace_late_bound_regions;
 use middle::typeck::CrateCtxt;
 use util::ppaux::Repr;
@@ -100,7 +100,7 @@ fn with_fcx(&mut self,
         let inh = Inherited::new(ccx.tcx, param_env);
         let fcx = blank_fn_ctxt(ccx, &inh, polytype.ty, item.id);
         f(self, &fcx);
-        vtable2::select_all_fcx_obligations_or_error(&fcx);
+        vtable::select_all_fcx_obligations_or_error(&fcx);
         regionck::regionck_item(&fcx, item);
     }
 
index 0ef0601828d735703ae7ee9a33e098e3d557b013..6a33777a413c5d5fa8394c47e18271095b913856 100644 (file)
@@ -71,7 +71,6 @@ fn main() {
 
 */
 
-use alloc::libc_heap::malloc_raw;
 use collections::string::String;
 use collections::hash;
 use core::fmt;
@@ -101,7 +100,8 @@ impl Clone for CString {
     /// with C's allocator API, rather than the usual shallow clone.
     fn clone(&self) -> CString {
         let len = self.len() + 1;
-        let buf = unsafe { malloc_raw(len) } as *mut libc::c_char;
+        let buf = unsafe { libc::malloc(len as libc::size_t) } as *mut libc::c_char;
+        if buf.is_null() { fail!("out of memory") }
         unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); }
         CString { buf: buf as *const libc::c_char, owns_buffer_: true }
     }
@@ -393,7 +393,8 @@ fn to_c_str(&self) -> CString {
 
     unsafe fn to_c_str_unchecked(&self) -> CString {
         let self_len = self.len();
-        let buf = malloc_raw(self_len + 1);
+        let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
+        if buf.is_null() { fail!("out of memory") }
 
         ptr::copy_memory(buf, self.as_ptr(), self_len);
         *buf.offset(self_len as int) = 0;
index b328df1949e0e57ab9e2b608e3671109073b1e64..838dfd6b7abe6b5807dfc0e6e5df06b5ebae1743 100644 (file)
@@ -516,7 +516,7 @@ fn pthread_cond_wait(cond: *mut pthread_cond_t,
 
 #[cfg(windows)]
 mod imp {
-    use alloc::libc_heap::malloc_raw;
+    use alloc::heap;
     use core::atomic;
     use core::ptr;
     use libc::{HANDLE, BOOL, LPSECURITY_ATTRIBUTES, c_void, DWORD, LPCSTR};
@@ -607,7 +607,7 @@ unsafe fn getcond(&self) -> *mut c_void {
     }
 
     pub unsafe fn init_lock() -> uint {
-        let block = malloc_raw(CRIT_SECTION_SIZE as uint) as *mut c_void;
+        let block = heap::allocate(CRIT_SECTION_SIZE, 8) as *mut c_void;
         InitializeCriticalSectionAndSpinCount(block, SPIN_COUNT);
         return block as uint;
     }
@@ -619,7 +619,7 @@ pub unsafe fn init_cond() -> uint {
 
     pub unsafe fn free_lock(h: uint) {
         DeleteCriticalSection(h as LPCRITICAL_SECTION);
-        libc::free(h as *mut c_void);
+        heap::deallocate(h as *mut u8, CRIT_SECTION_SIZE, 8);
     }
 
     pub unsafe fn free_cond(h: uint) {
index 95f8ab720169391af38079d9148274323b86ea2e..7ec25acb17308af454bb12f65c99d1ec08bc667d 100644 (file)
@@ -165,11 +165,11 @@ mod tests {
     use super::CVec;
     use libc;
     use ptr;
-    use rt::libc_heap::malloc_raw;
 
     fn malloc(n: uint) -> CVec<u8> {
         unsafe {
-            let mem = malloc_raw(n);
+            let mem = libc::malloc(n as libc::size_t);
+            if mem.is_null() { fail!("out of memory") }
 
             CVec::new_with_dtor(mem as *mut u8, n,
                 proc() { libc::free(mem as *mut libc::c_void); })
index dde1f27c9a322dd54665d584c81224d6e63be61b..ca954679c1c9d7db7851c03df088a8bf33524f32 100644 (file)
@@ -186,7 +186,7 @@ pub fn reserve(&mut self, n: uint) {
     /// # Example
     ///
     /// This is a slightly silly example where we define the number's
-    /// parity as the equivilance class. It is important that the
+    /// parity as the equivalance class. It is important that the
     /// values hash the same, which is why we implement `Hash`.
     ///
     /// ```
index f86ae05d623ca462c2a70e87c9e899b19326d996..dd4a3e0593594100dacb97bcf0f56ef26a1acf4f 100644 (file)
@@ -22,7 +22,7 @@
 use slice::AsSlice;
 use vec::Vec;
 
-static BUF_CAPACITY: uint = 128;
+const BUF_CAPACITY: uint = 128;
 
 fn combine(seek: SeekStyle, cur: uint, end: uint, offset: i64) -> IoResult<u64> {
     // compute offset as signed and clamp to prevent overflow
@@ -71,7 +71,12 @@ pub fn new() -> MemWriter {
     /// the internal buffer.
     #[inline]
     pub fn with_capacity(n: uint) -> MemWriter {
-        MemWriter { buf: Vec::with_capacity(n) }
+        MemWriter::from_vec(Vec::with_capacity(n))
+    }
+    /// Create a new `MemWriter` that will append to an existing `Vec`.
+    #[inline]
+    pub fn from_vec(buf: Vec<u8>) -> MemWriter {
+        MemWriter { buf: buf }
     }
 
     /// Acquires an immutable reference to the underlying buffer of this
index 53e60d553be5f6ce0ba3297b25dcefcf00cabab9..7d9eea3a73279bf535fdeb6cc8cb230fe6bf6718 100644 (file)
@@ -100,6 +100,8 @@ pub fn send_to(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> {
     ///
     /// Note that this call does not perform any actual network communication,
     /// because UDP is a datagram protocol.
+    #[deprecated = "`UdpStream` has been deprecated"]
+    #[allow(deprecated)]
     pub fn connect(self, other: SocketAddr) -> UdpStream {
         UdpStream {
             socket: self,
@@ -205,6 +207,14 @@ fn clone(&self) -> UdpSocket {
 
 /// A type that allows convenient usage of a UDP stream connected to one
 /// address via the `Reader` and `Writer` traits.
+///
+/// # Note
+///
+/// This structure has been deprecated because `Reader` is a stream-oriented API but UDP
+/// is a packet-oriented protocol. Every `Reader` method will read a whole packet and
+/// throw all superfluous bytes away so that they are no longer available for further
+/// method calls.
+#[deprecated]
 pub struct UdpStream {
     socket: UdpSocket,
     connected_to: SocketAddr
@@ -225,13 +235,15 @@ pub fn disconnect(self) -> UdpSocket {
 }
 
 impl Reader for UdpStream {
+    /// Returns the next non-empty message from the specified address.
     fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
         let peer = self.connected_to;
         self.as_socket(|sock| {
-            match sock.recv_from(buf) {
-                Ok((_nread, src)) if src != peer => Ok(0),
-                Ok((nread, _src)) => Ok(nread),
-                Err(e) => Err(e),
+            loop {
+                let (nread, src) = try!(sock.recv_from(buf));
+                if nread > 0 && src == peer {
+                    return Ok(nread);
+                }
             }
         })
     }
@@ -334,22 +346,28 @@ fn socket_smoke_test_ip6() {
     }
 
     #[test]
+    #[allow(deprecated)]
     fn stream_smoke_test_ip4() {
         let server_ip = next_test_ip4();
         let client_ip = next_test_ip4();
+        let dummy_ip = next_test_ip4();
         let (tx1, rx1) = channel();
         let (tx2, rx2) = channel();
 
         spawn(proc() {
-            match UdpSocket::bind(client_ip) {
-                Ok(client) => {
-                    let client = box client;
-                    let mut stream = client.connect(server_ip);
-                    rx1.recv();
-                    stream.write([99]).unwrap();
+            let send_as = |ip, val: &[u8]| {
+                match UdpSocket::bind(ip) {
+                    Ok(client) => {
+                        let client = box client;
+                        let mut stream = client.connect(server_ip);
+                        stream.write(val).unwrap();
+                    }
+                    Err(..) => fail!()
                 }
-                Err(..) => fail!()
-            }
+            };
+            rx1.recv();
+            send_as(dummy_ip, [98]);
+            send_as(client_ip, [99]);
             tx2.send(());
         });
 
@@ -364,7 +382,7 @@ fn stream_smoke_test_ip4() {
                         assert_eq!(nread, 1);
                         assert_eq!(buf[0], 99);
                     }
-                    Err(..) => fail!()
+                    Err(..) => fail!(),
                 }
             }
             Err(..) => fail!()
@@ -373,6 +391,7 @@ fn stream_smoke_test_ip4() {
     }
 
     #[test]
+    #[allow(deprecated)]
     fn stream_smoke_test_ip6() {
         let server_ip = next_test_ip6();
         let client_ip = next_test_ip6();
index 689bcdad1311cfd40e7a767e31292646fc2f35dc..a91c6c572e686c0f8ff073b342846f8c3a9b08ce 100644 (file)
@@ -62,7 +62,7 @@
 
 // Reexport functionality from librustrt and other crates underneath the
 // standard library which work together to create the entire runtime.
-pub use alloc::{heap, libc_heap};
+pub use alloc::heap;
 pub use rustrt::{task, local, mutex, exclusive, stack, args, rtio, thread};
 pub use rustrt::{Stdio, Stdout, Stderr, begin_unwind, begin_unwind_fmt};
 pub use rustrt::{bookkeeping, at_exit, unwind, DEFAULT_ERROR_CODE, Runtime};
index 8eaee7282d1971f4527f37cb4287626add9f0ca3..eaa370d95a85c1321e15691922165648dae287be 100644 (file)
@@ -24,6 +24,9 @@
 use std::rc::Rc;
 use serialize::{Encodable, Decodable, Encoder, Decoder};
 
+#[cfg(stage0)]
+pub use self::TtToken as TTTok;
+
 // FIXME #6993: in librustc, uses of "ident" should be replaced
 // by just "Name".
 
@@ -436,7 +439,7 @@ pub enum Stmt_ {
     /// Expr with trailing semi-colon (may have any type):
     StmtSemi(P<Expr>, NodeId),
 
-    /// bool: is there a trailing sem-colon?
+    /// bool: is there a trailing semi-colon?
     StmtMac(Mac, bool),
 }
 
@@ -592,6 +595,28 @@ pub enum CaptureClause {
     CaptureByRef,
 }
 
+/// A token that delimits a sequence of token trees
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub struct Delimiter {
+    pub span: Span,
+    pub token: ::parse::token::Token,
+}
+
+impl Delimiter {
+    /// Convert the delimiter to a `TtToken`
+    pub fn to_tt(&self) -> TokenTree {
+        TtToken(self.span, self.token.clone())
+    }
+}
+
+/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star)
+/// for token sequences.
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub enum KleeneOp {
+    ZeroOrMore,
+    OneOrMore,
+}
+
 /// When the main rust parser encounters a syntax-extension invocation, it
 /// parses the arguments to the invocation as a token-tree. This is a very
 /// loose structure, such that all sorts of different AST-fragments can
@@ -600,9 +625,9 @@ pub enum CaptureClause {
 /// If the syntax extension is an MBE macro, it will attempt to match its
 /// LHS "matchers" against the provided token tree, and if it finds a
 /// match, will transcribe the RHS token tree, splicing in any captured
-/// macro_parser::matched_nonterminals into the TTNonterminals it finds.
+/// `macro_parser::matched_nonterminals` into the `TtNonterminal`s it finds.
 ///
-/// The RHS of an MBE macro is the only place a TTNonterminal or TTSeq
+/// The RHS of an MBE macro is the only place a `TtNonterminal` or `TtSequence`
 /// makes any real sense. You could write them elsewhere but nothing
 /// else knows what to do with them, so you'll probably get a syntax
 /// error.
@@ -610,22 +635,29 @@ pub enum CaptureClause {
 #[doc="For macro invocations; parsing is delegated to the macro"]
 pub enum TokenTree {
     /// A single token
-    TTTok(Span, ::parse::token::Token),
-    /// A delimited sequence (the delimiters appear as the first
-    /// and last elements of the vector)
-    // FIXME(eddyb) #6308 Use Rc<[TokenTree]> after DST.
-    TTDelim(Rc<Vec<TokenTree>>),
+    TtToken(Span, ::parse::token::Token),
+    /// A delimited sequence of token trees
+    TtDelimited(Span, Rc<(Delimiter, Vec<TokenTree>, Delimiter)>),
 
     // These only make sense for right-hand-sides of MBE macros:
 
-    /// A kleene-style repetition sequence with a span, a TTForest,
-    /// an optional separator, and a boolean where true indicates
-    /// zero or more (..), and false indicates one or more (+).
+    /// A Kleene-style repetition sequence with an optional separator.
     // FIXME(eddyb) #6308 Use Rc<[TokenTree]> after DST.
-    TTSeq(Span, Rc<Vec<TokenTree>>, Option<::parse::token::Token>, bool),
-
+    TtSequence(Span, Rc<Vec<TokenTree>>, Option<::parse::token::Token>, KleeneOp),
     /// A syntactic variable that will be filled in by macro expansion.
-    TTNonterminal(Span, Ident)
+    TtNonterminal(Span, Ident)
+}
+
+impl TokenTree {
+    /// Returns the `Span` corresponding to this token tree.
+    pub fn get_span(&self) -> Span {
+        match *self {
+            TtToken(span, _)           => span,
+            TtDelimited(span, _)       => span,
+            TtSequence(span, _, _, _)  => span,
+            TtNonterminal(span, _)     => span,
+        }
+    }
 }
 
 // Matchers are nodes defined-by and recognized-by the main rust parser and
@@ -684,9 +716,9 @@ pub enum TokenTree {
 pub enum Matcher_ {
     /// Match one token
     MatchTok(::parse::token::Token),
-    /// Match repetitions of a sequence: body, separator, zero ok?,
+    /// Match repetitions of a sequence: body, separator, Kleene operator,
     /// lo, hi position-in-match-array used:
-    MatchSeq(Vec<Matcher> , Option<::parse::token::Token>, bool, uint, uint),
+    MatchSeq(Vec<Matcher> , Option<::parse::token::Token>, KleeneOp, uint, uint),
     /// Parse a Rust NT: name to bind, name of NT, position in match array:
     MatchNonterminal(Ident, Ident, uint)
 }
index 8824a937038a8143e1b0c4733d7579b5f1609f63..72c62a173fc30b88bf18992e5f86448cc7bd397d 100644 (file)
@@ -250,30 +250,18 @@ fn impl_item_in_cfg(cx: &mut Context, impl_item: &ast::ImplItem) -> bool {
 // Determine if an item should be translated in the current crate
 // configuration based on the item's attributes
 fn in_cfg(diagnostic: &SpanHandler, cfg: &[P<ast::MetaItem>], attrs: &[ast::Attribute]) -> bool {
-    let mut in_cfg = false;
-    let mut seen_cfg = false;
-    for attr in attrs.iter() {
+    attrs.iter().all(|attr| {
         let mis = match attr.node.value.node {
             ast::MetaList(_, ref mis) if attr.check_name("cfg") => mis,
-            _ => continue
+            _ => return true
         };
 
         if mis.len() != 1 {
             diagnostic.span_err(attr.span, "expected 1 cfg-pattern");
-            return false;
+            return true;
         }
 
-        if seen_cfg {
-            diagnostic.span_err(attr.span, "The semantics of multiple `#[cfg(..)]` attributes on \
-                                            same item are changing from the union of the cfgs to \
-                                            the intersection of the cfgs. Change `#[cfg(a)] \
-                                            #[cfg(b)]` to `#[cfg(any(a, b))]`.");
-            return false;
-        }
-
-        seen_cfg = true;
-        in_cfg |= attr::cfg_matches(diagnostic, cfg, &*mis[0]);
-    }
-    in_cfg | !seen_cfg
+        attr::cfg_matches(diagnostic, cfg, &*mis[0])
+    })
 }
 
index d3c39284f55822f5d701d39d1df7176a4cebf859..b8795ad5be80fa12211ca1a34b99deb01afbd995 100644 (file)
@@ -50,7 +50,7 @@ pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt,
                                    token_tree: &[TokenTree])
                                    -> Box<MacResult+'cx> {
     let code = match token_tree {
-        [ast::TTTok(_, token::IDENT(code, _))] => code,
+        [ast::TtToken(_, token::IDENT(code, _))] => code,
         _ => unreachable!()
     };
     with_registered_diagnostics(|diagnostics| {
@@ -82,12 +82,12 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt,
                                        token_tree: &[TokenTree])
                                        -> Box<MacResult+'cx> {
     let (code, description) = match token_tree {
-        [ast::TTTok(_, token::IDENT(ref code, _))] => {
+        [ast::TtToken(_, token::IDENT(ref code, _))] => {
             (code, None)
         },
-        [ast::TTTok(_, token::IDENT(ref code, _)),
-         ast::TTTok(_, token::COMMA),
-         ast::TTTok(_, token::LIT_STR_RAW(description, _))] => {
+        [ast::TtToken(_, token::IDENT(ref code, _)),
+         ast::TtToken(_, token::COMMA),
+         ast::TtToken(_, token::LIT_STR_RAW(description, _))] => {
             (code, Some(description))
         }
         _ => unreachable!()
@@ -110,7 +110,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt,
                                           token_tree: &[TokenTree])
                                           -> Box<MacResult+'cx> {
     let name = match token_tree {
-        [ast::TTTok(_, token::IDENT(ref name, _))] => name,
+        [ast::TtToken(_, token::IDENT(ref name, _))] => name,
         _ => unreachable!()
     };
 
index 5cc2fe03618c46b25df24d5b333d26340f2771fe..64c8068607aa011259e14c0528419e248ef1a25f 100644 (file)
@@ -684,8 +684,8 @@ pub fn get_single_str_from_tts(cx: &ExtCtxt,
         cx.span_err(sp, format!("{} takes 1 argument.", name).as_slice());
     } else {
         match tts[0] {
-            ast::TTTok(_, token::LIT_STR(ident)) => return Some(parse::str_lit(ident.as_str())),
-            ast::TTTok(_, token::LIT_STR_RAW(ident, _)) => {
+            ast::TtToken(_, token::LIT_STR(ident)) => return Some(parse::str_lit(ident.as_str())),
+            ast::TtToken(_, token::LIT_STR_RAW(ident, _)) => {
                 return Some(parse::raw_str_lit(ident.as_str()))
             }
             _ => {
index 145412caa0bfe44bbac17fa10e7ac0a512181cd4..e12f9ee133a328171a687b423d7b40b6ba3a576e 100644 (file)
@@ -23,7 +23,7 @@ pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]
     for (i, e) in tts.iter().enumerate() {
         if i & 1 == 1 {
             match *e {
-                ast::TTTok(_, token::COMMA) => (),
+                ast::TtToken(_, token::COMMA) => (),
                 _ => {
                     cx.span_err(sp, "concat_idents! expecting comma.");
                     return DummyResult::expr(sp);
@@ -31,7 +31,7 @@ pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]
             }
         } else {
             match *e {
-                ast::TTTok(_, token::IDENT(ident,_)) => {
+                ast::TtToken(_, token::IDENT(ident,_)) => {
                     res_str.push_str(token::get_ident(ident).get())
                 }
                 _ => {
index 8df5746e412d49aab017be628cb2b8c5768f0c89..30301e3b8cc92414a940ebc6fb374d958a267479 100644 (file)
 use ext::base;
 use print;
 
-use std::rc::Rc;
-
 pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt,
                               sp: codemap::Span,
-                              tt: &[ast::TokenTree])
+                              tts: &[ast::TokenTree])
                               -> Box<base::MacResult+'cx> {
 
     cx.print_backtrace();
-    println!("{}", print::pprust::tt_to_string(&ast::TTDelim(
-                Rc::new(tt.iter().map(|x| (*x).clone()).collect()))));
+
+    println!("{}", print::pprust::tts_to_string(tts));
 
     // any so that `log_syntax` can be invoked as an expression and item.
     base::DummyResult::any(sp)
index 84775c12d641f7570ea422534afa7d76930a6f68..6f1fd90adfa4b6591a58d80f596d184fa1c51f5b 100644 (file)
@@ -23,7 +23,7 @@
 *
 * This is registered as a set of expression syntax extension called quote!
 * that lifts its argument token-tree to an AST representing the
-* construction of the same token tree, with ast::TTNonterminal nodes
+* construction of the same token tree, with ast::TtNonterminal nodes
 * interpreted as antiquotes (splices).
 *
 */
@@ -637,12 +637,12 @@ fn mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
 }
 
 
-fn mk_tt(cx: &ExtCtxt, sp: Span, tt: &ast::TokenTree) -> Vec<P<ast::Stmt>> {
+fn mk_tt(cx: &ExtCtxt, _: Span, tt: &ast::TokenTree) -> Vec<P<ast::Stmt>> {
     match *tt {
-        ast::TTTok(sp, ref tok) => {
+        ast::TtToken(sp, ref tok) => {
             let e_sp = cx.expr_ident(sp, id_ext("_sp"));
             let e_tok = cx.expr_call(sp,
-                                     mk_ast_path(cx, sp, "TTTok"),
+                                     mk_ast_path(cx, sp, "TtToken"),
                                      vec!(e_sp, mk_token(cx, sp, tok)));
             let e_push =
                 cx.expr_method_call(sp,
@@ -650,13 +650,16 @@ fn mk_tt(cx: &ExtCtxt, sp: Span, tt: &ast::TokenTree) -> Vec<P<ast::Stmt>> {
                                     id_ext("push"),
                                     vec!(e_tok));
             vec!(cx.stmt_expr(e_push))
-        }
-
-        ast::TTDelim(ref tts) => mk_tts(cx, sp, tts.as_slice()),
-        ast::TTSeq(..) => fail!("TTSeq in quote!"),
-
-        ast::TTNonterminal(sp, ident) => {
-
+        },
+        ast::TtDelimited(sp, ref delimed) => {
+            let (ref open, ref tts, ref close) = **delimed;
+            mk_tt(cx, sp, &open.to_tt()).into_iter()
+                .chain(tts.iter().flat_map(|tt| mk_tt(cx, sp, tt).into_iter()))
+                .chain(mk_tt(cx, sp, &close.to_tt()).into_iter())
+                .collect()
+        },
+        ast::TtSequence(..) => fail!("TtSequence in quote!"),
+        ast::TtNonterminal(sp, ident) => {
             // tt.extend($ident.to_tokens(ext_cx).into_iter())
 
             let e_to_toks =
@@ -674,7 +677,7 @@ fn mk_tt(cx: &ExtCtxt, sp: Span, tt: &ast::TokenTree) -> Vec<P<ast::Stmt>> {
                                     vec!(e_to_toks));
 
             vec!(cx.stmt_expr(e_push))
-        }
+        },
     }
 }
 
@@ -690,7 +693,7 @@ fn mk_tts(cx: &ExtCtxt, sp: Span, tts: &[ast::TokenTree])
 fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[ast::TokenTree])
               -> (P<ast::Expr>, P<ast::Expr>) {
     // NB: It appears that the main parser loses its mind if we consider
-    // $foo as a TTNonterminal during the main parse, so we have to re-parse
+    // $foo as a TtNonterminal during the main parse, so we have to re-parse
     // under quote_depth > 0. This is silly and should go away; the _guess_ is
     // it has to do with transition away from supporting old-style macros, so
     // try removing it when enough of them are gone.
index 1f50eb933bb4e80a1c7b731b9a9b0db2aba178a0..abf798ddacb3a12c36895d32f77b9c21033e347a 100644 (file)
@@ -20,10 +20,10 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt,
                            tt: &[ast::TokenTree])
                            -> Box<base::MacResult+'static> {
     match tt {
-        [ast::TTTok(_, ref tok)] if is_keyword(keywords::True, tok) => {
+        [ast::TtToken(_, ref tok)] if is_keyword(keywords::True, tok) => {
             cx.set_trace_macros(true);
         }
-        [ast::TTTok(_, ref tok)] if is_keyword(keywords::False, tok) => {
+        [ast::TtToken(_, ref tok)] if is_keyword(keywords::False, tok) => {
             cx.set_trace_macros(false);
         }
         _ => cx.span_err(sp, "trace_macros! accepts only `true` or `false`"),
index f2081674fb7c847097768cab5fad31925b42c1f3..cea8cab52654d3e3a0af7fe6f73b15224cef6b90 100644 (file)
@@ -323,9 +323,9 @@ pub fn parse(sess: &ParseSess,
             } else {
                 match ei.elts[idx].node.clone() {
                   /* need to descend into sequence */
-                  MatchSeq(ref matchers, ref sep, zero_ok,
+                  MatchSeq(ref matchers, ref sep, kleene_op,
                            match_idx_lo, match_idx_hi) => {
-                    if zero_ok {
+                    if kleene_op == ast::ZeroOrMore {
                         let mut new_ei = ei.clone();
                         new_ei.idx += 1u;
                         //we specifically matched zero repeats.
index 91db3a9d8df50a6b6200a16fb49b894fbb812a6b..3b51fb380b816853611a75d0e4cb6762355a5827 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{Ident, Matcher_, Matcher, MatchTok, MatchNonterminal, MatchSeq, TTDelim};
+use ast::{Ident, Matcher_, Matcher, MatchTok, MatchNonterminal, MatchSeq, TtDelimited};
 use ast;
 use codemap::{Span, Spanned, DUMMY_SP};
 use ext::base::{ExtCtxt, MacResult, MacroDef};
@@ -147,13 +147,9 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                           rhses: &[Rc<NamedMatch>])
                           -> Box<MacResult+'cx> {
     if cx.trace_macros() {
-        println!("{}! {} {} {}",
+        println!("{}! {{ {} }}",
                  token::get_ident(name),
-                 "{",
-                 print::pprust::tt_to_string(&TTDelim(Rc::new(arg.iter()
-                                                              .map(|x| (*x).clone())
-                                                              .collect()))),
-                 "}");
+                 print::pprust::tts_to_string(arg));
     }
 
     // Which arm's failure should we report? (the one furthest along)
@@ -175,15 +171,12 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                     // okay, what's your transcriber?
                     MatchedNonterminal(NtTT(ref tt)) => {
                         match **tt {
-                            // cut off delimiters; don't parse 'em
-                            TTDelim(ref tts) => {
-                                (*tts).slice(1u,(*tts).len()-1u)
-                                      .iter()
-                                      .map(|x| (*x).clone())
-                                      .collect()
-                            }
-                            _ => cx.span_fatal(
-                                sp, "macro rhs must be delimited")
+                            // ignore delimiters
+                            TtDelimited(_, ref delimed) => {
+                                let (_, ref tts, _) = **delimed;
+                                tts.clone()
+                            },
+                            _ => cx.span_fatal(sp, "macro rhs must be delimited"),
                         }
                     },
                     _ => cx.span_bug(sp, "bad thing in rhs")
@@ -239,10 +232,11 @@ fn ms(m: Matcher_) -> Matcher {
         ms(MatchSeq(vec!(
             ms(MatchNonterminal(lhs_nm, special_idents::matchers, 0u)),
             ms(MatchTok(FAT_ARROW)),
-            ms(MatchNonterminal(rhs_nm, special_idents::tt, 1u))), Some(SEMI), false, 0u, 2u)),
+            ms(MatchNonterminal(rhs_nm, special_idents::tt, 1u))), Some(SEMI),
+                                ast::OneOrMore, 0u, 2u)),
         //to phase into semicolon-termination instead of
         //semicolon-separation
-        ms(MatchSeq(vec!(ms(MatchTok(SEMI))), None, true, 2u, 2u)));
+        ms(MatchSeq(vec!(ms(MatchTok(SEMI))), None, ast::ZeroOrMore, 2u, 2u)));
 
 
     // Parse the macro_rules! invocation (`none` is for no interpolations):
index 35ec37d842af1c6e56aeb703a249bdd96c505590..1bb519f66cd55fca25fc26930f80c3a2f727787c 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use ast;
-use ast::{TokenTree, TTDelim, TTTok, TTSeq, TTNonterminal, Ident};
+use ast::{TokenTree, TtDelimited, TtToken, TtSequence, TtNonterminal, Ident};
 use codemap::{Span, DUMMY_SP};
 use diagnostic::SpanHandler;
 use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
@@ -18,6 +18,7 @@
 use parse::lexer::TokenAndSpan;
 
 use std::rc::Rc;
+use std::ops::Add;
 use std::collections::HashMap;
 
 ///an unzipping of `TokenTree`s
@@ -44,7 +45,7 @@ pub struct TtReader<'a> {
 }
 
 /// This can do Macro-By-Example transcription. On the other hand, if
-/// `src` contains no `TTSeq`s and `TTNonterminal`s, `interp` can (and
+/// `src` contains no `TtSequence`s and `TtNonterminal`s, `interp` can (and
 /// should) be none.
 pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
                          interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
@@ -104,37 +105,45 @@ enum LockstepIterSize {
     LisContradiction(String),
 }
 
-fn lis_merge(lhs: LockstepIterSize, rhs: LockstepIterSize) -> LockstepIterSize {
-    match lhs {
-        LisUnconstrained => rhs.clone(),
-        LisContradiction(_) => lhs.clone(),
-        LisConstraint(l_len, l_id) => match rhs {
-            LisUnconstrained => lhs.clone(),
-            LisContradiction(_) => rhs.clone(),
-            LisConstraint(r_len, _) if l_len == r_len => lhs.clone(),
-            LisConstraint(r_len, r_id) => {
-                let l_n = token::get_ident(l_id);
-                let r_n = token::get_ident(r_id);
-                LisContradiction(format!("inconsistent lockstep iteration: \
-                                          '{}' has {} items, but '{}' has {}",
-                                          l_n, l_len, r_n, r_len).to_string())
-            }
+impl Add<LockstepIterSize, LockstepIterSize> for LockstepIterSize {
+    fn add(&self, other: &LockstepIterSize) -> LockstepIterSize {
+        match *self {
+            LisUnconstrained => other.clone(),
+            LisContradiction(_) => self.clone(),
+            LisConstraint(l_len, l_id) => match *other {
+                LisUnconstrained => self.clone(),
+                LisContradiction(_) => other.clone(),
+                LisConstraint(r_len, _) if l_len == r_len => self.clone(),
+                LisConstraint(r_len, r_id) => {
+                    let l_n = token::get_ident(l_id);
+                    let r_n = token::get_ident(r_id);
+                    LisContradiction(format!("inconsistent lockstep iteration: \
+                                              '{}' has {} items, but '{}' has {}",
+                                              l_n, l_len, r_n, r_len).to_string())
+                }
+            },
         }
     }
 }
 
 fn lockstep_iter_size(t: &TokenTree, r: &TtReader) -> LockstepIterSize {
     match *t {
-        TTDelim(ref tts) | TTSeq(_, ref tts, _, _) => {
-            tts.iter().fold(LisUnconstrained, |lis, tt| {
-                lis_merge(lis, lockstep_iter_size(tt, r))
+        TtDelimited(_, ref delimed) => {
+            let (_, ref tts, _) = **delimed;
+            tts.iter().fold(LisUnconstrained, |size, tt| {
+                size + lockstep_iter_size(tt, r)
             })
-        }
-        TTTok(..) => LisUnconstrained,
-        TTNonterminal(_, name) => match *lookup_cur_matched(r, name) {
+        },
+        TtSequence(_, ref tts, _, _) => {
+            tts.iter().fold(LisUnconstrained, |size, tt| {
+                size + lockstep_iter_size(tt, r)
+            })
+        },
+        TtToken(..) => LisUnconstrained,
+        TtNonterminal(_, name) => match *lookup_cur_matched(r, name) {
             MatchedNonterminal(_) => LisUnconstrained,
             MatchedSeq(ref ads, _) => LisConstraint(ads.len(), name)
-        }
+        },
     }
 }
 
@@ -189,32 +198,38 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
             }
         }
     }
-    loop { /* because it's easiest, this handles `TTDelim` not starting
-              with a `TTTok`, even though it won't happen */
+    loop { /* because it's easiest, this handles `TtDelimited` not starting
+              with a `TtToken`, even though it won't happen */
         let t = {
             let frame = r.stack.last().unwrap();
             // FIXME(pcwalton): Bad copy.
             (*frame.forest)[frame.idx].clone()
         };
         match t {
-            TTDelim(tts) => {
+            TtDelimited(_, ref delimed) => {
+                let (ref open, ref tts, ref close) = **delimed;
+                let mut forest = Vec::with_capacity(1 + tts.len() + 1);
+                forest.push(open.to_tt());
+                forest.extend(tts.iter().map(|x| (*x).clone()));
+                forest.push(close.to_tt());
+
                 r.stack.push(TtFrame {
-                    forest: tts,
+                    forest: Rc::new(forest),
                     idx: 0,
                     dotdotdoted: false,
                     sep: None
                 });
                 // if this could be 0-length, we'd need to potentially recur here
             }
-            TTTok(sp, tok) => {
+            TtToken(sp, tok) => {
                 r.cur_span = sp;
                 r.cur_tok = tok;
                 r.stack.last_mut().unwrap().idx += 1;
                 return ret_val;
             }
-            TTSeq(sp, tts, sep, zerok) => {
+            TtSequence(sp, tts, sep, kleene_op) => {
                 // FIXME(pcwalton): Bad copy.
-                match lockstep_iter_size(&TTSeq(sp, tts.clone(), sep.clone(), zerok), r) {
+                match lockstep_iter_size(&TtSequence(sp, tts.clone(), sep.clone(), kleene_op), r) {
                     LisUnconstrained => {
                         r.sp_diag.span_fatal(
                             sp.clone(), /* blame macro writer */
@@ -228,7 +243,7 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
                         }
                     LisConstraint(len, _) => {
                         if len == 0 {
-                            if !zerok {
+                            if kleene_op == ast::OneOrMore {
                                 // FIXME #2887 blame invoker
                                 r.sp_diag.span_fatal(sp.clone(),
                                                      "this must repeat at least once");
@@ -249,7 +264,7 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
                 }
             }
             // FIXME #2887: think about span stuff here
-            TTNonterminal(sp, ident) => {
+            TtNonterminal(sp, ident) => {
                 r.stack.last_mut().unwrap().idx += 1;
                 match *lookup_cur_matched(r, ident) {
                     /* sidestep the interpolation tricks for ident because
index ceef190f5d4535731614987efddfb2ed1a7b91d3..0f9ab5c6b261ece7ff24a099f92b4a8c4a4c8e9e 100644 (file)
@@ -569,16 +569,29 @@ pub fn noop_fold_arg<T: Folder>(Arg {id, pat, ty}: Arg, fld: &mut T) -> Arg {
 
 pub fn noop_fold_tt<T: Folder>(tt: &TokenTree, fld: &mut T) -> TokenTree {
     match *tt {
-        TTTok(span, ref tok) =>
-            TTTok(span, fld.fold_token(tok.clone())),
-        TTDelim(ref tts) => TTDelim(Rc::new(fld.fold_tts(tts.as_slice()))),
-        TTSeq(span, ref pattern, ref sep, is_optional) =>
-            TTSeq(span,
-                  Rc::new(fld.fold_tts(pattern.as_slice())),
-                  sep.clone().map(|tok| fld.fold_token(tok)),
-                  is_optional),
-        TTNonterminal(sp,ref ident) =>
-            TTNonterminal(sp,fld.fold_ident(*ident))
+        TtToken(span, ref tok) =>
+            TtToken(span, fld.fold_token(tok.clone())),
+        TtDelimited(span, ref delimed) => {
+            let (ref open, ref tts, ref close) = **delimed;
+            TtDelimited(span, Rc::new((
+                            Delimiter {
+                                span: open.span,
+                                token: fld.fold_token(open.token.clone())
+                            },
+                            fld.fold_tts(tts.as_slice()),
+                            Delimiter {
+                                span: close.span,
+                                token: fld.fold_token(close.token.clone())
+                            },
+                        )))
+        },
+        TtSequence(span, ref pattern, ref sep, is_optional) =>
+            TtSequence(span,
+                       Rc::new(fld.fold_tts(pattern.as_slice())),
+                       sep.clone().map(|tok| fld.fold_token(tok)),
+                       is_optional),
+        TtNonterminal(sp,ref ident) =>
+            TtNonterminal(sp,fld.fold_ident(*ident))
     }
 }
 
index e5c37e5041abf43a984c2716fdc56d8c5bcdfe25..4f09b34557c74e93ab2938474406992381a77e14 100644 (file)
@@ -74,7 +74,7 @@ pub fn from_vec(mut v: Vec<T>) -> OwnedSlice<T> {
     pub fn into_vec(self) -> Vec<T> {
         // null is ok, because len == 0 in that case, as required by Vec.
         unsafe {
-            let ret = Vec::from_raw_parts(self.len, self.len, self.data);
+            let ret = Vec::from_raw_parts(self.data, self.len, self.len);
             // the vector owns the allocation now
             mem::forget(self);
             ret
index 2d7d32cd9eaccdcdf189b1f82cc5d699575fa1af..2965094f23662f396aeb47ec7fcd3f6da47e740a 100644 (file)
@@ -788,65 +788,57 @@ fn sp(a: u32, b: u32) -> Span {
     }
 
     // check the token-tree-ization of macros
-    #[test] fn string_to_tts_macro () {
+    #[test]
+    fn string_to_tts_macro () {
         let tts = string_to_tts("macro_rules! zip (($a)=>($a))".to_string());
         let tts: &[ast::TokenTree] = tts.as_slice();
         match tts {
-            [ast::TTTok(_,_),
-             ast::TTTok(_,token::NOT),
-             ast::TTTok(_,_),
-             ast::TTDelim(ref delim_elts)] => {
-                let delim_elts: &[ast::TokenTree] = delim_elts.as_slice();
-                match delim_elts {
-                    [ast::TTTok(_,token::LPAREN),
-                     ast::TTDelim(ref first_set),
-                     ast::TTTok(_,token::FAT_ARROW),
-                     ast::TTDelim(ref second_set),
-                     ast::TTTok(_,token::RPAREN)] => {
-                        let first_set: &[ast::TokenTree] =
-                            first_set.as_slice();
-                        match first_set {
-                            [ast::TTTok(_,token::LPAREN),
-                             ast::TTTok(_,token::DOLLAR),
-                             ast::TTTok(_,_),
-                             ast::TTTok(_,token::RPAREN)] => {
-                                let second_set: &[ast::TokenTree] =
-                                    second_set.as_slice();
-                                match second_set {
-                                    [ast::TTTok(_,token::LPAREN),
-                                     ast::TTTok(_,token::DOLLAR),
-                                     ast::TTTok(_,_),
-                                     ast::TTTok(_,token::RPAREN)] => {
-                                        assert_eq!("correct","correct")
-                                    }
-                                    _ => assert_eq!("wrong 4","correct")
-                                }
-                            },
-                            _ => {
-                                error!("failing value 3: {}",first_set);
-                                assert_eq!("wrong 3","correct")
-                            }
+            [ast::TtToken(_, token::IDENT(name_macro_rules, false)),
+             ast::TtToken(_, token::NOT),
+             ast::TtToken(_, token::IDENT(name_zip, false)),
+             ast::TtDelimited(_, ref macro_delimed)]
+            if name_macro_rules.as_str() == "macro_rules"
+            && name_zip.as_str() == "zip" => {
+                let (ref macro_open, ref macro_tts, ref macro_close) = **macro_delimed;
+                match (macro_open, macro_tts.as_slice(), macro_close) {
+                    (&ast::Delimiter { token: token::LPAREN, .. },
+                     [ast::TtDelimited(_, ref first_delimed),
+                      ast::TtToken(_, token::FAT_ARROW),
+                      ast::TtDelimited(_, ref second_delimed)],
+                     &ast::Delimiter { token: token::RPAREN, .. }) => {
+                        let (ref first_open, ref first_tts, ref first_close) = **first_delimed;
+                        match (first_open, first_tts.as_slice(), first_close) {
+                            (&ast::Delimiter { token: token::LPAREN, .. },
+                             [ast::TtToken(_, token::DOLLAR),
+                              ast::TtToken(_, token::IDENT(name, false))],
+                             &ast::Delimiter { token: token::RPAREN, .. })
+                            if name.as_str() == "a" => {},
+                            _ => fail!("value 3: {}", **first_delimed),
+                        }
+                        let (ref second_open, ref second_tts, ref second_close) = **second_delimed;
+                        match (second_open, second_tts.as_slice(), second_close) {
+                            (&ast::Delimiter { token: token::LPAREN, .. },
+                             [ast::TtToken(_, token::DOLLAR),
+                              ast::TtToken(_, token::IDENT(name, false))],
+                             &ast::Delimiter { token: token::RPAREN, .. })
+                            if name.as_str() == "a" => {},
+                            _ => fail!("value 4: {}", **second_delimed),
                         }
                     },
-                    _ => {
-                        error!("failing value 2: {}",delim_elts);
-                        assert_eq!("wrong","correct");
-                    }
+                    _ => fail!("value 2: {}", **macro_delimed),
                 }
             },
-            _ => {
-                error!("failing value: {}",tts);
-                assert_eq!("wrong 1","correct");
-            }
+            _ => fail!("value: {}",tts),
         }
     }
 
-    #[test] fn string_to_tts_1 () {
+    #[test]
+    fn string_to_tts_1 () {
         let tts = string_to_tts("fn a (b : int) { b; }".to_string());
         assert_eq!(json::encode(&tts),
         "[\
     {\
-        \"variant\":\"TTTok\",\
+        \"variant\":\"TtToken\",\
         \"fields\":[\
             null,\
             {\
@@ -859,7 +851,7 @@ fn sp(a: u32, b: u32) -> Span {
         ]\
     },\
     {\
-        \"variant\":\"TTTok\",\
+        \"variant\":\"TtToken\",\
         \"fields\":[\
             null,\
             {\
@@ -872,96 +864,90 @@ fn sp(a: u32, b: u32) -> Span {
         ]\
     },\
     {\
-        \"variant\":\"TTDelim\",\
+        \"variant\":\"TtDelimited\",\
         \"fields\":[\
+            null,\
             [\
                 {\
-                    \"variant\":\"TTTok\",\
-                    \"fields\":[\
-                        null,\
-                        \"LPAREN\"\
-                    ]\
-                },\
-                {\
-                    \"variant\":\"TTTok\",\
-                    \"fields\":[\
-                        null,\
-                        {\
-                            \"variant\":\"IDENT\",\
-                            \"fields\":[\
-                                \"b\",\
-                                false\
-                            ]\
-                        }\
-                    ]\
+                    \"span\":null,\
+                    \"token\":\"LPAREN\"\
                 },\
+                [\
+                    {\
+                        \"variant\":\"TtToken\",\
+                        \"fields\":[\
+                            null,\
+                            {\
+                                \"variant\":\"IDENT\",\
+                                \"fields\":[\
+                                    \"b\",\
+                                    false\
+                                ]\
+                            }\
+                        ]\
+                    },\
+                    {\
+                        \"variant\":\"TtToken\",\
+                        \"fields\":[\
+                            null,\
+                            \"COLON\"\
+                        ]\
+                    },\
+                    {\
+                        \"variant\":\"TtToken\",\
+                        \"fields\":[\
+                            null,\
+                            {\
+                                \"variant\":\"IDENT\",\
+                                \"fields\":[\
+                                    \"int\",\
+                                    false\
+                                ]\
+                            }\
+                        ]\
+                    }\
+                ],\
                 {\
-                    \"variant\":\"TTTok\",\
-                    \"fields\":[\
-                        null,\
-                        \"COLON\"\
-                    ]\
-                },\
-                {\
-                    \"variant\":\"TTTok\",\
-                    \"fields\":[\
-                        null,\
-                        {\
-                            \"variant\":\"IDENT\",\
-                            \"fields\":[\
-                                \"int\",\
-                                false\
-                            ]\
-                        }\
-                    ]\
-                },\
-                {\
-                    \"variant\":\"TTTok\",\
-                    \"fields\":[\
-                        null,\
-                        \"RPAREN\"\
-                    ]\
+                    \"span\":null,\
+                    \"token\":\"RPAREN\"\
                 }\
             ]\
         ]\
     },\
     {\
-        \"variant\":\"TTDelim\",\
+        \"variant\":\"TtDelimited\",\
         \"fields\":[\
+            null,\
             [\
                 {\
-                    \"variant\":\"TTTok\",\
-                    \"fields\":[\
-                        null,\
-                        \"LBRACE\"\
-                    ]\
-                },\
-                {\
-                    \"variant\":\"TTTok\",\
-                    \"fields\":[\
-                        null,\
-                        {\
-                            \"variant\":\"IDENT\",\
-                            \"fields\":[\
-                                \"b\",\
-                                false\
-                            ]\
-                        }\
-                    ]\
-                },\
-                {\
-                    \"variant\":\"TTTok\",\
-                    \"fields\":[\
-                        null,\
-                        \"SEMI\"\
-                    ]\
+                    \"span\":null,\
+                    \"token\":\"LBRACE\"\
                 },\
+                [\
+                    {\
+                        \"variant\":\"TtToken\",\
+                        \"fields\":[\
+                            null,\
+                            {\
+                                \"variant\":\"IDENT\",\
+                                \"fields\":[\
+                                    \"b\",\
+                                    false\
+                                ]\
+                            }\
+                        ]\
+                    },\
+                    {\
+                        \"variant\":\"TtToken\",\
+                        \"fields\":[\
+                            null,\
+                            \"SEMI\"\
+                        ]\
+                    }\
+                ],\
                 {\
-                    \"variant\":\"TTTok\",\
-                    \"fields\":[\
-                        null,\
-                        \"RBRACE\"\
-                    ]\
+                    \"span\":null,\
+                    \"token\":\"RBRACE\"\
                 }\
             ]\
         ]\
index 5abf79836f5b2b4d5a45d8c4852f779ebcc18e49..7bf751c2d5ebf3b4a7a9c50767bdd4e4c20d618d 100644 (file)
@@ -48,8 +48,8 @@
 use ast::{StructVariantKind, BiSub};
 use ast::StrStyle;
 use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue};
-use ast::{TokenTree, TraitItem, TraitRef, TTDelim, TTSeq, TTTok};
-use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot};
+use ast::{Delimiter, TokenTree, TraitItem, TraitRef, TtDelimited, TtSequence, TtToken};
+use ast::{TtNonterminal, TupleVariantKind, Ty, Ty_, TyBot};
 use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
 use ast::{TyTypeof, TyInfer, TypeMethod};
 use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyQPath};
@@ -2497,27 +2497,30 @@ pub fn parse_dot_or_call_expr_with(&mut self, e0: P<Expr>) -> P<Expr> {
         return e;
     }
 
-    /// Parse an optional separator followed by a kleene-style
+    /// Parse an optional separator followed by a Kleene-style
     /// repetition token (+ or *).
-    pub fn parse_sep_and_zerok(&mut self) -> (Option<token::Token>, bool) {
-        fn parse_zerok(parser: &mut Parser) -> Option<bool> {
+    pub fn parse_sep_and_kleene_op(&mut self) -> (Option<token::Token>, ast::KleeneOp) {
+        fn parse_kleene_op(parser: &mut Parser) -> Option<ast::KleeneOp> {
             match parser.token {
-                token::BINOP(token::STAR) | token::BINOP(token::PLUS) => {
-                    let zerok = parser.token == token::BINOP(token::STAR);
+                token::BINOP(token::STAR) => {
                     parser.bump();
-                    Some(zerok)
+                    Some(ast::ZeroOrMore)
+                },
+                token::BINOP(token::PLUS) => {
+                    parser.bump();
+                    Some(ast::OneOrMore)
                 },
                 _ => None
             }
         };
 
-        match parse_zerok(self) {
-            Some(zerok) => return (None, zerok),
+        match parse_kleene_op(self) {
+            Some(kleene_op) => return (None, kleene_op),
             None => {}
         }
 
         let separator = self.bump_and_get();
-        match parse_zerok(self) {
+        match parse_kleene_op(self) {
             Some(zerok) => (Some(separator), zerok),
             None => self.fatal("expected `*` or `+`")
         }
@@ -2526,8 +2529,8 @@ fn parse_zerok(parser: &mut Parser) -> Option<bool> {
     /// parse a single token tree from the input.
     pub fn parse_token_tree(&mut self) -> TokenTree {
         // FIXME #6994: currently, this is too eager. It
-        // parses token trees but also identifies TTSeq's
-        // and TTNonterminal's; it's too early to know yet
+        // parses token trees but also identifies TtSequence's
+        // and TtNonterminal's; it's too early to know yet
         // whether something will be a nonterminal or a seq
         // yet.
         maybe_whole!(deref self, NtTT);
@@ -2564,26 +2567,21 @@ fn parse_non_delim_tt_tok(p: &mut Parser) -> TokenTree {
                         seq_sep_none(),
                         |p| p.parse_token_tree()
                     );
-                    let (s, z) = p.parse_sep_and_zerok();
+                    let (sep, repeat) = p.parse_sep_and_kleene_op();
                     let seq = match seq {
                         Spanned { node, .. } => node,
                     };
-                    TTSeq(mk_sp(sp.lo, p.span.hi), Rc::new(seq), s, z)
+                    TtSequence(mk_sp(sp.lo, p.span.hi), Rc::new(seq), sep, repeat)
                 } else {
-                    TTNonterminal(sp, p.parse_ident())
+                    TtNonterminal(sp, p.parse_ident())
                 }
               }
               _ => {
-                  parse_any_tt_tok(p)
+                  TtToken(p.span, p.bump_and_get())
               }
             }
         }
 
-        // turn the next token into a TTTok:
-        fn parse_any_tt_tok(p: &mut Parser) -> TokenTree {
-            TTTok(p.span, p.bump_and_get())
-        }
-
         match (&self.token, token::close_delimiter_for(&self.token)) {
             (&token::EOF, _) => {
                 let open_braces = self.open_braces.clone();
@@ -2595,21 +2593,32 @@ fn parse_any_tt_tok(p: &mut Parser) -> TokenTree {
                 self.fatal("this file contains an un-closed delimiter ");
             }
             (_, Some(close_delim)) => {
+                // The span for beginning of the delimited section
+                let pre_span = self.span;
+
                 // Parse the open delimiter.
                 self.open_braces.push(self.span);
-                let mut result = vec!(parse_any_tt_tok(self));
+                let open = Delimiter {
+                    span: self.span,
+                    token: self.bump_and_get(),
+                };
 
-                let trees =
-                    self.parse_seq_to_before_end(&close_delim,
-                                                 seq_sep_none(),
-                                                 |p| p.parse_token_tree());
-                result.extend(trees.into_iter());
+                // Parse the token trees within the delimeters
+                let tts = self.parse_seq_to_before_end(
+                    &close_delim, seq_sep_none(), |p| p.parse_token_tree()
+                );
 
                 // Parse the close delimiter.
-                result.push(parse_any_tt_tok(self));
+                let close = Delimiter {
+                    span: self.span,
+                    token: self.bump_and_get(),
+                };
                 self.open_braces.pop().unwrap();
 
-                TTDelim(Rc::new(result))
+                // Expand to cover the entire delimited token tree
+                let span = Span { hi: self.span.hi, ..pre_span };
+
+                TtDelimited(span, Rc::new((open, tts, close)))
             }
             _ => parse_non_delim_tt_tok(self)
         }
@@ -2673,8 +2682,8 @@ pub fn parse_matcher(&mut self, name_idx: &mut uint) -> Matcher {
                 if ms.len() == 0u {
                     self.fatal("repetition body must be nonempty");
                 }
-                let (sep, zerok) = self.parse_sep_and_zerok();
-                MatchSeq(ms, sep, zerok, name_idx_lo, *name_idx)
+                let (sep, kleene_op) = self.parse_sep_and_kleene_op();
+                MatchSeq(ms, sep, kleene_op, name_idx_lo, *name_idx)
             } else {
                 let bound_to = self.parse_ident();
                 self.expect(&token::COLON);
index b63f9b0120b9ee2e65614a9a36a9a0decfd9df1c..de60e6cd2764ba60080b143f2ae1336fe38728f3 100644 (file)
@@ -224,6 +224,10 @@ pub fn item_to_string(i: &ast::Item) -> String {
     $to_string(|s| s.print_item(i))
 }
 
+pub fn view_item_to_string(i: &ast::ViewItem) -> String {
+    $to_string(|s| s.print_view_item(i))
+}
+
 pub fn generics_to_string(generics: &ast::Generics) -> String {
     $to_string(|s| s.print_generics(generics))
 }
@@ -1020,8 +1024,15 @@ pub fn print_struct(&mut self,
     /// expression arguments as expressions). It can be done! I think.
     pub fn print_tt(&mut self, tt: &ast::TokenTree) -> IoResult<()> {
         match *tt {
-            ast::TTDelim(ref tts) => self.print_tts(tts.as_slice()),
-            ast::TTTok(_, ref tk) => {
+            ast::TtDelimited(_, ref delimed) => {
+                let (ref open, ref tts, ref close) = **delimed;
+                try!(word(&mut self.s, parse::token::to_string(&open.token).as_slice()));
+                try!(space(&mut self.s));
+                try!(self.print_tts(tts.as_slice()));
+                try!(space(&mut self.s));
+                word(&mut self.s, parse::token::to_string(&close.token).as_slice())
+            },
+            ast::TtToken(_, ref tk) => {
                 try!(word(&mut self.s, parse::token::to_string(tk).as_slice()));
                 match *tk {
                     parse::token::DOC_COMMENT(..) => {
@@ -1030,22 +1041,25 @@ pub fn print_tt(&mut self, tt: &ast::TokenTree) -> IoResult<()> {
                     _ => Ok(())
                 }
             }
-            ast::TTSeq(_, ref tts, ref sep, zerok) => {
+            ast::TtSequence(_, ref tts, ref separator, kleene_op) => {
                 try!(word(&mut self.s, "$("));
                 for tt_elt in (*tts).iter() {
                     try!(self.print_tt(tt_elt));
                 }
                 try!(word(&mut self.s, ")"));
-                match *sep {
+                match *separator {
                     Some(ref tk) => {
                         try!(word(&mut self.s,
                                   parse::token::to_string(tk).as_slice()));
                     }
                     None => ()
                 }
-                word(&mut self.s, if zerok { "*" } else { "+" })
+                match kleene_op {
+                    ast::ZeroOrMore => word(&mut self.s, "*"),
+                    ast::OneOrMore => word(&mut self.s, "+"),
+                }
             }
-            ast::TTNonterminal(_, name) => {
+            ast::TtNonterminal(_, name) => {
                 try!(word(&mut self.s, "$"));
                 self.print_ident(name)
             }
index 0aae85503d07ddaf5647950e410a1762c029f871..d4f06403c1a6e6bd02c9ffec821197f94ddc4fe1 100644 (file)
@@ -71,7 +71,8 @@ fn color_to_bits(color: color::Color) -> u16 {
 }
 
 fn bits_to_color(bits: u16) -> color::Color {
-    let color = match bits & 0x7 {
+    let bits = bits & 0x7;
+    let color = match bits {
         0 => color::BLACK,
         0x1 => color::BLUE,
         0x2 => color::GREEN,
index 43842fae70f802412bb5ed2261060ef7e8715ab5..40ed3a35ddf134bb6b6f9b174bb704d800738314 100644 (file)
@@ -18,7 +18,7 @@
 
 use syntax::codemap::Span;
 use syntax::parse::token::{IDENT, get_ident};
-use syntax::ast::{TokenTree, TTTok};
+use syntax::ast::{TokenTree, TtToken};
 use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacExpr};
 use syntax::ext::build::AstBuilder;  // trait for expr_uint
 use rustc::plugin::Registry;
@@ -39,7 +39,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
         ("I",    1)];
 
     let text = match args {
-        [TTTok(_, IDENT(s, _))] => get_ident(s).to_string(),
+        [TtToken(_, IDENT(s, _))] => get_ident(s).to_string(),
         _ => {
             cx.span_err(sp, "argument should be a single identifier");
             return DummyResult::any(sp);
index 352d351973bc68c326a7acc56c4d903e8c3111cd..dc54374f0fa74d23575dd10a7327b075deaf112b 100644 (file)
 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 // OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// ignore-pretty very bad with line comments
 // ignore-android doesn't terminate?
 
-#![feature(slicing_syntax)]
+#![feature(slicing_syntax, asm, if_let, tuple_indexing)]
 
-use std::iter::range_step;
-use std::io::{stdin, stdout, File};
+extern crate libc;
 
-static LINE_LEN: uint = 60;
+use std::io::stdio::{stdin_raw, stdout_raw};
+use std::sync::{Future};
+use std::num::{div_rem};
+use std::ptr::{copy_memory};
+use std::io::{IoResult, EndOfFile};
+use std::slice::raw::{mut_buf_as_slice};
 
-fn make_complements() -> [u8, ..256] {
-    let transforms = [
-        ('A', 'T'), ('C', 'G'), ('G', 'C'), ('T', 'A'),
-        ('U', 'A'), ('M', 'K'), ('R', 'Y'), ('W', 'W'),
-        ('S', 'S'), ('Y', 'R'), ('K', 'M'), ('V', 'B'),
-        ('H', 'D'), ('D', 'H'), ('B', 'V'), ('N', 'N'),
-        ('\n', '\n')];
-    let mut complements: [u8, ..256] = [0, ..256];
-    for (i, c) in complements.iter_mut().enumerate() {
-        *c = i as u8;
+use shared_memory::{SharedMemory};
+
+mod tables {
+    use std::sync::{Once, ONCE_INIT};
+
+    /// Lookup tables.
+    static mut CPL16: [u16, ..1 << 16] = [0, ..1 << 16];
+    static mut CPL8:  [u8,  ..1 << 8]  = [0, ..1 << 8];
+
+    /// Generates the tables.
+    pub fn get() -> Tables {
+        /// To make sure we initialize the tables only once.
+        static INIT: Once = ONCE_INIT;
+        INIT.doit(|| {
+            unsafe {
+                for i in range(0, 1 << 8) {
+                    CPL8[i] = match i as u8 {
+                        b'A' | b'a' => b'T',
+                        b'C' | b'c' => b'G',
+                        b'G' | b'g' => b'C',
+                        b'T' | b't' => b'A',
+                        b'U' | b'u' => b'A',
+                        b'M' | b'm' => b'K',
+                        b'R' | b'r' => b'Y',
+                        b'W' | b'w' => b'W',
+                        b'S' | b's' => b'S',
+                        b'Y' | b'y' => b'R',
+                        b'K' | b'k' => b'M',
+                        b'V' | b'v' => b'B',
+                        b'H' | b'h' => b'D',
+                        b'D' | b'd' => b'H',
+                        b'B' | b'b' => b'V',
+                        b'N' | b'n' => b'N',
+                        i => i,
+                    };
+                }
+
+                for (i, v) in CPL16.iter_mut().enumerate() {
+                    *v = *CPL8.unsafe_get(i & 255) as u16 << 8 |
+                         *CPL8.unsafe_get(i >> 8)  as u16;
+                }
+            }
+        });
+        Tables { _dummy: () }
     }
-    let lower = 'A' as u8 - 'a' as u8;
-    for &(from, to) in transforms.iter() {
-        complements[from as uint] = to as u8;
-        complements[(from as u8 - lower) as uint] = to as u8;
+
+    /// Accessor for the static arrays.
+    ///
+    /// To make sure that the tables can't be accessed without having been initialized.
+    pub struct Tables {
+        _dummy: ()
+    }
+
+    impl Tables {
+        /// Retreives the complement for `i`.
+        pub fn cpl8(self, i: u8) -> u8 {
+            // Not really unsafe.
+            unsafe { CPL8[i as uint] }
+        }
+
+        /// Retreives the complement for `i`.
+        pub fn cpl16(self, i: u16) -> u16 {
+            unsafe { CPL16[i as uint] }
+        }
     }
-    complements
 }
 
-fn main() {
-    let complements = make_complements();
-    let data = if std::os::getenv("RUST_BENCH").is_some() {
-        File::open(&Path::new("shootout-k-nucleotide.data")).read_to_end()
-    } else {
-        stdin().read_to_end()
-    };
-    let mut data = data.unwrap();
+mod shared_memory {
+    use std::sync::{Arc};
+    use std::mem::{transmute};
+    use std::raw::{Slice};
 
-    for seq in data.as_mut_slice().split_mut(|c| *c == '>' as u8) {
-        // skip header and last \n
-        let begin = match seq.iter().position(|c| *c == '\n' as u8) {
-            None => continue,
-            Some(c) => c
-        };
-        let len = seq.len();
-        let seq = seq[mut begin+1..len-1];
-
-        // arrange line breaks
-        let len = seq.len();
-        let off = LINE_LEN - len % (LINE_LEN + 1);
-        for i in range_step(LINE_LEN, len, LINE_LEN + 1) {
-            for j in std::iter::count(i, -1).take(off) {
-                seq[j] = seq[j - 1];
+    /// Structure for sharing disjoint parts of a vector mutably across tasks.
+    pub struct SharedMemory {
+        ptr: Arc<Vec<u8>>,
+        start: uint,
+        len: uint,
+    }
+
+    impl SharedMemory {
+        pub fn new(ptr: Vec<u8>) -> SharedMemory {
+            let len = ptr.len();
+            SharedMemory {
+                ptr: Arc::new(ptr),
+                start: 0,
+                len: len,
             }
-            seq[i - off] = '\n' as u8;
         }
 
-        // reverse complement, as
-        //    seq.reverse(); for c in seq.iter_mut() { *c = complements[*c] }
-        // but faster:
-        for (front, back) in two_side_iter(seq) {
-            let tmp = complements[*front as uint];
-            *front = complements[*back as uint];
-            *back = tmp;
+        pub fn as_mut_slice(&mut self) -> &mut [u8] {
+            unsafe {
+                transmute(Slice {
+                    data: self.ptr.as_ptr().offset(self.start as int) as *const u8,
+                    len: self.len,
+                })
+            }
         }
-        if seq.len() % 2 == 1 {
-            let middle = &mut seq[seq.len() / 2];
-            *middle = complements[*middle as uint];
+
+        pub fn len(&self) -> uint {
+            self.len
         }
-    }
 
-    stdout().write(data.as_slice()).unwrap();
+        pub fn split_at(self, mid: uint) -> (SharedMemory, SharedMemory) {
+            assert!(mid <= self.len);
+            let left = SharedMemory {
+                ptr: self.ptr.clone(),
+                start: self.start,
+                len: mid,
+            };
+            let right = SharedMemory {
+                ptr: self.ptr,
+                start: self.start + mid,
+                len: self.len - mid,
+            };
+            (left, right)
+        }
+
+        /// Resets the object so that it covers the whole range of the contained vector.
+        ///
+        /// You must not call this method if `self` is not the only reference to the
+        /// shared memory.
+        ///
+        /// FIXME: If `Arc` had a method to check if the reference is unique, then we
+        /// wouldn't need the `unsafe` here.
+        ///
+        /// FIXME: If `Arc` had a method to unwrap the contained value, then we could
+        /// simply unwrap here.
+        pub unsafe fn reset(self) -> SharedMemory {
+            let len = self.ptr.len();
+            SharedMemory {
+                ptr: self.ptr,
+                start: 0,
+                len: len,
+            }
+        }
+    }
 }
 
-pub struct TwoSideIter<'a, T: 'a> {
-    first: *mut T,
-    last: *mut T,
-    marker: std::kinds::marker::ContravariantLifetime<'a>,
-    marker2: std::kinds::marker::NoCopy
+
+/// Reads all remaining bytes from the stream.
+fn read_to_end<R: Reader>(r: &mut R) -> IoResult<Vec<u8>> {
+    const CHUNK: uint = 64 * 1024;
+
+    let mut vec = Vec::with_capacity(1024 * 1024);
+    loop {
+        if vec.capacity() - vec.len() < CHUNK {
+            let cap = vec.capacity();
+            let mult = if cap < 256 * 1024 * 1024 {
+                // FIXME (mahkoh): Temporary workaround for jemalloc on linux. Replace
+                // this by 2x once the jemalloc preformance issue has been fixed.
+                16
+            } else {
+                2
+            };
+            vec.reserve_exact(mult * cap);
+        }
+        unsafe {
+            let ptr = vec.as_mut_ptr().offset(vec.len() as int);
+            match mut_buf_as_slice(ptr, CHUNK, |s| r.read(s)) {
+                Ok(n) => {
+                    let len = vec.len();
+                    vec.set_len(len + n);
+                },
+                Err(ref e) if e.kind == EndOfFile => break,
+                Err(e) => return Err(e),
+            }
+        }
+    }
+    Ok(vec)
 }
 
-pub fn two_side_iter<'a, T>(slice: &'a mut [T]) -> TwoSideIter<'a, T> {
-    let len = slice.len();
-    let first = slice.as_mut_ptr();
-    let last = if len == 0 {
-        first
-    } else {
-        unsafe { first.offset(len as int - 1) }
+/// Finds the first position at which `b` occurs in `s`.
+fn memchr(h: &[u8], n: u8) -> Option<uint> {
+    use libc::{c_void, c_int, size_t};
+    extern {
+        fn memchr(h: *const c_void, n: c_int, s: size_t) -> *mut c_void;
+    }
+    let res = unsafe {
+        memchr(h.as_ptr() as *const c_void, n as c_int, h.len() as size_t)
     };
-
-    TwoSideIter {
-        first: first,
-        last: last,
-        marker: std::kinds::marker::ContravariantLifetime,
-        marker2: std::kinds::marker::NoCopy
+    if res.is_null() {
+        None
+    } else {
+        Some(res as uint - h.as_ptr() as uint)
     }
 }
 
-impl<'a, T> Iterator<(&'a mut T, &'a mut T)> for TwoSideIter<'a, T> {
-    fn next(&mut self) -> Option<(&'a mut T, &'a mut T)> {
-        if self.first < self.last {
-            let result = unsafe { (&mut *self.first, &mut *self.last) };
-            self.first = unsafe { self.first.offset(1) };
-            self.last = unsafe { self.last.offset(-1) };
-            Some(result)
-        } else {
-            None
+/// Length of a normal line without the terminating \n.
+const LINE_LEN: uint = 60;
+
+/// Compute the reverse complement.
+fn reverse_complement(mut view: SharedMemory, tables: tables::Tables) {
+    // Drop the last newline
+    let seq = view.as_mut_slice().init_mut();
+    let len = seq.len();
+    let off = LINE_LEN - len % (LINE_LEN + 1);
+    let mut i = LINE_LEN;
+    while i < len {
+        unsafe {
+            copy_memory(seq.as_mut_ptr().offset((i - off + 1) as int),
+                        seq.as_ptr().offset((i - off) as int), off);
+            *seq.unsafe_mut(i - off) = b'\n';
+        }
+        i += LINE_LEN + 1;
+    }
+
+    let (div, rem) = div_rem(len, 4);
+    unsafe {
+        let mut left = seq.as_mut_ptr() as *mut u16;
+        // This is slow if len % 2 != 0 but still faster than bytewise operations.
+        let mut right = seq.as_mut_ptr().offset(len as int - 2) as *mut u16;
+        let end = left.offset(div as int);
+        while left != end {
+            let tmp = tables.cpl16(*left);
+            *left = tables.cpl16(*right);
+            *right = tmp;
+            left = left.offset(1);
+            right = right.offset(-1);
+        }
+
+        let end = end as *mut u8;
+        match rem {
+            1 => *end = tables.cpl8(*end),
+            2 => {
+                let tmp = tables.cpl8(*end);
+                *end = tables.cpl8(*end.offset(1));
+                *end.offset(1) = tmp;
+            },
+            3 => {
+                *end.offset(1) = tables.cpl8(*end.offset(1));
+                let tmp = tables.cpl8(*end);
+                *end = tables.cpl8(*end.offset(2));
+                *end.offset(2) = tmp;
+            },
+            _ => { },
         }
     }
 }
+
+fn main() {
+    let mut data = SharedMemory::new(read_to_end(&mut stdin_raw()).unwrap());
+    let tables = tables::get();
+
+    let mut futures = vec!();
+    loop {
+        let (_, mut tmp_data) = match memchr(data.as_mut_slice(), b'\n') {
+            Some(i) => data.split_at(i + 1),
+            _ => break,
+        };
+        let (view, tmp_data) = match memchr(tmp_data.as_mut_slice(), b'>') {
+            Some(i) => tmp_data.split_at(i),
+            None => {
+                let len = tmp_data.len();
+                tmp_data.split_at(len)
+            },
+        };
+        futures.push(Future::spawn(proc() reverse_complement(view, tables)));
+        data = tmp_data;
+    }
+
+    for f in futures.iter_mut() {
+        f.get();
+    }
+
+    // Not actually unsafe. If Arc had a way to check uniqueness then we could do that in
+    // `reset` and it would tell us that, yes, it is unique at this point.
+    data = unsafe { data.reset() };
+
+    stdout_raw().write(data.as_mut_slice()).unwrap();
+}
diff --git a/src/test/compile-fail/issue-12863.rs b/src/test/compile-fail/issue-12863.rs
new file mode 100644 (file)
index 0000000..0767667
--- /dev/null
@@ -0,0 +1,17 @@
+// 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.
+
+mod foo { pub fn bar() {} }
+
+fn main() {
+    match () {
+        foo::bar => {} //~ ERROR `bar` is not an enum variant, struct or const
+    }
+}
diff --git a/src/test/compile-fail/issue-14721.rs b/src/test/compile-fail/issue-14721.rs
new file mode 100644 (file)
index 0000000..92add18
--- /dev/null
@@ -0,0 +1,15 @@
+// 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() {
+    let foo = "str";
+    println!("{}", foo.desc); //~ ERROR attempted access of field `desc` on type `&str`,
+                              //        but no field with that name was found
+}
diff --git a/src/test/compile-fail/issue-16683.rs b/src/test/compile-fail/issue-16683.rs
new file mode 100644 (file)
index 0000000..d9dfaac
--- /dev/null
@@ -0,0 +1,18 @@
+// 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.
+
+trait T<'a> {
+    fn a(&'a self) -> &'a bool;
+    fn b(&self) {
+        self.a(); //~ ERROR mismatched types: expected `&'a Self`, found `&Self` (lifetime mismatch)
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-17551.rs b/src/test/compile-fail/issue-17551.rs
new file mode 100644 (file)
index 0000000..197319b
--- /dev/null
@@ -0,0 +1,18 @@
+// 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.
+
+#![feature(unboxed_closures)]
+
+struct B<T>;
+
+fn main() {
+    let foo = B; //~ ERROR unable to infer enough type information to locate the impl of the trait
+    let closure = |:| foo;
+}
diff --git a/src/test/compile-fail/issue-18118.rs b/src/test/compile-fail/issue-18118.rs
new file mode 100644 (file)
index 0000000..4497c80
--- /dev/null
@@ -0,0 +1,17 @@
+// 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.
+
+pub fn main() {
+    static z: &'static int = {
+        let p = 3;
+        &p
+//~^ ERROR cannot borrow a local variable inside a static block, define a separate static instead
+    };
+}
diff --git a/src/test/compile-fail/issue-18252.rs b/src/test/compile-fail/issue-18252.rs
new file mode 100644 (file)
index 0000000..c884f02
--- /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.
+
+#![feature(struct_variant)]
+
+enum Foo {
+    Variant { x: uint }
+}
+
+fn main() {
+    let f = Variant(42u); //~ ERROR expected function, found `Foo`
+}
diff --git a/src/test/compile-fail/issue-18294.rs b/src/test/compile-fail/issue-18294.rs
new file mode 100644 (file)
index 0000000..ca4cf52
--- /dev/null
@@ -0,0 +1,15 @@
+// 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() {
+    const X: u32 = 1;
+    const Y: uint = &X as *const u32 as uint; //~ ERROR E0018
+    println!("{}", Y);
+}
diff --git a/src/test/compile-fail/issue-18343.rs b/src/test/compile-fail/issue-18343.rs
new file mode 100644 (file)
index 0000000..1608d21
--- /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.
+
+struct Obj<'a> {
+    closure: ||: 'a -> u32
+}
+
+fn main() {
+    let o = Obj { closure: || 42 };
+    o.closure(); //~ ERROR type `Obj<'_>` does not implement any method in scope named `closure`
+    //~^ NOTE use `(s.closure)(...)` if you meant to call the function stored in the `closure` field
+}
diff --git a/src/test/compile-fail/issue-6991.rs b/src/test/compile-fail/issue-6991.rs
new file mode 100644 (file)
index 0000000..a5d23c7
--- /dev/null
@@ -0,0 +1,15 @@
+// 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.
+
+static x: &'static uint = &1;
+static y: uint = *x;
+//~^ ERROR cannot refer to other statics by value,
+//         use the address-of operator or a constant instead
+fn main() {}
diff --git a/src/test/compile-fail/issue-7867.rs b/src/test/compile-fail/issue-7867.rs
new file mode 100644 (file)
index 0000000..0ab5516
--- /dev/null
@@ -0,0 +1,27 @@
+// 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.
+
+enum A { B, C }
+
+mod foo { pub fn bar() {} }
+
+fn main() {
+    match (true, false) {
+        B => (), //~ ERROR expected `(bool,bool)`, found `A` (expected tuple, found enum A)
+        _ => ()
+    }
+
+    match &Some(42i) {
+        Some(x) => (), //~ ERROR expected `&core::option::Option<int>`,
+                       //        found `core::option::Option<<generic #4>>`
+        None => ()     //~ ERROR expected `&core::option::Option<int>`,
+                       //        found `core::option::Option<<generic #5>>`
+    }
+}
diff --git a/src/test/compile-fail/unboxed-closure-immutable-capture.rs b/src/test/compile-fail/unboxed-closure-immutable-capture.rs
new file mode 100644 (file)
index 0000000..e28abaf
--- /dev/null
@@ -0,0 +1,31 @@
+// 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.
+
+#![feature(unboxed_closures)]
+
+// Test that even unboxed closures that are capable of mutating their
+// environment cannot mutate captured variables that have not been
+// declared mutable (#18335)
+
+fn set(x: &mut uint) { *x = 0; }
+
+fn main() {
+    let x = 0u;
+    move |&mut:| x = 1; //~ ERROR cannot assign
+    move |&mut:| set(&mut x); //~ ERROR cannot borrow
+    move |:| x = 1; //~ ERROR cannot assign
+    move |:| set(&mut x); //~ ERROR cannot borrow
+    |&mut:| x = 1; //~ ERROR cannot assign
+    // FIXME: this should be `cannot borrow` (issue #18330)
+    |&mut:| set(&mut x); //~ ERROR cannot assign
+    |:| x = 1; //~ ERROR cannot assign
+    // FIXME: this should be `cannot borrow` (issue #18330)
+    |:| set(&mut x); //~ ERROR cannot assign
+}
index b5a94a02b346b319ad6c8e7d0c599ea78e4d089b..9d98a7ac12f9ba1809d7845d3630ea3a3fde7ac9 100644 (file)
@@ -9,6 +9,9 @@
 // except according to those terms.
 
 #![allow(dead_code)]
+#![feature(unboxed_closures, unboxed_closure_sugar)]
+
+// compile-flags:-g
 
 fn foo<T>() {}
 
@@ -82,6 +85,9 @@ fn bar<'b>() {
     // issue #13490
     let _ = || -> ! loop {};
     let _ = proc() -> ! loop {};
+
+    // issue #17021
+    let c = box |&:| {};
 }
 
 struct B<T>;
index 1c9d5cd3afe4d6c2a8b997090bd864ec694e9936..dbad546ce1ae3fd1a427b91afa99d06deecaed6f 100644 (file)
@@ -28,7 +28,7 @@ pub fn main() {
 
     let x: *mut S = &mut S;
 
-    // Test we can chnage the mutability from mut to const.
+    // Test we can change the mutability from mut to const.
     let x: &T = &mut S;
     let x: *const T = &mut S;
 }
diff --git a/src/test/run-pass/issue-12028.rs b/src/test/run-pass/issue-12028.rs
new file mode 100644 (file)
index 0000000..4d64103
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Hash<H> {
+    fn hash2(&self, hasher: &H) -> u64;
+}
+
+trait Stream {
+    fn input(&mut self, bytes: &[u8]);
+    fn result(&self) -> u64;
+}
+
+trait StreamHasher<S: Stream> {
+    fn stream(&self) -> S;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+trait StreamHash<S: Stream, H: StreamHasher<S>>: Hash<H> {
+    fn input_stream(&self, stream: &mut S);
+}
+
+impl<S: Stream, H: StreamHasher<S>> Hash<H> for u8 {
+    fn hash2(&self, hasher: &H) -> u64 {
+        let mut stream = hasher.stream();
+        self.input_stream(&mut stream);
+        stream.result()
+    }
+}
+
+impl<S: Stream, H: StreamHasher<S>> StreamHash<S, H> for u8 {
+    fn input_stream(&self, stream: &mut S) {
+        stream.input([*self]);
+    }
+}
+
+fn main() {}
diff --git a/src/test/run-pass/issue-14901.rs b/src/test/run-pass/issue-14901.rs
new file mode 100644 (file)
index 0000000..f93347f
--- /dev/null
@@ -0,0 +1,27 @@
+// 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::io::Reader;
+
+enum Wrapper<'a> {
+    WrapReader(&'a Reader + 'a)
+}
+
+trait Wrap<'a> {
+    fn wrap(self) -> Wrapper<'a>;
+}
+
+impl<'a, R: Reader> Wrap<'a> for &'a mut R {
+    fn wrap(self) -> Wrapper<'a> {
+        WrapReader(self as &'a mut Reader)
+    }
+}
+
+pub fn main() {}
diff --git a/src/test/run-pass/issue-16560.rs b/src/test/run-pass/issue-16560.rs
new file mode 100644 (file)
index 0000000..77eba02
--- /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.
+
+#![feature(unboxed_closures)]
+
+use std::mem;
+
+fn main() {
+    let y = 0u8;
+    let closure = move |&: x| y + x;
+
+    // Check that both closures are capturing by value
+    assert_eq!(1, mem::size_of_val(&closure));
+
+    spawn(proc() {
+        let ok = closure;
+    })
+}
diff --git a/src/test/run-pass/issue-16668.rs b/src/test/run-pass/issue-16668.rs
new file mode 100644 (file)
index 0000000..1bfa79b
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(unboxed_closures)]
+
+struct Parser<'a, I, O> {
+    parse: Box<FnMut<(I,), Result<O, String>> + 'a>
+}
+
+impl<'a, I, O: 'a> Parser<'a, I, O> {
+    fn compose<K: 'a>(mut self, mut rhs: Parser<O, K>) -> Parser<'a, I, K> {
+        Parser {
+            parse: box move |&mut: x: I| {
+                match self.parse.call_mut((x,)) {
+                    Ok(r) => rhs.parse.call_mut((r,)),
+                    Err(e) => Err(e)
+                }
+            }
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/run-pass/out-pointer-aliasing.rs b/src/test/run-pass/out-pointer-aliasing.rs
new file mode 100644 (file)
index 0000000..2a44df7
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub struct Foo {
+    f1: int,
+    _f2: int,
+}
+
+#[inline(never)]
+pub fn foo(f: &mut Foo) -> Foo {
+    let ret = *f;
+    f.f1 = 0;
+    ret
+}
+
+pub fn main() {
+    let mut f = Foo {
+        f1: 8,
+        _f2: 9,
+    };
+    f = foo(&mut f);
+    assert_eq!(f.f1, 8);
+}
index d8f48c7e6623bb4dfb5150b4504c19b36f3a9c43..966e34dfe49c6902ae161768403ebf9dfd167608 100644 (file)
@@ -30,7 +30,7 @@ unsafe fn test_triangle() -> bool {
     let ascend = ascend.as_mut_slice();
     static ALIGN : uint = 1;
 
-    // Checks that `ascend` forms triangle of acending size formed
+    // Checks that `ascend` forms triangle of ascending size formed
     // from pairs of rows (where each pair of rows is equally sized),
     // and the elements of the triangle match their row-pair index.
     unsafe fn sanity_check(ascend: &[*mut u8]) {
diff --git a/src/test/run-pass/trait-cache-issue-18209.rs b/src/test/run-pass/trait-cache-issue-18209.rs
new file mode 100644 (file)
index 0000000..a5efb32
--- /dev/null
@@ -0,0 +1,27 @@
+// 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.
+
+// Test that the cache results from the default method do not pollute
+// the cache for the later call in `load()`.
+//
+// See issue #18209.
+
+pub trait Foo {
+    fn load_from() -> Box<Self>;
+    fn load() -> Box<Self> {
+        Foo::load_from()
+    }
+}
+
+pub fn load<M: Foo>() -> Box<M> {
+    Foo::load()
+}
+
+fn main() { }
diff --git a/src/test/run-pass/unboxed-closures-move-mutable.rs b/src/test/run-pass/unboxed-closures-move-mutable.rs
new file mode 100644 (file)
index 0000000..f7e1e46
--- /dev/null
@@ -0,0 +1,28 @@
+// 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.
+
+#![feature(unboxed_closures)]
+#![deny(unused_mut)]
+
+// Test that mutating a mutable upvar in a capture-by-value unboxed
+// closure does not ice (issue #18238) and marks the upvar as used
+// mutably so we do not get a spurious warning about it not needing to
+// be declared mutable (issue #18336).
+
+fn main() {
+    {
+        let mut x = 0u;
+        move |&mut:| x += 1;
+    }
+    {
+        let mut x = 0u;
+        move |:| x += 1;
+    }
+}
index 2fe8f4bdf011ae70aab7a2890c8b2a997faa3b0f..11b58948e0535d1f928630cf16740ece3ce9efb2 100644 (file)
@@ -10,7 +10,7 @@
 
 fn sub_expr() {
     // Test for a &[T] => &&[T] coercion in sub-expression position
-    // (surpisingly, this can cause errors which are not caused by either of:
+    // (surprisingly, this can cause errors which are not caused by either of:
     //    `let x = vec.slice_mut(0, 2);`
     //    `foo(vec.slice_mut(0, 2));` ).
     let mut vec: Vec<int> = vec!(1, 2, 3, 4);