]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #21132 : sfackler/rust/wait_timeout, r=alexcrichton
authorbors <bors@rust-lang.org>
Sat, 17 Jan 2015 03:51:34 +0000 (03:51 +0000)
committerbors <bors@rust-lang.org>
Sat, 17 Jan 2015 03:51:34 +0000 (03:51 +0000)
**The implementation is a direct adaptation of libcxx's condition_variable implementation.**

I also added a wait_timeout_with method, which matches the second overload in C++'s condition_variable. The implementation right now is kind of dumb but it works. There is an outstanding issue with it: as is it doesn't support the use case where a user doesn't care about poisoning and wants to continue through poison.

r? @alexcrichton @aturon

301 files changed:
AUTHORS.txt
CONTRIBUTING.md
Makefile.in
README.md
configure
mk/cfg/aarch64-apple-ios.mk
mk/cfg/armv7-apple-ios.mk
mk/cfg/armv7s-apple-ios.mk
mk/cfg/i386-apple-ios.mk
mk/cfg/powerpc-unknown-linux-gnu.mk [new file with mode: 0644]
mk/cfg/x86_64-apple-ios.mk
mk/main.mk
mk/platform.mk
mk/prepare.mk
src/doc/complement-lang-faq.md
src/doc/complement-project-faq.md
src/doc/intro.md
src/doc/not_found.md
src/doc/reference.md
src/doc/rust.css
src/doc/rustdoc.md
src/doc/trpl/README.md
src/doc/trpl/SUMMARY.md
src/doc/trpl/arrays-vectors-and-slices.md
src/doc/trpl/closures.md
src/doc/trpl/compound-data-types.md
src/doc/trpl/error-handling.md
src/doc/trpl/ffi.md
src/doc/trpl/functions.md
src/doc/trpl/generics.md
src/doc/trpl/guessing-game.md
src/doc/trpl/hello-world.md
src/doc/trpl/macros.md
src/doc/trpl/ownership.md
src/doc/trpl/plugins.md
src/doc/trpl/pointers.md
src/doc/trpl/tasks.md [deleted file]
src/doc/trpl/testing.md
src/doc/trpl/threads.md [new file with mode: 0644]
src/doc/trpl/traits.md
src/doc/trpl/unsafe.md
src/doc/trpl/variable-bindings.md
src/doc/tutorial.md
src/grammar/RustLexer.g4
src/grammar/verify.rs
src/liballoc/heap.rs
src/liballoc/lib.rs
src/liballoc/rc.rs
src/libcollections/bit.rs
src/libcollections/btree/map.rs
src/libcollections/btree/set.rs
src/libcollections/dlist.rs
src/libcollections/slice.rs
src/libcollections/str.rs
src/libcollections/string.rs
src/libcollections/vec.rs
src/libcore/cell.rs
src/libcore/finally.rs
src/libcore/fmt/float.rs
src/libcore/fmt/mod.rs
src/libcore/intrinsics.rs
src/libcore/marker.rs
src/libcore/option.rs
src/libcore/ptr.rs
src/libcore/result.rs
src/libcore/slice.rs
src/libcore/str/mod.rs
src/libcore/tuple.rs
src/libcoretest/char.rs
src/libcoretest/iter.rs
src/libcoretest/mem.rs
src/libfmt_macros/lib.rs
src/liblibc/lib.rs
src/librand/lib.rs
src/librbml/io.rs
src/librustc/lint/builtin.rs
src/librustc/metadata/creader.rs
src/librustc/metadata/csearch.rs
src/librustc/metadata/cstore.rs
src/librustc/metadata/decoder.rs
src/librustc/metadata/filesearch.rs
src/librustc/metadata/loader.rs
src/librustc/middle/cfg/construct.rs
src/librustc/middle/cfg/graphviz.rs
src/librustc/middle/check_const.rs
src/librustc/middle/check_match.rs
src/librustc/middle/check_static.rs
src/librustc/middle/check_static_recursion.rs
src/librustc/middle/const_eval.rs
src/librustc/middle/effect.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/liveness.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/privacy.rs
src/librustc/middle/reachable.rs
src/librustc/middle/recursion_limit.rs
src/librustc/middle/region.rs
src/librustc/middle/subst.rs
src/librustc/middle/traits/error_reporting.rs
src/librustc/middle/traits/mod.rs
src/librustc/middle/traits/select.rs
src/librustc/middle/ty.rs
src/librustc/middle/ty_fold.rs
src/librustc/plugin/registry.rs
src/librustc/session/mod.rs
src/librustc/session/search_paths.rs
src/librustc/util/ppaux.rs
src/librustc_back/sha2.rs
src/librustc_back/svh.rs
src/librustc_back/target/mod.rs
src/librustc_back/target/powerpc_unknown_linux_gnu.rs [new file with mode: 0644]
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_driver/mod.rs [deleted file]
src/librustc_driver/pretty.rs
src/librustc_llvm/lib.rs
src/librustc_resolve/lib.rs
src/librustc_trans/back/link.rs
src/librustc_trans/back/lto.rs
src/librustc_trans/back/write.rs
src/librustc_trans/save/mod.rs
src/librustc_trans/save/recorder.rs
src/librustc_trans/trans/_match.rs
src/librustc_trans/trans/asm.rs
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/builder.rs
src/librustc_trans/trans/cabi.rs
src/librustc_trans/trans/cabi_powerpc.rs [new file with mode: 0644]
src/librustc_trans/trans/callee.rs
src/librustc_trans/trans/common.rs
src/librustc_trans/trans/consts.rs
src/librustc_trans/trans/controlflow.rs
src/librustc_trans/trans/debuginfo.rs
src/librustc_trans/trans/expr.rs
src/librustc_trans/trans/glue.rs
src/librustc_trans/trans/machine.rs
src/librustc_trans/trans/meth.rs
src/librustc_trans/trans/mod.rs
src/librustc_trans/trans/monomorphize.rs
src/librustc_trans/trans/tvec.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/compare_method.rs [new file with mode: 0644]
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/check/method/suggest.rs [new file with mode: 0644]
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/wf.rs
src/librustc_typeck/coherence/impls.rs [new file with mode: 0644]
src/librustc_typeck/coherence/mod.rs
src/librustc_typeck/coherence/overlap.rs
src/librustc_typeck/coherence/unsafety.rs
src/librustc_typeck/lib.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/html/format.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/static/playpen.js
src/librustdoc/markdown.rs
src/libserialize/json.rs
src/libstd/io/buffered.rs
src/libstd/io/comm_adapters.rs
src/libstd/io/fs.rs
src/libstd/io/mem.rs
src/libstd/io/mod.rs
src/libstd/io/net/ip.rs
src/libstd/io/process.rs
src/libstd/io/util.rs
src/libstd/lib.rs
src/libstd/os.rs
src/libstd/path/mod.rs
src/libstd/path/posix.rs
src/libstd/path/windows.rs
src/libstd/rand/mod.rs
src/libstd/rand/os.rs
src/libstd/rt/libunwind.rs
src/libstd/rt/unwind.rs
src/libstd/rt/util.rs
src/libstd/sync/condvar.rs
src/libstd/sync/mpsc/blocking.rs
src/libstd/sync/mpsc/mod.rs
src/libstd/sync/mpsc/select.rs
src/libstd/sync/mutex.rs
src/libstd/sync/rwlock.rs
src/libstd/sys/common/stack.rs
src/libstd/sys/unix/c.rs
src/libstd/sys/unix/stack_overflow.rs
src/libstd/sys/unix/sync.rs
src/libstd/sys/windows/condvar.rs
src/libstd/sys/windows/mutex.rs
src/libstd/sys/windows/os.rs
src/libstd/sys/windows/sync.rs
src/libsyntax/ast.rs
src/libsyntax/ast_map/mod.rs
src/libsyntax/codemap.rs
src/libsyntax/diagnostic.rs
src/libsyntax/ext/asm.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/deriving/decodable.rs
src/libsyntax/ext/deriving/generic/mod.rs
src/libsyntax/ext/deriving/hash.rs
src/libsyntax/ext/expand.rs
src/libsyntax/fold.rs
src/libsyntax/parse/obsolete.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pp.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/libtest/lib.rs
src/rt/arch/powerpc/morestack.S [new file with mode: 0644]
src/rt/arch/powerpc/record_sp.S [new file with mode: 0644]
src/rustbook/build.rs
src/rustbook/css.rs
src/rustbook/javascript.rs [new file with mode: 0644]
src/rustbook/main.rs
src/rustllvm/llvm-auto-clean-trigger
src/test/auxiliary/macro_crate_test.rs
src/test/auxiliary/no_method_suggested_traits.rs [new file with mode: 0644]
src/test/bench/shootout-fasta-redux.rs
src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs [new file with mode: 0644]
src/test/compile-fail/coherence-impls-builtin.rs [new file with mode: 0644]
src/test/compile-fail/coherence-negative-impls-safe.rs [new file with mode: 0644]
src/test/compile-fail/coherence-orphan.rs
src/test/compile-fail/issue-14853.rs
src/test/compile-fail/issue-17718-static-sync.rs
src/test/compile-fail/issue-20831-debruijn.rs [new file with mode: 0644]
src/test/compile-fail/issue-21045.rs [new file with mode: 0644]
src/test/compile-fail/issue-21160.rs [new file with mode: 0644]
src/test/compile-fail/issue-2611-4.rs
src/test/compile-fail/issue-7013.rs
src/test/compile-fail/kindck-nonsendable-1.rs
src/test/compile-fail/marker-no-send.rs [deleted file]
src/test/compile-fail/marker-no-share.rs [deleted file]
src/test/compile-fail/mutable-enum-indirect.rs
src/test/compile-fail/no-method-suggested-traits.rs [new file with mode: 0644]
src/test/compile-fail/no-send-res-ports.rs
src/test/compile-fail/no_send-enum.rs
src/test/compile-fail/no_send-rc.rs
src/test/compile-fail/no_send-struct.rs
src/test/compile-fail/no_share-enum.rs
src/test/compile-fail/no_share-rc.rs
src/test/compile-fail/no_share-struct.rs
src/test/compile-fail/obsolete-tilde.rs [deleted file]
src/test/compile-fail/obsolete-tuple-struct-deref.rs [deleted file]
src/test/compile-fail/regions-bound-missing-bound-in-impl.rs
src/test/compile-fail/task-rng-isnt-sendable.rs
src/test/compile-fail/trait-bounds-impl-comparison-1.rs
src/test/compile-fail/trait-bounds-impl-comparison-2.rs
src/test/compile-fail/traits-negative-impls.rs [new file with mode: 0644]
src/test/compile-fail/typeck-negative-impls-builtin.rs [new file with mode: 0644]
src/test/compile-fail/typeck-unsafe-always-share.rs
src/test/compile-fail/ufcs-qpath-missing-params.rs [new file with mode: 0644]
src/test/compile-fail/ufcs-qpath-self-mismatch.rs [new file with mode: 0644]
src/test/compile-fail/unique-unique-kind.rs
src/test/compile-fail/unsendable-class.rs
src/test/compile-fail/vec-matching-obsolete-syntax.rs [deleted file]
src/test/debuginfo/limited-debuginfo.rs
src/test/pretty/trait-polarity.rs
src/test/run-make/compiler-lookup-paths-2/Makefile [new file with mode: 0644]
src/test/run-make/compiler-lookup-paths-2/a.rs [new file with mode: 0644]
src/test/run-make/compiler-lookup-paths-2/b.rs [new file with mode: 0644]
src/test/run-make/compiler-lookup-paths-2/c.rs [new file with mode: 0644]
src/test/run-make/extern-flag-disambiguates/Makefile
src/test/run-make/extern-flag-disambiguates/a.rs
src/test/run-make/extern-flag-disambiguates/b.rs
src/test/run-make/extern-flag-disambiguates/c.rs
src/test/run-make/extern-flag-disambiguates/d.rs
src/test/run-make/graphviz-flowgraph/Makefile
src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot
src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot
src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot
src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot
src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot
src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot
src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot
src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot
src/test/run-make/tools.mk
src/test/run-pass-fulldeps/macro-crate.rs
src/test/run-pass/associated-types-enum-field-named.rs [new file with mode: 0644]
src/test/run-pass/associated-types-enum-field-numbered.rs [new file with mode: 0644]
src/test/run-pass/associated-types-normalize-unifield-struct.rs [new file with mode: 0644]
src/test/run-pass/associated-types-projection-in-object-type.rs [new file with mode: 0644]
src/test/run-pass/associated-types-struct-field-named.rs [new file with mode: 0644]
src/test/run-pass/associated-types-struct-field-numbered.rs [new file with mode: 0644]
src/test/run-pass/backtrace.rs
src/test/run-pass/coherence-negative-impls-safe.rs [new file with mode: 0644]
src/test/run-pass/const-polymorphic-paths.rs
src/test/run-pass/issue-16530.rs [new file with mode: 0644]
src/test/run-pass/issue-17503.rs
src/test/run-pass/issue-20575.rs [new file with mode: 0644]
src/test/run-pass/issue-20676.rs [new file with mode: 0644]
src/test/run-pass/issue-21058.rs [new file with mode: 0644]
src/test/run-pass/issue-8898.rs
src/test/run-pass/regions-debruijn-of-object.rs [new file with mode: 0644]
src/test/run-pass/slice-2.rs
src/test/run-pass/syntax-trait-polarity.rs
src/test/run-pass/trait-false-ambiguity-where-clause-builtin-bound.rs [new file with mode: 0644]
src/test/run-pass/traits-negative-impls.rs [new file with mode: 0644]
src/test/run-pass/ufcs-trait-object.rs [new file with mode: 0644]
src/test/run-pass/where-clause-bounds-inconsistency.rs [new file with mode: 0644]
src/test/run-pass/zero_sized_subslice_match.rs [new file with mode: 0644]

index bc8dbc878baa3a0f59f3a5276866d2e726ecd990..896731f02515b615582a63bf49684939b5c4188e 100644 (file)
@@ -581,7 +581,7 @@ Robert Knight <robertknight@gmail.com>
 Robert Millar <robert.millar@cantab.net>
 Robin Gloster <robin@loc-com.de>
 Robin Stocker <robin@nibor.org>
-Rohit Joshi <rohit.joshi@capitalone.com>
+Rohit Joshi <rohit.c.joshi@gmail.com>
 Roland Tanglao <roland@rolandtanglao.com>
 Rolf Timmermans <rolftimmermans@voormedia.com>
 Rolf van de Krol <info@rolfvandekrol.nl>
index 2b3609e28a6a0c15441c05946485d8ebd37a3640..9f2bd6dc30c5dd9f1054a69f7f8e233d8bc092e2 100644 (file)
@@ -27,7 +27,7 @@ please do two things:
 
 Pull requests will be treated as "review requests", and we will give
 feedback we expect to see corrected on
-[style](https://github.com/rust-lang/rust/wiki/Note-style-guide) and
+[style](http://aturon.github.io/) and
 substance before pulling.  Changes contributed via pull request should
 focus on a single issue at a time, like any other.  We will not accept
 pull-requests that try to "sneak" unrelated changes in.
index a2394101f3a72f8a30a7cc952bd712289165fba9..63c5742a540d404c0502a38326fceb06e47da22a 100644 (file)
 #     make check-stage1-std RUST_TEST_TASKS=1
 #
 # This is hardly all there is to know of The Rust Build System's
-# mysteries. The tale continues on the wiki[1][2].
+# mysteries. The tale continues on the wiki[1].
 #
-# [1]: https://github.com/rust-lang/rust/wiki/Note-getting-started-developing-Rust
-# [2]: https://github.com/rust-lang/rust/wiki/Note-testsuite
+# [1]: https://github.com/rust-lang/rust/wiki/Note-testsuite
 #
 # If you really feel like getting your hands dirty, then:
 #
index e858e91773b9288e6df572d205f419ac067963c1..147d2e9d2f44aa1c377bd06a1757616d7a3840bf 100644 (file)
--- a/README.md
+++ b/README.md
@@ -58,16 +58,23 @@ documentation.
 
 ### Building on Windows
 
-To easily build on windows we can use [MSYS2](http://sourceforge.net/projects/msys2/):
+To easily build on windows we can use [MSYS2](http://msys2.github.io/):
 
 1. Grab the latest MSYS2 installer and go through the installer.
 2. Now from the MSYS2 terminal we want to install the mingw64 toolchain and the other
    tools we need.
 
-        $ pacman -S mingw-w64-i686-toolchain
-        $ pacman -S base-devel
+```bash
+# choose one based on platform
+$ pacman -S mingw-w64-i686-toolchain
+$ pacman -S mingw-w64-x86_64-toolchain
 
-3. With that now start `mingw32_shell.bat` from where you installed MSYS2 (i.e. `C:\msys`).
+$ pacman -S base-devel
+```
+
+3. With that now start `mingw32_shell.bat` or `mingw64_shell.bat`
+   from where you installed MSYS2 (i.e. `C:\msys`). Which one you
+   choose depends on if you want 32 or 64 bit Rust.
 4. From there just navigate to where you have Rust's source code, configure and build it:
 
         $ ./configure
index d0b99b12fd90d080b054bb9ffb0d32ca648363f2..86ed88c8d06315e87247b8f4c8106d6b7d32df90 100755 (executable)
--- a/configure
+++ b/configure
@@ -448,6 +448,10 @@ case $CFG_CPUTYPE in
         CFG_CPUTYPE=aarch64
         ;;
 
+    powerpc)
+        CFG_CPUTYPE=powerpc
+        ;;
+
     x86_64 | x86-64 | x64 | amd64)
         CFG_CPUTYPE=x86_64
         ;;
@@ -1004,7 +1008,7 @@ do
     make_dir $t/rt/jemalloc
     for i in                                          \
       isaac sync test \
-      arch/i386 arch/x86_64 arch/arm arch/aarch64 arch/mips
+      arch/i386 arch/x86_64 arch/arm arch/aarch64 arch/mips arch/powerpc
     do
       make_dir $t/rt/stage$s/$i
     done
@@ -1169,7 +1173,7 @@ do
 
         msg "configuring LLVM for $gnu_t"
 
-        LLVM_TARGETS="--enable-targets=x86,x86_64,arm,aarch64,mips"
+        LLVM_TARGETS="--enable-targets=x86,x86_64,arm,aarch64,mips,powerpc"
         LLVM_BUILD="--build=$gnu_t"
         LLVM_HOST="--host=$gnu_t"
         LLVM_TARGET="--target=$gnu_t"
index cbd889669ab22921885a17b870acaf0fd7b9d6ad..0219ab960579bb81239b8df362a522c7e4615834 100644 (file)
@@ -11,7 +11,7 @@ AR_aarch64-apple-ios = $(shell xcrun -find -sdk iphoneos ar)
 endif
 CFG_LIB_NAME_aarch64-apple-ios = lib$(1).a
 CFG_LIB_GLOB_aarch64-apple-ios = lib$(1)-*.a
-CFG_LIB_SKIP_INSTALL_aarch64-apple-ios = 1 #lib$(1)-*.a
+CFG_INSTALL_ONLY_RLIB_aarch64-apple-ios = 1
 CFG_STATIC_LIB_NAME_aarch64-apple-ios=lib$(1).a
 CFG_LIB_DSYM_GLOB_aarch64-apple-ios = lib$(1)-*.a.dSYM
 CFG_CFLAGS_aarch64-apple-ios := $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios)
index 23686c41f2b19ccfc7063d74d1ec5b942ae3f1b1..aee4e64addfc1834040be1717ca8379d63ea781f 100644 (file)
@@ -11,7 +11,7 @@ AR_armv7-apple-ios = $(shell xcrun -find -sdk iphoneos ar)
 endif
 CFG_LIB_NAME_armv7-apple-ios = lib$(1).a
 CFG_LIB_GLOB_armv7-apple-ios = lib$(1)-*.a
-CFG_LIB_SKIP_INSTALL_armv7-apple-ios = 1 #lib$(1)-*.a
+CFG_INSTALL_ONLY_RLIB_armv7-apple-ios = 1
 CFG_STATIC_LIB_NAME_armv7-apple-ios=lib$(1).a
 CFG_LIB_DSYM_GLOB_armv7-apple-ios = lib$(1)-*.a.dSYM
 CFG_JEMALLOC_CFLAGS_armv7-apple-ios := -arch armv7 -mfpu=vfp3 $(CFG_IOS_SDK_FLAGS_armv7-apple-ios)
index ccb7f014159ff9e8a55bc6acbb35c26652e0a58d..7540bd44de878211e1b540e05465c8d1c23358e4 100644 (file)
@@ -11,7 +11,7 @@ AR_armv7s-apple-ios = $(shell xcrun -find -sdk iphoneos ar)
 endif
 CFG_LIB_NAME_armv7s-apple-ios = lib$(1).a
 CFG_LIB_GLOB_armv7s-apple-ios = lib$(1)-*.a
-CFG_LIB_SKIP_INSTALL_armv7s-apple-ios = 1 #lib$(1)-*.a
+CFG_INSTALL_ONLY_RLIB_armv7s-apple-ios = 1
 CFG_STATIC_LIB_NAME_armv7s-apple-ios=lib$(1).a
 CFG_LIB_DSYM_GLOB_armv7s-apple-ios = lib$(1)-*.a.dSYM
 CFG_JEMALLOC_CFLAGS_armv7s-apple-ios := -arch armv7s -mfpu=vfp4 $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios)
index 5007c0617c5a988cbfdf032ef33984edf01e045d..e84bf49d4079a39830b28f95f958e3caf1bc4c21 100644 (file)
@@ -11,6 +11,7 @@ AR_i386-apple-ios = $(shell xcrun -find -sdk iphonesimulator ar)
 endif
 CFG_LIB_NAME_i386-apple-ios = lib$(1).a
 CFG_LIB_GLOB_i386-apple-ios = lib$(1)-*.dylib
+CFG_INSTALL_ONLY_RLIB_i386-apple-ios = 1
 CFG_STATIC_LIB_NAME_i386-apple-ios=lib$(1).a
 CFG_LIB_DSYM_GLOB_i386-apple-ios = lib$(1)-*.dylib.dSYM
 CFG_GCCISH_CFLAGS_i386-apple-ios := -Wall -Werror -g -fPIC -m32 $(CFG_IOSSIM_FLAGS_i386-apple-ios)
diff --git a/mk/cfg/powerpc-unknown-linux-gnu.mk b/mk/cfg/powerpc-unknown-linux-gnu.mk
new file mode 100644 (file)
index 0000000..fd37bd6
--- /dev/null
@@ -0,0 +1,28 @@
+# powerpc-unknown-linux-gnu configuration
+CROSS_PREFIX_powerpc-unknown-linux-gnu=powerpc-linux-gnu-
+CC_powerpc-unknown-linux-gnu=$(CC)
+CXX_powerpc-unknown-linux-gnu=$(CXX)
+CPP_powerpc-unknown-linux-gnu=$(CPP)
+AR_powerpc-unknown-linux-gnu=$(AR)
+CFG_LIB_NAME_powerpc-unknown-linux-gnu=lib$(1).so
+CFG_STATIC_LIB_NAME_powerpc-unknown-linux-gnu=lib$(1).a
+CFG_LIB_GLOB_powerpc-unknown-linux-gnu=lib$(1)-*.so
+CFG_LIB_DSYM_GLOB_powerpc-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
+CFG_CFLAGS_powerpc-unknown-linux-gnu := -m32 $(CFLAGS)
+CFG_GCCISH_CFLAGS_powerpc-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32 $(CFLAGS)
+CFG_GCCISH_CXXFLAGS_powerpc-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
+CFG_GCCISH_LINK_FLAGS_powerpc-unknown-linux-gnu := -shared -fPIC -ldl -pthread  -lrt -g -m32
+CFG_GCCISH_DEF_FLAG_powerpc-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
+CFG_GCCISH_PRE_LIB_FLAGS_powerpc-unknown-linux-gnu := -Wl,-whole-archive
+CFG_GCCISH_POST_LIB_FLAGS_powerpc-unknown-linux-gnu := -Wl,-no-whole-archive
+CFG_DEF_SUFFIX_powerpc-unknown-linux-gnu := .linux.def
+CFG_LLC_FLAGS_powerpc-unknown-linux-gnu :=
+CFG_INSTALL_NAME_powerpc-unknown-linux-gnu =
+CFG_EXE_SUFFIX_powerpc-unknown-linux-gnu =
+CFG_WINDOWSY_powerpc-unknown-linux-gnu :=
+CFG_UNIXY_powerpc-unknown-linux-gnu := 1
+CFG_PATH_MUNGE_powerpc-unknown-linux-gnu := true
+CFG_LDPATH_powerpc-unknown-linux-gnu :=
+CFG_RUN_powerpc-unknown-linux-gnu=$(2)
+CFG_RUN_TARG_powerpc-unknown-linux-gnu=$(call CFG_RUN_powerpc-unknown-linux-gnu,,$(2))
+CFG_GNU_TRIPLE_powerpc-unknown-linux-gnu := powerpc-unknown-linux-gnu
index 69070ec4fad4d5e57843074cd9477bb4c9f9ddee..b3f05a895a49fe0f65c912ac9997a59270fb1744 100644 (file)
@@ -11,7 +11,7 @@ AR_x86_64-apple-ios = $(shell xcrun -find -sdk iphonesimulator ar)
 endif
 CFG_LIB_NAME_x86_64-apple-ios = lib$(1).a
 CFG_LIB_GLOB_x86_64-apple-ios = lib$(1)-*.a
-CFG_LIB_SKIP_INSTALL_x86_64-apple-ios = 1 #lib$(1)-*.a
+CFG_INSTALL_ONLY_RLIB_x86_64-apple-ios = 1
 CFG_STATIC_LIB_NAME_x86_64-apple-ios=lib$(1).a
 CFG_LIB_DSYM_GLOB_x86_64-apple-ios = lib$(1)-*.a.dSYM
 CFG_CFLAGS_x86_64-apple-ios := $(CFG_IOSSIM_FLAGS_x86_64-apple-ios)
index ba6baa3fefef7a3bba9a455213f2fae28ec80a74..46cbe34904dbcb5698c457130dabbb18ad4e69b0 100644 (file)
@@ -18,7 +18,7 @@ CFG_RELEASE_NUM=1.0.0
 # An optional number to put after the label, e.g. '.2' -> '-beta.2'
 # NB Make sure it starts with a dot to conform to semver pre-release
 # versions (section 9)
-CFG_PRERELEASE_VERSION=
+CFG_PRERELEASE_VERSION=.1
 
 CFG_FILENAME_EXTRA=4e7c5e5c
 
@@ -30,9 +30,8 @@ CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)
 CFG_DISABLE_UNSTABLE_FEATURES=1
 endif
 ifeq ($(CFG_RELEASE_CHANNEL),beta)
-# The beta channel is temporarily called 'alpha'
-CFG_RELEASE=$(CFG_RELEASE_NUM)-alpha$(CFG_PRERELEASE_VERSION)
-CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-alpha$(CFG_PRERELEASE_VERSION)
+CFG_RELEASE=$(CFG_RELEASE_NUM)-beta(CFG_PRERELEASE_VERSION)
+CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-beta(CFG_PRERELEASE_VERSION)
 CFG_DISABLE_UNSTABLE_FEATURES=1
 endif
 ifeq ($(CFG_RELEASE_CHANNEL),nightly)
@@ -263,7 +262,7 @@ endif
 ######################################################################
 
 # FIXME: x86-ism
-LLVM_COMPONENTS=x86 arm aarch64 mips ipo bitreader bitwriter linker asmparser mcjit \
+LLVM_COMPONENTS=x86 arm aarch64 mips powerpc ipo bitreader bitwriter linker asmparser mcjit \
                 interpreter instrumentation
 
 # Only build these LLVM tools
index 50bf51b20de18f4bfb87d66c43ed00d3744366b1..78c1057c2fe524ca28a19e6d9164c0f1d08ab771 100644 (file)
@@ -177,7 +177,7 @@ define CFG_MAKE_TOOLCHAIN
         $$(CFG_GCCISH_DEF_FLAG_$(1))$$(3) $$(2) \
         $$(call CFG_INSTALL_NAME_$(1),$$(4))
 
-  ifeq ($$(findstring $(HOST_$(1)),arm aarch64 mips mipsel),)
+  ifeq ($$(findstring $(HOST_$(1)),arm aarch64 mips mipsel powerpc),)
 
   # We're using llvm-mc as our assembler because it supports
   # .cfi pseudo-ops on mac
@@ -189,7 +189,7 @@ define CFG_MAKE_TOOLCHAIN
                     -o=$$(1)
   else
 
-  # For the ARM, AARCH64 and MIPS crosses, use the toolchain assembler
+  # For the ARM, AARCH64, MIPS and POWER crosses, use the toolchain assembler
   # FIXME: We should be able to use the LLVM assembler
   CFG_ASSEMBLE_$(1)=$$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \
                    $$(CFG_DEPEND_FLAGS) $$(2) -c -o $$(1)
index 6a5daeb690941f98097570ce3676e24bc101a67c..f1c4aa65f5ffe5943b302698eda17ebdd7697bcc 100644 (file)
@@ -134,7 +134,7 @@ prepare-target-$(2)-host-$(3)-$(1)-$(4): prepare-maybe-clean-$(4) \
         $$(if $$(findstring $(3), $$(PREPARE_HOST)), \
           $$(call PREPARE_DIR,$$(PREPARE_WORKING_DEST_LIB_DIR)) \
           $$(foreach crate,$$(TARGET_CRATES), \
-           $$(if $$(findstring 1, $$(ONLY_RLIB_$$(crate))),, \
+           $$(if $$(or $$(findstring 1, $$(ONLY_RLIB_$$(crate))),$$(findstring 1,$$(CFG_INSTALL_ONLY_RLIB_$(2)))),, \
               $$(call PREPARE_LIB,$$(call CFG_LIB_GLOB_$(2),$$(crate)))) \
             $$(call PREPARE_LIB,$$(call CFG_RLIB_GLOB,$$(crate)))) \
           $$(if $$(findstring $(2),$$(CFG_HOST)), \
index a9a9e0858ec6b7cc387a5b48d2d09b8c5f166b24..8238dd3a5ba42d7dcfffc4647a524c08b91b0652 100644 (file)
@@ -10,7 +10,7 @@ There aren't many large programs yet. The Rust [compiler][rustc], 60,000+ lines
 
 A research browser engine called [Servo][servo], currently 30,000+ lines across more than a dozen crates, will be exercising a lot of Rust's distinctive type-system and concurrency features, and integrating many native libraries.
 
-[servo]: https://github.com/mozilla/servo
+[servo]: https://github.com/servo/servo
 
 Some examples that demonstrate different aspects of the language:
 
index 1b463d77693534fa8bb1f6404abd9196f60c16af..bb1805d694fd090e6085690aeef069042dc19656 100644 (file)
@@ -30,7 +30,7 @@ No. It started as a Graydon Hoare's part-time side project in 2006 and remained
 
 # What will Mozilla use Rust for?
 
-Mozilla intends to use Rust as a platform for prototyping experimental browser architectures. Specifically, the hope is to develop a browser that is more amenable to parallelization than existing ones, while also being less prone to common C++ coding errors that result in security exploits. The name of that project is _[Servo](http://github.com/mozilla/servo)_.
+Mozilla intends to use Rust as a platform for prototyping experimental browser architectures. Specifically, the hope is to develop a browser that is more amenable to parallelization than existing ones, while also being less prone to common C++ coding errors that result in security exploits. The name of that project is _[Servo](http://github.com/servo/servo)_.
 
 # Why a BSD-style permissive license rather than MPL or tri-license?
 
index 0d5e547c827022b9d278a338bc59cda6cafcf367..d93b680ae6de704cb83fd73394475fb1681b88e8 100644 (file)
@@ -5,7 +5,7 @@ accomplishes these goals by being memory safe without using garbage collection.
 
 This introduction will give you a rough idea of what Rust is like, eliding many
 details. It does not require prior experience with systems programming, but you
-may find the syntax easier if you've used a 'curly brace' programming language
+may find the syntax easier if you've used a "curly brace" programming language
 before, like C or JavaScript. The concepts are more important than the syntax,
 so don't worry if you don't get every last detail: you can read [The
 Rust Programming Language](book/index.html) to get a more complete explanation.
@@ -15,7 +15,7 @@ Rust to follow along. If you'd like to anyway, check out [the
 homepage](http://rust-lang.org) for explanation.
 
 To show off Rust, let's talk about how easy it is to get started with Rust.
-Then, we'll talk about Rust's most interesting feature, **ownership**, and
+Then, we'll talk about Rust's most interesting feature, *ownership*, and
 then discuss how it makes concurrency easier to reason about. Finally,
 we'll talk about how Rust breaks down the perceived dichotomy between speed
 and safety.
@@ -57,7 +57,7 @@ version = "0.0.1"
 authors = ["Your Name <you@example.com>"]
 ```
 
-This is called a **manifest**, and it contains all of the metadata that Cargo
+This is called a *manifest*, and it contains all of the metadata that Cargo
 needs to compile your project.
 
 Here's what's in `src/main.rs`:
@@ -68,7 +68,7 @@ fn main() {
 }
 ```
 
-Cargo generated a 'hello world' for us. We'll talk more about the syntax here
+Cargo generated a "Hello World" for us. We'll talk more about the syntax here
 later, but that's what Rust code looks like! Let's compile and run it:
 
 ```{bash}
@@ -146,8 +146,8 @@ Enough about tools, let's talk code!
 
 # Ownership
 
-Rust's defining feature is 'memory safety without garbage collection.' Let's
-take a moment to talk about what that means. **Memory safety** means that the
+Rust's defining feature is "memory safety without garbage collection". Let's
+take a moment to talk about what that means. *Memory safety* means that the
 programming language eliminates certain kinds of bugs, such as [buffer
 overflows](http://en.wikipedia.org/wiki/Buffer_overflow) and [dangling
 pointers](http://en.wikipedia.org/wiki/Dangling_pointer). These problems occur
@@ -170,7 +170,7 @@ We make an array, `v`, and then call `push` on it. `push` is a method which
 adds an element to the end of an array.
 
 Next, we make a new variable, `x`, that's equal to the first element of
-the array. Simple, but this is where the 'bug' will appear.
+the array. Simple, but this is where the "bug" will appear.
 
 Let's keep going. We then call `push` again, pushing "world" onto the
 end of the array. `v` now is `["Hello", "world"]`.
@@ -222,7 +222,7 @@ its length changes, we may need to allocate more memory. In Ruby, this happens
 as well, we just don't think about it very often. So why does the C++ version
 segfault when we allocate more memory?
 
-The answer is that in the C++ version, `x` is a **reference** to the memory
+The answer is that in the C++ version, `x` is a *reference* to the memory
 location where the first element of the array is stored. But in Ruby, `x` is a
 standalone value, not connected to the underyling array at all. Let's dig into
 the details for a moment. Your program has access to memory, provided to it by
@@ -332,11 +332,11 @@ error: aborting due to previous error
 
 When we try to mutate the array by `push`ing it the second time, Rust throws
 an error. It says that we "cannot borrow v as mutable because it is also
-borrowed as immutable." What's up with "borrowed"?
+borrowed as immutable." What does it mean by "borrowed"?
 
-In Rust, the type system encodes the notion of **ownership**. The variable `v`
-is an "owner" of the vector. When we make a reference to `v`, we let that
-variable (in this case, `x`) 'borrow' it for a while. Just like if you own a
+In Rust, the type system encodes the notion of *ownership*. The variable `v`
+is an *owner* of the vector. When we make a reference to `v`, we let that
+variable (in this case, `x`) *borrow* it for a while. Just like if you own a
 book, and you lend it to me, I'm borrowing the book.
 
 So, when I try to modify the vector with the second call to `push`, I need
@@ -392,22 +392,23 @@ Here's an example of a concurrent Rust program:
 use std::thread::Thread;
 
 fn main() {
-    for _ in range(0u, 10u) {
-        Thread::spawn(move || {
+    let guards: Vec<_> = (0..10).map(|_| {
+        Thread::scoped(|| {
             println!("Hello, world!");
-        });
-    }
+        })
+    }).collect();
 }
 ```
 
-This program creates ten threads, who all print `Hello, world!`. The
-`spawn` function takes one argument, a closure, indicated by the
-double bars `||`. (The `move` keyword indicates that the closure takes
-ownership of any data it uses; we'll have more on the significance of
-this shortly.) This closure is executed in a new thread created by
-`spawn`.
+This program creates ten threads, which all print `Hello, world!`. The `scoped`
+function takes one argument, a closure, indicated by the double bars `||`. This
+closure is executed in a new thread created by `scoped`. The method is called
+`scoped` because it returns a 'join guard', which will automatically join the
+child thread when it goes out of scope. Because we `collect` these guards into
+a `Vec<T>`, and that vector goes out of scope at the end of our program, our
+program will wait for every thread to finish before finishing.
 
-One common form of problem in concurrent programs is a 'data race.'
+One common form of problem in concurrent programs is a *data race*.
 This occurs when two different threads attempt to access the same
 location in memory in a non-synchronized way, where at least one of
 them is a write. If one thread is attempting to read, and one thread
@@ -460,9 +461,9 @@ code tries to make three owners. This may cause a safety problem, so
 Rust disallows it.
 
 What to do here? Rust has two types that helps us: `Arc<T>` and `Mutex<T>`.
-"Arc" stands for "atomically reference counted." In other words, an Arc will
+*Arc* stands for "atomically reference counted". In other words, an Arc will
 keep track of the number of references to something, and not free the
-associated resource until the count is zero. The 'atomic' portion refers to an
+associated resource until the count is zero. The *atomic* portion refers to an
 Arc's usage of concurrency primitives to atomically update the count, making it
 safe across threads. If we use an Arc, we can have our three references. But,
 an Arc does not allow mutable borrows of the data it holds, and we want to
@@ -525,13 +526,13 @@ give us assurance _at compile time_ that we weren't doing something incorrect
 with regards to concurrency. In order to share ownership, we were forced to be
 explicit and use a mechanism to ensure that it would be properly handled.
 
-# Safety _and_ speed
+# Safety _and_ Speed
 
-Safety and speed are always presented as a continuum. On one hand, you have
-maximum speed, but no safety. On the other, you have absolute safety, with no
-speed. Rust seeks to break out of this mode by introducing safety at compile
-time, ensuring that you haven't done anything wrong, while compiling to the
-same low-level code you'd expect without the safety.
+Safety and speed are always presented as a continuum. At one end of the spectrum,
+you have maximum speed, but no safety. On the other end, you have absolute safety
+with no speed. Rust seeks to break out of this paradigm by introducing safety at
+compile time, ensuring that you haven't done anything wrong, while compiling to
+the same low-level code you'd expect without the safety.
 
 As an example, Rust's ownership system is _entirely_ at compile time. The
 safety check that makes this an error about moved values:
index bd4d959109716e354d97227bda0b38a5958d1f30..c746c5773dd0907ce8fea7c97a69e47c66de178f 100644 (file)
@@ -12,6 +12,7 @@ Looks like you've taken a wrong turn.
 Some things that might be helpful to you though:
 
 ## Search
+
 * <form action="https://duckduckgo.com/">
     <input type="text" id="site-search" name="q" size="80"></input>
     <input type="submit" value="Search DuckDuckGo">
@@ -19,10 +20,12 @@ Some things that might be helpful to you though:
 * Rust doc search: <span id="core-search"></span>
 
 ## Reference
+
 * [The Rust official site](http://rust-lang.org)
-* [The Rust reference](http://doc.rust-lang.org/reference.html) (* [PDF](http://doc.rust-lang.org/reference.pdf))
+* [The Rust reference](http://doc.rust-lang.org/reference.html)
 
 ## Docs
+
 * [The standard library](http://doc.rust-lang.org/std/)
 
 <script>
index 623097b2fc90f872fae1f3530468c183e9fe1481..c8e31f27b3507629e1824be826960ed9605ec041 100644 (file)
@@ -1588,7 +1588,6 @@ pointer values (pointing to a type for which an implementation of the given
 trait is in scope) to pointers to the trait name, used as a type.
 
 ```
-# use std::boxed::Box;
 # trait Shape { }
 # impl Shape for int { }
 # let mycircle = 0i;
@@ -1647,7 +1646,6 @@ fn radius_times_area<T: Circle>(c: T) -> f64 {
 Likewise, supertrait methods may also be called on trait objects.
 
 ```{.ignore}
-# use std::boxed::Box;
 # trait Shape { fn area(&self) -> f64; }
 # trait Circle : Shape { fn radius(&self) -> f64; }
 # impl Shape for int { fn area(&self) -> f64 { 0.0 } }
@@ -2170,7 +2168,7 @@ arbitrarily complex configurations through nesting.
 The following configurations must be defined by the implementation:
 
 * `target_arch = "..."`. Target CPU architecture, such as `"x86"`, `"x86_64"`
-  `"mips"`, `"arm"`, or `"aarch64"`.
+  `"mips"`, `"powerpc"`, `"arm"`, or `"aarch64"`.
 * `target_endian = "..."`. Endianness of the target CPU, either `"little"` or
   `"big"`.
 * `target_family = "..."`. Operating system family of the target, e. g.
@@ -2432,15 +2430,15 @@ There are three different types of inline attributes:
 * `#[inline(always)]` asks the compiler to always perform an inline expansion.
 * `#[inline(never)]` asks the compiler to never perform an inline expansion.
 
-### Deriving
+### Derive
 
-The `deriving` attribute allows certain traits to be automatically implemented
+The `derive` attribute allows certain traits to be automatically implemented
 for data structures. For example, the following will create an `impl` for the
 `PartialEq` and `Clone` traits for `Foo`, the type parameter `T` will be given
 the `PartialEq` or `Clone` constraints for the appropriate `impl`:
 
 ```
-#[deriving(PartialEq, Clone)]
+#[derive(PartialEq, Clone)]
 struct Foo<T> {
     a: int,
     b: T
@@ -2462,7 +2460,7 @@ impl<T: PartialEq> PartialEq for Foo<T> {
 }
 ```
 
-Supported traits for `deriving` are:
+Supported traits for `derive` are:
 
 * Comparison traits: `PartialEq`, `Eq`, `PartialOrd`, `Ord`.
 * Serialization: `Encodable`, `Decodable`. These require `serialize`.
@@ -2967,8 +2965,8 @@ _panicked state_.
 
 ### Unary operator expressions
 
-Rust defines six symbolic unary operators. They are all written as prefix
-operators, before the expression they apply to.
+Rust defines three unary operators. They are all written as prefix operators,
+before the expression they apply to.
 
 * `-`
   : Negation. May only be applied to numeric types.
@@ -2986,13 +2984,6 @@ operators, before the expression they apply to.
   : Logical negation. On the boolean type, this flips between `true` and
     `false`. On integer types, this inverts the individual bits in the
     two's complement representation of the value.
-* `box`
-  : [Boxing](#pointer-types) operators. Allocate a box to hold the value they
-    are applied to, and store the value in it. `box` creates a box.
-* `&`
-  : Borrow operator. Returns a reference, pointing to its operand. The operand
-    of a borrow is statically proven to outlive the resulting pointer. If the
-    borrow-checker cannot prove this, it is a compilation error.
 
 ### Binary operator expressions
 
@@ -3799,7 +3790,6 @@ enclosing `enum` or `struct` type itself. Such recursion has restrictions:
 An example of a *recursive* type and its use:
 
 ```
-# use std::boxed::Box;
 enum List<T> {
     Nil,
     Cons(T, Box<List<T>>)
@@ -3912,7 +3902,6 @@ implementation of `R`, and the pointer value of `E`.
 An example of an object type:
 
 ```
-# use std::boxed::Box;
 trait Printable {
   fn stringify(&self) -> String;
 }
@@ -4120,7 +4109,6 @@ the type of a box is `std::owned::Box<T>`.
 An example of a box type and value:
 
 ```
-# use std::boxed::Box;
 let x: Box<int> = Box::new(10);
 ```
 
@@ -4130,7 +4118,6 @@ copy of a box to move ownership of the value. After a value has been moved,
 the source location cannot be used unless it is reinitialized.
 
 ```
-# use std::boxed::Box;
 let x: Box<int> = Box::new(10);
 let y = x;
 // attempting to use `x` will result in an error here
index 128d75468e6f4239274d463943b91f784b7ca863..3f59f12e74ca3cd5d28ba0d60eebf506800e2429 100644 (file)
@@ -195,6 +195,7 @@ h5 a:hover {text-decoration: none;}
 
 pre, code {
     font-family: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", monospace;
+    word-wrap: break-word;
 }
 pre {
     border-left: 2px solid #eee;
@@ -204,7 +205,6 @@ pre {
     margin: 20px 0;
     font-size: 13px;
     word-break: break-all;
-    word-wrap: break-word;
 }
 code {
     padding: 0 2px;
@@ -315,6 +315,8 @@ hr {
 table {
     border-collapse: collapse;
     border-spacing: 0;
+    overflow-x: auto;
+    display: block;
 }
 
 table tr.odd {
index 054552559dbec077fb5a1fd4533b3f0d40b83efb..0b686eb76dbfb2d5dcf1eba88d965d1c2b069cc7 100644 (file)
@@ -198,7 +198,7 @@ Rustdoc also supplies some extra sugar for helping with some tedious
 documentation examples. If a line is prefixed with `# `, then the line
 will not show up in the HTML documentation, but it will be used when
 testing the code block (NB. the space after the `#` is required, so
-that one can still write things like `#[deriving(Eq)]`).
+that one can still write things like `#[derive(Eq)]`).
 
 ~~~md
 ```
@@ -217,6 +217,35 @@ spawn(move || { fib(200); })
 The documentation online would look like `spawn(move || { fib(200); })`, but when
 testing this code, the `fib` function will be included (so it can compile).
 
+Rustdoc will automatically add a `main()` wrapper around your code, and in the right
+place. For example:
+
+```
+/// ```
+/// use std::rc::Rc;
+///
+/// let five = Rc::new(5);
+/// ```
+# fn foo() {}
+```
+
+This will end up testing:
+
+```
+fn main() {
+    use std::rc::Rc;
+    let five = Rc::new(5);
+}
+```
+
+Here's the full algorithm:
+
+1. Given a code block, if it does not contain `fn main`, it is wrapped in `fn main() { your_code }`
+2. Given that result, if it contains no `extern crate` directives but it also
+   contains the name of the crate being tested, then `extern crate <name>` is
+   injected at the top.
+3. Some common `allow` attributes are added for documentation examples at the top.
+
 ## Running tests (advanced)
 
 Running tests often requires some special configuration to filter tests, find
index 67fcb94326c409ff3853adbde3dda5043dda84da..eb9e2b24ac900e0d7f1090cc7697c057111bec19 100644 (file)
@@ -8,7 +8,7 @@ memory safe without using garbage collection.
 "The Rust Programming Language" is split into three sections, which you can
 navigate through the menu on the left.
 
-## Basics
+<h2 class="section-header"><a href="basic.html">Basics</a></h2>
 
 This section is a linear introduction to the basic syntax and semantics of
 Rust. It has individual sections on each part of Rust's syntax, and culminates
@@ -17,7 +17,7 @@ in a small project: a guessing game.
 After reading "Basics," you will have a good foundation to learn more about
 Rust, and can write very simple programs.
 
-## Intermediate
+<h2 class="section-header"><a href="intermediate.html">Intermediate</a></h2>
 
 This section contains individual chapters, which are self-contained. They focus
 on specific topics, and can be read in any order.
@@ -25,7 +25,7 @@ on specific topics, and can be read in any order.
 After reading "Intermediate," you will have a solid understanding of Rust,
 and will be able to understand most Rust code and write more complex programs.
 
-## Advanced
+<h2 class="section-header"><a href="advanced.html">Advanced</a></h2>
 
 In a similar fashion to "Intermediate," this section is full of individual,
 deep-dive chapters, which stand alone and can be read in any order. These
index 1a61c6d216b68054cda09231b979b8cfe7bdaa1b..aab03add905bb2f691b58f25cf40b147b7f67656 100644 (file)
@@ -26,7 +26,7 @@
     * [Iterators](iterators.md)
     * [Generics](generics.md)
     * [Traits](traits.md)
-    * [Tasks](tasks.md)
+    * [Threads](threads.md)
     * [Error Handling](error-handling.md)
 * [III: Advanced Topics](advanced.md)
     * [FFI](ffi.md)
index 7f8bdfe6972c0ba2ea6a32753dcde76af3ee3827..e7ac55bfbd30d4ccb26792f059054f8a4f1d0a2f 100644 (file)
@@ -82,7 +82,7 @@ arrays:
 
 ```{rust}
 let a = [0, 1, 2, 3, 4];
-let middle = a.slice(1, 4);     // A slice of a: just the elements [1,2,3]
+let middle = &a[1..4];     // A slice of a: just the elements 1, 2, and 3
 
 for e in middle.iter() {
     println!("{}", e);          // Prints 1, 2, 3
index 5b49df92fe39691a60213e05e7f7f2f8cabe48c2..51a0bb69a7ce9291df9959dd084794917de0ec41 100644 (file)
@@ -51,7 +51,7 @@ defined. The closure borrows any variables it uses, so this will error:
 
 ```{rust,ignore}
 fn main() {
-    let mut x = 5;
+    let mut x: i32 = 5;
 
     let printer = |&:| { println!("x is: {}", x); };
 
index afa890b84b401576108aacddebb64a65652fc83e..5ad9fcd41f554f0052a788801ca03f94be2a06df 100644 (file)
@@ -182,7 +182,7 @@ and with a struct, we have actual names.
 
 There _is_ one case when a tuple struct is very useful, though, and that's a
 tuple struct with only one element. We call this a *newtype*, because it lets
-you create a new type that's a synonym for another one:
+you create a new type that's similar to another one:
 
 ```{rust}
 struct Inches(i32);
@@ -194,7 +194,8 @@ println!("length is {} inches", integer_length);
 ```
 
 As you can see here, you can extract the inner integer type through a
-destructuring `let`.
+destructuring `let`, as we discussed previously in 'tuples.' In this case, the
+`let Inches(integer_length)` assigns `10` to `integer_length`.
 
 ## Enums
 
index 3e7af5bbdde69bdf3313ca8409bcd266cdb1a679..4b1c92239aed348f633b8837f571b4a6da5565a1 100644 (file)
@@ -181,7 +181,7 @@ errors that can occur.
 # Non-recoverable errors with `panic!`
 
 In the case of an error that is unexpected and not recoverable, the `panic!`
-macro will induce a panic. This will crash the current task, and give an error:
+macro will induce a panic. This will crash the current thread, and give an error:
 
 ```{rust,ignore}
 panic!("boom");
@@ -190,7 +190,7 @@ panic!("boom");
 gives
 
 ```text
-task '<main>' panicked at 'boom', hello.rs:2
+thread '<main>' panicked at 'boom', hello.rs:2
 ```
 
 when you run it.
index a65325af7be3db9532474e8a52ada8efed1975b0..940d2c968be677e33d6754e2fd4d0f7e21ed3414 100644 (file)
@@ -166,12 +166,12 @@ GitHub](https://github.com/thestinger/rust-snappy).
 
 # Stack management
 
-Rust tasks by default run on a *large stack*. This is actually implemented as a
+Rust threads by default run on a *large stack*. This is actually implemented as a
 reserving a large segment of the address space and then lazily mapping in pages
 as they are needed. When calling an external C function, the code is invoked on
 the same stack as the rust stack. This means that there is no extra
 stack-switching mechanism in place because it is assumed that the large stack
-for the rust task is plenty for the C function to have.
+for the rust thread is plenty for the C function to have.
 
 A planned future improvement (not yet implemented at the time of this writing)
 is to have a guard page at the end of every rust stack. No rust function will
@@ -184,8 +184,8 @@ For normal external function usage, this all means that there shouldn't be any
 need for any extra effort on a user's perspective. The C stack naturally
 interleaves with the rust stack, and it's "large enough" for both to
 interoperate. If, however, it is determined that a larger stack is necessary,
-there are appropriate functions in the task spawning API to control the size of
-the stack of the task which is spawned.
+there are appropriate functions in the thread spawning API to control the size of
+the stack of the thread which is spawned.
 
 # Destructors
 
@@ -262,8 +262,6 @@ referenced Rust object.
 Rust code:
 
 ~~~~no_run
-# use std::boxed::Box;
-
 #[repr(C)]
 struct RustObject {
     a: i32,
@@ -320,8 +318,7 @@ In the previously given examples the callbacks are invoked as a direct reaction
 to a function call to the external C library.
 The control over the current thread is switched from Rust to C to Rust for the
 execution of the callback, but in the end the callback is executed on the
-same thread (and Rust task) that lead called the function which triggered
-the callback.
+same thread that called the function which triggered the callback.
 
 Things get more complicated when the external library spawns its own threads
 and invokes callbacks from there.
@@ -329,7 +326,7 @@ In these cases access to Rust data structures inside the callbacks is
 especially unsafe and proper synchronization mechanisms must be used.
 Besides classical synchronization mechanisms like mutexes, one possibility in
 Rust is to use channels (in `std::comm`) to forward data from the C thread
-that invoked the callback into a Rust task.
+that invoked the callback into a Rust thread.
 
 If an asynchronous callback targets a special object in the Rust address space
 it is also absolutely necessary that no more callbacks are performed by the
index 6980663651a4a27a30a4032b27e0747b46b14de0..eae7fc1989506d91291b2c47c73304b4399df60c 100644 (file)
@@ -142,5 +142,23 @@ fn foo(x: i32) -> i32 {
 }
 ```
 
+The previous definition without `return` may look a bit strange if you haven't
+worked in an expression-based language before, but it becomes intutive over
+time. If this were production code, we wouldn't write it in that way anyway,
+we'd write this:
+
+```rust
+fn foo(x: i32) -> i32 {
+    if x < 5 {
+        x
+    } else {
+        x + 1
+    }
+}
+```
+
+Because `if` is an expression, and it's the only expression in this function,
+the value will be the result of the `if`.
+
 There are some additional ways to define functions, but they involve features
 that we haven't learned about yet, so let's just leave it at that for now.
index 402f36cd74bd9239f3b15f86e17ec859cd446907..023143ae64e264b90b2df1977fa08a46a81c32bb 100644 (file)
@@ -88,9 +88,9 @@ enum Result<H, N> {
 if we wanted to. Convention says that the first generic parameter should be
 `T`, for 'type,' and that we use `E` for 'error.' Rust doesn't care, however.
 
-The `Result<T, E>` type is intended to
-be used to return the result of a computation, and to have the ability to
-return an error if it didn't work out. Here's an example:
+The `Result<T, E>` type is intended to be used to return the result of a
+computation, and to have the ability to return an error if it didn't work out.
+Here's an example:
 
 ```{rust}
 let x: Result<f64, String> = Ok(2.3f64);
index 16bd1e347b7c85c839848a130fa9016e197e11d5..474e7db6942e1e260d817a7fce8d13dc083a1e63 100644 (file)
@@ -239,7 +239,7 @@ use std::rand;
 fn main() {
     println!("Guess the number!");
 
-    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+    let secret_number = (rand::random::<u32>() % 100) + 1;
 
     println!("The secret number is: {}", secret_number);
 
@@ -283,7 +283,7 @@ use std::cmp::Ordering;
 fn main() {
     println!("Guess the number!");
 
-    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+    let secret_number = (rand::random::<u32>() % 100) + 1;
 
     println!("The secret number is: {}", secret_number);
 
@@ -318,7 +318,7 @@ $ cargo build
 src/main.rs:20:15: 20:20 error: mismatched types: expected `i32` but found `collections::string::String` (expected i32 but found struct collections::string::String)
 src/main.rs:20     match cmp(input, secret_number) {
                              ^~~~~
-src/main.rs:20:22: 20:35 error: mismatched types: expected `i32` but found `uint` (expected i32 but found uint)
+src/main.rs:20:22: 20:35 error: mismatched types: expected `i32` but found `u32` (expected i32 but found u32)
 src/main.rs:20     match cmp(input, secret_number) {
                                     ^~~~~~~~~~~~~
 error: aborting due to 2 previous errors
@@ -328,7 +328,7 @@ This often happens when writing Rust programs, and is one of Rust's greatest
 strengths. You try out some code, see if it compiles, and Rust tells you that
 you've done something wrong. In this case, our `cmp` function works on integers,
 but we've given it unsigned integers. In this case, the fix is easy, because
-we wrote the `cmp` function! Let's change it to take `uint`s:
+we wrote the `cmp` function! Let's change it to take `u32`s:
 
 ```{rust,ignore}
 use std::io;
@@ -338,7 +338,7 @@ use std::cmp::Ordering;
 fn main() {
     println!("Guess the number!");
 
-    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+    let secret_number = (rand::random::<u32>() % 100) + 1;
 
     println!("The secret number is: {}", secret_number);
 
@@ -358,7 +358,7 @@ fn main() {
     }
 }
 
-fn cmp(a: uint, b: uint) -> Ordering {
+fn cmp(a: u32, b: u32) -> Ordering {
     if a < b { Ordering::Less }
     else if a > b { Ordering::Greater }
     else { Ordering::Equal }
@@ -370,13 +370,13 @@ And try compiling again:
 ```bash
 $ cargo build
    Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
-src/main.rs:20:15: 20:20 error: mismatched types: expected `uint` but found `collections::string::String` (expected uint but found struct collections::string::String)
+src/main.rs:20:15: 20:20 error: mismatched types: expected `u32` but found `collections::string::String` (expected u32 but found struct collections::string::String)
 src/main.rs:20     match cmp(input, secret_number) {
                              ^~~~~
 error: aborting due to previous error
 ```
 
-This error is similar to the last one: we expected to get a `uint`, but we got
+This error is similar to the last one: we expected to get a `u32`, but we got
 a `String` instead! That's because our `input` variable is coming from the
 standard input, and you can guess anything. Try it:
 
@@ -393,14 +393,14 @@ Oops! Also, you'll note that we just ran our program even though it didn't compi
 This works because the older version we did successfully compile was still lying
 around. Gotta be careful!
 
-Anyway, we have a `String`, but we need a `uint`. What to do? Well, there's
+Anyway, we have a `String`, but we need a `u32`. What to do? Well, there's
 a function for that:
 
 ```{rust,ignore}
 let input = io::stdin().read_line()
                        .ok()
                        .expect("Failed to read line");
-let input_num: Option<uint> = input.parse();
+let input_num: Option<u32> = input.parse();
 ```
 
 The `parse` function takes in a `&str` value and converts it into something.
@@ -408,22 +408,22 @@ We tell it what kind of something with a type hint. Remember our type hint with
 `random()`? It looked like this:
 
 ```{rust,ignore}
-rand::random::<uint>();
+rand::random::<u32>();
 ```
 
 There's an alternate way of providing a hint too, and that's declaring the type
 in a `let`:
 
 ```{rust,ignore}
-let x: uint = rand::random();
+let x: u32 = rand::random();
 ```
 
-In this case, we say `x` is a `uint` explicitly, so Rust is able to properly
+In this case, we say `x` is a `u32` explicitly, so Rust is able to properly
 tell `random()` what to generate. In a similar fashion, both of these work:
 
 ```{rust,ignore}
-let input_num = "5".parse::<uint>();         // input_num: Option<uint>
-let input_num: Option<uint> = "5".parse();   // input_num: Option<uint>
+let input_num = "5".parse::<u32>();         // input_num: Option<u32>
+let input_num: Option<u32> = "5".parse();   // input_num: Option<u32>
 ```
 
 Anyway, with us now converting our input to a number, our code looks like this:
@@ -436,7 +436,7 @@ use std::cmp::Ordering;
 fn main() {
     println!("Guess the number!");
 
-    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+    let secret_number = (rand::random::<u32>() % 100) + 1;
 
     println!("The secret number is: {}", secret_number);
 
@@ -445,7 +445,7 @@ fn main() {
     let input = io::stdin().read_line()
                            .ok()
                            .expect("Failed to read line");
-    let input_num: Option<uint> = input.parse();
+    let input_num: Option<u32> = input.parse();
 
     println!("You guessed: {}", input_num);
 
@@ -456,7 +456,7 @@ fn main() {
     }
 }
 
-fn cmp(a: uint, b: uint) -> Ordering {
+fn cmp(a: u32, b: u32) -> Ordering {
     if a < b { Ordering::Less }
     else if a > b { Ordering::Greater }
     else { Ordering::Equal }
@@ -468,13 +468,13 @@ Let's try it out!
 ```bash
 $ cargo build
    Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
-src/main.rs:22:15: 22:24 error: mismatched types: expected `uint` but found `core::option::Option<uint>` (expected uint but found enum core::option::Option)
+src/main.rs:22:15: 22:24 error: mismatched types: expected `u32` but found `core::option::Option<u32>` (expected u32 but found enum core::option::Option)
 src/main.rs:22     match cmp(input_num, secret_number) {
                              ^~~~~~~~~
 error: aborting due to previous error
 ```
 
-Oh yeah! Our `input_num` has the type `Option<uint>`, rather than `uint`. We
+Oh yeah! Our `input_num` has the type `Option<u32>`, rather than `u32`. We
 need to unwrap the Option. If you remember from before, `match` is a great way
 to do that. Try this code:
 
@@ -486,7 +486,7 @@ use std::cmp::Ordering;
 fn main() {
     println!("Guess the number!");
 
-    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+    let secret_number = (rand::random::<u32>() % 100) + 1;
 
     println!("The secret number is: {}", secret_number);
 
@@ -495,7 +495,7 @@ fn main() {
     let input = io::stdin().read_line()
                            .ok()
                            .expect("Failed to read line");
-    let input_num: Option<uint> = input.parse();
+    let input_num: Option<u32> = input.parse();
 
     let num = match input_num {
         Some(num) => num,
@@ -515,14 +515,14 @@ fn main() {
     }
 }
 
-fn cmp(a: uint, b: uint) -> Ordering {
+fn cmp(a: u32, b: u32) -> Ordering {
     if a < b { Ordering::Less }
     else if a > b { Ordering::Greater }
     else { Ordering::Equal }
 }
 ```
 
-We use a `match` to either give us the `uint` inside of the `Option`, or else
+We use a `match` to either give us the `u32` inside of the `Option`, or else
 print an error message and return. Let's give this a shot:
 
 ```bash
@@ -553,7 +553,7 @@ use std::cmp::Ordering;
 fn main() {
     println!("Guess the number!");
 
-    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+    let secret_number = (rand::random::<u32>() % 100) + 1;
 
     println!("The secret number is: {}", secret_number);
 
@@ -562,7 +562,7 @@ fn main() {
     let input = io::stdin().read_line()
                            .ok()
                            .expect("Failed to read line");
-    let input_num: Option<uint> = input.trim().parse();
+    let input_num: Option<u32> = input.trim().parse();
 
     let num = match input_num {
         Some(num) => num,
@@ -582,7 +582,7 @@ fn main() {
     }
 }
 
-fn cmp(a: uint, b: uint) -> Ordering {
+fn cmp(a: u32, b: u32) -> Ordering {
     if a < b { Ordering::Less }
     else if a > b { Ordering::Greater }
     else { Ordering::Equal }
@@ -627,7 +627,7 @@ use std::cmp::Ordering;
 fn main() {
     println!("Guess the number!");
 
-    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+    let secret_number = (rand::random::<u32>() % 100) + 1;
 
     println!("The secret number is: {}", secret_number);
 
@@ -638,7 +638,7 @@ fn main() {
         let input = io::stdin().read_line()
                                .ok()
                                .expect("Failed to read line");
-        let input_num: Option<uint> = input.trim().parse();
+        let input_num: Option<u32> = input.trim().parse();
 
         let num = match input_num {
             Some(num) => num,
@@ -659,7 +659,7 @@ fn main() {
     }
 }
 
-fn cmp(a: uint, b: uint) -> Ordering {
+fn cmp(a: u32, b: u32) -> Ordering {
     if a < b { Ordering::Less }
     else if a > b { Ordering::Greater }
     else { Ordering::Equal }
@@ -703,7 +703,7 @@ use std::cmp::Ordering;
 fn main() {
     println!("Guess the number!");
 
-    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+    let secret_number = (rand::random::<u32>() % 100) + 1;
 
     println!("The secret number is: {}", secret_number);
 
@@ -714,7 +714,7 @@ fn main() {
         let input = io::stdin().read_line()
                                .ok()
                                .expect("Failed to read line");
-        let input_num: Option<uint> = input.trim().parse();
+        let input_num: Option<u32> = input.trim().parse();
 
         let num = match input_num {
             Some(num) => num,
@@ -738,7 +738,7 @@ fn main() {
     }
 }
 
-fn cmp(a: uint, b: uint) -> Ordering {
+fn cmp(a: u32, b: u32) -> Ordering {
     if a < b { Ordering::Less }
     else if a > b { Ordering::Greater }
     else { Ordering::Equal }
@@ -759,7 +759,7 @@ use std::cmp::Ordering;
 fn main() {
     println!("Guess the number!");
 
-    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+    let secret_number = (rand::random::<u32>() % 100) + 1;
 
     println!("The secret number is: {}", secret_number);
 
@@ -770,7 +770,7 @@ fn main() {
         let input = io::stdin().read_line()
                                .ok()
                                .expect("Failed to read line");
-        let input_num: Option<uint> = input.trim().parse();
+        let input_num: Option<u32> = input.trim().parse();
 
         let num = match input_num {
             Some(num) => num,
@@ -794,7 +794,7 @@ fn main() {
     }
 }
 
-fn cmp(a: uint, b: uint) -> Ordering {
+fn cmp(a: u32, b: u32) -> Ordering {
     if a < b { Ordering::Less }
     else if a > b { Ordering::Greater }
     else { Ordering::Equal }
@@ -838,7 +838,7 @@ use std::cmp::Ordering;
 fn main() {
     println!("Guess the number!");
 
-    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+    let secret_number = (rand::random::<u32>() % 100) + 1;
 
     loop {
 
@@ -847,7 +847,7 @@ fn main() {
         let input = io::stdin().read_line()
                                .ok()
                                .expect("Failed to read line");
-        let input_num: Option<uint> = input.trim().parse();
+        let input_num: Option<u32> = input.trim().parse();
 
         let num = match input_num {
             Some(num) => num,
@@ -871,7 +871,7 @@ fn main() {
     }
 }
 
-fn cmp(a: uint, b: uint) -> Ordering {
+fn cmp(a: u32, b: u32) -> Ordering {
     if a < b { Ordering::Less }
     else if a > b { Ordering::Greater }
     else { Ordering::Equal }
index 3cb14df1210a9af07524bdbb1921441a5c055326..640f0109b0697d841c0bed2d53a89d0014c612ca 100644 (file)
@@ -71,8 +71,8 @@ These lines define a *function* in Rust. The `main` function is special:
 it's the beginning of every Rust program. The first line says "I'm declaring a
 function named `main`, which takes no arguments and returns nothing." If there
 were arguments, they would go inside the parentheses (`(` and `)`), and because
-we aren't returning anything from this function, we've dropped that notation
-entirely.  We'll get to it later.
+we aren't returning anything from this function, we can omit the return type
+entirely. We'll get to it later.
 
 You'll also note that the function is wrapped in curly braces (`{` and `}`).
 Rust requires these around all function bodies. It is also considered good
index c73fbefb2a4019352bfb7104ecfcc11c38049a92..8f4db3eee5ae7d0d281bc5c20c2efc572030405a 100644 (file)
@@ -42,7 +42,7 @@ the pattern in the above code:
 # let input_1 = T::SpecialA(0);
 # let input_2 = T::SpecialA(0);
 macro_rules! early_return {
-    ($inp:expr, $sp:path) => ( // invoke it like `(input_5 SpecialE)`
+    ($inp:expr, $sp:path) => ( // invoke it like `(input_5, SpecialE)`
         match $inp {
             $sp(x) => { return x; }
             _ => {}
@@ -59,7 +59,7 @@ early_return!(input_2, T::SpecialB);
 ~~~~
 
 Macros are defined in pattern-matching style: in the above example, the text
-`($inp:expr $sp:ident)` that appears on the left-hand side of the `=>` is the
+`($inp:expr, $sp:path)` that appears on the left-hand side of the `=>` is the
 *macro invocation syntax*, a pattern denoting how to write a call to the
 macro. The text on the right-hand side of the `=>`, beginning with `match
 $inp`, is the *macro transcription syntax*: what the macro expands to.
@@ -74,6 +74,8 @@ conforms to the following rules:
 2. `$` has special meaning (described below).
 3. The `()`s, `[]`s, and `{}`s it contains must balance. For example, `([)` is
 forbidden.
+4. Some arguments can be followed only by a limited set of separators, to
+avoid ambiguity (described below).
 
 Otherwise, the invocation syntax is free-form.
 
@@ -86,7 +88,8 @@ To take a fragment of Rust code as an argument, write `$` followed by a name
   `foo`.)
 * `expr` (an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`;
   `f(42)`.)
-* `ty` (a type. Examples: `int`, `Vec<(char, String)>`, `&T`.)
+* `ty` (a type. Examples: `i32`, `Vec<(char, String)>`, `&T`.)
+* `path` (a path to struct or enum variant. Example: `T::SpecialA`)
 * `pat` (a pattern, usually appearing in a `match` or on the left-hand side of
   a declaration. Examples: `Some(t)`; `(17, 'a')`; `_`.)
 * `block` (a sequence of actions. Example: `{ log(error, "hi"); return 12; }`)
@@ -97,6 +100,12 @@ rules of tokenization apply,
 So `($x:ident -> (($e:expr)))`, though excessively fancy, would designate a macro
 that could be invoked like: `my_macro!(i->(( 2+2 )))`.
 
+To avoid ambiguity, macro invocation syntax must conform to the following rules:
+* `expr` must be followed by `=>`, `,` or `;`.
+* `ty` and `path` must be followed by `=>`, `,`, `:`, `=`, `>` or `as`.
+* `pat` must be followed by `=>`, `,` or `=`.
+* `ident` and `block` can be followed by any token.
+
 ## Invocation location
 
 A macro invocation may take the place of (and therefore expand to) an
@@ -571,7 +580,7 @@ intermediate states out, and passing the flag `--pretty expanded` as a
 command-line argument to the compiler will show the result of expansion.
 
 If Rust's macro system can't do what you need, you may want to write a
-[compiler plugin](plugin.html) instead. Compared to `macro_rules!`
+[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
 macros, this is significantly more work, the interfaces are much less stable,
 and the warnings about debugging apply ten-fold. In exchange you get the
 flexibility of running arbitrary Rust code within the compiler. Syntax
index 8e5a757e1bda7e34dd6b4026bceca9a7b7a91ab5..7a397ce535470bf1ff2039fe896648368ff10e50 100644 (file)
@@ -81,7 +81,6 @@ therefore deallocates the memory for you. Here's the equivalent example in
 Rust:
 
 ```rust
-# use std::boxed::Box;
 {
     let x = Box::new(5);
 }
@@ -101,7 +100,6 @@ This is pretty straightforward, but what happens when we want to pass our box
 to a function? Let's look at some code:
 
 ```rust
-# use std::boxed::Box;
 fn main() {
     let x = Box::new(5);
 
@@ -117,7 +115,6 @@ This code works, but it's not ideal. For example, let's add one more line of
 code, where we print out the value of `x`:
 
 ```{rust,ignore}
-# use std::boxed::Box;
 fn main() {
     let x = Box::new(5);
 
@@ -151,7 +148,6 @@ To fix this, we can have `add_one` give ownership back when it's done with the
 box:
 
 ```rust
-# use std::boxed::Box;
 fn main() {
     let x = Box::new(5);
 
@@ -207,6 +203,26 @@ fn add_one(num: &mut i32) {
 This function borrows an `i32` from its caller, and then increments it. When
 the function is over, and `num` goes out of scope, the borrow is over.
 
+We have to change our `main` a bit too:
+
+```rust
+fn main() {
+    let mut x = 5;
+
+    add_one(&mut x);
+
+    println!("{}", x);
+}
+
+fn add_one(num: &mut i32) {
+    *num += 1;
+}
+```
+
+We don't need to assign the result of `add_one()` anymore, because it doesn't
+return anything anymore. This is because we're not passing ownership back,
+since we just borrow, not take ownership.
+
 # Lifetimes
 
 Lending out a reference to a resource that someone else owns can be
@@ -225,7 +241,7 @@ To fix this, we have to make sure that step four never happens after step
 three. The ownership system in Rust does this through a concept called
 *lifetimes*, which describe the scope that a reference is valid for.
 
-Let's look at that function which borrows an `i32` again:
+Remember the function that borrowed an `i32`? Let's look at it again.
 
 ```rust
 fn add_one(num: &i32) -> i32 {
@@ -310,7 +326,7 @@ valid for. For example:
 
 ```rust
 fn main() {
-    let y = &5;    // -+ y goes into scope
+    let y = &5;     // -+ y goes into scope
                     //  |
     // stuff        //  |
                     //  |
@@ -325,7 +341,7 @@ struct Foo<'a> {
 }
 
 fn main() {
-    let y = &5;          // -+ y goes into scope
+    let y = &5;           // -+ y goes into scope
     let f = Foo { x: y }; // -+ f goes into scope
     // stuff              //  |
                           //  |
@@ -344,7 +360,7 @@ fn main() {
     let x;                    // -+ x goes into scope
                               //  |
     {                         //  |
-        let y = &5;          // ---+ y goes into scope
+        let y = &5;           // ---+ y goes into scope
         let f = Foo { x: y }; // ---+ f goes into scope
         x = &f.x;             //  | | error here
     }                         // ---+ f and y go out of scope
index 2fc361ca1b2841eaae1809c65d7aec3392ba9e49..4cd39d407a243b184c80fa590cbf0dba2a84ef78 100644 (file)
@@ -126,7 +126,7 @@ The advantages over a simple `fn(&str) -> uint` are:
   a way to define new literal syntax for any data type.
 
 In addition to procedural macros, you can define new
-[`deriving`](../reference.html#deriving)-like attributes and other kinds of
+[`derive`](../reference.html#derive)-like attributes and other kinds of
 extensions.  See
 [`Registry::register_syntax_extension`](../rustc/plugin/registry/struct.Registry.html#method.register_syntax_extension)
 and the [`SyntaxExtension`
index 63c16ef191e06787cda71640225ed97c20bc4336..6832d75245e5cc9ebf51ba6434af0ce52cd94c79 100644 (file)
@@ -455,7 +455,6 @@ fn rc_succ(x: Rc<int>) -> int { *x + 1 }
 Note that the caller of your function will have to modify their calls slightly:
 
 ```{rust}
-# use std::boxed::Box;
 use std::rc::Rc;
 
 fn succ(x: &int) -> int { *x + 1 }
@@ -478,7 +477,6 @@ those contents.
 heap allocation in Rust. Creating a box looks like this:
 
 ```{rust}
-# use std::boxed::Box;
 let x = Box::new(5i);
 ```
 
@@ -486,7 +484,6 @@ Boxes are heap allocated and they are deallocated automatically by Rust when
 they go out of scope:
 
 ```{rust}
-# use std::boxed::Box;
 {
     let x = Box::new(5i);
 
@@ -507,7 +504,6 @@ You don't need to fully grok the theory of affine types or regions to grok
 boxes, though. As a rough approximation, you can treat this Rust code:
 
 ```{rust}
-# use std::boxed::Box;
 {
     let x = Box::new(5i);
 
@@ -548,7 +544,6 @@ for more detail on how lifetimes work.
 Using boxes and references together is very common. For example:
 
 ```{rust}
-# use std::boxed::Box;
 fn add_one(x: &int) -> int {
     *x + 1
 }
@@ -566,7 +561,6 @@ function, and since it's only reading the value, allows it.
 We can borrow `x` multiple times, as long as it's not simultaneous:
 
 ```{rust}
-# use std::boxed::Box;
 fn add_one(x: &int) -> int {
     *x + 1
 }
@@ -583,7 +577,6 @@ fn main() {
 Or as long as it's not a mutable borrow. This will error:
 
 ```{rust,ignore}
-# use std::boxed::Box;
 fn add_one(x: &mut int) -> int {
     *x + 1
 }
@@ -610,7 +603,6 @@ Sometimes, you need a recursive data structure. The simplest is known as a
 
 
 ```{rust}
-# use std::boxed::Box;
 #[derive(Show)]
 enum List<T> {
     Cons(T, Box<List<T>>),
@@ -666,7 +658,6 @@ In many languages with pointers, you'd return a pointer from a function
 so as to avoid copying a large data structure. For example:
 
 ```{rust}
-# use std::boxed::Box;
 struct BigStruct {
     one: int,
     two: int,
@@ -695,7 +686,6 @@ than the hundred `int`s that make up the `BigStruct`.
 This is an antipattern in Rust. Instead, write this:
 
 ```{rust}
-# use std::boxed::Box;
 struct BigStruct {
     one: int,
     two: int,
@@ -721,11 +711,10 @@ fn main() {
 This gives you flexibility without sacrificing performance.
 
 You may think that this gives us terrible performance: return a value and then
-immediately box it up ?! Isn't that the worst of both worlds? Rust is smarter
-than that. There is no copy in this code. `main` allocates enough room for the
-`box`, passes a pointer to that memory into `foo` as `x`, and then `foo` writes
-the value straight into that pointer. This writes the return value directly into
-the allocated box.
+immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is
+smarter than that. There is no copy in this code. `main` allocates enough room
+for the `box`, passes a pointer to that memory into `foo` as `x`, and then
+`foo` writes the value straight into the `Box<T>`.
 
 This is important enough that it bears repeating: pointers are not for
 optimizing returning values from your code. Allow the caller to choose how they
diff --git a/src/doc/trpl/tasks.md b/src/doc/trpl/tasks.md
deleted file mode 100644 (file)
index 4c6a7f1..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-% The Rust Threads and Communication Guide
-
-**NOTE** This guide is badly out of date and needs to be rewritten.
-
-# Introduction
-
-Rust provides safe concurrent abstractions through a number of core library
-primitives. This guide will describe the concurrency model in Rust, how it
-relates to the Rust type system, and introduce the fundamental library
-abstractions for constructing concurrent programs.
-
-Threads provide failure isolation and recovery. When a fatal error occurs in Rust
-code as a result of an explicit call to `panic!()`, an assertion failure, or
-another invalid operation, the runtime system destroys the entire thread. Unlike
-in languages such as Java and C++, there is no way to `catch` an exception.
-Instead, threads may monitor each other to see if they panic.
-
-Threads use Rust's type system to provide strong memory safety guarantees.  In
-particular, the type system guarantees that threads cannot induce a data race
-from shared mutable state.
-
-# Basics
-
-At its simplest, creating a thread is a matter of calling the `spawn` function
-with a closure argument. `spawn` executes the closure in the new thread.
-
-```{rust,ignore}
-# use std::thread::spawn;
-
-// Print something profound in a different thread using a named function
-fn print_message() { println!("I am running in a different thread!"); }
-spawn(print_message);
-
-// Alternatively, use a `move ||` expression instead of a named function.
-// `||` expressions evaluate to an unnamed closure. The `move` keyword
-// indicates that the closure should take ownership of any variables it
-// touches.
-spawn(move || println!("I am also running in a different thread!"));
-```
-
-In Rust, a thread is not a concept that appears in the language semantics.
-Instead, Rust's type system provides all the tools necessary to implement safe
-concurrency: particularly, ownership. The language leaves the implementation
-details to the standard library.
-
-The `spawn` function has the type signature: `fn
-spawn<F:FnOnce()+Send>(f: F)`.  This indicates that it takes as
-argument a closure (of type `F`) that it will run exactly once. This
-closure is limited to capturing `Send`-able data from its environment
-(that is, data which is deeply owned). Limiting the closure to `Send`
-ensures that `spawn` can safely move the entire closure and all its
-associated state into an entirely different thread for execution.
-
-```{rust,ignore}
-# use std::thread::spawn;
-# fn generate_thread_number() -> int { 0 }
-// Generate some state locally
-let child_thread_number = generate_thread_number();
-
-spawn(move || {
-    // Capture it in the remote thread. The `move` keyword indicates
-    // that this closure should move `child_thread_number` into its
-    // environment, rather than capturing a reference into the
-    // enclosing stack frame.
-    println!("I am child number {}", child_thread_number);
-});
-```
-
-## Communication
-
-Now that we have spawned a new thread, it would be nice if we could communicate
-with it. For this, we use *channels*. A channel is simply a pair of endpoints:
-one for sending messages and another for receiving messages.
-
-The simplest way to create a channel is to use the `channel` function to create a
-`(Sender, Receiver)` pair. In Rust parlance, a *sender* is a sending endpoint
-of a channel, and a *receiver* is the receiving endpoint. Consider the following
-example of calculating two results concurrently:
-
-```{rust,ignore}
-# use std::thread::spawn;
-
-let (tx, rx): (Sender<int>, Receiver<int>) = channel();
-
-spawn(move || {
-    let result = some_expensive_computation();
-    tx.send(result);
-});
-
-some_other_expensive_computation();
-let result = rx.recv();
-# fn some_expensive_computation() -> int { 42 }
-# fn some_other_expensive_computation() {}
-```
-
-Let's examine this example in detail. First, the `let` statement creates a
-stream for sending and receiving integers (the left-hand side of the `let`,
-`(tx, rx)`, is an example of a destructuring let: the pattern separates a tuple
-into its component parts).
-
-```{rust,ignore}
-let (tx, rx): (Sender<int>, Receiver<int>) = channel();
-```
-
-The child thread will use the sender to send data to the parent thread, which will
-wait to receive the data on the receiver. The next statement spawns the child
-thread.
-
-```{rust,ignore}
-# use std::thread::spawn;
-# fn some_expensive_computation() -> int { 42 }
-# let (tx, rx) = channel();
-spawn(move || {
-    let result = some_expensive_computation();
-    tx.send(result);
-});
-```
-
-Notice that the creation of the thread closure transfers `tx` to the child thread
-implicitly: the closure captures `tx` in its environment. Both `Sender` and
-`Receiver` are sendable types and may be captured into threads or otherwise
-transferred between them. In the example, the child thread runs an expensive
-computation, then sends the result over the captured channel.
-
-Finally, the parent continues with some other expensive computation, then waits
-for the child's result to arrive on the receiver:
-
-```{rust,ignore}
-# fn some_other_expensive_computation() {}
-# let (tx, rx) = channel::<int>();
-# tx.send(0);
-some_other_expensive_computation();
-let result = rx.recv();
-```
-
-The `Sender` and `Receiver` pair created by `channel` enables efficient
-communication between a single sender and a single receiver, but multiple
-senders cannot use a single `Sender` value, and multiple receivers cannot use a
-single `Receiver` value.  What if our example needed to compute multiple
-results across a number of threads? The following program is ill-typed:
-
-```{rust,ignore}
-# fn some_expensive_computation() -> int { 42 }
-let (tx, rx) = channel();
-
-spawn(move || {
-    tx.send(some_expensive_computation());
-});
-
-// ERROR! The previous spawn statement already owns the sender,
-// so the compiler will not allow it to be captured again
-spawn(move || {
-    tx.send(some_expensive_computation());
-});
-```
-
-Instead we can clone the `tx`, which allows for multiple senders.
-
-```{rust,ignore}
-let (tx, rx) = channel();
-
-for init_val in range(0u, 3) {
-    // Create a new channel handle to distribute to the child thread
-    let child_tx = tx.clone();
-    spawn(move || {
-        child_tx.send(some_expensive_computation(init_val));
-    });
-}
-
-let result = rx.recv() + rx.recv() + rx.recv();
-# fn some_expensive_computation(_i: uint) -> int { 42 }
-```
-
-Cloning a `Sender` produces a new handle to the same channel, allowing multiple
-threads to send data to a single receiver. It upgrades the channel internally in
-order to allow this functionality, which means that channels that are not
-cloned can avoid the overhead required to handle multiple senders. But this
-fact has no bearing on the channel's usage: the upgrade is transparent.
-
-Note that the above cloning example is somewhat contrived since you could also
-simply use three `Sender` pairs, but it serves to illustrate the point. For
-reference, written with multiple streams, it might look like the example below.
-
-```{rust,ignore}
-# use std::thread::spawn;
-
-// Create a vector of ports, one for each child thread
-let rxs = Vec::from_fn(3, |init_val| {
-    let (tx, rx) = channel();
-    spawn(move || {
-        tx.send(some_expensive_computation(init_val));
-    });
-    rx
-});
-
-// Wait on each port, accumulating the results
-let result = rxs.iter().fold(0, |accum, rx| accum + rx.recv() );
-# fn some_expensive_computation(_i: uint) -> int { 42 }
-```
-
-## Backgrounding computations: Futures
-
-With `sync::Future`, rust has a mechanism for requesting a computation and
-getting the result later.
-
-The basic example below illustrates this.
-
-```{rust,ignore}
-# #![allow(deprecated)]
-use std::sync::Future;
-
-# fn main() {
-# fn make_a_sandwich() {};
-fn fib(n: u64) -> u64 {
-    // lengthy computation returning an uint
-    12586269025
-}
-
-let mut delayed_fib = Future::spawn(move || fib(50));
-make_a_sandwich();
-println!("fib(50) = {}", delayed_fib.get())
-# }
-```
-
-The call to `future::spawn` immediately returns a `future` object regardless of
-how long it takes to run `fib(50)`. You can then make yourself a sandwich while
-the computation of `fib` is running. The result of the execution of the method
-is obtained by calling `get` on the future. This call will block until the
-value is available (*i.e.* the computation is complete). Note that the future
-needs to be mutable so that it can save the result for next time `get` is
-called.
-
-Here is another example showing how futures allow you to background
-computations. The workload will be distributed on the available cores.
-
-```{rust,ignore}
-# #![allow(deprecated)]
-# use std::num::Float;
-# use std::sync::Future;
-fn partial_sum(start: uint) -> f64 {
-    let mut local_sum = 0f64;
-    for num in range(start*100000, (start+1)*100000) {
-        local_sum += (num as f64 + 1.0).powf(-2.0);
-    }
-    local_sum
-}
-
-fn main() {
-    let mut futures = Vec::from_fn(200, |ind| Future::spawn(move || partial_sum(ind)));
-
-    let mut final_res = 0f64;
-    for ft in futures.iter_mut()  {
-        final_res += ft.get();
-    }
-    println!("π^2/6 is not far from : {}", final_res);
-}
-```
-
-## Sharing without copying: Arc
-
-To share data between threads, a first approach would be to only use channel as
-we have seen previously. A copy of the data to share would then be made for
-each thread. In some cases, this would add up to a significant amount of wasted
-memory and would require copying the same data more than necessary.
-
-To tackle this issue, one can use an Atomically Reference Counted wrapper
-(`Arc`) as implemented in the `sync` library of Rust. With an Arc, the data
-will no longer be copied for each thread. The Arc acts as a reference to the
-shared data and only this reference is shared and cloned.
-
-Here is a small example showing how to use Arcs. We wish to run concurrently
-several computations on a single large vector of floats. Each thread needs the
-full vector to perform its duty.
-
-```{rust,ignore}
-use std::num::Float;
-use std::rand;
-use std::sync::Arc;
-
-fn pnorm(nums: &[f64], p: uint) -> f64 {
-    nums.iter().fold(0.0, |a, b| a + b.powf(p as f64)).powf(1.0 / (p as f64))
-}
-
-fn main() {
-    let numbers = Vec::from_fn(1000000, |_| rand::random::<f64>());
-    let numbers_arc = Arc::new(numbers);
-
-    for num in range(1u, 10) {
-        let thread_numbers = numbers_arc.clone();
-
-        spawn(move || {
-            println!("{}-norm = {}", num, pnorm(thread_numbers.as_slice(), num));
-        });
-    }
-}
-```
-
-The function `pnorm` performs a simple computation on the vector (it computes
-the sum of its items at the power given as argument and takes the inverse power
-of this value). The Arc on the vector is created by the line:
-
-```{rust,ignore}
-# use std::rand;
-# use std::sync::Arc;
-# fn main() {
-# let numbers = Vec::from_fn(1000000, |_| rand::random::<f64>());
-let numbers_arc = Arc::new(numbers);
-# }
-```
-
-and a clone is captured for each thread via a procedure. This only copies
-the wrapper and not its contents. Within the thread's procedure, the captured
-Arc reference can be used as a shared reference to the underlying vector as
-if it were local.
-
-```{rust,ignore}
-# use std::rand;
-# use std::sync::Arc;
-# fn pnorm(nums: &[f64], p: uint) -> f64 { 4.0 }
-# fn main() {
-# let numbers=Vec::from_fn(1000000, |_| rand::random::<f64>());
-# let numbers_arc = Arc::new(numbers);
-# let num = 4;
-let thread_numbers = numbers_arc.clone();
-spawn(move || {
-    // Capture thread_numbers and use it as if it was the underlying vector
-    println!("{}-norm = {}", num, pnorm(thread_numbers.as_slice(), num));
-});
-# }
-```
-
-# Handling thread panics
-
-Rust has a built-in mechanism for raising exceptions. The `panic!()` macro
-(which can also be written with an error string as an argument: `panic!(
-~reason)`) and the `assert!` construct (which effectively calls `panic!()` if a
-boolean expression is false) are both ways to raise exceptions. When a thread
-raises an exception, the thread unwinds its stack—running destructors and
-freeing memory along the way—and then exits. Unlike exceptions in C++,
-exceptions in Rust are unrecoverable within a single thread: once a thread panics,
-there is no way to "catch" the exception.
-
-While it isn't possible for a thread to recover from panicking, threads may notify
-each other if they panic. The simplest way of handling a panic is with the
-`try` function, which is similar to `spawn`, but immediately blocks and waits
-for the child thread to finish. `try` returns a value of type
-`Result<T, Box<Any + Send>>`. `Result` is an `enum` type with two variants:
-`Ok` and `Err`. In this case, because the type arguments to `Result` are `int`
-and `()`, callers can pattern-match on a result to check whether it's an `Ok`
-result with an `int` field (representing a successful result) or an `Err` result
-(representing termination with an error).
-
-```{rust,ignore}
-# use std::thread::Thread;
-# fn some_condition() -> bool { false }
-# fn calculate_result() -> int { 0 }
-let result: Result<int, Box<std::any::Any + Send>> = Thread::spawn(move || {
-    if some_condition() {
-        calculate_result()
-    } else {
-        panic!("oops!");
-    }
-}).join();
-assert!(result.is_err());
-```
-
-Unlike `spawn`, the function spawned using `try` may return a value, which
-`try` will dutifully propagate back to the caller in a [`Result`] enum. If the
-child thread terminates successfully, `try` will return an `Ok` result; if the
-child thread panics, `try` will return an `Error` result.
-
-[`Result`]: ../std/result/index.html
-
-> *Note:* A panicked thread does not currently produce a useful error
-> value (`try` always returns `Err(())`). In the
-> future, it may be possible for threads to intercept the value passed to
-> `panic!()`.
-
-But not all panics are created equal. In some cases you might need to abort
-the entire program (perhaps you're writing an assert which, if it trips,
-indicates an unrecoverable logic error); in other cases you might want to
-contain the panic at a certain boundary (perhaps a small piece of input from
-the outside world, which you happen to be processing in parallel, is malformed
-such that the processing thread cannot proceed).
index 66da6395a5e09ae3b040a28b1dc5a8bc3ae64324..aefc7d7aa3d3ce09622e8ed9e40ac69adfa1126e 100644 (file)
@@ -96,7 +96,7 @@ test it_works ... FAILED
 failures:
 
 ---- it_works stdout ----
-        task 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3
+        thread 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3
 
 
 
@@ -105,7 +105,7 @@ failures:
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
 
-task '<main>' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247
+thread '<main>' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247
 ```
 
 Rust indicates that our test failed:
@@ -254,7 +254,6 @@ a large module, and so this is a common use of the `glob` feature. Let's change
 our `src/lib.rs` to make use of it:
 
 ```{rust,ignore}
-#![feature(globs)]
 
 pub fn add_two(a: i32) -> i32 {
     a + 2
@@ -271,8 +270,7 @@ mod tests {
 }
 ```
 
-Note the `feature` attribute, as well as the different `use` line. Now we run
-our tests:
+Note the different `use` line. Now we run our tests:
 
 ```bash
 $ cargo test
@@ -370,8 +368,6 @@ with examples:
 //! assert_eq!(4, adder::add_two(2));
 //! ```
 
-#![feature(globs)]
-
 /// This function adds two to its argument.
 ///
 /// # Examples
@@ -440,8 +436,6 @@ Rust also supports benchmark tests, which can test the performance of your
 code. Let's make our `src/lib.rs` look like this (comments elided):
 
 ```{rust,ignore}
-#![feature(globs)]
-
 extern crate test;
 
 pub fn add_two(a: i32) -> i32 {
diff --git a/src/doc/trpl/threads.md b/src/doc/trpl/threads.md
new file mode 100644 (file)
index 0000000..4c6a7f1
--- /dev/null
@@ -0,0 +1,384 @@
+% The Rust Threads and Communication Guide
+
+**NOTE** This guide is badly out of date and needs to be rewritten.
+
+# Introduction
+
+Rust provides safe concurrent abstractions through a number of core library
+primitives. This guide will describe the concurrency model in Rust, how it
+relates to the Rust type system, and introduce the fundamental library
+abstractions for constructing concurrent programs.
+
+Threads provide failure isolation and recovery. When a fatal error occurs in Rust
+code as a result of an explicit call to `panic!()`, an assertion failure, or
+another invalid operation, the runtime system destroys the entire thread. Unlike
+in languages such as Java and C++, there is no way to `catch` an exception.
+Instead, threads may monitor each other to see if they panic.
+
+Threads use Rust's type system to provide strong memory safety guarantees.  In
+particular, the type system guarantees that threads cannot induce a data race
+from shared mutable state.
+
+# Basics
+
+At its simplest, creating a thread is a matter of calling the `spawn` function
+with a closure argument. `spawn` executes the closure in the new thread.
+
+```{rust,ignore}
+# use std::thread::spawn;
+
+// Print something profound in a different thread using a named function
+fn print_message() { println!("I am running in a different thread!"); }
+spawn(print_message);
+
+// Alternatively, use a `move ||` expression instead of a named function.
+// `||` expressions evaluate to an unnamed closure. The `move` keyword
+// indicates that the closure should take ownership of any variables it
+// touches.
+spawn(move || println!("I am also running in a different thread!"));
+```
+
+In Rust, a thread is not a concept that appears in the language semantics.
+Instead, Rust's type system provides all the tools necessary to implement safe
+concurrency: particularly, ownership. The language leaves the implementation
+details to the standard library.
+
+The `spawn` function has the type signature: `fn
+spawn<F:FnOnce()+Send>(f: F)`.  This indicates that it takes as
+argument a closure (of type `F`) that it will run exactly once. This
+closure is limited to capturing `Send`-able data from its environment
+(that is, data which is deeply owned). Limiting the closure to `Send`
+ensures that `spawn` can safely move the entire closure and all its
+associated state into an entirely different thread for execution.
+
+```{rust,ignore}
+# use std::thread::spawn;
+# fn generate_thread_number() -> int { 0 }
+// Generate some state locally
+let child_thread_number = generate_thread_number();
+
+spawn(move || {
+    // Capture it in the remote thread. The `move` keyword indicates
+    // that this closure should move `child_thread_number` into its
+    // environment, rather than capturing a reference into the
+    // enclosing stack frame.
+    println!("I am child number {}", child_thread_number);
+});
+```
+
+## Communication
+
+Now that we have spawned a new thread, it would be nice if we could communicate
+with it. For this, we use *channels*. A channel is simply a pair of endpoints:
+one for sending messages and another for receiving messages.
+
+The simplest way to create a channel is to use the `channel` function to create a
+`(Sender, Receiver)` pair. In Rust parlance, a *sender* is a sending endpoint
+of a channel, and a *receiver* is the receiving endpoint. Consider the following
+example of calculating two results concurrently:
+
+```{rust,ignore}
+# use std::thread::spawn;
+
+let (tx, rx): (Sender<int>, Receiver<int>) = channel();
+
+spawn(move || {
+    let result = some_expensive_computation();
+    tx.send(result);
+});
+
+some_other_expensive_computation();
+let result = rx.recv();
+# fn some_expensive_computation() -> int { 42 }
+# fn some_other_expensive_computation() {}
+```
+
+Let's examine this example in detail. First, the `let` statement creates a
+stream for sending and receiving integers (the left-hand side of the `let`,
+`(tx, rx)`, is an example of a destructuring let: the pattern separates a tuple
+into its component parts).
+
+```{rust,ignore}
+let (tx, rx): (Sender<int>, Receiver<int>) = channel();
+```
+
+The child thread will use the sender to send data to the parent thread, which will
+wait to receive the data on the receiver. The next statement spawns the child
+thread.
+
+```{rust,ignore}
+# use std::thread::spawn;
+# fn some_expensive_computation() -> int { 42 }
+# let (tx, rx) = channel();
+spawn(move || {
+    let result = some_expensive_computation();
+    tx.send(result);
+});
+```
+
+Notice that the creation of the thread closure transfers `tx` to the child thread
+implicitly: the closure captures `tx` in its environment. Both `Sender` and
+`Receiver` are sendable types and may be captured into threads or otherwise
+transferred between them. In the example, the child thread runs an expensive
+computation, then sends the result over the captured channel.
+
+Finally, the parent continues with some other expensive computation, then waits
+for the child's result to arrive on the receiver:
+
+```{rust,ignore}
+# fn some_other_expensive_computation() {}
+# let (tx, rx) = channel::<int>();
+# tx.send(0);
+some_other_expensive_computation();
+let result = rx.recv();
+```
+
+The `Sender` and `Receiver` pair created by `channel` enables efficient
+communication between a single sender and a single receiver, but multiple
+senders cannot use a single `Sender` value, and multiple receivers cannot use a
+single `Receiver` value.  What if our example needed to compute multiple
+results across a number of threads? The following program is ill-typed:
+
+```{rust,ignore}
+# fn some_expensive_computation() -> int { 42 }
+let (tx, rx) = channel();
+
+spawn(move || {
+    tx.send(some_expensive_computation());
+});
+
+// ERROR! The previous spawn statement already owns the sender,
+// so the compiler will not allow it to be captured again
+spawn(move || {
+    tx.send(some_expensive_computation());
+});
+```
+
+Instead we can clone the `tx`, which allows for multiple senders.
+
+```{rust,ignore}
+let (tx, rx) = channel();
+
+for init_val in range(0u, 3) {
+    // Create a new channel handle to distribute to the child thread
+    let child_tx = tx.clone();
+    spawn(move || {
+        child_tx.send(some_expensive_computation(init_val));
+    });
+}
+
+let result = rx.recv() + rx.recv() + rx.recv();
+# fn some_expensive_computation(_i: uint) -> int { 42 }
+```
+
+Cloning a `Sender` produces a new handle to the same channel, allowing multiple
+threads to send data to a single receiver. It upgrades the channel internally in
+order to allow this functionality, which means that channels that are not
+cloned can avoid the overhead required to handle multiple senders. But this
+fact has no bearing on the channel's usage: the upgrade is transparent.
+
+Note that the above cloning example is somewhat contrived since you could also
+simply use three `Sender` pairs, but it serves to illustrate the point. For
+reference, written with multiple streams, it might look like the example below.
+
+```{rust,ignore}
+# use std::thread::spawn;
+
+// Create a vector of ports, one for each child thread
+let rxs = Vec::from_fn(3, |init_val| {
+    let (tx, rx) = channel();
+    spawn(move || {
+        tx.send(some_expensive_computation(init_val));
+    });
+    rx
+});
+
+// Wait on each port, accumulating the results
+let result = rxs.iter().fold(0, |accum, rx| accum + rx.recv() );
+# fn some_expensive_computation(_i: uint) -> int { 42 }
+```
+
+## Backgrounding computations: Futures
+
+With `sync::Future`, rust has a mechanism for requesting a computation and
+getting the result later.
+
+The basic example below illustrates this.
+
+```{rust,ignore}
+# #![allow(deprecated)]
+use std::sync::Future;
+
+# fn main() {
+# fn make_a_sandwich() {};
+fn fib(n: u64) -> u64 {
+    // lengthy computation returning an uint
+    12586269025
+}
+
+let mut delayed_fib = Future::spawn(move || fib(50));
+make_a_sandwich();
+println!("fib(50) = {}", delayed_fib.get())
+# }
+```
+
+The call to `future::spawn` immediately returns a `future` object regardless of
+how long it takes to run `fib(50)`. You can then make yourself a sandwich while
+the computation of `fib` is running. The result of the execution of the method
+is obtained by calling `get` on the future. This call will block until the
+value is available (*i.e.* the computation is complete). Note that the future
+needs to be mutable so that it can save the result for next time `get` is
+called.
+
+Here is another example showing how futures allow you to background
+computations. The workload will be distributed on the available cores.
+
+```{rust,ignore}
+# #![allow(deprecated)]
+# use std::num::Float;
+# use std::sync::Future;
+fn partial_sum(start: uint) -> f64 {
+    let mut local_sum = 0f64;
+    for num in range(start*100000, (start+1)*100000) {
+        local_sum += (num as f64 + 1.0).powf(-2.0);
+    }
+    local_sum
+}
+
+fn main() {
+    let mut futures = Vec::from_fn(200, |ind| Future::spawn(move || partial_sum(ind)));
+
+    let mut final_res = 0f64;
+    for ft in futures.iter_mut()  {
+        final_res += ft.get();
+    }
+    println!("π^2/6 is not far from : {}", final_res);
+}
+```
+
+## Sharing without copying: Arc
+
+To share data between threads, a first approach would be to only use channel as
+we have seen previously. A copy of the data to share would then be made for
+each thread. In some cases, this would add up to a significant amount of wasted
+memory and would require copying the same data more than necessary.
+
+To tackle this issue, one can use an Atomically Reference Counted wrapper
+(`Arc`) as implemented in the `sync` library of Rust. With an Arc, the data
+will no longer be copied for each thread. The Arc acts as a reference to the
+shared data and only this reference is shared and cloned.
+
+Here is a small example showing how to use Arcs. We wish to run concurrently
+several computations on a single large vector of floats. Each thread needs the
+full vector to perform its duty.
+
+```{rust,ignore}
+use std::num::Float;
+use std::rand;
+use std::sync::Arc;
+
+fn pnorm(nums: &[f64], p: uint) -> f64 {
+    nums.iter().fold(0.0, |a, b| a + b.powf(p as f64)).powf(1.0 / (p as f64))
+}
+
+fn main() {
+    let numbers = Vec::from_fn(1000000, |_| rand::random::<f64>());
+    let numbers_arc = Arc::new(numbers);
+
+    for num in range(1u, 10) {
+        let thread_numbers = numbers_arc.clone();
+
+        spawn(move || {
+            println!("{}-norm = {}", num, pnorm(thread_numbers.as_slice(), num));
+        });
+    }
+}
+```
+
+The function `pnorm` performs a simple computation on the vector (it computes
+the sum of its items at the power given as argument and takes the inverse power
+of this value). The Arc on the vector is created by the line:
+
+```{rust,ignore}
+# use std::rand;
+# use std::sync::Arc;
+# fn main() {
+# let numbers = Vec::from_fn(1000000, |_| rand::random::<f64>());
+let numbers_arc = Arc::new(numbers);
+# }
+```
+
+and a clone is captured for each thread via a procedure. This only copies
+the wrapper and not its contents. Within the thread's procedure, the captured
+Arc reference can be used as a shared reference to the underlying vector as
+if it were local.
+
+```{rust,ignore}
+# use std::rand;
+# use std::sync::Arc;
+# fn pnorm(nums: &[f64], p: uint) -> f64 { 4.0 }
+# fn main() {
+# let numbers=Vec::from_fn(1000000, |_| rand::random::<f64>());
+# let numbers_arc = Arc::new(numbers);
+# let num = 4;
+let thread_numbers = numbers_arc.clone();
+spawn(move || {
+    // Capture thread_numbers and use it as if it was the underlying vector
+    println!("{}-norm = {}", num, pnorm(thread_numbers.as_slice(), num));
+});
+# }
+```
+
+# Handling thread panics
+
+Rust has a built-in mechanism for raising exceptions. The `panic!()` macro
+(which can also be written with an error string as an argument: `panic!(
+~reason)`) and the `assert!` construct (which effectively calls `panic!()` if a
+boolean expression is false) are both ways to raise exceptions. When a thread
+raises an exception, the thread unwinds its stack—running destructors and
+freeing memory along the way—and then exits. Unlike exceptions in C++,
+exceptions in Rust are unrecoverable within a single thread: once a thread panics,
+there is no way to "catch" the exception.
+
+While it isn't possible for a thread to recover from panicking, threads may notify
+each other if they panic. The simplest way of handling a panic is with the
+`try` function, which is similar to `spawn`, but immediately blocks and waits
+for the child thread to finish. `try` returns a value of type
+`Result<T, Box<Any + Send>>`. `Result` is an `enum` type with two variants:
+`Ok` and `Err`. In this case, because the type arguments to `Result` are `int`
+and `()`, callers can pattern-match on a result to check whether it's an `Ok`
+result with an `int` field (representing a successful result) or an `Err` result
+(representing termination with an error).
+
+```{rust,ignore}
+# use std::thread::Thread;
+# fn some_condition() -> bool { false }
+# fn calculate_result() -> int { 0 }
+let result: Result<int, Box<std::any::Any + Send>> = Thread::spawn(move || {
+    if some_condition() {
+        calculate_result()
+    } else {
+        panic!("oops!");
+    }
+}).join();
+assert!(result.is_err());
+```
+
+Unlike `spawn`, the function spawned using `try` may return a value, which
+`try` will dutifully propagate back to the caller in a [`Result`] enum. If the
+child thread terminates successfully, `try` will return an `Ok` result; if the
+child thread panics, `try` will return an `Error` result.
+
+[`Result`]: ../std/result/index.html
+
+> *Note:* A panicked thread does not currently produce a useful error
+> value (`try` always returns `Err(())`). In the
+> future, it may be possible for threads to intercept the value passed to
+> `panic!()`.
+
+But not all panics are created equal. In some cases you might need to abort
+the entire program (perhaps you're writing an assert which, if it trips,
+indicates an unrecoverable logic error); in other cases you might want to
+contain the panic at a certain boundary (perhaps a small piece of input from
+the outside world, which you happen to be processing in parallel, is malformed
+such that the processing thread cannot proceed).
index acbcb0b5dd9752bf9197ec386aa1ea846457df01..96322296407f366773c3f46944230b58c208a4cc 100644 (file)
@@ -315,3 +315,76 @@ The names don't actually change to this, it's just for illustration. But
 as you can see, there's no overhead of deciding which version to call here,
 hence *statically dispatched*. The downside is that we have two copies of
 the same function, so our binary is a little bit larger.
+
+## Our `inverse` Example
+
+Back in [Generics](generics.html), we were trying to write code like this:
+
+```{rust,ignore}
+fn inverse<T>(x: T) -> Result<T, String> {
+    if x == 0.0 { return Err("x cannot be zero!".to_string()); }
+
+    Ok(1.0 / x)
+}
+```
+
+If we try to compile it, we get this error:
+
+```text
+error: binary operation `==` cannot be applied to type `T`
+```
+
+This is because `T` is too generic: we don't know if a random `T` can be
+compared. For that, we can use trait bounds. It doesn't quite work, but try
+this:
+
+```{rust,ignore}
+fn inverse<T: PartialEq>(x: T) -> Result<T, String> {
+    if x == 0.0 { return Err("x cannot be zero!".to_string()); }
+
+    Ok(1.0 / x)
+}
+```
+
+You should get this error:
+
+```text
+error: mismatched types:
+ expected `T`,
+    found `_`
+(expected type parameter,
+    found floating-point variable)
+```
+
+So this won't work. While our `T` is `PartialEq`, we expected to have another `T`,
+but instead, we found a floating-point variable. We need a different bound. `Float`
+to the rescue:
+
+```
+use std::num::Float;
+
+fn inverse<T: Float>(x: T) -> Result<T, String> {
+    if x == Float::zero() { return Err("x cannot be zero!".to_string()) }
+
+    let one: T = Float::one();
+    Ok(one / x)
+}
+```
+
+We've had to replace our generic `0.0` and `1.0` with the appropriate methods
+from the `Float` trait. Both `f32` and `f64` implement `Float`, so our function
+works just fine:
+
+```
+# use std::num::Float;
+# fn inverse<T: Float>(x: T) -> Result<T, String> {
+#     if x == Float::zero() { return Err("x cannot be zero!".to_string()) }
+#     let one: T = Float::one();
+#     Ok(one / x)
+# }
+println!("the inverse of {} is {:?}", 2.0f32, inverse(2.0f32));
+println!("the inverse of {} is {:?}", 2.0f64, inverse(2.0f64));
+
+println!("the inverse of {} is {:?}", 0.0f32, inverse(0.0f32));
+println!("the inverse of {} is {:?}", 0.0f64, inverse(0.0f64));
+```
index 38427875a6230562663777cfcd690b6a481f6e0a..075340660df154611e042fcdf34abe51df93251d 100644 (file)
@@ -182,7 +182,7 @@ code:
 - implement the `Drop` for resource clean-up via a destructor, and use
   RAII (Resource Acquisition Is Initialization). This reduces the need
   for any manual memory management by users, and automatically ensures
-  that clean-up is always run, even when the task panics.
+  that clean-up is always run, even when the thread panics.
 - ensure that any data stored behind a raw pointer is destroyed at the
   appropriate time.
 
@@ -197,7 +197,6 @@ extern crate libc;
 use libc::{c_void, size_t, malloc, free};
 use std::mem;
 use std::ptr;
-# use std::boxed::Box;
 
 // Define a wrapper around the handle returned by the foreign code.
 // Unique<T> has the same semantics as Box<T>
@@ -499,7 +498,7 @@ library, but without it you must define your own.
 The first of these three functions, `stack_exhausted`, is invoked whenever stack
 overflow is detected.  This function has a number of restrictions about how it
 can be called and what it must do, but if the stack limit register is not being
-maintained then a task always has an "infinite stack" and this function
+maintained then a thread always has an "infinite stack" and this function
 shouldn't get triggered.
 
 The second of these three functions, `eh_personality`, is used by the
@@ -530,7 +529,6 @@ vectors provided from C, using idiomatic Rust practices.
 
 ```
 #![no_std]
-#![feature(globs)]
 #![feature(lang_items)]
 
 # extern crate libc;
index 59085c5cf5df3d8ae885f6511a434fc625966702..e57fc7a120653aa29507b477b04eabefd34c895b 100644 (file)
@@ -89,25 +89,7 @@ what you need, so it's not verboten.
 
 Let's get back to bindings. Rust variable bindings have one more aspect that
 differs from other languages: bindings are required to be initialized with a
-value before you're allowed to use them. If we try...
-
-```{ignore}
-let x;
-```
-
-...we'll get an error:
-
-```text
-src/main.rs:2:9: 2:10 error: unable to infer enough type information about `_`; type annotations required
-src/main.rs:2     let x;
-                      ^
-```
-
-Giving it a type will compile, though:
-
-```{rust}
-let x: i32;
-```
+value before you're allowed to use them.
 
 Let's try it out. Change your `src/main.rs` file to look like this:
 
index f6e64d899607455e8433df1c69d6b6f3d76ca70b..87f3a0c765c5ef4fbef558902e5e8c60c2aacdeb 100644 (file)
@@ -1,3 +1,3 @@
 % The Rust Tutorial
 
-This tutorial has been deprecated in favor of [the Guide](guide.html). Go check that out instead!
+This tutorial has been deprecated in favor of [the Book](book/index.html). Go check that out instead!
index 88de5db41fe7b555369e2ff6e595e8bda6e8c650..7d071d5e724b4635c2a9640bcb4685b05f4701e3 100644 (file)
@@ -194,8 +194,13 @@ LIT_STR_RAW
   : 'r' LIT_STR_RAW_INNER SUFFIX?
   ;
 
+
+QUESTION : '?';
+
 IDENT : XID_start XID_continue* ;
 
+fragment QUESTION_IDENTIFIER : QUESTION? IDENT;
+
 LIFETIME : '\'' IDENT ;
 
 WHITESPACE : [ \r\n\t]+ ;
index 9194c7a47663d66e343750d8c515e39da09b8c8a..e9409a6106131ec3870e91776f27cce605e92e33 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(globs, plugin)]
+#![feature(plugin)]
 
 extern crate syntax;
 extern crate rustc;
@@ -107,13 +107,14 @@ fn id() -> token::Token {
             "LE"                => token::Le,
             "LIT_BINARY"        => token::Literal(token::Binary(Name(0)), None),
             "LIT_BINARY_RAW"    => token::Literal(token::BinaryRaw(Name(0), 0), None),
+            "QUESTION"          => token::Question,
             _                   => continue,
         };
 
         res.insert(num.to_string(), tok);
     }
 
-    debug!("Token map: {}", res);
+    debug!("Token map: {:?}", res);
     res
 }
 
@@ -161,7 +162,7 @@ fn fixchar(mut lit: &str) -> ast::Name {
     parse::token::intern(lit.slice(1, lit.len() - 1))
 }
 
-fn count(lit: &str) -> uint {
+fn count(lit: &str) -> usize {
     lit.chars().take_while(|c| *c == '#').count()
 }
 
@@ -176,12 +177,12 @@ fn parse_antlr_token(s: &str, tokens: &HashMap<String, token::Token>) -> TokenAn
     let toknum = m.name("toknum").unwrap_or("");
     let content = m.name("content").unwrap_or("");
 
-    let proto_tok = tokens.get(toknum).expect(format!("didn't find token {} in the map",
+    let proto_tok = tokens.get(toknum).expect(format!("didn't find token {:?} in the map",
                                                               toknum).as_slice());
 
     let nm = parse::token::intern(content);
 
-    debug!("What we got: content (`{}`), proto: {}", content, proto_tok);
+    debug!("What we got: content (`{}`), proto: {:?}", content, proto_tok);
 
     let real_tok = match *proto_tok {
         token::BinOp(..)           => token::BinOp(str_to_binop(content)),
@@ -265,7 +266,7 @@ fn next(r: &mut lexer::StringReader) -> TokenAndSpan {
             continue
         }
 
-        assert!(rustc_tok.sp == antlr_tok.sp, "{} and {} have different spans", rustc_tok,
+        assert!(rustc_tok.sp == antlr_tok.sp, "{:?} and {:?} have different spans", rustc_tok,
                 antlr_tok);
 
         macro_rules! matches {
@@ -276,12 +277,12 @@ macro_rules! matches {
                             if !tok_cmp(&rustc_tok.tok, &antlr_tok.tok) {
                                 // FIXME #15677: needs more robust escaping in
                                 // antlr
-                                warn!("Different names for {} and {}", rustc_tok, antlr_tok);
+                                warn!("Different names for {:?} and {:?}", rustc_tok, antlr_tok);
                             }
                         }
-                        _ => panic!("{} is not {}", antlr_tok, rustc_tok)
+                        _ => panic!("{:?} is not {:?}", antlr_tok, rustc_tok)
                     },)*
-                    ref c => assert!(c == &antlr_tok.tok, "{} is not {}", rustc_tok, antlr_tok)
+                    ref c => assert!(c == &antlr_tok.tok, "{:?} is not {:?}", rustc_tok, antlr_tok)
                 }
             )
         }
index 02933c763efe5f56997f72c2fd6feeb91d68fa59..b7bc1b4764614ac50e6f9fd32384e812ca1bbc2e 100644 (file)
@@ -119,7 +119,8 @@ unsafe fn exchange_free(ptr: *mut u8, old_size: uint, align: uint) {
           not(feature = "external_crate"),
           any(target_arch = "arm",
               target_arch = "mips",
-              target_arch = "mipsel")))]
+              target_arch = "mipsel",
+              target_arch = "powerpc")))]
 const MIN_ALIGN: uint = 8;
 #[cfg(all(not(feature = "external_funcs"),
           not(feature = "external_crate"),
index 4a85637625a22ff09465e7b73e83b950ddd32ce3..6c85330603514a0ea109774787be9f18397019b0 100644 (file)
@@ -68,6 +68,7 @@
 #![allow(unknown_features)]
 #![feature(lang_items, unsafe_destructor)]
 #![feature(box_syntax)]
+#![feature(optin_builtin_traits)]
 #![allow(unknown_features)] #![feature(int_uint)]
 
 #[macro_use]
index f42c6dbdc15a592721d2f7422e53bc2c8e3cb68e..0e18cdda8dd894cb747c835240e9ef8c66f250a9 100644 (file)
@@ -174,6 +174,7 @@ struct RcBox<T> {
 /// See the [module level documentation](../index.html) for more details.
 #[unsafe_no_drop_flag]
 #[stable]
+#[cfg(stage0)] // NOTE remove impl after next snapshot
 pub struct Rc<T> {
     // FIXME #12808: strange names to try to avoid interfering with field accesses of the contained
     // type via Deref
@@ -182,6 +183,24 @@ pub struct Rc<T> {
     _noshare: marker::NoSync
 }
 
+/// An immutable reference-counted pointer type.
+///
+/// See the [module level documentation](../index.html) for more details.
+#[unsafe_no_drop_flag]
+#[stable]
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+pub struct Rc<T> {
+    // FIXME #12808: strange names to try to avoid interfering with field accesses of the contained
+    // type via Deref
+    _ptr: NonZero<*mut RcBox<T>>,
+}
+
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+impl<T> !marker::Send for Rc<T> {}
+
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+impl<T> !marker::Sync for Rc<T> {}
+
 impl<T> Rc<T> {
     /// Constructs a new `Rc<T>`.
     ///
@@ -193,6 +212,7 @@ impl<T> Rc<T> {
     /// let five = Rc::new(5i);
     /// ```
     #[stable]
+    #[cfg(stage0)] // NOTE remove after next snapshot
     pub fn new(value: T) -> Rc<T> {
         unsafe {
             Rc {
@@ -210,6 +230,32 @@ pub fn new(value: T) -> Rc<T> {
         }
     }
 
+    /// Constructs a new `Rc<T>`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::rc::Rc;
+    ///
+    /// let five = Rc::new(5i);
+    /// ```
+    #[stable]
+    #[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+    pub fn new(value: T) -> Rc<T> {
+        unsafe {
+            Rc {
+                // there is an implicit weak pointer owned by all the strong pointers, which
+                // ensures that the weak destructor never frees the allocation while the strong
+                // destructor is running, even if the weak pointer is stored inside the strong one.
+                _ptr: NonZero::new(transmute(box RcBox {
+                    value: value,
+                    strong: Cell::new(1),
+                    weak: Cell::new(1)
+                })),
+            }
+        }
+    }
+
     /// Downgrades the `Rc<T>` to a `Weak<T>` reference.
     ///
     /// # Examples
@@ -221,6 +267,7 @@ pub fn new(value: T) -> Rc<T> {
     ///
     /// let weak_five = five.downgrade();
     /// ```
+    #[cfg(stage0)] // NOTE remove after next snapshot
     #[unstable = "Weak pointers may not belong in this module"]
     pub fn downgrade(&self) -> Weak<T> {
         self.inc_weak();
@@ -230,6 +277,24 @@ pub fn downgrade(&self) -> Weak<T> {
             _noshare: marker::NoSync
         }
     }
+
+    /// Downgrades the `Rc<T>` to a `Weak<T>` reference.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::rc::Rc;
+    ///
+    /// let five = Rc::new(5i);
+    ///
+    /// let weak_five = five.downgrade();
+    /// ```
+    #[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+    #[unstable = "Weak pointers may not belong in this module"]
+    pub fn downgrade(&self) -> Weak<T> {
+        self.inc_weak();
+        Weak { _ptr: self._ptr }
+    }
 }
 
 /// Get the number of weak references to this value.
@@ -432,10 +497,31 @@ impl<T> Clone for Rc<T> {
     /// five.clone();
     /// ```
     #[inline]
+    #[cfg(stage0)] // NOTE remove after next snapshot
     fn clone(&self) -> Rc<T> {
         self.inc_strong();
         Rc { _ptr: self._ptr, _nosend: marker::NoSend, _noshare: marker::NoSync }
     }
+
+    /// Makes a clone of the `Rc<T>`.
+    ///
+    /// This increases the strong reference count.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::rc::Rc;
+    ///
+    /// let five = Rc::new(5i);
+    ///
+    /// five.clone();
+    /// ```
+    #[inline]
+    #[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+    fn clone(&self) -> Rc<T> {
+        self.inc_strong();
+        Rc { _ptr: self._ptr }
+    }
 }
 
 #[stable]
@@ -636,6 +722,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 /// See the [module level documentation](../index.html) for more.
 #[unsafe_no_drop_flag]
 #[unstable = "Weak pointers may not belong in this module."]
+#[cfg(stage0)] // NOTE remove impl after next snapshot
 pub struct Weak<T> {
     // FIXME #12808: strange names to try to avoid interfering with
     // field accesses of the contained type via Deref
@@ -644,6 +731,29 @@ pub struct Weak<T> {
     _noshare: marker::NoSync
 }
 
+/// A weak version of `Rc<T>`.
+///
+/// Weak references do not count when determining if the inner value should be dropped.
+///
+/// See the [module level documentation](../index.html) for more.
+#[unsafe_no_drop_flag]
+#[unstable = "Weak pointers may not belong in this module."]
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+pub struct Weak<T> {
+    // FIXME #12808: strange names to try to avoid interfering with
+    // field accesses of the contained type via Deref
+    _ptr: NonZero<*mut RcBox<T>>,
+}
+
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+#[allow(unstable)]
+impl<T> !marker::Send for Weak<T> {}
+
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+#[allow(unstable)]
+impl<T> !marker::Sync for Weak<T> {}
+
+
 #[unstable = "Weak pointers may not belong in this module."]
 impl<T> Weak<T> {
     /// Upgrades a weak reference to a strong reference.
@@ -663,6 +773,7 @@ impl<T> Weak<T> {
     ///
     /// let strong_five: Option<Rc<_>> = weak_five.upgrade();
     /// ```
+    #[cfg(stage0)] // NOTE remove after next snapshot
     pub fn upgrade(&self) -> Option<Rc<T>> {
         if self.strong() == 0 {
             None
@@ -671,6 +782,33 @@ pub fn upgrade(&self) -> Option<Rc<T>> {
             Some(Rc { _ptr: self._ptr, _nosend: marker::NoSend, _noshare: marker::NoSync })
         }
     }
+
+    /// Upgrades a weak reference to a strong reference.
+    ///
+    /// Upgrades the `Weak<T>` reference to an `Rc<T>`, if possible.
+    ///
+    /// Returns `None` if there were no strong references and the data was destroyed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::rc::Rc;
+    ///
+    /// let five = Rc::new(5i);
+    ///
+    /// let weak_five = five.downgrade();
+    ///
+    /// let strong_five: Option<Rc<_>> = weak_five.upgrade();
+    /// ```
+    #[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+    pub fn upgrade(&self) -> Option<Rc<T>> {
+        if self.strong() == 0 {
+            None
+        } else {
+            self.inc_strong();
+            Some(Rc { _ptr: self._ptr })
+        }
+    }
 }
 
 #[unsafe_destructor]
@@ -733,10 +871,31 @@ impl<T> Clone for Weak<T> {
     /// weak_five.clone();
     /// ```
     #[inline]
+    #[cfg(stage0)] // NOTE remove after next snapshot
     fn clone(&self) -> Weak<T> {
         self.inc_weak();
         Weak { _ptr: self._ptr, _nosend: marker::NoSend, _noshare: marker::NoSync }
     }
+
+    /// Makes a clone of the `Weak<T>`.
+    ///
+    /// This increases the weak reference count.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::rc::Rc;
+    ///
+    /// let weak_five = Rc::new(5i).downgrade();
+    ///
+    /// weak_five.clone();
+    /// ```
+    #[inline]
+    #[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+    fn clone(&self) -> Weak<T> {
+        self.inc_weak();
+        Weak { _ptr: self._ptr }
+    }
 }
 
 #[unstable = "Show is experimental."]
index c1b34c52fcc154c260de01340982ea77f4083b4c..82e5af67ae31649e8cc0b0693a870c5c5671b3ee 100644 (file)
@@ -2526,7 +2526,7 @@ fn bench_uint_small(b: &mut Bencher) {
             for _ in range(0u, 100) {
                 bitv |= 1 << ((r.next_u32() as uint) % u32::BITS);
             }
-            black_box(&bitv)
+            black_box(&bitv);
         });
     }
 
@@ -2538,7 +2538,7 @@ fn bench_bitv_set_big_fixed(b: &mut Bencher) {
             for _ in range(0u, 100) {
                 bitv.set((r.next_u32() as uint) % BENCH_BITS, true);
             }
-            black_box(&bitv)
+            black_box(&bitv);
         });
     }
 
index 3e1533dd35f598aad43903e14b74774627c0af14..6c3767b011158403bed037a173487c8a129a97b7 100644 (file)
@@ -1422,7 +1422,6 @@ pub fn entry<'a>(&'a mut self, mut key: K) -> Entry<'a, K, V> {
 #[cfg(test)]
 mod test {
     use prelude::*;
-    use std::borrow::BorrowFrom;
 
     use super::{BTreeMap, Occupied, Vacant};
 
index 812cff6fab722d223997f813221b98ba5eea399c..6e048e0e83cb58946cd4e133e1183a3b177ac5d4 100644 (file)
@@ -18,6 +18,8 @@
 use core::default::Default;
 use core::fmt::Show;
 use core::fmt;
+// NOTE(stage0) remove import after a snapshot
+#[cfg(stage0)]
 use core::hash::Hash;
 use core::iter::{Peekable, Map, FromIterator};
 use core::ops::{BitOr, BitAnd, BitXor, Sub};
index 4f918ceac578c636203cd0b60b6d318cb113b32e..cce8cf398e12e06bc9827936b26b93cd6298b634 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -230,7 +230,7 @@ pub fn new() -> DList<T> {
     ///
     /// # Examples
     ///
-    /// ```rust
+    /// ```
     /// use std::collections::DList;
     ///
     /// let mut a = DList::new();
@@ -304,6 +304,18 @@ pub fn into_iter(self) -> IntoIter<T> {
     /// Returns `true` if the `DList` is empty.
     ///
     /// This operation should compute in O(1) time.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::DList;
+    ///
+    /// let mut dl = DList::new();
+    /// assert!(dl.is_empty());
+    ///
+    /// dl.push_front("foo");
+    /// assert!(!dl.is_empty());
+    /// ```
     #[inline]
     #[stable]
     pub fn is_empty(&self) -> bool {
@@ -313,6 +325,24 @@ pub fn is_empty(&self) -> bool {
     /// Returns the length of the `DList`.
     ///
     /// This operation should compute in O(1) time.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::DList;
+    ///
+    /// let mut dl = DList::new();
+    ///
+    /// dl.push_front(2is);
+    /// assert_eq!(dl.len(), 1);
+    ///
+    /// dl.push_front(1);
+    /// assert_eq!(dl.len(), 2);
+    ///
+    /// dl.push_back(3);
+    /// assert_eq!(dl.len(), 3);
+    ///
+    /// ```
     #[inline]
     #[stable]
     pub fn len(&self) -> uint {
@@ -322,6 +352,24 @@ pub fn len(&self) -> uint {
     /// Removes all elements from the `DList`.
     ///
     /// This operation should compute in O(n) time.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::DList;
+    ///
+    /// let mut dl = DList::new();
+    ///
+    /// dl.push_front(2is);
+    /// dl.push_front(1);
+    /// assert_eq!(dl.len(), 2);
+    /// assert_eq!(dl.front(), Some(&1is));
+    ///
+    /// dl.clear();
+    /// assert_eq!(dl.len(), 0);
+    /// assert_eq!(dl.front(), None);
+    ///
+    /// ```
     #[inline]
     #[stable]
     pub fn clear(&mut self) {
@@ -330,6 +378,19 @@ pub fn clear(&mut self) {
 
     /// Provides a reference to the front element, or `None` if the list is
     /// empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::DList;
+    ///
+    /// let mut dl = DList::new();
+    /// assert_eq!(dl.front(), None);
+    ///
+    /// dl.push_front(1);
+    /// assert_eq!(dl.front(), Some(&1is));
+    ///
+    /// ```
     #[inline]
     #[stable]
     pub fn front(&self) -> Option<&T> {
@@ -338,6 +399,25 @@ pub fn front(&self) -> Option<&T> {
 
     /// Provides a mutable reference to the front element, or `None` if the list
     /// is empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::DList;
+    ///
+    /// let mut dl = DList::new();
+    /// assert_eq!(dl.front(), None);
+    ///
+    /// dl.push_front(1);
+    /// assert_eq!(dl.front(), Some(&1is));
+    ///
+    /// match dl.front_mut() {
+    ///     None => {},
+    ///     Some(x) => *x = 5is,
+    /// }
+    /// assert_eq!(dl.front(), Some(&5is));
+    ///
+    /// ```
     #[inline]
     #[stable]
     pub fn front_mut(&mut self) -> Option<&mut T> {
@@ -346,6 +426,19 @@ pub fn front_mut(&mut self) -> Option<&mut T> {
 
     /// Provides a reference to the back element, or `None` if the list is
     /// empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::DList;
+    ///
+    /// let mut dl = DList::new();
+    /// assert_eq!(dl.back(), None);
+    ///
+    /// dl.push_back(1);
+    /// assert_eq!(dl.back(), Some(&1is));
+    ///
+    /// ```
     #[inline]
     #[stable]
     pub fn back(&self) -> Option<&T> {
@@ -354,6 +447,25 @@ pub fn back(&self) -> Option<&T> {
 
     /// Provides a mutable reference to the back element, or `None` if the list
     /// is empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::DList;
+    ///
+    /// let mut dl = DList::new();
+    /// assert_eq!(dl.back(), None);
+    ///
+    /// dl.push_back(1);
+    /// assert_eq!(dl.back(), Some(&1is));
+    ///
+    /// match dl.back_mut() {
+    ///     None => {},
+    ///     Some(x) => *x = 5is,
+    /// }
+    /// assert_eq!(dl.back(), Some(&5is));
+    ///
+    /// ```
     #[inline]
     #[stable]
     pub fn back_mut(&mut self) -> Option<&mut T> {
@@ -363,6 +475,21 @@ pub fn back_mut(&mut self) -> Option<&mut T> {
     /// Adds an element first in the list.
     ///
     /// This operation should compute in O(1) time.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::DList;
+    ///
+    /// let mut dl = DList::new();
+    ///
+    /// dl.push_front(2is);
+    /// assert_eq!(dl.front().unwrap(), &2is);
+    ///
+    /// dl.push_front(1);
+    /// assert_eq!(dl.front().unwrap(), &1);
+    ///
+    /// ```
     #[stable]
     pub fn push_front(&mut self, elt: T) {
         self.push_front_node(box Node::new(elt))
@@ -372,6 +499,23 @@ pub fn push_front(&mut self, elt: T) {
     /// empty.
     ///
     /// This operation should compute in O(1) time.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::DList;
+    ///
+    /// let mut d = DList::new();
+    /// assert_eq!(d.pop_front(), None);
+    ///
+    /// d.push_front(1is);
+    /// d.push_front(3);
+    /// assert_eq!(d.pop_front(), Some(3));
+    /// assert_eq!(d.pop_front(), Some(1));
+    /// assert_eq!(d.pop_front(), None);
+    ///
+    /// ```
+    ///
     #[stable]
     pub fn pop_front(&mut self) -> Option<T> {
         self.pop_front_node().map(|box Node{value, ..}| value)
@@ -381,7 +525,7 @@ pub fn pop_front(&mut self) -> Option<T> {
     ///
     /// # Examples
     ///
-    /// ```rust
+    /// ```
     /// use std::collections::DList;
     ///
     /// let mut d = DList::new();
@@ -399,7 +543,7 @@ pub fn push_back(&mut self, elt: T) {
     ///
     /// # Examples
     ///
-    /// ```rust
+    /// ```
     /// use std::collections::DList;
     ///
     /// let mut d = DList::new();
@@ -417,6 +561,22 @@ pub fn pop_back(&mut self) -> Option<T> {
     /// including the index.
     ///
     /// This operation should compute in O(n) time.
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::DList;
+    ///
+    /// let mut d = DList::new();
+    ///
+    /// d.push_front(1is);
+    /// d.push_front(2);
+    /// d.push_front(3);
+    ///
+    /// let mut splitted = d.split_off(2);
+    ///
+    /// assert_eq!(splitted.pop_front(), Some(1));
+    /// assert_eq!(splitted.pop_front(), None);
+    /// ```
     #[stable]
     pub fn split_off(&mut self, at: uint) -> DList<T> {
         let len = self.len();
@@ -593,7 +753,7 @@ impl<'a, A> IterMut<'a, A> {
     ///
     /// # Examples
     ///
-    /// ```rust
+    /// ```
     /// use std::collections::DList;
     ///
     /// let mut list: DList<int> = vec![1, 3, 4].into_iter().collect();
@@ -619,7 +779,7 @@ pub fn insert_next(&mut self, elt: A) {
     ///
     /// # Examples
     ///
-    /// ```rust
+    /// ```
     /// use std::collections::DList;
     ///
     /// let mut list: DList<int> = vec![1, 2, 3].into_iter().collect();
index 9a1f22ef7a643067ae4314c9fe77fbbf01c21775..4812ecc2c0b754b7a3a83b58dd1f43446271b495 100644 (file)
@@ -1631,7 +1631,7 @@ fn test_slice() {
     #[test]
     fn test_slice_from() {
         let vec: &[int] = &[1, 2, 3, 4];
-        assert_eq!(&vec[0..], vec);
+        assert_eq!(&vec[], vec);
         let b: &[int] = &[3, 4];
         assert_eq!(&vec[2..], b);
         let b: &[int] = &[];
@@ -1641,11 +1641,11 @@ fn test_slice_from() {
     #[test]
     fn test_slice_to() {
         let vec: &[int] = &[1, 2, 3, 4];
-        assert_eq!(&vec[0..4], vec);
+        assert_eq!(&vec[..4], vec);
         let b: &[int] = &[1, 2];
-        assert_eq!(&vec[0..2], b);
+        assert_eq!(&vec[..2], b);
         let b: &[int] = &[];
-        assert_eq!(&vec[0..0], b);
+        assert_eq!(&vec[..0], b);
     }
 
 
@@ -2538,7 +2538,7 @@ fn test_mut_split_at() {
             let (left, right) = values.split_at_mut(2);
             {
                 let left: &[_] = left;
-                assert!(left[0..left.len()] == [1, 2][]);
+                assert!(left[..left.len()] == [1, 2][]);
             }
             for p in left.iter_mut() {
                 *p += 1;
@@ -2546,7 +2546,7 @@ fn test_mut_split_at() {
 
             {
                 let right: &[_] = right;
-                assert!(right[0..right.len()] == [3, 4, 5][]);
+                assert!(right[..right.len()] == [3, 4, 5][]);
             }
             for p in right.iter_mut() {
                 *p += 2;
index ccf654ac0a048a93860f585977c52e2830a15cf5..f7668930660b0203481894aaeb05ff408d0e8210 100644 (file)
@@ -807,7 +807,7 @@ fn slice_from(&self, begin: uint) -> &str {
     /// out of bounds.
     ///
     /// See also `slice`, `slice_from` and `slice_chars`.
-    #[unstable = "use slice notation [0..a] instead"]
+    #[unstable = "use slice notation [..a] instead"]
     fn slice_to(&self, end: uint) -> &str {
         core_str::StrExt::slice_to(&self[], end)
     }
@@ -2841,7 +2841,7 @@ fn char_iterator_for(b: &mut Bencher) {
         let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
 
         b.iter(|| {
-            for ch in s.chars() { black_box(ch) }
+            for ch in s.chars() { black_box(ch); }
         });
     }
 
@@ -2869,7 +2869,7 @@ fn char_iterator_rev_for(b: &mut Bencher) {
         let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
 
         b.iter(|| {
-            for ch in s.chars().rev() { black_box(ch) }
+            for ch in s.chars().rev() { black_box(ch); }
         });
     }
 
index e30e7e8600dcbc773117078d6957ee077c71c9ea..c845d86ca0fe78dc043a8131b3da0d13b1bbfa09 100644 (file)
@@ -168,7 +168,7 @@ fn safe_get(xs: &[u8], i: uint, total: uint) -> u8 {
 
         if i > 0 {
             unsafe {
-                res.as_mut_vec().push_all(&v[0..i])
+                res.as_mut_vec().push_all(&v[..i])
             };
         }
 
index e5f9b2513e277c2d78666c1fee9b8b419d9d0c95..73afefc5a03317c5281a52c8a25a9861f700d031 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! A growable list type, written `Vec<T>` but pronounced 'vector.'
+//! A growable list type with heap-allocated contents, written `Vec<T>` but pronounced 'vector.'
 //!
 //! Vectors have `O(1)` indexing, push (to the end) and pop (from the end).
 //!
@@ -1511,6 +1511,9 @@ pub struct IntoIter<T> {
     end: *const T
 }
 
+unsafe impl<T: Send> Send for IntoIter<T> { }
+unsafe impl<T: Sync> Sync for IntoIter<T> { }
+
 impl<T> IntoIter<T> {
     #[inline]
     /// Drops all items that have not yet been moved and returns the empty vector.
index 6db01b7cb7afe67d6d26b12f4f9c0881092ff967..ec4007c4c6dd425b891f26a1fe7c542e06e2e7b2 100644 (file)
@@ -509,12 +509,13 @@ fn deref_mut<'a>(&'a mut self) -> &'a mut T {
 ///
 /// ```rust
 /// use std::cell::UnsafeCell;
-/// use std::marker;
+/// use std::marker::Sync;
 ///
 /// struct NotThreadSafe<T> {
 ///     value: UnsafeCell<T>,
-///     marker: marker::NoSync
 /// }
+///
+/// unsafe impl<T> Sync for NotThreadSafe<T> {}
 /// ```
 ///
 /// **NOTE:** `UnsafeCell<T>` fields are public to allow static initializers. It
index a21ec892dd77a64abfc60a564c3268f04ecb6a1c..4c2a2ff1086039c2c3f4c39a28aef8b9c2a53024 100644 (file)
 //! # }
 //! ```
 
-#![unstable]
+#![deprecated = "It is unclear if this module is more robust than implementing \
+                 Drop on a custom type, and this module is being removed with no \
+                 replacement. Use a custom Drop implementation to regain existing \
+                 functionality."]
+#![allow(deprecated)]
 
 use ops::{Drop, FnMut, FnOnce};
 
index 0ffcb014c2877f558f6b9e4dc6f41e6b894fa416..f1b9ebe6d905d13e6271094fe4bd61126aaff854 100644 (file)
@@ -332,5 +332,5 @@ fn write_str(&mut self, s: &str) -> fmt::Result {
         }
     }
 
-    f(unsafe { str::from_utf8_unchecked(&buf[0..end]) })
+    f(unsafe { str::from_utf8_unchecked(&buf[..end]) })
 }
index a0ec9e5f151c2c2eaf28a2e357b646413e1a0ab2..20ac3e28c973ecb65f439556f9a491462fdb14c6 100644 (file)
@@ -449,7 +449,7 @@ pub fn pad_integral(&mut self,
             for c in sign.into_iter() {
                 let mut b = [0; 4];
                 let n = c.encode_utf8(&mut b).unwrap_or(0);
-                let b = unsafe { str::from_utf8_unchecked(&b[0..n]) };
+                let b = unsafe { str::from_utf8_unchecked(&b[..n]) };
                 try!(f.buf.write_str(b));
             }
             if prefixed { f.buf.write_str(prefix) }
@@ -692,7 +692,7 @@ impl String for char {
     fn fmt(&self, f: &mut Formatter) -> Result {
         let mut utf8 = [0u8; 4];
         let amt = self.encode_utf8(&mut utf8).unwrap_or(0);
-        let s: &str = unsafe { mem::transmute(&utf8[0..amt]) };
+        let s: &str = unsafe { mem::transmute(&utf8[..amt]) };
         String::fmt(s, f)
     }
 }
index 5924d515dda595c5e785608d110108e5aeae1e97..978e8a19737b4a6164f78aeab68dcf55ae824c45 100644 (file)
@@ -198,6 +198,10 @@ pub struct TyDesc {
     pub fn pref_align_of<T>() -> uint;
 
     /// Get a static pointer to a type descriptor.
+    #[cfg(not(stage0))]
+    pub fn get_tydesc<T: ?Sized>() -> *const TyDesc;
+
+    #[cfg(stage0)]
     pub fn get_tydesc<T>() -> *const TyDesc;
 
     /// Gets an identifier which is globally unique to the specified type. This
index d400cb47cbff6d14f5ed4da9d26ff6921e3c4a70..715a79abe854056aeeb8c200d901c6a97761f375 100644 (file)
@@ -286,6 +286,7 @@ fn clone(&self) -> InvariantType<T> { *self }
 #[unstable = "likely to change with new variance strategy"]
 #[lang="no_send_bound"]
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+#[cfg(stage0)] // NOTE remove impl after next snapshot
 pub struct NoSend;
 
 /// A type which is considered "not POD", meaning that it is not
@@ -303,6 +304,7 @@ fn clone(&self) -> InvariantType<T> { *self }
 #[unstable = "likely to change with new variance strategy"]
 #[lang="no_sync_bound"]
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+#[cfg(stage0)] // NOTE remove impl after next snapshot
 pub struct NoSync;
 
 /// A type which is considered managed by the GC. This is typically
index 41eecb4649d97decab6b9961dd61fd3e61d7f9fc..af7fc875389c07d4fdb416e6b77cfe7e0bee9ce3 100644 (file)
@@ -66,7 +66,6 @@
 //! not (`None`).
 //!
 //! ```
-//! # use std::boxed::Box;
 //! let optional: Option<Box<int>> = None;
 //! check_optional(&optional);
 //!
index ab1e69f0060644d5f3d7525ca9574c5c669fcd8f..baf998d0828a27c7f7818c0aca169ee91794ee0f 100644 (file)
@@ -46,7 +46,6 @@
 //! though unsafely, transformed from one type to the other.
 //!
 //! ```
-//! # use std::boxed::Box;
 //! use std::mem;
 //!
 //! unsafe {
index f7421203336c3571e2b55a686ebbea52eac22577..110bce5c12472a1702113e7fc8d5cd5601c325b8 100644 (file)
 //! drop(file);
 //! ```
 //!
-//! If you *do* write that in Rust, the compiler will by give you a
+//! If you *do* write that in Rust, the compiler will give you a
 //! warning (by default, controlled by the `unused_must_use` lint).
 //!
 //! You might instead, if you don't want to handle the error, simply
 //! fn write_info(info: &Info) -> Result<(), IoError> {
 //!     let mut file = File::open_mode(&Path::new("my_best_friends.txt"), Open, Write);
 //!     // Early return on error
-//!     match file.write_line(format!("name: {}", info.name).as_slice()) {
-//!         Ok(_) => (),
-//!         Err(e) => return Err(e)
+//!     if let Err(e) = file.write_line(format!("name: {}", info.name).as_slice()) {
+//!         return Err(e)
 //!     }
-//!     match file.write_line(format!("age: {}", info.age).as_slice()) {
-//!         Ok(_) => (),
-//!         Err(e) => return Err(e)
+//!     if let Err(e) = file.write_line(format!("age: {}", info.age).as_slice()) {
+//!         return Err(e)
 //!     }
 //!     return file.write_line(format!("rating: {}", info.rating).as_slice());
 //! }
index 7e47c5257a344942cfab44a2f0465dce27712f5f..22da168911daad66f84a6bc6a731408cfbae17c0 100644 (file)
@@ -159,7 +159,7 @@ fn slice_to(&self, end: uint) -> &[T] {
 
     #[inline]
     fn split_at(&self, mid: uint) -> (&[T], &[T]) {
-        (&self[0..mid], &self[mid..])
+        (&self[..mid], &self[mid..])
     }
 
     #[inline]
@@ -240,7 +240,7 @@ fn tail(&self) -> &[T] { &self[1..] }
 
     #[inline]
     fn init(&self) -> &[T] {
-        &self[0..(self.len() - 1)]
+        &self[..(self.len() - 1)]
     }
 
     #[inline]
@@ -443,7 +443,7 @@ fn contains(&self, x: &T) -> bool where T: PartialEq {
     #[inline]
     fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq {
         let n = needle.len();
-        self.len() >= n && needle == &self[0..n]
+        self.len() >= n && needle == &self[..n]
     }
 
     #[inline]
@@ -972,7 +972,7 @@ fn next(&mut self) -> Option<&'a [T]> {
         match self.v.iter().position(|x| (self.pred)(x)) {
             None => self.finish(),
             Some(idx) => {
-                let ret = Some(&self.v[0..idx]);
+                let ret = Some(&self.v[..idx]);
                 self.v = &self.v[(idx + 1)..];
                 ret
             }
@@ -999,7 +999,7 @@ fn next_back(&mut self) -> Option<&'a [T]> {
             None => self.finish(),
             Some(idx) => {
                 let ret = Some(&self.v[(idx + 1)..]);
-                self.v = &self.v[0..idx];
+                self.v = &self.v[..idx];
                 ret
             }
         }
@@ -1195,7 +1195,7 @@ fn next(&mut self) -> Option<&'a [T]> {
         if self.size > self.v.len() {
             None
         } else {
-            let ret = Some(&self.v[0..self.size]);
+            let ret = Some(&self.v[..self.size]);
             self.v = &self.v[1..];
             ret
         }
index 94ee9b7dcf6adaa639e931f9888a88b3546c3e5e..d9cf6dc086d9972099544924198cdf313333f096 100644 (file)
@@ -701,10 +701,10 @@ fn new(needle: &[u8]) -> TwoWaySearcher {
         //
         // What's going on is we have some critical factorization (u, v) of the
         // needle, and we want to determine whether u is a suffix of
-        // &v[0..period]. If it is, we use "Algorithm CP1". Otherwise we use
+        // &v[..period]. If it is, we use "Algorithm CP1". Otherwise we use
         // "Algorithm CP2", which is optimized for when the period of the needle
         // is large.
-        if &needle[0..crit_pos] == &needle[period.. period + crit_pos] {
+        if &needle[..crit_pos] == &needle[period.. period + crit_pos] {
             TwoWaySearcher {
                 crit_pos: crit_pos,
                 period: period,
@@ -1412,7 +1412,7 @@ unsafe fn slice_unchecked(&self, begin: uint, end: uint) -> &str {
     #[inline]
     fn starts_with(&self, needle: &str) -> bool {
         let n = needle.len();
-        self.len() >= n && needle.as_bytes() == &self.as_bytes()[0..n]
+        self.len() >= n && needle.as_bytes() == &self.as_bytes()[..n]
     }
 
     #[inline]
index 4aca830cb941390c7846d491a1f9bb847b19dbf9..5baeae236b33ef573d6e37f793db6348ff7d5ab7 100644 (file)
@@ -35,9 +35,6 @@
 
 #![stable]
 
-#[unstable = "this is just a documentation module and should not be part \
-              of the public api"]
-
 use clone::Clone;
 use cmp::*;
 use cmp::Ordering::*;
index 7b6b4f848085e75a49d2c578e83b9662a3c50aa0..2e29b1c41c418f1fb098735d3df6ee353e942d3a 100644 (file)
@@ -167,7 +167,7 @@ fn test_encode_utf8() {
     fn check(input: char, expect: &[u8]) {
         let mut buf = [0u8; 4];
         let n = input.encode_utf8(buf.as_mut_slice()).unwrap_or(0);
-        assert_eq!(&buf[0..n], expect);
+        assert_eq!(&buf[..n], expect);
     }
 
     check('x', &[0x78]);
@@ -181,7 +181,7 @@ fn test_encode_utf16() {
     fn check(input: char, expect: &[u16]) {
         let mut buf = [0u16; 2];
         let n = input.encode_utf16(buf.as_mut_slice()).unwrap_or(0);
-        assert_eq!(&buf[0..n], expect);
+        assert_eq!(&buf[..n], expect);
     }
 
     check('x', &[0x0078]);
index 61266a926494458f62bfffdbac6b964cbcffac83..26819bf92098631a86ba05c2940d201fe1a6e996 100644 (file)
@@ -288,7 +288,7 @@ fn test_iterator_len() {
     let v: &[_] = &[0i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
     assert_eq!(v[..4].iter().count(), 4);
     assert_eq!(v[..10].iter().count(), 10);
-    assert_eq!(v[0..0].iter().count(), 0);
+    assert_eq!(v[..0].iter().count(), 0);
 }
 
 #[test]
@@ -296,31 +296,31 @@ fn test_iterator_sum() {
     let v: &[_] = &[0i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
     assert_eq!(v[..4].iter().map(|&x| x).sum(), 6);
     assert_eq!(v.iter().map(|&x| x).sum(), 55);
-    assert_eq!(v[0..0].iter().map(|&x| x).sum(), 0);
+    assert_eq!(v[..0].iter().map(|&x| x).sum(), 0);
 }
 
 #[test]
 fn test_iterator_product() {
     let v: &[_] = &[0i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-    assert_eq!(v[0..4].iter().map(|&x| x).product(), 0);
+    assert_eq!(v[..4].iter().map(|&x| x).product(), 0);
     assert_eq!(v[1..5].iter().map(|&x| x).product(), 24);
-    assert_eq!(v[0..0].iter().map(|&x| x).product(), 1);
+    assert_eq!(v[..0].iter().map(|&x| x).product(), 1);
 }
 
 #[test]
 fn test_iterator_max() {
     let v: &[_] = &[0i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-    assert_eq!(v[0..4].iter().map(|&x| x).max(), Some(3));
+    assert_eq!(v[..4].iter().map(|&x| x).max(), Some(3));
     assert_eq!(v.iter().map(|&x| x).max(), Some(10));
-    assert_eq!(v[0..0].iter().map(|&x| x).max(), None);
+    assert_eq!(v[..0].iter().map(|&x| x).max(), None);
 }
 
 #[test]
 fn test_iterator_min() {
     let v: &[_] = &[0i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-    assert_eq!(v[0..4].iter().map(|&x| x).min(), Some(0));
+    assert_eq!(v[..4].iter().map(|&x| x).min(), Some(0));
     assert_eq!(v.iter().map(|&x| x).min(), Some(0));
-    assert_eq!(v[0..0].iter().map(|&x| x).min(), None);
+    assert_eq!(v[..0].iter().map(|&x| x).min(), None);
 }
 
 #[test]
@@ -373,7 +373,7 @@ fn test_all() {
     assert!(v.iter().all(|&x| x < 10));
     assert!(!v.iter().all(|&x| x % 2 == 0));
     assert!(!v.iter().all(|&x| x > 100));
-    assert!(v[0..0].iter().all(|_| panic!()));
+    assert!(v[..0].iter().all(|_| panic!()));
 }
 
 #[test]
@@ -382,7 +382,7 @@ fn test_any() {
     assert!(v.iter().any(|&x| x < 10));
     assert!(v.iter().any(|&x| x % 2 == 0));
     assert!(!v.iter().any(|&x| x > 100));
-    assert!(!v[0..0].iter().any(|_| panic!()));
+    assert!(!v[..0].iter().any(|_| panic!()));
 }
 
 #[test]
index 96b50e8bccbad0c62c067522ee8a93a68ff781b9..3dc209e6fcb247fe41760e4da303dc7bb8899aad 100644 (file)
@@ -19,18 +19,14 @@ fn size_of_basic() {
 }
 
 #[test]
-#[cfg(any(target_arch = "x86",
-          target_arch = "arm",
-          target_arch = "mips",
-          target_arch = "mipsel"))]
+#[cfg(target_pointer_width = "32")]
 fn size_of_32() {
     assert_eq!(size_of::<uint>(), 4u);
     assert_eq!(size_of::<*const uint>(), 4u);
 }
 
 #[test]
-#[cfg(any(target_arch = "x86_64",
-          target_arch = "aarch64"))]
+#[cfg(target_pointer_width = "64")]
 fn size_of_64() {
     assert_eq!(size_of::<uint>(), 8u);
     assert_eq!(size_of::<*const uint>(), 8u);
@@ -52,18 +48,14 @@ fn align_of_basic() {
 }
 
 #[test]
-#[cfg(any(target_arch = "x86",
-          target_arch = "arm",
-          target_arch = "mips",
-          target_arch = "mipsel"))]
+#[cfg(target_pointer_width = "32")]
 fn align_of_32() {
     assert_eq!(align_of::<uint>(), 4u);
     assert_eq!(align_of::<*const uint>(), 4u);
 }
 
 #[test]
-#[cfg(any(target_arch = "x86_64",
-          target_arch = "aarch64"))]
+#[cfg(target_pointer_width = "64")]
 fn align_of_64() {
     assert_eq!(align_of::<uint>(), 8u);
     assert_eq!(align_of::<*const uint>(), 8u);
index 70ad8d28d271ff727f6841c3f2fd8a8e63d60e53..85944ccc5517c1c855152e0e10c12c0c2eb641b6 100644 (file)
@@ -286,7 +286,7 @@ fn format(&mut self) -> FormatSpec<'a> {
             flags: 0,
             precision: CountImplied,
             width: CountImplied,
-            ty: &self.input[0..0],
+            ty: &self.input[..0],
         };
         if !self.consume(':') { return spec }
 
@@ -395,7 +395,7 @@ fn word(&mut self) -> &'a str {
                 self.cur.next();
                 pos
             }
-            Some(..) | None => { return &self.input[0..0]; }
+            Some(..) | None => { return &self.input[..0]; }
         };
         let mut end;
         loop {
index c866deafee4569a84bb99985e4a760f27d9391e3..deab0cabfbe5195bfce29fbb75be076cdb0b4c55 100644 (file)
@@ -497,7 +497,8 @@ pub mod bsd44 {
         #[cfg(any(target_arch = "x86",
                   target_arch = "arm",
                   target_arch = "mips",
-                  target_arch = "mipsel"))]
+                  target_arch = "mipsel",
+                  target_arch = "powerpc"))]
         pub mod arch {
             pub mod c95 {
                 pub type c_char = i8;
@@ -528,7 +529,8 @@ pub mod c99 {
             }
             #[cfg(any(target_arch = "x86",
                       target_arch = "mips",
-                      target_arch = "mipsel"))]
+                      target_arch = "mipsel",
+                      target_arch = "powerpc"))]
             pub mod posix88 {
                 pub type off_t = i32;
                 pub type dev_t = u64;
@@ -642,7 +644,9 @@ pub mod posix01 {
                     pub __size: [u32; 9]
                 }
             }
-            #[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
+            #[cfg(any(target_arch = "mips",
+                      target_arch = "mipsel",
+                      target_arch = "powerpc"))]
             pub mod posix01 {
                 use types::os::arch::c95::{c_long, c_ulong, time_t};
                 use types::os::arch::posix88::{gid_t, ino_t};
@@ -2697,7 +2701,9 @@ pub mod posix88 {
             pub const EHWPOISON: c_int = 133;
         }
 
-        #[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
+        #[cfg(any(target_arch = "mips",
+                  target_arch = "mipsel",
+                  target_arch = "powerpc"))]
         pub mod posix88 {
             use types::os::arch::c95::c_int;
             use types::common::c95::c_void;
@@ -2982,7 +2988,8 @@ pub mod posix01 {
             #[cfg(all(target_os = "linux",
                       any(target_arch = "mips",
                           target_arch = "mipsel",
-                          target_arch = "aarch64")))]
+                          target_arch = "aarch64",
+                          target_arch = "powerpc")))]
             pub const PTHREAD_STACK_MIN: size_t = 131072;
 
             pub const CLOCK_REALTIME: c_int = 0;
@@ -3040,7 +3047,9 @@ pub mod bsd44 {
             pub const SHUT_WR: c_int = 1;
             pub const SHUT_RDWR: c_int = 2;
         }
-        #[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
+        #[cfg(any(target_arch = "mips",
+                  target_arch = "mipsel",
+                  target_arch = "powerpc"))]
         pub mod bsd44 {
             use types::os::arch::c95::c_int;
 
@@ -3115,7 +3124,9 @@ pub mod extra {
             pub const MAP_NONBLOCK : c_int = 0x010000;
             pub const MAP_STACK : c_int = 0x020000;
         }
-        #[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
+        #[cfg(any(target_arch = "mips",
+                  target_arch = "mipsel",
+                  target_arch = "powerpc"))]
         pub mod extra {
             use types::os::arch::c95::c_int;
 
index 4d605253ab06474c6671c4cdd8f416e45d373099..8430ee81c321462a6ee025850b8ce739a0b8bcff 100644 (file)
@@ -270,8 +270,7 @@ fn gen_ascii_chars<'a>(&'a mut self) -> AsciiGenerator<'a, Self> {
     /// let choices = [1i, 2, 4, 8, 16, 32];
     /// let mut rng = thread_rng();
     /// println!("{:?}", rng.choose(&choices));
-    /// # // uncomment when slicing syntax is stable
-    /// //assert_eq!(rng.choose(&choices[0..0]), None);
+    /// assert_eq!(rng.choose(&choices[..0]), None);
     /// ```
     fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> {
         if values.is_empty() {
index bdc00d7db97fe8e22da8b66d50826f459683b3ea..f39860c8695c96c8c629513fe4138b19f219e656 100644 (file)
@@ -95,7 +95,7 @@ fn write(&mut self, buf: &[u8]) -> IoResult<()> {
             // there (left), and what will be appended on the end (right)
             let cap = self.buf.len() - self.pos;
             let (left, right) = if cap <= buf.len() {
-                (&buf[0..cap], &buf[cap..])
+                (&buf[..cap], &buf[cap..])
             } else {
                 let result: (_, &[_]) = (buf, &[]);
                 result
index 8ed177c82a8f7c70749990544ef4c4e3e42f59a2..59808b302f47dff362678a63eb41cf1b073fffbf 100644 (file)
@@ -774,9 +774,8 @@ fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
                         warned |= check_must_use(cx, &it.attrs[], s.span);
                     }
                 } else {
-                    csearch::get_item_attrs(&cx.sess().cstore, did, |attrs| {
-                        warned |= check_must_use(cx, &attrs[], s.span);
-                    });
+                    let attrs = csearch::get_item_attrs(&cx.sess().cstore, did);
+                    warned |= check_must_use(cx, &attrs[], s.span);
                 }
             }
             _ => {}
@@ -1732,7 +1731,7 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
         let mut span = e.span;
 
         let id = match e.node {
-            ast::ExprPath(..) | ast::ExprStruct(..) => {
+            ast::ExprPath(..) | ast::ExprQPath(..) | ast::ExprStruct(..) => {
                 match cx.tcx.def_map.borrow().get(&e.id) {
                     Some(&def) => def.def_id(),
                     None => return
index a8326cc060ae75de1a50a76561ddad2d16f58811..5de683f8a4f076b8dd857fa53982483398601b20 100644 (file)
@@ -58,8 +58,8 @@ fn dump_crates(cstore: &CStore) {
         debug!("  hash: {}", data.hash());
         opt_source.map(|cs| {
             let CrateSource { dylib, rlib, cnum: _ } = cs;
-            dylib.map(|dl| debug!("  dylib: {}", dl.display()));
-            rlib.map(|rl|  debug!("   rlib: {}", rl.display()));
+            dylib.map(|dl| debug!("  dylib: {}", dl.0.display()));
+            rlib.map(|rl|  debug!("   rlib: {}", rl.0.display()));
         });
     })
 }
@@ -305,8 +305,8 @@ fn process_item(&self, i: &ast::Item) {
         }
     }
 
-    fn existing_match(&self, name: &str,
-                      hash: Option<&Svh>) -> Option<ast::CrateNum> {
+    fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind)
+                      -> Option<ast::CrateNum> {
         let mut ret = None;
         self.sess.cstore.iter_crate_data(|cnum, data| {
             if data.name != name { return }
@@ -317,27 +317,37 @@ fn existing_match(&self, name: &str,
                 None => {}
             }
 
-            // When the hash is None we're dealing with a top-level dependency in
-            // which case we may have a specification on the command line for this
-            // library. Even though an upstream library may have loaded something of
-            // the same name, we have to make sure it was loaded from the exact same
-            // location as well.
+            // When the hash is None we're dealing with a top-level dependency
+            // in which case we may have a specification on the command line for
+            // this library. Even though an upstream library may have loaded
+            // something of the same name, we have to make sure it was loaded
+            // from the exact same location as well.
             //
             // We're also sure to compare *paths*, not actual byte slices. The
             // `source` stores paths which are normalized which may be different
             // from the strings on the command line.
             let source = self.sess.cstore.get_used_crate_source(cnum).unwrap();
-            match self.sess.opts.externs.get(name) {
-                Some(locs) => {
-                    let found = locs.iter().any(|l| {
-                        let l = fs::realpath(&Path::new(&l[])).ok();
-                        l == source.dylib || l == source.rlib
-                    });
-                    if found {
-                        ret = Some(cnum);
-                    }
+            if let Some(locs) = self.sess.opts.externs.get(name) {
+                let found = locs.iter().any(|l| {
+                    let l = fs::realpath(&Path::new(&l[])).ok();
+                    source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
+                    source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
+                });
+                if found {
+                    ret = Some(cnum);
                 }
-                None => ret = Some(cnum),
+            }
+
+            // Alright, so we've gotten this far which means that `data` has the
+            // right name, we don't have a hash, and we don't have a --extern
+            // pointing for ourselves. We're still not quite yet done because we
+            // have to make sure that this crate was found in the crate lookup
+            // path (this is a top-level dependency) as we don't want to
+            // implicitly load anything inside the dependency lookup path.
+            let prev_kind = source.dylib.as_ref().or(source.rlib.as_ref())
+                                  .unwrap().1;
+            if ret.is_none() && (prev_kind == kind || prev_kind == PathKind::All) {
+                ret = Some(cnum);
             }
         });
         return ret;
@@ -359,8 +369,8 @@ fn register_crate(&mut self,
         let crate_paths = if root.is_none() {
             Some(CratePaths {
                 ident: ident.to_string(),
-                dylib: lib.dylib.clone(),
-                rlib:  lib.rlib.clone(),
+                dylib: lib.dylib.clone().map(|p| p.0),
+                rlib:  lib.rlib.clone().map(|p| p.0),
             })
         } else {
             None
@@ -400,7 +410,7 @@ fn resolve_crate(&mut self,
                      kind: PathKind)
                          -> (ast::CrateNum, Rc<cstore::crate_metadata>,
                              cstore::CrateSource) {
-        match self.existing_match(name, hash) {
+        match self.existing_match(name, hash, kind) {
             None => {
                 let mut load_ctxt = loader::Context {
                     sess: self.sess,
@@ -483,8 +493,8 @@ pub fn read_plugin_metadata<'b>(&'b mut self,
         let library = match load_ctxt.maybe_load_library_crate() {
             Some(l) => l,
             None if is_cross => {
-                // Try loading from target crates. This will abort later if we try to
-                // load a plugin registrar function,
+                // Try loading from target crates. This will abort later if we
+                // try to load a plugin registrar function,
                 target_only = true;
                 should_link = info.should_link;
 
@@ -497,7 +507,9 @@ pub fn read_plugin_metadata<'b>(&'b mut self,
         };
 
         let dylib = library.dylib.clone();
-        let register = should_link && self.existing_match(info.name.as_slice(), None).is_none();
+        let register = should_link && self.existing_match(info.name.as_slice(),
+                                                          None,
+                                                          PathKind::Crate).is_none();
         let metadata = if register {
             // Register crate now to avoid double-reading metadata
             let (_, cmd, _) = self.register_crate(&None, &info.ident[],
@@ -511,7 +523,7 @@ pub fn read_plugin_metadata<'b>(&'b mut self,
         PluginMetadata {
             sess: self.sess,
             metadata: metadata,
-            dylib: dylib,
+            dylib: dylib.map(|p| p.0),
             info: info,
             vi_span: span,
             target_only: target_only,
index cfff7c9935bc8ddefd18986be22f2710964d550c..e34fb37e1c5551b499270a49387b193550fc07b7 100644 (file)
@@ -203,13 +203,11 @@ pub fn get_methods_if_impl(cstore: &cstore::CStore,
     decoder::get_methods_if_impl(cstore.intr.clone(), &*cdata, def.node)
 }
 
-pub fn get_item_attrs<F>(cstore: &cstore::CStore,
-                         def_id: ast::DefId,
-                         f: F) where
-    F: FnOnce(Vec<ast::Attribute>),
-{
+pub fn get_item_attrs(cstore: &cstore::CStore,
+                      def_id: ast::DefId)
+                      -> Vec<ast::Attribute> {
     let cdata = cstore.get_crate_data(def_id.krate);
-    decoder::get_item_attrs(&*cdata, def_id.node, f)
+    decoder::get_item_attrs(&*cdata, def_id.node)
 }
 
 pub fn get_struct_fields(cstore: &cstore::CStore,
@@ -264,6 +262,15 @@ pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId,
     }
 }
 
+pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>,
+                               def: ast::DefId)
+                               -> Option<ast::ImplPolarity>
+{
+    let cstore = &tcx.sess.cstore;
+    let cdata = cstore.get_crate_data(def.krate);
+    decoder::get_impl_polarity(&*cdata, def.node)
+}
+
 // Given a def_id for an impl, return the trait it implements,
 // if there is one.
 pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
index ec0b80c3a5342f26b6af6563ab6a628b0f2810b1..49e03376a8cdd2100eb94fe8f3cd2313313f9bee 100644 (file)
@@ -20,6 +20,7 @@
 use back::svh::Svh;
 use metadata::decoder;
 use metadata::loader;
+use session::search_paths::PathKind;
 use util::nodemap::{FnvHashMap, NodeMap};
 
 use std::cell::RefCell;
@@ -65,8 +66,8 @@ pub enum NativeLibraryKind {
 // must be non-None.
 #[derive(PartialEq, Clone)]
 pub struct CrateSource {
-    pub dylib: Option<Path>,
-    pub rlib: Option<Path>,
+    pub dylib: Option<(Path, PathKind)>,
+    pub rlib: Option<(Path, PathKind)>,
     pub cnum: ast::CrateNum,
 }
 
@@ -178,10 +179,10 @@ fn visit(cstore: &CStore, cnum: ast::CrateNum,
         let mut libs = self.used_crate_sources.borrow()
             .iter()
             .map(|src| (src.cnum, match prefer {
-                RequireDynamic => src.dylib.clone(),
-                RequireStatic => src.rlib.clone(),
+                RequireDynamic => src.dylib.clone().map(|p| p.0),
+                RequireStatic => src.rlib.clone().map(|p| p.0),
             }))
-            .collect::<Vec<(ast::CrateNum, Option<Path>)>>();
+            .collect::<Vec<_>>();
         libs.sort_by(|&(a, _), &(b, _)| {
             ordering.position_elem(&a).cmp(&ordering.position_elem(&b))
         });
index 5ac8f908bf1642360d3e4f2ab461786eb573fefe..6bf1798d246a409e5b36e7d0531380e6e965c54d 100644 (file)
@@ -371,6 +371,15 @@ fn parse_unsafety(item_doc: rbml::Doc) -> ast::Unsafety {
     }
 }
 
+fn parse_polarity(item_doc: rbml::Doc) -> ast::ImplPolarity {
+    let polarity_doc = reader::get_doc(item_doc, tag_polarity);
+    if reader::doc_as_u8(polarity_doc) != 0 {
+        ast::ImplPolarity::Negative
+    } else {
+        ast::ImplPolarity::Positive
+    }
+}
+
 fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec<ast::Name> {
     let names_doc = reader::get_doc(item_doc, tag_associated_type_names);
     let mut names = Vec::new();
@@ -436,6 +445,20 @@ pub fn get_repr_attrs(cdata: Cmd, id: ast::NodeId) -> Vec<attr::ReprAttr> {
     }
 }
 
+pub fn get_impl_polarity<'tcx>(cdata: Cmd,
+                               id: ast::NodeId)
+                               -> Option<ast::ImplPolarity>
+{
+    let item_doc = lookup_item(id, cdata.data());
+    let fam = item_family(item_doc);
+    match fam {
+        Family::Impl => {
+            Some(parse_polarity(item_doc))
+        }
+        _ => None
+    }
+}
+
 pub fn get_impl_trait<'tcx>(cdata: Cmd,
                             id: ast::NodeId,
                             tcx: &ty::ctxt<'tcx>)
@@ -1025,18 +1048,16 @@ pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd,
     ret
 }
 
-pub fn get_item_attrs<F>(cdata: Cmd,
-                         orig_node_id: ast::NodeId,
-                         f: F) where
-    F: FnOnce(Vec<ast::Attribute>),
-{
+pub fn get_item_attrs(cdata: Cmd,
+                      orig_node_id: ast::NodeId)
+                      -> Vec<ast::Attribute> {
     // The attributes for a tuple struct are attached to the definition, not the ctor;
     // we assume that someone passing in a tuple struct ctor is actually wanting to
     // look at the definition
     let node_id = get_tuple_struct_definition_if_ctor(cdata, orig_node_id);
     let node_id = node_id.map(|x| x.node).unwrap_or(orig_node_id);
     let item = lookup_item(node_id, cdata.data());
-    f(get_attributes(item));
+    get_attributes(item)
 }
 
 pub fn get_struct_field_attrs(cdata: Cmd) -> HashMap<ast::NodeId, Vec<ast::Attribute>> {
index e8160487e16f73f1a7c36048a4e57c82498e4984..55a23aa516ecad697fe4f80e15db6e2debe4dd27 100644 (file)
@@ -39,13 +39,13 @@ pub struct FileSearch<'a> {
 
 impl<'a> FileSearch<'a> {
     pub fn for_each_lib_search_path<F>(&self, mut f: F) where
-        F: FnMut(&Path) -> FileMatch,
+        F: FnMut(&Path, PathKind) -> FileMatch,
     {
         let mut visited_dirs = HashSet::new();
         let mut found = false;
 
-        for path in self.search_paths.iter(self.kind) {
-            match f(path) {
+        for (path, kind) in self.search_paths.iter(self.kind) {
+            match f(path, kind) {
                 FileMatches => found = true,
                 FileDoesntMatch => ()
             }
@@ -54,9 +54,9 @@ pub fn for_each_lib_search_path<F>(&self, mut f: F) where
 
         debug!("filesearch: searching lib path");
         let tlib_path = make_target_lib_path(self.sysroot,
-                                    self.triple);
+                                             self.triple);
         if !visited_dirs.contains(tlib_path.as_vec()) {
-            match f(&tlib_path) {
+            match f(&tlib_path, PathKind::All) {
                 FileMatches => found = true,
                 FileDoesntMatch => ()
             }
@@ -76,7 +76,7 @@ pub fn for_each_lib_search_path<F>(&self, mut f: F) where
                     visited_dirs.insert(tlib_path.as_vec().to_vec());
                     // Don't keep searching the RUST_PATH if one match turns up --
                     // if we did, we'd get a "multiple matching crates" error
-                    match f(&tlib_path) {
+                    match f(&tlib_path, PathKind::All) {
                        FileMatches => {
                            break;
                        }
@@ -91,8 +91,10 @@ pub fn get_lib_path(&self) -> Path {
         make_target_lib_path(self.sysroot, self.triple)
     }
 
-    pub fn search<F>(&self, mut pick: F) where F: FnMut(&Path) -> FileMatch {
-        self.for_each_lib_search_path(|lib_search_path| {
+    pub fn search<F>(&self, mut pick: F)
+        where F: FnMut(&Path, PathKind) -> FileMatch
+    {
+        self.for_each_lib_search_path(|lib_search_path, kind| {
             debug!("searching {}", lib_search_path.display());
             match fs::readdir(lib_search_path) {
                 Ok(files) => {
@@ -108,7 +110,7 @@ fn is_rlib(p: & &Path) -> bool {
                     let files2 = files.iter().filter(|p| !is_rlib(p));
                     for path in files1.chain(files2) {
                         debug!("testing {}", path.display());
-                        let maybe_picked = pick(path);
+                        let maybe_picked = pick(path, kind);
                         match maybe_picked {
                             FileMatches => {
                                 debug!("picked {}", path.display());
@@ -142,7 +144,7 @@ pub fn new(sysroot: &'a Path,
     // Returns a list of directories where target-specific dylibs might be located.
     pub fn get_dylib_search_paths(&self) -> Vec<Path> {
         let mut paths = Vec::new();
-        self.for_each_lib_search_path(|lib_search_path| {
+        self.for_each_lib_search_path(|lib_search_path, _| {
             paths.push(lib_search_path.clone());
             FileDoesntMatch
         });
index f749721cca8c2a3da0269cb20b43e81ed42c35a8..70b6ddf23fd8d96a68aae6173c9dba33a279cf61 100644 (file)
 use back::archive::{METADATA_FILENAME};
 use back::svh::Svh;
 use session::Session;
+use session::search_paths::PathKind;
 use llvm;
 use llvm::{False, ObjectFile, mk_section_iter};
 use llvm::archive_ro::ArchiveRO;
 
 use std::ffi::CString;
 use std::cmp;
-use std::collections::{HashMap, HashSet};
+use std::collections::HashMap;
 use std::io::fs::PathExtensions;
 use std::io;
 use std::ptr;
@@ -260,8 +261,8 @@ pub struct Context<'a> {
 }
 
 pub struct Library {
-    pub dylib: Option<Path>,
-    pub rlib: Option<Path>,
+    pub dylib: Option<(Path, PathKind)>,
+    pub rlib: Option<(Path, PathKind)>,
     pub metadata: MetadataBlob,
 }
 
@@ -384,7 +385,7 @@ fn find_library_crate(&mut self) -> Option<Library> {
         // of the crate id (path/name/id).
         //
         // The goal of this step is to look at as little metadata as possible.
-        self.filesearch.search(|path| {
+        self.filesearch.search(|path, kind| {
             let file = match path.filename_str() {
                 None => return FileDoesntMatch,
                 Some(file) => file,
@@ -404,12 +405,12 @@ fn find_library_crate(&mut self) -> Option<Library> {
 
             let hash_str = hash.to_string();
             let slot = candidates.entry(hash_str).get().unwrap_or_else(
-                |vacant_entry| vacant_entry.insert((HashSet::new(), HashSet::new())));
+                |vacant_entry| vacant_entry.insert((HashMap::new(), HashMap::new())));
             let (ref mut rlibs, ref mut dylibs) = *slot;
             if rlib {
-                rlibs.insert(fs::realpath(path).unwrap());
+                rlibs.insert(fs::realpath(path).unwrap(), kind);
             } else {
-                dylibs.insert(fs::realpath(path).unwrap());
+                dylibs.insert(fs::realpath(path).unwrap(), kind);
             }
 
             FileMatches
@@ -453,16 +454,16 @@ fn find_library_crate(&mut self) -> Option<Library> {
                 self.sess.note("candidates:");
                 for lib in libraries.iter() {
                     match lib.dylib {
-                        Some(ref p) => {
+                        Some((ref p, _)) => {
                             self.sess.note(&format!("path: {}",
                                                    p.display())[]);
                         }
                         None => {}
                     }
                     match lib.rlib {
-                        Some(ref p) => {
+                        Some((ref p, _)) => {
                             self.sess.note(&format!("path: {}",
-                                                   p.display())[]);
+                                                    p.display())[]);
                         }
                         None => {}
                     }
@@ -483,9 +484,9 @@ fn find_library_crate(&mut self) -> Option<Library> {
     // read the metadata from it if `*slot` is `None`. If the metadata couldn't
     // be read, it is assumed that the file isn't a valid rust library (no
     // errors are emitted).
-    fn extract_one(&mut self, m: HashSet<Path>, flavor: &str,
-                   slot: &mut Option<MetadataBlob>) -> Option<Path> {
-        let mut ret = None::<Path>;
+    fn extract_one(&mut self, m: HashMap<Path, PathKind>, flavor: &str,
+                   slot: &mut Option<MetadataBlob>) -> Option<(Path, PathKind)> {
+        let mut ret = None::<(Path, PathKind)>;
         let mut error = 0u;
 
         if slot.is_some() {
@@ -500,7 +501,7 @@ fn extract_one(&mut self, m: HashSet<Path>, flavor: &str,
             }
         }
 
-        for lib in m.into_iter() {
+        for (lib, kind) in m.into_iter() {
             info!("{} reading metadata from: {}", flavor, lib.display());
             let metadata = match get_metadata_section(self.target.options.is_like_osx,
                                                       &lib) {
@@ -525,7 +526,7 @@ fn extract_one(&mut self, m: HashSet<Path>, flavor: &str,
                                            self.crate_name)[]);
                 self.sess.span_note(self.span,
                                     &format!(r"candidate #1: {}",
-                                            ret.as_ref().unwrap()
+                                            ret.as_ref().unwrap().0
                                                .display())[]);
                 error = 1;
                 ret = None;
@@ -538,7 +539,7 @@ fn extract_one(&mut self, m: HashSet<Path>, flavor: &str,
                 continue
             }
             *slot = Some(metadata);
-            ret = Some(lib);
+            ret = Some((lib, kind));
         }
         return if error > 0 {None} else {ret}
     }
@@ -606,8 +607,8 @@ fn find_commandline_library(&mut self) -> Option<Library> {
         // rlibs/dylibs.
         let sess = self.sess;
         let dylibname = self.dylibname();
-        let mut rlibs = HashSet::new();
-        let mut dylibs = HashSet::new();
+        let mut rlibs = HashMap::new();
+        let mut dylibs = HashMap::new();
         {
             let mut locs = locs.iter().map(|l| Path::new(&l[])).filter(|loc| {
                 if !loc.exists() {
@@ -637,13 +638,15 @@ fn find_commandline_library(&mut self) -> Option<Library> {
                 false
             });
 
-            // Now that we have an iterator of good candidates, make sure there's at
-            // most one rlib and at most one dylib.
+            // Now that we have an iterator of good candidates, make sure
+            // there's at most one rlib and at most one dylib.
             for loc in locs {
                 if loc.filename_str().unwrap().ends_with(".rlib") {
-                    rlibs.insert(fs::realpath(&loc).unwrap());
+                    rlibs.insert(fs::realpath(&loc).unwrap(),
+                                 PathKind::ExternFlag);
                 } else {
-                    dylibs.insert(fs::realpath(&loc).unwrap());
+                    dylibs.insert(fs::realpath(&loc).unwrap(),
+                                  PathKind::ExternFlag);
                 }
             }
         };
index b601ea59486ce6ee32e67218530700b0c20e75f4..07b520e5865b233b28e666d4b9dcfe1d32b7d118 100644 (file)
@@ -495,7 +495,8 @@ fn expr(&mut self, expr: &ast::Expr, pred: CFGIndex) -> CFGIndex {
             ast::ExprMac(..) |
             ast::ExprClosure(..) |
             ast::ExprLit(..) |
-            ast::ExprPath(..) => {
+            ast::ExprPath(..) |
+            ast::ExprQPath(..) => {
                 self.straightline(expr, pred, None::<ast::Expr>.iter())
             }
         }
index f4db2b6e61db2d7ba6bcf8e98a18a447f3c15f2e..3d8348e8f5a991ddc28ebf53b1ffabae028e59e0 100644 (file)
@@ -28,6 +28,8 @@ pub struct LabelledCFG<'a, 'ast: 'a> {
     pub ast_map: &'a ast_map::Map<'ast>,
     pub cfg: &'a cfg::CFG,
     pub name: String,
+    /// `labelled_edges` controls whether we emit labels on the edges
+    pub labelled_edges: bool,
 }
 
 fn replace_newline_with_backslash_l(s: String) -> String {
@@ -75,6 +77,9 @@ fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> {
 
     fn edge_label(&self, e: &Edge<'a>) -> dot::LabelText<'a> {
         let mut label = String::new();
+        if !self.labelled_edges {
+            return dot::LabelText::EscStr(label.into_cow());
+        }
         let mut put_one = false;
         for (i, &node_id) in e.data.exiting_scopes.iter().enumerate() {
             if put_one {
index 621d7274b3f7c01a41c3c386ab8c1c3cf4623c5d..202020a9033ed9ced58f1411ddf0573dbcf9ef5a 100644 (file)
@@ -111,7 +111,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) {
                            expression");
             }
         }
-        ast::ExprPath(_) => {
+        ast::ExprPath(_) | ast::ExprQPath(_) => {
             match v.tcx.def_map.borrow()[e.id] {
                 DefStatic(..) | DefConst(..) |
                 DefFn(..) | DefStaticMethod(..) | DefMethod(..) |
index 43f39a67f5c41b1d78b34b74a602d0965c2d9f40..a1a90395b3b783306c08c7a9f488348694a53a58 100644 (file)
@@ -926,7 +926,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
         }
     };
     head.map(|mut head| {
-        head.push_all(&r[0..col]);
+        head.push_all(&r[..col]);
         head.push_all(&r[(col + 1)..]);
         head
     })
index 154272d2deb41caefec580c198a041ed889d8cbe..026aa3c5ccf837d710b72c5db398759c010aa9c1 100644 (file)
@@ -228,7 +228,7 @@ fn visit_expr(&mut self, e: &ast::Expr) {
                           "{} are not allowed to have custom pointers",
                           self.msg());
             }
-            ast::ExprPath(..) => {
+            ast::ExprPath(_) | ast::ExprQPath(_) => {
                 match ty::resolve_expr(self.tcx, e) {
                     def::DefStatic(..) if self.mode == InConstant => {
                         let msg = "constants cannot refer to other statics, \
index e2a0738def180dd2c47a28e5968c7d14a21bb511..86a58dae45aa4c96676b6df893f1a8a2ba46a0c5 100644 (file)
@@ -93,7 +93,7 @@ fn visit_item(&mut self, it: &ast::Item) {
 
     fn visit_expr(&mut self, e: &ast::Expr) {
         match e.node {
-            ast::ExprPath(..) => {
+            ast::ExprPath(_) | ast::ExprQPath(_) => {
                 match self.def_map.borrow().get(&e.id) {
                     Some(&DefStatic(def_id, _)) |
                     Some(&DefConst(def_id)) if
index 52352e920ce36a3922683413684780e822e951d9..c998d178c22459b8c91a898ab4544370eed060d4 100644 (file)
@@ -244,7 +244,7 @@ fn classify(&mut self, e: &Expr) -> constness {
 
             // FIXME: (#3728) we can probably do something CCI-ish
             // surrounding nonlocal constants. But we don't yet.
-            ast::ExprPath(_) => self.lookup_constness(e),
+            ast::ExprPath(_) | ast::ExprQPath(_) => self.lookup_constness(e),
 
             ast::ExprRepeat(..) => general_const,
 
@@ -356,6 +356,13 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr) -> P<ast::Pat> {
             }
         }
 
+        ast::ExprQPath(_) => {
+            match lookup_const(tcx, expr) {
+                Some(actual) => return const_expr_to_pat(tcx, actual),
+                _ => unreachable!()
+            }
+        }
+
         _ => ast::PatLit(P(expr.clone()))
     };
     P(ast::Pat { id: expr.id, node: pat, span: expr.span })
@@ -542,7 +549,7 @@ macro_rules! define_casts {
                 ty::ty_float(ast::TyF64) => (f64, const_float, f64)
             }))
       }
-      ast::ExprPath(_) => {
+      ast::ExprPath(_) | ast::ExprQPath(_) => {
           match lookup_const(tcx, e) {
               Some(actual_e) => eval_const_expr_partial(tcx, &*actual_e),
               None => Err("non-constant path in constant expr".to_string())
index f7eea6e5cb7c9cc45da7be1b13ae6c291afd87a2..abb8f35f662b5e07604f03d873a7d0861a8b9c99 100644 (file)
@@ -175,7 +175,7 @@ fn visit_expr(&mut self, expr: &ast::Expr) {
             ast::ExprInlineAsm(..) => {
                 self.require_unsafe(expr.span, "use of inline assembly");
             }
-            ast::ExprPath(..) => {
+            ast::ExprPath(_) | ast::ExprQPath(_) => {
                 if let def::DefStatic(_, true) = ty::resolve_expr(self.tcx, expr) {
                     self.require_unsafe(expr.span, "use of mutable static");
                 }
index e5eb439d42c75a3fa6f20bb8b22e8bab50cc7059..a5f2dc398e9e2fddb71b4a1ff81811a591a65d3d 100644 (file)
@@ -424,7 +424,7 @@ pub fn walk_expr(&mut self, expr: &ast::Expr) {
                 self.walk_expr(&**subexpr)
             }
 
-            ast::ExprPath(..) => { }
+            ast::ExprPath(_) | ast::ExprQPath(_) => { }
 
             ast::ExprUnary(ast::UnDeref, ref base) => {      // *base
                 if !self.walk_overloaded_operator(expr, &**base, Vec::new(), PassArgs::ByRef) {
index 1b1dca004228eafb3d9e6074f254ae19b7128b15..6b9e5b2ceea3a6d4ba40df2e5724cc09717f9430 100644 (file)
@@ -447,7 +447,7 @@ fn visit_arm(ir: &mut IrMaps, arm: &ast::Arm) {
 fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
     match expr.node {
       // live nodes required for uses or definitions of variables:
-      ast::ExprPath(_) => {
+      ast::ExprPath(_) | ast::ExprQPath(_) => {
         let def = ir.tcx.def_map.borrow()[expr.id].clone();
         debug!("expr {}: path that leads to {:?}", expr.id, def);
         if let DefLocal(..) = def {
@@ -960,7 +960,7 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
         match expr.node {
           // Interesting cases with control flow or which gen/kill
 
-          ast::ExprPath(_) => {
+          ast::ExprPath(_) | ast::ExprQPath(_) => {
               self.access_path(expr, succ, ACC_READ | ACC_USE)
           }
 
@@ -1289,7 +1289,7 @@ fn propagate_through_lvalue_components(&mut self,
         // just ignore such cases and treat them as reads.
 
         match expr.node {
-            ast::ExprPath(_) => succ,
+            ast::ExprPath(_) | ast::ExprQPath(_) => succ,
             ast::ExprField(ref e, _) => self.propagate_through_expr(&**e, succ),
             ast::ExprTupField(ref e, _) => self.propagate_through_expr(&**e, succ),
             _ => self.propagate_through_expr(expr, succ)
@@ -1300,7 +1300,9 @@ fn propagate_through_lvalue_components(&mut self,
     fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: uint)
                     -> LiveNode {
         match expr.node {
-          ast::ExprPath(_) => self.access_path(expr, succ, acc),
+          ast::ExprPath(_) | ast::ExprQPath(_) => {
+              self.access_path(expr, succ, acc)
+          }
 
           // We do not track other lvalues, so just propagate through
           // to their subcomponents.  Also, it may happen that
@@ -1492,7 +1494,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       ast::ExprBlock(..) | ast::ExprMac(..) | ast::ExprAddrOf(..) |
       ast::ExprStruct(..) | ast::ExprRepeat(..) | ast::ExprParen(..) |
       ast::ExprClosure(..) | ast::ExprPath(..) | ast::ExprBox(..) |
-      ast::ExprRange(..) => {
+      ast::ExprRange(..) | ast::ExprQPath(..) => {
         visit::walk_expr(this, expr);
       }
       ast::ExprIfLet(..) => {
@@ -1583,7 +1585,7 @@ fn check_ret(&self,
 
     fn check_lvalue(&mut self, expr: &Expr) {
         match expr.node {
-            ast::ExprPath(_) => {
+            ast::ExprPath(_) | ast::ExprQPath(_) => {
                 if let DefLocal(nid) = self.ir.tcx.def_map.borrow()[expr.id].clone() {
                     // Assignment to an immutable variable or argument: only legal
                     // if there is no later assignment. If this local is actually
index 51ec75284326c4f76f9b790ef99b19cc654b76a4..90fe6b4991138d3fd8b45072efd8cf63f228be30 100644 (file)
@@ -520,7 +520,7 @@ pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
             }
           }
 
-          ast::ExprPath(_) => {
+          ast::ExprPath(_) | ast::ExprQPath(_) => {
             let def = (*self.tcx().def_map.borrow())[expr.id];
             self.cat_def(expr.id, expr.span, expr_ty, def)
           }
index aa37c2fe348b586c178e121114ac47d79b41d027..b92870cfa42b0d181ce1e8f3be12771646bd588e 100644 (file)
@@ -920,7 +920,7 @@ fn visit_expr(&mut self, expr: &ast::Expr) {
                                                             struct type?!"),
                 }
             }
-            ast::ExprPath(..) => {
+            ast::ExprPath(_) | ast::ExprQPath(_) => {
                 let guard = |&: did: ast::DefId| {
                     let fields = ty::lookup_struct_fields(self.tcx, did);
                     let any_priv = fields.iter().any(|f| {
index 906607ddc5ba14e77e205064b5f67a2425fb914c..b7e6da8c5f63aa29664cbaa9e7bfcd4a53fd20f4 100644 (file)
@@ -104,7 +104,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &ast::Expr) {
 
         match expr.node {
-            ast::ExprPath(_) => {
+            ast::ExprPath(_) | ast::ExprQPath(_) => {
                 let def = match self.tcx.def_map.borrow().get(&expr.id) {
                     Some(&def) => def,
                     None => {
index a6a6703353cd1ca12911f72ea3b6fb101eab43c8..017641bd3b71aeb6cbf4f6fbe75412c9fc2c6e4d 100644 (file)
@@ -12,7 +12,7 @@
 //
 // There are various parts of the compiler that must impose arbitrary limits
 // on how deeply they recurse to prevent stack overflow. Users can override
-// this via an attribute on the crate like `#![recursion_limit(22)]`. This pass
+// this via an attribute on the crate like `#![recursion_limit="22"]`. This pass
 // just peeks and looks for that attribute.
 
 use session::Session;
@@ -34,6 +34,6 @@ pub fn update_recursion_limit(sess: &Session, krate: &ast::Crate) {
         }
 
         sess.span_err(attr.span, "malformed recursion limit attribute, \
-                                  expected #![recursion_limit(\"N\")]");
+                                  expected #![recursion_limit=\"N\"]");
     }
 }
index 5d33a7efd3bee4c60eab14348c520feeee5e5cbc..8dcbc74f0eb6e6583cebaca4af0f6b53425924cf 100644 (file)
@@ -22,6 +22,8 @@
 use util::common::can_reach;
 
 use std::cell::RefCell;
+// NOTE(stage0) remove import after a snapshot
+#[cfg(stage0)]
 use std::hash::{Hash};
 use syntax::codemap::Span;
 use syntax::{ast, visit};
index 9ac6b8a86b68b10585fb191f64ca5552f3cb181a..9ad2dd499cc9deb56b69154a4213847f3167d72d 100644 (file)
@@ -19,7 +19,7 @@
 
 use std::fmt;
 use std::slice::Iter;
-use std::vec::Vec;
+use std::vec::{Vec, IntoIter};
 use syntax::codemap::{Span, DUMMY_SP};
 
 ///////////////////////////////////////////////////////////////////////////
@@ -397,6 +397,10 @@ pub fn iter<'a>(&'a self) -> Iter<'a,T> {
         self.content.iter()
     }
 
+    pub fn into_iter(self) -> IntoIter<T> {
+        self.content.into_iter()
+    }
+
     pub fn iter_enumerated<'a>(&'a self) -> EnumeratedItems<'a,T> {
         EnumeratedItems::new(self)
     }
index 6b4dd101286d664ec0195992e7dd29c48a2c6b09..6d0e60ec495a7bee25ea3fe8249befef125adf29 100644 (file)
@@ -70,7 +70,7 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                      span: Span) -> Option<String> {
     let def_id = trait_ref.def_id;
     let mut report = None;
-    ty::each_attr(infcx.tcx, def_id, |item| {
+    for item in ty::get_attrs(infcx.tcx, def_id).iter() {
         if item.check_name("rustc_on_unimplemented") {
             let err_sp = if item.meta().span == DUMMY_SP {
                 span
@@ -136,11 +136,9 @@ trait definition for {} must have a value, \
                                                  eg `#[rustc_on_unimplemented = \"foo\"]`",
                                                  trait_str).as_slice());
             }
-            false
-        } else {
-            true
+            break;
         }
-    });
+    }
     report
 }
 
@@ -163,66 +161,80 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
 
             note_obligation_cause(infcx, obligation);
         }
-        SelectionError::Unimplemented => {
-            match obligation.predicate {
-                ty::Predicate::Trait(ref trait_predicate) => {
-                    let trait_predicate =
-                        infcx.resolve_type_vars_if_possible(trait_predicate);
-                    if !trait_predicate.references_error() {
-                        let trait_ref = trait_predicate.to_poly_trait_ref();
-                        infcx.tcx.sess.span_err(
-                            obligation.cause.span,
-                            format!(
-                                "the trait `{}` is not implemented for the type `{}`",
-                                trait_ref.user_string(infcx.tcx),
-                                trait_ref.self_ty().user_string(infcx.tcx)).as_slice());
-                        // Check if it has a custom "#[rustc_on_unimplemented]" error message,
-                        // report with that message if it does
-                        let custom_note = report_on_unimplemented(infcx, &*trait_ref.0,
-                                                                  obligation.cause.span);
-                        if let Some(s) = custom_note {
-                           infcx.tcx.sess.span_note(obligation.cause.span,
-                                                    s.as_slice());
-                        }
-                    }
-                }
 
-                ty::Predicate::Equate(ref predicate) => {
-                    let predicate = infcx.resolve_type_vars_if_possible(predicate);
-                    let err = infcx.equality_predicate(obligation.cause.span,
-                                                             &predicate).unwrap_err();
+        SelectionError::Unimplemented => {
+            match &obligation.cause.code {
+                &ObligationCauseCode::CompareImplMethodObligation => {
                     infcx.tcx.sess.span_err(
                         obligation.cause.span,
                         format!(
-                            "the requirement `{}` is not satisfied (`{}`)",
-                            predicate.user_string(infcx.tcx),
-                            ty::type_err_to_str(infcx.tcx, &err)).as_slice());
+                            "the requirement `{}` appears on the impl \
+                            method but not on the corresponding trait method",
+                            obligation.predicate.user_string(infcx.tcx)).as_slice());
                 }
+                _ => {
+                    match obligation.predicate {
+                        ty::Predicate::Trait(ref trait_predicate) => {
+                            let trait_predicate =
+                                infcx.resolve_type_vars_if_possible(trait_predicate);
 
-                ty::Predicate::RegionOutlives(ref predicate) => {
-                    let predicate = infcx.resolve_type_vars_if_possible(predicate);
-                    let err = infcx.region_outlives_predicate(obligation.cause.span,
-                                                              &predicate).unwrap_err();
-                    infcx.tcx.sess.span_err(
-                        obligation.cause.span,
-                        format!(
-                            "the requirement `{}` is not satisfied (`{}`)",
-                            predicate.user_string(infcx.tcx),
-                            ty::type_err_to_str(infcx.tcx, &err)).as_slice());
-                }
+                            if !trait_predicate.references_error() {
+                                let trait_ref = trait_predicate.to_poly_trait_ref();
+                                infcx.tcx.sess.span_err(
+                                    obligation.cause.span,
+                                    format!(
+                                        "the trait `{}` is not implemented for the type `{}`",
+                                        trait_ref.user_string(infcx.tcx),
+                                        trait_ref.self_ty().user_string(infcx.tcx)).as_slice());
+                                // Check if it has a custom "#[rustc_on_unimplemented]"
+                                // error message, report with that message if it does
+                                let custom_note = report_on_unimplemented(infcx, &*trait_ref.0,
+                                                                          obligation.cause.span);
+                                if let Some(s) = custom_note {
+                                    infcx.tcx.sess.span_note(obligation.cause.span,
+                                                             s.as_slice());
+                                }
+                            }
+                        }
 
-                ty::Predicate::Projection(..) |
-                ty::Predicate::TypeOutlives(..) => {
-                    let predicate =
-                        infcx.resolve_type_vars_if_possible(&obligation.predicate);
-                    infcx.tcx.sess.span_err(
-                        obligation.cause.span,
-                        format!(
-                            "the requirement `{}` is not satisfied",
-                            predicate.user_string(infcx.tcx)).as_slice());
+                        ty::Predicate::Equate(ref predicate) => {
+                            let predicate = infcx.resolve_type_vars_if_possible(predicate);
+                            let err = infcx.equality_predicate(obligation.cause.span,
+                                                               &predicate).unwrap_err();
+                            infcx.tcx.sess.span_err(
+                                obligation.cause.span,
+                                format!(
+                                    "the requirement `{}` is not satisfied (`{}`)",
+                                    predicate.user_string(infcx.tcx),
+                                    ty::type_err_to_str(infcx.tcx, &err)).as_slice());
+                        }
+
+                        ty::Predicate::RegionOutlives(ref predicate) => {
+                            let predicate = infcx.resolve_type_vars_if_possible(predicate);
+                            let err = infcx.region_outlives_predicate(obligation.cause.span,
+                                                                      &predicate).unwrap_err();
+                            infcx.tcx.sess.span_err(
+                                obligation.cause.span,
+                                format!(
+                                    "the requirement `{}` is not satisfied (`{}`)",
+                                    predicate.user_string(infcx.tcx),
+                                    ty::type_err_to_str(infcx.tcx, &err)).as_slice());
+                        }
+
+                        ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
+                                let predicate =
+                                    infcx.resolve_type_vars_if_possible(&obligation.predicate);
+                                infcx.tcx.sess.span_err(
+                                    obligation.cause.span,
+                                    format!(
+                                        "the requirement `{}` is not satisfied",
+                                        predicate.user_string(infcx.tcx)).as_slice());
+                        }
+                    }
                 }
             }
         }
+
         OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
             let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref);
             let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref);
@@ -231,12 +243,12 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                     obligation.cause.span,
                     format!(
                         "type mismatch: the type `{}` implements the trait `{}`, \
-                         but the trait `{}` is required ({})",
+                        but the trait `{}` is required ({})",
                         expected_trait_ref.self_ty().user_string(infcx.tcx),
                         expected_trait_ref.user_string(infcx.tcx),
                         actual_trait_ref.user_string(infcx.tcx),
                         ty::type_err_to_str(infcx.tcx, e)).as_slice());
-                note_obligation_cause(infcx, obligation);
+                    note_obligation_cause(infcx, obligation);
             }
         }
     }
@@ -332,7 +344,7 @@ fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
 }
 
 fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
-                                        _predicate: &ty::Predicate<'tcx>,
+                                        predicate: &ty::Predicate<'tcx>,
                                         cause_span: Span,
                                         cause_code: &ObligationCauseCode<'tcx>)
 {
@@ -419,6 +431,12 @@ fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
             let parent_predicate = parent_trait_ref.as_predicate();
             note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
         }
+        ObligationCauseCode::CompareImplMethodObligation => {
+            span_note!(tcx.sess, cause_span,
+                      "the requirement `{}` appears on the impl method\
+                      but not on the corresponding trait method",
+                      predicate.user_string(infcx.tcx));
+        }
     }
 }
 
index 3502909251790d3566fa76ae73862e00d0e550d5..425765edf870c5c30cd56a007ca2d2a3d7e639c6 100644 (file)
@@ -121,9 +121,12 @@ pub enum ObligationCauseCode<'tcx> {
     // static items must have `Sync` type
     SharedStatic,
 
+
     BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
 
     ImplDerivedObligation(DerivedObligationCause<'tcx>),
+
+    CompareImplMethodObligation,
 }
 
 #[derive(Clone)]
index 2520434f68f26335b22f272fe1496bfab4c407ee..62649653a6972374b5be5bfb901882e28f52d3eb 100644 (file)
@@ -611,6 +611,7 @@ fn candidate_from_obligation_no_cache<'o>(&mut self,
             return Ok(None);
         }
 
+
         // If there are *NO* candidates, that there are no impls --
         // that we know of, anyway. Note that in the case where there
         // are unbound type variables within the obligation, it might
@@ -626,6 +627,17 @@ fn candidate_from_obligation_no_cache<'o>(&mut self,
 
         // Just one candidate left.
         let candidate = candidates.pop().unwrap();
+
+        match candidate {
+            ImplCandidate(def_id) => {
+                match ty::trait_impl_polarity(self.tcx(), def_id) {
+                    Some(ast::ImplPolarity::Negative) => return Err(Unimplemented),
+                    _ => {}
+                }
+            }
+            _ => {}
+        }
+
         Ok(Some(candidate))
     }
 
@@ -714,7 +726,7 @@ fn assemble_candidates<'o>(&mut self,
                 debug!("obligation self ty is {}",
                        obligation.predicate.0.self_ty().repr(self.tcx()));
 
-                try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec));
+                try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
 
                 try!(self.assemble_builtin_bound_candidates(ty::BoundCopy,
                                                             stack,
@@ -722,10 +734,10 @@ fn assemble_candidates<'o>(&mut self,
             }
             Some(bound @ ty::BoundSend) |
             Some(bound @ ty::BoundSync) => {
-                try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec));
+                try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
 
                 // No explicit impls were declared for this type, consider the fallback rules.
-                if candidates.vec.is_empty() {
+                if candidates.vec.is_empty() && !candidates.ambiguous {
                     try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates));
                 }
             }
@@ -741,7 +753,7 @@ fn assemble_candidates<'o>(&mut self,
                 // (And unboxed candidates only apply to the Fn/FnMut/etc traits.)
                 try!(self.assemble_unboxed_closure_candidates(obligation, &mut candidates));
                 try!(self.assemble_fn_pointer_candidates(obligation, &mut candidates));
-                try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec));
+                try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
                 self.assemble_candidates_from_object_ty(obligation, &mut candidates);
             }
         }
@@ -1013,9 +1025,12 @@ fn assemble_fn_pointer_candidates(&mut self,
     /// Search for impls that might apply to `obligation`.
     fn assemble_candidates_from_impls(&mut self,
                                       obligation: &TraitObligation<'tcx>,
-                                      candidate_vec: &mut Vec<SelectionCandidate<'tcx>>)
+                                      candidates: &mut SelectionCandidateSet<'tcx>)
                                       -> Result<(), SelectionError<'tcx>>
     {
+        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+        debug!("assemble_candidates_from_impls(self_ty={})", self_ty.repr(self.tcx()));
+
         let all_impls = self.all_impls(obligation.predicate.def_id());
         for &impl_def_id in all_impls.iter() {
             self.infcx.probe(|snapshot| {
@@ -1024,7 +1039,7 @@ fn assemble_candidates_from_impls(&mut self,
                 match self.match_impl(impl_def_id, obligation, snapshot,
                                       &skol_map, skol_obligation_trait_pred.trait_ref.clone()) {
                     Ok(_) => {
-                        candidate_vec.push(ImplCandidate(impl_def_id));
+                        candidates.vec.push(ImplCandidate(impl_def_id));
                     }
                     Err(()) => { }
                 }
@@ -1186,6 +1201,14 @@ fn candidate_should_be_dropped_in_favor_of<'o>(&mut self,
                         .is_ok()
                 })
             }
+            (&BuiltinCandidate(_), &ParamCandidate(_)) => {
+                // If we have a where-clause like `Option<K> : Send`,
+                // then we wind up in a situation where there is a
+                // default rule (`Option<K>:Send if K:Send) and the
+                // where-clause that both seem applicable. Just take
+                // the where-clause in that case.
+                true
+            }
             (&ProjectionCandidate, &ParamCandidate(_)) => {
                 // FIXME(#20297) -- this gives where clauses precedent
                 // over projections. Really these are just two means
@@ -2206,8 +2229,8 @@ fn push_stack<'o,'s:'o>(&mut self,
 
     /// Returns set of all impls for a given trait.
     fn all_impls(&self, trait_def_id: ast::DefId) -> Vec<ast::DefId> {
-        ty::populate_implementations_for_trait_if_necessary(self.tcx(),
-                                                            trait_def_id);
+        ty::populate_implementations_for_trait_if_necessary(self.tcx(), trait_def_id);
+
         match self.tcx().trait_impls.borrow().get(&trait_def_id) {
             None => Vec::new(),
             Some(impls) => impls.borrow().clone()
index cf30969ebefcc8540c3e6982c21475f57cc665e1..c72fbc745651a5049b8bc096d9e77cc8126a5074 100644 (file)
@@ -68,7 +68,7 @@
 use util::nodemap::{FnvHashMap};
 
 use arena::TypedArena;
-use std::borrow::BorrowFrom;
+use std::borrow::{BorrowFrom, Cow};
 use std::cell::{Cell, RefCell};
 use std::cmp::{self, Ordering};
 use std::fmt::{self, Show};
@@ -76,6 +76,7 @@
 use std::mem;
 use std::ops;
 use std::rc::Rc;
+use std::vec::CowVec;
 use collections::enum_set::{EnumSet, CLike};
 use std::collections::{HashMap, HashSet};
 use syntax::abi;
@@ -1890,7 +1891,7 @@ pub fn def_id(&self) -> ast::DefId {
 /// normal trait predicate (`T : TraitRef<...>`) and one of these
 /// predicates. Form #2 is a broader form in that it also permits
 /// equality between arbitrary types. Processing an instance of Form
-/// \#2 eventually yields one of these `ProjectionPredicate`
+/// #2 eventually yields one of these `ProjectionPredicate`
 /// instances to normalize the LHS.
 #[derive(Clone, PartialEq, Eq, Hash, Show)]
 pub struct ProjectionPredicate<'tcx> {
@@ -2604,12 +2605,17 @@ fn add_sty(&mut self, st: &sty) {
 
             &ty_projection(ref data) => {
                 self.add_flags(HAS_PROJECTION);
-                self.add_substs(data.trait_ref.substs);
+                self.add_projection_ty(data);
             }
 
             &ty_trait(box TyTrait { ref principal, ref bounds }) => {
                 let mut computation = FlagComputation::new();
                 computation.add_substs(principal.0.substs);
+                for projection_bound in bounds.projection_bounds.iter() {
+                    let mut proj_computation = FlagComputation::new();
+                    proj_computation.add_projection_predicate(&projection_bound.0);
+                    computation.add_bound_computation(&proj_computation);
+                }
                 self.add_bound_computation(&computation);
 
                 self.add_bounds(bounds);
@@ -2673,6 +2679,15 @@ fn add_region(&mut self, r: Region) {
         }
     }
 
+    fn add_projection_predicate(&mut self, projection_predicate: &ProjectionPredicate) {
+        self.add_projection_ty(&projection_predicate.projection_ty);
+        self.add_ty(projection_predicate.ty);
+    }
+
+    fn add_projection_ty(&mut self, projection_ty: &ProjectionTy) {
+        self.add_substs(projection_ty.trait_ref.substs);
+    }
+
     fn add_substs(&mut self, substs: &Substs) {
         self.add_tys(substs.types.as_slice());
         match substs.regions {
@@ -4132,12 +4147,8 @@ pub fn node_id_to_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId)
     }
 }
 
-pub fn try_node_id_to_type<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> Option<Ty<'tcx>> {
-    cx.node_types.borrow().get(&id).cloned()
-}
-
 pub fn node_id_to_type<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> Ty<'tcx> {
-    match try_node_id_to_type(cx, id) {
+    match node_id_to_type_opt(cx, id) {
        Some(ty) => ty,
        None => cx.sess.bug(
            &format!("node_id_to_type: no type for node `{}`",
@@ -4514,7 +4525,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
     }
 
     match expr.node {
-        ast::ExprPath(..) => {
+        ast::ExprPath(_) | ast::ExprQPath(_) => {
             match resolve_expr(tcx, expr) {
                 def::DefVariant(tid, vid, _) => {
                     let variant_info = enum_variant_with_id(tcx, tid, vid);
@@ -5024,6 +5035,23 @@ pub fn trait_items<'tcx>(cx: &ctxt<'tcx>, trait_did: ast::DefId)
     }
 }
 
+pub fn trait_impl_polarity<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
+                            -> Option<ast::ImplPolarity> {
+     if id.krate == ast::LOCAL_CRATE {
+         match cx.map.find(id.node) {
+             Some(ast_map::NodeItem(item)) => {
+                 match item.node {
+                     ast::ItemImpl(_, polarity, _, _, _, _) => Some(polarity),
+                     _ => None
+                 }
+             }
+             _ => None
+         }
+     } else {
+         csearch::get_impl_polarity(cx, id)
+     }
+}
+
 pub fn impl_or_trait_item<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
                                 -> ImplOrTraitItem<'tcx> {
     lookup_locally_or_in_crate_store("impl_or_trait_items",
@@ -5555,40 +5583,20 @@ pub fn predicates<'tcx>(
     vec
 }
 
-/// Iterate over attributes of a definition.
-// (This should really be an iterator, but that would require csearch and
-// decoder to use iterators instead of higher-order functions.)
-pub fn each_attr<F>(tcx: &ctxt, did: DefId, mut f: F) -> bool where
-    F: FnMut(&ast::Attribute) -> bool,
-{
+/// Get the attributes of a definition.
+pub fn get_attrs<'tcx>(tcx: &'tcx ctxt, did: DefId)
+                       -> CowVec<'tcx, ast::Attribute> {
     if is_local(did) {
         let item = tcx.map.expect_item(did.node);
-        item.attrs.iter().all(|attr| f(attr))
+        Cow::Borrowed(&item.attrs[])
     } else {
-        info!("getting foreign attrs");
-        let mut cont = true;
-        csearch::get_item_attrs(&tcx.sess.cstore, did, |attrs| {
-            if cont {
-                cont = attrs.iter().all(|attr| f(attr));
-            }
-        });
-        info!("done");
-        cont
+        Cow::Owned(csearch::get_item_attrs(&tcx.sess.cstore, did))
     }
 }
 
 /// Determine whether an item is annotated with an attribute
 pub fn has_attr(tcx: &ctxt, did: DefId, attr: &str) -> bool {
-    let mut found = false;
-    each_attr(tcx, did, |item| {
-        if item.check_name(attr) {
-            found = true;
-            false
-        } else {
-            true
-        }
-    });
-    found
+    get_attrs(tcx, did).iter().any(|item| item.check_name(attr))
 }
 
 /// Determine whether an item is annotated with `#[repr(packed)]`
@@ -5605,13 +5613,9 @@ pub fn lookup_simd(tcx: &ctxt, did: DefId) -> bool {
 pub fn lookup_repr_hints(tcx: &ctxt, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
     memoized(&tcx.repr_hint_cache, did, |did: DefId| {
         Rc::new(if did.krate == LOCAL_CRATE {
-            let mut acc = Vec::new();
-            ty::each_attr(tcx, did, |meta| {
-                acc.extend(attr::find_repr_attrs(tcx.sess.diagnostic(),
-                                                 meta).into_iter());
-                true
-            });
-            acc
+            get_attrs(tcx, did).iter().flat_map(|meta| {
+                attr::find_repr_attrs(tcx.sess.diagnostic(), meta).into_iter()
+            }).collect()
         } else {
             csearch::get_repr_attrs(&tcx.sess.cstore, did)
         })
@@ -5997,6 +6001,7 @@ pub fn item_variances(tcx: &ctxt, item_id: ast::DefId) -> Rc<ItemVariances> {
 pub fn record_trait_implementation(tcx: &ctxt,
                                    trait_def_id: DefId,
                                    impl_def_id: DefId) {
+
     match tcx.trait_impls.borrow().get(&trait_def_id) {
         Some(impls_for_trait) => {
             impls_for_trait.borrow_mut().push(impl_def_id);
@@ -6004,6 +6009,7 @@ pub fn record_trait_implementation(tcx: &ctxt,
         }
         None => {}
     }
+
     tcx.trait_impls.borrow_mut().insert(trait_def_id, Rc::new(RefCell::new(vec!(impl_def_id))));
 }
 
@@ -7364,3 +7370,15 @@ fn repr(&self, tcx: &ctxt<'tcx>) -> String {
                 self.mt.repr(tcx))
     }
 }
+
+impl<'a, 'tcx> Repr<'tcx> for ParameterEnvironment<'a, 'tcx> {
+    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+        format!("ParameterEnvironment(\
+            free_substs={}, \
+            implicit_region_bound={}, \
+            caller_bounds={})",
+            self.free_substs.repr(tcx),
+            self.implicit_region_bound.repr(tcx),
+            self.caller_bounds.repr(tcx))
+        }
+    }
index cab41d665297879ace454b0d88fa5f5a0ab72e1c..37886b4a1e1f670681be6705676362901d458074 100644 (file)
@@ -564,6 +564,18 @@ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::UnboxedClosureUpv
     }
 }
 
+impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where 'tcx: 'a {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ParameterEnvironment<'a, 'tcx> {
+        ty::ParameterEnvironment {
+            tcx: self.tcx,
+            free_substs: self.free_substs.fold_with(folder),
+            implicit_region_bound: self.implicit_region_bound.fold_with(folder),
+            caller_bounds: self.caller_bounds.fold_with(folder),
+            selection_cache: traits::SelectionCache::new(),
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // "super" routines: these are the default implementations for TypeFolder.
 //
index feec97f02da55dd204399f7bdf39066605298934..f6fb1c2d41928ad57cabd02a69f56cf9842474ff 100644 (file)
@@ -14,7 +14,7 @@
 use session::Session;
 
 use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
-use syntax::ext::base::{IdentTT, Decorator, Modifier, MacroRulesTT};
+use syntax::ext::base::{IdentTT, Decorator, Modifier, MultiModifier, MacroRulesTT};
 use syntax::ext::base::{MacroExpanderFn};
 use syntax::codemap::Span;
 use syntax::parse::token;
@@ -82,7 +82,7 @@ pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxEx
             IdentTT(ext, _) => IdentTT(ext, Some(self.krate_span)),
             Decorator(ext) => Decorator(ext),
             Modifier(ext) => Modifier(ext),
-
+            MultiModifier(ext) => MultiModifier(ext),
             MacroRulesTT => {
                 self.sess.err("plugin tried to register a new MacroRulesTT");
                 return;
index 27acc39c77863304291884edd0c70a4709556795..8a7c7b38287ecf4e2fb09b0b18bed0131daf4089 100644 (file)
@@ -174,6 +174,9 @@ pub fn span_help(&self, sp: Span, msg: &str) {
     pub fn fileline_note(&self, sp: Span, msg: &str) {
         self.diagnostic().fileline_note(sp, msg)
     }
+    pub fn fileline_help(&self, sp: Span, msg: &str) {
+        self.diagnostic().fileline_help(sp, msg)
+    }
     pub fn note(&self, msg: &str) {
         self.diagnostic().handler().note(msg)
     }
index 9bff54352179ec0c0d4785539a63b68825bbe986..0cf04fe0a006a94623155305a0b6fd2efb5805bc 100644 (file)
@@ -10,7 +10,7 @@
 
 use std::slice;
 
-#[derive(Clone)]
+#[derive(Clone, Show)]
 pub struct SearchPaths {
     paths: Vec<(PathKind, Path)>,
 }
@@ -20,11 +20,12 @@ pub struct Iter<'a> {
     iter: slice::Iter<'a, (PathKind, Path)>,
 }
 
-#[derive(Eq, PartialEq, Clone, Copy)]
+#[derive(Eq, PartialEq, Clone, Copy, Show)]
 pub enum PathKind {
     Native,
     Crate,
     Dependency,
+    ExternFlag,
     All,
 }
 
@@ -54,14 +55,16 @@ pub fn iter(&self, kind: PathKind) -> Iter {
 }
 
 impl<'a> Iterator for Iter<'a> {
-    type Item = &'a Path;
+    type Item = (&'a Path, PathKind);
 
-    fn next(&mut self) -> Option<&'a Path> {
+    fn next(&mut self) -> Option<(&'a Path, PathKind)> {
         loop {
             match self.iter.next() {
                 Some(&(kind, ref p)) if self.kind == PathKind::All ||
                                         kind == PathKind::All ||
-                                        kind == self.kind => return Some(p),
+                                        kind == self.kind => {
+                    return Some((p, kind))
+                }
                 Some(..) => {}
                 None => return None,
             }
index 559ec533baa9eca1ed0a67d7bbca462541c5ad9f..fb44d0cadfa6c8f50ba5965078236e948fc5b331 100644 (file)
@@ -542,7 +542,7 @@ pub fn parameterized<'tcx>(cx: &ctxt<'tcx>,
         0
     };
 
-    for t in tps[0..(tps.len() - num_defaults)].iter() {
+    for t in tps[..(tps.len() - num_defaults)].iter() {
         strs.push(ty_to_string(cx, *t))
     }
 
@@ -1430,7 +1430,7 @@ fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
 impl<'tcx> Repr<'tcx> for ty::ProjectionTy<'tcx> {
     fn repr(&self, tcx: &ctxt<'tcx>) -> String {
         format!("<{} as {}>::{}",
-                self.trait_ref.self_ty().repr(tcx),
+                self.trait_ref.substs.self_ty().repr(tcx),
                 self.trait_ref.repr(tcx),
                 self.item_name.repr(tcx))
     }
index ac5662f534c86c4fa229ac14eb590f679b6348af..e376ac50dcdf5ebd1055e6892a1409d1d257bdaf 100644 (file)
@@ -140,7 +140,7 @@ fn input<F>(&mut self, input: &[u8], mut func: F) where
             if input.len() >= buffer_remaining {
                     copy_memory(
                         self.buffer.slice_mut(self.buffer_idx, size),
-                        &input[0..buffer_remaining]);
+                        &input[..buffer_remaining]);
                 self.buffer_idx = 0;
                 func(&self.buffer);
                 i += buffer_remaining;
@@ -188,7 +188,7 @@ fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8] {
     fn full_buffer<'s>(&'s mut self) -> &'s [u8] {
         assert!(self.buffer_idx == 64);
         self.buffer_idx = 0;
-        return &self.buffer[0..64];
+        return &self.buffer[..64];
     }
 
     fn position(&self) -> uint { self.buffer_idx }
index 4e260da2e4dedd3ff176f35473410da6b1894f28..789a87bbcdafcd63a2f1aca5e8d2df7739e00223 100644 (file)
@@ -252,6 +252,7 @@ pub enum SawExprComponent<'a> {
         SawExprIndex,
         SawExprRange,
         SawExprPath,
+        SawExprQPath,
         SawExprAddrOf(ast::Mutability),
         SawExprRet,
         SawExprInlineAsm(&'a ast::InlineAsm),
@@ -285,6 +286,7 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
             ExprIndex(..)            => SawExprIndex,
             ExprRange(..)            => SawExprRange,
             ExprPath(..)             => SawExprPath,
+            ExprQPath(..)            => SawExprQPath,
             ExprAddrOf(m, _)         => SawExprAddrOf(m),
             ExprBreak(id)            => SawExprBreak(id.map(content)),
             ExprAgain(id)            => SawExprAgain(id.map(content)),
index 57e2744ae9bf8c467e33c47e5d4dc5c67e9d8915..f8eabb4375fb3b83bfa2015f48f96a9b2419341b 100644 (file)
@@ -72,6 +72,7 @@
 mod i686_unknown_linux_gnu;
 mod mips_unknown_linux_gnu;
 mod mipsel_unknown_linux_gnu;
+mod powerpc_unknown_linux_gnu;
 mod x86_64_apple_darwin;
 mod x86_64_apple_ios;
 mod x86_64_pc_windows_gnu;
@@ -95,7 +96,7 @@ pub struct Target {
     /// OS name to use for conditional compilation.
     pub target_os: String,
     /// Architecture to use for ABI considerations. Valid options: "x86", "x86_64", "arm",
-    /// "aarch64", and "mips". "mips" includes "mipsel".
+    /// "aarch64", "mips", and "powerpc". "mips" includes "mipsel".
     pub arch: String,
     /// Optional settings with defaults.
     pub options: TargetOptions,
@@ -339,6 +340,7 @@ macro_rules! load_specific {
             i686_unknown_linux_gnu,
             mips_unknown_linux_gnu,
             mipsel_unknown_linux_gnu,
+            powerpc_unknown_linux_gnu,
             arm_linux_androideabi,
             arm_unknown_linux_gnueabi,
             arm_unknown_linux_gnueabihf,
diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs
new file mode 100644 (file)
index 0000000..5e0b7bc
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use target::Target;
+
+pub fn target() -> Target {
+    let mut base = super::linux_base::opts();
+    base.pre_link_args.push("-m32".to_string());
+
+    Target {
+        data_layout: "E-S8-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string(),
+        llvm_target: "powerpc-unknown-linux-gnu".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "32".to_string(),
+        arch: "powerpc".to_string(),
+        target_os: "linux".to_string(),
+        options: base,
+    }
+}
index f35f8ab1b40f5cb741392bf2cb3b0390b0e1f0aa..be620c72178bbd0a4ee27403ebb578639a4ca39a 100644 (file)
@@ -103,6 +103,13 @@ macro_rules! controller_entry_point{($point: ident, $make_state: expr) => ({
 
         write_out_deps(&sess, input, &outputs, &id[]);
 
+        controller_entry_point!(after_write_deps,
+                                CompileState::state_after_write_deps(input,
+                                                                     &sess,
+                                                                     outdir,
+                                                                     &ast_map,
+                                                                     &id[]));
+
         let arenas = ty::CtxtArenas::new();
         let analysis = phase_3_run_analysis_passes(sess,
                                                    ast_map,
@@ -176,6 +183,7 @@ pub fn source_name(input: &Input) -> String {
 pub struct CompileController<'a> {
     pub after_parse: PhaseController<'a>,
     pub after_expand: PhaseController<'a>,
+    pub after_write_deps: PhaseController<'a>,
     pub after_analysis: PhaseController<'a>,
     pub after_llvm: PhaseController<'a>,
 
@@ -187,6 +195,7 @@ pub fn basic() -> CompileController<'a> {
         CompileController {
             after_parse: PhaseController::basic(),
             after_expand: PhaseController::basic(),
+            after_write_deps:  PhaseController::basic(),
             after_analysis: PhaseController::basic(),
             after_llvm: PhaseController::basic(),
             make_glob_map: resolve::MakeGlobMap::No,
@@ -271,6 +280,19 @@ fn state_after_expand(input: &'a Input,
         }
     }
 
+    fn state_after_write_deps(input: &'a Input,
+                              session: &'a Session,
+                              out_dir: &'a Option<Path>,
+                              ast_map: &'a ast_map::Map<'ast>,
+                              crate_name: &'a str)
+                              -> CompileState<'a, 'ast, 'tcx> {
+        CompileState {
+            crate_name: Some(crate_name),
+            ast_map: Some(ast_map),
+            .. CompileState::empty(input, session, out_dir)
+        }
+    }
+
     fn state_after_analysis(input: &'a Input,
                             session: &'a Session,
                             out_dir: &'a Option<Path>,
index ce2b03e17448a1398f2b93c34d720b84b2309b40..40a3eb9fe5b1d646314c76016e60e427b34b6758 100644 (file)
@@ -186,7 +186,7 @@ fn run_compiler(args: &[String]) {
                 list_metadata(&sess, &(*ifile), &mut stdout).unwrap();
             }
             Input::Str(_) => {
-                early_error("can not list metadata for stdin");
+                early_error("cannot list metadata for stdin");
             }
         }
         return;
@@ -207,7 +207,7 @@ fn build_controller<'a>(sess: &Session) -> CompileController<'a> {
     }
 
     if sess.opts.no_analysis || sess.opts.debugging_opts.ast_json {
-        control.after_expand.stop = true;
+        control.after_write_deps.stop = true;
     }
 
     if sess.opts.no_trans {
diff --git a/src/librustc_driver/mod.rs b/src/librustc_driver/mod.rs
deleted file mode 100644 (file)
index 1fbbc9c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
index 6429c5f59856e2394f23cf6ac85a489defb1d003..279442891bec0c631a91364d3cefd11c21baf831 100644 (file)
@@ -53,10 +53,20 @@ pub enum PpSourceMode {
     PpmExpandedHygiene,
 }
 
+
+#[derive(Copy, PartialEq, Show)]
+pub enum PpFlowGraphMode {
+    Default,
+    /// Drops the labels from the edges in the flowgraph output. This
+    /// is mostly for use in the --xpretty flowgraph run-make tests,
+    /// since the labels are largely uninteresting in those cases and
+    /// have become a pain to maintain.
+    UnlabelledEdges,
+}
 #[derive(Copy, PartialEq, Show)]
 pub enum PpMode {
     PpmSource(PpSourceMode),
-    PpmFlowGraph,
+    PpmFlowGraph(PpFlowGraphMode),
 }
 
 pub fn parse_pretty(sess: &Session,
@@ -73,12 +83,13 @@ pub fn parse_pretty(sess: &Session,
         ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
         ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
         ("identified", _)   => PpmSource(PpmIdentified),
-        ("flowgraph", true)    => PpmFlowGraph,
+        ("flowgraph", true)    => PpmFlowGraph(PpFlowGraphMode::Default),
+        ("flowgraph,unlabelled", true)    => PpmFlowGraph(PpFlowGraphMode::UnlabelledEdges),
         _ => {
             if extended {
                 sess.fatal(format!(
                     "argument to `xpretty` must be one of `normal`, \
-                     `expanded`, `flowgraph=<nodeid>`, `typed`, `identified`, \
+                     `expanded`, `flowgraph[,unlabelled]=<nodeid>`, `typed`, `identified`, \
                      `expanded,identified`, or `everybody_loops`; got {}", name).as_slice());
             } else {
                 sess.fatal(format!(
@@ -417,7 +428,7 @@ fn needs_ast_map(ppm: &PpMode, opt_uii: &Option<UserIdentifiedItem>) -> bool {
         PpmSource(PpmExpandedIdentified) |
         PpmSource(PpmExpandedHygiene) |
         PpmSource(PpmTyped) |
-        PpmFlowGraph => true
+        PpmFlowGraph(_) => true
     }
 }
 
@@ -431,7 +442,7 @@ fn needs_expansion(ppm: &PpMode) -> bool {
         PpmSource(PpmExpandedIdentified) |
         PpmSource(PpmExpandedHygiene) |
         PpmSource(PpmTyped) |
-        PpmFlowGraph => true
+        PpmFlowGraph(_) => true
     }
 }
 
@@ -589,7 +600,7 @@ pub fn pretty_print_input(sess: Session,
                     pp::eof(&mut pp_state.s)
                 }),
 
-        (PpmFlowGraph, opt_uii) => {
+        (PpmFlowGraph(mode), opt_uii) => {
             debug!("pretty printing flow graph for {:?}", opt_uii);
             let uii = opt_uii.unwrap_or_else(|| {
                 sess.fatal(&format!("`pretty flowgraph=..` needs NodeId (int) or
@@ -613,7 +624,7 @@ pub fn pretty_print_input(sess: Session,
                                                                        &arenas,
                                                                        id,
                                                                        resolve::MakeGlobMap::No);
-                    print_flowgraph(variants, analysis, code, out)
+                    print_flowgraph(variants, analysis, code, mode, out)
                 }
                 None => {
                     let message = format!("--pretty=flowgraph needs \
@@ -635,20 +646,23 @@ pub fn pretty_print_input(sess: Session,
 fn print_flowgraph<W:io::Writer>(variants: Vec<borrowck_dot::Variant>,
                                  analysis: ty::CrateAnalysis,
                                  code: blocks::Code,
+                                 mode: PpFlowGraphMode,
                                  mut out: W) -> io::IoResult<()> {
     let ty_cx = &analysis.ty_cx;
     let cfg = match code {
         blocks::BlockCode(block) => cfg::CFG::new(ty_cx, &*block),
         blocks::FnLikeCode(fn_like) => cfg::CFG::new(ty_cx, &*fn_like.body()),
     };
+    let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
+    let lcfg = LabelledCFG {
+        ast_map: &ty_cx.map,
+        cfg: &cfg,
+        name: format!("node_{}", code.id()),
+        labelled_edges: labelled_edges,
+    };
 
     match code {
         _ if variants.len() == 0 => {
-            let lcfg = LabelledCFG {
-                ast_map: &ty_cx.map,
-                cfg: &cfg,
-                name: format!("node_{}", code.id()),
-            };
             let r = dot::render(&lcfg, &mut out);
             return expand_err_details(r);
         }
@@ -662,11 +676,6 @@ fn print_flowgraph<W:io::Writer>(variants: Vec<borrowck_dot::Variant>,
             let (bccx, analysis_data) =
                 borrowck::build_borrowck_dataflow_data_for_fn(ty_cx, fn_parts);
 
-            let lcfg = LabelledCFG {
-                ast_map: &ty_cx.map,
-                cfg: &cfg,
-                name: format!("node_{}", code.id()),
-            };
             let lcfg = borrowck_dot::DataflowLabeller {
                 inner: lcfg,
                 variants: variants,
index a4f9b1f98d4c969cbc1bec5cae04130ad0e5a89c..3edb1ec48a023f00117ff00615ae6efc23a19bea 100644 (file)
@@ -1974,6 +1974,11 @@ pub fn LLVMDIBuilderCreateNameSpace(Builder: DIBuilderRef,
     pub fn LLVMInitializeMipsTargetMC();
     pub fn LLVMInitializeMipsAsmPrinter();
     pub fn LLVMInitializeMipsAsmParser();
+    pub fn LLVMInitializePowerPCTargetInfo();
+    pub fn LLVMInitializePowerPCTarget();
+    pub fn LLVMInitializePowerPCTargetMC();
+    pub fn LLVMInitializePowerPCAsmPrinter();
+    pub fn LLVMInitializePowerPCAsmParser();
 
     pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: *const c_char) -> bool;
     pub fn LLVMRustCreateTargetMachine(Triple: *const c_char,
@@ -2249,6 +2254,12 @@ pub unsafe fn static_link_hack_this_sucks() {
     LLVMInitializeMipsAsmPrinter();
     LLVMInitializeMipsAsmParser();
 
+    LLVMInitializePowerPCTargetInfo();
+    LLVMInitializePowerPCTarget();
+    LLVMInitializePowerPCTargetMC();
+    LLVMInitializePowerPCAsmPrinter();
+    LLVMInitializePowerPCAsmParser();
+
     LLVMRustSetLLVMOptions(0 as c_int,
                                        0 as *const _);
 
index ea6ecfbb92b4f2f3a90b685eaf48a0b56406a23f..7743a437858d2e97d3b4a350b8d81dfc7a750d4a 100644 (file)
@@ -61,7 +61,7 @@
 use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum};
 use syntax::ast::{DefId, Expr, ExprAgain, ExprBreak, ExprField};
 use syntax::ast::{ExprClosure, ExprForLoop, ExprLoop, ExprWhile, ExprMethodCall};
-use syntax::ast::{ExprPath, ExprStruct, FnDecl};
+use syntax::ast::{ExprPath, ExprQPath, ExprStruct, FnDecl};
 use syntax::ast::{ForeignItemFn, ForeignItemStatic, Generics};
 use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemFn};
 use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic};
@@ -2081,7 +2081,7 @@ fn resolve_module_path(&mut self,
                                             // idx +- 1 to account for the
                                             // colons on either side
                                             &mpath[(idx + 1)..],
-                                            &mpath[0..(idx - 1)]);
+                                            &mpath[..(idx - 1)]);
                         return Failed(Some((span, msg)));
                     },
                     None => {
@@ -3169,7 +3169,7 @@ fn resolve_trait_reference(&mut self,
                     TraitImplementation        => "implement",
                     TraitDerivation            => "derive",
                     TraitObject                => "reference",
-                    TraitQPath                 => "extract an associated type from",
+                    TraitQPath                 => "extract an associated item from",
                 };
 
                 let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str);
@@ -3565,31 +3565,17 @@ fn resolve_type(&mut self, ty: &Ty) {
                     }
                 }
 
-                match result_def {
-                    None => {
-                        match self.resolve_path(ty.id, path, TypeNS, true) {
-                            Some(def) => {
-                                debug!("(resolving type) resolved `{:?}` to \
-                                        type {:?}",
-                                       token::get_ident(path.segments.last().unwrap() .identifier),
-                                       def);
-                                result_def = Some(def);
-                            }
-                            None => {
-                                result_def = None;
-                            }
-                        }
-                    }
-                    Some(_) => {}   // Continue.
+                if let None = result_def {
+                    result_def = self.resolve_path(ty.id, path, TypeNS, true);
                 }
 
                 match result_def {
                     Some(def) => {
                         // Write the result into the def map.
                         debug!("(resolving type) writing resolution for `{}` \
-                                (id {})",
+                                (id {}) = {:?}",
                                self.path_names_to_string(path),
-                               path_id);
+                               path_id, def);
                         self.record_def(path_id, def);
                     }
                     None => {
@@ -3609,6 +3595,12 @@ fn resolve_type(&mut self, ty: &Ty) {
             TyQPath(ref qpath) => {
                 self.resolve_type(&*qpath.self_type);
                 self.resolve_trait_reference(ty.id, &*qpath.trait_ref, TraitQPath);
+                for ty in qpath.item_path.parameters.types().into_iter() {
+                    self.resolve_type(&**ty);
+                }
+                for binding in qpath.item_path.parameters.bindings().into_iter() {
+                    self.resolve_type(&*binding.ty);
+                }
             }
 
             TyPolyTraitRef(ref bounds) => {
@@ -4400,15 +4392,25 @@ fn resolve_expr(&mut self, expr: &Expr) {
             // The interpretation of paths depends on whether the path has
             // multiple elements in it or not.
 
-            ExprPath(ref path) => {
+            ExprPath(_) | ExprQPath(_) => {
+                let mut path_from_qpath;
+                let path = match expr.node {
+                    ExprPath(ref path) => path,
+                    ExprQPath(ref qpath) => {
+                        self.resolve_type(&*qpath.self_type);
+                        self.resolve_trait_reference(expr.id, &*qpath.trait_ref, TraitQPath);
+                        path_from_qpath = qpath.trait_ref.path.clone();
+                        path_from_qpath.segments.push(qpath.item_path.clone());
+                        &path_from_qpath
+                    }
+                    _ => unreachable!()
+                };
                 // This is a local path in the value namespace. Walk through
                 // scopes looking for it.
-
-                let path_name = self.path_names_to_string(path);
-
                 match self.resolve_path(expr.id, path, ValueNS, true) {
                     // Check if struct variant
                     Some((DefVariant(_, _, true), _)) => {
+                        let path_name = self.path_names_to_string(path);
                         self.resolve_error(expr.span,
                                 format!("`{}` is a struct variant name, but \
                                          this expression \
@@ -4423,7 +4425,7 @@ fn resolve_expr(&mut self, expr: &Expr) {
                     Some(def) => {
                         // Write the result into the def map.
                         debug!("(resolving expr) resolved `{}`",
-                               path_name);
+                               self.path_names_to_string(path));
 
                         self.record_def(expr.id, def);
                     }
@@ -4432,6 +4434,7 @@ fn resolve_expr(&mut self, expr: &Expr) {
                         // (The pattern matching def_tys where the id is in self.structs
                         // matches on regular structs while excluding tuple- and enum-like
                         // structs, which wouldn't result in this error.)
+                        let path_name = self.path_names_to_string(path);
                         match self.with_no_errors(|this|
                             this.resolve_path(expr.id, path, TypeNS, false)) {
                             Some((DefTy(struct_id, _), _))
index 351be70cf52614497b11564c976209cdd489af29..dacf620cbd1d0e1c7a5ef97465e1f65e60286159 100644 (file)
@@ -507,7 +507,7 @@ fn link_binary_output(sess: &Session,
 
 fn archive_search_paths(sess: &Session) -> Vec<Path> {
     let mut search = Vec::new();
-    sess.target_filesearch(PathKind::Native).for_each_lib_search_path(|path| {
+    sess.target_filesearch(PathKind::Native).for_each_lib_search_path(|path, _| {
         search.push(path.clone());
         FileDoesntMatch
     });
@@ -1043,7 +1043,7 @@ fn link_args(cmd: &mut Command,
 // in the current crate. Upstream crates with native library dependencies
 // may have their native library pulled in above.
 fn add_local_native_libraries(cmd: &mut Command, sess: &Session) {
-    sess.target_filesearch(PathKind::All).for_each_lib_search_path(|path| {
+    sess.target_filesearch(PathKind::All).for_each_lib_search_path(|path, _| {
         cmd.arg("-L").arg(path);
         FileDoesntMatch
     });
@@ -1146,10 +1146,10 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
         let src = sess.cstore.get_used_crate_source(cnum).unwrap();
         match kind {
             cstore::RequireDynamic => {
-                add_dynamic_crate(cmd, sess, src.dylib.unwrap())
+                add_dynamic_crate(cmd, sess, src.dylib.unwrap().0)
             }
             cstore::RequireStatic => {
-                add_static_crate(cmd, sess, tmpdir, src.rlib.unwrap())
+                add_static_crate(cmd, sess, tmpdir, src.rlib.unwrap().0)
             }
         }
 
index b6a6b526faccd5662c67e25225f84863673c5853..c0b1492a7845099c2d22a2a13f5738c269b11d2c 100644 (file)
@@ -167,7 +167,10 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
         llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
         llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);
 
+        let opt = sess.opts.cg.opt_level.unwrap_or(0) as libc::c_uint;
+
         let builder = llvm::LLVMPassManagerBuilderCreate();
+        llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt);
         llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,
             /* Internalize = */ False,
             /* RunInliner = */ True);
@@ -186,7 +189,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
 fn is_versioned_bytecode_format(bc: &[u8]) -> bool {
     let magic_id_byte_count = link::RLIB_BYTECODE_OBJECT_MAGIC.len();
     return bc.len() > magic_id_byte_count &&
-           &bc[0..magic_id_byte_count] == link::RLIB_BYTECODE_OBJECT_MAGIC;
+           &bc[..magic_id_byte_count] == link::RLIB_BYTECODE_OBJECT_MAGIC;
 }
 
 fn extract_bytecode_format_version(bc: &[u8]) -> u32 {
index c818dda7581bd02aa32c737e21c5b7bada86f067..aa51b0c5ee24805ed20c327d30ad40d15a643041 100644 (file)
@@ -1039,6 +1039,12 @@ unsafe fn configure_llvm(sess: &Session) {
         llvm::LLVMInitializeMipsAsmPrinter();
         llvm::LLVMInitializeMipsAsmParser();
 
+        llvm::LLVMInitializePowerPCTargetInfo();
+        llvm::LLVMInitializePowerPCTarget();
+        llvm::LLVMInitializePowerPCTargetMC();
+        llvm::LLVMInitializePowerPCAsmPrinter();
+        llvm::LLVMInitializePowerPCAsmParser();
+
         llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
                                      llvm_args.as_ptr());
     });
index 1bd8e01817485732cf82ad4106c17b97b8c70901..b12903c814cbf83db5e50deac0fda6bc6e189175 100644 (file)
@@ -186,7 +186,7 @@ fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) {
         if len <= 2 {
             return;
         }
-        let sub_paths = &sub_paths[0..(len-2)];
+        let sub_paths = &sub_paths[..(len-2)];
         for &(ref span, ref qualname) in sub_paths.iter() {
             self.fmt.sub_mod_ref_str(path.span,
                                      *span,
@@ -278,7 +278,7 @@ fn process_method(&mut self, method: &ast::Method) {
         // The qualname for a method is the trait name or name of the struct in an impl in
         // which the method is declared in followed by the method's name.
         let mut qualname = match ty::impl_of_method(&self.analysis.ty_cx,
-                                                ast_util::local_def(method.id)) {
+                                                    ast_util::local_def(method.id)) {
             Some(impl_id) => match self.analysis.ty_cx.map.get(impl_id.node) {
                 NodeItem(item) => {
                     scope_id = item.id;
@@ -349,7 +349,7 @@ fn process_method(&mut self, method: &ast::Method) {
             .and_then(|def_id| {
                 if match def_id {
                     ty::MethodTraitItemId(def_id) => {
-                        method.id != 0 && def_id.node == 0
+                        def_id.node != 0 && def_id != ast_util::local_def(method.id)
                     }
                     ty::TypeTraitItemId(_) => false,
                 } {
@@ -392,8 +392,7 @@ fn process_method(&mut self, method: &ast::Method) {
     }
 
     fn process_trait_ref(&mut self,
-                         trait_ref: &ast::TraitRef,
-                         impl_id: Option<NodeId>) {
+                         trait_ref: &ast::TraitRef) {
         match self.lookup_type_ref(trait_ref.ref_id) {
             Some(id) => {
                 let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
@@ -402,14 +401,6 @@ fn process_trait_ref(&mut self,
                                  sub_span,
                                  id,
                                  self.cur_scope);
-                match impl_id {
-                    Some(impl_id) => self.fmt.impl_str(trait_ref.path.span,
-                                                       sub_span,
-                                                       impl_id,
-                                                       id,
-                                                       self.cur_scope),
-                    None => (),
-                }
                 visit::walk_path(self, &trait_ref.path);
             },
             None => ()
@@ -652,7 +643,9 @@ fn process_impl(&mut self,
                     trait_ref: &Option<ast::TraitRef>,
                     typ: &ast::Ty,
                     impl_items: &Vec<ast::ImplItem>) {
+        let trait_id = trait_ref.as_ref().and_then(|tr| self.lookup_type_ref(tr.ref_id));
         match typ.node {
+            // Common case impl for a struct or something basic.
             ast::TyPath(ref path, id) => {
                 match self.lookup_type_ref(id) {
                     Some(id) => {
@@ -665,17 +658,29 @@ fn process_impl(&mut self,
                         self.fmt.impl_str(path.span,
                                           sub_span,
                                           item.id,
-                                          id,
+                                          Some(id),
+                                          trait_id,
                                           self.cur_scope);
                     },
                     None => ()
                 }
             },
-            _ => self.visit_ty(&*typ),
+            _ => {
+                // Less useful case, impl for a compound type.
+                self.visit_ty(&*typ);
+
+                let sub_span = self.span.sub_span_for_type_name(typ.span);
+                self.fmt.impl_str(typ.span,
+                                  sub_span,
+                                  item.id,
+                                  None,
+                                  trait_id,
+                                  self.cur_scope);
+            }
         }
 
         match *trait_ref {
-            Some(ref trait_ref) => self.process_trait_ref(trait_ref, Some(item.id)),
+            Some(ref trait_ref) => self.process_trait_ref(trait_ref),
             None => (),
         }
 
@@ -767,7 +772,7 @@ fn process_path(&mut self,
                     span: Span,
                     path: &ast::Path,
                     ref_kind: Option<recorder::Row>) {
-        if generated_code(path.span) {
+        if generated_code(span) {
             return
         }
 
@@ -1076,7 +1081,7 @@ fn visit_generics(&mut self, generics: &ast::Generics) {
         for param in generics.ty_params.iter() {
             for bound in param.bounds.iter() {
                 if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
-                    self.process_trait_ref(&trait_ref.trait_ref, None);
+                    self.process_trait_ref(&trait_ref.trait_ref);
                 }
             }
             if let Some(ref ty) = param.default {
@@ -1307,9 +1312,15 @@ fn visit_expr(&mut self, ex: &ast::Expr) {
                 visit::walk_expr(self, ex);
             },
             ast::ExprPath(ref path) => {
-                self.process_path(ex.id, ex.span, path, None);
+                self.process_path(ex.id, path.span, path, None);
                 visit::walk_path(self, path);
             }
+            ast::ExprQPath(ref qpath) => {
+                let mut path = qpath.trait_ref.path.clone();
+                path.segments.push(qpath.item_path.clone());
+                self.process_path(ex.id, ex.span, &path, None);
+                visit::walk_qpath(self, ex.span, &**qpath);
+            }
             ast::ExprStruct(ref path, ref fields, ref base) =>
                 self.process_struct_lit(ex, path, fields, base),
             ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args),
@@ -1439,7 +1450,7 @@ fn visit_arm(&mut self, arm: &ast::Arm) {
                                           "")
                 }
                 def::DefVariant(..) => {
-                    paths_to_process.push((id, p.span, p.clone(), Some(ref_kind)))
+                    paths_to_process.push((id, p.clone(), Some(ref_kind)))
                 }
                 // FIXME(nrc) what are these doing here?
                 def::DefStatic(_, _) => {}
@@ -1448,8 +1459,8 @@ fn visit_arm(&mut self, arm: &ast::Arm) {
                             *def)
             }
         }
-        for &(id, span, ref path, ref_kind) in paths_to_process.iter() {
-            self.process_path(id, span, path, ref_kind);
+        for &(id, ref path, ref_kind) in paths_to_process.iter() {
+            self.process_path(id, path.span, path, ref_kind);
         }
         self.collecting = false;
         self.collected_paths.clear();
index 23598751c08d73c724f0947d6bd0c312bc361723..eefaeca8306c638cd6a57017785dd502a75c7ed2 100644 (file)
@@ -19,6 +19,8 @@
 use syntax::ast::{NodeId,DefId};
 use syntax::codemap::*;
 
+const ZERO_DEF_ID: DefId = DefId { node: 0, krate: 0 };
+
 pub struct Recorder {
     // output file
     pub out: Box<Writer+'static>,
@@ -121,7 +123,9 @@ fn lookup_row(r: Row) -> (&'static str, Vec<&'static str>, bool, bool) {
             MethodDecl => ("method_decl", vec!("id","qualname","scopeid"), true, true),
             Struct => ("struct", vec!("id","ctor_id","qualname","scopeid","value"), true, true),
             Trait => ("trait", vec!("id","qualname","scopeid","value"), true, true),
-            Impl => ("impl", vec!("id","refid","refidcrate","scopeid"), true, true),
+            Impl => ("impl",
+                     vec!("id","refid","refidcrate","traitid","traitidcrate","scopeid"),
+                     true, true),
             Module => ("module", vec!("id","qualname","scopeid","def_file"), true, false),
             UseAlias => ("use_alias",
                          vec!("id","refid","refidcrate","name","scopeid"),
@@ -166,7 +170,7 @@ pub fn make_values_str(&self,
         let values = values.iter().map(|s| {
             // Never take more than 1020 chars
             if s.len() > 1020 {
-                &s[0..1020]
+                &s[..1020]
             } else {
                 &s[]
             }
@@ -444,12 +448,20 @@ pub fn impl_str(&mut self,
                     span: Span,
                     sub_span: Option<Span>,
                     id: NodeId,
-                    ref_id: DefId,
+                    ref_id: Option<DefId>,
+                    trait_id: Option<DefId>,
                     scope_id: NodeId) {
+        let ref_id = ref_id.unwrap_or(ZERO_DEF_ID);
+        let trait_id = trait_id.unwrap_or(ZERO_DEF_ID);
         self.check_and_record(Impl,
                               span,
                               sub_span,
-                              svec!(id, ref_id.node, ref_id.krate, scope_id));
+                              svec!(id,
+                                    ref_id.node,
+                                    ref_id.krate,
+                                    trait_id.node,
+                                    trait_id.krate,
+                                    scope_id));
     }
 
     pub fn mod_str(&mut self,
index fc19a582db2f5d070381891f816ee0bd699eb874..be927503badd1d74d78ddb2a555f8f31569721ae 100644 (file)
 use trans::adt;
 use trans::base::*;
 use trans::build::{AddCase, And, BitCast, Br, CondBr, GEPi, InBoundsGEP, Load};
-use trans::build::{Mul, Not, Store, Sub, add_comment};
+use trans::build::{Not, Store, Sub, add_comment};
 use trans::build;
 use trans::callee;
 use trans::cleanup::{self, CleanupMethods};
@@ -471,7 +471,7 @@ fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     // Collect all of the matches that can match against anything.
     enter_match(bcx, dm, m, col, val, |pats| {
         if pat_is_binding_or_wild(dm, &*pats[col]) {
-            let mut r = pats[0..col].to_vec();
+            let mut r = pats[..col].to_vec();
             r.push_all(&pats[(col + 1)..]);
             Some(r)
         } else {
@@ -630,8 +630,7 @@ fn bind_subslice_pat(bcx: Block,
     let vec_datum = match_datum(val, vec_ty);
     let (base, len) = vec_datum.get_vec_base_and_len(bcx);
 
-    let slice_byte_offset = Mul(bcx, vt.llunit_size, C_uint(bcx.ccx(), offset_left));
-    let slice_begin = tvec::pointer_add_byte(bcx, base, slice_byte_offset);
+    let slice_begin = InBoundsGEP(bcx, base, &[C_uint(bcx.ccx(), offset_left)]);
     let slice_len_offset = C_uint(bcx.ccx(), offset_left + offset_right);
     let slice_len = Sub(bcx, len, slice_len_offset);
     let slice_ty = ty::mk_slice(bcx.tcx(),
@@ -857,16 +856,9 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch);
         }
 
-        debug!("binding {} to {}",
-               binding_info.id,
-               bcx.val_to_string(llval));
+        debug!("binding {} to {}", binding_info.id, bcx.val_to_string(llval));
         bcx.fcx.lllocals.borrow_mut().insert(binding_info.id, datum);
-
-        if bcx.sess().opts.debuginfo == FullDebugInfo {
-            debuginfo::create_match_binding_metadata(bcx,
-                                                     ident,
-                                                     binding_info);
-        }
+        debuginfo::create_match_binding_metadata(bcx, ident, binding_info);
     }
     bcx
 }
@@ -1235,7 +1227,7 @@ pub fn trans_match<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 /// Checks whether the binding in `discr` is assigned to anywhere in the expression `body`
 fn is_discr_reassigned(bcx: Block, discr: &ast::Expr, body: &ast::Expr) -> bool {
     let (vid, field) = match discr.node {
-        ast::ExprPath(..) => match bcx.def(discr.id) {
+        ast::ExprPath(_) | ast::ExprQPath(_) => match bcx.def(discr.id) {
             def::DefLocal(vid) | def::DefUpvar(vid, _, _) => (vid, None),
             _ => return false
         },
index 9b6fa32405ffb9c2247318779d675967f65a67a2..05abd3ff5577d7b211a0a59a2ded4b493aeccf8f 100644 (file)
@@ -161,10 +161,7 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
 // Default per-arch clobbers
 // Basically what clang does
 
-#[cfg(any(target_arch = "arm",
-          target_arch = "aarch64",
-          target_arch = "mips",
-          target_arch = "mipsel"))]
+#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
 fn get_clobbers() -> String {
     "".to_string()
 }
index ea98d6bb74e9504b502c5f41e8aff2424aede395..3072bcae0bfb9a927d27059f6aa3d94ec9b6f249 100644 (file)
@@ -44,7 +44,7 @@
 use middle::weak_lang_items;
 use middle::subst::{Subst, Substs};
 use middle::ty::{self, Ty, UnboxedClosureTyper};
-use session::config::{self, NoDebugInfo, FullDebugInfo};
+use session::config::{self, NoDebugInfo};
 use session::Session;
 use trans::_match;
 use trans::adt;
@@ -248,9 +248,8 @@ fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>,
 
     let f = decl_rust_fn(ccx, fn_ty, name);
 
-    csearch::get_item_attrs(&ccx.sess().cstore, did, |attrs| {
-        set_llvm_fn_attrs(ccx, &attrs[], f)
-    });
+    let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did);
+    set_llvm_fn_attrs(ccx, &attrs[], f);
 
     ccx.externs().borrow_mut().insert(name.to_string(), f);
     f
@@ -353,12 +352,11 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
         // don't do this then linker errors can be generated where the linker
         // complains that one object files has a thread local version of the
         // symbol and another one doesn't.
-        ty::each_attr(ccx.tcx(), did, |attr| {
+        for attr in ty::get_attrs(ccx.tcx(), did).iter() {
             if attr.check_name("thread_local") {
                 llvm::set_thread_local(c, true);
             }
-            true
-        });
+        }
         ccx.externs().borrow_mut().insert(name.to_string(), c);
         return c;
     }
@@ -546,15 +544,6 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 }
 
-// Structural comparison: a rather involved form of glue.
-pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) {
-    if cx.sess().opts.cg.save_temps {
-        let buf = CString::from_slice(s.as_bytes());
-        unsafe { llvm::LLVMSetValueName(v, buf.as_ptr()) }
-    }
-}
-
-
 // Used only for creating scalar comparison glue.
 #[derive(Copy)]
 pub enum scalar_type { nil_type, signed_int, unsigned_int, floating_point, }
@@ -702,9 +691,8 @@ fn iter_variant<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
         let mut cx = cx;
 
         for (i, &arg) in variant.args.iter().enumerate() {
-            cx = (*f)(cx,
-                   adt::trans_field_ptr(cx, repr, av, variant.disr_val, i),
-                   arg.subst(tcx, substs));
+            let arg = monomorphize::apply_param_substs(tcx, substs, &arg);
+            cx = f(cx, adt::trans_field_ptr(cx, repr, av, variant.disr_val, i), arg);
         }
         return cx;
     }
@@ -1629,9 +1617,8 @@ fn create_datums_for_fn_args_under_call_abi<'blk, 'tcx>(
     result
 }
 
-fn copy_args_to_allocas<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>,
+fn copy_args_to_allocas<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                     arg_scope: cleanup::CustomScopeIndex,
-                                    bcx: Block<'blk, 'tcx>,
                                     args: &[ast::Arg],
                                     arg_datums: Vec<RvalueDatum<'tcx>>)
                                     -> Block<'blk, 'tcx> {
@@ -1652,10 +1639,7 @@ fn copy_args_to_allocas<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>,
         // the event it's not truly needed.
 
         bcx = _match::store_arg(bcx, &*args[i].pat, arg_datum, arg_scope_id);
-
-        if fcx.ccx.sess().opts.debuginfo == FullDebugInfo {
-            debuginfo::create_argument_metadata(bcx, &args[i]);
-        }
+        debuginfo::create_argument_metadata(bcx, &args[i]);
     }
 
     bcx
@@ -1705,9 +1689,7 @@ fn copy_unboxed_closure_args_to_allocas<'blk, 'tcx>(
                                 tuple_element_datum,
                                 arg_scope_id);
 
-        if bcx.fcx.ccx.sess().opts.debuginfo == FullDebugInfo {
-            debuginfo::create_argument_metadata(bcx, &args[j]);
-        }
+        debuginfo::create_argument_metadata(bcx, &args[j]);
     }
 
     bcx
@@ -1880,9 +1862,8 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     bcx = match closure_env.kind {
         closure::NotClosure | closure::BoxedClosure(..) => {
-            copy_args_to_allocas(&fcx,
+            copy_args_to_allocas(bcx,
                                  arg_scope,
-                                 bcx,
                                  &decl.inputs[],
                                  arg_datums)
         }
index b80088e4690c966024257b8584535db71a0ad824..75194e3d21fcb57ac29602db0ed39d9e803159b3 100644 (file)
@@ -552,7 +552,7 @@ pub fn gepi(&self, base: ValueRef, ixs: &[uint]) -> ValueRef {
             for (small_vec_e, &ix) in small_vec.iter_mut().zip(ixs.iter()) {
                 *small_vec_e = C_i32(self.ccx, ix as i32);
             }
-            self.inbounds_gep(base, &small_vec[0..ixs.len()])
+            self.inbounds_gep(base, &small_vec[..ixs.len()])
         } else {
             let v = ixs.iter().map(|i| C_i32(self.ccx, *i as i32)).collect::<Vec<ValueRef>>();
             self.count_insn("gepi");
index f7ffbb95feb3b43699a5002d526f6e1546a45d87..7abcdd07cc5da6a0ea6bb4827ce190ddcbe54969 100644 (file)
@@ -18,6 +18,7 @@
 use trans::cabi_x86_win64;
 use trans::cabi_arm;
 use trans::cabi_aarch64;
+use trans::cabi_powerpc;
 use trans::cabi_mips;
 use trans::type_::Type;
 
@@ -125,6 +126,7 @@ pub fn compute_abi_info(ccx: &CrateContext,
             cabi_arm::compute_abi_info(ccx, atys, rty, ret_def, flavor)
         },
         "mips" => cabi_mips::compute_abi_info(ccx, atys, rty, ret_def),
+        "powerpc" => cabi_powerpc::compute_abi_info(ccx, atys, rty, ret_def),
         a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)
                               []),
     }
diff --git a/src/librustc_trans/trans/cabi_powerpc.rs b/src/librustc_trans/trans/cabi_powerpc.rs
new file mode 100644 (file)
index 0000000..9fc67e1
--- /dev/null
@@ -0,0 +1,183 @@
+// Copyright 2014-2015 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 libc::c_uint;
+use llvm;
+use llvm::{Integer, Pointer, Float, Double, Struct, Array};
+use llvm::{StructRetAttribute, ZExtAttribute};
+use trans::cabi::{FnType, ArgType};
+use trans::context::CrateContext;
+use trans::type_::Type;
+
+use std::cmp;
+
+fn align_up_to(off: uint, a: uint) -> uint {
+    return (off + a - 1u) / a * a;
+}
+
+fn align(off: uint, ty: Type) -> uint {
+    let a = ty_align(ty);
+    return align_up_to(off, a);
+}
+
+fn ty_align(ty: Type) -> uint {
+    match ty.kind() {
+        Integer => {
+            unsafe {
+                ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
+            }
+        }
+        Pointer => 4,
+        Float => 4,
+        Double => 8,
+        Struct => {
+          if ty.is_packed() {
+            1
+          } else {
+            let str_tys = ty.field_types();
+            str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
+          }
+        }
+        Array => {
+            let elt = ty.element_type();
+            ty_align(elt)
+        }
+        _ => panic!("ty_size: unhandled type")
+    }
+}
+
+fn ty_size(ty: Type) -> uint {
+    match ty.kind() {
+        Integer => {
+            unsafe {
+                ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
+            }
+        }
+        Pointer => 4,
+        Float => 4,
+        Double => 8,
+        Struct => {
+            if ty.is_packed() {
+                let str_tys = ty.field_types();
+                str_tys.iter().fold(0, |s, t| s + ty_size(*t))
+            } else {
+                let str_tys = ty.field_types();
+                let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
+                align(size, ty)
+            }
+        }
+        Array => {
+            let len = ty.array_length();
+            let elt = ty.element_type();
+            let eltsz = ty_size(elt);
+            len * eltsz
+        }
+        _ => panic!("ty_size: unhandled type")
+    }
+}
+
+fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
+    if is_reg_ty(ty) {
+        let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
+        ArgType::direct(ty, None, None, attr)
+    } else {
+        ArgType::indirect(ty, Some(StructRetAttribute))
+    }
+}
+
+fn classify_arg_ty(ccx: &CrateContext, ty: Type, offset: &mut uint) -> ArgType {
+    let orig_offset = *offset;
+    let size = ty_size(ty) * 8;
+    let mut align = ty_align(ty);
+
+    align = cmp::min(cmp::max(align, 4), 8);
+    *offset = align_up_to(*offset, align);
+    *offset += align_up_to(size, align * 8) / 8;
+
+    if is_reg_ty(ty) {
+        let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
+        ArgType::direct(ty, None, None, attr)
+    } else {
+        ArgType::direct(
+            ty,
+            Some(struct_ty(ccx, ty)),
+            padding_ty(ccx, align, orig_offset),
+            None
+        )
+    }
+}
+
+fn is_reg_ty(ty: Type) -> bool {
+    return match ty.kind() {
+        Integer
+        | Pointer
+        | Float
+        | Double => true,
+        _ => false
+    };
+}
+
+fn padding_ty(ccx: &CrateContext, align: uint, offset: uint) -> Option<Type> {
+    if ((align - 1 ) & offset) > 0 {
+        Some(Type::i32(ccx))
+    } else {
+        None
+    }
+}
+
+fn coerce_to_int(ccx: &CrateContext, size: uint) -> Vec<Type> {
+    let int_ty = Type::i32(ccx);
+    let mut args = Vec::new();
+
+    let mut n = size / 32;
+    while n > 0 {
+        args.push(int_ty);
+        n -= 1;
+    }
+
+    let r = size % 32;
+    if r > 0 {
+        unsafe {
+            args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
+        }
+    }
+
+    args
+}
+
+fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
+    let size = ty_size(ty) * 8;
+    Type::struct_(ccx, coerce_to_int(ccx, size).as_slice(), false)
+}
+
+pub fn compute_abi_info(ccx: &CrateContext,
+                        atys: &[Type],
+                        rty: Type,
+                        ret_def: bool) -> FnType {
+    let ret_ty = if ret_def {
+        classify_ret_ty(ccx, rty)
+    } else {
+        ArgType::direct(Type::void(ccx), None, None, None)
+    };
+
+    let sret = ret_ty.is_indirect();
+    let mut arg_tys = Vec::new();
+    let mut offset = if sret { 4 } else { 0 };
+
+    for aty in atys.iter() {
+        let ty = classify_arg_ty(ccx, *aty, &mut offset);
+        arg_tys.push(ty);
+    };
+
+    return FnType {
+        arg_tys: arg_tys,
+        ret_ty: ret_ty,
+    };
+}
index 6196f9e5eab65eff401594f9cfad0699ecfd9378..11006f37531d2b5ebcb90ddfa27c0379b5bcf782 100644 (file)
@@ -91,8 +91,11 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
     debug!("callee::trans(expr={})", expr.repr(bcx.tcx()));
 
     // pick out special kinds of expressions that can be called:
-    if let ast::ExprPath(_) = expr.node {
-        return trans_def(bcx, bcx.def(expr.id), expr);
+    match expr.node {
+        ast::ExprPath(_) | ast::ExprQPath(_) => {
+            return trans_def(bcx, bcx.def(expr.id), expr);
+        }
+        _ => {}
     }
 
     // any other expressions are closures:
index f59e70d099a638342005c300f5c02ed8e3574abe..3eee4637de1995322030c5224f7d65de8cf50946 100644 (file)
@@ -217,12 +217,15 @@ pub fn type_needs_drop<'tcx>(cx: &ty::ctxt<'tcx>,
     ty::type_contents(cx, ty).needs_drop(cx)
 }
 
-fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                   ty: Ty<'tcx>) -> bool {
+fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.sty {
         ty::ty_struct(def_id, substs) => {
-            let fields = ty::struct_fields(ccx.tcx(), def_id, substs);
-            fields.len() == 1 && type_is_immediate(ccx, fields[0].mt.ty)
+            let fields = ty::lookup_struct_fields(ccx.tcx(), def_id);
+            fields.len() == 1 && {
+                let ty = ty::lookup_field_type(ccx.tcx(), def_id, fields[0].id, substs);
+                let ty = monomorphize::normalize_associated_type(ccx.tcx(), &ty);
+                type_is_immediate(ccx, ty)
+            }
         }
         _ => false
     }
index 00b97286de36780519e0471448cce156cb580991..29cf9f72ef8e88e6d6f06ce974ece47a272b5428 100644 (file)
@@ -600,7 +600,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef {
                 C_array(llunitty, &vs[])
             }
           }
-          ast::ExprPath(_) => {
+          ast::ExprPath(_) | ast::ExprQPath(_) => {
             let def = cx.tcx().def_map.borrow()[e.id];
             match def {
                 def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => {
index adf302501cd1f48b2c2a2bd50c3777db0ff4474d..5dc939dc2025bca7d192bd396e7112d7b2568e8f 100644 (file)
@@ -28,7 +28,6 @@
 use trans;
 use middle::ty;
 use middle::ty::MethodCall;
-use session::config::FullDebugInfo;
 use util::ppaux::Repr;
 use util::ppaux;
 
@@ -66,10 +65,7 @@ pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
             match d.node {
                 ast::DeclLocal(ref local) => {
                     bcx = init_local(bcx, &**local);
-                    if cx.sess().opts.debuginfo == FullDebugInfo {
-                        trans::debuginfo::create_local_var_metadata(bcx,
-                                                                    &**local);
-                    }
+                    debuginfo::create_local_var_metadata(bcx, &**local);
                 }
                 // Inner items are visited by `trans_item`/`trans_meth`.
                 ast::DeclItem(_) => {},
index 2f58baab7fca944327b5e073538c0e9150431f62..a03a5090c050bc9f73b33618f523a8311c7c596e 100644 (file)
@@ -854,7 +854,9 @@ pub fn create_global_var_metadata(cx: &CrateContext,
 /// local in `bcx.fcx.lllocals`.
 /// Adds the created metadata nodes directly to the crate's IR.
 pub fn create_local_var_metadata(bcx: Block, local: &ast::Local) {
-    if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
+    if bcx.unreachable.get() ||
+       fn_should_be_ignored(bcx.fcx) ||
+       bcx.sess().opts.debuginfo != FullDebugInfo  {
         return;
     }
 
@@ -898,7 +900,9 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                                 env_index: uint,
                                                 captured_by_ref: bool,
                                                 span: Span) {
-    if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
+    if bcx.unreachable.get() ||
+       fn_should_be_ignored(bcx.fcx) ||
+       bcx.sess().opts.debuginfo != FullDebugInfo {
         return;
     }
 
@@ -962,7 +966,7 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let variable_access = IndirectVariable {
         alloca: env_pointer,
-        address_operations: &address_operations[0..address_op_count]
+        address_operations: &address_operations[..address_op_count]
     };
 
     declare_local(bcx,
@@ -981,7 +985,9 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                                  variable_ident: ast::Ident,
                                                  binding: BindingInfo<'tcx>) {
-    if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
+    if bcx.unreachable.get() ||
+       fn_should_be_ignored(bcx.fcx) ||
+       bcx.sess().opts.debuginfo != FullDebugInfo {
         return;
     }
 
@@ -1021,7 +1027,9 @@ pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 /// argument in `bcx.fcx.lllocals`.
 /// Adds the created metadata nodes directly to the crate's IR.
 pub fn create_argument_metadata(bcx: Block, arg: &ast::Arg) {
-    if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
+    if bcx.unreachable.get() ||
+       fn_should_be_ignored(bcx.fcx) ||
+       bcx.sess().opts.debuginfo != FullDebugInfo {
         return;
     }
 
@@ -1075,7 +1083,9 @@ pub fn create_argument_metadata(bcx: Block, arg: &ast::Arg) {
 /// loop variable in `bcx.fcx.lllocals`.
 /// Adds the created metadata nodes directly to the crate's IR.
 pub fn create_for_loop_var_metadata(bcx: Block, pat: &ast::Pat) {
-    if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
+    if bcx.unreachable.get() ||
+       fn_should_be_ignored(bcx.fcx) ||
+       bcx.sess().opts.debuginfo != FullDebugInfo {
         return;
     }
 
@@ -3502,7 +3512,8 @@ fn walk_expr(cx: &CrateContext,
             ast::ExprLit(_)   |
             ast::ExprBreak(_) |
             ast::ExprAgain(_) |
-            ast::ExprPath(_)  => {}
+            ast::ExprPath(_)  |
+            ast::ExprQPath(_) => {}
 
             ast::ExprCast(ref sub_exp, _)     |
             ast::ExprAddrOf(_, ref sub_exp)  |
index ac50445be2f9b41adea0427d9c49b003b83bad36..7abd59ca0cd0e27fa6f09597398742db147ff8e7 100644 (file)
@@ -564,7 +564,7 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         ast::ExprParen(ref e) => {
             trans(bcx, &**e)
         }
-        ast::ExprPath(_) => {
+        ast::ExprPath(_) | ast::ExprQPath(_) => {
             trans_def(bcx, expr, bcx.def(expr.id))
         }
         ast::ExprField(ref base, ident) => {
@@ -768,7 +768,6 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 tvec::vec_types(bcx,
                                 ty::sequence_element_type(bcx.tcx(),
                                                           base_datum.ty));
-            base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
 
             let (base, len) = base_datum.get_vec_base_and_len(bcx);
 
@@ -997,7 +996,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         ast::ExprParen(ref e) => {
             trans_into(bcx, &**e, dest)
         }
-        ast::ExprPath(_) => {
+        ast::ExprPath(_) | ast::ExprQPath(_) => {
             trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
         }
         ast::ExprIf(ref cond, ref thn, ref els) => {
index a79bb6ca1647068f5887056cd13f3590af614439..d3f3f34b76bbb3e3e079df5de26d51c95bc51e11 100644 (file)
@@ -346,12 +346,14 @@ fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info:
             let align_ptr = GEPi(bcx, info, &[2u]);
             (Load(bcx, size_ptr), Load(bcx, align_ptr))
         }
-        ty::ty_vec(unit_ty, None) => {
-            // The info in this case is the length of the vec, so the size is that
+        ty::ty_vec(_, None) | ty::ty_str => {
+            let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
+            // The info in this case is the length of the str, so the size is that
             // times the unit size.
             let llunit_ty = sizing_type_of(bcx.ccx(), unit_ty);
+            let unit_align = llalign_of_min(bcx.ccx(), llunit_ty);
             let unit_size = llsize_of_alloc(bcx.ccx(), llunit_ty);
-            (Mul(bcx, info, C_uint(bcx.ccx(), unit_size)), C_uint(bcx.ccx(), 8u))
+            (Mul(bcx, info, C_uint(bcx.ccx(), unit_size)), C_uint(bcx.ccx(), unit_align))
         }
         _ => bcx.sess().bug(&format!("Unexpected unsized type, found {}",
                                     bcx.ty_to_string(t))[])
@@ -456,8 +458,11 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
                  &[PointerCast(bcx, Load(bcx, lluniquevalue), Type::i8p(bcx.ccx()))],
                  None);
             bcx
-        }
-        ty::ty_vec(ty, None) => tvec::make_drop_glue_unboxed(bcx, v0, ty, false),
+        },
+        ty::ty_vec(_, None) | ty::ty_str => {
+            let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
+            tvec::make_drop_glue_unboxed(bcx, v0, unit_ty, false)
+        },
         _ => {
             assert!(type_is_sized(bcx.tcx(), t));
             if type_needs_drop(bcx.tcx(), t) &&
index 95d67cd54c124e59a38eaf5a31c8a004f1212a84..1552ac0bea0fe0f4e714fc81e22a1faaccdc39b4 100644 (file)
@@ -82,17 +82,6 @@ pub fn llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
     return C_uint(cx, llsize_of_alloc(cx, ty));
 }
 
-// Returns the "default" size of t (see above), or 1 if the size would
-// be zero.  This is important for things like vectors that expect
-// space to be consumed.
-pub fn nonzero_llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
-    if llbitsize_of_real(cx, ty) == 0 {
-        unsafe { llvm::LLVMConstInt(cx.int_type().to_ref(), 1, False) }
-    } else {
-        llsize_of(cx, ty)
-    }
-}
-
 // Returns the preferred alignment of the given type for the current target.
 // The preferred alignment may be larger than the alignment used when
 // packing the type into structs. This will be used for things like
index 493df366d2ae69c6e82a27e2892566b7f60bb3de..0fb0dffe930fa958547c5cd2375f3b001d91c075 100644 (file)
@@ -288,6 +288,17 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                      param_substs,
                                      callee_substs)
         }
+        traits::VtableObject(ref data) => {
+            let trait_item_def_ids =
+                ty::trait_item_def_ids(ccx.tcx(), trait_id);
+            let method_offset_in_trait =
+                trait_item_def_ids.iter()
+                                  .position(|item| item.def_id() == method_id)
+                                  .unwrap();
+            let (llfn, ty) =
+                trans_object_shim(ccx, data.object_ty, trait_id, method_offset_in_trait);
+            immediate_rvalue(llfn, ty)
+        }
         _ => {
             tcx.sess.bug(&format!("static call to invalid vtable: {}",
                                  vtbl.repr(tcx))[]);
@@ -371,7 +382,7 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             Callee { bcx: bcx, data: Fn(llfn) }
         }
         traits::VtableObject(ref data) => {
-            let llfn = trans_object_shim(bcx.ccx(), data.object_ty, trait_id, n_method);
+            let (llfn, _) = trans_object_shim(bcx.ccx(), data.object_ty, trait_id, n_method);
             Callee { bcx: bcx, data: Fn(llfn) }
         }
         traits::VtableBuiltin(..) |
@@ -540,7 +551,7 @@ pub fn trans_object_shim<'a, 'tcx>(
     object_ty: Ty<'tcx>,
     trait_id: ast::DefId,
     method_offset_in_trait: uint)
-    -> ValueRef
+    -> (ValueRef, Ty<'tcx>)
 {
     let _icx = push_ctxt("trans_object_shim");
     let tcx = ccx.tcx();
@@ -667,7 +678,7 @@ pub fn trans_object_shim<'a, 'tcx>(
 
     finish_fn(&fcx, bcx, sig.output);
 
-    llfn
+    (llfn, method_bare_fn_ty)
 }
 
 /// Creates a returns a dynamic vtable for the given type and vtable origin.
index 42134789546958bbb3d2a47d835bfc0e6126a4bc..91c6c9a13a362107520277bb890299fa24dcdaff 100644 (file)
@@ -45,6 +45,7 @@
 mod cabi_arm;
 mod cabi_aarch64;
 mod cabi_mips;
+mod cabi_powerpc;
 mod foreign;
 mod intrinsic;
 mod debuginfo;
index 93076260349abd5c81aee5d5801823a800ec4a2d..f52e7c0ec94c09122aef2551bffbeff53cdfe72e 100644 (file)
@@ -274,6 +274,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         ast_map::NodeArg(..) |
         ast_map::NodeBlock(..) |
         ast_map::NodePat(..) |
+        ast_map::NodeViewItem(..) |
         ast_map::NodeLocal(..) => {
             ccx.sess().bug(&format!("can't monomorphize a {:?}",
                                    map_node)[])
index e3288466aa79c6c617890e58d86360dc15303dc3..f8b01ebf4ccad1ade99bf6b54d9aea470aa5dad7 100644 (file)
@@ -25,7 +25,7 @@
 use trans::expr;
 use trans::glue;
 use trans::machine;
-use trans::machine::{nonzero_llsize_of, llsize_of_alloc};
+use trans::machine::llsize_of_alloc;
 use trans::type_::Type;
 use trans::type_of;
 use middle::ty::{self, Ty};
@@ -44,13 +44,6 @@ fn get_dataptr(bcx: Block, vptr: ValueRef) -> ValueRef {
     Load(bcx, expr::get_dataptr(bcx, vptr))
 }
 
-pub fn pointer_add_byte(bcx: Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
-    let _icx = push_ctxt("tvec::pointer_add_byte");
-    let old_ty = val_ty(ptr);
-    let bptr = PointerCast(bcx, ptr, Type::i8p(bcx.ccx()));
-    return PointerCast(bcx, InBoundsGEP(bcx, bptr, &[bytes]), old_ty);
-}
-
 pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                           vptr: ValueRef,
                                           unit_ty: Ty<'tcx>,
@@ -94,17 +87,14 @@ pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 pub struct VecTypes<'tcx> {
     pub unit_ty: Ty<'tcx>,
     pub llunit_ty: Type,
-    pub llunit_size: ValueRef,
     pub llunit_alloc_size: u64
 }
 
 impl<'tcx> VecTypes<'tcx> {
     pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
-        format!("VecTypes {{unit_ty={}, llunit_ty={}, \
-                 llunit_size={}, llunit_alloc_size={}}}",
+        format!("VecTypes {{unit_ty={}, llunit_ty={}, llunit_alloc_size={}}}",
                 ty_to_string(ccx.tcx(), self.unit_ty),
                 ccx.tn().type_to_string(self.llunit_ty),
-                ccx.tn().val_to_string(self.llunit_size),
                 self.llunit_alloc_size)
     }
 }
@@ -333,13 +323,11 @@ pub fn vec_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                              -> VecTypes<'tcx> {
     let ccx = bcx.ccx();
     let llunit_ty = type_of::type_of(ccx, unit_ty);
-    let llunit_size = nonzero_llsize_of(ccx, llunit_ty);
     let llunit_alloc_size = llsize_of_alloc(ccx, llunit_ty);
 
     VecTypes {
         unit_ty: unit_ty,
         llunit_ty: llunit_ty,
-        llunit_size: llunit_size,
         llunit_alloc_size: llunit_alloc_size
     }
 }
@@ -486,17 +474,13 @@ pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
     let fcx = bcx.fcx;
 
     let vt = vec_types(bcx, unit_ty);
-    let fill = Mul(bcx, len, vt.llunit_size);
 
     if vt.llunit_alloc_size == 0 {
         // Special-case vectors with elements of size 0  so they don't go out of bounds (#9890)
-        iter_vec_loop(bcx, data_ptr, &vt, fill, f)
+        iter_vec_loop(bcx, data_ptr, &vt, len, f)
     } else {
         // Calculate the last pointer address we want to handle.
-        // FIXME (#3729): Optimize this when the size of the unit type is
-        // statically known to not use pointer casts, which tend to confuse
-        // LLVM.
-        let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill);
+        let data_end_ptr = InBoundsGEP(bcx, data_ptr, &[len]);
 
         // Now perform the iteration.
         let header_bcx = fcx.new_temp_block("iter_vec_loop_header");
index 45e05c12713bfbc78401aed51c413ca6721c5ef9..f2927dfd843400551699b78d77612a71bd5127c7 100644 (file)
@@ -516,8 +516,15 @@ pub fn instantiate_poly_trait_ref<'tcx>(
 {
     let mut projections = Vec::new();
 
+    // the trait reference introduces a binding level here, so
+    // we need to shift the `rscope`. It'd be nice if we could
+    // do away with this rscope stuff and work this knowledge
+    // into resolve_lifetimes, as we do with non-omitted
+    // lifetimes. Oh well, not there yet.
+    let shifted_rscope = ShiftedRscope::new(rscope);
+
     let trait_ref =
-        instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref,
+        instantiate_trait_ref(this, &shifted_rscope, &ast_trait_ref.trait_ref,
                               self_ty, Some(&mut projections));
 
     for projection in projections.into_iter() {
@@ -561,6 +568,29 @@ pub fn instantiate_trait_ref<'tcx>(
     }
 }
 
+fn object_path_to_poly_trait_ref<'a,'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
+    trait_def_id: ast::DefId,
+    path: &ast::Path,
+    mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+    -> ty::PolyTraitRef<'tcx>
+{
+    // we are introducing a binder here, so shift the
+    // anonymous regions depth to account for that
+    let shifted_rscope = ShiftedRscope::new(rscope);
+
+    let mut tmp = Vec::new();
+    let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
+                                                     &shifted_rscope,
+                                                     trait_def_id,
+                                                     None,
+                                                     path,
+                                                     Some(&mut tmp)));
+    projections.extend(tmp.into_iter().map(ty::Binder));
+    trait_ref
+}
+
 fn ast_path_to_trait_ref<'a,'tcx>(
     this: &AstConv<'tcx>,
     rscope: &RegionScope,
@@ -573,13 +603,6 @@ fn ast_path_to_trait_ref<'a,'tcx>(
     debug!("ast_path_to_trait_ref {:?}", path);
     let trait_def = this.get_trait_def(trait_def_id);
 
-    // the trait reference introduces a binding level here, so
-    // we need to shift the `rscope`. It'd be nice if we could
-    // do away with this rscope stuff and work this knowledge
-    // into resolve_lifetimes, as we do with non-omitted
-    // lifetimes. Oh well, not there yet.
-    let shifted_rscope = ShiftedRscope::new(rscope);
-
     let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
         ast::AngleBracketedParameters(ref data) => {
             // For now, require that parenthetical notation be used
@@ -595,7 +618,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
                             the crate attributes to enable");
             }
 
-            convert_angle_bracketed_parameters(this, &shifted_rscope, data)
+            convert_angle_bracketed_parameters(this, rscope, data)
         }
         ast::ParenthesizedParameters(ref data) => {
             // For now, require that parenthetical notation be used
@@ -616,7 +639,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
     };
 
     let substs = create_substs_for_ast_path(this,
-                                            &shifted_rscope,
+                                            rscope,
                                             path.span,
                                             &trait_def.generics,
                                             self_ty,
@@ -851,15 +874,11 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
             match this.tcx().def_map.borrow().get(&id) {
                 Some(&def::DefTrait(trait_def_id)) => {
                     let mut projection_bounds = Vec::new();
-                    let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
-                                                                     rscope,
-                                                                     trait_def_id,
-                                                                     None,
-                                                                     path,
-                                                                     Some(&mut projection_bounds)));
-                    let projection_bounds = projection_bounds.into_iter()
-                                                             .map(ty::Binder)
-                                                             .collect();
+                    let trait_ref = object_path_to_poly_trait_ref(this,
+                                                                  rscope,
+                                                                  trait_def_id,
+                                                                  path,
+                                                                  &mut projection_bounds);
                     Ok((trait_ref, projection_bounds))
                 }
                 _ => {
@@ -1001,9 +1020,12 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
 
     debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx()));
 
+    // `<T as Trait>::U<V>` shouldn't parse right now.
+    assert!(qpath.item_path.parameters.is_empty());
+
     return this.projected_ty(ast_ty.span,
                              trait_ref,
-                             qpath.item_name.name);
+                             qpath.item_path.identifier.name);
 }
 
 // Parses the programmer's textual representation of a type into our
@@ -1095,16 +1117,13 @@ pub fn ast_ty_to_ty<'tcx>(
                         // N.B. this case overlaps somewhat with
                         // TyObjectSum, see that fn for details
                         let mut projection_bounds = Vec::new();
-                        let trait_ref = ast_path_to_trait_ref(this,
-                                                              rscope,
-                                                              trait_def_id,
-                                                              None,
-                                                              path,
-                                                              Some(&mut projection_bounds));
-                        let trait_ref = ty::Binder(trait_ref);
-                        let projection_bounds = projection_bounds.into_iter()
-                                                                 .map(ty::Binder)
-                                                                 .collect();
+
+                        let trait_ref = object_path_to_poly_trait_ref(this,
+                                                                      rscope,
+                                                                      trait_def_id,
+                                                                      path,
+                                                                      &mut projection_bounds);
+
                         trait_ref_to_object_type(this, rscope, path.span,
                                                  trait_ref, projection_bounds, &[])
                     }
index cacf9bb19d20faeabcedd73894b7b4ebe8bd7256..47346592c86bb859220ba8186d4470cf6002952b 100644 (file)
@@ -467,7 +467,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
     };
 
     instantiate_path(pcx.fcx, path, ty::lookup_item_type(tcx, enum_def_id),
-                     def, pat.span, pat.id);
+                     None, def, pat.span, pat.id);
 
     let pat_ty = fcx.node_ty(pat.id);
     demand::eqtype(fcx, pat.span, expected, pat_ty);
@@ -505,7 +505,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
     } else {
         ctor_scheme
     };
-    instantiate_path(pcx.fcx, path, path_scheme, def, pat.span, pat.id);
+    instantiate_path(pcx.fcx, path, path_scheme, None, def, pat.span, pat.id);
 
     let pat_ty = fcx.node_ty(pat.id);
     demand::eqtype(fcx, pat.span, expected, pat_ty);
@@ -619,6 +619,8 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
             }
         };
 
+        let field_type = pcx.fcx.normalize_associated_types_in(span, &field_type);
+
         check_pat(pcx, &*field.pat, field_type);
     }
 
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
new file mode 100644 (file)
index 0000000..27d4b20
--- /dev/null
@@ -0,0 +1,413 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use middle::infer;
+use middle::traits;
+use middle::ty::{self};
+use middle::subst::{self, Subst, Substs, VecPerParamSpace};
+use util::ppaux::{self, Repr};
+
+use syntax::ast;
+use syntax::codemap::{Span};
+use syntax::parse::token;
+
+use super::assoc;
+
+/// Checks that a method from an impl conforms to the signature of
+/// the same method as declared in the trait.
+///
+/// # Parameters
+///
+/// - impl_m: type of the method we are checking
+/// - impl_m_span: span to use for reporting errors
+/// - impl_m_body_id: id of the method body
+/// - trait_m: the method in the trait
+/// - impl_trait_ref: the TraitRef corresponding to the trait implementation
+
+pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                 impl_m: &ty::Method<'tcx>,
+                                 impl_m_span: Span,
+                                 impl_m_body_id: ast::NodeId,
+                                 trait_m: &ty::Method<'tcx>,
+                                 impl_trait_ref: &ty::TraitRef<'tcx>) {
+    debug!("compare_impl_method(impl_trait_ref={})",
+           impl_trait_ref.repr(tcx));
+
+    debug!("compare_impl_method: impl_trait_ref (liberated) = {}",
+           impl_trait_ref.repr(tcx));
+
+    let infcx = infer::new_infer_ctxt(tcx);
+    let mut fulfillment_cx = traits::FulfillmentContext::new();
+
+    let trait_to_impl_substs = &impl_trait_ref.substs;
+
+    // Try to give more informative error messages about self typing
+    // mismatches.  Note that any mismatch will also be detected
+    // below, where we construct a canonical function type that
+    // includes the self parameter as a normal parameter.  It's just
+    // that the error messages you get out of this code are a bit more
+    // inscrutable, particularly for cases where one method has no
+    // self.
+    match (&trait_m.explicit_self, &impl_m.explicit_self) {
+        (&ty::StaticExplicitSelfCategory,
+         &ty::StaticExplicitSelfCategory) => {}
+        (&ty::StaticExplicitSelfCategory, _) => {
+            tcx.sess.span_err(
+                impl_m_span,
+                format!("method `{}` has a `{}` declaration in the impl, \
+                        but not in the trait",
+                        token::get_name(trait_m.name),
+                        ppaux::explicit_self_category_to_str(
+                            &impl_m.explicit_self)).as_slice());
+            return;
+        }
+        (_, &ty::StaticExplicitSelfCategory) => {
+            tcx.sess.span_err(
+                impl_m_span,
+                format!("method `{}` has a `{}` declaration in the trait, \
+                        but not in the impl",
+                        token::get_name(trait_m.name),
+                        ppaux::explicit_self_category_to_str(
+                            &trait_m.explicit_self)).as_slice());
+            return;
+        }
+        _ => {
+            // Let the type checker catch other errors below
+        }
+    }
+
+    let num_impl_m_type_params = impl_m.generics.types.len(subst::FnSpace);
+    let num_trait_m_type_params = trait_m.generics.types.len(subst::FnSpace);
+    if num_impl_m_type_params != num_trait_m_type_params {
+        span_err!(tcx.sess, impl_m_span, E0049,
+            "method `{}` has {} type parameter{} \
+             but its trait declaration has {} type parameter{}",
+            token::get_name(trait_m.name),
+            num_impl_m_type_params,
+            if num_impl_m_type_params == 1 {""} else {"s"},
+            num_trait_m_type_params,
+            if num_trait_m_type_params == 1 {""} else {"s"});
+        return;
+    }
+
+    if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() {
+        span_err!(tcx.sess, impl_m_span, E0050,
+            "method `{}` has {} parameter{} \
+             but the declaration in trait `{}` has {}",
+            token::get_name(trait_m.name),
+            impl_m.fty.sig.0.inputs.len(),
+            if impl_m.fty.sig.0.inputs.len() == 1 {""} else {"s"},
+            ty::item_path_str(tcx, trait_m.def_id),
+            trait_m.fty.sig.0.inputs.len());
+        return;
+    }
+
+    // This code is best explained by example. Consider a trait:
+    //
+    //     trait Trait<'t,T> {
+    //          fn method<'a,M>(t: &'t T, m: &'a M) -> Self;
+    //     }
+    //
+    // And an impl:
+    //
+    //     impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
+    //          fn method<'b,N>(t: &'j &'i U, m: &'b N) -> Foo;
+    //     }
+    //
+    // We wish to decide if those two method types are compatible.
+    //
+    // We start out with trait_to_impl_substs, that maps the trait
+    // type parameters to impl type parameters. This is taken from the
+    // impl trait reference:
+    //
+    //     trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
+    //
+    // We create a mapping `dummy_substs` that maps from the impl type
+    // parameters to fresh types and regions. For type parameters,
+    // this is the identity transform, but we could as well use any
+    // skolemized types. For regions, we convert from bound to free
+    // regions (Note: but only early-bound regions, i.e., those
+    // declared on the impl or used in type parameter bounds).
+    //
+    //     impl_to_skol_substs = {'i => 'i0, U => U0, N => N0 }
+    //
+    // Now we can apply skol_substs to the type of the impl method
+    // to yield a new function type in terms of our fresh, skolemized
+    // types:
+    //
+    //     <'b> fn(t: &'i0 U0, m: &'b) -> Foo
+    //
+    // We now want to extract and substitute the type of the *trait*
+    // method and compare it. To do so, we must create a compound
+    // substitution by combining trait_to_impl_substs and
+    // impl_to_skol_substs, and also adding a mapping for the method
+    // type parameters. We extend the mapping to also include
+    // the method parameters.
+    //
+    //     trait_to_skol_substs = { T => &'i0 U0, Self => Foo, M => N0 }
+    //
+    // Applying this to the trait method type yields:
+    //
+    //     <'a> fn(t: &'i0 U0, m: &'a) -> Foo
+    //
+    // This type is also the same but the name of the bound region ('a
+    // vs 'b).  However, the normal subtyping rules on fn types handle
+    // this kind of equivalency just fine.
+    //
+    // We now use these subsititions to ensure that all declared bounds are
+    // satisfied by the implementation's method.
+    //
+    // We do this by creating a parameter environment which contains a
+    // substition corresponding to impl_to_skol_substs. We then build
+    // trait_to_skol_substs and use it to convert the predicates contained
+    // in the trait_m.generics to the skolemized form.
+    //
+    // Finally we register each of these predicates as an obligation in
+    // a fresh FulfillmentCtxt, and invoke select_all_or_error.
+
+    // Create a parameter environment that represents the implementation's
+    // method.
+    let impl_param_env =
+        ty::ParameterEnvironment::for_item(tcx, impl_m.def_id.node);
+
+    // Create mapping from impl to skolemized.
+    let impl_to_skol_substs = &impl_param_env.free_substs;
+
+    // Create mapping from trait to skolemized.
+    let trait_to_skol_substs =
+        trait_to_impl_substs
+        .subst(tcx, impl_to_skol_substs)
+        .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
+                     impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
+    debug!("compare_impl_method: trait_to_skol_substs={}",
+           trait_to_skol_substs.repr(tcx));
+
+    // Check region bounds. FIXME(@jroesch) refactor this away when removing
+    // ParamBounds.
+    if !check_region_bounds_on_impl_method(tcx,
+                                           impl_m_span,
+                                           impl_m,
+                                           &trait_m.generics,
+                                           &impl_m.generics,
+                                           &trait_to_skol_substs,
+                                           impl_to_skol_substs) {
+        return;
+    }
+
+    // Create obligations for each predicate declared by the impl
+    // definition in the context of the trait's parameter
+    // environment. We can't just use `impl_env.caller_bounds`,
+    // however, because we want to replace all late-bound regions with
+    // region variables.
+    let impl_bounds =
+        impl_m.generics.to_bounds(tcx, impl_to_skol_substs);
+
+    let (impl_bounds, _) =
+        infcx.replace_late_bound_regions_with_fresh_var(
+            impl_m_span,
+            infer::HigherRankedType,
+            &ty::Binder(impl_bounds));
+    debug!("compare_impl_method: impl_bounds={}",
+           impl_bounds.repr(tcx));
+
+    // // Normalize the associated types in the impl_bounds.
+    // let traits::Normalized { value: impl_bounds, .. } =
+    //     traits::normalize(&mut selcx, normalize_cause.clone(), &impl_bounds);
+
+    // Normalize the associated types in the trait_bounds.
+    let trait_bounds = trait_m.generics.to_bounds(tcx, &trait_to_skol_substs);
+    // let traits::Normalized { value: trait_bounds, .. } =
+    //     traits::normalize(&mut selcx, normalize_cause, &trait_bounds);
+
+    // Obtain the predicate split predicate sets for each.
+    let trait_pred = trait_bounds.predicates.split();
+    let impl_pred = impl_bounds.predicates.split();
+
+    // This is the only tricky bit of the new way we check implementation methods
+    // We need to build a set of predicates where only the FnSpace bounds
+    // are from the trait and we assume all other bounds from the implementation
+    // to be previously satisfied.
+    //
+    // We then register the obligations from the impl_m and check to see
+    // if all constraints hold.
+    let hybrid_preds = VecPerParamSpace::new(
+        impl_pred.types,
+        impl_pred.selfs,
+        trait_pred.fns
+    );
+
+    // Construct trait parameter environment and then shift it into the skolemized viewpoint.
+    let mut trait_param_env = impl_param_env.clone();
+    // The key step here is to update the caller_bounds's predicates to be
+    // the new hybrid bounds we computed.
+    trait_param_env.caller_bounds.predicates = hybrid_preds;
+
+    debug!("compare_impl_method: trait_bounds={}",
+        trait_param_env.caller_bounds.repr(tcx));
+
+    let mut selcx = traits::SelectionContext::new(&infcx, &trait_param_env);
+
+    let normalize_cause =
+        traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
+
+    for predicate in impl_pred.fns.into_iter() {
+        let traits::Normalized { value: predicate, .. } =
+            traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);
+
+        let cause = traits::ObligationCause {
+            span: impl_m_span,
+            body_id: impl_m_body_id,
+            code: traits::ObligationCauseCode::CompareImplMethodObligation
+        };
+
+        fulfillment_cx.register_predicate_obligation(
+            &infcx,
+            traits::Obligation::new(cause, predicate));
+    }
+
+    // We now need to check that the signature of the impl method is
+    // compatible with that of the trait method. We do this by
+    // checking that `impl_fty <: trait_fty`.
+    //
+    // FIXME. Unfortunately, this doesn't quite work right now because
+    // associated type normalization is not integrated into subtype
+    // checks. For the comparison to be valid, we need to
+    // normalize the associated types in the impl/trait methods
+    // first. However, because function types bind regions, just
+    // calling `normalize_associated_types_in` would have no effect on
+    // any associated types appearing in the fn arguments or return
+    // type.
+
+    // Compute skolemized form of impl and trait method tys.
+    let impl_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(impl_m.fty.clone()));
+    let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs);
+    let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone()));
+    let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
+
+    let err = infcx.try(|snapshot| {
+        let origin = infer::MethodCompatCheck(impl_m_span);
+
+        let (impl_sig, _) =
+            infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
+                                                            infer::HigherRankedType,
+                                                            &impl_m.fty.sig);
+        let impl_sig =
+            impl_sig.subst(tcx, impl_to_skol_substs);
+        let impl_sig =
+            assoc::normalize_associated_types_in(&infcx,
+                                                 &impl_param_env,
+                                                 &mut fulfillment_cx,
+                                                 impl_m_span,
+                                                 impl_m_body_id,
+                                                 &impl_sig);
+        let impl_fty =
+            ty::mk_bare_fn(tcx,
+                           None,
+                           tcx.mk_bare_fn(ty::BareFnTy { unsafety: impl_m.fty.unsafety,
+                                                         abi: impl_m.fty.abi,
+                                                         sig: ty::Binder(impl_sig) }));
+        debug!("compare_impl_method: impl_fty={}",
+               impl_fty.repr(tcx));
+
+        let (trait_sig, skol_map) =
+            infcx.skolemize_late_bound_regions(&trait_m.fty.sig, snapshot);
+        let trait_sig =
+            trait_sig.subst(tcx, &trait_to_skol_substs);
+        let trait_sig =
+            assoc::normalize_associated_types_in(&infcx,
+                                                 &impl_param_env,
+                                                 &mut fulfillment_cx,
+                                                 impl_m_span,
+                                                 impl_m_body_id,
+                                                 &trait_sig);
+        let trait_fty =
+            ty::mk_bare_fn(tcx,
+                           None,
+                           tcx.mk_bare_fn(ty::BareFnTy { unsafety: trait_m.fty.unsafety,
+                                                         abi: trait_m.fty.abi,
+                                                         sig: ty::Binder(trait_sig) }));
+
+        debug!("compare_impl_method: trait_fty={}",
+               trait_fty.repr(tcx));
+
+        try!(infer::mk_subty(&infcx, false, origin, impl_fty, trait_fty));
+
+        infcx.leak_check(&skol_map, snapshot)
+    });
+
+    match err {
+        Ok(()) => { }
+        Err(terr) => {
+            debug!("checking trait method for compatibility: impl ty {}, trait ty {}",
+                   impl_fty.repr(tcx),
+                   trait_fty.repr(tcx));
+            span_err!(tcx.sess, impl_m_span, E0053,
+                      "method `{}` has an incompatible type for trait: {}",
+                      token::get_name(trait_m.name),
+                      ty::type_err_to_str(tcx, &terr));
+            return;
+        }
+    }
+
+    // Check that all obligations are satisfied by the implementation's
+    // version.
+    match fulfillment_cx.select_all_or_error(&infcx, &trait_param_env) {
+        Err(ref errors) => { traits::report_fulfillment_errors(&infcx, errors) }
+        Ok(_) => {}
+    }
+
+    // Finally, resolve all regions. This catches wily misuses of lifetime
+    // parameters.
+    infcx.resolve_regions_and_report_errors(impl_m_body_id);
+
+    fn check_region_bounds_on_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                                span: Span,
+                                                impl_m: &ty::Method<'tcx>,
+                                                trait_generics: &ty::Generics<'tcx>,
+                                                impl_generics: &ty::Generics<'tcx>,
+                                                trait_to_skol_substs: &Substs<'tcx>,
+                                                impl_to_skol_substs: &Substs<'tcx>)
+                                                -> bool
+    {
+
+        let trait_params = trait_generics.regions.get_slice(subst::FnSpace);
+        let impl_params = impl_generics.regions.get_slice(subst::FnSpace);
+
+        debug!("check_region_bounds_on_impl_method: \
+               trait_generics={} \
+               impl_generics={} \
+               trait_to_skol_substs={} \
+               impl_to_skol_substs={}",
+               trait_generics.repr(tcx),
+               impl_generics.repr(tcx),
+               trait_to_skol_substs.repr(tcx),
+               impl_to_skol_substs.repr(tcx));
+
+        // Must have same number of early-bound lifetime parameters.
+        // Unfortunately, if the user screws up the bounds, then this
+        // will change classification between early and late.  E.g.,
+        // if in trait we have `<'a,'b:'a>`, and in impl we just have
+        // `<'a,'b>`, then we have 2 early-bound lifetime parameters
+        // in trait but 0 in the impl. But if we report "expected 2
+        // but found 0" it's confusing, because it looks like there
+        // are zero. Since I don't quite know how to phrase things at
+        // the moment, give a kind of vague error message.
+        if trait_params.len() != impl_params.len() {
+            tcx.sess.span_err(
+                span,
+                &format!("lifetime parameters or bounds on method `{}` do \
+                         not match the trait declaration",
+                         token::get_name(impl_m.name))[]);
+            return false;
+        }
+
+        return true;
+    }
+}
index 0c53a16a8118b2a76d746d6f0e749b2aa02c311d..345bc5fd2aa60772cb367f8fce554789034013ab 100644 (file)
@@ -12,7 +12,6 @@
 
 use astconv::AstConv;
 use check::{FnCtxt};
-use check::{impl_self_ty};
 use check::vtable;
 use check::vtable::select_new_fcx_obligations;
 use middle::subst;
@@ -20,7 +19,7 @@
 use middle::ty::*;
 use middle::ty;
 use middle::infer;
-use util::ppaux::{Repr, UserString};
+use util::ppaux::Repr;
 
 use std::rc::Rc;
 use syntax::ast::{DefId};
 pub use self::MethodError::*;
 pub use self::CandidateSource::*;
 
+pub use self::suggest::{report_error, AllTraitsVec};
+
 mod confirm;
 mod doc;
 mod probe;
+mod suggest;
 
 pub enum MethodError {
     // Did not find an applicable method, but we did find various
-    // static methods that may apply.
-    NoMatch(Vec<CandidateSource>),
+    // static methods that may apply, as well as a list of
+    // not-in-scope traits which may work.
+    NoMatch(Vec<CandidateSource>, Vec<ast::DefId>),
 
     // Multiple methods might apply.
     Ambiguity(Vec<CandidateSource>),
@@ -63,7 +66,7 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 {
     match probe::probe(fcx, span, method_name, self_ty, call_expr_id) {
         Ok(_) => true,
-        Err(NoMatch(_)) => false,
+        Err(NoMatch(_, _)) => false,
         Err(Ambiguity(_)) => true,
     }
 }
@@ -294,105 +297,6 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     Some(callee)
 }
 
-pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                              span: Span,
-                              rcvr_ty: Ty<'tcx>,
-                              method_name: ast::Name,
-                              error: MethodError)
-{
-    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 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_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)[]);
-            }
-
-            if static_sources.len() > 0 {
-                fcx.tcx().sess.fileline_note(
-                    span,
-                    "found defined static methods, maybe a `self` is missing?");
-
-                report_candidates(fcx, span, method_name, static_sources);
-            }
-        }
-
-        Ambiguity(sources) => {
-            span_err!(fcx.sess(), span, E0034,
-                      "multiple applicable methods in scope");
-
-            report_candidates(fcx, span, method_name, sources);
-        }
-    }
-
-    fn report_candidates(fcx: &FnCtxt,
-                         span: Span,
-                         method_name: ast::Name,
-                         mut sources: Vec<CandidateSource>) {
-        sources.sort();
-        sources.dedup();
-
-        for (idx, source) in sources.iter().enumerate() {
-            match *source {
-                ImplSource(impl_did) => {
-                    // Provide the best span we can. Use the method, if local to crate, else
-                    // the impl, if local to crate (method may be defaulted), else the call site.
-                    let method = impl_method(fcx.tcx(), impl_did, method_name).unwrap();
-                    let impl_span = fcx.tcx().map.def_id_span(impl_did, span);
-                    let method_span = fcx.tcx().map.def_id_span(method.def_id, impl_span);
-
-                    let impl_ty = impl_self_ty(fcx, span, impl_did).ty;
-
-                    let insertion = match impl_trait_ref(fcx.tcx(), impl_did) {
-                        None => format!(""),
-                        Some(trait_ref) => format!(" of the trait `{}`",
-                                                   ty::item_path_str(fcx.tcx(),
-                                                                     trait_ref.def_id)),
-                    };
-
-                    span_note!(fcx.sess(), method_span,
-                               "candidate #{} is defined in an impl{} for the type `{}`",
-                               idx + 1u,
-                               insertion,
-                               impl_ty.user_string(fcx.tcx()));
-                }
-                TraitSource(trait_did) => {
-                    let (_, method) = trait_method(fcx.tcx(), trait_did, method_name).unwrap();
-                    let method_span = fcx.tcx().map.def_id_span(method.def_id, span);
-                    span_note!(fcx.sess(), method_span,
-                               "candidate #{} is defined in the trait `{}`",
-                               idx + 1u,
-                               ty::item_path_str(fcx.tcx(), trait_did));
-                }
-            }
-        }
-    }
-}
 
 /// Find method with name `method_name` defined in `trait_def_id` and return it, along with its
 /// index (or `None`, if no such method).
index dc4d6c9a826c9912d0b6fb6994016a6f56233d9a..9df8875152e3b94e0f9bc40434f9005597a0bb49 100644 (file)
@@ -11,6 +11,7 @@
 use super::{MethodError,Ambiguity,NoMatch};
 use super::MethodIndex;
 use super::{CandidateSource,ImplSource,TraitSource};
+use super::suggest;
 
 use check;
 use check::{FnCtxt, NoPreference};
@@ -25,6 +26,7 @@
 use syntax::ast;
 use syntax::codemap::{Span, DUMMY_SP};
 use std::collections::HashSet;
+use std::mem;
 use std::rc::Rc;
 use util::ppaux::Repr;
 
@@ -42,6 +44,7 @@ struct ProbeContext<'a, 'tcx:'a> {
     extension_candidates: Vec<Candidate<'tcx>>,
     impl_dups: HashSet<ast::DefId>,
     static_candidates: Vec<CandidateSource>,
+    all_traits_search: bool,
 }
 
 struct CandidateStep<'tcx> {
@@ -127,7 +130,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // take place in the `fcx.infcx().probe` below.
     let steps = match create_steps(fcx, span, self_ty) {
         Some(steps) => steps,
-        None => return Err(NoMatch(Vec::new())),
+        None => return Err(NoMatch(Vec::new(), Vec::new())),
     };
 
     // Create a list of simplified self types, if we can.
@@ -208,9 +211,17 @@ fn new(fcx: &'a FnCtxt<'a,'tcx>,
             steps: Rc::new(steps),
             opt_simplified_steps: opt_simplified_steps,
             static_candidates: Vec::new(),
+            all_traits_search: false,
         }
     }
 
+    fn reset(&mut self) {
+        self.inherent_candidates.clear();
+        self.extension_candidates.clear();
+        self.impl_dups.clear();
+        self.static_candidates.clear();
+    }
+
     fn tcx(&self) -> &'a ty::ctxt<'tcx> {
         self.fcx.tcx()
     }
@@ -446,6 +457,15 @@ fn assemble_extension_candidates_for_traits_in_scope(&mut self,
         }
     }
 
+    fn assemble_extension_candidates_for_all_traits(&mut self) {
+        let mut duplicates = HashSet::new();
+        for trait_info in suggest::all_traits(self.fcx.ccx) {
+            if duplicates.insert(trait_info.def_id) {
+                self.assemble_extension_candidates_for_trait(trait_info.def_id)
+            }
+        }
+    }
+
     fn assemble_extension_candidates_for_trait(&mut self,
                                                trait_def_id: ast::DefId) {
         debug!("assemble_extension_candidates_for_trait(trait_def_id={})",
@@ -715,7 +735,47 @@ fn pick(mut self) -> PickResult<'tcx> {
             }
         }
 
-        Err(NoMatch(self.static_candidates))
+        let static_candidates = mem::replace(&mut self.static_candidates, vec![]);
+
+        let out_of_scope_traits = if !self.all_traits_search {
+            // things failed, and we haven't yet looked through all
+            // traits, so lets do that now:
+            self.reset();
+            self.all_traits_search = true;
+
+            let span = self.span;
+            let tcx = self.tcx();
+
+            self.assemble_extension_candidates_for_all_traits();
+
+            match self.pick() {
+                Ok(p) => vec![p.method_ty.container.id()],
+                Err(Ambiguity(v)) => v.into_iter().map(|source| {
+                    match source {
+                        TraitSource(id) => id,
+                        ImplSource(impl_id) => {
+                            match ty::trait_id_of_impl(tcx, impl_id) {
+                                Some(id) => id,
+                                None => tcx.sess.span_bug(span,
+                                                          "found inherent method when looking \
+                                                           at traits")
+                            }
+                        }
+                    }
+                }).collect(),
+                // it'd be really weird for this assertion to trigger,
+                // given the `vec![]` in the else branch below
+                Err(NoMatch(_, others)) => {
+                    assert!(others.is_empty());
+                    vec![]
+                }
+            }
+        } else {
+            // we've just looked through all traits and didn't find
+            // anything at all.
+            vec![]
+        };
+        Err(NoMatch(static_candidates, out_of_scope_traits))
     }
 
     fn pick_step(&mut self, step: &CandidateStep<'tcx>) -> Option<PickResult<'tcx>> {
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
new file mode 100644 (file)
index 0000000..013c6e2
--- /dev/null
@@ -0,0 +1,306 @@
+// 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.
+
+//! Give useful errors and suggestions to users when a method can't be
+//! found or is otherwise invalid.
+
+use CrateCtxt;
+
+use astconv::AstConv;
+use check::{self, FnCtxt};
+use middle::ty::{self, Ty};
+use middle::def;
+use metadata::{csearch, cstore, decoder};
+use util::ppaux::UserString;
+
+use syntax::{ast, ast_util};
+use syntax::codemap::Span;
+
+use std::cell;
+use std::cmp::Ordering;
+
+use super::{MethodError, CandidateSource, impl_method, trait_method};
+
+pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+                              span: Span,
+                              rcvr_ty: Ty<'tcx>,
+                              method_name: ast::Name,
+                              error: MethodError)
+{
+    match error {
+        MethodError::NoMatch(static_sources, out_of_scope_traits) => {
+            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 rcvr_ty.sty {
+                ty::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_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)[]);
+            }
+
+            if static_sources.len() > 0 {
+                fcx.tcx().sess.fileline_note(
+                    span,
+                    "found defined static methods, maybe a `self` is missing?");
+
+                report_candidates(fcx, span, method_name, static_sources);
+            }
+
+            suggest_traits_to_import(fcx, span, rcvr_ty, method_name, out_of_scope_traits)
+        }
+
+        MethodError::Ambiguity(sources) => {
+            span_err!(fcx.sess(), span, E0034,
+                      "multiple applicable methods in scope");
+
+            report_candidates(fcx, span, method_name, sources);
+        }
+    }
+
+    fn report_candidates(fcx: &FnCtxt,
+                         span: Span,
+                         method_name: ast::Name,
+                         mut sources: Vec<CandidateSource>) {
+        sources.sort();
+        sources.dedup();
+
+        for (idx, source) in sources.iter().enumerate() {
+            match *source {
+                CandidateSource::ImplSource(impl_did) => {
+                    // Provide the best span we can. Use the method, if local to crate, else
+                    // the impl, if local to crate (method may be defaulted), else the call site.
+                    let method = impl_method(fcx.tcx(), impl_did, method_name).unwrap();
+                    let impl_span = fcx.tcx().map.def_id_span(impl_did, span);
+                    let method_span = fcx.tcx().map.def_id_span(method.def_id, impl_span);
+
+                    let impl_ty = check::impl_self_ty(fcx, span, impl_did).ty;
+
+                    let insertion = match ty::impl_trait_ref(fcx.tcx(), impl_did) {
+                        None => format!(""),
+                        Some(trait_ref) => format!(" of the trait `{}`",
+                                                   ty::item_path_str(fcx.tcx(),
+                                                                     trait_ref.def_id)),
+                    };
+
+                    span_note!(fcx.sess(), method_span,
+                               "candidate #{} is defined in an impl{} for the type `{}`",
+                               idx + 1u,
+                               insertion,
+                               impl_ty.user_string(fcx.tcx()));
+                }
+                CandidateSource::TraitSource(trait_did) => {
+                    let (_, method) = trait_method(fcx.tcx(), trait_did, method_name).unwrap();
+                    let method_span = fcx.tcx().map.def_id_span(method.def_id, span);
+                    span_note!(fcx.sess(), method_span,
+                               "candidate #{} is defined in the trait `{}`",
+                               idx + 1u,
+                               ty::item_path_str(fcx.tcx(), trait_did));
+                }
+            }
+        }
+    }
+}
+
+
+pub type AllTraitsVec = Vec<TraitInfo>;
+
+fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+                                      span: Span,
+                                      _rcvr_ty: Ty<'tcx>,
+                                      method_name: ast::Name,
+                                      valid_out_of_scope_traits: Vec<ast::DefId>)
+{
+    let tcx = fcx.tcx();
+    let method_ustring = method_name.user_string(tcx);
+
+    if !valid_out_of_scope_traits.is_empty() {
+        let mut candidates = valid_out_of_scope_traits;
+        candidates.sort();
+        let msg = format!(
+            "methods from traits can only be called if the trait is in scope; \
+             the following {traits_are} implemented and {define} a method `{name}`:",
+            traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"},
+            define = if candidates.len() == 1 {"defines"} else {"define"},
+            name = method_ustring);
+
+        fcx.sess().fileline_help(span, &msg[]);
+
+        for (i, trait_did) in candidates.iter().enumerate() {
+            fcx.sess().fileline_help(span,
+                                     &*format!("candidate #{}: `{}`",
+                                               i + 1,
+                                               ty::item_path_str(fcx.tcx(), *trait_did)))
+
+        }
+        return
+    }
+
+    // there's no implemented traits, so lets suggest some traits to implement
+    let mut candidates = all_traits(fcx.ccx)
+        .filter(|info| trait_method(tcx, info.def_id, method_name).is_some())
+        .collect::<Vec<_>>();
+
+    if candidates.len() > 0 {
+        // sort from most relevant to least relevant
+        candidates.sort_by(|a, b| a.cmp(b).reverse());
+
+        let msg = format!(
+            "methods from traits can only be called if the trait is implemented and \
+             in scope; no such traits are but the following {traits_define} a method `{name}`:",
+            traits_define = if candidates.len() == 1 {"trait defines"} else {"traits define"},
+            name = method_ustring);
+
+        fcx.sess().fileline_help(span, &msg[]);
+
+        for (i, trait_info) in candidates.iter().enumerate() {
+            fcx.sess().fileline_help(span,
+                                     &*format!("candidate #{}: `{}`",
+                                               i + 1,
+                                               ty::item_path_str(fcx.tcx(), trait_info.def_id)))
+        }
+    }
+}
+
+#[derive(Copy)]
+pub struct TraitInfo {
+    pub def_id: ast::DefId,
+}
+
+impl TraitInfo {
+    fn new(def_id: ast::DefId) -> TraitInfo {
+        TraitInfo {
+            def_id: def_id,
+        }
+    }
+}
+impl PartialEq for TraitInfo {
+    fn eq(&self, other: &TraitInfo) -> bool {
+        self.cmp(other) == Ordering::Equal
+    }
+}
+impl Eq for TraitInfo {}
+impl PartialOrd for TraitInfo {
+    fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> { Some(self.cmp(other)) }
+}
+impl Ord for TraitInfo {
+    fn cmp(&self, other: &TraitInfo) -> Ordering {
+        // accessible traits are more important/relevant than
+        // inaccessible ones, local crates are more important than
+        // remote ones (local: cnum == 0), and NodeIds just for
+        // totality.
+
+        let lhs = (other.def_id.krate, other.def_id.node);
+        let rhs = (self.def_id.krate, self.def_id.node);
+        lhs.cmp(&rhs)
+    }
+}
+
+/// Retrieve all traits in this crate and any dependent crates.
+pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
+    if ccx.all_traits.borrow().is_none() {
+        use syntax::visit;
+
+        let mut traits = vec![];
+
+        // Crate-local:
+        //
+        // meh.
+        struct Visitor<'a, 'b: 'a, 'tcx: 'a + 'b> {
+            traits: &'a mut AllTraitsVec,
+        }
+        impl<'v,'a, 'b, 'tcx> visit::Visitor<'v> for Visitor<'a, 'b, 'tcx> {
+            fn visit_item(&mut self, i: &'v ast::Item) {
+                match i.node {
+                    ast::ItemTrait(..) => {
+                        self.traits.push(TraitInfo::new(ast_util::local_def(i.id)));
+                    }
+                    _ => {}
+                }
+                visit::walk_item(self, i)
+            }
+        }
+        visit::walk_crate(&mut Visitor {
+            traits: &mut traits
+        }, ccx.tcx.map.krate());
+
+        // Cross-crate:
+        fn handle_external_def(traits: &mut AllTraitsVec,
+                               ccx: &CrateCtxt,
+                               cstore: &cstore::CStore,
+                               dl: decoder::DefLike) {
+            match dl {
+                decoder::DlDef(def::DefTrait(did)) => {
+                    traits.push(TraitInfo::new(did));
+                }
+                decoder::DlDef(def::DefMod(did)) => {
+                    csearch::each_child_of_item(cstore, did, |dl, _, _| {
+                        handle_external_def(traits, ccx, cstore, dl)
+                    })
+                }
+                _ => {}
+            }
+        }
+        let cstore = &ccx.tcx.sess.cstore;
+        cstore.iter_crate_data(|&mut: cnum, _| {
+            csearch::each_top_level_item_of_crate(cstore, cnum, |dl, _, _| {
+                handle_external_def(&mut traits, ccx, cstore, dl)
+            })
+        });
+
+        *ccx.all_traits.borrow_mut() = Some(traits);
+    }
+
+    let borrow = ccx.all_traits.borrow();
+    assert!(borrow.is_some());
+    AllTraits {
+        borrow: borrow,
+        idx: 0
+    }
+}
+
+pub struct AllTraits<'a> {
+    borrow: cell::Ref<'a Option<AllTraitsVec>>,
+    idx: usize
+}
+
+impl<'a> Iterator for AllTraits<'a> {
+    type Item = TraitInfo;
+
+    fn next(&mut self) -> Option<TraitInfo> {
+        let AllTraits { ref borrow, ref mut idx } = *self;
+        // ugh.
+        borrow.as_ref().unwrap().get(*idx).map(|info| {
+            *idx += 1;
+            *info
+        })
+    }
+}
index 7473f0223a669c01fe84072b22bfa1689b36a84e..7e38321049ed7a8c9acf85a71287224d19cff672 100644 (file)
@@ -78,6 +78,7 @@
 
 pub use self::LvaluePreference::*;
 pub use self::Expectation::*;
+pub use self::compare_method::compare_impl_method;
 use self::IsBinopAssignment::*;
 use self::TupleArgumentsFlag::*;
 
 use middle::lang_items::TypeIdLangItem;
 use lint;
 use util::common::{block_query, indenter, loop_query};
-use util::ppaux::{self, UserString, Repr};
+use util::ppaux::{self, Repr};
 use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
 
 use std::cell::{Cell, Ref, RefCell};
 pub mod wf;
 mod closure;
 mod callee;
+mod compare_method;
 
-/// Fields that are part of a `FnCtxt` which are inherited by
 /// closures defined within the function.  For example:
 ///
 ///     fn foo() {
@@ -993,503 +994,6 @@ trait `{}`",
     }
 }
 
-/// Checks that a method from an impl conforms to the signature of
-/// the same method as declared in the trait.
-///
-/// # Parameters
-///
-/// - impl_generics: the generics declared on the impl itself (not the method!)
-/// - impl_m: type of the method we are checking
-/// - impl_m_span: span to use for reporting errors
-/// - impl_m_body_id: id of the method body
-/// - trait_m: the method in the trait
-/// - trait_to_impl_substs: the substitutions used on the type of the trait
-fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
-                             impl_m: &ty::Method<'tcx>,
-                             impl_m_span: Span,
-                             impl_m_body_id: ast::NodeId,
-                             trait_m: &ty::Method<'tcx>,
-                             impl_trait_ref: &ty::TraitRef<'tcx>) {
-    debug!("compare_impl_method(impl_trait_ref={})",
-           impl_trait_ref.repr(tcx));
-
-    debug!("impl_trait_ref (liberated) = {}",
-           impl_trait_ref.repr(tcx));
-
-    let infcx = infer::new_infer_ctxt(tcx);
-    let mut fulfillment_cx = traits::FulfillmentContext::new();
-
-    let trait_to_impl_substs = &impl_trait_ref.substs;
-
-    // Try to give more informative error messages about self typing
-    // mismatches.  Note that any mismatch will also be detected
-    // below, where we construct a canonical function type that
-    // includes the self parameter as a normal parameter.  It's just
-    // that the error messages you get out of this code are a bit more
-    // inscrutable, particularly for cases where one method has no
-    // self.
-    match (&trait_m.explicit_self, &impl_m.explicit_self) {
-        (&ty::StaticExplicitSelfCategory,
-         &ty::StaticExplicitSelfCategory) => {}
-        (&ty::StaticExplicitSelfCategory, _) => {
-            tcx.sess.span_err(
-                impl_m_span,
-                &format!("method `{}` has a `{}` declaration in the impl, \
-                        but not in the trait",
-                        token::get_name(trait_m.name),
-                        ppaux::explicit_self_category_to_str(
-                            &impl_m.explicit_self))[]);
-            return;
-        }
-        (_, &ty::StaticExplicitSelfCategory) => {
-            tcx.sess.span_err(
-                impl_m_span,
-                &format!("method `{}` has a `{}` declaration in the trait, \
-                        but not in the impl",
-                        token::get_name(trait_m.name),
-                        ppaux::explicit_self_category_to_str(
-                            &trait_m.explicit_self))[]);
-            return;
-        }
-        _ => {
-            // Let the type checker catch other errors below
-        }
-    }
-
-    let num_impl_m_type_params = impl_m.generics.types.len(subst::FnSpace);
-    let num_trait_m_type_params = trait_m.generics.types.len(subst::FnSpace);
-    if num_impl_m_type_params != num_trait_m_type_params {
-        span_err!(tcx.sess, impl_m_span, E0049,
-            "method `{}` has {} type parameter{} \
-             but its trait declaration has {} type parameter{}",
-            token::get_name(trait_m.name),
-            num_impl_m_type_params,
-            if num_impl_m_type_params == 1 {""} else {"s"},
-            num_trait_m_type_params,
-            if num_trait_m_type_params == 1 {""} else {"s"});
-        return;
-    }
-
-    if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() {
-        span_err!(tcx.sess, impl_m_span, E0050,
-            "method `{}` has {} parameter{} \
-             but the declaration in trait `{}` has {}",
-            token::get_name(trait_m.name),
-            impl_m.fty.sig.0.inputs.len(),
-            if impl_m.fty.sig.0.inputs.len() == 1 {""} else {"s"},
-            ty::item_path_str(tcx, trait_m.def_id),
-            trait_m.fty.sig.0.inputs.len());
-        return;
-    }
-
-    // This code is best explained by example. Consider a trait:
-    //
-    //     trait Trait<'t,T> {
-    //          fn method<'a,M>(t: &'t T, m: &'a M) -> Self;
-    //     }
-    //
-    // And an impl:
-    //
-    //     impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
-    //          fn method<'b,N>(t: &'j &'i U, m: &'b N) -> Foo;
-    //     }
-    //
-    // We wish to decide if those two method types are compatible.
-    //
-    // We start out with trait_to_impl_substs, that maps the trait
-    // type parameters to impl type parameters. This is taken from the
-    // impl trait reference:
-    //
-    //     trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
-    //
-    // We create a mapping `dummy_substs` that maps from the impl type
-    // parameters to fresh types and regions. For type parameters,
-    // this is the identity transform, but we could as well use any
-    // skolemized types. For regions, we convert from bound to free
-    // regions (Note: but only early-bound regions, i.e., those
-    // declared on the impl or used in type parameter bounds).
-    //
-    //     impl_to_skol_substs = {'i => 'i0, U => U0, N => N0 }
-    //
-    // Now we can apply skol_substs to the type of the impl method
-    // to yield a new function type in terms of our fresh, skolemized
-    // types:
-    //
-    //     <'b> fn(t: &'i0 U0, m: &'b) -> Foo
-    //
-    // We now want to extract and substitute the type of the *trait*
-    // method and compare it. To do so, we must create a compound
-    // substitution by combining trait_to_impl_substs and
-    // impl_to_skol_substs, and also adding a mapping for the method
-    // type parameters. We extend the mapping to also include
-    // the method parameters.
-    //
-    //     trait_to_skol_substs = { T => &'i0 U0, Self => Foo, M => N0 }
-    //
-    // Applying this to the trait method type yields:
-    //
-    //     <'a> fn(t: &'i0 U0, m: &'a) -> Foo
-    //
-    // This type is also the same but the name of the bound region ('a
-    // vs 'b).  However, the normal subtyping rules on fn types handle
-    // this kind of equivalency just fine.
-
-    // Create mapping from impl to skolemized.
-    let impl_param_env = ty::construct_parameter_environment(tcx, &impl_m.generics, impl_m_body_id);
-    let impl_to_skol_substs = &impl_param_env.free_substs;
-
-    // Create mapping from trait to skolemized.
-    let trait_to_skol_substs =
-        trait_to_impl_substs
-        .subst(tcx, impl_to_skol_substs)
-        .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
-                     impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
-
-    // Check region bounds.
-    if !check_region_bounds_on_impl_method(tcx,
-                                           impl_m_span,
-                                           impl_m,
-                                           &trait_m.generics,
-                                           &impl_m.generics,
-                                           &trait_to_skol_substs,
-                                           impl_to_skol_substs) {
-        return;
-    }
-
-    // Check bounds. Note that the bounds from the impl may reference
-    // late-bound regions declared on the impl, so liberate those.
-    // This requires two artificial binding scopes -- one for the impl,
-    // and one for the method.
-    //
-    // An example would be:
-    //
-    //     trait Foo<T> { fn method<U:Bound<T>>() { ... } }
-    //
-    //     impl<'a> Foo<&'a T> for &'a U {
-    //         fn method<U:Bound<&'a T>>() { ... }
-    //     }
-    //
-    // Here, the region parameter `'a` is late-bound, so in the bound
-    // `Bound<&'a T>`, the lifetime `'a` will be late-bound with a
-    // depth of 3 (it is nested within 3 binders: the impl, method,
-    // and trait-ref itself). So when we do the liberation, we have
-    // two introduce two `ty::Binder` scopes, one for the impl and one
-    // the method.
-    //
-    // The only late-bounded regions that can possibly appear here are
-    // from the impl, not the method. This is because region
-    // parameters declared on the method which appear in a type bound
-    // would be early bound. On the trait side, there can be no
-    // late-bound lifetimes because trait definitions do not introduce
-    // a late region binder.
-    let trait_bounds =
-        trait_m.generics.types.get_slice(subst::FnSpace).iter()
-        .map(|trait_param_def| &trait_param_def.bounds);
-    let impl_bounds =
-        impl_m.generics.types.get_slice(subst::FnSpace).iter()
-        .map(|impl_param_def| &impl_param_def.bounds);
-    for (i, (trait_param_bounds, impl_param_bounds)) in
-        trait_bounds.zip(impl_bounds).enumerate()
-    {
-        // Check that the impl does not require any builtin-bounds
-        // that the trait does not guarantee:
-        let extra_bounds =
-            impl_param_bounds.builtin_bounds -
-            trait_param_bounds.builtin_bounds;
-        if !extra_bounds.is_empty() {
-            span_err!(tcx.sess, impl_m_span, E0051,
-                "in method `{}`, type parameter {} requires `{}`, \
-                 which is not required by the corresponding type parameter \
-                 in the trait declaration",
-                token::get_name(trait_m.name),
-                i,
-                extra_bounds.user_string(tcx));
-           return;
-        }
-
-        // Check that the trait bounds of the trait imply the bounds of its
-        // implementation.
-        //
-        // FIXME(pcwalton): We could be laxer here regarding sub- and super-
-        // traits, but I doubt that'll be wanted often, so meh.
-        for impl_trait_bound in impl_param_bounds.trait_bounds.iter() {
-            debug!("compare_impl_method(): impl-trait-bound subst");
-            let impl_trait_bound =
-                impl_trait_bound.subst(tcx, impl_to_skol_substs);
-
-            // There may be late-bound regions from the impl in the
-            // impl's bound, so "liberate" those. Note that the
-            // trait_to_skol_substs is derived from the impl's
-            // trait-ref, and the late-bound regions appearing there
-            // have already been liberated, so the result should match
-            // up.
-
-            let found_match_in_trait =
-                trait_param_bounds.trait_bounds.iter().any(|trait_bound| {
-                    debug!("compare_impl_method(): trait-bound subst");
-                    let trait_bound =
-                        trait_bound.subst(tcx, &trait_to_skol_substs);
-                    infer::mk_sub_poly_trait_refs(&infcx,
-                                                  true,
-                                                  infer::Misc(impl_m_span),
-                                                  trait_bound,
-                                                  impl_trait_bound.clone()).is_ok()
-                });
-
-            if !found_match_in_trait {
-                span_err!(tcx.sess, impl_m_span, E0052,
-                          "in method `{}`, type parameter {} requires bound `{}`, which is not \
-                           required by the corresponding type parameter in the trait declaration",
-                          token::get_name(trait_m.name),
-                          i,
-                          impl_trait_bound.user_string(tcx));
-            }
-        }
-    }
-
-    // We now need to check that the signature of the impl method is
-    // compatible with that of the trait method. We do this by
-    // checking that `impl_fty <: trait_fty`.
-    //
-    // FIXME. Unfortunately, this doesn't quite work right now because
-    // associated type normalization is not integrated into subtype
-    // checks. For the comparison to be valid, we need to
-    // normalize the associated types in the impl/trait methods
-    // first. However, because function types bind regions, just
-    // calling `normalize_associated_types_in` would have no effect on
-    // any associated types appearing in the fn arguments or return
-    // type.
-
-
-    // Compute skolemized form of impl and trait method tys.
-    let impl_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(impl_m.fty.clone()));
-    let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs);
-    let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone()));
-    let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
-
-    let err = infcx.try(|snapshot| {
-        let origin = infer::MethodCompatCheck(impl_m_span);
-
-        let (impl_sig, _) =
-            infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
-                                                            infer::HigherRankedType,
-                                                            &impl_m.fty.sig);
-        let impl_sig =
-            impl_sig.subst(tcx, impl_to_skol_substs);
-        let impl_sig =
-            assoc::normalize_associated_types_in(&infcx,
-                                                 &impl_param_env,
-                                                 &mut fulfillment_cx,
-                                                 impl_m_span,
-                                                 impl_m_body_id,
-                                                 &impl_sig);
-        let impl_fty =
-            ty::mk_bare_fn(tcx,
-                           None,
-                           tcx.mk_bare_fn(ty::BareFnTy { unsafety: impl_m.fty.unsafety,
-                                                         abi: impl_m.fty.abi,
-                                                         sig: ty::Binder(impl_sig) }));
-        debug!("compare_impl_method: impl_fty={}",
-               impl_fty.repr(tcx));
-
-        let (trait_sig, skol_map) =
-            infcx.skolemize_late_bound_regions(&trait_m.fty.sig, snapshot);
-        let trait_sig =
-            trait_sig.subst(tcx, &trait_to_skol_substs);
-        let trait_sig =
-            assoc::normalize_associated_types_in(&infcx,
-                                                 &impl_param_env,
-                                                 &mut fulfillment_cx,
-                                                 impl_m_span,
-                                                 impl_m_body_id,
-                                                 &trait_sig);
-        let trait_fty =
-            ty::mk_bare_fn(tcx,
-                           None,
-                           tcx.mk_bare_fn(ty::BareFnTy { unsafety: trait_m.fty.unsafety,
-                                                         abi: trait_m.fty.abi,
-                                                         sig: ty::Binder(trait_sig) }));
-
-        debug!("compare_impl_method: trait_fty={}",
-               trait_fty.repr(tcx));
-
-        try!(infer::mk_subty(&infcx, false, origin, impl_fty, trait_fty));
-
-        infcx.leak_check(&skol_map, snapshot)
-    });
-
-    match err {
-        Ok(()) => { }
-        Err(terr) => {
-            debug!("checking trait method for compatibility: impl ty {}, trait ty {}",
-                   impl_fty.repr(tcx),
-                   trait_fty.repr(tcx));
-            span_err!(tcx.sess, impl_m_span, E0053,
-                      "method `{}` has an incompatible type for trait: {}",
-                      token::get_name(trait_m.name),
-                      ty::type_err_to_str(tcx, &terr));
-            return;
-        }
-    }
-
-    // Run the fulfillment context to completion to accommodate any
-    // associated type normalizations that may have occurred.
-    match fulfillment_cx.select_all_or_error(&infcx, &impl_param_env) {
-        Ok(()) => { }
-        Err(errors) => {
-            traits::report_fulfillment_errors(&infcx, &errors);
-        }
-    }
-
-    // Finally, resolve all regions. This catches wily misuses of lifetime
-    // parameters.
-    infcx.resolve_regions_and_report_errors(impl_m_body_id);
-
-    /// Check that region bounds on impl method are the same as those on the trait. In principle,
-    /// it could be ok for there to be fewer region bounds on the impl method, but this leads to an
-    /// annoying corner case that is painful to handle (described below), so for now we can just
-    /// forbid it.
-    ///
-    /// Example (see `src/test/compile-fail/regions-bound-missing-bound-in-impl.rs`):
-    ///
-    /// ```
-    /// trait Foo<'a> {
-    ///     fn method1<'b>();
-    ///     fn method2<'b:'a>();
-    /// }
-    ///
-    /// impl<'a> Foo<'a> for ... {
-    ///     fn method1<'b:'a>() { .. case 1, definitely bad .. }
-    ///     fn method2<'b>() { .. case 2, could be ok .. }
-    /// }
-    /// ```
-    ///
-    /// The "definitely bad" case is case #1. Here, the impl adds an extra constraint not present
-    /// in the trait.
-    ///
-    /// The "maybe bad" case is case #2. Here, the impl adds an extra constraint not present in the
-    /// trait. We could in principle allow this, but it interacts in a complex way with early/late
-    /// bound resolution of lifetimes. Basically the presence or absence of a lifetime bound
-    /// affects whether the lifetime is early/late bound, and right now the code breaks if the
-    /// trait has an early bound lifetime parameter and the method does not.
-    fn check_region_bounds_on_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                                span: Span,
-                                                impl_m: &ty::Method<'tcx>,
-                                                trait_generics: &ty::Generics<'tcx>,
-                                                impl_generics: &ty::Generics<'tcx>,
-                                                trait_to_skol_substs: &Substs<'tcx>,
-                                                impl_to_skol_substs: &Substs<'tcx>)
-                                                -> bool
-    {
-
-        let trait_params = trait_generics.regions.get_slice(subst::FnSpace);
-        let impl_params = impl_generics.regions.get_slice(subst::FnSpace);
-
-        debug!("check_region_bounds_on_impl_method: \
-               trait_generics={} \
-               impl_generics={} \
-               trait_to_skol_substs={} \
-               impl_to_skol_substs={}",
-               trait_generics.repr(tcx),
-               impl_generics.repr(tcx),
-               trait_to_skol_substs.repr(tcx),
-               impl_to_skol_substs.repr(tcx));
-
-        // Must have same number of early-bound lifetime parameters.
-        // Unfortunately, if the user screws up the bounds, then this
-        // will change classification between early and late.  E.g.,
-        // if in trait we have `<'a,'b:'a>`, and in impl we just have
-        // `<'a,'b>`, then we have 2 early-bound lifetime parameters
-        // in trait but 0 in the impl. But if we report "expected 2
-        // but found 0" it's confusing, because it looks like there
-        // are zero. Since I don't quite know how to phrase things at
-        // the moment, give a kind of vague error message.
-        if trait_params.len() != impl_params.len() {
-            tcx.sess.span_err(
-                span,
-                &format!("lifetime parameters or bounds on method `{}` do \
-                         not match the trait declaration",
-                        token::get_name(impl_m.name))[]);
-            return false;
-        }
-
-        // Each parameter `'a:'b+'c+'d` in trait should have the same
-        // set of bounds in the impl, after subst.
-        for (trait_param, impl_param) in
-            trait_params.iter().zip(
-                impl_params.iter())
-        {
-            let trait_bounds =
-                trait_param.bounds.subst(tcx, trait_to_skol_substs);
-            let impl_bounds =
-                impl_param.bounds.subst(tcx, impl_to_skol_substs);
-
-            debug!("check_region_bounds_on_impl_method: \
-                   trait_param={} \
-                   impl_param={} \
-                   trait_bounds={} \
-                   impl_bounds={}",
-                   trait_param.repr(tcx),
-                   impl_param.repr(tcx),
-                   trait_bounds.repr(tcx),
-                   impl_bounds.repr(tcx));
-
-            // Collect the set of bounds present in trait but not in
-            // impl.
-            let missing: Vec<ty::Region> =
-                trait_bounds.iter()
-                .filter(|&b| !impl_bounds.contains(b))
-                .map(|&b| b)
-                .collect();
-
-            // Collect set present in impl but not in trait.
-            let extra: Vec<ty::Region> =
-                impl_bounds.iter()
-                .filter(|&b| !trait_bounds.contains(b))
-                .map(|&b| b)
-                .collect();
-
-            debug!("missing={} extra={}",
-                   missing.repr(tcx), extra.repr(tcx));
-
-            let err = if missing.len() != 0 || extra.len() != 0 {
-                tcx.sess.span_err(
-                    span,
-                    &format!(
-                        "the lifetime parameter `{}` declared in the impl \
-                         has a distinct set of bounds \
-                         from its counterpart `{}` \
-                         declared in the trait",
-                        impl_param.name.user_string(tcx),
-                        trait_param.name.user_string(tcx))[]);
-                true
-            } else {
-                false
-            };
-
-            if missing.len() != 0 {
-                tcx.sess.span_note(
-                    span,
-                    &format!("the impl is missing the following bounds: `{}`",
-                            missing.user_string(tcx))[]);
-            }
-
-            if extra.len() != 0 {
-                tcx.sess.span_note(
-                    span,
-                    &format!("the impl has the following extra bounds: `{}`",
-                            extra.user_string(tcx))[]);
-            }
-
-            if err {
-                return false;
-            }
-        }
-
-        return true;
-    }
-}
-
 fn check_cast(fcx: &FnCtxt,
               cast_expr: &ast::Expr,
               e: &ast::Expr,
@@ -2093,7 +1597,6 @@ pub fn register_predicate(&self,
     {
         debug!("register_predicate({})",
                obligation.repr(self.tcx()));
-
         self.inh.fulfillment_cx
             .borrow_mut()
             .register_predicate_obligation(self.infcx(), obligation);
@@ -2289,6 +1792,34 @@ pub fn add_obligations_for_parameters(&self,
 
         obligations.map_move(|o| self.register_predicate(o));
     }
+
+    // Only for fields! Returns <none> for methods>
+    // Indifferent to privacy flags
+    pub fn lookup_field_ty(&self,
+                           span: Span,
+                           class_id: ast::DefId,
+                           items: &[ty::field_ty],
+                           fieldname: ast::Name,
+                           substs: &subst::Substs<'tcx>)
+                           -> Option<Ty<'tcx>>
+    {
+        let o_field = items.iter().find(|f| f.name == fieldname);
+        o_field.map(|f| ty::lookup_field_type(self.tcx(), class_id, f.id, substs))
+               .map(|t| self.normalize_associated_types_in(span, &t))
+    }
+
+    pub fn lookup_tup_field_ty(&self,
+                               span: Span,
+                               class_id: ast::DefId,
+                               items: &[ty::field_ty],
+                               idx: uint,
+                               substs: &subst::Substs<'tcx>)
+                               -> Option<Ty<'tcx>>
+    {
+        let o_field = if idx < items.len() { Some(&items[idx]) } else { None };
+        o_field.map(|f| ty::lookup_field_type(self.tcx(), class_id, f.id, substs))
+               .map(|t| self.normalize_associated_types_in(span, &t))
+    }
 }
 
 impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {
@@ -3043,30 +2574,6 @@ pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     TypeAndSubsts { substs: substs, ty: substd_ty }
 }
 
-// Only for fields! Returns <none> for methods>
-// Indifferent to privacy flags
-pub fn lookup_field_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
-                             class_id: ast::DefId,
-                             items: &[ty::field_ty],
-                             fieldname: ast::Name,
-                             substs: &subst::Substs<'tcx>)
-                             -> Option<Ty<'tcx>> {
-
-    let o_field = items.iter().find(|f| f.name == fieldname);
-    o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
-}
-
-pub fn lookup_tup_field_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                 class_id: ast::DefId,
-                                 items: &[ty::field_ty],
-                                 idx: uint,
-                                 substs: &subst::Substs<'tcx>)
-                                 -> Option<Ty<'tcx>> {
-
-    let o_field = if idx < items.len() { Some(&items[idx]) } else { None };
-    o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
-}
-
 // Controls whether the arguments are automatically referenced. This is useful
 // for overloaded binary and unary operators.
 #[derive(Copy, PartialEq)]
@@ -3530,8 +3037,8 @@ fn check_field(fcx: &FnCtxt,
                     ty::ty_struct(base_id, substs) => {
                         debug!("struct named {}", ppaux::ty_to_string(tcx, base_t));
                         let fields = ty::lookup_struct_fields(tcx, base_id);
-                        lookup_field_ty(tcx, base_id, &fields[],
-                                        field.node.name, &(*substs))
+                        fcx.lookup_field_ty(expr.span, base_id, &fields[],
+                                            field.node.name, &(*substs))
                     }
                     _ => None
                 }
@@ -3593,8 +3100,8 @@ fn check_tup_field(fcx: &FnCtxt,
                         if tuple_like {
                             debug!("tuple struct named {}", ppaux::ty_to_string(tcx, base_t));
                             let fields = ty::lookup_struct_fields(tcx, base_id);
-                            lookup_tup_field_ty(tcx, base_id, &fields[],
-                                                idx.node, &(*substs))
+                            fcx.lookup_tup_field_ty(expr.span, base_id, &fields[],
+                                                    idx.node, &(*substs))
                         } else {
                             None
                         }
@@ -4045,10 +3552,25 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
         };
         fcx.write_ty(id, oprnd_t);
       }
-      ast::ExprPath(ref pth) => {
-          let defn = lookup_def(fcx, pth.span, id);
+      ast::ExprPath(ref path) => {
+          let defn = lookup_def(fcx, path.span, id);
+          let pty = type_scheme_for_def(fcx, expr.span, defn);
+          instantiate_path(fcx, path, pty, None, defn, expr.span, expr.id);
+
+          // We always require that the type provided as the value for
+          // a type parameter outlives the moment of instantiation.
+          constrain_path_type_parameters(fcx, expr);
+      }
+      ast::ExprQPath(ref qpath) => {
+          // Require explicit type params for the trait.
+          let self_ty = fcx.to_ty(&*qpath.self_type);
+          astconv::instantiate_trait_ref(fcx, fcx, &*qpath.trait_ref, Some(self_ty), None);
+
+          let defn = lookup_def(fcx, expr.span, id);
           let pty = type_scheme_for_def(fcx, expr.span, defn);
-          instantiate_path(fcx, pth, pty, defn, expr.span, expr.id);
+          let mut path = qpath.trait_ref.path.clone();
+          path.segments.push(qpath.item_path.clone());
+          instantiate_path(fcx, &path, pty, Some(self_ty), defn, expr.span, expr.id);
 
           // We always require that the type provided as the value for
           // a type parameter outlives the moment of instantiation.
@@ -5111,6 +4633,7 @@ pub fn type_scheme_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                   path: &ast::Path,
                                   type_scheme: TypeScheme<'tcx>,
+                                  opt_self_ty: Option<Ty<'tcx>>,
                                   def: def::Def,
                                   span: Span,
                                   node_id: ast::NodeId) {
@@ -5268,6 +4791,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             }
         }
     }
+    if let Some(self_ty) = opt_self_ty {
+        // `<T as Trait>::foo` shouldn't have resolved to a `Self`-less item.
+        assert_eq!(type_defs.len(subst::SelfSpace), 1);
+        substs.types.push(subst::SelfSpace, self_ty);
+    }
 
     // Now we have to compare the types that the user *actually*
     // provided against the types that were *expected*. If the user
index 89de1ea80fcf42fd2328c9e19f92b9b409a99791..e6390212c6002ca09d726ac418be058dfef8c704 100644 (file)
@@ -56,9 +56,38 @@ fn check_item_well_formed(&mut self, item: &ast::Item) {
                ty::item_path_str(ccx.tcx, local_def(item.id)));
 
         match item.node {
-            ast::ItemImpl(..) => {
+            /// Right now we check that every default trait implementation
+            /// has an implementation of itself. Basically, a case like:
+            ///
+            /// `impl Trait for T {}`
+            ///
+            /// has a requirement of `T: Trait` which was required for default
+            /// method implementations. Although this could be improved now that
+            /// there's a better infrastructure in place for this, it's being left
+            /// for a follow-up work.
+            ///
+            /// Since there's such a requirement, we need to check *just* positive
+            /// implementations, otherwise things like:
+            ///
+            /// impl !Send for T {}
+            ///
+            /// won't be allowed unless there's an *explicit* implementation of `Send`
+            /// for `T`
+            ast::ItemImpl(_, ast::ImplPolarity::Positive, _, _, _, _) => {
                 self.check_impl(item);
             }
+            ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(ref tref), _, _) => {
+                let trait_ref = ty::node_id_to_trait_ref(ccx.tcx, tref.ref_id);
+                match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
+                    Some(ty::BoundSend) | Some(ty::BoundSync) => {}
+                    Some(_) | None => {
+                        ccx.tcx.sess.span_err(
+                            item.span,
+                            format!("negative impls are currently \
+                                     allowed just for `Send` and `Sync`").as_slice())
+                    }
+                }
+            }
             ast::ItemFn(..) => {
                 self.check_item_type(item);
             }
diff --git a/src/librustc_typeck/coherence/impls.rs b/src/librustc_typeck/coherence/impls.rs
new file mode 100644 (file)
index 0000000..2719a09
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2015 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.
+
+//! Implementations checker: builtin traits and default impls are allowed just
+//! for structs and enums.
+
+use middle::ty;
+use syntax::ast::{Item, ItemImpl};
+use syntax::ast;
+use syntax::visit;
+
+pub fn check(tcx: &ty::ctxt) {
+    let mut impls = ImplsChecker { tcx: tcx };
+    visit::walk_crate(&mut impls, tcx.map.krate());
+}
+
+struct ImplsChecker<'cx, 'tcx:'cx> {
+    tcx: &'cx ty::ctxt<'tcx>
+}
+
+impl<'cx, 'tcx,'v> visit::Visitor<'v> for ImplsChecker<'cx, 'tcx> {
+    fn visit_item(&mut self, item: &'v ast::Item) {
+        match item.node {
+            ast::ItemImpl(_, _, _, Some(ref opt_trait), _, _) => {
+                let trait_ref = ty::node_id_to_trait_ref(self.tcx, opt_trait.ref_id);
+                if let Some(_) = self.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
+                    match trait_ref.self_ty().sty {
+                        ty::ty_struct(..) | ty::ty_enum(..) => {}
+                        _ => {
+                            self.tcx.sess.span_err(
+                                item.span,
+                                &format!("builtin traits can only be \
+                                          implemented on structs or enums")[]);
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+    }
+}
index 9d4aa23960db957fd83c15bc34a3d50cbc547f4e..a7ef4c1e9f2a572a9c1409d61d7cb62aff5cdf09 100644 (file)
@@ -49,6 +49,7 @@
 use util::nodemap::{DefIdMap, FnvHashMap};
 use util::ppaux::Repr;
 
+mod impls;
 mod orphan;
 mod overlap;
 mod unsafety;
@@ -596,6 +597,7 @@ pub fn check_coherence(crate_context: &CrateCtxt) {
         inference_context: new_infer_ctxt(crate_context.tcx),
         inherent_impls: RefCell::new(FnvHashMap::new()),
     }.check(crate_context.tcx.map.krate());
+    impls::check(crate_context.tcx);
     unsafety::check(crate_context.tcx);
     orphan::check(crate_context.tcx);
     overlap::check(crate_context.tcx);
index f618a79e27de791a63fb7ec2bca4431c3b046364..ce7ba9ac11e6576c04921bafb3575f3fce7d84d6 100644 (file)
@@ -38,36 +38,34 @@ fn check_for_overlapping_impls(&self) {
         // check_for_overlapping_impls_of_trait() check, since that
         // check can populate this table further with impls from other
         // crates.
-        let trait_def_ids: Vec<ast::DefId> =
-            self.tcx.trait_impls.borrow().keys().map(|&d| d).collect();
-
-        for trait_def_id in trait_def_ids.iter() {
-            self.check_for_overlapping_impls_of_trait(*trait_def_id);
+        let trait_def_ids: Vec<(ast::DefId, Vec<ast::DefId>)> =
+            self.tcx.trait_impls.borrow().iter().map(|(&k, v)| {
+                // FIXME -- it seems like this method actually pushes
+                // duplicate impls onto the list
+                ty::populate_implementations_for_trait_if_necessary(self.tcx, k);
+                (k, v.borrow().clone())
+            }).collect();
+
+        for &(trait_def_id, ref impls) in trait_def_ids.iter() {
+            self.check_for_overlapping_impls_of_trait(trait_def_id, impls);
         }
     }
 
     fn check_for_overlapping_impls_of_trait(&self,
-                                            trait_def_id: ast::DefId)
+                                            trait_def_id: ast::DefId,
+                                            trait_impls: &Vec<ast::DefId>)
     {
         debug!("check_for_overlapping_impls_of_trait(trait_def_id={})",
                trait_def_id.repr(self.tcx));
 
-        // FIXME -- it seems like this method actually pushes
-        // duplicate impls onto the list
-        ty::populate_implementations_for_trait_if_necessary(self.tcx,
-                                                            trait_def_id);
-
-        let mut impls = Vec::new();
-        self.push_impls_of_trait(trait_def_id, &mut impls);
-
-        for (i, &impl1_def_id) in impls.iter().enumerate() {
+        for (i, &impl1_def_id) in trait_impls.iter().enumerate() {
             if impl1_def_id.krate != ast::LOCAL_CRATE {
                 // we don't need to check impls if both are external;
                 // that's the other crate's job.
                 continue;
             }
 
-            for &impl2_def_id in impls.slice_from(i+1).iter() {
+            for &impl2_def_id in trait_impls.slice_from(i+1).iter() {
                 self.check_if_impls_overlap(trait_def_id,
                                             impl1_def_id,
                                             impl2_def_id);
@@ -108,15 +106,6 @@ fn check_if_impls_overlap(&self,
         }
     }
 
-    fn push_impls_of_trait(&self,
-                           trait_def_id: ast::DefId,
-                           out: &mut Vec<ast::DefId>) {
-        match self.tcx.trait_impls.borrow().get(&trait_def_id) {
-            Some(impls) => { out.push_all(impls.borrow().as_slice()); }
-            None => { /* no impls */ }
-        }
-    }
-
     fn span_of_impl(&self, impl_did: ast::DefId) -> Span {
         assert_eq!(impl_did.krate, ast::LOCAL_CRATE);
         self.tcx.map.span(impl_did.node)
index 1acea6fd58179eac948cd3085b65f8247ffa2981..e30d0a29938aa91090365b87c7cc8fd1c5bbd2c1 100644 (file)
@@ -30,7 +30,7 @@ struct UnsafetyChecker<'cx, 'tcx:'cx> {
 impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v ast::Item) {
         match item.node {
-            ast::ItemImpl(unsafety, _, _, _, _, _) => {
+            ast::ItemImpl(unsafety, polarity, _, _, _, _) => {
                 match ty::impl_trait_ref(self.tcx, ast_util::local_def(item.id)) {
                     None => {
                         // Inherent impl.
@@ -46,23 +46,34 @@ fn visit_item(&mut self, item: &'v ast::Item) {
 
                     Some(trait_ref) => {
                         let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id);
-                        match (trait_def.unsafety, unsafety) {
-                            (ast::Unsafety::Normal, ast::Unsafety::Unsafe) => {
+                        match (trait_def.unsafety, unsafety, polarity) {
+                            (ast::Unsafety::Unsafe,
+                             ast::Unsafety::Unsafe, ast::ImplPolarity::Negative) => {
+                                self.tcx.sess.span_err(
+                                    item.span,
+                                    format!("negative implementations are not unsafe").as_slice());
+                            }
+
+                            (ast::Unsafety::Normal, ast::Unsafety::Unsafe, _) => {
                                 self.tcx.sess.span_err(
                                     item.span,
                                     format!("implementing the trait `{}` is not unsafe",
                                             trait_ref.user_string(self.tcx)).as_slice());
                             }
 
-                            (ast::Unsafety::Unsafe, ast::Unsafety::Normal) => {
+                            (ast::Unsafety::Unsafe,
+                             ast::Unsafety::Normal, ast::ImplPolarity::Positive) => {
                                 self.tcx.sess.span_err(
                                     item.span,
                                     format!("the trait `{}` requires an `unsafe impl` declaration",
                                             trait_ref.user_string(self.tcx)).as_slice());
                             }
 
-                            (ast::Unsafety::Unsafe, ast::Unsafety::Unsafe) |
-                            (ast::Unsafety::Normal, ast::Unsafety::Normal) => {
+                            (ast::Unsafety::Unsafe,
+                             ast::Unsafety::Normal, ast::ImplPolarity::Negative) |
+                            (ast::Unsafety::Unsafe,
+                             ast::Unsafety::Unsafe, ast::ImplPolarity::Positive) |
+                            (ast::Unsafety::Normal, ast::Unsafety::Normal, _) => {
                                 /* OK */
                             }
                         }
index 68b152dee233b4ea86be313adcf9076049d2e6f8..88fe88bf2654052346aff8a87763b075df8b5f61 100644 (file)
 use syntax::{ast, ast_map, abi};
 use syntax::ast_util::local_def;
 
+use std::cell::RefCell;
+
 mod check;
 mod rscope;
 mod astconv;
@@ -123,6 +125,11 @@ struct TypeAndSubsts<'tcx> {
 struct CrateCtxt<'a, 'tcx: 'a> {
     // A mapping from method call sites to traits that have that method.
     trait_map: ty::TraitMap,
+    /// A vector of every trait accessible in the whole crate
+    /// (i.e. including those from subcrates). This is used only for
+    /// error reporting, and so is lazily initialised and generally
+    /// shouldn't taint the common path (hence the RefCell).
+    all_traits: RefCell<Option<check::method::AllTraitsVec>>,
     tcx: &'a ty::ctxt<'tcx>,
 }
 
@@ -320,6 +327,7 @@ pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) {
     let time_passes = tcx.sess.time_passes();
     let ccx = CrateCtxt {
         trait_map: trait_map,
+        all_traits: RefCell::new(None),
         tcx: tcx
     };
 
index 3e2474468adb696c8edc83717f67794a538c0973..ccaefadc1fcd963e281e00a6e788792df3f8df60 100644 (file)
@@ -126,13 +126,8 @@ fn try_inline_def(cx: &DocContext, tcx: &ty::ctxt,
 
 pub fn load_attrs(cx: &DocContext, tcx: &ty::ctxt,
                   did: ast::DefId) -> Vec<clean::Attribute> {
-    let mut attrs = Vec::new();
-    csearch::get_item_attrs(&tcx.sess.cstore, did, |v| {
-        attrs.extend(v.into_iter().map(|a| {
-            a.clean(cx)
-        }));
-    });
-    attrs
+    let attrs = csearch::get_item_attrs(&tcx.sess.cstore, did);
+    attrs.into_iter().map(|a| a.clean(cx)).collect()
 }
 
 /// Record an external fully qualified name in the external_paths cache.
index a44c73e8c4120f91d9b986673e6a68273003faf8..8dc3adad3b27a010feae9758f61c427960daaf76 100644 (file)
@@ -104,6 +104,12 @@ fn clean(&self, cx: &DocContext) -> Option<U> {
     }
 }
 
+impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
+    fn clean(&self, cx: &DocContext) -> U {
+        self.0.clean(cx)
+    }
+}
+
 impl<T: Clean<U>, U> Clean<Vec<U>> for syntax::owned_slice::OwnedSlice<T> {
     fn clean(&self, cx: &DocContext) -> Vec<U> {
         self.iter().map(|x| x.clean(cx)).collect()
@@ -498,22 +504,28 @@ fn clean(&self, cx: &DocContext) -> TyParamBound {
     }
 }
 
-impl<'tcx> Clean<Vec<TyParamBound>> for ty::ExistentialBounds<'tcx> {
-    fn clean(&self, cx: &DocContext) -> Vec<TyParamBound> {
-        let mut vec = vec![];
-        self.region_bound.clean(cx).map(|b| vec.push(RegionBound(b)));
+impl<'tcx> Clean<(Vec<TyParamBound>, Vec<TypeBinding>)> for ty::ExistentialBounds<'tcx> {
+    fn clean(&self, cx: &DocContext) -> (Vec<TyParamBound>, Vec<TypeBinding>) {
+        let mut tp_bounds = vec![];
+        self.region_bound.clean(cx).map(|b| tp_bounds.push(RegionBound(b)));
         for bb in self.builtin_bounds.iter() {
-            vec.push(bb.clean(cx));
+            tp_bounds.push(bb.clean(cx));
         }
 
-        // FIXME(#20299) -- should do something with projection bounds
+        let mut bindings = vec![];
+        for &ty::Binder(ref pb) in self.projection_bounds.iter() {
+            bindings.push(TypeBinding {
+                name: pb.projection_ty.item_name.clean(cx),
+                ty: pb.ty.clean(cx)
+            });
+        }
 
-        vec
+        (tp_bounds, bindings)
     }
 }
 
 fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
-                        substs: &subst::Substs) -> PathParameters {
+                        bindings: Vec<TypeBinding>, substs: &subst::Substs) -> PathParameters {
     use rustc::middle::ty::sty;
     let lifetimes = substs.regions().get_slice(subst::TypeSpace)
                     .iter()
@@ -531,7 +543,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
                     return PathParameters::AngleBracketed {
                         lifetimes: lifetimes,
                         types: types.clean(cx),
-                        bindings: vec![]
+                        bindings: bindings
                     }
                 }
             };
@@ -548,7 +560,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
             PathParameters::AngleBracketed {
                 lifetimes: lifetimes,
                 types: types.clean(cx),
-                bindings: vec![] // FIXME(#20646)
+                bindings: bindings
             }
         }
     }
@@ -557,12 +569,12 @@ fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
 // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
 // from Fn<(A, B,), C> to Fn(A, B) -> C
 fn external_path(cx: &DocContext, name: &str, trait_did: Option<ast::DefId>,
-                 substs: &subst::Substs) -> Path {
+                 bindings: Vec<TypeBinding>, substs: &subst::Substs) -> Path {
     Path {
         global: false,
         segments: vec![PathSegment {
             name: name.to_string(),
-            params: external_path_params(cx, trait_did, substs)
+            params: external_path_params(cx, trait_did, bindings, substs)
         }],
     }
 }
@@ -577,16 +589,16 @@ fn clean(&self, cx: &DocContext) -> TyParamBound {
         let (did, path) = match *self {
             ty::BoundSend =>
                 (tcx.lang_items.send_trait().unwrap(),
-                 external_path(cx, "Send", None, &empty)),
+                 external_path(cx, "Send", None, vec![], &empty)),
             ty::BoundSized =>
                 (tcx.lang_items.sized_trait().unwrap(),
-                 external_path(cx, "Sized", None, &empty)),
+                 external_path(cx, "Sized", None, vec![], &empty)),
             ty::BoundCopy =>
                 (tcx.lang_items.copy_trait().unwrap(),
-                 external_path(cx, "Copy", None, &empty)),
+                 external_path(cx, "Copy", None, vec![], &empty)),
             ty::BoundSync =>
                 (tcx.lang_items.sync_trait().unwrap(),
-                 external_path(cx, "Sync", None, &empty)),
+                 external_path(cx, "Sync", None, vec![], &empty)),
         };
         let fqn = csearch::get_item_path(tcx, did);
         let fqn = fqn.into_iter().map(|i| i.to_string()).collect();
@@ -603,12 +615,6 @@ fn clean(&self, cx: &DocContext) -> TyParamBound {
     }
 }
 
-impl<'tcx> Clean<TyParamBound> for ty::PolyTraitRef<'tcx> {
-    fn clean(&self, cx: &DocContext) -> TyParamBound {
-        self.0.clean(cx)
-    }
-}
-
 impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
     fn clean(&self, cx: &DocContext) -> TyParamBound {
         let tcx = match cx.tcx_opt() {
@@ -619,7 +625,7 @@ fn clean(&self, cx: &DocContext) -> TyParamBound {
         let fqn = fqn.into_iter().map(|i| i.to_string())
                      .collect::<Vec<String>>();
         let path = external_path(cx, fqn.last().unwrap().as_slice(),
-                                 Some(self.def_id), self.substs);
+                                 Some(self.def_id), vec![], self.substs);
         cx.external_paths.borrow_mut().as_mut().unwrap().insert(self.def_id,
                                                             (fqn, TypeTrait));
 
@@ -730,8 +736,7 @@ fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
 pub enum WherePredicate {
     BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
     RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
-    // FIXME (#20041)
-    EqPredicate
+    EqPredicate { lhs: Type, rhs: Type }
 }
 
 impl Clean<WherePredicate> for ast::WherePredicate {
@@ -752,12 +757,89 @@ fn clean(&self, cx: &DocContext) -> WherePredicate {
             }
 
             ast::WherePredicate::EqPredicate(_) => {
-                WherePredicate::EqPredicate
+                unimplemented!() // FIXME(#20041)
             }
         }
     }
 }
 
+impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
+    fn clean(&self, cx: &DocContext) -> WherePredicate {
+        use rustc::middle::ty::Predicate;
+
+        match *self {
+            Predicate::Trait(ref pred) => pred.clean(cx),
+            Predicate::Equate(ref pred) => pred.clean(cx),
+            Predicate::RegionOutlives(ref pred) => pred.clean(cx),
+            Predicate::TypeOutlives(ref pred) => pred.clean(cx),
+            Predicate::Projection(ref pred) => pred.clean(cx)
+        }
+    }
+}
+
+impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
+    fn clean(&self, cx: &DocContext) -> WherePredicate {
+        WherePredicate::BoundPredicate {
+            ty: self.trait_ref.substs.self_ty().clean(cx).unwrap(),
+            bounds: vec![self.trait_ref.clean(cx)]
+        }
+    }
+}
+
+impl<'tcx> Clean<WherePredicate> for ty::EquatePredicate<'tcx> {
+    fn clean(&self, cx: &DocContext) -> WherePredicate {
+        let ty::EquatePredicate(ref lhs, ref rhs) = *self;
+        WherePredicate::EqPredicate {
+            lhs: lhs.clean(cx),
+            rhs: rhs.clean(cx)
+        }
+    }
+}
+
+impl Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region, ty::Region> {
+    fn clean(&self, cx: &DocContext) -> WherePredicate {
+        let ty::OutlivesPredicate(ref a, ref b) = *self;
+        WherePredicate::RegionPredicate {
+            lifetime: a.clean(cx).unwrap(),
+            bounds: vec![b.clean(cx).unwrap()]
+        }
+    }
+}
+
+impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, ty::Region> {
+    fn clean(&self, cx: &DocContext) -> WherePredicate {
+        let ty::OutlivesPredicate(ref ty, ref lt) = *self;
+
+        WherePredicate::BoundPredicate {
+            ty: ty.clean(cx),
+            bounds: vec![TyParamBound::RegionBound(lt.clean(cx).unwrap())]
+        }
+    }
+}
+
+impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
+    fn clean(&self, cx: &DocContext) -> WherePredicate {
+        WherePredicate::EqPredicate {
+            lhs: self.projection_ty.clean(cx),
+            rhs: self.ty.clean(cx)
+        }
+    }
+}
+
+impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
+    fn clean(&self, cx: &DocContext) -> Type {
+        let trait_ = match self.trait_ref.clean(cx) {
+            TyParamBound::TraitBound(t, _) => t.trait_,
+            TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"),
+        };
+        Type::QPath {
+            name: self.item_name.clean(cx),
+            self_type: box self.trait_ref.self_ty().clean(cx),
+            trait_: box trait_
+        }
+    }
+}
+
 // maybe use a Generic enum and use ~[Generic]?
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
 pub struct Generics {
@@ -778,11 +860,80 @@ fn clean(&self, cx: &DocContext) -> Generics {
 
 impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>, subst::ParamSpace) {
     fn clean(&self, cx: &DocContext) -> Generics {
-        let (me, space) = *self;
+        use std::collections::HashSet;
+        use syntax::ast::TraitBoundModifier as TBM;
+        use self::WherePredicate as WP;
+
+        fn has_sized_bound(bounds: &[TyParamBound], cx: &DocContext) -> bool {
+            if let Some(tcx) = cx.tcx_opt() {
+                let sized_did = match tcx.lang_items.sized_trait() {
+                    Some(did) => did,
+                    None => return false
+                };
+                for bound in bounds.iter() {
+                    if let TyParamBound::TraitBound(PolyTrait {
+                        trait_: Type::ResolvedPath { did, .. }, ..
+                    }, TBM::None) = *bound {
+                        if did == sized_did {
+                            return true
+                        }
+                    }
+                }
+            }
+            false
+        }
+
+        let (gens, space) = *self;
+        // Bounds in the type_params and lifetimes fields are repeated in the predicates
+        // field (see rustc_typeck::collect::ty_generics), so remove them.
+        let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| {
+            let mut stp = tp.clone();
+            stp.bounds = ty::ParamBounds::empty();
+            stp.clean(cx)
+        }).collect::<Vec<_>>();
+        let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| {
+            let mut srp = rp.clone();
+            srp.bounds = Vec::new();
+            srp.clean(cx)
+        }).collect::<Vec<_>>();
+
+        let where_predicates = gens.predicates.get_slice(space).to_vec().clean(cx);
+        // Type parameters have a Sized bound by default unless removed with ?Sized.
+        // Scan through the predicates and mark any type parameter with a Sized
+        // bound, removing the bounds as we find them.
+        let mut sized_params = HashSet::new();
+        let mut where_predicates = where_predicates.into_iter().filter_map(|pred| {
+            if let WP::BoundPredicate { ty: Type::Generic(ref g), ref bounds } = pred {
+                if has_sized_bound(&**bounds, cx) {
+                    sized_params.insert(g.clone());
+                    return None
+                }
+            }
+            Some(pred)
+        }).collect::<Vec<_>>();
+        // Finally, run through the type parameters again and insert a ?Sized unbound for
+        // any we didn't find to be Sized.
+        for tp in stripped_typarams.iter() {
+            if !sized_params.contains(&tp.name) {
+                let mut sized_bound = ty::BuiltinBound::BoundSized.clean(cx);
+                if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
+                    *tbm = TBM::Maybe
+                };
+                where_predicates.push(WP::BoundPredicate {
+                    ty: Type::Generic(tp.name.clone()),
+                    bounds: vec![sized_bound]
+                })
+            }
+        }
+
+        // It would be nice to collect all of the bounds on a type and recombine
+        // them if possible, to avoid e.g. `where T: Foo, T: Bar, T: Sized, T: 'a`
+        // and instead see `where T: Foo + Bar + Sized + 'a`
+
         Generics {
-            type_params: me.types.get_slice(space).to_vec().clean(cx),
-            lifetimes: me.regions.get_slice(space).to_vec().clean(cx),
-            where_predicates: vec![]
+            type_params: stripped_typarams,
+            lifetimes: stripped_lifetimes,
+            where_predicates: where_predicates
         }
     }
 }
@@ -910,27 +1061,6 @@ fn clean(&self, cx: &DocContext) -> Item {
     }
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
-pub struct ClosureDecl {
-    pub lifetimes: Vec<Lifetime>,
-    pub decl: FnDecl,
-    pub onceness: ast::Onceness,
-    pub unsafety: ast::Unsafety,
-    pub bounds: Vec<TyParamBound>,
-}
-
-impl Clean<ClosureDecl> for ast::ClosureTy {
-    fn clean(&self, cx: &DocContext) -> ClosureDecl {
-        ClosureDecl {
-            lifetimes: self.lifetimes.clean(cx),
-            decl: self.decl.clean(cx),
-            onceness: self.onceness,
-            unsafety: self.unsafety,
-            bounds: self.bounds.clean(cx)
-        }
-    }
-}
-
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
 pub struct FnDecl {
     pub inputs: Arguments,
@@ -1207,8 +1337,6 @@ pub enum Type {
     Generic(String),
     /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
     Primitive(PrimitiveType),
-    Closure(Box<ClosureDecl>),
-    Proc(Box<ClosureDecl>),
     /// extern "ABI" fn
     BareFunction(Box<BareFunctionDecl>),
     Tuple(Vec<Type>),
@@ -1436,7 +1564,7 @@ fn clean(&self, cx: &DocContext) -> Type {
                     _ => TypeEnum,
                 };
                 let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(),
-                                         None, substs);
+                                         None, vec![], substs);
                 cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind));
                 ResolvedPath {
                     path: path,
@@ -1448,12 +1576,13 @@ fn clean(&self, cx: &DocContext) -> Type {
                 let did = principal.def_id();
                 let fqn = csearch::get_item_path(cx.tcx(), did);
                 let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
+                let (typarams, bindings) = bounds.clean(cx);
                 let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(),
-                                         Some(did), principal.substs());
+                                         Some(did), bindings, principal.substs());
                 cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeTrait));
                 ResolvedPath {
                     path: path,
-                    typarams: Some(bounds.clean(cx)),
+                    typarams: Some(typarams),
                     did: did,
                 }
             }
@@ -1485,7 +1614,7 @@ fn clean(&self, cx: &DocContext) -> Type {
 impl Clean<Type> for ast::QPath {
     fn clean(&self, cx: &DocContext) -> Type {
         Type::QPath {
-            name: self.item_name.clean(cx),
+            name: self.item_path.identifier.clean(cx),
             self_type: box self.self_type.clean(cx),
             trait_: box self.trait_ref.clean(cx)
         }
index 00f7c570b5d09f5b96c3d61eef0b213060ad561b..d13936b2168658f80472d625bacabfde1bcc6a9f 100644 (file)
@@ -153,8 +153,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                         try!(write!(f, "{}", lifetime));
                     }
                 }
-                &clean::WherePredicate::EqPredicate => {
-                    unimplemented!()
+                &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => {
+                    try!(write!(f, "{} == {}", lhs, rhs));
                 }
             }
         }
@@ -332,7 +332,7 @@ fn path<F, G>(w: &mut fmt::Formatter,
         match rel_root {
             Some(root) => {
                 let mut root = String::from_str(root.as_slice());
-                for seg in path.segments[0..amt].iter() {
+                for seg in path.segments[..amt].iter() {
                     if "super" == seg.name ||
                             "self" == seg.name {
                         try!(write!(w, "{}::", seg.name));
@@ -347,7 +347,7 @@ fn path<F, G>(w: &mut fmt::Formatter,
                 }
             }
             None => {
-                for seg in path.segments[0..amt].iter() {
+                for seg in path.segments[..amt].iter() {
                     try!(write!(w, "{}::", seg.name));
                 }
             }
@@ -465,61 +465,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             }
             clean::Infer => write!(f, "_"),
             clean::Primitive(prim) => primitive_link(f, prim, prim.to_string()),
-            clean::Closure(ref decl) => {
-                write!(f, "{style}{lifetimes}|{args}|{bounds}{arrow}",
-                       style = UnsafetySpace(decl.unsafety),
-                       lifetimes = if decl.lifetimes.len() == 0 {
-                           "".to_string()
-                       } else {
-                           format!("for &lt;{}&gt;",
-                                   CommaSep(decl.lifetimes.as_slice()))
-                       },
-                       args = decl.decl.inputs,
-                       arrow = decl.decl.output,
-                       bounds = {
-                           let mut ret = String::new();
-                           for bound in decl.bounds.iter() {
-                                match *bound {
-                                    clean::RegionBound(..) => {}
-                                    clean::TraitBound(ref t, modifier) => {
-                                        if ret.len() == 0 {
-                                            ret.push_str(": ");
-                                        } else {
-                                            ret.push_str(" + ");
-                                        }
-                                        if modifier == ast::TraitBoundModifier::Maybe {
-                                            ret.push_str("?");
-                                        }
-                                        ret.push_str(format!("{}",
-                                                             *t).as_slice());
-                                    }
-                                }
-                           }
-                           ret
-                       })
-            }
-            clean::Proc(ref decl) => {
-                write!(f, "{style}{lifetimes}proc({args}){bounds}{arrow}",
-                       style = UnsafetySpace(decl.unsafety),
-                       lifetimes = if decl.lifetimes.len() == 0 {
-                           "".to_string()
-                       } else {
-                           format!("for &lt;{}&gt;",
-                                   CommaSep(decl.lifetimes.as_slice()))
-                       },
-                       args = decl.decl.inputs,
-                       bounds = if decl.bounds.len() == 0 {
-                           "".to_string()
-                       } else {
-                           let m = decl.bounds
-                                           .iter()
-                                           .map(|s| s.to_string());
-                           format!(
-                               ": {}",
-                               m.collect::<Vec<String>>().connect(" + "))
-                       },
-                       arrow = decl.decl.output)
-            }
             clean::BareFunction(ref decl) => {
                 write!(f, "{}{}fn{}{}",
                        UnsafetySpace(decl.unsafety),
index a063191a12fd6c505715954910808de554da3220..0dbd13b4616bb36bf91f6d8ed1dde08202eb5cbd 100644 (file)
@@ -30,7 +30,7 @@
 use libc;
 use std::ascii::AsciiExt;
 use std::ffi::CString;
-use std::cell::{RefCell, Cell};
+use std::cell::RefCell;
 use std::collections::HashMap;
 use std::fmt;
 use std::slice;
@@ -155,7 +155,6 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
 thread_local!(static USED_HEADER_MAP: RefCell<HashMap<String, uint>> = {
     RefCell::new(HashMap::new())
 });
-thread_local!(static TEST_IDX: Cell<uint> = Cell::new(0));
 
 thread_local!(pub static PLAYGROUND_KRATE: RefCell<Option<Option<String>>> = {
     RefCell::new(None)
@@ -195,26 +194,19 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
             if rendered { return }
             PLAYGROUND_KRATE.with(|krate| {
                 let mut s = String::new();
-                let id = krate.borrow().as_ref().map(|krate| {
-                    let idx = TEST_IDX.with(|slot| {
-                        let i = slot.get();
-                        slot.set(i + 1);
-                        i
-                    });
-
+                krate.borrow().as_ref().map(|krate| {
                     let test = origtext.lines().map(|l| {
                         stripped_filtered_line(l).unwrap_or(l)
                     }).collect::<Vec<&str>>().connect("\n");
                     let krate = krate.as_ref().map(|s| s.as_slice());
                     let test = test::maketest(test.as_slice(), krate, false, false);
-                    s.push_str(format!("<span id='rust-example-raw-{}' \
-                                         class='rusttest'>{}</span>",
-                                       idx, Escape(test.as_slice())).as_slice());
-                    format!("rust-example-rendered-{}", idx)
+                    s.push_str(format!("<span class='rusttest'>{}</span>",
+                                         Escape(test.as_slice())).as_slice());
                 });
-                let id = id.as_ref().map(|a| a.as_slice());
-                s.push_str(highlight::highlight(text.as_slice(), None, id)
-                                     .as_slice());
+                s.push_str(highlight::highlight(text.as_slice(),
+                                                None,
+                                                Some("rust-example-rendered"))
+                             .as_slice());
                 let output = CString::from_vec(s.into_bytes());
                 hoedown_buffer_puts(ob, output.as_ptr());
             })
@@ -432,7 +424,6 @@ fn parse(string: &str) -> LangString {
 /// previous state (if any).
 pub fn reset_headers() {
     USED_HEADER_MAP.with(|s| s.borrow_mut().clear());
-    TEST_IDX.with(|s| s.set(0));
 }
 
 impl<'a> fmt::String for Markdown<'a> {
index f7d6b872940a439b00131f812fe1efa10d9dd590..687f764f02077a10cc0df749585984d9e08030b7 100644 (file)
 (function() {
     if (window.playgroundUrl) {
         $('pre.rust').hover(function() {
-            if (!$(this).attr('id')) { return; }
-            var id = '#' + $(this).attr('id').replace('rendered', 'raw');
             var a = $('<a>').text('⇱').attr('class', 'test-arrow');
-            var code = $(id).text();
+            var code = $(this).siblings(".rusttest").text();
             a.attr('href', window.playgroundUrl + '?code=' +
                            encodeURIComponent(code));
             a.attr('target', '_blank');
index ab9c4ef942230bcc7a94ee0203085c42aeb4fc95..dc98a56eb1a4e7c1ed598ed393f9d099d44c6e60 100644 (file)
@@ -91,6 +91,7 @@ pub fn render(input: &str, mut output: Path, matches: &getopts::Matches,
 <html lang="en">
 <head>
     <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <meta name="generator" content="rustdoc">
     <title>{title}</title>
 
index 62acef2ca1cc75476f1cc27a13200f0784988b33..41499b5ae0efed34bafe3b29191c5db904c957f0 100644 (file)
@@ -401,7 +401,7 @@ fn escape_str(wr: &mut fmt::Writer, v: &str) -> fmt::Result {
 fn escape_char(writer: &mut fmt::Writer, v: char) -> fmt::Result {
     let mut buf = [0; 4];
     let n = v.encode_utf8(&mut buf).unwrap();
-    let buf = unsafe { str::from_utf8_unchecked(&buf[0..n]) };
+    let buf = unsafe { str::from_utf8_unchecked(&buf[..n]) };
     escape_str(writer, buf)
 }
 
@@ -414,7 +414,7 @@ fn spaces(wr: &mut fmt::Writer, mut n: uint) -> fmt::Result {
     }
 
     if n > 0 {
-        wr.write_str(&BUF[0..n])
+        wr.write_str(&BUF[..n])
     } else {
         Ok(())
     }
index 36def48b88b324d633453d236b624874bf1e895d..8c38bc009cc63058aeaf82fffb54a18eed15cd1d 100644 (file)
@@ -15,7 +15,7 @@
 use cmp;
 use fmt;
 use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE, IoResult};
-use iter::{IteratorExt, ExactSizeIterator};
+use iter::{IteratorExt, ExactSizeIterator, repeat};
 use ops::Drop;
 use option::Option;
 use option::Option::{Some, None};
@@ -62,17 +62,11 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 impl<R: Reader> BufferedReader<R> {
     /// Creates a new `BufferedReader` with the specified buffer capacity
     pub fn with_capacity(cap: uint, inner: R) -> BufferedReader<R> {
-        // It's *much* faster to create an uninitialized buffer than it is to
-        // fill everything in with 0. This buffer is entirely an implementation
-        // detail and is never exposed, so we're safe to not initialize
-        // everything up-front. This allows creation of BufferedReader instances
-        // to be very cheap (large mallocs are not nearly as expensive as large
-        // callocs).
-        let mut buf = Vec::with_capacity(cap);
-        unsafe { buf.set_len(cap); }
         BufferedReader {
             inner: inner,
-            buf: buf,
+            // We can't use the same trick here as we do for BufferedWriter,
+            // since this memory is visible to the inner Reader.
+            buf: repeat(0).take(cap).collect(),
             pos: 0,
             cap: 0,
         }
@@ -122,7 +116,7 @@ fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
         let nread = {
             let available = try!(self.fill_buf());
             let nread = cmp::min(available.len(), buf.len());
-            slice::bytes::copy_memory(buf, &available[0..nread]);
+            slice::bytes::copy_memory(buf, &available[..nread]);
             nread
         };
         self.pos += nread;
@@ -166,7 +160,12 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 impl<W: Writer> BufferedWriter<W> {
     /// Creates a new `BufferedWriter` with the specified buffer capacity
     pub fn with_capacity(cap: uint, inner: W) -> BufferedWriter<W> {
-        // See comments in BufferedReader for why this uses unsafe code.
+        // It's *much* faster to create an uninitialized buffer than it is to
+        // fill everything in with 0. This buffer is entirely an implementation
+        // detail and is never exposed, so we're safe to not initialize
+        // everything up-front. This allows creation of BufferedWriter instances
+        // to be very cheap (large mallocs are not nearly as expensive as large
+        // callocs).
         let mut buf = Vec::with_capacity(cap);
         unsafe { buf.set_len(cap); }
         BufferedWriter {
@@ -183,7 +182,7 @@ pub fn new(inner: W) -> BufferedWriter<W> {
 
     fn flush_buf(&mut self) -> IoResult<()> {
         if self.pos != 0 {
-            let ret = self.inner.as_mut().unwrap().write(&self.buf[0..self.pos]);
+            let ret = self.inner.as_mut().unwrap().write(&self.buf[..self.pos]);
             self.pos = 0;
             ret
         } else {
@@ -282,7 +281,7 @@ impl<W: Writer> Writer for LineBufferedWriter<W> {
     fn write(&mut self, buf: &[u8]) -> IoResult<()> {
         match buf.iter().rposition(|&b| b == b'\n') {
             Some(i) => {
-                try!(self.inner.write(&buf[0..(i + 1)]));
+                try!(self.inner.write(&buf[..(i + 1)]));
                 try!(self.inner.flush());
                 try!(self.inner.write(&buf[(i + 1)..]));
                 Ok(())
index b578f4d5adcba81f5f84491abf8b60fa54256414..4b0014c68f7a84289cd17be9d6ff93a986b031e3 100644 (file)
@@ -90,7 +90,7 @@ fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
                 Some(src) => {
                     let dst = buf.slice_from_mut(num_read);
                     let count = cmp::min(src.len(), dst.len());
-                    bytes::copy_memory(dst, &src[0..count]);
+                    bytes::copy_memory(dst, &src[..count]);
                     count
                 },
                 None => 0,
index dbccc81c4cc72ea45a5fa218c43de82d4453259a..64406d88253a775305fb03749efe875c3c4d0bb9 100644 (file)
@@ -889,7 +889,7 @@ fn file_test_io_smoke_test() {
             let mut read_buf = [0; 1028];
             let read_str = match check!(read_stream.read(&mut read_buf)) {
                 -1|0 => panic!("shouldn't happen"),
-                n => str::from_utf8(&read_buf[0..n]).unwrap().to_string()
+                n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
             };
             assert_eq!(read_str.as_slice(), message);
         }
index c5e289398e0466bc5faa2fa9a2f5da4feb8b516a..ee05a9e55964eb527421eca7707422f55d73b18e 100644 (file)
@@ -204,7 +204,7 @@ fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
 
         let write_len = min(buf.len(), self.len());
         {
-            let input = &self[0..write_len];
+            let input = &self[..write_len];
             let output = buf.slice_to_mut(write_len);
             slice::bytes::copy_memory(output, input);
         }
@@ -286,7 +286,7 @@ fn write(&mut self, src: &[u8]) -> IoResult<()> {
 
             Ok(())
         } else {
-            slice::bytes::copy_memory(dst, &src[0..dst_len]);
+            slice::bytes::copy_memory(dst, &src[..dst_len]);
 
             self.pos += dst_len;
 
@@ -498,7 +498,7 @@ fn test_mem_reader() {
         assert_eq!(buf, b);
         assert_eq!(reader.read(&mut buf), Ok(3));
         let b: &[_] = &[5, 6, 7];
-        assert_eq!(&buf[0..3], b);
+        assert_eq!(&buf[..3], b);
         assert!(reader.read(&mut buf).is_err());
         let mut reader = MemReader::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
         assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3));
@@ -524,7 +524,7 @@ fn test_slice_reader() {
         assert_eq!(buf.as_slice(), b);
         assert_eq!(reader.read(&mut buf), Ok(3));
         let b: &[_] = &[5, 6, 7];
-        assert_eq!(&buf[0..3], b);
+        assert_eq!(&buf[..3], b);
         assert!(reader.read(&mut buf).is_err());
         let mut reader = &mut in_buf.as_slice();
         assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3));
@@ -551,7 +551,7 @@ fn test_buf_reader() {
         assert_eq!(buf, b);
         assert_eq!(reader.read(&mut buf), Ok(3));
         let b: &[_] = &[5, 6, 7];
-        assert_eq!(&buf[0..3], b);
+        assert_eq!(&buf[..3], b);
         assert!(reader.read(&mut buf).is_err());
         let mut reader = BufReader::new(in_buf.as_slice());
         assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3));
index 3968dda2a82026051a4687abf6a487314a63fa1b..bab4dafd090bdfc40ec6f90f5c2072744d16835d 100644 (file)
@@ -1069,7 +1069,7 @@ fn write_line(&mut self, s: &str) -> IoResult<()> {
     fn write_char(&mut self, c: char) -> IoResult<()> {
         let mut buf = [0u8; 4];
         let n = c.encode_utf8(buf.as_mut_slice()).unwrap_or(0);
-        self.write(&buf[0..n])
+        self.write(&buf[..n])
     }
 
     /// Write the result of passing n through `int::to_str_bytes`.
@@ -1454,7 +1454,7 @@ fn read_until(&mut self, byte: u8) -> IoResult<Vec<u8>> {
                 };
                 match available.iter().position(|&b| b == byte) {
                     Some(i) => {
-                        res.push_all(&available[0..(i + 1)]);
+                        res.push_all(&available[..(i + 1)]);
                         used = i + 1;
                         break
                     }
@@ -1493,7 +1493,7 @@ fn read_char(&mut self) -> IoResult<char> {
                 }
             }
         }
-        match str::from_utf8(&buf[0..width]).ok() {
+        match str::from_utf8(&buf[..width]).ok() {
             Some(s) => Ok(s.char_at(0)),
             None => Err(standard_error(InvalidInput))
         }
index d09afea94dcc1023827c4157f49062bd69e04195..adc122ff44741114d1337442addff67b03560714 100644 (file)
@@ -313,7 +313,7 @@ fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> IpAddr {
 
         let mut tail = [0u16; 8];
         let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size);
-        Some(ipv6_addr_from_head_tail(&head[0..head_size], &tail[0..tail_size]))
+        Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size]))
     }
 
     fn read_ipv6_addr(&mut self) -> Option<IpAddr> {
index a093e748d573653a80f5cd01ff392fef1289c72a..43ca7b131455b4b2fb14f04bbaae74f704ead1b2 100644 (file)
@@ -21,6 +21,8 @@
 use collections::HashMap;
 use ffi::CString;
 use fmt;
+// NOTE(stage0) remove import after a snapshot
+#[cfg(stage0)]
 use hash::Hash;
 use io::pipe::{PipeStream, PipePair};
 use io::{IoResult, IoError};
index ac7fb3f9cdb4a40ef8ed65b7711d55cebf31dd1f..adfd88644ccec6e4ec35c57efdd17c836e7b2e9c 100644 (file)
@@ -60,7 +60,7 @@ fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
 impl<R: Buffer> Buffer for LimitReader<R> {
     fn fill_buf<'a>(&'a mut self) -> io::IoResult<&'a [u8]> {
         let amt = try!(self.inner.fill_buf());
-        let buf = &amt[0..cmp::min(amt.len(), self.limit)];
+        let buf = &amt[..cmp::min(amt.len(), self.limit)];
         if buf.len() == 0 {
             Err(io::standard_error(io::EndOfFile))
         } else {
@@ -223,7 +223,7 @@ pub fn into_inner(self) -> (R, W) {
 impl<R: Reader, W: Writer> Reader for TeeReader<R, W> {
     fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
         self.reader.read(buf).and_then(|len| {
-            self.writer.write(&mut buf[0..len]).map(|()| len)
+            self.writer.write(&mut buf[..len]).map(|()| len)
         })
     }
 }
@@ -237,7 +237,7 @@ pub fn copy<R: Reader, W: Writer>(r: &mut R, w: &mut W) -> io::IoResult<()> {
             Err(ref e) if e.kind == io::EndOfFile => return Ok(()),
             Err(e) => return Err(e),
         };
-        try!(w.write(&buf[0..len]));
+        try!(w.write(&buf[..len]));
     }
 }
 
index 03d9030b02517733b41c2e219847d8e62015760d..182344452a484580154d250f765c6a9e50fc19c0 100644 (file)
 #![feature(slicing_syntax, unboxed_closures)]
 #![feature(box_syntax)]
 #![feature(old_impl_check)]
+#![feature(optin_builtin_traits)]
 #![allow(unknown_features)] #![feature(int_uint)]
 
 // Don't link to std. We are std.
index 588f729d8005d4687157cf8e8b88e27482dd95d7..fc0c838a3f11800418dce248a4c98c951be7f81c 100644 (file)
@@ -1422,6 +1422,11 @@ mod arch_consts {
     pub const ARCH: &'static str = "mipsel";
 }
 
+#[cfg(target_arch = "powerpc")]
+mod arch_consts {
+    pub const ARCH: &'static str = "powerpc";
+}
+
 #[cfg(test)]
 mod tests {
     use prelude::v1::*;
index 1ec7b6b3edcbbd4c351c0d4b4eb1870246314ef2..541f1e7714070584dd0bf49046af9d6a9dba55a0 100644 (file)
@@ -352,7 +352,7 @@ fn filestem<'a>(&'a self) -> Option<&'a [u8]> {
                 match name.rposition_elem(&dot) {
                     None | Some(0) => name,
                     Some(1) if name == b".." => name,
-                    Some(pos) => &name[0..pos]
+                    Some(pos) => &name[..pos]
                 }
             })
         }
@@ -475,7 +475,7 @@ fn set_extension<T: BytesContainer>(&mut self, extension: T) {
             let extlen = extension.container_as_bytes().len();
             match (name.rposition_elem(&dot), extlen) {
                 (None, 0) | (Some(0), 0) => None,
-                (Some(idx), 0) => Some(name[0..idx].to_vec()),
+                (Some(idx), 0) => Some(name[..idx].to_vec()),
                 (idx, extlen) => {
                     let idx = match idx {
                         None | Some(0) => name.len(),
@@ -484,7 +484,7 @@ fn set_extension<T: BytesContainer>(&mut self, extension: T) {
 
                     let mut v;
                     v = Vec::with_capacity(idx + extlen + 1);
-                    v.push_all(&name[0..idx]);
+                    v.push_all(&name[..idx]);
                     v.push(dot);
                     v.push_all(extension.container_as_bytes());
                     Some(v)
index 293696d5ccada853d2393f525e3460527d3fa89e..aab64639ab5903865a180c74dc2715d88e71e10d 100644 (file)
@@ -136,7 +136,7 @@ unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
             }
             Some(idx) => {
                 let mut v = Vec::with_capacity(idx + 1 + filename.len());
-                v.push_all(&self.repr[0..(idx+1)]);
+                v.push_all(&self.repr[..(idx+1)]);
                 v.push_all(filename);
                 // FIXME: this is slow
                 self.repr = Path::normalize(v.as_slice());
@@ -177,9 +177,9 @@ fn dirname<'a>(&'a self) -> &'a [u8] {
         match self.sepidx {
             None if b".." == self.repr => self.repr.as_slice(),
             None => dot_static,
-            Some(0) => &self.repr[0..1],
+            Some(0) => &self.repr[..1],
             Some(idx) if &self.repr[(idx+1)..] == b".." => self.repr.as_slice(),
-            Some(idx) => &self.repr[0..idx]
+            Some(idx) => &self.repr[..idx]
         }
     }
 
index 2a1f1794e49e7c059342940d02c006b9f17fffd7..3cff1c67be3684ed07c810d4ec69f17ff9eabaa9 100644 (file)
@@ -180,20 +180,20 @@ unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
             }
             Some((_,idxa,end)) if &self.repr[idxa..end] == ".." => {
                 let mut s = String::with_capacity(end + 1 + filename.len());
-                s.push_str(&self.repr[0..end]);
+                s.push_str(&self.repr[..end]);
                 s.push(SEP);
                 s.push_str(filename);
                 self.update_normalized(&s[]);
             }
             Some((idxb,idxa,_)) if self.prefix == Some(DiskPrefix) && idxa == self.prefix_len() => {
                 let mut s = String::with_capacity(idxb + filename.len());
-                s.push_str(&self.repr[0..idxb]);
+                s.push_str(&self.repr[..idxb]);
                 s.push_str(filename);
                 self.update_normalized(&s[]);
             }
             Some((idxb,_,_)) => {
                 let mut s = String::with_capacity(idxb + 1 + filename.len());
-                s.push_str(&self.repr[0..idxb]);
+                s.push_str(&self.repr[..idxb]);
                 s.push(SEP);
                 s.push_str(filename);
                 self.update_normalized(&s[]);
@@ -350,13 +350,13 @@ fn dirname_str<'a>(&'a self) -> Option<&'a str> {
             Some((idxb,_,end)) if &self.repr[idxb..end] == "\\" => {
                 &self.repr[]
             }
-            Some((0,idxa,_)) => &self.repr[0..idxa],
+            Some((0,idxa,_)) => &self.repr[..idxa],
             Some((idxb,idxa,_)) => {
                 match self.prefix {
                     Some(DiskPrefix) | Some(VerbatimDiskPrefix) if idxb == self.prefix_len() => {
-                        &self.repr[0..idxa]
+                        &self.repr[..idxa]
                     }
-                    _ => &self.repr[0..idxb]
+                    _ => &self.repr[..idxb]
                 }
             }
         })
@@ -428,15 +428,15 @@ fn root_path(&self) -> Option<Path> {
         if self.prefix.is_some() {
             Some(Path::new(match self.prefix {
                 Some(DiskPrefix) if self.is_absolute() => {
-                    &self.repr[0..(self.prefix_len()+1)]
+                    &self.repr[..(self.prefix_len()+1)]
                 }
                 Some(VerbatimDiskPrefix) => {
-                    &self.repr[0..(self.prefix_len()+1)]
+                    &self.repr[..(self.prefix_len()+1)]
                 }
-                _ => &self.repr[0..self.prefix_len()]
+                _ => &self.repr[..self.prefix_len()]
             }))
         } else if is_vol_relative(self) {
-            Some(Path::new(&self.repr[0..1]))
+            Some(Path::new(&self.repr[..1]))
         } else {
             None
         }
@@ -683,7 +683,7 @@ fn equiv_prefix(&self, other: &Path) -> bool {
             }
             (None, None) => true,
             (a, b) if a == b => {
-                &s_repr[0..self.prefix_len()] == &o_repr[0..other.prefix_len()]
+                &s_repr[..self.prefix_len()] == &o_repr[..other.prefix_len()]
             }
             _ => false
         }
@@ -737,7 +737,7 @@ fn normalize__(s: &str, prefix: Option<PathPrefix>) -> Option<String> {
                         match prefix.unwrap() {
                             DiskPrefix => {
                                 let len = prefix_len(prefix) + is_abs as uint;
-                                let mut s = String::from_str(&s[0..len]);
+                                let mut s = String::from_str(&s[..len]);
                                 unsafe {
                                     let v = s.as_mut_vec();
                                     v[0] = (*v)[0].to_ascii_uppercase();
@@ -752,7 +752,7 @@ fn normalize__(s: &str, prefix: Option<PathPrefix>) -> Option<String> {
                             }
                             VerbatimDiskPrefix => {
                                 let len = prefix_len(prefix) + is_abs as uint;
-                                let mut s = String::from_str(&s[0..len]);
+                                let mut s = String::from_str(&s[..len]);
                                 unsafe {
                                     let v = s.as_mut_vec();
                                     v[4] = (*v)[4].to_ascii_uppercase();
@@ -762,14 +762,14 @@ fn normalize__(s: &str, prefix: Option<PathPrefix>) -> Option<String> {
                             _ => {
                                 let plen = prefix_len(prefix);
                                 if s.len() > plen {
-                                    Some(String::from_str(&s[0..plen]))
+                                    Some(String::from_str(&s[..plen]))
                                 } else { None }
                             }
                         }
                     } else if is_abs && comps.is_empty() {
                         Some(repeat(SEP).take(1).collect())
                     } else {
-                        let prefix_ = &s[0..prefix_len(prefix)];
+                        let prefix_ = &s[..prefix_len(prefix)];
                         let n = prefix_.len() +
                                 if is_abs { comps.len() } else { comps.len() - 1} +
                                 comps.iter().map(|v| v.len()).sum();
@@ -780,7 +780,7 @@ fn normalize__(s: &str, prefix: Option<PathPrefix>) -> Option<String> {
                                 s.push(':');
                             }
                             Some(VerbatimDiskPrefix) => {
-                                s.push_str(&prefix_[0..4]);
+                                s.push_str(&prefix_[..4]);
                                 s.push(prefix_.as_bytes()[4].to_ascii_uppercase() as char);
                                 s.push_str(&prefix_[5..]);
                             }
@@ -813,7 +813,7 @@ fn normalize__(s: &str, prefix: Option<PathPrefix>) -> Option<String> {
 
     fn update_sepidx(&mut self) {
         let s = if self.has_nonsemantic_trailing_slash() {
-                    &self.repr[0..(self.repr.len()-1)]
+                    &self.repr[..(self.repr.len()-1)]
                 } else { &self.repr[] };
         let sep_test: fn(char) -> bool = if !prefix_is_verbatim(self.prefix) {
             is_sep
index 60d490982db7ea284bb0c250c3a14baddff309c4..8130a6c82ec3e8c0fdae0f11b19f12c568e77692 100644 (file)
@@ -374,9 +374,13 @@ fn fill_bytes(&mut self, bytes: &mut [u8]) {
 /// `random()` can generate various types of random things, and so may require
 /// type hinting to generate the specific type you want.
 ///
+/// This function uses the thread local random number generator. This means
+/// that if you're calling `random()` in a loop, caching the generator can
+/// increase performance. An example is shown below.
+///
 /// # Examples
 ///
-/// ```rust
+/// ```
 /// use std::rand;
 ///
 /// let x = rand::random();
@@ -389,6 +393,27 @@ fn fill_bytes(&mut self, bytes: &mut [u8]) {
 ///     println!("Better lucky than good!");
 /// }
 /// ```
+///
+/// Caching the thread local random number generator:
+///
+/// ```
+/// use std::rand;
+/// use std::rand::Rng;
+///
+/// let mut v = vec![1, 2, 3];
+///
+/// for x in v.iter_mut() {
+///     *x = rand::random()
+/// }
+///
+/// // would be faster as
+///
+/// let mut rng = rand::thread_rng();
+///
+/// for x in v.iter_mut() {
+///     *x = rng.gen();
+/// }
+/// ```
 #[inline]
 pub fn random<T: Rand>() -> T {
     thread_rng().gen()
index 18d40ecd3ebe54f6e1003f1627f236a7f4790703..68ba7e1dd29e6716ab313ae576dc141df0bfc1ff 100644 (file)
@@ -32,7 +32,8 @@ mod imp {
               any(target_arch = "x86_64",
                   target_arch = "x86",
                   target_arch = "arm",
-                  target_arch = "aarch64")))]
+                  target_arch = "aarch64",
+                  target_arch = "powerpc")))]
     fn getrandom(buf: &mut [u8]) -> libc::c_long {
         extern "C" {
             fn syscall(number: libc::c_long, ...) -> libc::c_long;
@@ -44,6 +45,8 @@ fn getrandom(buf: &mut [u8]) -> libc::c_long {
         const NR_GETRANDOM: libc::c_long = 355;
         #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
         const NR_GETRANDOM: libc::c_long = 384;
+        #[cfg(target_arch = "powerpc")]
+        const NR_GETRANDOM: libc::c_long = 384;
 
         unsafe {
             syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
@@ -54,7 +57,8 @@ fn getrandom(buf: &mut [u8]) -> libc::c_long {
                   any(target_arch = "x86_64",
                       target_arch = "x86",
                       target_arch = "arm",
-                      target_arch = "aarch64"))))]
+                      target_arch = "aarch64",
+                      target_arch = "powerpc"))))]
     fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }
 
     fn getrandom_fill_bytes(v: &mut [u8]) {
@@ -91,7 +95,8 @@ fn getrandom_next_u64() -> u64 {
               any(target_arch = "x86_64",
                   target_arch = "x86",
                   target_arch = "arm",
-                  target_arch = "aarch64")))]
+                  target_arch = "aarch64",
+                  target_arch = "powerpc")))]
     fn is_getrandom_available() -> bool {
         use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
 
@@ -119,7 +124,8 @@ fn is_getrandom_available() -> bool {
                   any(target_arch = "x86_64",
                       target_arch = "x86",
                       target_arch = "arm",
-                      target_arch = "aarch64"))))]
+                      target_arch = "aarch64",
+                      target_arch = "powerpc"))))]
     fn is_getrandom_available() -> bool { false }
 
     /// A random number generator that retrieves randomness straight from
index 7cc39d7d972485977c23d9e3870f6b5b2bdd48fe..dd9923307d6f0e788421a685573833f64b5cecfc 100644 (file)
@@ -81,6 +81,9 @@ pub enum _Unwind_Reason_Code {
 #[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
 pub const unwinder_private_data_size: uint = 2;
 
+#[cfg(target_arch = "powerpc")]
+pub const unwinder_private_data_size: uint = 2;
+
 #[repr(C)]
 pub struct _Unwind_Exception {
     pub exception_class: _Unwind_Exception_Class,
index 6326e4c08f190e46b53a751a5ca08538b4310dbf..73b8f104c23691659f7bc484afbc6b66f29c7252 100644 (file)
@@ -544,7 +544,7 @@ fn begin_unwind_inner(msg: Box<Any + Send>, file_line: &(&'static str, uint)) ->
     // MAX_CALLBACKS, so we're sure to clamp it as necessary.
     let callbacks = {
         let amt = CALLBACK_CNT.load(Ordering::SeqCst);
-        &CALLBACKS[0..cmp::min(amt, MAX_CALLBACKS)]
+        &CALLBACKS[..cmp::min(amt, MAX_CALLBACKS)]
     };
     for cb in callbacks.iter() {
         match cb.load(Ordering::SeqCst) {
index 83f646d89dcecf5409082d5e81a266ec6122d3f2..235cedcda524442959179eb13ace211a741b4b06 100644 (file)
@@ -131,7 +131,7 @@ struct BufWriter<'a> {
     impl<'a> fmt::Writer for BufWriter<'a> {
         fn write_str(&mut self, bytes: &str) -> fmt::Result {
             let left = self.buf.slice_from_mut(self.pos);
-            let to_write = &bytes.as_bytes()[0..cmp::min(bytes.len(), left.len())];
+            let to_write = &bytes.as_bytes()[..cmp::min(bytes.len(), left.len())];
             slice::bytes::copy_memory(left, to_write);
             self.pos += to_write.len();
             Ok(())
@@ -142,7 +142,7 @@ fn write_str(&mut self, bytes: &str) -> fmt::Result {
     let mut msg = [0u8; 512];
     let mut w = BufWriter { buf: &mut msg, pos: 0 };
     let _ = write!(&mut w, "{}", args);
-    let msg = str::from_utf8(&w.buf[0..w.pos]).unwrap_or("aborted");
+    let msg = str::from_utf8(&w.buf[..w.pos]).unwrap_or("aborted");
     let msg = if msg.is_empty() {"aborted"} else {msg};
     rterrln!("fatal runtime error: {}", msg);
     unsafe { intrinsics::abort(); }
index b8b186f31e044089afe0e1fdfdb9d394489e757d..a81a4504323071c4f28bbde7442114b5013b8cb1 100644 (file)
@@ -188,7 +188,7 @@ pub fn wait_timeout_with<'a, T, F>(&self,
     /// be woken up from its call to `wait` or `wait_timeout`. Calls to
     /// `notify_one` are not buffered in any way.
     ///
-    /// To wake up all threads, see `notify_one()`.
+    /// To wake up all threads, see `notify_all()`.
     #[stable]
     pub fn notify_one(&self) { unsafe { self.inner.inner.notify_one() } }
 
index f174771a3e011527a03f052b4252c8705549cdbc..17e690e9540925e323a6b52b0d34d99e197e2f96 100644 (file)
@@ -14,6 +14,7 @@
 use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
 use sync::Arc;
 use marker::{Sync, Send};
+#[cfg(stage0)] // NOTE remove use after next snapshot
 use marker::{NoSend, NoSync};
 use mem;
 use clone::Clone;
@@ -31,12 +32,25 @@ pub struct SignalToken {
     inner: Arc<Inner>,
 }
 
+#[cfg(stage0)] // NOTE remove impl after next snapshot
 pub struct WaitToken {
     inner: Arc<Inner>,
     no_send: NoSend,
     no_sync: NoSync,
 }
 
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+pub struct WaitToken {
+    inner: Arc<Inner>,
+}
+
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+impl !Send for WaitToken {}
+
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+impl !Sync for WaitToken {}
+
+#[cfg(stage0)] // NOTE remove impl after next snapshot
 pub fn tokens() -> (WaitToken, SignalToken) {
     let inner = Arc::new(Inner {
         thread: Thread::current(),
@@ -53,6 +67,21 @@ pub fn tokens() -> (WaitToken, SignalToken) {
     (wait_token, signal_token)
 }
 
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+pub fn tokens() -> (WaitToken, SignalToken) {
+    let inner = Arc::new(Inner {
+        thread: Thread::current(),
+        woken: ATOMIC_BOOL_INIT,
+    });
+    let wait_token = WaitToken {
+        inner: inner.clone(),
+    };
+    let signal_token = SignalToken {
+        inner: inner
+    };
+    (wait_token, signal_token)
+}
+
 impl SignalToken {
     pub fn signal(&self) -> bool {
         let wake = !self.inner.woken.compare_and_swap(false, true, Ordering::SeqCst);
index eca7d3155b18be2983b1682d4922ec347267a98e..0ba19b706176b8f0beb25e87d4f63c8a244bc851 100644 (file)
@@ -370,12 +370,24 @@ unsafe impl<T:Send> Send for Sender<T> { }
 /// The sending-half of Rust's synchronous channel type. This half can only be
 /// owned by one task, but it can be cloned to send to other tasks.
 #[stable]
+#[cfg(stage0)] // NOTE remove impl after next snapshot
 pub struct SyncSender<T> {
     inner: Arc<RacyCell<sync::Packet<T>>>,
     // can't share in an arc
     _marker: marker::NoSync,
 }
 
+/// The sending-half of Rust's synchronous channel type. This half can only be
+/// owned by one task, but it can be cloned to send to other tasks.
+#[stable]
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+pub struct SyncSender<T> {
+    inner: Arc<RacyCell<sync::Packet<T>>>,
+}
+
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+impl<T> !marker::Sync for SyncSender<T> {}
+
 /// An error returned from the `send` function on channels.
 ///
 /// A `send` operation can only fail if the receiving end of a channel is
@@ -677,10 +689,16 @@ fn drop(&mut self) {
 ////////////////////////////////////////////////////////////////////////////////
 
 impl<T: Send> SyncSender<T> {
+    #[cfg(stage0)] // NOTE remove impl after next snapshot
     fn new(inner: Arc<RacyCell<sync::Packet<T>>>) -> SyncSender<T> {
         SyncSender { inner: inner, _marker: marker::NoSync }
     }
 
+    #[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+    fn new(inner: Arc<RacyCell<sync::Packet<T>>>) -> SyncSender<T> {
+        SyncSender { inner: inner }
+    }
+
     /// Sends a value on this synchronous channel.
     ///
     /// This function will *block* until space in the internal buffer becomes
index 0da458a51f10848b9988bf1b202c9d4569e08496..62a7b823ec8acd5e9df8af58cd441a084c1699ac 100644 (file)
@@ -66,6 +66,7 @@
 
 /// The "receiver set" of the select interface. This structure is used to manage
 /// a set of receivers which are being selected over.
+#[cfg(stage0)] // NOTE remove impl after next snapshot
 pub struct Select {
     head: *mut Handle<'static, ()>,
     tail: *mut Handle<'static, ()>,
@@ -73,6 +74,18 @@ pub struct Select {
     marker1: marker::NoSend,
 }
 
+/// The "receiver set" of the select interface. This structure is used to manage
+/// a set of receivers which are being selected over.
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+pub struct Select {
+    head: *mut Handle<'static, ()>,
+    tail: *mut Handle<'static, ()>,
+    next_id: Cell<uint>,
+}
+
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+impl !marker::Send for Select {}
+
 /// A handle to a receiver which is currently a member of a `Select` set of
 /// receivers.  This handle is used to keep the receiver in the set as well as
 /// interact with the underlying receiver.
@@ -113,6 +126,7 @@ impl Select {
     ///
     /// Usage of this struct directly can sometimes be burdensome, and usage is
     /// rather much easier through the `select!` macro.
+    #[cfg(stage0)] // NOTE remove impl after next snapshot
     pub fn new() -> Select {
         Select {
             marker1: marker::NoSend,
@@ -122,6 +136,20 @@ pub fn new() -> Select {
         }
     }
 
+    /// Creates a new selection structure. This set is initially empty and
+    /// `wait` will panic!() if called.
+    ///
+    /// Usage of this struct directly can sometimes be burdensome, and usage is
+    /// rather much easier through the `select!` macro.
+    #[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+    pub fn new() -> Select {
+        Select {
+            head: 0 as *mut Handle<'static, ()>,
+            tail: 0 as *mut Handle<'static, ()>,
+            next_id: Cell::new(1),
+        }
+    }
+
     /// Creates a new handle into this receiver set for a new receiver. Note
     /// that this does *not* add the receiver to the receiver set, for that you
     /// must call the `add` method on the handle itself.
index c1b55c6ff78db3b3f91bc0201f7994f8e428b29c..73d5332d16fe4f02dd4ea48a947b9121bf8d1ee4 100644 (file)
@@ -160,6 +160,7 @@ unsafe impl Sync for StaticMutex {}
 /// Deref and DerefMut implementations
 #[must_use]
 #[stable]
+#[cfg(stage0)] // NOTE remove impl after next snapshot
 pub struct MutexGuard<'a, T: 'a> {
     // funny underscores due to how Deref/DerefMut currently work (they
     // disregard field privacy).
@@ -169,6 +170,25 @@ pub struct MutexGuard<'a, T: 'a> {
     __marker: marker::NoSend,
 }
 
+/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
+/// dropped (falls out of scope), the lock will be unlocked.
+///
+/// The data protected by the mutex can be access through this guard via its
+/// Deref and DerefMut implementations
+#[must_use]
+#[stable]
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+pub struct MutexGuard<'a, T: 'a> {
+    // funny underscores due to how Deref/DerefMut currently work (they
+    // disregard field privacy).
+    __lock: &'a StaticMutex,
+    __data: &'a UnsafeCell<T>,
+    __poison: poison::Guard,
+}
+
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+impl<'a, T> !marker::Send for MutexGuard<'a, T> {}
+
 /// Static initialization of a mutex. This constant can be used to initialize
 /// other mutex constants.
 #[unstable = "may be merged with Mutex in the future"]
@@ -279,6 +299,7 @@ pub unsafe fn destroy(&'static self) {
 }
 
 impl<'mutex, T> MutexGuard<'mutex, T> {
+    #[cfg(stage0)] // NOTE remove afte next snapshot
     fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell<T>)
            -> LockResult<MutexGuard<'mutex, T>> {
         poison::map_result(lock.poison.borrow(), |guard| {
@@ -290,6 +311,18 @@ fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell<T>)
             }
         })
     }
+
+    #[cfg(not(stage0))] // NOTE remove cfg afte next snapshot
+    fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell<T>)
+           -> LockResult<MutexGuard<'mutex, T>> {
+        poison::map_result(lock.poison.borrow(), |guard| {
+            MutexGuard {
+                __lock: lock,
+                __data: data,
+                __poison: guard,
+            }
+        })
+    }
 }
 
 #[stable]
index 7db2111cc4629eed04b5fa749498bf5db000305e..237f6d08a9541885314e25706655aebf614f760b 100644 (file)
@@ -110,16 +110,31 @@ unsafe impl Sync for StaticRwLock {}
 /// dropped.
 #[must_use]
 #[stable]
+#[cfg(stage0)] // NOTE remove impl after next snapshot
 pub struct RwLockReadGuard<'a, T: 'a> {
     __lock: &'a StaticRwLock,
     __data: &'a UnsafeCell<T>,
     __marker: marker::NoSend,
 }
 
+/// RAII structure used to release the shared read access of a lock when
+/// dropped.
+#[must_use]
+#[stable]
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+pub struct RwLockReadGuard<'a, T: 'a> {
+    __lock: &'a StaticRwLock,
+    __data: &'a UnsafeCell<T>,
+}
+
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+impl<'a, T> !marker::Send for RwLockReadGuard<'a, T> {}
+
 /// RAII structure used to release the exclusive write access of a lock when
 /// dropped.
 #[must_use]
 #[stable]
+#[cfg(stage0)] // NOTE remove impl after next snapshot
 pub struct RwLockWriteGuard<'a, T: 'a> {
     __lock: &'a StaticRwLock,
     __data: &'a UnsafeCell<T>,
@@ -127,6 +142,20 @@ pub struct RwLockWriteGuard<'a, T: 'a> {
     __marker: marker::NoSend,
 }
 
+/// RAII structure used to release the exclusive write access of a lock when
+/// dropped.
+#[must_use]
+#[stable]
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+pub struct RwLockWriteGuard<'a, T: 'a> {
+    __lock: &'a StaticRwLock,
+    __data: &'a UnsafeCell<T>,
+    __poison: poison::Guard,
+}
+
+#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+impl<'a, T> !marker::Send for RwLockWriteGuard<'a, T> {}
+
 impl<T: Send + Sync> RwLock<T> {
     /// Creates a new instance of an RwLock which is unlocked and read to go.
     #[stable]
@@ -303,6 +332,7 @@ pub unsafe fn destroy(&'static self) {
 }
 
 impl<'rwlock, T> RwLockReadGuard<'rwlock, T> {
+    #[cfg(stage0)] // NOTE remove impl after next snapshot
     fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>)
            -> LockResult<RwLockReadGuard<'rwlock, T>> {
         poison::map_result(lock.poison.borrow(), |_| {
@@ -313,8 +343,20 @@ fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>)
             }
         })
     }
+
+    #[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+    fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>)
+           -> LockResult<RwLockReadGuard<'rwlock, T>> {
+        poison::map_result(lock.poison.borrow(), |_| {
+            RwLockReadGuard {
+                __lock: lock,
+                __data: data,
+            }
+        })
+    }
 }
 impl<'rwlock, T> RwLockWriteGuard<'rwlock, T> {
+    #[cfg(stage0)] // NOTE remove impl after next snapshot
     fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>)
            -> LockResult<RwLockWriteGuard<'rwlock, T>> {
         poison::map_result(lock.poison.borrow(), |guard| {
@@ -326,6 +368,18 @@ fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>)
             }
         })
     }
+
+    #[cfg(not(stage0))] // NOTE remove cfg after next snapshot
+    fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>)
+           -> LockResult<RwLockWriteGuard<'rwlock, T>> {
+        poison::map_result(lock.poison.borrow(), |guard| {
+            RwLockWriteGuard {
+                __lock: lock,
+                __data: data,
+                __poison: guard,
+            }
+        })
+    }
 }
 
 #[stable]
index ce5ab67ae613c5c66e099aa5407127b210b010ef..88bb9395cf122e9fe15c1a8790798bd26ccdf90f 100644 (file)
@@ -231,6 +231,12 @@ unsafe fn target_record_sp_limit(limit: uint) {
     unsafe fn target_record_sp_limit(_: uint) {
     }
 
+    // powerpc - FIXME(POWERPC): missing...
+    #[cfg(target_arch = "powerpc")]
+    unsafe fn target_record_sp_limit(_: uint) {
+    }
+
+
     // iOS segmented stack is disabled for now, see related notes
     #[cfg(all(target_arch = "arm", target_os = "ios"))] #[inline(always)]
     unsafe fn target_record_sp_limit(_: uint) {
@@ -326,6 +332,12 @@ unsafe fn target_get_sp_limit() -> uint {
         1024
     }
 
+    // powepc - FIXME(POWERPC): missing...
+    #[cfg(target_arch = "powerpc")]
+    unsafe fn target_get_sp_limit() -> uint {
+        1024
+    }
+
     // iOS doesn't support segmented stacks yet. This function might
     // be called by runtime though so it is unsafe to mark it as
     // unreachable, let's return a fixed constant.
index 1d523ed6eddace4426c7c710070d4d58892a18c9..fed700cc9d52a93805118d240fb0f8c3793a1860 100644 (file)
@@ -33,7 +33,9 @@
           target_os = "android"))]
 pub const FIONBIO: libc::c_ulong = 0x5421;
 #[cfg(all(target_os = "linux",
-          any(target_arch = "mips", target_arch = "mipsel")))]
+          any(target_arch = "mips",
+              target_arch = "mipsel",
+              target_arch = "powerpc")))]
 pub const FIONBIO: libc::c_ulong = 0x667e;
 
 #[cfg(any(target_os = "macos",
@@ -49,7 +51,9 @@
           target_os = "android"))]
 pub const FIOCLEX: libc::c_ulong = 0x5451;
 #[cfg(all(target_os = "linux",
-          any(target_arch = "mips", target_arch = "mipsel")))]
+          any(target_arch = "mips",
+              target_arch = "mipsel",
+              target_arch = "powerpc")))]
 pub const FIOCLEX: libc::c_ulong = 0x6601;
 
 #[cfg(any(target_os = "macos",
@@ -182,7 +186,9 @@ pub struct sigset_t {
 }
 
 #[cfg(all(target_os = "linux",
-          any(target_arch = "mips", target_arch = "mipsel")))]
+          any(target_arch = "mips",
+              target_arch = "mipsel",
+              target_arch = "powerpc")))]
 mod signal {
     use libc;
 
index 48a51813ba4ab5a44f3b55f8ca77444322eda640..45680f52e73d12c54607780c132ef70cff277c19 100644 (file)
@@ -150,6 +150,7 @@ pub unsafe fn drop_handler(handler: &mut Handler) {
               all(target_os = "linux", target_arch = "aarch64"),
               all(target_os = "linux", target_arch = "mips"), // may not match
               all(target_os = "linux", target_arch = "mipsel"), // may not match
+              all(target_os = "linux", target_arch = "powerpc"), // may not match
               target_os = "android"))] // may not match
     mod signal {
         use libc;
index fbbdee1009d5b7adefe5eaf716df9b5b12817f42..c1e3fc88794eb1751dcd22368914819fb6d0ff4b 100644 (file)
@@ -126,7 +126,8 @@ mod os {
     #[cfg(any(target_arch = "x86",
               target_arch = "arm",
               target_arch = "mips",
-              target_arch = "mipsel"))]
+              target_arch = "mipsel",
+              target_arch = "powerpc"))]
     const __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
     #[cfg(target_arch = "aarch64")]
     const __SIZEOF_PTHREAD_MUTEX_T: uint = 48 - 8;
@@ -136,7 +137,8 @@ mod os {
               target_arch = "arm",
               target_arch = "aarch64",
               target_arch = "mips",
-              target_arch = "mipsel"))]
+              target_arch = "mipsel",
+              target_arch = "powerpc"))]
     const __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
 
     #[cfg(any(target_arch = "x86_64",
@@ -146,7 +148,8 @@ mod os {
     #[cfg(any(target_arch = "x86",
               target_arch = "arm",
               target_arch = "mips",
-              target_arch = "mipsel"))]
+              target_arch = "mipsel",
+              target_arch = "powerpc"))]
     const __SIZEOF_PTHREAD_RWLOCK_T: uint = 32 - 8;
 
     #[repr(C)]
index 291a8024cfccec76080f25deccdac04b98463501..db8038006fd6a81451a3783951609bddb7f8719f 100644 (file)
@@ -27,16 +27,18 @@ pub unsafe fn new() -> Condvar { CONDVAR_INIT }
 
     #[inline]
     pub unsafe fn wait(&self, mutex: &Mutex) {
-        let r = ffi::SleepConditionVariableCS(self.inner.get(),
-                                              mutex::raw(mutex),
-                                              libc::INFINITE);
+        let r = ffi::SleepConditionVariableSRW(self.inner.get(),
+                                               mutex::raw(mutex),
+                                               libc::INFINITE,
+                                               0);
         debug_assert!(r != 0);
     }
 
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        let r = ffi::SleepConditionVariableCS(self.inner.get(),
-                                              mutex::raw(mutex),
-                                              dur.num_milliseconds() as DWORD);
+        let r = ffi::SleepConditionVariableSRW(self.inner.get(),
+                                               mutex::raw(mutex),
+                                               dur.num_milliseconds() as DWORD,
+                                               0);
         if r == 0 {
             const ERROR_TIMEOUT: DWORD = 0x5B4;
             debug_assert_eq!(os::errno() as uint, ERROR_TIMEOUT as uint);
index fcdd4ff7c5440832c0a2d7d65be66ab0c2873322..828ad795ed3b4eaa3871fb0d4c415fa79e714cab 100644 (file)
@@ -8,73 +8,51 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
-use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
-use alloc::{self, heap};
-
-use libc::DWORD;
+use marker::Sync;
+use cell::UnsafeCell;
 use sys::sync as ffi;
 
-const SPIN_COUNT: DWORD = 4000;
+pub struct Mutex { inner: UnsafeCell<ffi::SRWLOCK> }
 
-pub struct Mutex { inner: AtomicUsize }
-
-pub const MUTEX_INIT: Mutex = Mutex { inner: ATOMIC_USIZE_INIT };
+pub const MUTEX_INIT: Mutex = Mutex {
+    inner: UnsafeCell { value: ffi::SRWLOCK_INIT }
+};
 
 unsafe impl Sync for Mutex {}
 
 #[inline]
-pub unsafe fn raw(m: &Mutex) -> ffi::LPCRITICAL_SECTION {
-    m.get()
+pub unsafe fn raw(m: &Mutex) -> ffi::PSRWLOCK {
+    m.inner.get()
 }
 
+// So you might be asking why we're using SRWLock instead of CriticalSection?
+//
+// 1. SRWLock is several times faster than CriticalSection according to benchmarks performed on both
+// Windows 8 and Windows 7.
+//
+// 2. CriticalSection allows recursive locking while SRWLock deadlocks. The Unix implementation
+// deadlocks so consistency is preferred. See #19962 for more details.
+//
+// 3. While CriticalSection is fair and SRWLock is not, the current Rust policy is there there are
+// no guarantees of fairness.
+
 impl Mutex {
     #[inline]
-    pub unsafe fn new() -> Mutex {
-        Mutex { inner: AtomicUsize::new(init_lock() as uint) }
-    }
+    pub unsafe fn new() -> Mutex { MUTEX_INIT }
     #[inline]
     pub unsafe fn lock(&self) {
-        ffi::EnterCriticalSection(self.get())
+        ffi::AcquireSRWLockExclusive(self.inner.get())
     }
     #[inline]
     pub unsafe fn try_lock(&self) -> bool {
-        ffi::TryEnterCriticalSection(self.get()) != 0
+        ffi::TryAcquireSRWLockExclusive(self.inner.get()) != 0
     }
     #[inline]
     pub unsafe fn unlock(&self) {
-        ffi::LeaveCriticalSection(self.get())
+        ffi::ReleaseSRWLockExclusive(self.inner.get())
     }
+    #[inline]
     pub unsafe fn destroy(&self) {
-        let lock = self.inner.swap(0, Ordering::SeqCst);
-        if lock != 0 { free_lock(lock as ffi::LPCRITICAL_SECTION) }
-    }
-
-    unsafe fn get(&self) -> ffi::LPCRITICAL_SECTION {
-        match self.inner.load(Ordering::SeqCst) {
-            0 => {}
-            n => return n as ffi::LPCRITICAL_SECTION
-        }
-        let lock = init_lock();
-        match self.inner.compare_and_swap(0, lock as uint, Ordering::SeqCst) {
-            0 => return lock as ffi::LPCRITICAL_SECTION,
-            _ => {}
-        }
-        free_lock(lock);
-        return self.inner.load(Ordering::SeqCst) as ffi::LPCRITICAL_SECTION;
+        // ...
     }
 }
-
-unsafe fn init_lock() -> ffi::LPCRITICAL_SECTION {
-    let block = heap::allocate(ffi::CRITICAL_SECTION_SIZE, 8)
-                        as ffi::LPCRITICAL_SECTION;
-    if block.is_null() { alloc::oom() }
-    ffi::InitializeCriticalSectionAndSpinCount(block, SPIN_COUNT);
-    return block;
-}
-
-unsafe fn free_lock(h: ffi::LPCRITICAL_SECTION) {
-    ffi::DeleteCriticalSection(h);
-    heap::deallocate(h as *mut _, ffi::CRITICAL_SECTION_SIZE, 8);
-}
index 064633f321c19b1ed4689258eacb60f9ff4f5e65..4540068133bd796a7e734df0cbddef4c0ac03264 100644 (file)
@@ -36,7 +36,7 @@
 pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] {
     match v.iter().position(|c| *c == 0) {
         // don't include the 0
-        Some(i) => &v[0..i],
+        Some(i) => &v[..i],
         None => v
     }
 }
index cbca47912b511642ab309ddd1ca451ce7c7496bb..d60646b7db915cdd9e568619adf8d017b598bc6e 100644 (file)
@@ -8,17 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use libc::{BOOL, DWORD, c_void, LPVOID};
+use libc::{BOOL, DWORD, c_void, LPVOID, c_ulong};
 use libc::types::os::arch::extra::BOOLEAN;
 
-pub type LPCRITICAL_SECTION = *mut c_void;
-pub type LPCONDITION_VARIABLE = *mut CONDITION_VARIABLE;
-pub type LPSRWLOCK = *mut SRWLOCK;
-
-#[cfg(target_arch = "x86")]
-pub const CRITICAL_SECTION_SIZE: uint = 24;
-#[cfg(target_arch = "x86_64")]
-pub const CRITICAL_SECTION_SIZE: uint = 40;
+pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE;
+pub type PSRWLOCK = *mut SRWLOCK;
+pub type ULONG = c_ulong;
 
 #[repr(C)]
 pub struct CONDITION_VARIABLE { pub ptr: LPVOID }
@@ -31,28 +26,19 @@ pub struct SRWLOCK { pub ptr: LPVOID }
 pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { ptr: 0 as *mut _ };
 
 extern "system" {
-    // critical sections
-    pub fn InitializeCriticalSectionAndSpinCount(
-                    lpCriticalSection: LPCRITICAL_SECTION,
-                    dwSpinCount: DWORD) -> BOOL;
-    pub fn DeleteCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
-    pub fn EnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
-    pub fn LeaveCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
-    pub fn TryEnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION) -> BOOL;
-
     // condition variables
-    pub fn SleepConditionVariableCS(ConditionVariable: LPCONDITION_VARIABLE,
-                                    CriticalSection: LPCRITICAL_SECTION,
-                                    dwMilliseconds: DWORD) -> BOOL;
-    pub fn WakeConditionVariable(ConditionVariable: LPCONDITION_VARIABLE);
-    pub fn WakeAllConditionVariable(ConditionVariable: LPCONDITION_VARIABLE);
+    pub fn SleepConditionVariableSRW(ConditionVariable: PCONDITION_VARIABLE,
+                                     SRWLock: PSRWLOCK,
+                                     dwMilliseconds: DWORD,
+                                     Flags: ULONG) -> BOOL;
+    pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE);
+    pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE);
 
     // slim rwlocks
-    pub fn AcquireSRWLockExclusive(SRWLock: LPSRWLOCK);
-    pub fn AcquireSRWLockShared(SRWLock: LPSRWLOCK);
-    pub fn ReleaseSRWLockExclusive(SRWLock: LPSRWLOCK);
-    pub fn ReleaseSRWLockShared(SRWLock: LPSRWLOCK);
-    pub fn TryAcquireSRWLockExclusive(SRWLock: LPSRWLOCK) -> BOOLEAN;
-    pub fn TryAcquireSRWLockShared(SRWLock: LPSRWLOCK) -> BOOLEAN;
+    pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK);
+    pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK);
+    pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK);
+    pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK);
+    pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN;
+    pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN;
 }
-
index 630f7768885de6ec6097834c0b90a2a312398f6f..0ea429116b0bb86308ee7532ce1a8304016139ed 100644 (file)
@@ -747,6 +747,8 @@ pub enum Expr_ {
     /// Variable reference, possibly containing `::` and/or
     /// type parameters, e.g. foo::bar::<baz>
     ExprPath(Path),
+    /// A "qualified path", e.g. `<Vec<T> as SomeTrait>::SomeType`
+    ExprQPath(P<QPath>),
 
     ExprAddrOf(Mutability, P<Expr>),
     ExprBreak(Option<Ident>),
@@ -771,12 +773,12 @@ pub enum Expr_ {
 ///
 ///     <Vec<T> as SomeTrait>::SomeAssociatedItem
 ///      ^~~~~     ^~~~~~~~~   ^~~~~~~~~~~~~~~~~~
-///      self_type  trait_name  item_name
+///      self_type  trait_name  item_path
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)]
 pub struct QPath {
     pub self_type: P<Ty>,
     pub trait_ref: P<TraitRef>,
-    pub item_name: Ident, // FIXME(#20301) -- should use Name
+    pub item_path: PathSegment,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show, Copy)]
@@ -955,7 +957,7 @@ pub fn get_span(&self) -> Span {
 pub enum Mac_ {
     // NB: the additional ident for a macro_rules-style macro is actually
     // stored in the enclosing item. Oog.
-    MacInvocTT(Path, Vec<TokenTree> , SyntaxContext),   // new macro-invocation
+    MacInvocTT(Path, Vec<TokenTree>, SyntaxContext),   // new macro-invocation
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show, Copy)]
@@ -1528,6 +1530,19 @@ pub struct ViewItem {
     pub span: Span,
 }
 
+impl ViewItem {
+    pub fn id(&self) -> NodeId {
+        match self.node {
+            ViewItemExternCrate(_, _, id) => id,
+            ViewItemUse(ref vp) => match vp.node {
+                ViewPathSimple(_, _, id) => id,
+                ViewPathGlob(_, id) => id,
+                ViewPathList(_, _, id) => id,
+            }
+        }
+    }
+}
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)]
 pub enum ViewItem_ {
     /// Ident: name used to refer to this crate in the code
index 3ef572791752bfd7420ed17ec5b4622cda88ba45..f462a730d3aa0458099a48775522042328642d8c 100644 (file)
@@ -107,6 +107,7 @@ pub fn path_to_string<PI: Iterator<Item=PathElem>>(path: PI) -> String {
 #[derive(Copy, Show)]
 pub enum Node<'ast> {
     NodeItem(&'ast Item),
+    NodeViewItem(&'ast ViewItem),
     NodeForeignItem(&'ast ForeignItem),
     NodeTraitItem(&'ast TraitItem),
     NodeImplItem(&'ast ImplItem),
@@ -133,6 +134,7 @@ enum MapEntry<'ast> {
 
     /// All the node types, with a parent ID.
     EntryItem(NodeId, &'ast Item),
+    EntryViewItem(NodeId, &'ast ViewItem),
     EntryForeignItem(NodeId, &'ast ForeignItem),
     EntryTraitItem(NodeId, &'ast TraitItem),
     EntryImplItem(NodeId, &'ast ImplItem),
@@ -167,6 +169,7 @@ impl<'ast> MapEntry<'ast> {
     fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> {
         match node {
             NodeItem(n) => EntryItem(p, n),
+            NodeViewItem(n) => EntryViewItem(p, n),
             NodeForeignItem(n) => EntryForeignItem(p, n),
             NodeTraitItem(n) => EntryTraitItem(p, n),
             NodeImplItem(n) => EntryImplItem(p, n),
@@ -185,6 +188,7 @@ fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> {
     fn parent(self) -> Option<NodeId> {
         Some(match self {
             EntryItem(id, _) => id,
+            EntryViewItem(id, _) => id,
             EntryForeignItem(id, _) => id,
             EntryTraitItem(id, _) => id,
             EntryImplItem(id, _) => id,
@@ -204,6 +208,7 @@ fn parent(self) -> Option<NodeId> {
     fn to_node(self) -> Option<Node<'ast>> {
         Some(match self {
             EntryItem(_, n) => NodeItem(n),
+            EntryViewItem(_, n) => NodeViewItem(n),
             EntryForeignItem(_, n) => NodeForeignItem(n),
             EntryTraitItem(_, n) => NodeTraitItem(n),
             EntryImplItem(_, n) => NodeImplItem(n),
@@ -336,6 +341,13 @@ pub fn expect_item(&self, id: NodeId) -> &'ast Item {
         }
     }
 
+    pub fn expect_view_item(&self, id: NodeId) -> &'ast ViewItem {
+        match self.find(id) {
+            Some(NodeViewItem(view_item)) => view_item,
+            _ => panic!("expected view item, found {}", self.node_to_string(id))
+        }
+    }
+
     pub fn expect_struct(&self, id: NodeId) -> &'ast StructDef {
         match self.find(id) {
             Some(NodeItem(i)) => {
@@ -513,7 +525,7 @@ pub fn nodes_matching_suffix<'a>(&'a self, parts: &'a [String])
         NodesMatchingSuffix {
             map: self,
             item_name: parts.last().unwrap(),
-            in_which: &parts[0..(parts.len() - 1)],
+            in_which: &parts[..(parts.len() - 1)],
             idx: 0,
         }
     }
@@ -521,6 +533,7 @@ pub fn nodes_matching_suffix<'a>(&'a self, parts: &'a [String])
     pub fn opt_span(&self, id: NodeId) -> Option<Span> {
         let sp = match self.find(id) {
             Some(NodeItem(item)) => item.span,
+            Some(NodeViewItem(item)) => item.span,
             Some(NodeForeignItem(foreign_item)) => foreign_item.span,
             Some(NodeTraitItem(trait_method)) => {
                 match *trait_method {
@@ -813,6 +826,11 @@ fn visit_item(&mut self, i: &'ast Item) {
         self.parent = parent;
     }
 
+    fn visit_view_item(&mut self, item: &'ast ViewItem) {
+        self.insert(item.id(), NodeViewItem(item));
+        visit::walk_view_item(self, item);
+    }
+
     fn visit_pat(&mut self, pat: &'ast Pat) {
         self.insert(pat.id, match pat.node {
             // Note: this is at least *potentially* a pattern...
@@ -1018,6 +1036,7 @@ impl<'a> NodePrinter for pprust::State<'a> {
     fn print_node(&mut self, node: &Node) -> IoResult<()> {
         match *node {
             NodeItem(a)        => self.print_item(&*a),
+            NodeViewItem(a)    => self.print_view_item(&*a),
             NodeForeignItem(a) => self.print_foreign_item(&*a),
             NodeTraitItem(a)   => self.print_trait_method(&*a),
             NodeImplItem(a)    => self.print_impl_item(&*a),
@@ -1060,6 +1079,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
             };
             format!("{} {}{}", item_str, path_str, id_str)
         }
+        Some(NodeViewItem(item)) => {
+            format!("view item {}{}", pprust::view_item_to_string(&*item), id_str)
+        }
         Some(NodeForeignItem(item)) => {
             let path_str = map.path_to_str_with_ident(id, item.ident);
             format!("foreign item {}{}", path_str, id_str)
index 9a422e17bb4dee49fa7c36e5aed96c5239fcc05e..bf26687deededc5f370d1b2050e3d6470f5c66c0 100644 (file)
@@ -313,7 +313,7 @@ pub fn get_line(&self, line_number: uint) -> Option<String> {
             let begin = begin.to_uint();
             let slice = &self.src[begin..];
             match slice.find('\n') {
-                Some(e) => &slice[0..e],
+                Some(e) => &slice[..e],
                 None => slice
             }.to_string()
         })
index 3f81dac2b0d6224afcc608e887690a65ad140e1a..7213b0fa9556cf0eb51021ecbf1e8fbe5463b74f 100644 (file)
@@ -118,6 +118,9 @@ pub fn span_help(&self, sp: Span, msg: &str) {
     pub fn fileline_note(&self, sp: Span, msg: &str) {
         self.handler.custom_emit(&self.cm, FileLine(sp), msg, Note);
     }
+    pub fn fileline_help(&self, sp: Span, msg: &str) {
+        self.handler.custom_emit(&self.cm, FileLine(sp), msg, Help);
+    }
     pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
         self.handler.emit(Some((&self.cm, sp)), msg, Bug);
         panic!(ExplicitBug);
@@ -277,7 +280,7 @@ fn print_maybe_styled(w: &mut EmitterWriter,
             // to be miscolored. We assume this is rare enough that we don't
             // have to worry about it.
             if msg.ends_with("\n") {
-                try!(t.write_str(&msg[0..(msg.len()-1)]));
+                try!(t.write_str(&msg[..(msg.len()-1)]));
                 try!(t.reset());
                 try!(t.write_str("\n"));
             } else {
index fd3bac5b2fc7bce38d0304d2880e1e685593f6b3..4258eb32fdf0f671b47295596944f12a8f20d567 100644 (file)
@@ -63,6 +63,12 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
     'statement: loop {
         match state {
             Asm => {
+                if asm_str_style.is_some() {
+                    // If we already have a string with instructions,
+                    // ending up in Asm state again is an error.
+                    cx.span_err(sp, "malformed inline assembly");
+                    return DummyResult::expr(sp);
+                }
                 let (s, style) = match expr_to_string(cx, p.parse_expr(),
                                                    "inline assembly must be a string literal") {
                     Some((s, st)) => (s, st),
index 9b9d8a9ceb395bf7cf0024fe3ceb17030de165f7..f2498abfa6a593439e4cef48e71fae7e3aeab59c 100644 (file)
@@ -73,6 +73,108 @@ fn expand(&self,
     }
 }
 
+#[derive(Show,Clone)]
+pub enum Annotatable {
+    Item(P<ast::Item>),
+    TraitItem(ast::TraitItem),
+    ImplItem(ast::ImplItem),
+}
+
+impl Annotatable {
+    pub fn attrs(&self) -> &[ast::Attribute] {
+        match *self {
+            Annotatable::Item(ref i) => &i.attrs[],
+            Annotatable::TraitItem(ref i) => match *i {
+                ast::TraitItem::RequiredMethod(ref tm) => &tm.attrs[],
+                ast::TraitItem::ProvidedMethod(ref m) => &m.attrs[],
+                ast::TraitItem::TypeTraitItem(ref at) => &at.attrs[],
+            },
+            Annotatable::ImplItem(ref i) => match *i {
+                ast::ImplItem::MethodImplItem(ref m) => &m.attrs[],
+                ast::ImplItem::TypeImplItem(ref t) => &t.attrs[],
+            }
+        }
+    }
+
+    pub fn fold_attrs(self, attrs: Vec<ast::Attribute>) -> Annotatable {
+        match self {
+            Annotatable::Item(i) => Annotatable::Item(P(ast::Item {
+                attrs: attrs,
+                ..(*i).clone()
+            })),
+            Annotatable::TraitItem(i) => match i {
+                ast::TraitItem::RequiredMethod(tm) => Annotatable::TraitItem(
+                    ast::TraitItem::RequiredMethod(
+                        ast::TypeMethod { attrs: attrs, ..tm })),
+                ast::TraitItem::ProvidedMethod(m) => Annotatable::TraitItem(
+                    ast::TraitItem::ProvidedMethod(P(
+                        ast::Method { attrs: attrs, ..(*m).clone() }))),
+                ast::TraitItem::TypeTraitItem(at) => Annotatable::TraitItem(
+                    ast::TraitItem::TypeTraitItem(P(
+                        ast::AssociatedType { attrs: attrs, ..(*at).clone() }))),
+            },
+            Annotatable::ImplItem(i) => match i {
+                ast::ImplItem::MethodImplItem(m) => Annotatable::ImplItem(
+                    ast::ImplItem::MethodImplItem(P(
+                        ast::Method { attrs: attrs, ..(*m).clone() }))),
+                ast::ImplItem::TypeImplItem(t) => Annotatable::ImplItem(
+                    ast::ImplItem::TypeImplItem(P(
+                        ast::Typedef { attrs: attrs, ..(*t).clone() }))),
+            }
+        }
+    }
+
+    pub fn expect_item(self) -> P<ast::Item> {
+        match self {
+            Annotatable::Item(i) => i,
+            _ => panic!("expected Item")
+        }
+    }
+
+    pub fn expect_trait_item(self) -> ast::TraitItem {
+        match self {
+            Annotatable::TraitItem(i) => i,
+            _ => panic!("expected Item")
+        }
+    }
+
+    pub fn expect_impl_item(self) -> ast::ImplItem {
+        match self {
+            Annotatable::ImplItem(i) => i,
+            _ => panic!("expected Item")
+        }
+    }
+}
+
+// A more flexible ItemModifier (ItemModifier should go away, eventually, FIXME).
+// meta_item is the annotation, item is the item being modified, parent_item
+// is the impl or trait item is declared in if item is part of such a thing.
+// FIXME Decorators should follow the same pattern too.
+pub trait MultiItemModifier {
+    fn expand(&self,
+              ecx: &mut ExtCtxt,
+              span: Span,
+              meta_item: &ast::MetaItem,
+              item: Annotatable)
+              -> Annotatable;
+}
+
+impl<F> MultiItemModifier for F
+    where F: Fn(&mut ExtCtxt,
+                Span,
+                &ast::MetaItem,
+                Annotatable) -> Annotatable
+{
+    fn expand(&self,
+              ecx: &mut ExtCtxt,
+              span: Span,
+              meta_item: &ast::MetaItem,
+              item: Annotatable)
+              -> Annotatable {
+        (*self)(ecx, span, meta_item, item)
+    }
+}
+
 /// Represents a thing that maps token trees to Macro Results
 pub trait TTMacroExpander {
     fn expand<'cx>(&self,
@@ -299,6 +401,10 @@ pub enum SyntaxExtension {
     /// in-place.
     Modifier(Box<ItemModifier + 'static>),
 
+    /// A syntax extension that is attached to an item and modifies it
+    /// in-place. More flexible version than Modifier.
+    MultiModifier(Box<MultiItemModifier + 'static>),
+
     /// A normal, function-like syntax extension.
     ///
     /// `bytes!` is a `NormalTT`.
index 7c65d2b4ff483d55a1d3b101a83f6c6e1c9f8a52..f73023ddd1eb05c587928b6ec6e21971fc8c1974 100644 (file)
@@ -92,11 +92,10 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
     let recurse = vec!(cx.ident_of(krate),
                     cx.ident_of("Decodable"),
                     cx.ident_of("decode"));
+    let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse));
     // throw an underscore in front to suppress unused variable warnings
     let blkarg = cx.ident_of("_d");
     let blkdecoder = cx.expr_ident(trait_span, blkarg);
-    let calldecode = cx.expr_call_global(trait_span, recurse, vec!(blkdecoder.clone()));
-    let lambdadecode = cx.lambda_expr_1(trait_span, calldecode, blkarg);
 
     return match *substr.fields {
         StaticStruct(_, ref summary) => {
@@ -116,7 +115,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
                     cx.expr_method_call(span, blkdecoder.clone(), read_struct_field,
                                         vec!(cx.expr_str(span, name),
                                           cx.expr_uint(span, field),
-                                          lambdadecode.clone())))
+                                          exprdecode.clone())))
             });
             let result = cx.expr_ok(trait_span, result);
             cx.expr_method_call(trait_span,
@@ -147,7 +146,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
                     let idx = cx.expr_uint(span, field);
                     cx.expr_try(span,
                         cx.expr_method_call(span, blkdecoder.clone(), rvariant_arg,
-                                            vec!(idx, lambdadecode.clone())))
+                                            vec!(idx, exprdecode.clone())))
                 });
 
                 arms.push(cx.arm(v_span,
index e6b6f7bbd49c3d0f09d99bd7fcfd5d7fad69cce2..161b27d7abb597e3245c9cb7b0b0c38e476c1bb2 100644 (file)
 //!   (e.g. `Option<T>`), the parameters are automatically given the
 //!   current trait as a bound. (This includes separate type parameters
 //!   and lifetimes for methods.)
-//! - Additional bounds on the type parameters, e.g. the `Ord` instance
-//!   requires an explicit `PartialEq` bound at the
-//!   moment. (`TraitDef.additional_bounds`)
-//!
-//! Unsupported: FIXME #6257: calling methods on reference fields,
-//! e.g. derive Eq/Ord/Clone don't work on `struct A(&int)`,
-//! because of how the auto-dereferencing happens.
+//! - Additional bounds on the type parameters (`TraitDef.additional_bounds`)
 //!
 //! The most important thing for implementers is the `Substructure` and
 //! `SubstructureFields` objects. The latter groups 5 possibilities of the
 //! enums (one for each variant). For empty struct and empty enum
 //! variants, it is represented as a count of 0.
 //!
+//! # "`cs`" functions
+//!
+//! The `cs_...` functions ("combine substructure) are designed to
+//! make life easier by providing some pre-made recipes for common
+//! tasks; mostly calling the function being derived on all the
+//! arguments and then combining them back together in some way (or
+//! letting the user chose that). They are not meant to be the only
+//! way to handle the structures that this code creates.
+//!
 //! # Examples
 //!
 //! The following simplified `PartialEq` is used for in-code examples:
 //! When generating the `expr` for the `A` impl, the `SubstructureFields` is
 //!
 //! ```{.text}
-//! Struct(~[FieldInfo {
+//! Struct(vec![FieldInfo {
 //!            span: <span of x>
 //!            name: Some(<ident of x>),
 //!            self_: <expr for &self.x>,
-//!            other: ~[<expr for &other.x]
+//!            other: vec![<expr for &other.x]
 //!          }])
 //! ```
 //!
 //! For the `B` impl, called with `B(a)` and `B(b)`,
 //!
 //! ```{.text}
-//! Struct(~[FieldInfo {
+//! Struct(vec![FieldInfo {
 //!           span: <span of `int`>,
 //!           name: None,
-//!           <expr for &a>
-//!           ~[<expr for &b>]
+//!           self_: <expr for &a>
+//!           other: vec![<expr for &b>]
 //!          }])
 //! ```
 //!
 //!
 //! ```{.text}
 //! EnumMatching(0, <ast::Variant for C0>,
-//!              ~[FieldInfo {
+//!              vec![FieldInfo {
 //!                 span: <span of int>
 //!                 name: None,
 //!                 self_: <expr for &a>,
-//!                 other: ~[<expr for &b>]
+//!                 other: vec![<expr for &b>]
 //!               }])
 //! ```
 //!
 //!
 //! ```{.text}
 //! EnumMatching(1, <ast::Variant for C1>,
-//!              ~[FieldInfo {
+//!              vec![FieldInfo {
 //!                 span: <span of x>
 //!                 name: Some(<ident of x>),
 //!                 self_: <expr for &self.x>,
-//!                 other: ~[<expr for &other.x>]
+//!                 other: vec![<expr for &other.x>]
 //!                }])
 //! ```
 //!
 //!
 //! ```{.text}
 //! EnumNonMatchingCollapsed(
-//!     ~[<ident of self>, <ident of __arg_1>],
+//!     vec![<ident of self>, <ident of __arg_1>],
 //!     &[<ast::Variant for C0>, <ast::Variant for C1>],
 //!     &[<ident for self index value>, <ident of __arg_1 index value>])
 //! ```
 //!
 //! ## Static
 //!
-//! A static method on the above would result in,
+//! A static method on the types above would result in,
 //!
 //! ```{.text}
-//! StaticStruct(<ast::StructDef of A>, Named(~[(<ident of x>, <span of x>)]))
+//! StaticStruct(<ast::StructDef of A>, Named(vec![(<ident of x>, <span of x>)]))
 //!
-//! StaticStruct(<ast::StructDef of B>, Unnamed(~[<span of x>]))
+//! StaticStruct(<ast::StructDef of B>, Unnamed(vec![<span of x>]))
 //!
-//! StaticEnum(<ast::EnumDef of C>, ~[(<ident of C0>, <span of C0>, Unnamed(~[<span of int>])),
-//!                                   (<ident of C1>, <span of C1>,
-//!                                    Named(~[(<ident of x>, <span of x>)]))])
+//! StaticEnum(<ast::EnumDef of C>,
+//!            vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of int>])),
+//!                 (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))])
 //! ```
 
 pub use self::StaticFields::*;
@@ -1378,8 +1381,8 @@ pub fn cs_fold<F>(use_foldl: bool,
 /// process the collected results. i.e.
 ///
 /// ```
-/// f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
-///              self_2.method(__arg_1_2, __arg_2_2)])
+/// f(cx, span, vec![self_1.method(__arg_1_1, __arg_2_1),
+///                  self_2.method(__arg_1_2, __arg_2_2)])
 /// ```
 #[inline]
 pub fn cs_same_method<F>(f: F,
index db99c14244324569e63c86e56d399933ae56c93f..08336be87d107712c5c8f1f156d2784efcde8f0f 100644 (file)
@@ -63,11 +63,21 @@ pub fn expand_deriving_hash<F>(cx: &mut ExtCtxt,
 fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
     let state_expr = match substr.nonself_args {
         [ref state_expr] => state_expr,
-        _ => cx.span_bug(trait_span, "incorrect number of arguments in `deriving(Hash)`")
+        _ => cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`")
     };
-    let hash_ident = substr.method_ident;
     let call_hash = |&: span, thing_expr| {
-        let expr = cx.expr_method_call(span, thing_expr, hash_ident, vec!(state_expr.clone()));
+        let hash_path = {
+            let strs = vec![
+                cx.ident_of("std"),
+                cx.ident_of("hash"),
+                cx.ident_of("Hash"),
+                cx.ident_of("hash"),
+            ];
+
+            cx.expr_path(cx.path_global(span, strs))
+        };
+        let ref_thing = cx.expr_addr_of(span, thing_expr);
+        let expr = cx.expr_call(span, hash_path, vec!(ref_thing, state_expr.clone()));
         cx.stmt_expr(expr)
     };
     let mut stmts = Vec::new();
@@ -86,16 +96,12 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
 
             fs
         }
-        _ => cx.span_bug(trait_span, "impossible substructure in `deriving(Hash)`")
+        _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`")
     };
 
     for &FieldInfo { ref self_, span, .. } in fields.iter() {
         stmts.push(call_hash(span, self_.clone()));
     }
 
-    if stmts.len() == 0 {
-        cx.span_bug(trait_span, "#[derive(Hash)] needs at least one field");
-    }
-
     cx.expr_block(cx.block(trait_span, stmts, None))
 }
index 9ef996ac3179b15e4acb483cd13579b1709b2311..c95bdeefd454046f39e6d5548c9c5bf10c5d3b83 100644 (file)
@@ -395,81 +395,15 @@ pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
                    -> SmallVector<P<ast::Item>> {
     let it = expand_item_modifiers(it, fld);
 
-    let mut decorator_items = SmallVector::zero();
-    let mut new_attrs = Vec::new();
-    for attr in it.attrs.iter() {
-        let mname = attr.name();
-
-        match fld.cx.syntax_env.find(&intern(mname.get())) {
-            Some(rc) => match *rc {
-                Decorator(ref dec) => {
-                    attr::mark_used(attr);
-
-                    fld.cx.bt_push(ExpnInfo {
-                        call_site: attr.span,
-                        callee: NameAndSpan {
-                            name: mname.get().to_string(),
-                            format: MacroAttribute,
-                            span: None
-                        }
-                    });
-
-                    // we'd ideally decorator_items.push_all(expand_item(item, fld)),
-                    // but that double-mut-borrows fld
-                    let mut items: SmallVector<P<ast::Item>> = SmallVector::zero();
-                    dec.expand(fld.cx, attr.span, &*attr.node.value, &*it,
-                               box |&mut : item| items.push(item));
-                    decorator_items.extend(items.into_iter()
-                        .flat_map(|item| expand_item(item, fld).into_iter()));
-
-                    fld.cx.bt_pop();
-                }
-                _ => new_attrs.push((*attr).clone()),
-            },
-            _ => new_attrs.push((*attr).clone()),
-        }
-    }
-
-    let mut new_items = match it.node {
-        ast::ItemMac(..) => expand_item_mac(it, fld),
-        ast::ItemMod(_) | ast::ItemForeignMod(_) => {
-            let valid_ident =
-                it.ident.name != parse::token::special_idents::invalid.name;
-
-            if valid_ident {
-                fld.cx.mod_push(it.ident);
-            }
-            let macro_use = contains_macro_use(fld, &new_attrs[]);
-            let result = with_exts_frame!(fld.cx.syntax_env,
-                                          macro_use,
-                                          noop_fold_item(it, fld));
-            if valid_ident {
-                fld.cx.mod_pop();
-            }
-            result
-        },
-        _ => {
-            let it = P(ast::Item {
-                attrs: new_attrs,
-                ..(*it).clone()
-            });
-            noop_fold_item(it, fld)
-        }
-    };
-
-    new_items.push_all(decorator_items);
-    new_items
+    expand_annotatable(Annotatable::Item(it), fld)
+        .into_iter().map(|i| i.expect_item()).collect()
 }
 
 fn expand_item_modifiers(mut it: P<ast::Item>, fld: &mut MacroExpander)
                          -> P<ast::Item> {
     // partition the attributes into ItemModifiers and others
-    let (modifiers, other_attrs): (Vec<_>, _) = it.attrs.iter().cloned().partition(|attr| {
-        match fld.cx.syntax_env.find(&intern(attr.name().get())) {
-            Some(rc) => match *rc { Modifier(_) => true, _ => false },
-            _ => false
-        }
-    });
+    let (modifiers, other_attrs) = modifiers(&it.attrs, fld);
+
     // update the attrs, leave everything else alone. Is this mutation really a good idea?
     it = P(ast::Item {
         attrs: other_attrs,
@@ -477,7 +411,8 @@ fn expand_item_modifiers(mut it: P<ast::Item>, fld: &mut MacroExpander)
     });
 
     if modifiers.is_empty() {
-        return it;
+        let it = expand_item_multi_modifier(Annotatable::Item(it), fld);
+        return it.expect_item();
     }
 
     for attr in modifiers.iter() {
@@ -504,7 +439,12 @@ fn expand_item_modifiers(mut it: P<ast::Item>, fld: &mut MacroExpander)
         }
     }
 
-    // expansion may have added new ItemModifiers
+    // Expansion may have added new ItemModifiers.
+    // It is possible, that an item modifier could expand to a multi-modifier or
+    // vice versa. In this case we will expand all modifiers before multi-modifiers,
+    // which might give an odd ordering. However, I think it is unlikely that the
+    // two kinds will be mixed, and I old-style multi-modifiers should be deprecated
+    // anyway.
     expand_item_modifiers(it, fld)
 }
 
@@ -1029,6 +969,196 @@ fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
     }
 }
 
+fn expand_annotatable(a: Annotatable,
+                      fld: &mut MacroExpander)
+                      -> SmallVector<Annotatable> {
+    let a = expand_item_multi_modifier(a, fld);
+
+    let mut decorator_items = SmallVector::zero();
+    let mut new_attrs = Vec::new();
+    for attr in a.attrs().iter() {
+        let mname = attr.name();
+
+        match fld.cx.syntax_env.find(&intern(mname.get())) {
+            Some(rc) => match *rc {
+                Decorator(ref dec) => {
+                    let it = match a {
+                        Annotatable::Item(ref it) => it,
+                        // ItemDecorators are only implemented for Items.
+                        _ => break,
+                    };
+
+                    attr::mark_used(attr);
+
+                    fld.cx.bt_push(ExpnInfo {
+                        call_site: attr.span,
+                        callee: NameAndSpan {
+                            name: mname.get().to_string(),
+                            format: MacroAttribute,
+                            span: None
+                        }
+                    });
+
+                    // we'd ideally decorator_items.push_all(expand_item(item, fld)),
+                    // but that double-mut-borrows fld
+                    let mut items: SmallVector<P<ast::Item>> = SmallVector::zero();
+                    dec.expand(fld.cx, attr.span, &*attr.node.value, &**it,
+                               box |&mut: item| items.push(item));
+                    decorator_items.extend(items.into_iter()
+                        .flat_map(|item| expand_item(item, fld).into_iter()));
+
+                    fld.cx.bt_pop();
+                }
+                _ => new_attrs.push((*attr).clone()),
+            },
+            _ => new_attrs.push((*attr).clone()),
+        }
+    }
+
+    let mut new_items: SmallVector<Annotatable> = match a {
+        Annotatable::Item(it) => match it.node {
+            ast::ItemMac(..) => {
+                expand_item_mac(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect()
+            }
+            ast::ItemMod(_) | ast::ItemForeignMod(_) => {
+                let valid_ident =
+                    it.ident.name != parse::token::special_idents::invalid.name;
+
+                if valid_ident {
+                    fld.cx.mod_push(it.ident);
+                }
+                let macro_use = contains_macro_use(fld, &new_attrs[]);
+                let result = with_exts_frame!(fld.cx.syntax_env,
+                                              macro_use,
+                                              noop_fold_item(it, fld));
+                if valid_ident {
+                    fld.cx.mod_pop();
+                }
+                result.into_iter().map(|i| Annotatable::Item(i)).collect()
+            },
+            _ => {
+                let it = P(ast::Item {
+                    attrs: new_attrs,
+                    ..(*it).clone()
+                });
+                noop_fold_item(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect()
+            }
+        },
+        Annotatable::TraitItem(it) => match it {
+            ast::TraitItem::ProvidedMethod(m) => {
+                expand_method(m, fld).into_iter().map(|m|
+                    Annotatable::TraitItem(ast::TraitItem::ProvidedMethod(m))).collect()
+            }
+            ast::TraitItem::RequiredMethod(m) => {
+                SmallVector::one(Annotatable::TraitItem(
+                    ast::TraitItem::RequiredMethod(fld.fold_type_method(m))))
+            }
+            ast::TraitItem::TypeTraitItem(t) => {
+                SmallVector::one(Annotatable::TraitItem(
+                    ast::TraitItem::TypeTraitItem(P(fld.fold_associated_type((*t).clone())))))
+            }
+        },
+        Annotatable::ImplItem(it) => match it {
+            ast::ImplItem::MethodImplItem(m) => {
+                expand_method(m, fld).into_iter().map(|m|
+                    Annotatable::ImplItem(ast::ImplItem::MethodImplItem(m))).collect()
+            }
+            ast::ImplItem::TypeImplItem(t) => {
+                SmallVector::one(Annotatable::ImplItem(
+                    ast::ImplItem::TypeImplItem(P(fld.fold_typedef((*t).clone())))))
+            }
+        }
+    };
+
+    new_items.push_all(decorator_items.into_iter().map(|i| Annotatable::Item(i)).collect());
+    new_items
+}
+
+fn expand_trait_item(i: ast::TraitItem,
+                     fld: &mut MacroExpander)
+                     -> SmallVector<ast::TraitItem> {
+    expand_annotatable(Annotatable::TraitItem(i), fld)
+        .into_iter().map(|i| i.expect_trait_item()).collect()
+
+}
+
+fn expand_impl_item(i: ast::ImplItem,
+                    fld: &mut MacroExpander)
+                    -> SmallVector<ast::ImplItem> {
+    expand_annotatable(Annotatable::ImplItem(i), fld)
+        .into_iter().map(|i| i.expect_impl_item()).collect()
+}
+
+// partition the attributes into ItemModifiers and others
+fn modifiers(attrs: &Vec<ast::Attribute>,
+             fld: &MacroExpander)
+             -> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
+    attrs.iter().cloned().partition(|attr| {
+        match fld.cx.syntax_env.find(&intern(attr.name().get())) {
+            Some(rc) => match *rc {
+                Modifier(_) => true,
+                _ => false
+            },
+            _ => false
+        }
+    })
+}
+
+// partition the attributes into MultiModifiers and others
+fn multi_modifiers(attrs: &[ast::Attribute],
+                   fld: &MacroExpander)
+                   -> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
+    attrs.iter().cloned().partition(|attr| {
+        match fld.cx.syntax_env.find(&intern(attr.name().get())) {
+            Some(rc) => match *rc {
+                MultiModifier(_) => true,
+                _ => false
+            },
+            _ => false
+        }
+    })
+}
+
+fn expand_item_multi_modifier(mut it: Annotatable,
+                              fld: &mut MacroExpander)
+                              -> Annotatable {
+    let (modifiers, other_attrs) = multi_modifiers(it.attrs(), fld);
+
+    // Update the attrs, leave everything else alone. Is this mutation really a good idea?
+    it = it.fold_attrs(other_attrs);
+
+    if modifiers.is_empty() {
+        return it
+    }
+
+    for attr in modifiers.iter() {
+        let mname = attr.name();
+
+        match fld.cx.syntax_env.find(&intern(mname.get())) {
+            Some(rc) => match *rc {
+                MultiModifier(ref mac) => {
+                    attr::mark_used(attr);
+                    fld.cx.bt_push(ExpnInfo {
+                        call_site: attr.span,
+                        callee: NameAndSpan {
+                            name: mname.get().to_string(),
+                            format: MacroAttribute,
+                            span: None,
+                        }
+                    });
+                    it = mac.expand(fld.cx, attr.span, &*attr.node.value, it);
+                    fld.cx.bt_pop();
+                }
+                _ => unreachable!()
+            },
+            _ => unreachable!()
+        }
+    }
+
+    // Expansion may have added new ItemModifiers.
+    expand_item_multi_modifier(it, fld)
+}
+
 // expand a method
 fn expand_method(m: P<ast::Method>, fld: &mut MacroExpander) -> SmallVector<P<ast::Method>> {
     m.and_then(|m| match m.node {
@@ -1042,7 +1172,7 @@ fn expand_method(m: P<ast::Method>, fld: &mut MacroExpander) -> SmallVector<P<as
                       vis) => {
             let id = fld.new_id(m.id);
             let (rewritten_fn_decl, rewritten_body)
-                = expand_and_rename_fn_decl_and_block(decl,body,fld);
+                = expand_and_rename_fn_decl_and_block(decl, body, fld);
             SmallVector::one(P(ast::Method {
                     attrs: m.attrs.move_map(|a| fld.fold_attribute(a)),
                     id: id,
@@ -1147,6 +1277,14 @@ fn fold_arm(&mut self, arm: ast::Arm) -> ast::Arm {
         expand_arm(arm, self)
     }
 
+    fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector<ast::TraitItem> {
+        expand_trait_item(i, self)
+    }
+
+    fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector<ast::ImplItem> {
+        expand_impl_item(i, self)
+    }
+
     fn fold_method(&mut self, method: P<ast::Method>) -> SmallVector<P<ast::Method>> {
         expand_method(method, self)
     }
index c45a4005339baea337116a1494daf44e2da0d048..16c29c9b5eb33a4bc206baf8b39b477c3fb09064 100644 (file)
@@ -102,6 +102,14 @@ fn fold_item_underscore(&mut self, i: Item_) -> Item_ {
         noop_fold_item_underscore(i, self)
     }
 
+    fn fold_trait_item(&mut self, i: TraitItem) -> SmallVector<TraitItem> {
+        noop_fold_trait_item(i, self)
+    }
+
+    fn fold_impl_item(&mut self, i: ImplItem) -> SmallVector<ImplItem> {
+        noop_fold_impl_item(i, self)
+    }
+
     fn fold_fn_decl(&mut self, d: P<FnDecl>) -> P<FnDecl> {
         noop_fold_fn_decl(d, self)
     }
@@ -454,7 +462,10 @@ pub fn noop_fold_qpath<T: Folder>(qpath: P<QPath>, fld: &mut T) -> P<QPath> {
         QPath {
             self_type: fld.fold_ty(qpath.self_type),
             trait_ref: qpath.trait_ref.map(|tr| fld.fold_trait_ref(tr)),
-            item_name: fld.fold_ident(qpath.item_name),
+            item_path: PathSegment {
+                identifier: fld.fold_ident(qpath.item_path.identifier),
+                parameters: fld.fold_path_parameters(qpath.item_path.parameters),
+            }
         }
     })
 }
@@ -1004,21 +1015,9 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
             ItemStruct(struct_def, folder.fold_generics(generics))
         }
         ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => {
-            let mut new_impl_items = Vec::new();
-            for impl_item in impl_items.iter() {
-                match *impl_item {
-                    MethodImplItem(ref x) => {
-                        for method in folder.fold_method((*x).clone())
-                                            .into_iter() {
-                            new_impl_items.push(MethodImplItem(method))
-                        }
-                    }
-                    TypeImplItem(ref t) => {
-                        new_impl_items.push(TypeImplItem(
-                                P(folder.fold_typedef((**t).clone()))));
-                    }
-                }
-            }
+            let new_impl_items = impl_items.into_iter().flat_map(|item| {
+                folder.fold_impl_item(item).into_iter()
+            }).collect();
             let ifce = match ifce {
                 None => None,
                 Some(ref trait_ref) => {
@@ -1032,43 +1031,50 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
                      folder.fold_ty(ty),
                      new_impl_items)
         }
-        ItemTrait(unsafety, generics, bounds, methods) => {
+        ItemTrait(unsafety, generics, bounds, items) => {
             let bounds = folder.fold_bounds(bounds);
-            let methods = methods.into_iter().flat_map(|method| {
-                let r = match method {
-                    RequiredMethod(m) => {
-                            SmallVector::one(RequiredMethod(
-                                    folder.fold_type_method(m)))
-                                .into_iter()
-                    }
-                    ProvidedMethod(method) => {
-                        // the awkward collect/iter idiom here is because
-                        // even though an iter and a map satisfy the same
-                        // trait bound, they're not actually the same type, so
-                        // the method arms don't unify.
-                        let methods: SmallVector<ast::TraitItem> =
-                            folder.fold_method(method).into_iter()
-                            .map(|m| ProvidedMethod(m)).collect();
-                        methods.into_iter()
-                    }
-                    TypeTraitItem(at) => {
-                        SmallVector::one(TypeTraitItem(P(
-                                    folder.fold_associated_type(
-                                        (*at).clone()))))
-                            .into_iter()
-                    }
-                };
-                r
+            let items = items.into_iter().flat_map(|item| {
+                folder.fold_trait_item(item).into_iter()
             }).collect();
             ItemTrait(unsafety,
                       folder.fold_generics(generics),
                       bounds,
-                      methods)
+                      items)
         }
         ItemMac(m) => ItemMac(folder.fold_mac(m)),
     }
 }
 
+pub fn noop_fold_trait_item<T: Folder>(i: TraitItem, folder: &mut T) -> SmallVector<TraitItem> {
+    match i {
+        RequiredMethod(m) => {
+                SmallVector::one(RequiredMethod(
+                        folder.fold_type_method(m)))
+        }
+        ProvidedMethod(method) => {
+            folder.fold_method(method).into_iter()
+                .map(|m| ProvidedMethod(m)).collect()
+        }
+        TypeTraitItem(at) => {
+            SmallVector::one(TypeTraitItem(P(
+                        folder.fold_associated_type(
+                            (*at).clone()))))
+        }
+    }
+}
+
+pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T) -> SmallVector<ImplItem> {
+    match i {
+        MethodImplItem(ref x) => {
+            folder.fold_method((*x).clone()).into_iter().map(|m| MethodImplItem(m)).collect()
+        }
+        TypeImplItem(ref t) => {
+            SmallVector::one(TypeImplItem(
+                    P(folder.fold_typedef((**t).clone()))))
+        }
+    }
+}
+
 pub fn noop_fold_type_method<T: Folder>(m: TypeMethod, fld: &mut T) -> TypeMethod {
     let TypeMethod {
         id,
@@ -1381,6 +1387,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
                           e2.map(|x| folder.fold_expr(x)))
             }
             ExprPath(pth) => ExprPath(folder.fold_path(pth)),
+            ExprQPath(qpath) => ExprQPath(folder.fold_qpath(qpath)),
             ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| folder.fold_ident(x))),
             ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| folder.fold_ident(x))),
             ExprRet(e) => ExprRet(e.map(|x| folder.fold_expr(x))),
index e9e207e7dbc3ba15fbbb3de1ba1edbac07176530..9d03ec73af8b127f0f0fa4e606d9510d23fb89e7 100644 (file)
 pub enum ObsoleteSyntax {
     Sized,
     ForSized,
-    OwnedType,
-    OwnedExpr,
-    OwnedPattern,
-    OwnedVector,
-    OwnedSelf,
-    ImportRenaming,
-    SubsliceMatch,
-    ExternCrateRenaming,
     ProcType,
     ProcExpr,
     ClosureType,
@@ -69,38 +61,6 @@ fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) {
                 "`proc` expression",
                 "use a `move ||` expression instead",
             ),
-            ObsoleteSyntax::OwnedType => (
-                "`~` notation for owned pointers",
-                "use `Box<T>` in `std::owned` instead"
-            ),
-            ObsoleteSyntax::OwnedExpr => (
-                "`~` notation for owned pointer allocation",
-                "use the `box` operator instead of `~`"
-            ),
-            ObsoleteSyntax::OwnedPattern => (
-                "`~` notation for owned pointer patterns",
-                "use the `box` operator instead of `~`"
-            ),
-            ObsoleteSyntax::OwnedVector => (
-                "`~[T]` is no longer a type",
-                "use the `Vec` type instead"
-            ),
-            ObsoleteSyntax::OwnedSelf => (
-                "`~self` is no longer supported",
-                "write `self: Box<Self>` instead"
-            ),
-            ObsoleteSyntax::ImportRenaming => (
-                "`use foo = bar` syntax",
-                "write `use bar as foo` instead"
-            ),
-            ObsoleteSyntax::SubsliceMatch => (
-                "subslice match syntax",
-                "instead of `..xs`, write `xs..` in a pattern"
-            ),
-            ObsoleteSyntax::ExternCrateRenaming => (
-                "`extern crate foo = bar` syntax",
-                "write `extern crate bar as foo` instead"
-            ),
             ObsoleteSyntax::ClosureType => (
                 "`|uint| -> bool` closure type syntax",
                 "use unboxed closures instead, no type annotation needed"
index 33f9e35d8b7af76280b126d49ac8c12bf8006202..30cc9836374fb598775890b6e2037e21f340cff2 100644 (file)
@@ -25,7 +25,7 @@
 use ast::{ExprBreak, ExprCall, ExprCast};
 use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex};
 use ast::{ExprLit, ExprLoop, ExprMac, ExprRange};
-use ast::{ExprMethodCall, ExprParen, ExprPath};
+use ast::{ExprMethodCall, ExprParen, ExprPath, ExprQPath};
 use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
 use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
 use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
@@ -52,7 +52,7 @@
 use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef};
 use ast::{TtDelimited, TtSequence, TtToken};
 use ast::{TupleVariantKind, Ty, Ty_, TypeBinding};
-use ast::{TypeField, TyFixedLengthVec, TyBareFn};
+use ast::{TyFixedLengthVec, TyBareFn};
 use ast::{TyTypeof, TyInfer, TypeMethod};
 use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath};
 use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq};
@@ -71,7 +71,7 @@
 use parse::classify;
 use parse::common::{SeqSep, seq_sep_none, seq_sep_trailing_allowed};
 use parse::lexer::{Reader, TokenAndSpan};
-use parse::obsolete::*;
+use parse::obsolete::{ParserObsoleteMethods, ObsoleteSyntax};
 use parse::token::{self, MatchNt, SubstNt, SpecialVarNt, InternedString};
 use parse::token::{keywords, special_idents, SpecialMacroVar};
 use parse::{new_sub_parser_from_file, ParseSess};
@@ -1404,22 +1404,6 @@ pub fn parse_mt(&mut self) -> MutTy {
         MutTy { ty: t, mutbl: mutbl }
     }
 
-    /// Parse [mut/const/imm] ID : TY
-    /// now used only by obsolete record syntax parser...
-    pub fn parse_ty_field(&mut self) -> TypeField {
-        let lo = self.span.lo;
-        let mutbl = self.parse_mutability();
-        let id = self.parse_ident();
-        self.expect(&token::Colon);
-        let ty = self.parse_ty_sum();
-        let hi = ty.span.hi;
-        ast::TypeField {
-            ident: id,
-            mt: MutTy { ty: ty, mutbl: mutbl },
-            span: mk_sp(lo, hi),
-        }
-    }
-
     /// Parse optional return type [ -> TY ] in function decl
     pub fn parse_ret_ty(&mut self) -> FunctionRetTy {
         if self.eat(&token::RArrow) {
@@ -1506,17 +1490,6 @@ pub fn parse_ty(&mut self) -> P<Ty> {
             } else {
                 TyTup(ts)
             }
-        } else if self.token == token::Tilde {
-            // OWNED POINTER
-            self.bump();
-            let last_span = self.last_span;
-            match self.token {
-                token::OpenDelim(token::Bracket) => {
-                    self.obsolete(last_span, ObsoleteSyntax::OwnedVector)
-                }
-                _ => self.obsolete(last_span, ObsoleteSyntax::OwnedType)
-            }
-            TyTup(vec![self.parse_ty()])
         } else if self.check(&token::BinOp(token::Star)) {
             // STAR POINTER (bare pointer?)
             self.bump();
@@ -1573,7 +1546,10 @@ pub fn parse_ty(&mut self) -> P<Ty> {
             TyQPath(P(QPath {
                 self_type: self_type,
                 trait_ref: P(trait_ref),
-                item_name: item_name,
+                item_path: ast::PathSegment {
+                    identifier: item_name,
+                    parameters: ast::PathParameters::none()
+                }
             }))
         } else if self.check(&token::ModSep) ||
                   self.token.is_ident() ||
@@ -1894,11 +1870,7 @@ pub fn parse_path_segments_with_colons(&mut self) -> Vec<ast::PathSegment> {
             if !self.eat(&token::ModSep) {
                 segments.push(ast::PathSegment {
                     identifier: identifier,
-                    parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
-                        lifetimes: Vec::new(),
-                        types: OwnedSlice::empty(),
-                        bindings: OwnedSlice::empty(),
-                    })
+                    parameters: ast::PathParameters::none()
                 });
                 return segments;
             }
@@ -2253,6 +2225,37 @@ pub fn parse_bottom_expr(&mut self) -> P<Expr> {
                 hi = self.last_span.hi;
             }
             _ => {
+                if self.eat_lt() {
+                    // QUALIFIED PATH `<TYPE as TRAIT_REF>::item::<'a, T>`
+                    let self_type = self.parse_ty_sum();
+                    self.expect_keyword(keywords::As);
+                    let trait_ref = self.parse_trait_ref();
+                    self.expect(&token::Gt);
+                    self.expect(&token::ModSep);
+                    let item_name = self.parse_ident();
+                    let parameters = if self.eat(&token::ModSep) {
+                        self.expect_lt();
+                        // Consumed `item::<`, go look for types
+                        let (lifetimes, types, bindings) =
+                            self.parse_generic_values_after_lt();
+                        ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
+                            lifetimes: lifetimes,
+                            types: OwnedSlice::from_vec(types),
+                            bindings: OwnedSlice::from_vec(bindings),
+                        })
+                    } else {
+                        ast::PathParameters::none()
+                    };
+                    let hi = self.span.hi;
+                    return self.mk_expr(lo, hi, ExprQPath(P(QPath {
+                        self_type: self_type,
+                        trait_ref: P(trait_ref),
+                        item_path: ast::PathSegment {
+                            identifier: item_name,
+                            parameters: parameters
+                        }
+                    })));
+                }
                 if self.eat_keyword(keywords::Move) {
                     return self.parse_lambda_expr(CaptureByValue);
                 }
@@ -2800,20 +2803,6 @@ pub fn parse_prefix_expr(&mut self) -> P<Expr> {
             hi = e.span.hi;
             ex = ExprAddrOf(m, e);
           }
-          token::Tilde => {
-            self.bump();
-            let last_span = self.last_span;
-            match self.token {
-                token::OpenDelim(token::Bracket) => {
-                    self.obsolete(last_span, ObsoleteSyntax::OwnedVector)
-                },
-                _ => self.obsolete(last_span, ObsoleteSyntax::OwnedExpr)
-            }
-
-            let e = self.parse_prefix_expr();
-            hi = e.span.hi;
-            ex = self.mk_unary(UnUniq, e);
-          }
           token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => {
             // A range, closed above: `..expr`.
             self.bump();
@@ -3219,10 +3208,6 @@ fn parse_pat_vec_elements(
                             span: self.span,
                         }));
                         before_slice = false;
-                    } else {
-                        let _ = self.parse_pat();
-                        let span = self.span;
-                        self.obsolete(span, ObsoleteSyntax::SubsliceMatch);
                     }
                     continue
                 }
@@ -3331,20 +3316,6 @@ pub fn parse_pat(&mut self) -> P<Pat> {
                 span: mk_sp(lo, hi)
             })
           }
-          token::Tilde => {
-            // parse ~pat
-            self.bump();
-            let sub = self.parse_pat();
-            pat = PatBox(sub);
-            let last_span = self.last_span;
-            hi = last_span.hi;
-            self.obsolete(last_span, ObsoleteSyntax::OwnedPattern);
-            return P(ast::Pat {
-                id: ast::DUMMY_NODE_ID,
-                node: pat,
-                span: mk_sp(lo, hi)
-            })
-          }
           token::BinOp(token::And) | token::AndAnd => {
             // parse &pat and &mut pat
             let lo = self.span.lo;
@@ -4453,16 +4424,6 @@ fn maybe_parse_borrowed_explicit_self(this: &mut Parser)
                 self_ident_hi = self.last_span.hi;
                 eself
             }
-            token::Tilde => {
-                // We need to make sure it isn't a type
-                if self.look_ahead(1, |t| t.is_keyword(keywords::Self)) {
-                    self.bump();
-                    drop(self.expect_self_ident());
-                    let last_span = self.last_span;
-                    self.obsolete(last_span, ObsoleteSyntax::OwnedSelf)
-                }
-                SelfStatic
-            }
             token::BinOp(token::Star) => {
                 // Possibly "*self" or "*mut self" -- not supported. Try to avoid
                 // emitting cryptic "unexpected token" errors.
@@ -4503,15 +4464,6 @@ fn maybe_parse_borrowed_explicit_self(this: &mut Parser)
                     } else {
                         SelfValue(self_ident)
                     }
-                } else if self.token.is_mutability() &&
-                        self.look_ahead(1, |t| *t == token::Tilde) &&
-                        self.look_ahead(2, |t| t.is_keyword(keywords::Self)) {
-                    mutbl_self = self.parse_mutability();
-                    self.bump();
-                    drop(self.expect_self_ident());
-                    let last_span = self.last_span;
-                    self.obsolete(last_span, ObsoleteSyntax::OwnedSelf);
-                    SelfStatic
                 } else {
                     SelfStatic
                 }
@@ -5392,13 +5344,7 @@ fn parse_item_extern_crate(&mut self,
         let (maybe_path, ident) = match self.token {
             token::Ident(..) => {
                 let the_ident = self.parse_ident();
-                let path = if self.token == token::Eq {
-                    self.bump();
-                    let path = self.parse_str();
-                    let span = self.span;
-                    self.obsolete(span, ObsoleteSyntax::ExternCrateRenaming);
-                    Some(path)
-                } else if self.eat_keyword(keywords::As) {
+                let path = if self.eat_keyword(keywords::As) {
                     // skip the ident if there is one
                     if self.token.is_ident() { self.bump(); }
 
@@ -5668,17 +5614,7 @@ fn parse_item_or_view_item(&mut self,
         }
         // either a view item or an item:
         if self.eat_keyword(keywords::Extern) {
-            let next_is_mod = self.eat_keyword(keywords::Mod);
-
-            if next_is_mod || self.eat_keyword(keywords::Crate) {
-                if next_is_mod {
-                    let last_span = self.last_span;
-                    self.span_err(mk_sp(lo, last_span.hi),
-                                 &format!("`extern mod` is obsolete, use \
-                                          `extern crate` instead \
-                                          to refer to external \
-                                          crates.")[])
-                }
+            if self.eat_keyword(keywords::Crate) {
                 return self.parse_item_extern_crate(lo, visibility, attrs);
             }
 
@@ -6045,35 +5981,7 @@ fn parse_view_path(&mut self) -> P<ViewPath> {
 
         let first_ident = self.parse_ident();
         let mut path = vec!(first_ident);
-        match self.token {
-          token::Eq => {
-            // x = foo::bar
-            self.bump();
-            let path_lo = self.span.lo;
-            path = vec!(self.parse_ident());
-            while self.check(&token::ModSep) {
-                self.bump();
-                let id = self.parse_ident();
-                path.push(id);
-            }
-            let span = mk_sp(path_lo, self.span.hi);
-            self.obsolete(span, ObsoleteSyntax::ImportRenaming);
-            let path = ast::Path {
-                span: span,
-                global: false,
-                segments: path.into_iter().map(|identifier| {
-                    ast::PathSegment {
-                        identifier: identifier,
-                        parameters: ast::PathParameters::none(),
-                    }
-                }).collect()
-            };
-            return P(spanned(lo, self.span.hi,
-                             ViewPathSimple(first_ident, path,
-                                           ast::DUMMY_NODE_ID)));
-          }
-
-          token::ModSep => {
+        if let token::ModSep = self.token {
             // foo::bar or foo::{a,b,c} or foo::*
             while self.check(&token::ModSep) {
                 self.bump();
@@ -6126,8 +6034,6 @@ fn parse_view_path(&mut self) -> P<ViewPath> {
                   _ => break
                 }
             }
-          }
-          _ => ()
         }
         let mut rename_to = path[path.len() - 1u];
         let path = ast::Path {
index b69b812c9586e7f4abb485699544d343ff65c8a8..06d510d37bd312dc6a032b0975a1db3380d2bcfb 100644 (file)
 //! line (which it can't) and so naturally place the content on its own line to
 //! avoid combining it with other lines and making matters even worse.
 
-pub use self::PrintStackBreak::*;
-pub use self::Breaks::*;
-pub use self::Token::*;
-
 use std::io;
 use std::string;
 use std::iter::repeat;
@@ -87,7 +83,7 @@ pub struct BeginToken {
 
 #[derive(Clone)]
 pub enum Token {
-    String(string::String, int),
+    String(String, int),
     Break(BreakToken),
     Begin(BeginToken),
     End,
@@ -96,12 +92,15 @@ pub enum Token {
 
 impl Token {
     pub fn is_eof(&self) -> bool {
-        match *self { Eof => true, _ => false }
+        match *self {
+            Token::Eof => true,
+            _ => false,
+        }
     }
 
     pub fn is_hardbreak_tok(&self) -> bool {
         match *self {
-            Break(BreakToken {
+            Token::Break(BreakToken {
                 offset: 0,
                 blank_space: bs
             }) if bs == SIZE_INFINITY =>
@@ -112,22 +111,22 @@ pub fn is_hardbreak_tok(&self) -> bool {
     }
 }
 
-pub fn tok_str(t: Token) -> string::String {
-    match t {
-        String(s, len) => return format!("STR({},{})", s, len),
-        Break(_) => return "BREAK".to_string(),
-        Begin(_) => return "BEGIN".to_string(),
-        End => return "END".to_string(),
-        Eof => return "EOF".to_string()
+pub fn tok_str(token: &Token) -> String {
+    match *token {
+        Token::String(ref s, len) => format!("STR({},{})", s, len),
+        Token::Break(_) => "BREAK".to_string(),
+        Token::Begin(_) => "BEGIN".to_string(),
+        Token::End => "END".to_string(),
+        Token::Eof => "EOF".to_string()
     }
 }
 
-pub fn buf_str(toks: Vec<Token>,
-               szs: Vec<int>,
+pub fn buf_str(toks: &[Token],
+               szs: &[int],
                left: uint,
                right: uint,
                lim: uint)
-               -> string::String {
+               -> String {
     let n = toks.len();
     assert_eq!(n, szs.len());
     let mut i = left;
@@ -140,7 +139,7 @@ pub fn buf_str(toks: Vec<Token>,
         }
         s.push_str(&format!("{}={}",
                            szs[i],
-                           tok_str(toks[i].clone()))[]);
+                           tok_str(&toks[i]))[]);
         i += 1u;
         i %= n;
     }
@@ -167,7 +166,7 @@ pub fn mk_printer(out: Box<io::Writer+'static>, linewidth: uint) -> Printer {
     // fall behind.
     let n: uint = 3 * linewidth;
     debug!("mk_printer {}", linewidth);
-    let token: Vec<Token> = repeat(Eof).take(n).collect();
+    let token: Vec<Token> = repeat(Token::Eof).take(n).collect();
     let size: Vec<int> = repeat(0i).take(n).collect();
     let scan_stack: Vec<uint> = repeat(0u).take(n).collect();
     Printer {
@@ -312,20 +311,18 @@ pub fn last_token(&mut self) -> Token {
     pub fn replace_last_token(&mut self, t: Token) {
         self.token[self.right] = t;
     }
-    pub fn pretty_print(&mut self, t: Token) -> io::IoResult<()> {
+    pub fn pretty_print(&mut self, token: Token) -> io::IoResult<()> {
         debug!("pp ~[{},{}]", self.left, self.right);
-        match t {
-          Eof => {
+        match token {
+          Token::Eof => {
             if !self.scan_stack_empty {
                 self.check_stack(0);
-                let left = self.token[self.left].clone();
-                let left_size = self.size[self.left];
-                try!(self.advance_left(left, left_size));
+                try!(self.advance_left());
             }
             self.indent(0);
             Ok(())
           }
-          Begin(b) => {
+          Token::Begin(b) => {
             if self.scan_stack_empty {
                 self.left_total = 1;
                 self.right_total = 1;
@@ -334,27 +331,27 @@ pub fn pretty_print(&mut self, t: Token) -> io::IoResult<()> {
             } else { self.advance_right(); }
             debug!("pp Begin({})/buffer ~[{},{}]",
                    b.offset, self.left, self.right);
-            self.token[self.right] = t;
+            self.token[self.right] = token;
             self.size[self.right] = -self.right_total;
             let right = self.right;
             self.scan_push(right);
             Ok(())
           }
-          End => {
+          Token::End => {
             if self.scan_stack_empty {
                 debug!("pp End/print ~[{},{}]", self.left, self.right);
-                self.print(t, 0)
+                self.print(token, 0)
             } else {
                 debug!("pp End/buffer ~[{},{}]", self.left, self.right);
                 self.advance_right();
-                self.token[self.right] = t;
+                self.token[self.right] = token;
                 self.size[self.right] = -1;
                 let right = self.right;
                 self.scan_push(right);
                 Ok(())
             }
           }
-          Break(b) => {
+          Token::Break(b) => {
             if self.scan_stack_empty {
                 self.left_total = 1;
                 self.right_total = 1;
@@ -366,21 +363,21 @@ pub fn pretty_print(&mut self, t: Token) -> io::IoResult<()> {
             self.check_stack(0);
             let right = self.right;
             self.scan_push(right);
-            self.token[self.right] = t;
+            self.token[self.right] = token;
             self.size[self.right] = -self.right_total;
             self.right_total += b.blank_space;
             Ok(())
           }
-          String(ref s, len) => {
+          Token::String(s, len) => {
             if self.scan_stack_empty {
                 debug!("pp String('{}')/print ~[{},{}]",
-                       *s, self.left, self.right);
-                self.print(t.clone(), len)
+                       s, self.left, self.right);
+                self.print(Token::String(s, len), len)
             } else {
                 debug!("pp String('{}')/buffer ~[{},{}]",
-                       *s, self.left, self.right);
+                       s, self.left, self.right);
                 self.advance_right();
-                self.token[self.right] = t.clone();
+                self.token[self.right] = Token::String(s, len);
                 self.size[self.right] = len;
                 self.right_total += len;
                 self.check_stream()
@@ -401,9 +398,7 @@ pub fn check_stream(&mut self) -> io::IoResult<()> {
                     self.size[scanned] = SIZE_INFINITY;
                 }
             }
-            let left = self.token[self.left].clone();
-            let left_size = self.size[self.left];
-            try!(self.advance_left(left, left_size));
+            try!(self.advance_left());
             if self.left != self.right {
                 try!(self.check_stream());
             }
@@ -450,42 +445,52 @@ pub fn advance_right(&mut self) {
         self.right %= self.buf_len;
         assert!((self.right != self.left));
     }
-    pub fn advance_left(&mut self, x: Token, l: int) -> io::IoResult<()> {
+    pub fn advance_left(&mut self) -> io::IoResult<()> {
         debug!("advance_left ~[{},{}], sizeof({})={}", self.left, self.right,
-               self.left, l);
-        if l >= 0 {
-            let ret = self.print(x.clone(), l);
-            match x {
-              Break(b) => self.left_total += b.blank_space,
-              String(_, len) => {
-                assert_eq!(len, l); self.left_total += len;
-              }
-              _ => ()
-            }
-            if self.left != self.right {
-                self.left += 1u;
-                self.left %= self.buf_len;
-                let left = self.token[self.left].clone();
-                let left_size = self.size[self.left];
-                try!(self.advance_left(left, left_size));
+               self.left, self.size[self.left]);
+
+        let mut left_size = self.size[self.left];
+
+        while left_size >= 0 {
+            let left = self.token[self.left].clone();
+
+            let len = match left {
+                Token::Break(b) => b.blank_space,
+                Token::String(_, len) => {
+                    assert_eq!(len, left_size);
+                    len
+                }
+                _ => 0
+            };
+
+            try!(self.print(left, left_size));
+
+            self.left_total += len;
+
+            if self.left == self.right {
+                break;
             }
-            ret
-        } else {
-            Ok(())
+
+            self.left += 1u;
+            self.left %= self.buf_len;
+
+            left_size = self.size[self.left];
         }
+
+        Ok(())
     }
     pub fn check_stack(&mut self, k: int) {
         if !self.scan_stack_empty {
             let x = self.scan_top();
             match self.token[x] {
-                Begin(_) => {
+                Token::Begin(_) => {
                     if k > 0 {
                         let popped = self.scan_pop();
                         self.size[popped] = self.size[x] + self.right_total;
                         self.check_stack(k - 1);
                     }
                 }
-                End => {
+                Token::End => {
                     // paper says + not =, but that makes no sense.
                     let popped = self.scan_pop();
                     self.size[popped] = 1;
@@ -520,7 +525,7 @@ pub fn get_top(&mut self) -> PrintStackElem {
         } else {
             PrintStackElem {
                 offset: 0,
-                pbreak: Broken(Inconsistent)
+                pbreak: PrintStackBreak::Broken(Breaks::Inconsistent)
             }
         }
     }
@@ -531,56 +536,56 @@ pub fn print_str(&mut self, s: &str) -> io::IoResult<()> {
         }
         write!(self.out, "{}", s)
     }
-    pub fn print(&mut self, x: Token, l: int) -> io::IoResult<()> {
-        debug!("print {} {} (remaining line space={})", tok_str(x.clone()), l,
+    pub fn print(&mut self, token: Token, l: int) -> io::IoResult<()> {
+        debug!("print {} {} (remaining line space={})", tok_str(&token), l,
                self.space);
-        debug!("{}", buf_str(self.token.clone(),
-                             self.size.clone(),
+        debug!("{}", buf_str(&self.token[],
+                             &self.size[],
                              self.left,
                              self.right,
                              6));
-        match x {
-          Begin(b) => {
+        match token {
+          Token::Begin(b) => {
             if l > self.space {
                 let col = self.margin - self.space + b.offset;
                 debug!("print Begin -> push broken block at col {}", col);
                 self.print_stack.push(PrintStackElem {
                     offset: col,
-                    pbreak: Broken(b.breaks)
+                    pbreak: PrintStackBreak::Broken(b.breaks)
                 });
             } else {
                 debug!("print Begin -> push fitting block");
                 self.print_stack.push(PrintStackElem {
                     offset: 0,
-                    pbreak: Fits
+                    pbreak: PrintStackBreak::Fits
                 });
             }
             Ok(())
           }
-          End => {
+          Token::End => {
             debug!("print End -> pop End");
             let print_stack = &mut self.print_stack;
             assert!((print_stack.len() != 0u));
             print_stack.pop().unwrap();
             Ok(())
           }
-          Break(b) => {
+          Token::Break(b) => {
             let top = self.get_top();
             match top.pbreak {
-              Fits => {
+              PrintStackBreak::Fits => {
                 debug!("print Break({}) in fitting block", b.blank_space);
                 self.space -= b.blank_space;
                 self.indent(b.blank_space);
                 Ok(())
               }
-              Broken(Consistent) => {
+              PrintStackBreak::Broken(Breaks::Consistent) => {
                 debug!("print Break({}+{}) in consistent block",
                        top.offset, b.offset);
                 let ret = self.print_newline(top.offset + b.offset);
                 self.space = self.margin - (top.offset + b.offset);
                 ret
               }
-              Broken(Inconsistent) => {
+              PrintStackBreak::Broken(Breaks::Inconsistent) => {
                 if l > self.space {
                     debug!("print Break({}+{}) w/ newline in inconsistent",
                            top.offset, b.offset);
@@ -597,14 +602,14 @@ pub fn print(&mut self, x: Token, l: int) -> io::IoResult<()> {
               }
             }
           }
-          String(s, len) => {
+          Token::String(s, len) => {
             debug!("print String({})", s);
             assert_eq!(l, len);
             // assert!(l <= space);
             self.space -= len;
             self.print_str(&s[])
           }
-          Eof => {
+          Token::Eof => {
             // Eof should never get here.
             panic!();
           }
@@ -616,41 +621,45 @@ pub fn print(&mut self, x: Token, l: int) -> io::IoResult<()> {
 //
 // "raw box"
 pub fn rbox(p: &mut Printer, indent: uint, b: Breaks) -> io::IoResult<()> {
-    p.pretty_print(Begin(BeginToken {
+    p.pretty_print(Token::Begin(BeginToken {
         offset: indent as int,
         breaks: b
     }))
 }
 
 pub fn ibox(p: &mut Printer, indent: uint) -> io::IoResult<()> {
-    rbox(p, indent, Inconsistent)
+    rbox(p, indent, Breaks::Inconsistent)
 }
 
 pub fn cbox(p: &mut Printer, indent: uint) -> io::IoResult<()> {
-    rbox(p, indent, Consistent)
+    rbox(p, indent, Breaks::Consistent)
 }
 
 pub fn break_offset(p: &mut Printer, n: uint, off: int) -> io::IoResult<()> {
-    p.pretty_print(Break(BreakToken {
+    p.pretty_print(Token::Break(BreakToken {
         offset: off,
         blank_space: n as int
     }))
 }
 
-pub fn end(p: &mut Printer) -> io::IoResult<()> { p.pretty_print(End) }
+pub fn end(p: &mut Printer) -> io::IoResult<()> {
+    p.pretty_print(Token::End)
+}
 
-pub fn eof(p: &mut Printer) -> io::IoResult<()> { p.pretty_print(Eof) }
+pub fn eof(p: &mut Printer) -> io::IoResult<()> {
+    p.pretty_print(Token::Eof)
+}
 
 pub fn word(p: &mut Printer, wrd: &str) -> io::IoResult<()> {
-    p.pretty_print(String(/* bad */ wrd.to_string(), wrd.len() as int))
+    p.pretty_print(Token::String(/* bad */ wrd.to_string(), wrd.len() as int))
 }
 
 pub fn huge_word(p: &mut Printer, wrd: &str) -> io::IoResult<()> {
-    p.pretty_print(String(/* bad */ wrd.to_string(), SIZE_INFINITY))
+    p.pretty_print(Token::String(/* bad */ wrd.to_string(), SIZE_INFINITY))
 }
 
 pub fn zero_word(p: &mut Printer, wrd: &str) -> io::IoResult<()> {
-    p.pretty_print(String(/* bad */ wrd.to_string(), 0))
+    p.pretty_print(Token::String(/* bad */ wrd.to_string(), 0))
 }
 
 pub fn spaces(p: &mut Printer, n: uint) -> io::IoResult<()> {
@@ -670,7 +679,9 @@ pub fn hardbreak(p: &mut Printer) -> io::IoResult<()> {
 }
 
 pub fn hardbreak_tok_offset(off: int) -> Token {
-    Break(BreakToken {offset: off, blank_space: SIZE_INFINITY})
+    Token::Break(BreakToken {offset: off, blank_space: SIZE_INFINITY})
 }
 
-pub fn hardbreak_tok() -> Token { return hardbreak_tok_offset(0); }
+pub fn hardbreak_tok() -> Token {
+    hardbreak_tok_offset(0)
+}
index 9b6f8e6002d8aa894b2502a7a818d752be75fae0..5d76dc710060b591e4bed8764fc01ce9a9dfc9c7 100644 (file)
@@ -25,7 +25,8 @@
 use parse::lexer::comments;
 use parse;
 use print::pp::{self, break_offset, word, space, zerobreak, hardbreak};
-use print::pp::{Breaks, Consistent, Inconsistent, eof};
+use print::pp::{Breaks, eof};
+use print::pp::Breaks::{Consistent, Inconsistent};
 use ptr::P;
 
 use std::{ascii, mem};
@@ -459,7 +460,7 @@ fn needs_parentheses(expr: &ast::Expr) -> bool {
 
 impl<'a> State<'a> {
     pub fn ibox(&mut self, u: uint) -> IoResult<()> {
-        self.boxes.push(pp::Inconsistent);
+        self.boxes.push(pp::Breaks::Inconsistent);
         pp::ibox(&mut self.s, u)
     }
 
@@ -469,7 +470,7 @@ pub fn end(&mut self) -> IoResult<()> {
     }
 
     pub fn cbox(&mut self, u: uint) -> IoResult<()> {
-        self.boxes.push(pp::Consistent);
+        self.boxes.push(pp::Breaks::Consistent);
         pp::cbox(&mut self.s, u)
     }
 
@@ -531,11 +532,17 @@ pub fn bclose(&mut self, span: codemap::Span) -> IoResult<()> {
     }
 
     pub fn is_begin(&mut self) -> bool {
-        match self.s.last_token() { pp::Begin(_) => true, _ => false }
+        match self.s.last_token() {
+            pp::Token::Begin(_) => true,
+            _ => false,
+        }
     }
 
     pub fn is_end(&mut self) -> bool {
-        match self.s.last_token() { pp::End => true, _ => false }
+        match self.s.last_token() {
+            pp::Token::End => true,
+            _ => false,
+        }
     }
 
     // is this the beginning of a line?
@@ -545,7 +552,7 @@ pub fn is_bol(&mut self) -> bool {
 
     pub fn in_cbox(&self) -> bool {
         match self.boxes.last() {
-            Some(&last_box) => last_box == pp::Consistent,
+            Some(&last_box) => last_box == pp::Breaks::Consistent,
             None => false
         }
     }
@@ -727,14 +734,7 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> IoResult<()> {
                 try!(self.print_bounds("", &bounds[]));
             }
             ast::TyQPath(ref qpath) => {
-                try!(word(&mut self.s, "<"));
-                try!(self.print_type(&*qpath.self_type));
-                try!(space(&mut self.s));
-                try!(self.word_space("as"));
-                try!(self.print_trait_ref(&*qpath.trait_ref));
-                try!(word(&mut self.s, ">"));
-                try!(word(&mut self.s, "::"));
-                try!(self.print_ident(qpath.item_name));
+                try!(self.print_qpath(&**qpath, false))
             }
             ast::TyFixedLengthVec(ref ty, ref v) => {
                 try!(word(&mut self.s, "["));
@@ -1504,108 +1504,168 @@ pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr) -> IoResult<()> {
         Ok(())
     }
 
+    fn print_expr_box(&mut self,
+                      place: &Option<P<ast::Expr>>,
+                      expr: &ast::Expr) -> IoResult<()> {
+        try!(word(&mut self.s, "box"));
+        try!(word(&mut self.s, "("));
+        try!(place.as_ref().map_or(Ok(()), |e|self.print_expr(&**e)));
+        try!(self.word_space(")"));
+        self.print_expr(expr)
+    }
+
+    fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) -> IoResult<()> {
+        try!(self.ibox(indent_unit));
+        try!(word(&mut self.s, "["));
+        try!(self.commasep_exprs(Inconsistent, &exprs[]));
+        try!(word(&mut self.s, "]"));
+        self.end()
+    }
+
+    fn print_expr_repeat(&mut self,
+                         element: &ast::Expr,
+                         count: &ast::Expr) -> IoResult<()> {
+        try!(self.ibox(indent_unit));
+        try!(word(&mut self.s, "["));
+        try!(self.print_expr(element));
+        try!(self.word_space(";"));
+        try!(self.print_expr(count));
+        try!(word(&mut self.s, "]"));
+        self.end()
+    }
+
+    fn print_expr_struct(&mut self,
+                         path: &ast::Path,
+                         fields: &[ast::Field],
+                         wth: &Option<P<ast::Expr>>) -> IoResult<()> {
+        try!(self.print_path(path, true));
+        if !(fields.is_empty() && wth.is_none()) {
+            try!(word(&mut self.s, "{"));
+            try!(self.commasep_cmnt(
+                Consistent,
+                &fields[],
+                |s, field| {
+                    try!(s.ibox(indent_unit));
+                    try!(s.print_ident(field.ident.node));
+                    try!(s.word_space(":"));
+                    try!(s.print_expr(&*field.expr));
+                    s.end()
+                },
+                |f| f.span));
+            match *wth {
+                Some(ref expr) => {
+                    try!(self.ibox(indent_unit));
+                    if !fields.is_empty() {
+                        try!(word(&mut self.s, ","));
+                        try!(space(&mut self.s));
+                    }
+                    try!(word(&mut self.s, ".."));
+                    try!(self.print_expr(&**expr));
+                    try!(self.end());
+                }
+                _ => try!(word(&mut self.s, ",")),
+            }
+            try!(word(&mut self.s, "}"));
+        }
+        Ok(())
+    }
+
+    fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) -> IoResult<()> {
+        try!(self.popen());
+        try!(self.commasep_exprs(Inconsistent, &exprs[]));
+        if exprs.len() == 1 {
+            try!(word(&mut self.s, ","));
+        }
+        self.pclose()
+    }
+
+    fn print_expr_call(&mut self,
+                       func: &ast::Expr,
+                       args: &[P<ast::Expr>]) -> IoResult<()> {
+        try!(self.print_expr_maybe_paren(func));
+        self.print_call_post(args)
+    }
+
+    fn print_expr_method_call(&mut self,
+                              ident: ast::SpannedIdent,
+                              tys: &[P<ast::Ty>],
+                              args: &[P<ast::Expr>]) -> IoResult<()> {
+        let base_args = args.slice_from(1);
+        try!(self.print_expr(&*args[0]));
+        try!(word(&mut self.s, "."));
+        try!(self.print_ident(ident.node));
+        if tys.len() > 0u {
+            try!(word(&mut self.s, "::<"));
+            try!(self.commasep(Inconsistent, tys,
+                               |s, ty| s.print_type(&**ty)));
+            try!(word(&mut self.s, ">"));
+        }
+        self.print_call_post(base_args)
+    }
+
+    fn print_expr_binary(&mut self,
+                         op: ast::BinOp,
+                         lhs: &ast::Expr,
+                         rhs: &ast::Expr) -> IoResult<()> {
+        try!(self.print_expr(lhs));
+        try!(space(&mut self.s));
+        try!(self.word_space(ast_util::binop_to_string(op)));
+        self.print_expr(rhs)
+    }
+
+    fn print_expr_unary(&mut self,
+                        op: ast::UnOp,
+                        expr: &ast::Expr) -> IoResult<()> {
+        try!(word(&mut self.s, ast_util::unop_to_string(op)));
+        self.print_expr_maybe_paren(expr)
+    }
+
+    fn print_expr_addr_of(&mut self,
+                          mutability: ast::Mutability,
+                          expr: &ast::Expr) -> IoResult<()> {
+        try!(word(&mut self.s, "&"));
+        try!(self.print_mutability(mutability));
+        self.print_expr_maybe_paren(expr)
+    }
+
     pub fn print_expr(&mut self, expr: &ast::Expr) -> IoResult<()> {
         try!(self.maybe_print_comment(expr.span.lo));
         try!(self.ibox(indent_unit));
         try!(self.ann.pre(self, NodeExpr(expr)));
         match expr.node {
-            ast::ExprBox(ref p, ref e) => {
-                try!(word(&mut self.s, "box"));
-                try!(word(&mut self.s, "("));
-                try!(p.as_ref().map_or(Ok(()), |e|self.print_expr(&**e)));
-                try!(self.word_space(")"));
-                try!(self.print_expr(&**e));
+            ast::ExprBox(ref place, ref expr) => {
+                try!(self.print_expr_box(place, &**expr));
             }
             ast::ExprVec(ref exprs) => {
-                try!(self.ibox(indent_unit));
-                try!(word(&mut self.s, "["));
-                try!(self.commasep_exprs(Inconsistent, &exprs[]));
-                try!(word(&mut self.s, "]"));
-                try!(self.end());
+                try!(self.print_expr_vec(&exprs[]));
             }
-
             ast::ExprRepeat(ref element, ref count) => {
-                try!(self.ibox(indent_unit));
-                try!(word(&mut self.s, "["));
-                try!(self.print_expr(&**element));
-                try!(self.word_space(";"));
-                try!(self.print_expr(&**count));
-                try!(word(&mut self.s, "]"));
-                try!(self.end());
+                try!(self.print_expr_repeat(&**element, &**count));
             }
-
             ast::ExprStruct(ref path, ref fields, ref wth) => {
-                try!(self.print_path(path, true));
-                if !(fields.is_empty() && wth.is_none()) {
-                    try!(word(&mut self.s, "{"));
-                    try!(self.commasep_cmnt(
-                        Consistent,
-                        &fields[],
-                        |s, field| {
-                            try!(s.ibox(indent_unit));
-                            try!(s.print_ident(field.ident.node));
-                            try!(s.word_space(":"));
-                            try!(s.print_expr(&*field.expr));
-                            s.end()
-                        },
-                        |f| f.span));
-                    match *wth {
-                        Some(ref expr) => {
-                            try!(self.ibox(indent_unit));
-                            if !fields.is_empty() {
-                                try!(word(&mut self.s, ","));
-                                try!(space(&mut self.s));
-                            }
-                            try!(word(&mut self.s, ".."));
-                            try!(self.print_expr(&**expr));
-                            try!(self.end());
-                        }
-                        _ => try!(word(&mut self.s, ",")),
-                    }
-                    try!(word(&mut self.s, "}"));
-                }
+                try!(self.print_expr_struct(path, &fields[], wth));
             }
             ast::ExprTup(ref exprs) => {
-                try!(self.popen());
-                try!(self.commasep_exprs(Inconsistent, &exprs[]));
-                if exprs.len() == 1 {
-                    try!(word(&mut self.s, ","));
-                }
-                try!(self.pclose());
+                try!(self.print_expr_tup(&exprs[]));
             }
             ast::ExprCall(ref func, ref args) => {
-                try!(self.print_expr_maybe_paren(&**func));
-                try!(self.print_call_post(&args[]));
+                try!(self.print_expr_call(&**func, &args[]));
             }
             ast::ExprMethodCall(ident, ref tys, ref args) => {
-                let base_args = args.slice_from(1);
-                try!(self.print_expr(&*args[0]));
-                try!(word(&mut self.s, "."));
-                try!(self.print_ident(ident.node));
-                if tys.len() > 0u {
-                    try!(word(&mut self.s, "::<"));
-                    try!(self.commasep(Inconsistent, &tys[],
-                                       |s, ty| s.print_type(&**ty)));
-                    try!(word(&mut self.s, ">"));
-                }
-                try!(self.print_call_post(base_args));
+                try!(self.print_expr_method_call(ident, &tys[], &args[]));
             }
             ast::ExprBinary(op, ref lhs, ref rhs) => {
-                try!(self.print_expr(&**lhs));
-                try!(space(&mut self.s));
-                try!(self.word_space(ast_util::binop_to_string(op)));
-                try!(self.print_expr(&**rhs));
+                try!(self.print_expr_binary(op, &**lhs, &**rhs));
             }
             ast::ExprUnary(op, ref expr) => {
-                try!(word(&mut self.s, ast_util::unop_to_string(op)));
-                try!(self.print_expr_maybe_paren(&**expr));
+                try!(self.print_expr_unary(op, &**expr));
             }
             ast::ExprAddrOf(m, ref expr) => {
-                try!(word(&mut self.s, "&"));
-                try!(self.print_mutability(m));
-                try!(self.print_expr_maybe_paren(&**expr));
+                try!(self.print_expr_addr_of(m, &**expr));
+            }
+            ast::ExprLit(ref lit) => {
+                try!(self.print_literal(&**lit));
             }
-            ast::ExprLit(ref lit) => try!(self.print_literal(&**lit)),
             ast::ExprCast(ref expr, ref ty) => {
                 try!(self.print_expr(&**expr));
                 try!(space(&mut self.s));
@@ -1749,6 +1809,7 @@ pub fn print_expr(&mut self, expr: &ast::Expr) -> IoResult<()> {
                 }
             }
             ast::ExprPath(ref path) => try!(self.print_path(path, true)),
+            ast::ExprQPath(ref qpath) => try!(self.print_qpath(&**qpath, true)),
             ast::ExprBreak(opt_ident) => {
                 try!(word(&mut self.s, "break"));
                 try!(space(&mut self.s));
@@ -1933,6 +1994,22 @@ fn print_path(&mut self,
         Ok(())
     }
 
+    fn print_qpath(&mut self,
+                   qpath: &ast::QPath,
+                   colons_before_params: bool)
+                   -> IoResult<()>
+    {
+        try!(word(&mut self.s, "<"));
+        try!(self.print_type(&*qpath.self_type));
+        try!(space(&mut self.s));
+        try!(self.word_space("as"));
+        try!(self.print_trait_ref(&*qpath.trait_ref));
+        try!(word(&mut self.s, ">"));
+        try!(word(&mut self.s, "::"));
+        try!(self.print_ident(qpath.item_path.identifier));
+        self.print_path_parameters(&qpath.item_path.parameters, colons_before_params)
+    }
+
     fn print_path_parameters(&mut self,
                              parameters: &ast::PathParameters,
                              colons_before_params: bool)
@@ -2881,7 +2958,7 @@ pub fn print_comment(&mut self,
             comments::BlankLine => {
                 // We need to do at least one, possibly two hardbreaks.
                 let is_semi = match self.s.last_token() {
-                    pp::String(s, _) => ";" == s,
+                    pp::Token::String(s, _) => ";" == s,
                     _ => false
                 };
                 if is_semi || self.is_begin() || self.is_end() {
index 3f91304dcc5f21c528b2cfcdcee0c570109f10de..7778b4fa34aa1e7c19c258dbba2f10ec30c0cf0b 100644 (file)
@@ -126,6 +126,9 @@ fn visit_mac(&mut self, _mac: &'v Mac) {
     fn visit_path(&mut self, path: &'v Path, _id: ast::NodeId) {
         walk_path(self, path)
     }
+    fn visit_qpath(&mut self, qpath_span: Span, qpath: &'v QPath) {
+        walk_qpath(self, qpath_span, qpath)
+    }
     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) {
         walk_path_segment(self, path_span, path_segment)
     }
@@ -419,9 +422,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
             walk_ty_param_bounds_helper(visitor, bounds);
         }
         TyQPath(ref qpath) => {
-            visitor.visit_ty(&*qpath.self_type);
-            visitor.visit_trait_ref(&*qpath.trait_ref);
-            visitor.visit_ident(typ.span, qpath.item_name);
+            visitor.visit_qpath(typ.span, &**qpath);
         }
         TyFixedLengthVec(ref ty, ref expression) => {
             visitor.visit_ty(&**ty);
@@ -450,6 +451,14 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) {
     }
 }
 
+pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V,
+                                      qpath_span: Span,
+                                      qpath: &'v QPath) {
+    visitor.visit_ty(&*qpath.self_type);
+    visitor.visit_trait_ref(&*qpath.trait_ref);
+    visitor.visit_path_segment(qpath_span, &qpath.item_path);
+}
+
 pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
                                              path_span: Span,
                                              segment: &'v PathSegment) {
@@ -881,6 +890,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
         ExprPath(ref path) => {
             visitor.visit_path(path, expression.id)
         }
+        ExprQPath(ref qpath) => {
+            visitor.visit_qpath(expression.span, &**qpath)
+        }
         ExprBreak(_) | ExprAgain(_) => {}
         ExprRet(ref optional_expression) => {
             walk_expr_opt(visitor, optional_expression)
index c4cb53d6cb7b6e19cf557c613cc756d794ba0ac3..30173368585d2cf36d0a7c25e2130761b44dd6f2 100644 (file)
@@ -211,6 +211,8 @@ pub struct TestDesc {
     pub should_fail: ShouldFail,
 }
 
+unsafe impl Send for TestDesc {}
+
 #[derive(Show)]
 pub struct TestDescAndFn {
     pub desc: TestDesc,
@@ -525,6 +527,8 @@ pub enum TestResult {
     TrBench(BenchSamples),
 }
 
+unsafe impl Send for TestResult {}
+
 enum OutputLocation<T> {
     Pretty(Box<term::Terminal<term::WriterWrapper> + Send>),
     Raw(T),
@@ -978,7 +982,6 @@ enum TestEvent {
 
 pub type MonitorMsg = (TestDesc, TestResult, Vec<u8> );
 
-unsafe impl Send for MonitorMsg {}
 
 fn run_tests<F>(opts: &TestOpts,
                 tests: Vec<TestDescAndFn> ,
@@ -1332,10 +1335,11 @@ pub fn ratchet(&self, p: &Path, pct: Option<f64>) -> (MetricDiff, bool) {
 /// elimination.
 ///
 /// This function is a no-op, and does not even read from `dummy`.
-pub fn black_box<T>(dummy: T) {
+pub fn black_box<T>(dummy: T) -> T {
     // we need to "use" the argument in some way LLVM can't
     // introspect.
     unsafe {asm!("" : : "r"(&dummy))}
+    dummy
 }
 
 
diff --git a/src/rt/arch/powerpc/morestack.S b/src/rt/arch/powerpc/morestack.S
new file mode 100644 (file)
index 0000000..2502ac1
--- /dev/null
@@ -0,0 +1,18 @@
+// Mark stack as non-executable
+#if defined(__linux__) && defined(__ELF__)
+.section       .note.GNU-stack, "", %progbits
+#endif
+
+/* See i386/morestack.S for the lengthy, general explanation. */
+
+.global rust_stack_exhausted
+
+.hidden __morestack
+
+// FIXME(POWERPC): this might not be perfectly right but works for now
+__morestack:
+       .cfi_startproc
+       bl rust_stack_exhausted
+       // the above function ensures that it never returns
+       .cfi_endproc
+.end  __morestack
diff --git a/src/rt/arch/powerpc/record_sp.S b/src/rt/arch/powerpc/record_sp.S
new file mode 100644 (file)
index 0000000..e93a69a
--- /dev/null
@@ -0,0 +1,4 @@
+// Mark stack as non-executable
+#if defined(__linux__) && defined(__ELF__)
+.section       .note.GNU-stack, "", %progbits
+#endif
index 44b1630d9fb4c869e7a97f8c2d6b58b4ede7418a..50a6ad43aeeb109474781f9ea68196b1b15f27eb 100644 (file)
@@ -20,6 +20,7 @@
 use book;
 use book::{Book, BookItem};
 use css;
+use javascript;
 
 use regex::Regex;
 
@@ -63,7 +64,7 @@ fn walk_item(item: &BookItem,
         Ok(())
     }
 
-    try!(writeln!(out, "<div id='toc'>"));
+    try!(writeln!(out, "<div id='toc' class='mobile-hidden'>"));
     try!(writeln!(out, "<ul class='chapter'>"));
     try!(walk_items(&book.chapters[], "", path_to_root, out));
     try!(writeln!(out, "</ul>"));
@@ -102,6 +103,14 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
         let prelude = tmp.path().join("prelude.html");
         {
             let mut toc = BufferedWriter::new(try!(File::create(&prelude)));
+            try!(writeln!(&mut toc, r#"<div id="nav">
+                <button id="toggle-nav">
+                  <span class="sr-only">Toggle navigation</span>
+                  <span class="bar"></span>
+                  <span class="bar"></span>
+                  <span class="bar"></span>
+                </button>
+              </div>"#));
             let _ = write_toc(book, &item.path_to_root, &mut toc);
             try!(writeln!(&mut toc, "<div id='page-wrapper'>"));
             try!(writeln!(&mut toc, "<div id='page'>"));
@@ -111,6 +120,7 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
         let postlude = tmp.path().join("postlude.html");
         {
             let mut toc = BufferedWriter::new(try!(File::create(&postlude)));
+            try!(toc.write_str(javascript::JAVASCRIPT));
             try!(writeln!(&mut toc, "</div></div>"));
         }
 
index 92433589155ba91afce3db5b8c965cc8baccc1aa..65ba031a2d63488354ddf81c793b3d71ae0362fb 100644 (file)
@@ -45,7 +45,7 @@
 #page {
     margin-left: auto;
     margin-right:auto;
-    width: 750px;
+    max-width: 750px;
 }
 
 .chapter {
 .chapter li a {
     color: #000000;
 }
+
+@media only screen and (max-width: 1060px) {
+    #toc {
+        width: 100%;
+        margin-right: 0;
+        top: 40px;
+    }
+    #page-wrapper {
+        top: 40px;
+        left: 15px;
+        padding-right: 15px;
+    }
+    .mobile-hidden {
+        display: none;
+    }
+}
+
+
+#toggle-nav {
+    height: 20px;
+    width:  30px;
+    padding: 3px 3px 0 3px;
+}
+
+#toggle-nav {
+    margin-top: 5px;
+    width: 30px;
+    height: 30px;
+    background-color: #FFF;
+    border: 1px solid #666;
+    border-radius: 3px 3px 3px 3px;
+}
+
+.sr-only {
+    position: absolute;
+    width: 1px;
+    height: 1px;
+    margin: -1px;
+    padding: 0;
+    overflow: hidden;
+    clip: rect(0, 0, 0, 0);
+    border: 0;
+}
+
+.bar {
+    display: block;
+    background-color: #000;
+    border-radius: 2px;
+    width: 100%;
+    height: 2px;
+    margin: 2px 0 3px;
+    padding: 0;
+}
+
 "#;
diff --git a/src/rustbook/javascript.rs b/src/rustbook/javascript.rs
new file mode 100644 (file)
index 0000000..eb4401e
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2015 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 rust-book JavaScript in string form.
+
+pub static JAVASCRIPT: &'static str = r#"
+<script type="text/javascript">
+document.addEventListener("DOMContentLoaded", function(event) {
+  document.getElementById("toggle-nav").onclick = toggleNav;
+  function toggleNav() {
+    var toc = document.getElementById("toc");
+    var pagewrapper = document.getElementById("page-wrapper");
+    toggleClass(toc, "mobile-hidden");
+    toggleClass(pagewrapper, "mobile-hidden");
+  };
+
+  function toggleClass(el, className) {
+     // from http://youmightnotneedjquery.com/
+     if (el.classList) {
+       el.classList.toggle(className);
+     } else {
+       var classes = el.className.split(' ');
+       var existingIndex = classes.indexOf(className);
+
+       if (existingIndex >= 0) {
+         classes.splice(existingIndex, 1);
+       } else {
+         classes.push(className);
+       }
+
+       el.className = classes.join(' ');
+     }
+  }
+});
+</script>
+"#;
index 48dad14321a8d57db23e557f4716228980fba9f7..85b9a7d79dbfefc3bcca48eba8b10faee9ec4427 100644 (file)
@@ -39,6 +39,7 @@ macro_rules! try (
 mod test;
 
 mod css;
+mod javascript;
 
 #[cfg(not(test))] // thanks #12327
 fn main() {
index 2ac855681f28b9970b1b95e770552532a30149c5..4a16b9c257cbe953bb1edb192ba7ad43b49604c1 100644 (file)
@@ -1,4 +1,4 @@
 # If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
 # The actual contents of this file do not matter, but to trigger a change on the
 # build bots then the contents should be changed so git updates the mtime.
-2015-01-05
+2015-01-13
index 9eeb7ee88571ec50bdd98c0b91e906a99cf26933..e3e91e05f55e9197b5e23fe9facff88c17d2626e 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -16,7 +16,7 @@
 extern crate syntax;
 extern crate rustc;
 
-use syntax::ast::{TokenTree, Item, MetaItem};
+use syntax::ast::{TokenTree, Item, MetaItem, ImplItem, TraitItem, Method};
 use syntax::codemap::Span;
 use syntax::ext::base::*;
 use syntax::parse::token;
@@ -37,6 +37,9 @@ pub fn plugin_registrar(reg: &mut Registry) {
     reg.register_syntax_extension(
         token::intern("into_foo"),
         Modifier(box expand_into_foo));
+    reg.register_syntax_extension(
+        token::intern("into_multi_foo"),
+        MultiModifier(box expand_into_foo_multi));
 }
 
 fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
@@ -65,6 +68,30 @@ fn expand_into_foo(cx: &mut ExtCtxt, sp: Span, attr: &MetaItem, it: P<Item>)
     })
 }
 
+fn expand_into_foo_multi(cx: &mut ExtCtxt,
+                         sp: Span,
+                         attr: &MetaItem,
+                         it: Annotatable) -> Annotatable {
+    match it {
+        Annotatable::Item(it) => {
+            Annotatable::Item(P(Item {
+                attrs: it.attrs.clone(),
+                ..(*quote_item!(cx, enum Foo2 { Bar2, Baz2 }).unwrap()).clone()
+            }))
+        }
+        Annotatable::ImplItem(it) => {
+            Annotatable::ImplItem(ImplItem::MethodImplItem(
+                quote_method!(cx, fn foo(&self) -> i32 { 42 })
+            ))
+        }
+        Annotatable::TraitItem(it) => {
+            Annotatable::TraitItem(TraitItem::ProvidedMethod(
+                quote_method!(cx, fn foo(&self) -> i32 { 0 })
+            ))
+        }
+    }
+}
+
 fn expand_forged_ident(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult+'static> {
     use syntax::ext::quote::rt::*;
 
diff --git a/src/test/auxiliary/no_method_suggested_traits.rs b/src/test/auxiliary/no_method_suggested_traits.rs
new file mode 100644 (file)
index 0000000..3285614
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2015 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 use reexport::Reexported;
+
+pub mod foo {
+    pub trait PubPub {
+        fn method(&self) {}
+
+        fn method3(&self) {}
+    }
+
+    impl PubPub for u32 {}
+    impl PubPub for i32 {}
+}
+pub mod bar {
+    trait PubPriv {
+        fn method(&self);
+    }
+}
+mod qux {
+    pub trait PrivPub {
+        fn method(&self);
+    }
+}
+mod quz {
+    trait PrivPriv {
+        fn method(&self);
+    }
+}
+
+mod reexport {
+    pub trait Reexported {
+        fn method(&self);
+    }
+}
index 5a47f9fbc573a7f5ecbac739de55d877bdc9e402..9e5618579e40a5c520bec78e5974cf6bc9c3f129 100644 (file)
@@ -128,7 +128,7 @@ fn make(&mut self, n: uint) -> IoResult<()> {
         copy_memory(buf.as_mut_slice(), alu);
         let buf_len = buf.len();
         copy_memory(buf.slice_mut(alu_len, buf_len),
-                    &alu[0..LINE_LEN]);
+                    &alu[..LINE_LEN]);
 
         let mut pos = 0;
         let mut bytes;
@@ -204,7 +204,7 @@ fn make(&mut self, n: uint) -> IoResult<()> {
         for i in range(0u, chars_left) {
             buf[i] = self.nextc();
         }
-        self.out.write(&buf[0..chars_left])
+        self.out.write(&buf[..chars_left])
     }
 }
 
diff --git a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs
new file mode 100644 (file)
index 0000000..c9dfb82
--- /dev/null
@@ -0,0 +1,29 @@
+// 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(optin_builtin_traits)]
+
+trait MyTrait {}
+
+struct TestType<T>;
+
+unsafe impl<T: MyTrait> Send for TestType<T> {}
+//~^ ERROR conflicting implementations for trait `core::marker::Send`
+//~^^ ERROR conflicting implementations for trait `core::marker::Send`
+
+impl<T: MyTrait> !Send for TestType<T> {}
+//~^ ERROR conflicting implementations for trait `core::marker::Send`
+
+unsafe impl<T> Send for TestType<T> {}
+//~^ ERROR error: conflicting implementations for trait `core::marker::Send`
+
+impl !Send for TestType<i32> {}
+
+fn main() {}
diff --git a/src/test/compile-fail/coherence-impls-builtin.rs b/src/test/compile-fail/coherence-impls-builtin.rs
new file mode 100644 (file)
index 0000000..2ca288b
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2015 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::marker::Send;
+
+enum TestE {
+  A
+}
+
+struct MyType;
+
+unsafe impl Send for TestE {}
+unsafe impl Send for MyType {}
+unsafe impl Send for (MyType, MyType) {}
+//~^ ERROR builtin traits can only be implemented on structs or enums
+
+unsafe impl Send for &'static MyType {}
+//~^ ERROR builtin traits can only be implemented on structs or enums
+
+unsafe impl Send for [MyType] {}
+//~^ ERROR builtin traits can only be implemented on structs or enums
+
+unsafe impl Send for &'static [MyType] {}
+//~^ ERROR builtin traits can only be implemented on structs or enums
+
+fn is_send<T: Send>() {}
+
+fn main() {
+    is_send::<(MyType, TestE)>();
+}
diff --git a/src/test/compile-fail/coherence-negative-impls-safe.rs b/src/test/compile-fail/coherence-negative-impls-safe.rs
new file mode 100644 (file)
index 0000000..3b335d5
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 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(optin_builtin_traits)]
+
+use std::marker::Send;
+
+struct TestType;
+
+unsafe impl !Send for TestType {}
+//~^ ERROR negative implementations are not unsafe
+
+fn main() {}
index 0bd0224b246d1503fff6b5fbcf97274a2f0ff9d3..f9f965e1ae39dc2a5a6ae78adb18c119f9b98b80 100644 (file)
@@ -8,8 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-tidy-linelength
 // aux-build:coherence-orphan-lib.rs
 
+#![feature(optin_builtin_traits)]
+
 extern crate "coherence-orphan-lib" as lib;
 
 use lib::TheTrait;
@@ -22,4 +25,7 @@ impl TheTrait<TheType> for isize { } //~ ERROR E0117
 
 impl TheTrait<isize> for TheType { }
 
+impl !Send for Vec<isize> { } //~ ERROR E0117
+//~^ ERROR conflicting
+
 fn main() { }
index 3d8ebc1ecdf19e517bb197f93fe36bbece65ca47..22ba54fea14694f86c9dd2594698c5a395c46cdd 100644 (file)
@@ -20,8 +20,7 @@ struct X { data: u32 }
 
 impl Something for X {
     fn yay<T: Str>(_:Option<X>, thing: &[T]) {
-//~^ ERROR in method `yay`, type parameter 0 requires bound `Str`, which is not required
-
+    //~^ ERROR the requirement `T : Str` appears on the impl method
     }
 }
 
index 394a9cc69bee7d28126821544a892c4e930d3017..fa8035a79652ea27a1c7f8e67aad9d47562b6bad 100644 (file)
@@ -8,12 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::marker;
+#![feature(optin_builtin_traits)]
 
-struct Foo { marker: marker::NoSync }
+use std::marker::Sync;
+
+struct Foo;
+impl !Sync for Foo {}
 
 static FOO: usize = 3;
-static BAR: Foo = Foo { marker: marker::NoSync };
+static BAR: Foo = Foo;
 //~^ ERROR: the trait `core::marker::Sync` is not implemented
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-20831-debruijn.rs b/src/test/compile-fail/issue-20831-debruijn.rs
new file mode 100644 (file)
index 0000000..aaf45f2
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2015 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.
+
+// Regression test for #20831: debruijn index account was thrown off
+// by the (anonymous) lifetime in `<Self as Publisher>::Output`
+// below. Note that changing to a named lifetime made the problem go
+// away.
+
+use std::ops::{Shl, Shr};
+use std::cell::RefCell;
+
+pub trait Subscriber {
+    type Input;
+}
+
+pub trait Publisher<'a> {
+    type Output;
+    fn subscribe(&mut self, Box<Subscriber<Input=Self::Output> + 'a>);
+}
+
+pub trait Processor<'a> : Subscriber + Publisher<'a> { }
+
+impl<'a, P> Processor<'a> for P where P : Subscriber + Publisher<'a> { }
+
+struct MyStruct<'a> {
+    sub: Box<Subscriber<Input=u64> + 'a>
+}
+
+impl<'a> Publisher<'a> for MyStruct<'a> {
+    type Output = u64;
+    fn subscribe(&mut self, t : Box<Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
+        // Not obvious, but there is an implicit lifetime here -------^
+        //~^^ ERROR cannot infer
+        //
+        // The fact that `Publisher` is using an implicit lifetime is
+        // what was causing the debruijn accounting to be off, so
+        // leave it that way!
+        self.sub = t;
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-21045.rs b/src/test/compile-fail/issue-21045.rs
new file mode 100644 (file)
index 0000000..134240f
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![feature(asm)]
+
+fn main() {
+    let a;
+    asm!("nop" "nop"); //~ ERROR malformed inline assembly
+    asm!("nop" "nop" : "=r"(a)); //~ ERROR malformed inline assembly
+}
diff --git a/src/test/compile-fail/issue-21160.rs b/src/test/compile-fail/issue-21160.rs
new file mode 100644 (file)
index 0000000..0ee3816
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2015 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 Bar;
+
+impl Bar {
+    fn hash<T>(&self, _: T) {}
+}
+
+#[derive(Hash)]
+struct Foo(Bar);
+//~^ error: the trait `core::hash::Hash<__S>` is not implemented for the type `Bar`
+
+fn main() {}
index b141c1f441aeb436f08313a42b7d308d8ab7508a..31796e5e20c4492e683642701852db9bc439bfdf 100644 (file)
@@ -20,7 +20,8 @@ struct E {
 }
 
 impl A for E {
-  fn b<F: Sync, G>(_x: F) -> F { panic!() } //~ ERROR type parameter 0 requires `Sync`
+    fn b<F: Sync, G>(_x: F) -> F { panic!() }
+    //~^ ERROR `F : core::marker::Sync` appears on the impl method
 }
 
 fn main() {}
index d246e4e54d017501a122ba54f39f523e868a99d3..90ecfb6015dcd4a3a672caee67d558c80fabed83 100644 (file)
@@ -35,5 +35,4 @@ struct A {
 fn main() {
     let a = A {v: box B{v: None} as Box<Foo+Send>};
     //~^ ERROR the trait `core::marker::Send` is not implemented
-    //~^^ ERROR the trait `core::marker::Send` is not implemented
 }
index 79aec386d9a77c7f16f1ee61540abc0ea6aaaf32..5bc769f8e117b62e452e9d691fcce54c3e8f577a 100644 (file)
@@ -19,6 +19,5 @@ fn main() {
     let x = Rc::new(3us);
     bar(move|| foo(x));
     //~^ ERROR `core::marker::Send` is not implemented
-    //~^^ ERROR `core::marker::Send` is not implemented
 }
 
diff --git a/src/test/compile-fail/marker-no-send.rs b/src/test/compile-fail/marker-no-send.rs
deleted file mode 100644 (file)
index 032718d..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::marker;
-
-fn foo<P:Send>(p: P) { }
-
-fn main()
-{
-    foo(marker::NoSend); //~ ERROR the trait `core::marker::Send` is not implemented
-}
diff --git a/src/test/compile-fail/marker-no-share.rs b/src/test/compile-fail/marker-no-share.rs
deleted file mode 100644 (file)
index b29f7fa..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::marker;
-
-fn foo<P: Sync>(p: P) { }
-
-fn main()
-{
-    foo(marker::NoSync); //~ ERROR the trait `core::marker::Sync` is not implemented
-}
index f90bb610d374178c87c5b27d0243ccf97f6fb8fc..1657d602e24c485de42a3591d5006b92899e49fc 100644 (file)
 // Tests that an `&` pointer to something inherently mutable is itself
 // to be considered mutable.
 
-use std::marker;
+#![feature(optin_builtin_traits)]
 
-enum Foo { A(marker::NoSync) }
+use std::marker::Sync;
+
+struct NoSync;
+impl !Sync for NoSync {}
+
+enum Foo { A(NoSync) }
 
 fn bar<T: Sync>(_: T) {}
 
 fn main() {
-    let x = Foo::A(marker::NoSync);
+    let x = Foo::A(NoSync);
     bar(&x); //~ ERROR the trait `core::marker::Sync` is not implemented
 }
diff --git a/src/test/compile-fail/no-method-suggested-traits.rs b/src/test/compile-fail/no-method-suggested-traits.rs
new file mode 100644 (file)
index 0000000..2778007
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2015 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.
+
+// aux-build:no_method_suggested_traits.rs
+
+extern crate no_method_suggested_traits;
+
+mod foo {
+    trait Bar {
+        fn method(&self) {}
+
+        fn method2(&self) {}
+    }
+
+    impl Bar for u32 {}
+
+    impl Bar for char {}
+}
+
+fn main() {
+    1u32.method();
+    //~^ ERROR does not implement
+    //~^^ HELP the following traits are implemented and define a method `method`
+    //~^^^ HELP `foo::Bar`
+    //~^^^^ HELP `no_method_suggested_traits::foo::PubPub`
+
+    'a'.method();
+    //~^ ERROR does not implement
+    //~^^ HELP the following trait is implemented and defines a method `method`
+    //~^^^ HELP `foo::Bar`
+
+    1i32.method();
+    //~^ ERROR does not implement
+    //~^^ HELP the following trait is implemented and defines a method `method`
+    //~^^^ HELP `no_method_suggested_traits::foo::PubPub`
+
+    1u64.method();
+    //~^ ERROR does not implement
+    //~^^ HELP the following traits define a method `method`
+    //~^^^ HELP `foo::Bar`
+    //~^^^^ HELP `no_method_suggested_traits::foo::PubPub`
+    //~^^^^^ HELP `no_method_suggested_traits::reexport::Reexported`
+    //~^^^^^^ HELP `no_method_suggested_traits::bar::PubPriv`
+    //~^^^^^^^ HELP `no_method_suggested_traits::qux::PrivPub`
+    //~^^^^^^^^ HELP `no_method_suggested_traits::quz::PrivPriv`
+
+    1u64.method2();
+    //~^ ERROR does not implement
+    //~^^ HELP the following trait defines a method `method2`
+    //~^^^ HELP `foo::Bar`
+    1u64.method3();
+    //~^ ERROR does not implement
+    //~^^ HELP the following trait defines a method `method3`
+    //~^^^ HELP `no_method_suggested_traits::foo::PubPub`
+}
index 551953af13520e724db3bdc3dd4856f77b133217..52335ab76bda23abd042a9f09bc4e1997d70dd39 100644 (file)
@@ -37,7 +37,6 @@ fn foo(x: Port<()>) -> foo {
 
     Thread::spawn(move|| {
         //~^ ERROR `core::marker::Send` is not implemented
-        //~^^ ERROR `core::marker::Send` is not implemented
         let y = x;
         println!("{:?}", y);
     });
index cf1f13e8bb8683d1eb28f312518b7495dacea205..625d51260c4dcc4375d6704da1a11ce35adacc6b 100644 (file)
@@ -8,16 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::marker;
+#![feature(optin_builtin_traits)]
+
+use std::marker::Send;
+
+struct NoSend;
+impl !Send for NoSend {}
 
 enum Foo {
-    A(marker::NoSend)
+    A(NoSend)
 }
 
 fn bar<T: Send>(_: T) {}
 
 fn main() {
-    let x = Foo::A(marker::NoSend);
+    let x = Foo::A(NoSend);
     bar(x);
     //~^ ERROR `core::marker::Send` is not implemented
 }
index 82cc319466a6d8f3c1ea32b422a89f583b16cff1..d404988bd9848cb79a2a70fc53c1d4a8a576dc4e 100644 (file)
@@ -16,5 +16,4 @@ fn main() {
     let x = Rc::new(5is);
     bar(x);
     //~^ ERROR `core::marker::Send` is not implemented
-    //~^^ ERROR `core::marker::Send` is not implemented
 }
index bef705237872625bf3ab48c52963b119df09d1ed..7f16db0ba947be19ea11269408e9f2a68458763b 100644 (file)
@@ -8,17 +8,20 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::marker;
+#![feature(optin_builtin_traits)]
+
+use std::marker::Send;
 
 struct Foo {
     a: isize,
-    ns: marker::NoSend
 }
 
+impl !Send for Foo {}
+
 fn bar<T: Send>(_: T) {}
 
 fn main() {
-    let x = Foo { a: 5, ns: marker::NoSend };
+    let x = Foo { a: 5 };
     bar(x);
     //~^ ERROR the trait `core::marker::Send` is not implemented
 }
index 33222eef44e74122765b3251a237fd5bf9dd1239..9331afdbbb5d7d792a150e4cf128a9c635f182f5 100644 (file)
@@ -8,14 +8,19 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::marker;
+#![feature(optin_builtin_traits)]
 
-enum Foo { A(marker::NoSync) }
+use std::marker::Sync;
+
+struct NoSync;
+impl !Sync for NoSync {}
+
+enum Foo { A(NoSync) }
 
 fn bar<T: Sync>(_: T) {}
 
 fn main() {
-    let x = Foo::A(marker::NoSync);
+    let x = Foo::A(NoSync);
     bar(x);
     //~^ ERROR the trait `core::marker::Sync` is not implemented
 }
index 0d3e380d4a1224c9efb82923104b2dbaada12fa4..4917db602e175f1fc6aabef3102ad0d2de792a7c 100644 (file)
@@ -17,5 +17,4 @@ fn main() {
     let x = Rc::new(RefCell::new(5is));
     bar(x);
     //~^ ERROR the trait `core::marker::Sync` is not implemented
-    //~^^ ERROR the trait `core::marker::Sync` is not implemented
 }
index c7028ce9786982852322229e3ac98213d583763d..b5ccceb3b2a7d9ec72bc6fc286af790ff6e9cd8a 100644 (file)
@@ -8,14 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::marker;
+#![feature(optin_builtin_traits)]
 
-struct Foo { a: isize, m: marker::NoSync }
+use std::marker::Sync;
+
+struct Foo { a: isize }
+impl !Sync for Foo {}
 
 fn bar<T: Sync>(_: T) {}
 
 fn main() {
-    let x = Foo { a: 5, m: marker::NoSync };
+    let x = Foo { a: 5 };
     bar(x);
     //~^ ERROR the trait `core::marker::Sync` is not implemented
 }
diff --git a/src/test/compile-fail/obsolete-tilde.rs b/src/test/compile-fail/obsolete-tilde.rs
deleted file mode 100644 (file)
index d290d55..0000000
+++ /dev/null
@@ -1,21 +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.
-
-// Test that ~ pointers give an obsolescence message.
-
-fn foo(x: ~isize) {} //~ ERROR obsolete syntax: `~` notation for owned pointers
-fn bar(x: ~str) {} //~ ERROR obsolete syntax: `~` notation for owned pointers
-fn baz(x: ~[isize]) {} //~ ERROR obsolete syntax: `~[T]` is no longer a type
-
-fn main() {
-    let x = ~4is; //~ ERROR obsolete syntax: `~` notation for owned pointer allocation
-    let y = ~"hello"; //~ ERROR obsolete syntax: `~` notation for owned pointer allocation
-    let z = ~[1is, 2, 3]; //~ ERROR obsolete syntax: `~[T]` is no longer a type
-}
diff --git a/src/test/compile-fail/obsolete-tuple-struct-deref.rs b/src/test/compile-fail/obsolete-tuple-struct-deref.rs
deleted file mode 100644 (file)
index ad5fac3..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
-    struct S(isize);
-    let s = S(0);
-    let x = *s; //~ ERROR single-field tuple-structs can no longer be dereferenced
-}
index 5028ec8997261c6c2de76cc36ff87e33df9053ab..a3c38dff6b0f62f73275240d21286e2a1fdcc758 100644 (file)
@@ -16,15 +16,16 @@ struct Inv<'a> { // invariant w/r/t 'a
     x: &'a mut &'a isize
 }
 
-pub trait Foo<'a> {
+pub trait Foo<'a, 't> {
     fn no_bound<'b>(self, b: Inv<'b>);
     fn has_bound<'b:'a>(self, b: Inv<'b>);
     fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
-    fn wrong_bound2<'b,'c,'d:'a+'b+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+    fn okay_bound<'b,'c,'d:'a+'b+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+    fn another_bound<'x: 'a>(self, x: Inv<'x>);
 }
 
 
-impl<'a> Foo<'a> for &'a isize {
+impl<'a, 't> Foo<'a, 't> for &'a isize {
     fn no_bound<'b:'a>(self, b: Inv<'b>) {
         //~^ ERROR lifetime parameters or bounds on method `no_bound` do not match
     }
@@ -47,9 +48,10 @@ fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
         // cases.
     }
 
-    fn wrong_bound2<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
-        //~^ ERROR distinct set of bounds from its counterpart
+    fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
     }
+
+    fn another_bound<'x: 't>(self, x: Inv<'x>) {}
 }
 
 fn main() { }
index fe31d81983e16ad137adefe4a8ecafda3c21b28c..dc3385f4bb92f38e7366800fa15f31dc6f1291ca 100644 (file)
@@ -17,5 +17,4 @@ fn test_send<S: Send>() {}
 pub fn main() {
     test_send::<rand::ThreadRng>();
     //~^ ERROR `core::marker::Send` is not implemented
-    //~^^ ERROR `core::marker::Send` is not implemented
 }
index 5fc80d5660d04cd1c722b30eb20f667fc0061d7b..477bd4f5be9a1a8a942acc1fd2b625b82c1fb5c6 100644 (file)
@@ -32,15 +32,15 @@ trait Foo {
 impl Foo for isize {
     // invalid bound for T, was defined as Eq in trait
     fn test_error1_fn<T: Ord>(&self) {}
-    //~^ ERROR in method `test_error1_fn`, type parameter 0 requires bound `core::cmp::Ord`
+    //~^ ERROR the requirement `T : core::cmp::Ord` appears on the impl
 
     // invalid bound for T, was defined as Eq + Ord in trait
     fn test_error2_fn<T: Eq + B>(&self) {}
-    //~^ ERROR in method `test_error2_fn`, type parameter 0 requires bound `B`
+    //~^ ERROR the requirement `T : B` appears on the impl
 
     // invalid bound for T, was defined as Eq + Ord in trait
     fn test_error3_fn<T: B + Eq>(&self) {}
-    //~^ ERROR in method `test_error3_fn`, type parameter 0 requires bound `B`
+    //~^ ERROR the requirement `T : B` appears on the impl
 
     // multiple bounds, same order as in trait
     fn test3_fn<T: Ord + Eq>(&self) {}
@@ -50,16 +50,16 @@ fn test4_fn<T: Eq + Ord>(&self) {}
 
     // parameters in impls must be equal or more general than in the defining trait
     fn test_error5_fn<T: B>(&self) {}
-    //~^ ERROR in method `test_error5_fn`, type parameter 0 requires bound `B`
+    //~^ ERROR the requirement `T : B` appears on the impl
 
     // bound `std::cmp::Eq` not enforced by this implementation, but this is OK
     fn test6_fn<T: A>(&self) {}
 
     fn test_error7_fn<T: A + Eq>(&self) {}
-    //~^ ERROR in method `test_error7_fn`, type parameter 0 requires bound `core::cmp::Eq`
+    //~^ ERROR the requirement `T : core::cmp::Eq` appears on the impl
 
     fn test_error8_fn<T: C>(&self) {}
-    //~^ ERROR in method `test_error8_fn`, type parameter 0 requires bound `C`
+    //~^ ERROR the requirement `T : C` appears on the impl
 }
 
 
@@ -71,8 +71,7 @@ trait Trait {
 
 impl Trait for usize {
     fn method<G: Getter<usize>>() {}
-    //~^ ERROR in method `method`, type parameter 0 requires bound `Getter<usize>`
+    //~^ G : Getter<usize>` appears on the impl method but not on the corresponding trait method
 }
 
 fn main() {}
-
index a970a86408e90ad379aaeb31d8505037dc87691d..8ad19116e7bb13ba2b11af89f5121e45441c9949 100644 (file)
@@ -20,7 +20,7 @@ trait IteratorUtil<A> {
 
 impl<A, T: Iterator<A>> IteratorUtil<A> for T {
     fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<T, U> {
-    //~^ ERROR in method `zip`, type parameter 1 requires bound `Iterator<B>`
+    //~^ ERROR the requirement `U : Iterator<B>` appears on the impl method
         ZipIterator{a: self, b: other}
     }
 }
diff --git a/src/test/compile-fail/traits-negative-impls.rs b/src/test/compile-fail/traits-negative-impls.rs
new file mode 100644 (file)
index 0000000..3ef7600
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2015 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 dummy functions are used to avoid adding new cfail files.
+// What happens is that the compiler attempts to squash duplicates and some
+// errors are not reported. This way, we make sure that, for each function, different
+// typeck phases are involved and all errors are reported.
+
+#![feature(optin_builtin_traits)]
+
+use std::marker::Send;
+
+struct Outer<T: Send>(T);
+
+struct TestType;
+impl !Send for TestType {}
+
+struct Outer2<T>(T);
+
+unsafe impl<T: Send> Sync for Outer2<T> {}
+
+fn is_send<T: Send>(_: T) {}
+fn is_sync<T: Sync>(_: T) {}
+
+fn dummy() {
+    Outer(TestType);
+    //~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
+
+    is_send(TestType);
+    //~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
+
+    is_send((8, TestType));
+    //~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
+}
+
+fn dummy2() {
+    is_send(Box::new(TestType));
+    //~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
+}
+
+fn dummy3() {
+    is_send(Box::new(Outer2(TestType)));
+    //~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
+}
+
+fn main() {
+    // This will complain about a missing Send impl because `Sync` is implement *just*
+    // for T that are `Send`. Look at #20366 and #19950
+    is_sync(Outer2(TestType));
+    //~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
+}
diff --git a/src/test/compile-fail/typeck-negative-impls-builtin.rs b/src/test/compile-fail/typeck-negative-impls-builtin.rs
new file mode 100644 (file)
index 0000000..9da79b1
--- /dev/null
@@ -0,0 +1,20 @@
+// 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(optin_builtin_traits)]
+
+struct TestType;
+
+trait TestTrait {}
+
+impl !TestTrait for TestType {}
+//~^ ERROR  negative impls are currently allowed just for `Send` and `Sync`
+
+fn main() {}
index a9113c6e99f43fa780b0b2f320dccc72df95c2fb..38e3b57634838460e9036bc8e989dd54440f717d 100644 (file)
 
 // Verify that UnsafeCell is *always* sync regardless if `T` is sync.
 
-// ignore-tidy-linelength
+#![feature(optin_builtin_traits)]
 
 use std::cell::UnsafeCell;
-use std::marker;
+use std::marker::Sync;
 
 struct MySync<T> {
     u: UnsafeCell<T>
 }
 
-struct NoSync {
-    m: marker::NoSync
-}
-
-fn test<T: Sync>(s: T){
+struct NoSync;
+impl !Sync for NoSync {}
 
-}
+fn test<T: Sync>(s: T) {}
 
 fn main() {
     let us = UnsafeCell::new(MySync{u: UnsafeCell::new(0is)});
     test(us);
     //~^ ERROR `core::marker::Sync` is not implemented
 
-    let uns = UnsafeCell::new(NoSync{m: marker::NoSync});
+    let uns = UnsafeCell::new(NoSync);
     test(uns);
     //~^ ERROR `core::marker::Sync` is not implemented
 
@@ -40,7 +37,6 @@ fn main() {
     test(ms);
     //~^ ERROR `core::marker::Sync` is not implemented
 
-    let ns = NoSync{m: marker::NoSync};
-    test(ns);
+    test(NoSync);
     //~^ ERROR `core::marker::Sync` is not implemented
 }
diff --git a/src/test/compile-fail/ufcs-qpath-missing-params.rs b/src/test/compile-fail/ufcs-qpath-missing-params.rs
new file mode 100644 (file)
index 0000000..5fa66eb
--- /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.
+
+use std::borrow::IntoCow;
+
+fn main() {
+    <String as IntoCow>::into_cow("foo".to_string());
+    //~^ ERROR wrong number of type arguments: expected 2, found 0
+}
+
diff --git a/src/test/compile-fail/ufcs-qpath-self-mismatch.rs b/src/test/compile-fail/ufcs-qpath-self-mismatch.rs
new file mode 100644 (file)
index 0000000..868c1ea
--- /dev/null
@@ -0,0 +1,21 @@
+// 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::ops::Add;
+
+fn main() {
+    <i32 as Add<u32>>::add(1, 2);
+    //~^ ERROR the trait `core::ops::Add<u32>` is not implemented for the type `i32`
+    <i32 as Add<i32>>::add(1u32, 2);
+    //~^ ERROR mismatched types
+    <i32 as Add<i32>>::add(1, 2u32);
+    //~^ ERROR mismatched types
+}
+
index 4b7f11b05609ceb2c162fd4ebe4a12cf2c4b8335..322de45daf03e8e17881af8bfed703ad42dd395b 100644 (file)
@@ -19,5 +19,4 @@ fn main() {
     let i = box Rc::new(100is);
     f(i);
     //~^ ERROR `core::marker::Send` is not implemented
-    //~^^ ERROR `core::marker::Send` is not implemented
 }
index abd93fdfc6c61c5f34c00755f64ef86b508a8dd1..f51eee379347c2e40c8c088b22c19bd29d598032 100644 (file)
@@ -31,6 +31,5 @@ fn main() {
   let cat = "kitty".to_string();
   let (tx, _) = channel();
   //~^ ERROR `core::marker::Send` is not implemented
-  //~^^ ERROR `core::marker::Send` is not implemented
   tx.send(foo(42, Rc::new(cat)));
 }
diff --git a/src/test/compile-fail/vec-matching-obsolete-syntax.rs b/src/test/compile-fail/vec-matching-obsolete-syntax.rs
deleted file mode 100644 (file)
index 2715b31..0000000
+++ /dev/null
@@ -1,22 +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.
-
-fn main() {
-    let x = [1is, 2, 3];
-    match x {
-        [a, b, ..c] => {    //~ ERROR obsolete syntax
-            assert_eq!(a, 1);
-            assert_eq!(b, 2);
-            let expected: &[_] = &[3];
-            assert_eq!(c, expected);
-        }
-    }
-}
-
index 35889ff81335c04b9789447e487988d583d27a66..00de4497cedbf0ee2e7e88438a350dc0b4f79372 100644 (file)
@@ -48,7 +48,11 @@ fn zzz() {()}
 fn some_function(a: int, b: int) {
     let some_variable = Struct { a: 11, b: 22 };
     let some_other_variable = 23i;
-    zzz(); // #break
+
+    for x in range(0, 1) {
+        zzz(); // #break
+    }
 }
 
 fn some_other_function(a: int, b: int) -> bool { true }
+
index 47c36ac7a40de711c103ced414ed555e6ebe6588..7d3a921301e342a97f1279b3d96240ea2483eee0 100644 (file)
 
 // pp-exact
 
-trait UnsafeTrait {
-    fn foo(&self);
-}
+struct Test;
 
-impl !UnsafeTrait for int {
-    fn foo(&self) { }
-}
+impl !Send for Test { }
 
 pub fn main() { }
diff --git a/src/test/run-make/compiler-lookup-paths-2/Makefile b/src/test/run-make/compiler-lookup-paths-2/Makefile
new file mode 100644 (file)
index 0000000..bd7f62d
--- /dev/null
@@ -0,0 +1,8 @@
+-include ../tools.mk
+
+all:
+       mkdir -p $(TMPDIR)/a $(TMPDIR)/b
+       $(RUSTC) a.rs && mv $(TMPDIR)/liba.rlib $(TMPDIR)/a
+       $(RUSTC) b.rs -L $(TMPDIR)/a && mv $(TMPDIR)/libb.rlib $(TMPDIR)/b
+       $(RUSTC) c.rs -L crate=$(TMPDIR)/b -L dependency=$(TMPDIR)/a \
+               && exit 1 || exit 0
diff --git a/src/test/run-make/compiler-lookup-paths-2/a.rs b/src/test/run-make/compiler-lookup-paths-2/a.rs
new file mode 100644 (file)
index 0000000..e7572a5
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "lib"]
diff --git a/src/test/run-make/compiler-lookup-paths-2/b.rs b/src/test/run-make/compiler-lookup-paths-2/b.rs
new file mode 100644 (file)
index 0000000..fee0da9
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "lib"]
+extern crate a;
diff --git a/src/test/run-make/compiler-lookup-paths-2/c.rs b/src/test/run-make/compiler-lookup-paths-2/c.rs
new file mode 100644 (file)
index 0000000..66fe51d
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "lib"]
+extern crate b;
+extern crate a;
index 9b86bf9754956eea9a883510df3604c506923956..049b76c1b648a7514625fa2e8adead8fd8004150 100644 (file)
@@ -17,8 +17,10 @@ all:
        $(RUSTC) -C metadata=2 -C extra-filename=-2 a.rs
        $(RUSTC) b.rs --extern a=$(TMPDIR)/liba-1.rlib
        $(RUSTC) c.rs --extern a=$(TMPDIR)/liba-2.rlib
+       @echo before
        $(RUSTC) --cfg before d.rs --extern a=$(TMPDIR)/liba-1.rlib
        $(call RUN,d)
+       @echo after
        $(RUSTC) --cfg after  d.rs --extern a=$(TMPDIR)/liba-1.rlib
        $(call RUN,d)
 
index 11b9ba6fce3383fd5e2162076b56854feeba83a6..ac92aede7894f72083fef91889efeaa00e8195a9 100644 (file)
@@ -11,6 +11,6 @@
 #![crate_name = "a"]
 #![crate_type = "rlib"]
 
-static FOO: uint = 3;
+static FOO: usize = 3;
 
-pub fn token() -> &'static uint { &FOO }
+pub fn token() -> &'static usize { &FOO }
index 3156cf0ba7275a0f99ee4d1f0b0625f89c7624ea..8ae238f5a482c2f1a063b2ac825097f842724883 100644 (file)
@@ -13,7 +13,7 @@
 
 extern crate a;
 
-static FOO: uint = 3;
+static FOO: usize = 3;
 
-pub fn token() -> &'static uint { &FOO }
-pub fn a_token() -> &'static uint { a::token() }
+pub fn token() -> &'static usize { &FOO }
+pub fn a_token() -> &'static usize { a::token() }
index d3bbc762ef2f360e464ac5506e5b12e1c642e2be..6eccdf7e5c857b28b0cded71213ca98895b81747 100644 (file)
@@ -13,7 +13,7 @@
 
 extern crate a;
 
-static FOO: uint = 3;
+static FOO: usize = 3;
 
-pub fn token() -> &'static uint { &FOO }
-pub fn a_token() -> &'static uint { a::token() }
+pub fn token() -> &'static usize { &FOO }
+pub fn a_token() -> &'static usize { a::token() }
index d850daffc39414ce661b238d61f32eb1fa907d3f..90e1330d4ae472c8b6121704dbce97672bc3a1dc 100644 (file)
@@ -13,7 +13,7 @@
 extern crate c;
 #[cfg(after)] extern crate a;
 
-fn t(a: &'static uint) -> uint { a as *const _ as uint }
+fn t(a: &'static usize) -> usize { a as *const _ as usize }
 
 fn main() {
     assert!(t(a::token()) == t(b::a_token()));
index 0562e000e56e94beaf95079f8f6b5a35fc0dec70..4ac8cb7ae1da7e929d624c0076fc657f4f493c81 100644 (file)
@@ -28,7 +28,7 @@ $(TMPDIR)/%.pp: %.rs
 
 $(TMPDIR)/%.dot: %.rs
        $(eval $(call FIND_LAST_BLOCK,$<))
-       $(RUSTC_LIB) -Z unstable-options --xpretty flowgraph=$(LASTBLOCKNUM_$<) $< -o $@.tmp
+       $(RUSTC_LIB) -Z unstable-options --xpretty flowgraph,unlabelled=$(LASTBLOCKNUM_$<) $< -o $@.tmp
        cat $@.tmp | sed -e 's@ (id=[0-9]*)@@g' \
                          -e 's@\[label=""\]@@' \
                          -e 's@digraph [a-zA-Z0-9_]* @digraph block @' \
index e9cd07c0356f89b1329be12def22a2abf723ea11..12b16cc9f8ce8eabf3e7d70b5196bce50443a73a 100644 (file)
@@ -34,7 +34,7 @@ digraph block {
     N11 -> N12;
     N12 -> N13;
     N13 -> N14;
-    N14 -> N6[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 2is { break ; \"unreachable\"; },\lexiting scope_4 block { x -= 1is; if x == 2is { break ; \"unreachable\"; } }"];
+    N14 -> N6;
     N15 -> N16;
     N16 -> N17;
     N17 -> N18;
index 7b01c606083ff1d602f978a13a11b8a88911323b..47e9b3f6cbe1ad09884baa88f6b6021ab90b1da3 100644 (file)
@@ -61,7 +61,7 @@ digraph block {
     N12 -> N13;
     N13 -> N14;
     N14 -> N15;
-    N15 -> N9[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1is { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1is { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1is { break \'outer ; \"unreachable\"; }\l    if y >= 2is { break ; \"unreachable\"; }\l    y -= 3is;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1is { break \'outer ; \"unreachable\"; }\l        if y >= 2is { break ; \"unreachable\"; }\l        y -= 3is;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1is { break \'outer ; \"unreachable\"; }\l        if y >= 2is { break ; \"unreachable\"; }\l        y -= 3is;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1is { break \'outer ; \"unreachable\"; }\l            if y >= 2is { break ; \"unreachable\"; }\l            y -= 3is;\l        }\l    y -= 4is;\l    x -= 5is;\l}\l"];
+    N15 -> N9;
     N16 -> N17;
     N17 -> N18;
     N18 -> N19;
@@ -73,7 +73,7 @@ digraph block {
     N23 -> N24;
     N24 -> N25;
     N25 -> N26;
-    N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 2is { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 2is { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1is { break \'outer ; \"unreachable\"; }\l    if y >= 2is { break ; \"unreachable\"; }\l    y -= 3is;\l}\l"];
+    N26 -> N11;
     N27 -> N28;
     N28 -> N29;
     N29 -> N30;
index 2123185a083869415ef98d716fa46d6f5decb85e..a37869b2264986e01995827de48d1a2d0e7fab06 100644 (file)
@@ -64,7 +64,7 @@ digraph block {
     N12 -> N13;
     N13 -> N14;
     N14 -> N15;
-    N15 -> N8[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1is { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1is { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1is { continue \'outer ; \"unreachable\"; }\l    if y >= 1is { break ; \"unreachable\"; }\l    y -= 1is;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1is { continue \'outer ; \"unreachable\"; }\l        if y >= 1is { break ; \"unreachable\"; }\l        y -= 1is;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1is { continue \'outer ; \"unreachable\"; }\l        if y >= 1is { break ; \"unreachable\"; }\l        y -= 1is;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1is { continue \'outer ; \"unreachable\"; }\l            if y >= 1is { break ; \"unreachable\"; }\l            y -= 1is;\l        }\l    y -= 1is;\l    x -= 1is;\l}\l"];
+    N15 -> N8;
     N16 -> N17;
     N17 -> N18;
     N18 -> N19;
@@ -76,7 +76,7 @@ digraph block {
     N23 -> N24;
     N24 -> N25;
     N25 -> N26;
-    N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 1is { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 1is { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1is { continue \'outer ; \"unreachable\"; }\l    if y >= 1is { break ; \"unreachable\"; }\l    y -= 1is;\l}\l"];
+    N26 -> N11;
     N27 -> N28;
     N28 -> N29;
     N29 -> N30;
index e7a2cf2ff732f97e8d800858207ccf8f3f273b85..46f1634416e5b8a0dddbf544c96cec6c3d7b6a5a 100644 (file)
@@ -59,7 +59,7 @@ digraph block {
     N12 -> N13;
     N13 -> N14;
     N14 -> N15;
-    N15 -> N9[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1is { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1is { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1is { break \'outer ; \"unreachable\"; }\l    if y >= 2is { return; \"unreachable\"; }\l    y -= 3is;\l    x -= 5is;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1is { break \'outer ; \"unreachable\"; }\l        if y >= 2is { return; \"unreachable\"; }\l        y -= 3is;\l        x -= 5is;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1is { break \'outer ; \"unreachable\"; }\l        if y >= 2is { return; \"unreachable\"; }\l        y -= 3is;\l        x -= 5is;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1is { break \'outer ; \"unreachable\"; }\l            if y >= 2is { return; \"unreachable\"; }\l            y -= 3is;\l            x -= 5is;\l        }\l    \"unreachable\";\l}\l"];
+    N15 -> N9;
     N16 -> N17;
     N17 -> N18;
     N18 -> N19;
@@ -71,7 +71,7 @@ digraph block {
     N23 -> N24;
     N24 -> N25;
     N25 -> N26;
-    N26 -> N1[label="exiting scope_0 expr \'inner:\l    loop  {\l        if x == 1is { break \'outer ; \"unreachable\"; }\l        if y >= 2is { return; \"unreachable\"; }\l        y -= 3is;\l        x -= 5is;\l    }\l,\lexiting scope_1 expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1is { break \'outer ; \"unreachable\"; }\l                if y >= 2is { return; \"unreachable\"; }\l                y -= 3is;\l                x -= 5is;\l            }\l        \"unreachable\";\l    }\l"];
+    N26 -> N1;
     N27 -> N28;
     N28 -> N29;
     N29 -> N30;
index edd39b40b36a3a7b13df891ed2a585d7e88259eb..3f35a9b0f9ab3b782a38df6c54c22d14e4461be4 100644 (file)
@@ -62,7 +62,7 @@ digraph block {
     N12 -> N13;
     N13 -> N14;
     N14 -> N15;
-    N15 -> N8[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1is { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1is { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1is { continue \'outer ; \"unreachable\"; }\l    if y >= 2is { return; \"unreachable\"; }\l    x -= 1is;\l    y -= 3is;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1is { continue \'outer ; \"unreachable\"; }\l        if y >= 2is { return; \"unreachable\"; }\l        x -= 1is;\l        y -= 3is;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1is { continue \'outer ; \"unreachable\"; }\l        if y >= 2is { return; \"unreachable\"; }\l        x -= 1is;\l        y -= 3is;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1is { continue \'outer ; \"unreachable\"; }\l            if y >= 2is { return; \"unreachable\"; }\l            x -= 1is;\l            y -= 3is;\l        }\l    \"unreachable\";\l}\l"];
+    N15 -> N8;
     N16 -> N17;
     N17 -> N18;
     N18 -> N19;
@@ -74,7 +74,7 @@ digraph block {
     N23 -> N24;
     N24 -> N25;
     N25 -> N26;
-    N26 -> N1[label="exiting scope_0 expr \'inner:\l    loop  {\l        if x == 1is { continue \'outer ; \"unreachable\"; }\l        if y >= 2is { return; \"unreachable\"; }\l        x -= 1is;\l        y -= 3is;\l    }\l,\lexiting scope_1 expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1is { continue \'outer ; \"unreachable\"; }\l                if y >= 2is { return; \"unreachable\"; }\l                x -= 1is;\l                y -= 3is;\l            }\l        \"unreachable\";\l    }\l"];
+    N26 -> N1;
     N27 -> N28;
     N28 -> N29;
     N29 -> N30;
index 2b5c5cdff44e33eb69d60ef07ab9a9904aa40998..c9f7d4cdf0aabf3019b1478481a1ab559eca6837 100644 (file)
@@ -95,7 +95,7 @@ digraph block {
     N40 -> N41;
     N41 -> N42;
     N42 -> N43;
-    N43 -> N1[label="exiting scope_0 expr while y > 0is {\l    y -= 1is;\l    while z > 0is { z -= 1is; }\l    if x > 10is { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr while x > 0is {\l    x -= 1is;\l    while y > 0is {\l        y -= 1is;\l        while z > 0is { z -= 1is; }\l        if x > 10is { return; \"unreachable\"; }\l    }\l}\l"];
+    N43 -> N1;
     N44 -> N45;
     N45 -> N46;
     N46 -> N47;
index ee3fe7ced6cd71d6b4d0fa691c67e8233106aa15..a5373bda39b188d881e7c00bd8f8775174dc6889 100644 (file)
@@ -90,7 +90,7 @@ digraph block {
     N13 -> N14;
     N14 -> N15;
     N15 -> N16;
-    N16 -> N12[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0is { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0is { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 0is { break ; \"unreachable\"; }\l    x -= 1is;\l    loop  {\l        if y == 0is { break ; \"unreachable\"; }\l        y -= 1is;\l        loop  { if z == 0is { break ; \"unreachable\"; } z -= 1is; }\l        if x > 10is { return; \"unreachable\"; }\l    }\l}\l"];
+    N16 -> N12;
     N17 -> N18;
     N18 -> N19;
     N19 -> N20;
@@ -107,7 +107,7 @@ digraph block {
     N30 -> N31;
     N31 -> N32;
     N32 -> N33;
-    N33 -> N29[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0is { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0is { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if y == 0is { break ; \"unreachable\"; }\l    y -= 1is;\l    loop  { if z == 0is { break ; \"unreachable\"; } z -= 1is; }\l    if x > 10is { return; \"unreachable\"; }\l}\l"];
+    N33 -> N29;
     N34 -> N35;
     N35 -> N36;
     N36 -> N37;
@@ -124,7 +124,7 @@ digraph block {
     N47 -> N48;
     N48 -> N49;
     N49 -> N50;
-    N50 -> N46[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0is { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0is { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0is { break ; \"unreachable\"; } z -= 1is; }"];
+    N50 -> N46;
     N51 -> N52;
     N52 -> N53;
     N53 -> N54;
@@ -143,7 +143,7 @@ digraph block {
     N64 -> N65;
     N65 -> N66;
     N66 -> N67;
-    N67 -> N1[label="exiting scope_0 expr loop  {\l    if y == 0is { break ; \"unreachable\"; }\l    y -= 1is;\l    loop  { if z == 0is { break ; \"unreachable\"; } z -= 1is; }\l    if x > 10is { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr loop  {\l    if x == 0is { break ; \"unreachable\"; }\l    x -= 1is;\l    loop  {\l        if y == 0is { break ; \"unreachable\"; }\l        y -= 1is;\l        loop  { if z == 0is { break ; \"unreachable\"; } z -= 1is; }\l        if x > 10is { return; \"unreachable\"; }\l    }\l}\l"];
+    N67 -> N1;
     N68 -> N69;
     N69 -> N70;
     N70 -> N71;
index 82799c724b0bde59299236539d819b70c33a3603..2611219e816e950aeb35928b2e58f6790bd9556f 100644 (file)
@@ -90,7 +90,7 @@ digraph block {
     N13 -> N14;
     N14 -> N15;
     N15 -> N16;
-    N16 -> N12[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0is { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0is { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 0is { break ; \"unreachable\"; }\l    x -= 1is;\l    \'a:\l        loop  {\l            if y == 0is { break ; \"unreachable\"; }\l            y -= 1is;\l            \'a: loop  { if z == 0is { break ; \"unreachable\"; } z -= 1is; }\l            if x > 10is { continue \'a ; \"unreachable\"; }\l        }\l}\l"];
+    N16 -> N12;
     N17 -> N18;
     N18 -> N19;
     N19 -> N20;
@@ -107,7 +107,7 @@ digraph block {
     N30 -> N31;
     N31 -> N32;
     N32 -> N33;
-    N33 -> N29[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0is { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0is { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if y == 0is { break ; \"unreachable\"; }\l    y -= 1is;\l    \'a: loop  { if z == 0is { break ; \"unreachable\"; } z -= 1is; }\l    if x > 10is { continue \'a ; \"unreachable\"; }\l}\l"];
+    N33 -> N29;
     N34 -> N35;
     N35 -> N36;
     N36 -> N37;
@@ -124,7 +124,7 @@ digraph block {
     N47 -> N48;
     N48 -> N49;
     N49 -> N50;
-    N50 -> N46[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0is { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0is { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0is { break ; \"unreachable\"; } z -= 1is; }"];
+    N50 -> N46;
     N51 -> N52;
     N52 -> N53;
     N53 -> N54;
@@ -143,7 +143,7 @@ digraph block {
     N64 -> N65;
     N65 -> N66;
     N66 -> N67;
-    N67 -> N28[label="exiting scope_0 expr continue \'a,\lexiting scope_1 stmt continue \'a ;,\lexiting scope_2 block { continue \'a ; \"unreachable\"; },\lexiting scope_3 expr if x > 10is { continue \'a ; \"unreachable\"; },\lexiting scope_4 block {\l    if y == 0is { break ; \"unreachable\"; }\l    y -= 1is;\l    \'a: loop  { if z == 0is { break ; \"unreachable\"; } z -= 1is; }\l    if x > 10is { continue \'a ; \"unreachable\"; }\l}\l"];
+    N67 -> N28;
     N68 -> N69;
     N69 -> N70;
     N70 -> N71;
index f5027618814a9883f241fe53c8bc91749f661fc5..365cbf93da203cc42ae2073e383d0d04589c7bff 100644 (file)
@@ -51,7 +51,7 @@ endif
 
 # Extra flags needed to compile a working executable with the standard library
 ifdef IS_WINDOWS
-       EXTRACFLAGS :=
+       EXTRACFLAGS := -lws2_32
 else
 ifeq ($(shell uname),Darwin)
 else
index 4ffb8a3f74d4f0769bd368dc443ab267d595fd9b..5236b35d4d2b9019254dec0dd8d2480a2d7961af 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
 #[derive(PartialEq, Clone, Show)]
 fn foo() -> AFakeTypeThatHadBetterGoAway {}
 
+#[into_multi_foo]
+#[derive(PartialEq, Clone, Show)]
+fn foo() -> AnotherFakeTypeThatHadBetterGoAway {}
+
+trait Qux {
+    #[into_multi_foo]
+    fn bar();
+}
+
+impl Qux for i32 {
+    #[into_multi_foo]
+    fn bar() {}
+}
+
+impl Qux for u8 {}
+
 pub fn main() {
     assert_eq!(1, make_a_1!());
     assert_eq!(2, exported_macro!());
 
     assert_eq!(Foo::Bar, Foo::Bar);
     test(None::<Foo>);
+
+    assert_eq!(Foo2::Bar2, Foo2::Bar2);
+    test(None::<Foo2>);
+
+    let x = 10i32;
+    assert_eq!(x.foo(), 42);
+    let x = 10u8;
+    assert_eq!(x.foo(), 0);
 }
 
 fn test<T: PartialEq+Clone>(_: Option<T>) {}
diff --git a/src/test/run-pass/associated-types-enum-field-named.rs b/src/test/run-pass/associated-types-enum-field-named.rs
new file mode 100644 (file)
index 0000000..a499aa6
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2015 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 associated types appearing in struct-like enum variants.
+
+use self::VarValue::*;
+
+pub trait UnifyKey {
+    type Value;
+    fn to_index(&self) -> usize;
+}
+
+pub enum VarValue<K:UnifyKey> {
+    Redirect { to: K },
+    Root { value: K::Value, rank: usize },
+}
+
+fn get<'a,K:UnifyKey<Value=Option<V>>,V>(table: &'a Vec<VarValue<K>>, key: &K) -> &'a Option<V> {
+    match table[key.to_index()] {
+        VarValue::Redirect { to: ref k } => get(table, k),
+        VarValue::Root { value: ref v, rank: _ } => v,
+    }
+}
+
+impl UnifyKey for usize {
+    type Value = Option<char>;
+    fn to_index(&self) -> usize { *self }
+}
+
+fn main() {
+    let table = vec![/* 0 */ Redirect { to: 1 },
+                     /* 1 */ Redirect { to: 3 },
+                     /* 2 */ Root { value: Some('x'), rank: 0 },
+                     /* 3 */ Redirect { to: 2 }];
+    assert_eq!(get(&table, &0), &Some('x'));
+}
diff --git a/src/test/run-pass/associated-types-enum-field-numbered.rs b/src/test/run-pass/associated-types-enum-field-numbered.rs
new file mode 100644 (file)
index 0000000..e710c53
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2015 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 associated types appearing in tuple-like enum variants.
+
+use self::VarValue::*;
+
+pub trait UnifyKey {
+    type Value;
+    fn to_index(&self) -> usize;
+}
+
+pub enum VarValue<K:UnifyKey> {
+    Redirect(K),
+    Root(K::Value, usize),
+}
+
+fn get<'a,K:UnifyKey<Value=Option<V>>,V>(table: &'a Vec<VarValue<K>>, key: &K) -> &'a Option<V> {
+    match table[key.to_index()] {
+        VarValue::Redirect(ref k) => get(table, k),
+        VarValue::Root(ref v, _) => v,
+    }
+}
+
+impl UnifyKey for usize {
+    type Value = Option<char>;
+    fn to_index(&self) -> usize { *self }
+}
+
+fn main() {
+    let table = vec![/* 0 */ Redirect(1),
+                     /* 1 */ Redirect(3),
+                     /* 2 */ Root(Some('x'), 0),
+                     /* 3 */ Redirect(2)];
+    assert_eq!(get(&table, &0), &Some('x'));
+}
diff --git a/src/test/run-pass/associated-types-normalize-unifield-struct.rs b/src/test/run-pass/associated-types-normalize-unifield-struct.rs
new file mode 100644 (file)
index 0000000..c517f61
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2015 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.
+
+// Regression test for issue #21010: Normalize associated types in
+// various special paths in the `type_is_immediate` function.
+
+#![allow(unstable)]
+
+pub trait OffsetState: Sized {}
+pub trait Offset { type State: OffsetState; }
+
+#[derive(Copy)] pub struct X;
+impl Offset for X { type State = Y; }
+
+#[derive(Copy)] pub struct Y;
+impl OffsetState for Y {}
+
+pub fn now() -> DateTime<X> { from_utc(Y) }
+
+pub struct DateTime<Off: Offset> { pub offset: Off::State }
+pub fn from_utc<Off: Offset>(offset: Off::State) -> DateTime<Off> { DateTime { offset: offset } }
+
+pub fn main() {
+    let _x = now();
+}
diff --git a/src/test/run-pass/associated-types-projection-in-object-type.rs b/src/test/run-pass/associated-types-projection-in-object-type.rs
new file mode 100644 (file)
index 0000000..44dd49b
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2015 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.
+
+// Corrected regression test for #20831. The original did not compile.
+// When fixed, it revealed another problem concerning projections that
+// appear in associated type bindings in object types, which were not
+// being properly flagged.
+
+use std::ops::{Shl, Shr};
+use std::cell::RefCell;
+
+pub trait Subscriber {
+    type Input;
+}
+
+pub trait Publisher<'a> {
+    type Output;
+    fn subscribe(&mut self, Box<Subscriber<Input=Self::Output> + 'a>);
+}
+
+pub trait Processor<'a> : Subscriber + Publisher<'a> { }
+
+impl<'a, P> Processor<'a> for P where P : Subscriber + Publisher<'a> { }
+
+struct MyStruct<'a> {
+    sub: Box<Subscriber<Input=u64> + 'a>
+}
+
+impl<'a> Publisher<'a> for MyStruct<'a> {
+    type Output = u64;
+    fn subscribe(&mut self, t : Box<Subscriber<Input=u64> + 'a>) {
+        self.sub = t;
+    }
+}
+
+fn main() {}
diff --git a/src/test/run-pass/associated-types-struct-field-named.rs b/src/test/run-pass/associated-types-struct-field-named.rs
new file mode 100644 (file)
index 0000000..1ded34f
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2015 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 we correctly normalize the type of a struct field
+// which has an associated type.
+
+pub trait UnifyKey {
+    type Value;
+}
+
+pub struct Node<K:UnifyKey> {
+    pub key: K,
+    pub value: K::Value,
+}
+
+fn foo<K : UnifyKey<Value=Option<V>>,V : Clone>(node: &Node<K>) -> Option<V> {
+    node.value.clone()
+}
+
+impl UnifyKey for i32 {
+    type Value = Option<u32>;
+}
+
+impl UnifyKey for u32 {
+    type Value = Option<i32>;
+}
+
+pub fn main() {
+    let node: Node<i32> = Node { key: 1, value: Some(22) };
+    assert_eq!(foo(&node), Some(22_u32));
+
+    let node: Node<u32> = Node { key: 1, value: Some(22) };
+    assert_eq!(foo(&node), Some(22_i32));
+}
diff --git a/src/test/run-pass/associated-types-struct-field-numbered.rs b/src/test/run-pass/associated-types-struct-field-numbered.rs
new file mode 100644 (file)
index 0000000..3669dec
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2015 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 we correctly normalize the type of a struct field
+// which has an associated type.
+
+pub trait UnifyKey {
+    type Value;
+}
+
+pub struct Node<K:UnifyKey>(K, K::Value);
+
+fn foo<K : UnifyKey<Value=Option<V>>,V : Clone>(node: &Node<K>) -> Option<V> {
+    node.1.clone()
+}
+
+impl UnifyKey for i32 {
+    type Value = Option<u32>;
+}
+
+impl UnifyKey for u32 {
+    type Value = Option<i32>;
+}
+
+pub fn main() {
+    let node: Node<i32> = Node(1, Some(22));
+    assert_eq!(foo(&node), Some(22_u32));
+
+    let node: Node<u32> = Node(1, Some(22));
+    assert_eq!(foo(&node), Some(22_i32));
+}
index da5fa19f816f753771008632a3794a3ae882bf6e..320ad0bf4d1da67238892518a7b8c75dc830542f 100644 (file)
 // ignore-windows FIXME #13259
 
 #![feature(unboxed_closures)]
+#![feature(unsafe_destructor)]
 
 use std::os;
 use std::io::process::Command;
-use std::finally::Finally;
 use std::str;
+use std::ops::{Drop, FnMut, FnOnce};
 
 #[inline(never)]
 fn foo() {
@@ -28,11 +29,15 @@ fn foo() {
 
 #[inline(never)]
 fn double() {
-    (|&mut:| {
-        panic!("once");
-    }).finally(|| {
-        panic!("twice");
-    })
+    struct Double;
+
+    impl Drop for Double {
+        fn drop(&mut self) { panic!("twice") }
+    }
+
+    let _d = Double;
+
+    panic!("once");
 }
 
 fn runtest(me: &str) {
diff --git a/src/test/run-pass/coherence-negative-impls-safe.rs b/src/test/run-pass/coherence-negative-impls-safe.rs
new file mode 100644 (file)
index 0000000..7844ef3
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 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(optin_builtin_traits)]
+
+use std::marker::Send;
+
+struct TestType;
+
+impl !Send for TestType {}
+
+fn main() {}
index 28b346c9ed4d0532e240902677419fa09dbd8375..f8f92a56adb1a687c65033f37c1747f13b9a74d0 100644 (file)
 
 #![feature(macro_rules)]
 
+use std::borrow::{Cow, IntoCow};
 use std::collections::Bitv;
 use std::default::Default;
 use std::iter::FromIterator;
+use std::ops::Add;
 use std::option::IntoIter as OptionIter;
 use std::rand::Rand;
 use std::rand::XorShiftRng as DummyRng;
@@ -28,6 +30,11 @@ fn u8_as_i8(x: u8) -> i8 { x as i8 }
 fn odd(x: uint) -> bool { x % 2 == 1 }
 fn dummy_rng() -> DummyRng { DummyRng::new_unseeded() }
 
+trait Size: Sized {
+    fn size() -> uint { std::mem::size_of::<Self>() }
+}
+impl<T> Size for T {}
+
 macro_rules! tests {
     ($($expr:expr, $ty:ty, ($($test:expr),*);)+) => (pub fn main() {$({
         const C: $ty = $expr;
@@ -70,14 +77,31 @@ macro_rules! tests {
     //    , (vec![b'f', b'o', b'o'], u8_as_i8);
 
     // Trait static methods.
-    // FIXME qualified path expressions aka UFCS i.e. <T as Trait>::method.
+    <bool as Size>::size, fn() -> uint, ();
     Default::default, fn() -> int, ();
+    <int as Default>::default, fn() -> int, ();
     Rand::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng());
+    <int as Rand>::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng());
     Rand::rand::<DummyRng>, fn(&mut DummyRng) -> int, (&mut dummy_rng());
+    <int as Rand>::rand::<DummyRng>, fn(&mut DummyRng) -> int, (&mut dummy_rng());
 
     // Trait non-static methods.
     Clone::clone, fn(&int) -> int, (&5);
+    <int as Clone>::clone, fn(&int) -> int, (&5);
     FromIterator::from_iter, fn(OptionIter<int>) -> Vec<int>, (Some(5).into_iter());
-    FromIterator::from_iter::<OptionIter<int>>, fn(OptionIter<int>) -> Vec<int>
-       , (Some(5).into_iter());
+    <Vec<_> as FromIterator<_>>::from_iter, fn(OptionIter<int>) -> Vec<int>,
+        (Some(5).into_iter());
+    <Vec<int> as FromIterator<_>>::from_iter, fn(OptionIter<int>) -> Vec<int>,
+        (Some(5).into_iter());
+    FromIterator::from_iter::<OptionIter<int>>, fn(OptionIter<int>) -> Vec<int>,
+        (Some(5).into_iter());
+    <Vec<int> as FromIterator<_>>::from_iter::<OptionIter<int>>, fn(OptionIter<int>) -> Vec<int>,
+        (Some(5).into_iter());
+    Add::add, fn(i32, i32) -> i32, (5, 6);
+    <i32 as Add<_>>::add, fn(i32, i32) -> i32, (5, 6);
+    <i32 as Add<i32>>::add, fn(i32, i32) -> i32, (5, 6);
+    <String as IntoCow<_, _>>::into_cow, fn(String) -> Cow<'static, String, str>,
+        ("foo".to_string());
+    <String as IntoCow<'static, _, _>>::into_cow, fn(String) -> Cow<'static, String, str>,
+        ("foo".to_string());
 }
diff --git a/src/test/run-pass/issue-16530.rs b/src/test/run-pass/issue-16530.rs
new file mode 100644 (file)
index 0000000..7e3b796
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2015 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::hash::{SipHasher, hash};
+
+#[derive(Hash)]
+struct Empty;
+
+pub fn main() {
+    assert!(hash::<_, SipHasher>(&Empty) == hash::<_, SipHasher>(&Empty));
+}
index 65bf088786efb927273a95a3f2e0418cbe3da9f9..a071224999be094bcfc0d598fce7b86eebd1c2de 100644 (file)
@@ -13,7 +13,7 @@ fn main() {
     let ss: &&[int] = &s;
     let sss: &&&[int] = &ss;
 
-    println!("{:?}", &s[0..3]);
+    println!("{:?}", &s[..3]);
     println!("{:?}", &ss[3..]);
     println!("{:?}", &sss[2..4]);
 }
diff --git a/src/test/run-pass/issue-20575.rs b/src/test/run-pass/issue-20575.rs
new file mode 100644 (file)
index 0000000..f83150b
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 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 overloaded calls work with zero arity closures
+
+#![feature(box_syntax)]
+
+fn main() {
+    let functions: [Box<Fn() -> Option<()>>; 1] = [box || None];
+
+    let _: Option<Vec<()>> = functions.iter().map(|f| (*f)()).collect();
+}
diff --git a/src/test/run-pass/issue-20676.rs b/src/test/run-pass/issue-20676.rs
new file mode 100644 (file)
index 0000000..fd99fc0
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 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.
+
+// Regression test for #20676. Error was that we didn't support
+// UFCS-style calls to a method in `Trait` where `Self` was bound to a
+// trait object of type `Trait`. See also `ufcs-trait-object.rs`.
+
+use std::fmt;
+
+fn main() {
+    let a: &fmt::Show = &1_i32;
+    format!("{:?}", a);
+}
diff --git a/src/test/run-pass/issue-21058.rs b/src/test/run-pass/issue-21058.rs
new file mode 100644 (file)
index 0000000..cbce577
--- /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.
+
+#![allow(unstable)]
+
+struct NT(str);
+struct DST { a: u32, b: str }
+
+fn main() {
+    // get_tydesc should support unsized types
+    assert!(unsafe {(
+        // Slice
+        (*std::intrinsics::get_tydesc::<[u8]>()).name,
+        // str
+        (*std::intrinsics::get_tydesc::<str>()).name,
+        // Trait
+        (*std::intrinsics::get_tydesc::<Copy>()).name,
+        // Newtype
+        (*std::intrinsics::get_tydesc::<NT>()).name,
+        // DST
+        (*std::intrinsics::get_tydesc::<DST>()).name
+    )} == ("[u8]", "str", "core::marker::Copy + 'static", "NT", "DST"));
+}
index 42739628eed75c8dcb8f8dbd47316131a266c4e4..f845db9c421634bf0bbab252f85bc3312f488587 100644 (file)
@@ -16,7 +16,7 @@ pub fn main() {
     let abc = [1i, 2, 3];
     let tf = [true, false];
     let x  = [(), ()];
-    let slice = &x[0..1];
+    let slice = &x[..1];
 
     assert_repr_eq(&abc[], "[1i, 2i, 3i]".to_string());
     assert_repr_eq(&tf[], "[true, false]".to_string());
diff --git a/src/test/run-pass/regions-debruijn-of-object.rs b/src/test/run-pass/regions-debruijn-of-object.rs
new file mode 100644 (file)
index 0000000..b9d3ed4
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2015 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 ctxt<'tcx> {
+    x: &'tcx i32
+}
+
+trait AstConv<'tcx> {
+    fn tcx<'a>(&'a self) -> &'a ctxt<'tcx>;
+}
+
+fn foo(conv: &AstConv) { }
+
+fn bar<'tcx>(conv: &AstConv<'tcx>) {
+    foo(conv)
+}
+
+fn main() { }
index 8f031d2e97e3ffd90d61a671466b9a32ff4cdef2..43e517404cb09b3adc9414f17584d9da7cfae8b2 100644 (file)
@@ -17,7 +17,7 @@ fn main() {
     let cmp: &[int] = &[3, 4, 5];
     assert!(&x[2..] == cmp);
     let cmp: &[int] = &[1, 2, 3];
-    assert!(&x[0..3] == cmp);
+    assert!(&x[..3] == cmp);
     let cmp: &[int] = &[2, 3, 4];
     assert!(&x[1..4] == cmp);
 
@@ -27,7 +27,7 @@ fn main() {
     let cmp: &[int] = &[3, 4, 5];
     assert!(&x[2..] == cmp);
     let cmp: &[int] = &[1, 2, 3];
-    assert!(&x[0..3] == cmp);
+    assert!(&x[..3] == cmp);
     let cmp: &[int] = &[2, 3, 4];
     assert!(&x[1..4] == cmp);
 
index a91e5da15376800596c89ea4dfdbf9b3dbb67600..3344844d49ff786523bf094b4af715906895e40d 100644 (file)
@@ -18,14 +18,12 @@ impl TestType {}
 
 trait TestTrait {}
 
-unsafe impl !Send for TestType {}
-impl !TestTrait for TestType {}
+impl !Send for TestType {}
 
 struct TestType2<T>;
 
 impl<T> TestType2<T> {}
 
-unsafe impl<T> !Send for TestType2<T> {}
-impl<T> !TestTrait for TestType2<T> {}
+impl<T> !Send for TestType2<T> {}
 
 fn main() {}
diff --git a/src/test/run-pass/trait-false-ambiguity-where-clause-builtin-bound.rs b/src/test/run-pass/trait-false-ambiguity-where-clause-builtin-bound.rs
new file mode 100644 (file)
index 0000000..ca66a10
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2015 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 we do not error out because of a (False) ambiguity
+// between the builtin rules for Sized and the where clause. Issue
+// #20959.
+
+fn foo<K>(x: Option<K>)
+    where Option<K> : Sized
+{
+    let _y = x;
+}
+
+fn main() {
+    foo(Some(22));
+}
diff --git a/src/test/run-pass/traits-negative-impls.rs b/src/test/run-pass/traits-negative-impls.rs
new file mode 100644 (file)
index 0000000..09c7d07
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2015 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(optin_builtin_traits)]
+
+use std::marker::Send;
+
+pub struct WaitToken;
+impl !Send for WaitToken {}
+
+pub struct Test<T>(T);
+unsafe impl<T: 'static> Send for Test<T> {}
+
+pub fn spawn<F>(_: F) -> () where F: FnOnce(), F: Send + 'static {}
+
+fn main() {
+    let wt = Test(WaitToken);
+    spawn(move || {
+        let x = wt;
+        println!("Hello, World!");
+    });
+}
diff --git a/src/test/run-pass/ufcs-trait-object.rs b/src/test/run-pass/ufcs-trait-object.rs
new file mode 100644 (file)
index 0000000..2ae6304
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2015 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 when you use ufcs form to invoke a trait method (on a
+// trait object) everything works fine.
+
+trait Foo {
+    fn test(&self) -> i32;
+}
+
+impl Foo for i32 {
+    fn test(&self) -> i32 { *self }
+}
+
+fn main() {
+    let a: &Foo = &22_i32;
+    assert_eq!(Foo::test(a), 22);
+}
diff --git a/src/test/run-pass/where-clause-bounds-inconsistency.rs b/src/test/run-pass/where-clause-bounds-inconsistency.rs
new file mode 100644 (file)
index 0000000..a1a6112
--- /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.
+
+trait Bound {}
+
+trait Trait {
+    fn a<T>(&self, T) where T: Bound;
+    fn b<T>(&self, T) where T: Bound;
+    fn c<T: Bound>(&self, T);
+    fn d<T: Bound>(&self, T);
+}
+
+impl Trait for bool {
+    fn a<T: Bound>(&self, _: T) {}
+    //^~ This gets rejected but should be accepted
+    fn b<T>(&self, _: T) where T: Bound {}
+    fn c<T: Bound>(&self, _: T) {}
+    fn d<T>(&self, _: T) where T: Bound {}
+}
+
+fn main() {}
diff --git a/src/test/run-pass/zero_sized_subslice_match.rs b/src/test/run-pass/zero_sized_subslice_match.rs
new file mode 100644 (file)
index 0000000..65882d3
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 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 x = [(), ()];
+
+    // The subslice used to go out of bounds for zero-sized array items, check that this doesn't
+    // happen anymore
+    match x {
+        [_, y..] => assert_eq!(&x[1] as *const _, &y[0] as *const _)
+    }
+}