]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #40373 - TimNN:test-ub-packed, r=arielb1
authorAriel Ben-Yehuda <arielb1@mail.tau.ac.il>
Sat, 11 Mar 2017 19:57:46 +0000 (21:57 +0200)
committerGitHub <noreply@github.com>
Sat, 11 Mar 2017 19:57:46 +0000 (21:57 +0200)
Fix UB in repr(packed) tests

r? @arielb1

cc #37609 and #27060

193 files changed:
.gitmodules
.travis.yml
CONTRIBUTING.md
README.md
RELEASES.md
cargo [new submodule]
configure
src/Cargo.lock
src/Cargo.toml
src/bootstrap/bootstrap.py
src/bootstrap/check.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/config.toml.example
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/step.rs
src/bootstrap/util.rs
src/build_helper/lib.rs
src/ci/docker/dist-fuchsia/Dockerfile [new file with mode: 0644]
src/ci/docker/dist-fuchsia/build-toolchain.sh [new file with mode: 0755]
src/ci/docker/dist-fuchsia/shared.sh [new file with mode: 0644]
src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile [new file with mode: 0644]
src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh [new file with mode: 0644]
src/ci/docker/dist-i586-gnu-i686-musl/musl-libunwind-patch.patch [new file with mode: 0644]
src/ci/docker/dist-x86_64-musl/Dockerfile [new file with mode: 0644]
src/ci/docker/dist-x86_64-musl/build-musl.sh [new file with mode: 0644]
src/ci/docker/linux-tested-targets/Dockerfile [deleted file]
src/ci/docker/linux-tested-targets/build-musl.sh [deleted file]
src/ci/docker/linux-tested-targets/musl-libunwind-patch.patch [deleted file]
src/ci/docker/run.sh
src/doc/index.md
src/doc/nomicon [new submodule]
src/doc/nomicon/src/README.md [deleted file]
src/doc/nomicon/src/SUMMARY.md [deleted file]
src/doc/nomicon/src/arc-and-mutex.md [deleted file]
src/doc/nomicon/src/atomics.md [deleted file]
src/doc/nomicon/src/borrow-splitting.md [deleted file]
src/doc/nomicon/src/casts.md [deleted file]
src/doc/nomicon/src/chapter_1.md [deleted file]
src/doc/nomicon/src/checked-uninit.md [deleted file]
src/doc/nomicon/src/coercions.md [deleted file]
src/doc/nomicon/src/concurrency.md [deleted file]
src/doc/nomicon/src/constructors.md [deleted file]
src/doc/nomicon/src/conversions.md [deleted file]
src/doc/nomicon/src/data.md [deleted file]
src/doc/nomicon/src/destructors.md [deleted file]
src/doc/nomicon/src/dot-operator.md [deleted file]
src/doc/nomicon/src/drop-flags.md [deleted file]
src/doc/nomicon/src/dropck.md [deleted file]
src/doc/nomicon/src/exception-safety.md [deleted file]
src/doc/nomicon/src/exotic-sizes.md [deleted file]
src/doc/nomicon/src/hrtb.md [deleted file]
src/doc/nomicon/src/leaking.md [deleted file]
src/doc/nomicon/src/lifetime-elision.md [deleted file]
src/doc/nomicon/src/lifetime-mismatch.md [deleted file]
src/doc/nomicon/src/lifetimes.md [deleted file]
src/doc/nomicon/src/meet-safe-and-unsafe.md [deleted file]
src/doc/nomicon/src/obrm.md [deleted file]
src/doc/nomicon/src/other-reprs.md [deleted file]
src/doc/nomicon/src/ownership.md [deleted file]
src/doc/nomicon/src/phantom-data.md [deleted file]
src/doc/nomicon/src/poisoning.md [deleted file]
src/doc/nomicon/src/races.md [deleted file]
src/doc/nomicon/src/references.md [deleted file]
src/doc/nomicon/src/repr-rust.md [deleted file]
src/doc/nomicon/src/safe-unsafe-meaning.md [deleted file]
src/doc/nomicon/src/send-and-sync.md [deleted file]
src/doc/nomicon/src/subtyping.md [deleted file]
src/doc/nomicon/src/transmutes.md [deleted file]
src/doc/nomicon/src/unbounded-lifetimes.md [deleted file]
src/doc/nomicon/src/unchecked-uninit.md [deleted file]
src/doc/nomicon/src/uninitialized.md [deleted file]
src/doc/nomicon/src/unwinding.md [deleted file]
src/doc/nomicon/src/vec-alloc.md [deleted file]
src/doc/nomicon/src/vec-dealloc.md [deleted file]
src/doc/nomicon/src/vec-deref.md [deleted file]
src/doc/nomicon/src/vec-drain.md [deleted file]
src/doc/nomicon/src/vec-final.md [deleted file]
src/doc/nomicon/src/vec-insert-remove.md [deleted file]
src/doc/nomicon/src/vec-into-iter.md [deleted file]
src/doc/nomicon/src/vec-layout.md [deleted file]
src/doc/nomicon/src/vec-push-pop.md [deleted file]
src/doc/nomicon/src/vec-raw.md [deleted file]
src/doc/nomicon/src/vec-zsts.md [deleted file]
src/doc/nomicon/src/vec.md [deleted file]
src/doc/nomicon/src/working-with-unsafe.md [deleted file]
src/liballoc/boxed.rs
src/libcollections/str.rs
src/libcollections/string.rs
src/libcollections/vec.rs
src/libcollections/vec_deque.rs
src/libcollectionstest/lib.rs
src/libcollectionstest/vec_deque.rs
src/libcompiler_builtins/lib.rs
src/libcore/fmt/mod.rs
src/libcore/macros.rs
src/libcore/ptr.rs
src/libproc_macro/lib.rs
src/librustc/dep_graph/graph.rs
src/librustc/dep_graph/mod.rs
src/librustc/dep_graph/safe.rs [new file with mode: 0644]
src/librustc/infer/README.md
src/librustc/infer/region_inference/README.md
src/librustc/infer/region_inference/graphviz.rs
src/librustc/lint/context.rs
src/librustc/lint/mod.rs
src/librustc/mir/mod.rs
src/librustc/traits/select.rs
src/librustc/ty/mod.rs
src/librustc/ty/structural_impls.rs
src/librustc/ty/util.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_data_structures/indexed_vec.rs
src/librustc_data_structures/lib.rs
src/librustc_driver/driver.rs
src/librustc_errors/emitter.rs
src/librustc_errors/lib.rs
src/librustc_incremental/persist/load.rs
src/librustc_lint/unused.rs
src/librustc_metadata/locator.rs
src/librustc_mir/build/expr/as_temp.rs
src/librustc_mir/callgraph.rs [new file with mode: 0644]
src/librustc_mir/lib.rs
src/librustc_mir/mir_map.rs
src/librustc_mir/transform/inline.rs [new file with mode: 0644]
src/librustc_mir/transform/mod.rs
src/librustc_mir/transform/simplify.rs
src/librustc_plugin/registry.rs
src/librustc_save_analysis/data.rs
src/librustc_save_analysis/dump_visitor.rs
src/librustc_save_analysis/external_data.rs
src/librustc_save_analysis/json_dumper.rs
src/librustc_save_analysis/lib.rs
src/librustc_trans/back/link.rs
src/librustc_trans/base.rs
src/librustc_trans/context.rs
src/librustc_typeck/check/autoderef.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/collect.rs
src/librustdoc/html/static/rustdoc.css
src/librustdoc/html/static/styles/main.css
src/librustdoc/test.rs
src/libstd/collections/hash/map.rs
src/libstd/collections/hash/table.rs
src/libstd/env.rs
src/libstd/ffi/c_str.rs
src/libstd/ffi/os_str.rs
src/libstd/sys/redox/os_str.rs
src/libstd/sys/unix/os_str.rs
src/libstd/sys/windows/os_str.rs
src/libstd/sys_common/gnu/libbacktrace.rs
src/libstd/sys_common/wtf8.rs
src/libsyntax/ext/expand.rs
src/libsyntax/feature_gate.rs
src/stage0.txt
src/test/codegen/issue-15953.rs [new file with mode: 0644]
src/test/compile-fail/auxiliary/cfg-target-thread-local.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-cfg-target-thread-local.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-unwind-attributes.rs [new file with mode: 0644]
src/test/compile-fail/issue-18446.rs [new file with mode: 0644]
src/test/compile-fail/issue-22874.rs [new file with mode: 0644]
src/test/compile-fail/issue-40288-2.rs [new file with mode: 0644]
src/test/compile-fail/issue-40288.rs [new file with mode: 0644]
src/test/compile-fail/lint-unused-unsafe.rs [deleted file]
src/test/compile-fail/object-lifetime-default-elision.rs
src/test/compile-fail/object-lifetime-default-from-box-error.rs
src/test/compile-fail/regions-close-over-type-parameter-multiple.rs
src/test/compile-fail/regions-proc-bound-capture.rs
src/test/compile-fail/regions-trait-object-subtyping.rs
src/test/compile-fail/variance-contravariant-arg-object.rs
src/test/compile-fail/variance-covariant-arg-object.rs
src/test/compile-fail/variance-invariant-arg-object.rs
src/test/mir-opt/issue-38669.rs
src/test/run-make/dep-info-doesnt-run-much/Makefile [new file with mode: 0644]
src/test/run-make/dep-info-doesnt-run-much/foo.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs [deleted file]
src/test/run-pass-fulldeps/mir-pass.rs [deleted file]
src/test/run-pass/coerce-unsize-subtype.rs [new file with mode: 0644]
src/test/run-pass/issue-18446.rs [new file with mode: 0644]
src/test/run-pass/issue-23311.rs [new file with mode: 0644]
src/test/ui/span/issue-40157.rs [new file with mode: 0644]
src/test/ui/span/issue-40157.stderr [new file with mode: 0644]
src/test/ui/span/lint-unused-unsafe.rs [new file with mode: 0644]
src/test/ui/span/lint-unused-unsafe.stderr [new file with mode: 0644]
src/test/ui/span/suggestion-non-ascii.rs [new file with mode: 0644]
src/test/ui/span/suggestion-non-ascii.stderr [new file with mode: 0644]
src/tools/build-manifest/src/main.rs
src/tools/cargo [deleted submodule]
src/tools/tidy/src/features.rs

index d2c96ac901fc4e7b1afdfc13beaf93c40f9fc06f..9bc2a6a70eb45471df4b3d90f5946a8676a1bbe8 100644 (file)
 [submodule "src/liblibc"]
        path = src/liblibc
        url = https://github.com/rust-lang/libc.git
+[submodule "src/doc/nomicon"]
+       path = src/doc/nomicon
+       url = https://github.com/rust-lang-nursery/nomicon
 [submodule "src/tools/cargo"]
-       path = src/tools/cargo
+       path = cargo
        url = https://github.com/rust-lang/cargo
 [submodule "reference"]
        path = src/doc/reference
index 442d02aca7867f27fe58e95a4e08f17777c9e8a2..7dd5f6efaf07de5dd97c27734d4591c3f5e6275d 100644 (file)
@@ -15,17 +15,19 @@ matrix:
     - env: IMAGE=arm-android
     - env: IMAGE=armhf-gnu
     - env: IMAGE=cross DEPLOY=1
-    - env: IMAGE=linux-tested-targets DEPLOY=1
     - env: IMAGE=dist-android DEPLOY=1
     - env: IMAGE=dist-arm-linux DEPLOY=1
     - env: IMAGE=dist-armv7-aarch64-linux DEPLOY=1
     - env: IMAGE=dist-freebsd DEPLOY=1
+    - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1
+    - env: IMAGE=dist-fuchsia DEPLOY=1
     - env: IMAGE=dist-mips-linux DEPLOY=1
     - env: IMAGE=dist-mips64-linux DEPLOY=1
     - env: IMAGE=dist-powerpc-linux DEPLOY=1
     - env: IMAGE=dist-powerpc64-linux DEPLOY=1
     - env: IMAGE=dist-s390x-linux-netbsd DEPLOY=1
     - env: IMAGE=dist-x86-linux DEPLOY=1
+    - env: IMAGE=dist-x86_64-musl DEPLOY=1
     - env: IMAGE=emscripten
     - env: IMAGE=i686-gnu
     - env: IMAGE=i686-gnu-nopt
@@ -43,6 +45,7 @@ matrix:
         RUST_CHECK_TARGET=check
         RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin
         SRC=.
+        RUSTC_RETRY_LINKER_ON_SEGFAULT=1
       os: osx
       osx_image: xcode8.2
       install: &osx_install_sccache >
@@ -52,6 +55,7 @@ matrix:
         RUST_CHECK_TARGET=check
         RUST_CONFIGURE_ARGS=--build=i686-apple-darwin
         SRC=.
+        RUSTC_RETRY_LINKER_ON_SEGFAULT=1
       os: osx
       osx_image: xcode8.2
       install: *osx_install_sccache
@@ -61,18 +65,18 @@ matrix:
         RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-extended"
         SRC=.
         DEPLOY=1
+        RUSTC_RETRY_LINKER_ON_SEGFAULT=1
       os: osx
       osx_image: xcode8.2
       install: >
         travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-apple-darwin &&
-          chmod +x /usr/local/bin/sccache &&
-          brew uninstall --ignore-dependencies openssl &&
-          brew install openssl --universal --without-test
+          chmod +x /usr/local/bin/sccache
     - env: >
         RUST_CHECK_TARGET=dist
         RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended"
         SRC=.
         DEPLOY=1
+        RUSTC_RETRY_LINKER_ON_SEGFAULT=1
       os: osx
       osx_image: xcode8.2
       install: *osx_install_sccache
@@ -87,6 +91,7 @@ matrix:
         RUST_CONFIGURE_ARGS="--enable-extended"
         SRC=.
         DEPLOY_ALT=1
+        RUSTC_RETRY_LINKER_ON_SEGFAULT=1
       os: osx
       osx_image: xcode8.2
       install: *osx_install_sccache
@@ -98,6 +103,12 @@ env:
     # AWS_SECRET_ACCESS_KEY=...
     - secure: "Pixhh0hXDqGCdOyLtGFjli3J2AtDWIpyb2btIrLe956nCBDRutRoMm6rv5DI9sFZN07Mms7VzNNvhc9wCW1y63JAm414d2Co7Ob8kWMZlz9l9t7ACHuktUiis8yr+S4Quq1Vqd6pqi7pf2J++UxC8R/uLeqVrubzr6+X7AbmEFE="
 
+before_script:
+  - >
+      echo "#### Disk usage before running script:";
+      df -h;
+      du . | sort -nr | head -n100
+
 script:
   - >
       if [ "$ALLOW_PR" = "" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then
@@ -110,6 +121,19 @@ script:
           src/ci/docker/run.sh $IMAGE;
       fi
 
+after_success:
+  - >
+      echo "#### Build successful; Disk usage after running script:";
+      df -h;
+      du . | sort -nr | head -n100
+
+after_failure:
+  - >
+      echo "#### Build failed; Disk usage after running script:";
+      df -h;
+      du . | sort -nr | head -n100
+  - cat obj/tmp/sccache.log
+
 # Save tagged docker images we created and load them if they're available
 before_cache:
   - docker history -q rust-ci |
index 1e983cfd726d6990c25f6ce28f30a3efa8405082..f921fb2c94233efa196d6ef16ebc271dc2a813a5 100644 (file)
@@ -406,5 +406,5 @@ are:
 [rr]: https://doc.rust-lang.org/book/README.html
 [tlgba]: http://tomlee.co/2014/04/a-more-detailed-tour-of-the-rust-compiler/
 [ro]: http://www.rustaceans.org/
-[rctd]: ./COMPILER_TESTS.md
+[rctd]: ./src/test/COMPILER_TESTS.md
 [cheatsheet]: https://buildbot.rust-lang.org/homu/
index 93415adc423f4b26a28dddc1856fc2b519f8f0f7..79f11144a073d25373cf96784caf07f97c410171 100644 (file)
--- a/README.md
+++ b/README.md
@@ -149,7 +149,7 @@ $ ./configure
 $ make && sudo make install
 ```
 
-When using the configure script, the generated config.mk` file may override the
+When using the configure script, the generated `config.mk` file may override the
 `config.toml` file. To go back to the `config.toml` file, delete the generated
 `config.mk` file.
 
index 1de44ef7e6d0546dd024f5a7e0eaf1e6bc232528..606936778c49a96dc4d1040aa9caaec03dd9631b 100644 (file)
@@ -1,3 +1,194 @@
+Version 1.16.0 (2017-03-16)
+===========================
+
+Language
+--------
+
+* Lifetimes in statics and consts default to `'static`. [RFC 1623]
+* [The compiler's `dead_code` lint now accounts for type aliases][38051].
+* [Uninhabitable enums (those without any variants) no longer permit wildcard
+  match patterns][38069]
+* [Clean up semantics of `self` in an import list][38313]
+* [`Self` may appear in `impl` headers][38920]
+* [`Self` may appear in struct expressions][39282]
+
+Compiler
+--------
+
+* [`rustc` now supports `--emit=metadata`, which causes rustc to emit
+  a `.rmeta` file containing only crate metadata][38571]. This can be
+  used by tools like the Rust Language Service to perform
+  metadata-only builds.
+* [Levenshtein based typo suggestions now work in most places, while
+  previously they worked only for fields and sometimes for local
+  variables][38927]. Together with the overhaul of "no
+  resolution"/"unexpected resolution" errors (#[38154]) they result in
+  large and systematic improvement in resolution diagnostics.
+* [Fix `transmute::<T, U>` where `T` requires a bigger alignment than
+  `U`][38670]
+* [rustc: use -Xlinker when specifying an rpath with ',' in it][38798]
+* [`rustc` no longer attempts to provide "consider using an explicit
+  lifetime" suggestions][37057]. They were inaccurate.
+
+Stabilized APIs
+---------------
+
+* [`VecDeque::truncate`]
+* [`VecDeque::resize`]
+* [`String::insert_str`]
+* [`Duration::checked_add`]
+* [`Duration::checked_sub`]
+* [`Duration::checked_div`]
+* [`Duration::checked_mul`]
+* [`str::replacen`]
+* [`str::repeat`]
+* [`SocketAddr::is_ipv4`]
+* [`SocketAddr::is_ipv6`]
+* [`IpAddr::is_ipv4`]
+* [`IpAddr::is_ipv6`]
+* [`Vec::dedup_by`]
+* [`Vec::dedup_by_key`]
+* [`Result::unwrap_or_default`]
+* [`<*const T>::wrapping_offset`]
+* [`<*mut T>::wrapping_offset`]
+* `CommandExt::creation_flags`
+* [`File::set_permissions`]
+* [`String::split_off`]
+
+Libraries
+---------
+
+* [`[T]::binary_search` and `[T]::binary_search_by_key` now take
+  their argument by `Borrow` parameter][37761]
+* [All public types in std implement `Debug`][38006]
+* [`IpAddr` implements `From<Ipv4Addr>` and `From<Ipv6Addr>`][38327]
+* [`Ipv6Addr` implements `From<[u16; 8]>`][38131]
+* [Ctrl-Z returns from `Stdin.read()` when reading from the console on
+  Windows][38274]
+* [std: Fix partial writes in `LineWriter`][38062]
+* [std: Clamp max read/write sizes on Unix][38062]
+* [Use more specific panic message for `&str` slicing errors][38066]
+* [`TcpListener::set_only_v6` is deprecated][38304]. This
+  functionality cannot be achieved in std currently.
+* [`writeln!`, like `println!`, now accepts a form with no string
+  or formatting arguments, to just print a newline][38469]
+* [Implement `iter::Sum` and `iter::Product` for `Result`][38580]
+* [Reduce the size of static data in `std_unicode::tables`][38781]
+* [`char::EscapeDebug`, `EscapeDefault`, `EscapeUnicode`,
+  `CaseMappingIter`, `ToLowercase`, `ToUppercase`, implement
+  `Display`][38909]
+* [`Duration` implements `Sum`][38712]
+* [`String` implements `ToSocketAddrs`][39048]
+
+Cargo
+-----
+
+* [The `cargo check` command does a type check of a project without
+  building it][cargo/3296]
+* [crates.io will display CI badges from Travis and AppVeyor, if
+  specified in Cargo.toml][cargo/3546]
+* [crates.io will display categories listed in Cargo.toml][cargo/3301]
+* [Compilation profiles accept integer values for `debug`, in addition
+  to `true` and `false`. These are passed to `rustc` as the value to
+  `-C debuginfo`][cargo/3534]
+* [Implement `cargo --version --verbose`][cargo/3604]
+* [All builds now output 'dep-info' build dependencies compatible with
+  make and ninja][cargo/3557]
+* [Build all workspace members with `build --all`][cargo/3511]
+* [Document all workspace members with `doc --all`][cargo/3515]
+* [Path deps outside workspace are not members][cargo/3443]
+
+Misc
+----
+
+* [`rustdoc` has a `--sysroot` argument that, like `rustc`, specifies
+  the path to the Rust implementation][38589]
+* [The `armv7-linux-androideabi` target no longer enables NEON
+  extensions, per Google's ABI guide][38413]
+* [The stock standard library can be compiled for Redox OS][38401]
+* [Rust has initial SPARC support][38726]. Tier 3. No builds
+  available.
+* [Rust has experimental support for Nvidia PTX][38559]. Tier 3. No
+  builds available.
+* [Fix backtraces on i686-pc-windows-gnu by disabling FPO][39379]
+
+Compatibility Notes
+-------------------
+
+* [Uninhabitable enums (those without any variants) no longer permit wildcard
+  match patterns][38069]
+* In this release, references to uninhabited types can not be
+  pattern-matched. This was accidentally allowed in 1.15.
+* [The compiler's `dead_code` lint now accounts for type aliases][38051].
+* [Ctrl-Z returns from `Stdin.read()` when reading from the console on
+  Windows][38274]
+* [Clean up semantics of `self` in an import list][38313]
+
+[37057]: https://github.com/rust-lang/rust/pull/37057
+[37761]: https://github.com/rust-lang/rust/pull/37761
+[38006]: https://github.com/rust-lang/rust/pull/38006
+[38051]: https://github.com/rust-lang/rust/pull/38051
+[38062]: https://github.com/rust-lang/rust/pull/38062
+[38062]: https://github.com/rust-lang/rust/pull/38622
+[38066]: https://github.com/rust-lang/rust/pull/38066
+[38069]: https://github.com/rust-lang/rust/pull/38069
+[38131]: https://github.com/rust-lang/rust/pull/38131
+[38154]: https://github.com/rust-lang/rust/pull/38154
+[38274]: https://github.com/rust-lang/rust/pull/38274
+[38304]: https://github.com/rust-lang/rust/pull/38304
+[38313]: https://github.com/rust-lang/rust/pull/38313
+[38314]: https://github.com/rust-lang/rust/pull/38314
+[38327]: https://github.com/rust-lang/rust/pull/38327
+[38401]: https://github.com/rust-lang/rust/pull/38401
+[38413]: https://github.com/rust-lang/rust/pull/38413
+[38469]: https://github.com/rust-lang/rust/pull/38469
+[38559]: https://github.com/rust-lang/rust/pull/38559
+[38571]: https://github.com/rust-lang/rust/pull/38571
+[38580]: https://github.com/rust-lang/rust/pull/38580
+[38589]: https://github.com/rust-lang/rust/pull/38589
+[38670]: https://github.com/rust-lang/rust/pull/38670
+[38712]: https://github.com/rust-lang/rust/pull/38712
+[38726]: https://github.com/rust-lang/rust/pull/38726
+[38781]: https://github.com/rust-lang/rust/pull/38781
+[38798]: https://github.com/rust-lang/rust/pull/38798
+[38909]: https://github.com/rust-lang/rust/pull/38909
+[38920]: https://github.com/rust-lang/rust/pull/38920
+[38927]: https://github.com/rust-lang/rust/pull/38927
+[39048]: https://github.com/rust-lang/rust/pull/39048
+[39282]: https://github.com/rust-lang/rust/pull/39282
+[39379]: https://github.com/rust-lang/rust/pull/39379
+[`<*const T>::wrapping_offset`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset
+[`<*mut T>::wrapping_offset`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset
+[`Duration::checked_add`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.checked_add
+[`Duration::checked_div`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.checked_div
+[`Duration::checked_mul`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.checked_mul
+[`Duration::checked_sub`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.checked_sub
+[`File::set_permissions`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.set_permissions
+[`IpAddr::is_ipv4`]: https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_ipv4
+[`IpAddr::is_ipv6`]: https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_ipv6
+[`Result::unwrap_or_default`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or_default
+[`SocketAddr::is_ipv4`]: https://doc.rust-lang.org/std/net/enum.SocketAddr.html#method.is_ipv4
+[`SocketAddr::is_ipv6`]: https://doc.rust-lang.org/std/net/enum.SocketAddr.html#method.is_ipv6
+[`String::insert_str`]: https://doc.rust-lang.org/std/string/struct.String.html#method.insert_str
+[`String::split_off`]: https://doc.rust-lang.org/std/string/struct.String.html#method.split_off
+[`Vec::dedup_by_key`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.dedup_by_key
+[`Vec::dedup_by`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.dedup_by
+[`VecDeque::resize`]:  https://doc.rust-lang.org/std/collections/vec_deque/struct.VecDeque.html#method.resize
+[`VecDeque::truncate`]: https://doc.rust-lang.org/std/collections/vec_deque/struct.VecDeque.html#method.truncate
+[`str::repeat`]: https://doc.rust-lang.org/std/primitive.str.html#method.repeat
+[`str::replacen`]: https://doc.rust-lang.org/std/primitive.str.html#method.replacen
+[cargo/3296]: https://github.com/rust-lang/cargo/pull/3296
+[cargo/3301]: https://github.com/rust-lang/cargo/pull/3301
+[cargo/3443]: https://github.com/rust-lang/cargo/pull/3443
+[cargo/3511]: https://github.com/rust-lang/cargo/pull/3511
+[cargo/3515]: https://github.com/rust-lang/cargo/pull/3515
+[cargo/3534]: https://github.com/rust-lang/cargo/pull/3534
+[cargo/3546]: https://github.com/rust-lang/cargo/pull/3546
+[cargo/3557]: https://github.com/rust-lang/cargo/pull/3557
+[cargo/3604]: https://github.com/rust-lang/cargo/pull/3604
+[RFC 1623]: https://github.com/rust-lang/rfcs/blob/master/text/1623-static.md
+
+
 Version 1.15.1 (2017-02-09)
 ===========================
 
diff --git a/cargo b/cargo
new file mode 160000 (submodule)
index 0000000..5f3b9c4
--- /dev/null
+++ b/cargo
@@ -0,0 +1 @@
+Subproject commit 5f3b9c4c6a7be1f177d6024cb83d150b6479148a
index be8628de62832f0b01b8ca60b0c8a97696850c9a..d8861dacafac1091c3deb54ab211f54bc3d4e058 100755 (executable)
--- a/configure
+++ b/configure
@@ -512,7 +512,7 @@ case $CFG_CPUTYPE in
         CFG_OSTYPE="${CFG_OSTYPE}eabihf"
         ;;
 
-    armv7l)
+    armv7l | armv8l)
         CFG_CPUTYPE=armv7
         CFG_OSTYPE="${CFG_OSTYPE}eabihf"
         ;;
index f4174693a5771872cef659c99a00c2272e5b268e..6dc71e8b602db46269af3a242531e8db205d8e05 100644 (file)
@@ -6,23 +6,6 @@ dependencies = [
  "libc 0.0.0",
 ]
 
-[[package]]
-name = "advapi32-sys"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "aho-corasick"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "aho-corasick"
 version = "0.6.2"
@@ -90,11 +73,6 @@ dependencies = [
  "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "bufstream"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "build-manifest"
 version = "0.1.0"
@@ -110,81 +88,10 @@ dependencies = [
  "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "cargo"
-version = "0.18.0"
-dependencies = [
- "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "bufstream 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "cargotest 0.1.0",
- "crates-io 0.7.0",
- "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
- "fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "miow 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
- "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "cargotest"
-version = "0.1.0"
-dependencies = [
- "bufstream 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "cargo 0.18.0",
- "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
- "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "cargotest2"
 version = "0.1.0"
 
-[[package]]
-name = "cfg-if"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "clap"
 version = "2.20.5"
@@ -240,58 +147,6 @@ dependencies = [
 name = "core"
 version = "0.0.0"
 
-[[package]]
-name = "crates-io"
-version = "0.7.0"
-dependencies = [
- "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "crossbeam"
-version = "0.2.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "curl"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "curl-sys"
-version = "0.3.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "docopt"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
- "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "dtoa"
 version = "0.4.1"
@@ -334,48 +189,15 @@ dependencies = [
  "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "flate2"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "fmt_macros"
 version = "0.0.0"
 
-[[package]]
-name = "foreign-types"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "fs2"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "gcc"
 version = "0.3.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "gdi32-sys"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "getopts"
 version = "0.0.0"
@@ -385,48 +207,10 @@ name = "getopts"
 version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "git2"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "git2-curl"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "glob"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "graphviz"
 version = "0.0.0"
 
-[[package]]
-name = "hamcrest"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "handlebars"
 version = "0.25.1"
@@ -441,16 +225,6 @@ dependencies = [
  "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "idna"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "itoa"
 version = "0.3.1"
@@ -482,43 +256,6 @@ name = "libc"
 version = "0.2.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "libgit2-sys"
-version = "0.6.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "libssh2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "libssh2-sys"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "libz-sys"
-version = "1.0.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "linkchecker"
 version = "0.1.0"
@@ -532,11 +269,6 @@ name = "log"
 version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "matches"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "mdbook"
 version = "0.0.17"
@@ -554,14 +286,6 @@ dependencies = [
  "toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "memchr"
-version = "0.1.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "memchr"
 version = "1.0.1"
@@ -570,99 +294,6 @@ dependencies = [
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "miniz-sys"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "miow"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "net2"
-version = "0.2.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "num"
-version = "0.1.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-complex 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-rational 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "num-bigint"
-version = "0.1.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "num-complex"
-version = "0.1.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "num-integer"
-version = "0.1.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "num-iter"
-version = "0.1.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "num-rational"
-version = "0.1.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "num-traits"
 version = "0.1.36"
@@ -676,48 +307,11 @@ dependencies = [
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "num_cpus"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "open"
 version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "openssl"
-version = "0.9.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "openssl-probe"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "openssl-sys"
-version = "0.9.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "panic_abort"
 version = "0.0.0"
@@ -741,11 +335,6 @@ name = "pest"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "pkg-config"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "proc_macro"
 version = "0.0.0"
@@ -762,15 +351,6 @@ dependencies = [
  "syntax_pos 0.0.0",
 ]
 
-[[package]]
-name = "psapi-sys"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "pulldown-cmark"
 version = "0.0.8"
@@ -793,11 +373,6 @@ name = "quick-error"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "quote"
-version = "0.3.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "rand"
 version = "0.0.0"
@@ -805,26 +380,6 @@ dependencies = [
  "core 0.0.0",
 ]
 
-[[package]]
-name = "rand"
-version = "0.3.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "regex"
-version = "0.1.80"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "regex"
 version = "0.2.1"
@@ -837,11 +392,6 @@ dependencies = [
  "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "regex-syntax"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "regex-syntax"
 version = "0.4.0"
@@ -1218,50 +768,11 @@ dependencies = [
  "syntax_pos 0.0.0",
 ]
 
-[[package]]
-name = "semver"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "serde"
 version = "0.9.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "serde_codegen_internals"
-version = "0.14.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "serde_derive"
-version = "0.9.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_codegen_internals 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "serde_ignored"
-version = "0.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "serde_json"
 version = "0.9.7"
@@ -1277,11 +788,6 @@ dependencies = [
 name = "serialize"
 version = "0.0.0"
 
-[[package]]
-name = "shell-escape"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "std"
 version = "0.0.0"
@@ -1318,24 +824,6 @@ name = "strsim"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "syn"
-version = "0.11.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "synom 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "synom"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "syntax"
 version = "0.0.0"
@@ -1367,36 +855,10 @@ dependencies = [
  "serialize 0.0.0",
 ]
 
-[[package]]
-name = "tar"
-version = "0.4.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "tempdir"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "term"
 version = "0.0.0"
 
-[[package]]
-name = "term"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "term_size"
 version = "0.2.3"
@@ -1415,15 +877,6 @@ dependencies = [
  "term 0.0.0",
 ]
 
-[[package]]
-name = "thread-id"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "thread-id"
 version = "3.0.0"
@@ -1433,14 +886,6 @@ dependencies = [
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "thread_local"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "thread_local"
 version = "0.3.3"
@@ -1470,19 +915,6 @@ dependencies = [
  "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "unicode-bidi"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "unicode-normalization"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "unicode-segmentation"
 version = "1.1.0"
@@ -1493,11 +925,6 @@ name = "unicode-width"
 version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "unicode-xid"
-version = "0.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "unreachable"
 version = "0.1.1"
@@ -1506,29 +933,6 @@ dependencies = [
  "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "url"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "user32-sys"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "utf8-ranges"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "utf8-ranges"
 version = "1.0.0"
@@ -1554,119 +958,49 @@ name = "winapi-build"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "ws2_32-sys"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [metadata]
-"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a"
-"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
 "checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2"
 "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
 "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23"
 "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
-"checksum bufstream 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b48dbe2ff0e98fa2f03377d204a9637d3c9816cd431bfe05a8abbd0ea11d074"
-"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
 "checksum clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7db281b0520e97fbd15cd615dcd8f8bcad0c26f5f7d5effe705f090f39e9a758"
 "checksum cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "e1acc68a3f714627af38f9f5d09706a28584ba60dfe2cca68f40bf779f941b25"
-"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
-"checksum curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c90e1240ef340dd4027ade439e5c7c2064dd9dc652682117bd50d1486a3add7b"
-"checksum curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d909dc402ae80b6f7b0118c039203436061b9d9a3ca5d2c2546d93e0a61aaa"
-"checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8"
 "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90"
 "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
 "checksum env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "99971fb1b635fe7a0ee3c4d065845bb93cca80a23b5613b5613391ece5de4144"
 "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
-"checksum flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "d4e4d0c15ef829cbc1b7cda651746be19cceeb238be7b1049227b14891df9e25"
-"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d"
-"checksum fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf"
 "checksum gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "c07c758b972368e703a562686adb39125707cc1ef3399da8c019fc6c2498a75d"
-"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
 "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
-"checksum git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "046ae03385257040b2a35e56d9669d950dd911ba2bf48202fbef73ee6aab27b2"
-"checksum git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68676bc784bf0bef83278898929bf64a251e87c0340723d0b93fa096c9c5bf8e"
-"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
-"checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4"
 "checksum handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2249f6f0dc5a3bb2b3b1a8f797dfccbc4b053344d773d654ad565e51427d335"
-"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
 "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
 "checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b"
 "checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5"
-"checksum libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d951fd5eccae07c74e8c2c1075b05ea1e43be7f8952245af8c2840d1480b1d95"
-"checksum libssh2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "91e135645c2e198a39552c8c7686bb5b83b1b99f64831c040a6c2798a1195934"
-"checksum libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e5ee912a45d686d393d5ac87fac15ba0ba18daae14e8e7543c63ebf7fb7e970c"
 "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
-"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1"
 "checksum mdbook 0.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dbba458ca886cb082d026afd704eeeeb0531f7e4ffd6c619f72dc309c1c18fe4"
-"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
 "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
-"checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726"
-"checksum miow 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a78d2605eb97302c10cf944b8d96b0a2a890c52957caf92fcd1f24f69049579"
-"checksum net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "5edf9cb6be97212423aed9413dd4729d62b370b5e1c571750e882cebbbc1e3e2"
-"checksum num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "bde7c03b09e7c6a301ee81f6ddf66d7a28ec305699e3d3b056d2fc56470e3120"
-"checksum num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "88b14378471f7c2adc5262f05b4701ef53e8da376453a8d8fee48e51db745e49"
-"checksum num-complex 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c78e054dd19c3fd03419ade63fa661e9c49bb890ce3beb4eee5b7baf93f92f"
-"checksum num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "fb24d9bfb3f222010df27995441ded1e954f8f69cd35021f6bef02ca9552fb92"
-"checksum num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "287a1c9969a847055e1122ec0ea7a5c5d6f72aad97934e131c83d5c08ab4e45c"
-"checksum num-rational 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "54ff603b8334a72fbb27fe66948aac0abaaa40231b3cecd189e76162f6f38aaf"
 "checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c"
 "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3"
-"checksum num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a225d1e2717567599c24f88e49f00856c6e825a12125181ee42c4257e3688d39"
 "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842"
-"checksum openssl 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f9871ecf7629da3760599e3e547d35940cff3cead49159b49f81cd1250f24f1d"
-"checksum openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "756d49c8424483a3df3b5d735112b4da22109ced9a8294f1f5cdf80fb3810919"
-"checksum openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5dd48381e9e8a6dce9c4c402db143b2e243f5f872354532f7a009c289b3998ca"
 "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8"
-"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
-"checksum psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "abcd5d1a07d360e29727f757a9decb3ce8bc6e0efa8969cfaad669a8317a2478"
 "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41"
 "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c"
-"checksum quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7375cf7ad34a92e8fd18dd9c42f58b9a11def59ab48bec955bf359a788335592"
-"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
-"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
 "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01"
-"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
 "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457"
 "checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b"
-"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
-"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 "checksum serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1e0ed773960f90a78567fcfbe935284adf50c5d7cf119aa2cf43bb0b4afa69bb"
-"checksum serde_codegen_internals 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d52006899f910528a10631e5b727973fe668f3228109d1707ccf5bad5490b6e"
-"checksum serde_derive 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "789ee9f3cd78c850948b94121020147f5220b47dafbf230d7098a93a58f726cf"
-"checksum serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4b3f5576874721d14690657e9f0ed286e72a52be2f6fdc0cf2f024182bd8f64"
 "checksum serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb96d30e4e6f9fc52e08f51176d078b6f79b981dc3ed4134f7b850be9f446a8"
-"checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8"
 "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
-"checksum syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)" = "37c279fb816210c9bb28b2c292664581e7b87b4561e86b94df462664d8620bb8"
-"checksum synom 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27e31aa4b09b9f4cb12dff3c30ba503e17b1a624413d764d32dab76e3920e5bc"
-"checksum tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "1eb3bf6ec92843ca93f4fcfb5fc6dfe30534815b147885db4b5759b8e2ff7d52"
-"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
-"checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989"
 "checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a"
-"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
 "checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a"
-"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
 "checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7"
 "checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796"
 "checksum toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08272367dd2e766db3fa38f068067d17aa6a9dfd7259af24b3927db92f1e0c2f"
-"checksum unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a078ebdd62c0e71a709c3d53d2af693fe09fe93fbff8344aebe289b78f9032"
-"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff"
 "checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3"
 "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
-"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
 "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
-"checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e"
-"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47"
-"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
 "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
 "checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f"
 "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
 "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
-"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
index c5ca80accbf02c774b8d31aa1545835bd0082c99..0dafbb8428e3ebf6cd1d44d149805c914cff3e46 100644 (file)
@@ -13,7 +13,6 @@ members = [
   "tools/build-manifest",
   "tools/qemu-test-client",
   "tools/qemu-test-server",
-  "tools/cargo",
 ]
 
 # Curiously, compiletest will segfault if compiled with opt-level=3 on 64-bit
index 7dd53f41a214adb838a281bdef446e56590931be..4f41d337592b302ffe629ed192e0126d2fb3b383 100644 (file)
@@ -465,7 +465,7 @@ class RustBuild(object):
             cputype = 'i686'
         elif cputype in {'xscale', 'arm'}:
             cputype = 'arm'
-        elif cputype == 'armv7l':
+        elif cputype in {'armv7l', 'armv8l'}:
             cputype = 'arm'
             ostype += 'eabihf'
         elif cputype == 'aarch64':
index dfe96b51799c0f5813442a69fbc020513370e5b6..68b3623a53f255243ade5a90f8b328b390405e58 100644 (file)
@@ -550,7 +550,7 @@ fn find_tests(dir: &Path,
         let filename = e.file_name().into_string().unwrap();
         if (target.contains("windows") && filename.ends_with(".exe")) ||
            (!target.contains("windows") && !filename.contains(".")) ||
-           (target.contains("emscripten") && filename.contains(".js")){
+           (target.contains("emscripten") && filename.ends_with(".js")) {
             dst.push(e.path());
         }
     }
index 46d8d4b4aab2d6717017f75d660f0d424ad52976..3459c1d2b8425f89385e2a8ccb4023daf08f6fe9 100644 (file)
@@ -417,7 +417,10 @@ pub fn tool(build: &Build, stage: u32, target: &str, tool: &str) {
     // build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target));
 
     let mut cargo = build.cargo(&compiler, Mode::Tool, target, "build");
-    let dir = build.src.join("src/tools").join(tool);
+    let mut dir = build.src.join(tool);
+    if !dir.exists() {
+        dir = build.src.join("src/tools").join(tool);
+    }
     cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
 
     // We don't want to build tools dynamically as they'll be running across
index 438ce6103d624f814ddae98fe9afbea1830f407a..87c35e0502ce6d853ce5ad0ff95e1668b9bacead 100644 (file)
@@ -59,6 +59,7 @@ pub struct Config {
     pub llvm_static_stdcpp: bool,
     pub llvm_link_shared: bool,
     pub llvm_targets: Option<String>,
+    pub llvm_link_jobs: Option<u32>,
 
     // rust codegen options
     pub rust_optimize: bool,
@@ -179,6 +180,7 @@ struct Llvm {
     version_check: Option<bool>,
     static_libstdcpp: Option<bool>,
     targets: Option<String>,
+    link_jobs: Option<u32>,
 }
 
 #[derive(RustcDecodable, Default, Clone)]
@@ -333,6 +335,7 @@ pub fn parse(build: &str, file: Option<PathBuf>) -> Config {
             set(&mut config.llvm_version_check, llvm.version_check);
             set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp);
             config.llvm_targets = llvm.targets.clone();
+            config.llvm_link_jobs = llvm.link_jobs;
         }
 
         if let Some(ref rust) = toml.rust {
index 30763e38a336fa4569c41e6b91a371880ef6a71c..776bd729119e24458de1038d90252139159420a4 100644 (file)
 # Rust team and file an issue if you need assistance in porting!
 #targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX"
 
+# Cap the number of parallel linker invocations when compiling LLVM.
+# This can be useful when building LLVM with debug info, which significantly
+# increases the size of binaries and consequently the memory required by
+# each linker process.
+# If absent or 0, linker invocations are treated like any other job and
+# controlled by rustbuild's -j parameter.
+#link-jobs = 0
+
 # =============================================================================
 # General build configuration options
 # =============================================================================
index 67e4dad83ce8855bd93384a9ecc2b39e491624e7..5c4b718490c0cfe977d424ed8029254d76e75032 100644 (file)
@@ -392,6 +392,7 @@ pub fn rust_src(build: &Build) {
     let src_dirs = [
         "man",
         "src",
+        "cargo",
     ];
 
     let filter_fn = move |path: &Path| {
@@ -533,11 +534,11 @@ pub fn cargo(build: &Build, stage: u32, target: &str) {
     println!("Dist cargo stage{} ({})", stage, target);
     let compiler = Compiler::new(stage, &build.config.build);
 
-    let src = build.src.join("src/tools/cargo");
+    let src = build.src.join("cargo");
     let etc = src.join("src/etc");
-    let release_num = &build.crates["cargo"].version;
-    let name = format!("cargo-{}", build.package_vers(release_num));
-    let version = build.cargo_info.version(build, release_num);
+    let release_num = build.cargo_release_num();
+    let name = format!("cargo-{}", build.package_vers(&release_num));
+    let version = build.cargo_info.version(build, &release_num);
 
     let tmp = tmpdir(build);
     let image = tmp.join("cargo-image");
@@ -594,7 +595,7 @@ pub fn extended(build: &Build, stage: u32, target: &str) {
     println!("Dist extended stage{} ({})", stage, target);
 
     let dist = distdir(build);
-    let cargo_vers = &build.crates["cargo"].version;
+    let cargo_vers = build.cargo_release_num();
     let rustc_installer = dist.join(format!("{}-{}.tar.gz",
                                             pkgname(build, "rustc"),
                                             target));
@@ -943,7 +944,7 @@ pub fn hash_and_sign(build: &Build) {
     cmd.arg(distdir(build));
     cmd.arg(today.trim());
     cmd.arg(build.rust_package_vers());
-    cmd.arg(build.cargo_info.version(build, &build.crates["cargo"].version));
+    cmd.arg(build.cargo_info.version(build, &build.cargo_release_num()));
     cmd.arg(addr);
 
     t!(fs::create_dir_all(distdir(build)));
index d19e5b1b88456030eb959e9810535cdcdd198e18..5a5cfe0c682d40ad585c26b727869b52912f19f1 100644 (file)
 
 use std::fs::{self, File};
 use std::io::prelude::*;
+use std::io;
+use std::path::Path;
 use std::process::Command;
 
 use {Build, Compiler, Mode};
-use util::cp_r;
+use util::{cp_r, symlink_dir};
 use build_helper::up_to_date;
 
 /// Invoke `rustbook` as compiled in `stage` for `target` for the doc book
@@ -141,7 +143,22 @@ pub fn std(build: &Build, stage: u32, target: &str) {
                        .join(target).join("doc");
     let rustdoc = build.rustdoc(&compiler);
 
-    build.clear_if_dirty(&out_dir, &rustdoc);
+    // Here what we're doing is creating a *symlink* (directory junction on
+    // Windows) to the final output location. This is not done as an
+    // optimization but rather for correctness. We've got three trees of
+    // documentation, one for std, one for test, and one for rustc. It's then
+    // our job to merge them all together.
+    //
+    // Unfortunately rustbuild doesn't know nearly as well how to merge doc
+    // trees as rustdoc does itself, so instead of actually having three
+    // separate trees we just have rustdoc output to the same location across
+    // all of them.
+    //
+    // This way rustdoc generates output directly into the output, and rustdoc
+    // will also directly handle merging.
+    let my_out = build.crate_doc_out(target);
+    build.clear_if_dirty(&my_out, &rustdoc);
+    t!(symlink_dir_force(&my_out, &out_dir));
 
     let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc");
     cargo.arg("--manifest-path")
@@ -166,7 +183,7 @@ pub fn std(build: &Build, stage: u32, target: &str) {
 
 
     build.run(&mut cargo);
-    cp_r(&out_dir, &out)
+    cp_r(&my_out, &out);
 }
 
 /// Compile all libtest documentation.
@@ -187,13 +204,16 @@ pub fn test(build: &Build, stage: u32, target: &str) {
                        .join(target).join("doc");
     let rustdoc = build.rustdoc(&compiler);
 
-    build.clear_if_dirty(&out_dir, &rustdoc);
+    // See docs in std above for why we symlink
+    let my_out = build.crate_doc_out(target);
+    build.clear_if_dirty(&my_out, &rustdoc);
+    t!(symlink_dir_force(&my_out, &out_dir));
 
     let mut cargo = build.cargo(&compiler, Mode::Libtest, target, "doc");
     cargo.arg("--manifest-path")
          .arg(build.src.join("src/libtest/Cargo.toml"));
     build.run(&mut cargo);
-    cp_r(&out_dir, &out)
+    cp_r(&my_out, &out);
 }
 
 /// Generate all compiler documentation.
@@ -213,15 +233,28 @@ pub fn rustc(build: &Build, stage: u32, target: &str) {
     let out_dir = build.stage_out(&compiler, Mode::Librustc)
                        .join(target).join("doc");
     let rustdoc = build.rustdoc(&compiler);
-    if !up_to_date(&rustdoc, &out_dir.join("rustc/index.html")) && out_dir.exists() {
-        t!(fs::remove_dir_all(&out_dir));
-    }
+
+    // See docs in std above for why we symlink
+    let my_out = build.crate_doc_out(target);
+    build.clear_if_dirty(&my_out, &rustdoc);
+    t!(symlink_dir_force(&my_out, &out_dir));
+
     let mut cargo = build.cargo(&compiler, Mode::Librustc, target, "doc");
     cargo.arg("--manifest-path")
          .arg(build.src.join("src/rustc/Cargo.toml"))
          .arg("--features").arg(build.rustc_features());
+
+    // Like with libstd above if compiler docs aren't enabled then we're not
+    // documenting internal dependencies, so we have a whitelist.
+    if !build.config.compiler_docs {
+        cargo.arg("--no-deps");
+        for krate in &["proc_macro"] {
+            cargo.arg("-p").arg(krate);
+        }
+    }
+
     build.run(&mut cargo);
-    cp_r(&out_dir, &out)
+    cp_r(&my_out, &out);
 }
 
 /// Generates the HTML rendered error-index by running the
@@ -240,3 +273,19 @@ pub fn error_index(build: &Build, target: &str) {
 
     build.run(&mut index);
 }
+
+fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> {
+    if let Ok(m) = fs::symlink_metadata(dst) {
+        if m.file_type().is_dir() {
+            try!(fs::remove_dir_all(dst));
+        } else {
+            // handle directory junctions on windows by falling back to
+            // `remove_dir`.
+            try!(fs::remove_file(dst).or_else(|_| {
+                fs::remove_dir(dst)
+            }));
+        }
+    }
+
+    symlink_dir(src, dst)
+}
index 071d0b0b09009035fb9a886c2d45272fc2011518..618e4d67705da646ff756cc13bdb7e3f475f726a 100644 (file)
 extern crate rustc_serialize;
 extern crate toml;
 
-use std::collections::HashMap;
 use std::cmp;
+use std::collections::HashMap;
 use std::env;
 use std::ffi::OsString;
 use std::fs::{self, File};
+use std::io::Read;
 use std::path::{Component, PathBuf, Path};
 use std::process::Command;
 
@@ -707,6 +708,13 @@ fn doc_out(&self, target: &str) -> PathBuf {
         self.out.join(target).join("doc")
     }
 
+    /// Output directory for all crate documentation for a target (temporary)
+    ///
+    /// The artifacts here are then copied into `doc_out` above.
+    fn crate_doc_out(&self, target: &str) -> PathBuf {
+        self.out.join(target).join("crate-docs")
+    }
+
     /// Returns true if no custom `llvm-config` is set for the specified target.
     ///
     /// If no custom `llvm-config` was specified then Rust's llvm will be used.
@@ -995,6 +1003,21 @@ fn rust_version(&self) -> String {
         self.rust_info.version(self, channel::CFG_RELEASE_NUM)
     }
 
+    /// Returns the `a.b.c` version that Cargo is at.
+    fn cargo_release_num(&self) -> String {
+        let mut toml = String::new();
+        t!(t!(File::open(self.src.join("cargo/Cargo.toml"))).read_to_string(&mut toml));
+        for line in toml.lines() {
+            let prefix = "version = \"";
+            let suffix = "\"";
+            if line.starts_with(prefix) && line.ends_with(suffix) {
+                return line[prefix.len()..line.len() - suffix.len()].to_string()
+            }
+        }
+
+        panic!("failed to find version in cargo's Cargo.toml")
+    }
+
     /// Returns whether unstable features should be enabled for the compiler
     /// we're building.
     fn unstable_features(&self) -> bool {
index 483f45fdd621877a2e6772277111f13d3c47280d..c13235b9c76804cb9bbb572091307b894c7e4f24 100644 (file)
@@ -115,6 +115,12 @@ pub fn llvm(build: &Build, target: &str) {
         cfg.define("LLVM_BUILD_32_BITS", "ON");
     }
 
+    if let Some(num_linkers) = build.config.llvm_link_jobs {
+        if num_linkers > 0 {
+            cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
+        }
+    }
+
     // http://llvm.org/docs/HowToCrossCompileLLVM.html
     if target != build.config.build {
         // FIXME: if the llvm root for the build triple is overridden then we
index a5c0d11d21985bd227582d1dfccf4409d495cb20..39f07459d4267914de8c8314e72ec42d042f14b7 100644 (file)
@@ -559,7 +559,7 @@ fn crate_rule<'a, 'b>(build: &'a Build,
     rules.build("tool-qemu-test-client", "src/tools/qemu-test-client")
          .dep(|s| s.name("libstd"))
          .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-client"));
-    rules.build("tool-cargo", "src/tools/cargo")
+    rules.build("tool-cargo", "cargo")
          .dep(|s| s.name("libstd"))
          .dep(|s| s.stage(0).host(s.target).name("openssl"))
          .dep(move |s| {
@@ -640,7 +640,7 @@ fn crate_rule<'a, 'b>(build: &'a Build,
         rules.doc(&krate.doc_step, path)
              .dep(|s| s.name("librustc-link"))
              .host(true)
-             .default(default && build.config.compiler_docs)
+             .default(default && build.config.docs)
              .run(move |s| doc::rustc(build, s.stage, s.target));
     }
 
index 520514f5fc95a77871ad6db413d9b30e5ad56fd8..dab20f44bc361d4e18cdeb0d50fa1236ebe320c2 100644 (file)
 use std::env;
 use std::ffi::OsString;
 use std::fs;
+use std::io;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::time::Instant;
 
+use filetime::{self, FileTime};
+
 /// Returns the `name` as the filename of a static library for `target`.
 pub fn staticlib(name: &str, target: &str) -> String {
     if target.contains("windows") {
@@ -38,12 +41,18 @@ pub fn copy(src: &Path, dst: &Path) {
 
     // Attempt to "easy copy" by creating a hard link (symlinks don't work on
     // windows), but if that fails just fall back to a slow `copy` operation.
-    let res = fs::hard_link(src, dst);
-    let res = res.or_else(|_| fs::copy(src, dst).map(|_| ()));
+    // let res = fs::hard_link(src, dst);
+    let res = fs::copy(src, dst);
     if let Err(e) = res {
         panic!("failed to copy `{}` to `{}`: {}", src.display(),
                dst.display(), e)
     }
+    let metadata = t!(src.metadata());
+    t!(fs::set_permissions(dst, metadata.permissions()));
+    let atime = FileTime::from_last_access_time(&metadata);
+    let mtime = FileTime::from_last_modification_time(&metadata);
+    t!(filetime::set_file_times(dst, atime, mtime));
+
 }
 
 /// Copies the `src` directory recursively to `dst`. Both are assumed to exist
@@ -175,3 +184,141 @@ fn drop(&mut self) {
                  time.subsec_nanos() / 1_000_000);
     }
 }
+
+/// Symlinks two directories, using junctions on Windows and normal symlinks on
+/// Unix.
+pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> {
+    let _ = fs::remove_dir(dest);
+    return symlink_dir_inner(src, dest);
+
+    #[cfg(not(windows))]
+    fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
+        use std::os::unix::fs;
+        fs::symlink(src, dest)
+    }
+
+    // Creating a directory junction on windows involves dealing with reparse
+    // points and the DeviceIoControl function, and this code is a skeleton of
+    // what can be found here:
+    //
+    // http://www.flexhex.com/docs/articles/hard-links.phtml
+    //
+    // Copied from std
+    #[cfg(windows)]
+    #[allow(bad_style)]
+    fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> {
+        use std::ptr;
+        use std::ffi::OsStr;
+        use std::os::windows::ffi::OsStrExt;
+
+        const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024;
+        const GENERIC_WRITE: DWORD = 0x40000000;
+        const OPEN_EXISTING: DWORD = 3;
+        const FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000;
+        const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000;
+        const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4;
+        const IO_REPARSE_TAG_MOUNT_POINT: DWORD = 0xa0000003;
+        const FILE_SHARE_DELETE: DWORD = 0x4;
+        const FILE_SHARE_READ: DWORD = 0x1;
+        const FILE_SHARE_WRITE: DWORD = 0x2;
+
+        type BOOL = i32;
+        type DWORD = u32;
+        type HANDLE = *mut u8;
+        type LPCWSTR = *const u16;
+        type LPDWORD = *mut DWORD;
+        type LPOVERLAPPED = *mut u8;
+        type LPSECURITY_ATTRIBUTES = *mut u8;
+        type LPVOID = *mut u8;
+        type WCHAR = u16;
+        type WORD = u16;
+
+        #[repr(C)]
+        struct REPARSE_MOUNTPOINT_DATA_BUFFER {
+            ReparseTag: DWORD,
+            ReparseDataLength: DWORD,
+            Reserved: WORD,
+            ReparseTargetLength: WORD,
+            ReparseTargetMaximumLength: WORD,
+            Reserved1: WORD,
+            ReparseTarget: WCHAR,
+        }
+
+        extern "system" {
+            fn CreateFileW(lpFileName: LPCWSTR,
+                           dwDesiredAccess: DWORD,
+                           dwShareMode: DWORD,
+                           lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
+                           dwCreationDisposition: DWORD,
+                           dwFlagsAndAttributes: DWORD,
+                           hTemplateFile: HANDLE)
+                           -> HANDLE;
+            fn DeviceIoControl(hDevice: HANDLE,
+                               dwIoControlCode: DWORD,
+                               lpInBuffer: LPVOID,
+                               nInBufferSize: DWORD,
+                               lpOutBuffer: LPVOID,
+                               nOutBufferSize: DWORD,
+                               lpBytesReturned: LPDWORD,
+                               lpOverlapped: LPOVERLAPPED) -> BOOL;
+        }
+
+        fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
+            Ok(s.as_ref().encode_wide().chain(Some(0)).collect())
+        }
+
+        // We're using low-level APIs to create the junction, and these are more
+        // picky about paths. For example, forward slashes cannot be used as a
+        // path separator, so we should try to canonicalize the path first.
+        let target = try!(fs::canonicalize(target));
+
+        try!(fs::create_dir(junction));
+
+        let path = try!(to_u16s(junction));
+
+        unsafe {
+            let h = CreateFileW(path.as_ptr(),
+                                GENERIC_WRITE,
+                                FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                                0 as *mut _,
+                                OPEN_EXISTING,
+                                FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+                                ptr::null_mut());
+
+            let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+            let mut db = data.as_mut_ptr()
+                            as *mut REPARSE_MOUNTPOINT_DATA_BUFFER;
+            let buf = &mut (*db).ReparseTarget as *mut _;
+            let mut i = 0;
+            // FIXME: this conversion is very hacky
+            let v = br"\??\";
+            let v = v.iter().map(|x| *x as u16);
+            for c in v.chain(target.as_os_str().encode_wide().skip(4)) {
+                *buf.offset(i) = c;
+                i += 1;
+            }
+            *buf.offset(i) = 0;
+            i += 1;
+            (*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+            (*db).ReparseTargetMaximumLength = (i * 2) as WORD;
+            (*db).ReparseTargetLength = ((i - 1) * 2) as WORD;
+            (*db).ReparseDataLength =
+                    (*db).ReparseTargetLength as DWORD + 12;
+
+            let mut ret = 0;
+            let res = DeviceIoControl(h as *mut _,
+                                      FSCTL_SET_REPARSE_POINT,
+                                      data.as_ptr() as *mut _,
+                                      (*db).ReparseDataLength + 8,
+                                      ptr::null_mut(), 0,
+                                      &mut ret,
+                                      ptr::null_mut());
+
+            if res == 0 {
+                Err(io::Error::last_os_error())
+            } else {
+                Ok(())
+            }
+        }
+    }
+}
index dffaebbd92914b0a2270037f903ccd3f1675c108..cb58a916fb7971305675e4d2a2e47ccc949569cd 100644 (file)
 
 extern crate filetime;
 
-use std::{fs, env};
 use std::fs::File;
-use std::process::{Command, Stdio};
+use std::io;
 use std::path::{Path, PathBuf};
+use std::process::{Command, Stdio};
+use std::{fs, env};
 
 use filetime::FileTime;
 
@@ -196,7 +197,7 @@ pub fn native_lib_boilerplate(src_name: &str,
 
     let out_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap());
     let out_dir = PathBuf::from(out_dir).join(out_name);
-    let _ = fs::create_dir_all(&out_dir);
+    t!(create_dir_racy(&out_dir));
     println!("cargo:rustc-link-lib=static={}", link_name);
     println!("cargo:rustc-link-search=native={}", out_dir.join(search_subdir).display());
 
@@ -223,3 +224,21 @@ fn fail(s: &str) -> ! {
     println!("\n\n{}\n\n", s);
     std::process::exit(1);
 }
+
+fn create_dir_racy(path: &Path) -> io::Result<()> {
+    match fs::create_dir(path) {
+        Ok(()) => return Ok(()),
+        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()),
+        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
+        Err(e) => return Err(e),
+    }
+    match path.parent() {
+        Some(p) => try!(create_dir_racy(p)),
+        None => return Err(io::Error::new(io::ErrorKind::Other, "failed to create whole tree")),
+    }
+    match fs::create_dir(path) {
+        Ok(()) => Ok(()),
+        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()),
+        Err(e) => Err(e),
+    }
+}
diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile
new file mode 100644 (file)
index 0000000..25a47c5
--- /dev/null
@@ -0,0 +1,47 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  ninja-build \
+  file \
+  curl \
+  ca-certificates \
+  python2.7-dev \
+  git \
+  sudo \
+  bzip2 \
+  xz-utils \
+  swig \
+  libedit-dev \
+  libncurses5-dev
+
+RUN curl -L https://cmake.org/files/v3.8/cmake-3.8.0-rc1-Linux-x86_64.tar.gz | \
+      tar xzf - -C /usr/local --strip-components=1
+
+WORKDIR /tmp
+COPY shared.sh build-toolchain.sh /tmp/
+RUN /tmp/build-toolchain.sh
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENV \
+    AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \
+    CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \
+    CXX_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang++ \
+    AR_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-ar \
+    CC_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang \
+    CXX_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang++
+
+ENV TARGETS=x86_64-unknown-fuchsia
+ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia
+
+ENV RUST_CONFIGURE_ARGS --target=$TARGETS
+ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
diff --git a/src/ci/docker/dist-fuchsia/build-toolchain.sh b/src/ci/docker/dist-fuchsia/build-toolchain.sh
new file mode 100755 (executable)
index 0000000..cad73ee
--- /dev/null
@@ -0,0 +1,116 @@
+#!/bin/bash
+# Copyright 2017 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.
+
+set -ex
+source shared.sh
+
+# Download sources
+SRCS=(
+  "https://fuchsia.googlesource.com/magenta magenta ac69119"
+  "https://fuchsia.googlesource.com/third_party/llvm llvm 5463083"
+  "https://fuchsia.googlesource.com/third_party/clang llvm/tools/clang 4ff7b4b"
+  "https://fuchsia.googlesource.com/third_party/lld llvm/tools/lld fd465a3"
+  "https://fuchsia.googlesource.com/third_party/lldb llvm/tools/lldb 6bb11f8"
+  "https://fuchsia.googlesource.com/third_party/compiler-rt llvm/runtimes/compiler-rt 52d4ecc"
+  "https://fuchsia.googlesource.com/third_party/libcxx llvm/runtimes/libcxx e891cc8"
+  "https://fuchsia.googlesource.com/third_party/libcxxabi llvm/runtimes/libcxxabi f0f0257"
+  "https://fuchsia.googlesource.com/third_party/libunwind llvm/runtimes/libunwind 50bddc1"
+)
+
+fetch() {
+  mkdir -p $2
+  pushd $2 > /dev/null
+  curl -sL $1/+archive/$3.tar.gz | tar xzf -
+  popd > /dev/null
+}
+
+for i in "${SRCS[@]}"; do
+  fetch $i
+done
+
+# Build toolchain
+cd llvm
+mkdir build
+cd build
+hide_output cmake -GNinja \
+  -DFUCHSIA_SYSROOT=${PWD}/../../magenta/third_party/ulib/musl \
+  -DLLVM_ENABLE_LTO=OFF \
+  -DCLANG_BOOTSTRAP_PASSTHROUGH=LLVM_ENABLE_LTO \
+  -C ../tools/clang/cmake/caches/Fuchsia.cmake \
+  ..
+hide_output ninja stage2-distribution
+hide_output ninja stage2-install-distribution
+cd ../..
+
+# Build sysroot
+rm -rf llvm/runtimes/compiler-rt
+./magenta/scripts/download-toolchain
+
+build_sysroot() {
+  local arch="$1"
+
+  case "${arch}" in
+    x86_64) tgt="magenta-pc-x86-64" ;;
+    aarch64) tgt="magenta-qemu-arm64" ;;
+  esac
+
+  hide_output make -C magenta -j$(getconf _NPROCESSORS_ONLN) $tgt
+  dst=/usr/local/${arch}-unknown-fuchsia
+  mkdir -p $dst
+  cp -r magenta/build-${tgt}/sysroot/include $dst/
+  cp -r magenta/build-${tgt}/sysroot/lib $dst/
+
+  cd llvm
+  mkdir build-runtimes-${arch}
+  cd build-runtimes-${arch}
+  hide_output cmake -GNinja \
+    -DCMAKE_C_COMPILER=clang \
+    -DCMAKE_CXX_COMPILER=clang++ \
+    -DCMAKE_AR=/usr/local/bin/llvm-ar \
+    -DCMAKE_RANLIB=/usr/local/bin/llvm-ranlib \
+    -DCMAKE_INSTALL_PREFIX= \
+    -DLLVM_MAIN_SRC_DIR=${PWD}/.. \
+    -DLLVM_BINARY_DIR=${PWD}/../build \
+    -DLLVM_ENABLE_WERROR=OFF \
+    -DCMAKE_BUILD_TYPE=Release \
+    -DLLVM_INCLUDE_TESTS=ON \
+    -DCMAKE_SYSTEM_NAME=Fuchsia \
+    -DCMAKE_C_COMPILER_TARGET=${arch}-fuchsia \
+    -DCMAKE_CXX_COMPILER_TARGET=${arch}-fuchsia \
+    -DUNIX=1 \
+    -DLIBCXX_HAS_MUSL_LIBC=ON \
+    -DLIBCXXABI_USE_LLVM_UNWINDER=ON \
+    -DCMAKE_SYSROOT=${dst} \
+    -DCMAKE_C_COMPILER_FORCED=TRUE \
+    -DCMAKE_CXX_COMPILER_FORCED=TRUE \
+    -DLLVM_ENABLE_LIBCXX=ON \
+    -DCMAKE_EXE_LINKER_FLAGS="-nodefaultlibs -lc" \
+    -DCMAKE_SHARED_LINKER_FLAGS="$(clang --target=${arch}-fuchsia -print-libgcc-file-name)" \
+    ../runtimes
+  hide_output env DESTDIR="${dst}" ninja install
+  cd ../..
+}
+
+build_sysroot "x86_64"
+build_sysroot "aarch64"
+
+rm -rf magenta llvm
+
+for arch in x86_64 aarch64; do
+  for tool in clang clang++; do
+    cat >/usr/local/bin/${arch}-unknown-fuchsia-${tool} <<EOF
+#!/bin/sh
+${tool} --target=${arch}-unknown-fuchsia --sysroot=/usr/local/${arch}-unknown-fuchsia "\$@"
+EOF
+    chmod +x /usr/local/bin/${arch}-unknown-fuchsia-${tool}
+  done
+  ln -s /usr/local/bin/llvm-ar /usr/local/bin/${arch}-unknown-fuchsia-ar
+done
diff --git a/src/ci/docker/dist-fuchsia/shared.sh b/src/ci/docker/dist-fuchsia/shared.sh
new file mode 100644 (file)
index 0000000..e26c6eb
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright 2017 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.
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  "$@" &> /tmp/build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  set -x
+}
diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile
new file mode 100644 (file)
index 0000000..0897be8
--- /dev/null
@@ -0,0 +1,50 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++-multilib \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  xz-utils \
+  sudo \
+  gdb \
+  patch \
+  libssl-dev \
+  pkg-config
+
+WORKDIR /build/
+COPY musl-libunwind-patch.patch build-musl.sh /build/
+RUN sh /build/build-musl.sh && rm -rf /build
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENV RUST_CONFIGURE_ARGS \
+      --target=i686-unknown-linux-musl,i586-unknown-linux-gnu \
+      --musl-root-i686=/musl-i686
+
+# Newer binutils broke things on some vms/distros (i.e., linking against
+# unknown relocs disabled by the following flag), so we need to go out of our
+# way to produce "super compatible" binaries.
+#
+# See: https://github.com/rust-lang/rust/issues/34978
+ENV CFLAGS_i686_unknown_linux_musl=-Wa,-mrelax-relocations=no
+
+ENV SCRIPT \
+      python2.7 ../x.py test \
+          --target i686-unknown-linux-musl \
+          --target i586-unknown-linux-gnu \
+          && \
+      python2.7 ../x.py dist \
+          --target i686-unknown-linux-musl \
+          --target i586-unknown-linux-gnu
diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh
new file mode 100644 (file)
index 0000000..a50a25c
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Copyright 2016 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.
+
+set -ex
+
+# We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
+export CFLAGS="-fPIC -Wa,-mrelax-relocations=no"
+export CXXFLAGS="-Wa,-mrelax-relocations=no"
+
+MUSL=musl-1.1.14
+curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
+cd $MUSL
+CFLAGS="$CFLAGS -m32" ./configure --prefix=/musl-i686 --disable-shared --target=i686
+make -j10
+make install
+cd ..
+
+# To build MUSL we're going to need a libunwind lying around, so acquire that
+# here and build it.
+curl -L https://github.com/llvm-mirror/llvm/archive/release_37.tar.gz | tar xzf -
+curl -L https://github.com/llvm-mirror/libunwind/archive/release_37.tar.gz | tar xzf -
+
+# Whoa what's this mysterious patch we're applying to libunwind! Why are we
+# swapping the values of ESP/EBP in libunwind?!
+#
+# Discovered in #35599 it turns out that the vanilla build of libunwind is not
+# suitable for unwinding 32-bit musl. After some investigation it ended up
+# looking like the register values for ESP/EBP were indeed incorrect (swapped)
+# in the source. Similar commits in libunwind (r280099 and r282589) have noticed
+# this for other platforms, and we just need to realize it for musl linux as
+# well.
+#
+# More technical info can be found at #35599
+cd libunwind-release_37
+patch -Np1 < /build/musl-libunwind-patch.patch
+cd ..
+
+mkdir libunwind-build
+cd libunwind-build
+CFLAGS="$CFLAGS -m32" CXXFLAGS="$CXXFLAGS -m32" cmake ../libunwind-release_37 \
+          -DLLVM_PATH=/build/llvm-release_37 \
+          -DLIBUNWIND_ENABLE_SHARED=0
+make -j10
+cp lib/libunwind.a /musl-i686/lib
diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/musl-libunwind-patch.patch b/src/ci/docker/dist-i586-gnu-i686-musl/musl-libunwind-patch.patch
new file mode 100644 (file)
index 0000000..99cd685
--- /dev/null
@@ -0,0 +1,15 @@
+diff --git a/include/libunwind.h b/include/libunwind.h
+index c5b9633..1360eb2 100644
+--- a/include/libunwind.h
++++ b/include/libunwind.h
+@@ -151,8 +151,8 @@ enum {
+   UNW_X86_ECX = 1,
+   UNW_X86_EDX = 2,
+   UNW_X86_EBX = 3,
+-  UNW_X86_EBP = 4,
+-  UNW_X86_ESP = 5,
++  UNW_X86_ESP = 4,
++  UNW_X86_EBP = 5,
+   UNW_X86_ESI = 6,
+   UNW_X86_EDI = 7
+ };
diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile
new file mode 100644 (file)
index 0000000..5877404
--- /dev/null
@@ -0,0 +1,45 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  xz-utils \
+  sudo \
+  gdb \
+  patch \
+  libssl-dev \
+  pkg-config
+
+WORKDIR /build/
+COPY build-musl.sh /build/
+RUN sh /build/build-musl.sh && rm -rf /build
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENV RUST_CONFIGURE_ARGS \
+      --target=x86_64-unknown-linux-musl \
+      --musl-root-x86_64=/musl-x86_64
+
+# Newer binutils broke things on some vms/distros (i.e., linking against
+# unknown relocs disabled by the following flag), so we need to go out of our
+# way to produce "super compatible" binaries.
+#
+# See: https://github.com/rust-lang/rust/issues/34978
+ENV CFLAGS_x86_64_unknown_linux_musl=-Wa,-mrelax-relocations=no
+
+ENV SCRIPT \
+      python2.7 ../x.py test --target x86_64-unknown-linux-musl && \
+      python2.7 ../x.py dist --target x86_64-unknown-linux-musl
diff --git a/src/ci/docker/dist-x86_64-musl/build-musl.sh b/src/ci/docker/dist-x86_64-musl/build-musl.sh
new file mode 100644 (file)
index 0000000..86bb259
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Copyright 2016 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.
+
+set -ex
+
+# We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
+export CFLAGS="-fPIC -Wa,-mrelax-relocations=no"
+export CXXFLAGS="-Wa,-mrelax-relocations=no"
+
+MUSL=musl-1.1.14
+curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
+cd $MUSL
+./configure --prefix=/musl-x86_64 --disable-shared
+make -j10
+make install
+
+cd ..
+rm -rf $MUSL
+
+# To build MUSL we're going to need a libunwind lying around, so acquire that
+# here and build it.
+curl -L https://github.com/llvm-mirror/llvm/archive/release_37.tar.gz | tar xzf -
+curl -L https://github.com/llvm-mirror/libunwind/archive/release_37.tar.gz | tar xzf -
+
+mkdir libunwind-build
+cd libunwind-build
+cmake ../libunwind-release_37 -DLLVM_PATH=/build/llvm-release_37 \
+          -DLIBUNWIND_ENABLE_SHARED=0
+make -j10
+cp lib/libunwind.a /musl-x86_64/lib
diff --git a/src/ci/docker/linux-tested-targets/Dockerfile b/src/ci/docker/linux-tested-targets/Dockerfile
deleted file mode 100644 (file)
index a7060cd..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++-multilib \
-  make \
-  file \
-  curl \
-  ca-certificates \
-  python2.7 \
-  git \
-  cmake \
-  xz-utils \
-  sudo \
-  gdb \
-  patch \
-  libssl-dev \
-  pkg-config
-
-WORKDIR /build/
-COPY musl-libunwind-patch.patch build-musl.sh /build/
-RUN sh /build/build-musl.sh && rm -rf /build
-
-RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
-    dpkg -i dumb-init_*.deb && \
-    rm dumb-init_*.deb
-ENTRYPOINT ["/usr/bin/dumb-init", "--"]
-
-RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
-      chmod +x /usr/local/bin/sccache
-
-ENV RUST_CONFIGURE_ARGS \
-      --target=x86_64-unknown-linux-musl,i686-unknown-linux-musl,i586-unknown-linux-gnu \
-      --musl-root-x86_64=/musl-x86_64 \
-      --musl-root-i686=/musl-i686
-
-# Newer binutils broke things on some vms/distros (i.e., linking against
-# unknown relocs disabled by the following flag), so we need to go out of our
-# way to produce "super compatible" binaries.
-#
-# See: https://github.com/rust-lang/rust/issues/34978
-ENV CFLAGS_i686_unknown_linux_musl=-Wa,-mrelax-relocations=no \
-    CFLAGS_x86_64_unknown_linux_musl=-Wa,-mrelax-relocations=no
-
-ENV SCRIPT \
-      python2.7 ../x.py test \
-          --target x86_64-unknown-linux-musl \
-          --target i686-unknown-linux-musl \
-          --target i586-unknown-linux-gnu \
-          && \
-      python2.7 ../x.py dist \
-          --target x86_64-unknown-linux-musl \
-          --target i686-unknown-linux-musl \
-          --target i586-unknown-linux-gnu
diff --git a/src/ci/docker/linux-tested-targets/build-musl.sh b/src/ci/docker/linux-tested-targets/build-musl.sh
deleted file mode 100644 (file)
index ce62c39..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/sh
-# Copyright 2016 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.
-
-set -ex
-
-# We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
-export CFLAGS="-fPIC -Wa,-mrelax-relocations=no"
-export CXXFLAGS="-Wa,-mrelax-relocations=no"
-
-MUSL=musl-1.1.14
-curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
-cd $MUSL
-./configure --prefix=/musl-x86_64 --disable-shared
-make -j10
-make install
-make clean
-# for i686
-CFLAGS="$CFLAGS -m32" ./configure --prefix=/musl-i686 --disable-shared --target=i686
-make -j10
-make install
-cd ..
-
-# To build MUSL we're going to need a libunwind lying around, so acquire that
-# here and build it.
-curl -L https://github.com/llvm-mirror/llvm/archive/release_37.tar.gz | tar xzf -
-curl -L https://github.com/llvm-mirror/libunwind/archive/release_37.tar.gz | tar xzf -
-
-# Whoa what's this mysterious patch we're applying to libunwind! Why are we
-# swapping the values of ESP/EBP in libunwind?!
-#
-# Discovered in #35599 it turns out that the vanilla build of libunwind is not
-# suitable for unwinding 32-bit musl. After some investigation it ended up
-# looking like the register values for ESP/EBP were indeed incorrect (swapped)
-# in the source. Similar commits in libunwind (r280099 and r282589) have noticed
-# this for other platforms, and we just need to realize it for musl linux as
-# well.
-#
-# More technical info can be found at #35599
-cd libunwind-release_37
-patch -Np1 < /build/musl-libunwind-patch.patch
-cd ..
-
-mkdir libunwind-build
-cd libunwind-build
-cmake ../libunwind-release_37 -DLLVM_PATH=/build/llvm-release_37 \
-          -DLIBUNWIND_ENABLE_SHARED=0
-make -j10
-cp lib/libunwind.a /musl-x86_64/lib
-
-# (Note: the next cmake call doesn't fully override the previous cached one, so remove the cached
-# configuration manually. IOW, if don't do this or call make clean we'll end up building libunwind
-# for x86_64 again)
-rm -rf *
-# for i686
-CFLAGS="$CFLAGS -m32" CXXFLAGS="$CXXFLAGS -m32" cmake ../libunwind-release_37 \
-          -DLLVM_PATH=/build/llvm-release_37 \
-          -DLIBUNWIND_ENABLE_SHARED=0
-make -j10
-cp lib/libunwind.a /musl-i686/lib
diff --git a/src/ci/docker/linux-tested-targets/musl-libunwind-patch.patch b/src/ci/docker/linux-tested-targets/musl-libunwind-patch.patch
deleted file mode 100644 (file)
index 99cd685..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-diff --git a/include/libunwind.h b/include/libunwind.h
-index c5b9633..1360eb2 100644
---- a/include/libunwind.h
-+++ b/include/libunwind.h
-@@ -151,8 +151,8 @@ enum {
-   UNW_X86_ECX = 1,
-   UNW_X86_EDX = 2,
-   UNW_X86_EBX = 3,
--  UNW_X86_EBP = 4,
--  UNW_X86_ESP = 5,
-+  UNW_X86_ESP = 4,
-+  UNW_X86_EBP = 5,
-   UNW_X86_ESI = 6,
-   UNW_X86_EDI = 7
- };
index 1e61f2169106cdf63a2678db2a36c587df43ff35..b5a713dc38259997b22b54bb351687101fb0c989 100755 (executable)
@@ -30,13 +30,17 @@ retry docker \
 objdir=$root_dir/obj
 
 mkdir -p $HOME/.cargo
-mkdir -p $objdir
+mkdir -p $objdir/tmp
 
 args=
 if [ "$SCCACHE_BUCKET" != "" ]; then
     args="$args --env SCCACHE_BUCKET=$SCCACHE_BUCKET"
     args="$args --env AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID"
     args="$args --env AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY"
+    args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log"
+    args="$args --env SCCACHE_LOG_LEVEL=debug"
+    args="$args --env RUST_LOG=sccache=debug"
+    args="$args --volume $objdir/tmp:/tmp/sccache"
 else
     mkdir -p $HOME/.cache/sccache
     args="$args --env SCCACHE_DIR=/sccache --volume $HOME/.cache/sccache:/sccache"
@@ -54,6 +58,7 @@ exec docker \
   --env DEPLOY_ALT=$DEPLOY_ALT \
   --env LOCAL_USER_ID=`id -u` \
   --volume "$HOME/.cargo:/cargo" \
+  --privileged \
   --rm \
   rust-ci \
   /checkout/src/ci/run.sh
index 982e24ef69549621e6df4a5b917ecd6b482ce973..1f262b360e3ed7562491c20c44cc308da7f0c4c1 100644 (file)
@@ -28,6 +28,7 @@ Rust provides a number of book-length sets of documentation, collectively
 nicknamed 'The Rust Bookshelf.'
 
 * [The Rust Programming Language][book] teaches you how to program in Rust.
+* [The Unstable Book][unstable-book] has documentation for unstable features.
 * [The Rustonomicon][nomicon] is your guidebook to the dark arts of unsafe Rust.
 * [The Reference][ref] is not a formal spec, but is more detailed and comprehensive than the book.
 
@@ -44,4 +45,5 @@ landed before then. That work is being tracked [here][38643].
 [err]: error-index.html
 [book]: book/index.html
 [nomicon]: nomicon/index.html
+[unstable-book]: unstable-book/index.html
 
diff --git a/src/doc/nomicon b/src/doc/nomicon
new file mode 160000 (submodule)
index 0000000..d08fe97
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit d08fe97d12b41c1ed8cc7701e545864132783941
diff --git a/src/doc/nomicon/src/README.md b/src/doc/nomicon/src/README.md
deleted file mode 100644 (file)
index d577d7b..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-# The Rustonomicon
-
-#### The Dark Arts of Advanced and Unsafe Rust Programming
-
-# NOTE: This is a draft document, and may contain serious errors
-
-> Instead of the programs I had hoped for, there came only a shuddering blackness
-and ineffable loneliness; and I saw at last a fearful truth which no one had
-ever dared to breathe before — the unwhisperable secret of secrets — The fact
-that this language of stone and stridor is not a sentient perpetuation of Rust
-as London is of Old London and Paris of Old Paris, but that it is in fact
-quite unsafe, its sprawling body imperfectly embalmed and infested with queer
-animate things which have nothing to do with it as it was in compilation.
-
-This book digs into all the awful details that are necessary to understand in
-order to write correct Unsafe Rust programs. Due to the nature of this problem,
-it may lead to unleashing untold horrors that shatter your psyche into a billion
-infinitesimal fragments of despair.
-
-Should you wish a long and happy career of writing Rust programs, you should
-turn back now and forget you ever saw this book. It is not necessary. However
-if you intend to write unsafe code -- or just want to dig into the guts of the
-language -- this book contains invaluable information.
-
-Unlike [The Book][trpl] we will be assuming considerable prior knowledge. In
-particular, you should be comfortable with basic systems programming and Rust.
-If you don't feel comfortable with these topics, you should consider [reading
-The Book][trpl] first. Though we will not be assuming that you have, and will
-take care to occasionally give a refresher on the basics where appropriate. You
-can skip straight to this book if you want; just know that we won't be
-explaining everything from the ground up.
-
-To be clear, this book goes into deep detail. We're going to dig into
-exception-safety, pointer aliasing, memory models, and even some type-theory.
-We will also be spending a lot of time talking about the different kinds
-of safety and guarantees.
-
-[trpl]: ../book/index.html
diff --git a/src/doc/nomicon/src/SUMMARY.md b/src/doc/nomicon/src/SUMMARY.md
deleted file mode 100644 (file)
index e33dcbb..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-# Summary
-
-[Introduction](README.md)
-
-* [Meet Safe and Unsafe](meet-safe-and-unsafe.md)
-       * [How Safe and Unsafe Interact](safe-unsafe-meaning.md)
-       * [Working with Unsafe](working-with-unsafe.md)
-* [Data Layout](data.md)
-       * [repr(Rust)](repr-rust.md)
-       * [Exotically Sized Types](exotic-sizes.md)
-       * [Other reprs](other-reprs.md)
-* [Ownership](ownership.md)
-       * [References](references.md)
-       * [Lifetimes](lifetimes.md)
-       * [Limits of Lifetimes](lifetime-mismatch.md)
-       * [Lifetime Elision](lifetime-elision.md)
-       * [Unbounded Lifetimes](unbounded-lifetimes.md)
-       * [Higher-Rank Trait Bounds](hrtb.md)
-       * [Subtyping and Variance](subtyping.md)
-       * [Drop Check](dropck.md)
-       * [PhantomData](phantom-data.md)
-       * [Splitting Borrows](borrow-splitting.md)
-* [Type Conversions](conversions.md)
-       * [Coercions](coercions.md)
-       * [The Dot Operator](dot-operator.md)
-       * [Casts](casts.md)
-       * [Transmutes](transmutes.md)
-* [Uninitialized Memory](uninitialized.md)
-       * [Checked](checked-uninit.md)
-       * [Drop Flags](drop-flags.md)
-       * [Unchecked](unchecked-uninit.md)
-* [Ownership Based Resource Management](obrm.md)
-       * [Constructors](constructors.md)
-       * [Destructors](destructors.md)
-       * [Leaking](leaking.md)
-* [Unwinding](unwinding.md)
-       * [Exception Safety](exception-safety.md)
-       * [Poisoning](poisoning.md)
-* [Concurrency](concurrency.md)
-       * [Races](races.md)
-       * [Send and Sync](send-and-sync.md)
-       * [Atomics](atomics.md)
-* [Implementing Vec](vec.md)
-       * [Layout](vec-layout.md)
-       * [Allocating](vec-alloc.md)
-       * [Push and Pop](vec-push-pop.md)
-       * [Deallocating](vec-dealloc.md)
-       * [Deref](vec-deref.md)
-       * [Insert and Remove](vec-insert-remove.md)
-       * [IntoIter](vec-into-iter.md)
-       * [RawVec](vec-raw.md)
-       * [Drain](vec-drain.md)
-       * [Handling Zero-Sized Types](vec-zsts.md)
-       * [Final Code](vec-final.md)
-* [Implementing Arc and Mutex](arc-and-mutex.md)
diff --git a/src/doc/nomicon/src/arc-and-mutex.md b/src/doc/nomicon/src/arc-and-mutex.md
deleted file mode 100644 (file)
index fedc7b8..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# Implementing Arc and Mutex
-
-Knowing the theory is all fine and good, but the *best* way to understand
-something is to use it. To better understand atomics and interior mutability,
-we'll be implementing versions of the standard library's Arc and Mutex types.
-
-TODO: ALL OF THIS OMG
diff --git a/src/doc/nomicon/src/atomics.md b/src/doc/nomicon/src/atomics.md
deleted file mode 100644 (file)
index e9ed21a..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-# Atomics
-
-Rust pretty blatantly just inherits C11's memory model for atomics. This is not
-due to this model being particularly excellent or easy to understand. Indeed,
-this model is quite complex and known to have [several flaws][C11-busted].
-Rather, it is a pragmatic concession to the fact that *everyone* is pretty bad
-at modeling atomics. At very least, we can benefit from existing tooling and
-research around C.
-
-Trying to fully explain the model in this book is fairly hopeless. It's defined
-in terms of madness-inducing causality graphs that require a full book to
-properly understand in a practical way. If you want all the nitty-gritty
-details, you should check out [C's specification (Section 7.17)][C11-model].
-Still, we'll try to cover the basics and some of the problems Rust developers
-face.
-
-The C11 memory model is fundamentally about trying to bridge the gap between the
-semantics we want, the optimizations compilers want, and the inconsistent chaos
-our hardware wants. *We* would like to just write programs and have them do
-exactly what we said but, you know, fast. Wouldn't that be great?
-
-
-
-
-# Compiler Reordering
-
-Compilers fundamentally want to be able to do all sorts of complicated
-transformations to reduce data dependencies and eliminate dead code. In
-particular, they may radically change the actual order of events, or make events
-never occur! If we write something like
-
-```rust,ignore
-x = 1;
-y = 3;
-x = 2;
-```
-
-The compiler may conclude that it would be best if your program did
-
-```rust,ignore
-x = 2;
-y = 3;
-```
-
-This has inverted the order of events and completely eliminated one event.
-From a single-threaded perspective this is completely unobservable: after all
-the statements have executed we are in exactly the same state. But if our
-program is multi-threaded, we may have been relying on `x` to actually be
-assigned to 1 before `y` was assigned. We would like the compiler to be
-able to make these kinds of optimizations, because they can seriously improve
-performance. On the other hand, we'd also like to be able to depend on our
-program *doing the thing we said*.
-
-
-
-
-# Hardware Reordering
-
-On the other hand, even if the compiler totally understood what we wanted and
-respected our wishes, our hardware might instead get us in trouble. Trouble
-comes from CPUs in the form of memory hierarchies. There is indeed a global
-shared memory space somewhere in your hardware, but from the perspective of each
-CPU core it is *so very far away* and *so very slow*. Each CPU would rather work
-with its local cache of the data and only go through all the anguish of
-talking to shared memory only when it doesn't actually have that memory in
-cache.
-
-After all, that's the whole point of the cache, right? If every read from the
-cache had to run back to shared memory to double check that it hadn't changed,
-what would the point be? The end result is that the hardware doesn't guarantee
-that events that occur in the same order on *one* thread, occur in the same
-order on *another* thread. To guarantee this, we must issue special instructions
-to the CPU telling it to be a bit less smart.
-
-For instance, say we convince the compiler to emit this logic:
-
-```text
-initial state: x = 0, y = 1
-
-THREAD 1        THREAD2
-y = 3;          if x == 1 {
-x = 1;              y *= 2;
-                }
-```
-
-Ideally this program has 2 possible final states:
-
-* `y = 3`: (thread 2 did the check before thread 1 completed)
-* `y = 6`: (thread 2 did the check after thread 1 completed)
-
-However there's a third potential state that the hardware enables:
-
-* `y = 2`: (thread 2 saw `x = 1`, but not `y = 3`, and then overwrote `y = 3`)
-
-It's worth noting that different kinds of CPU provide different guarantees. It
-is common to separate hardware into two categories: strongly-ordered and weakly-
-ordered. Most notably x86/64 provides strong ordering guarantees, while ARM
-provides weak ordering guarantees. This has two consequences for concurrent
-programming:
-
-* Asking for stronger guarantees on strongly-ordered hardware may be cheap or
-  even free because they already provide strong guarantees unconditionally.
-  Weaker guarantees may only yield performance wins on weakly-ordered hardware.
-
-* Asking for guarantees that are too weak on strongly-ordered hardware is
-  more likely to *happen* to work, even though your program is strictly
-  incorrect. If possible, concurrent algorithms should be tested on
-  weakly-ordered hardware.
-
-
-
-
-
-# Data Accesses
-
-The C11 memory model attempts to bridge the gap by allowing us to talk about the
-*causality* of our program. Generally, this is by establishing a *happens
-before* relationship between parts of the program and the threads that are
-running them. This gives the hardware and compiler room to optimize the program
-more aggressively where a strict happens-before relationship isn't established,
-but forces them to be more careful where one is established. The way we
-communicate these relationships are through *data accesses* and *atomic
-accesses*.
-
-Data accesses are the bread-and-butter of the programming world. They are
-fundamentally unsynchronized and compilers are free to aggressively optimize
-them. In particular, data accesses are free to be reordered by the compiler on
-the assumption that the program is single-threaded. The hardware is also free to
-propagate the changes made in data accesses to other threads as lazily and
-inconsistently as it wants. Most critically, data accesses are how data races
-happen. Data accesses are very friendly to the hardware and compiler, but as
-we've seen they offer *awful* semantics to try to write synchronized code with.
-Actually, that's too weak.
-
-**It is literally impossible to write correct synchronized code using only data
-accesses.**
-
-Atomic accesses are how we tell the hardware and compiler that our program is
-multi-threaded. Each atomic access can be marked with an *ordering* that
-specifies what kind of relationship it establishes with other accesses. In
-practice, this boils down to telling the compiler and hardware certain things
-they *can't* do. For the compiler, this largely revolves around re-ordering of
-instructions. For the hardware, this largely revolves around how writes are
-propagated to other threads. The set of orderings Rust exposes are:
-
-* Sequentially Consistent (SeqCst)
-* Release
-* Acquire
-* Relaxed
-
-(Note: We explicitly do not expose the C11 *consume* ordering)
-
-TODO: negative reasoning vs positive reasoning? TODO: "can't forget to
-synchronize"
-
-
-
-# Sequentially Consistent
-
-Sequentially Consistent is the most powerful of all, implying the restrictions
-of all other orderings. Intuitively, a sequentially consistent operation
-cannot be reordered: all accesses on one thread that happen before and after a
-SeqCst access stay before and after it. A data-race-free program that uses
-only sequentially consistent atomics and data accesses has the very nice
-property that there is a single global execution of the program's instructions
-that all threads agree on. This execution is also particularly nice to reason
-about: it's just an interleaving of each thread's individual executions. This
-does not hold if you start using the weaker atomic orderings.
-
-The relative developer-friendliness of sequential consistency doesn't come for
-free. Even on strongly-ordered platforms sequential consistency involves
-emitting memory fences.
-
-In practice, sequential consistency is rarely necessary for program correctness.
-However sequential consistency is definitely the right choice if you're not
-confident about the other memory orders. Having your program run a bit slower
-than it needs to is certainly better than it running incorrectly! It's also
-mechanically trivial to downgrade atomic operations to have a weaker
-consistency later on. Just change `SeqCst` to `Relaxed` and you're done! Of
-course, proving that this transformation is *correct* is a whole other matter.
-
-
-
-
-# Acquire-Release
-
-Acquire and Release are largely intended to be paired. Their names hint at their
-use case: they're perfectly suited for acquiring and releasing locks, and
-ensuring that critical sections don't overlap.
-
-Intuitively, an acquire access ensures that every access after it stays after
-it. However operations that occur before an acquire are free to be reordered to
-occur after it. Similarly, a release access ensures that every access before it
-stays before it. However operations that occur after a release are free to be
-reordered to occur before it.
-
-When thread A releases a location in memory and then thread B subsequently
-acquires *the same* location in memory, causality is established. Every write
-that happened before A's release will be observed by B after its release.
-However no causality is established with any other threads. Similarly, no
-causality is established if A and B access *different* locations in memory.
-
-Basic use of release-acquire is therefore simple: you acquire a location of
-memory to begin the critical section, and then release that location to end it.
-For instance, a simple spinlock might look like:
-
-```rust
-use std::sync::Arc;
-use std::sync::atomic::{AtomicBool, Ordering};
-use std::thread;
-
-fn main() {
-    let lock = Arc::new(AtomicBool::new(false)); // value answers "am I locked?"
-
-    // ... distribute lock to threads somehow ...
-
-    // Try to acquire the lock by setting it to true
-    while lock.compare_and_swap(false, true, Ordering::Acquire) { }
-    // broke out of the loop, so we successfully acquired the lock!
-
-    // ... scary data accesses ...
-
-    // ok we're done, release the lock
-    lock.store(false, Ordering::Release);
-}
-```
-
-On strongly-ordered platforms most accesses have release or acquire semantics,
-making release and acquire often totally free. This is not the case on
-weakly-ordered platforms.
-
-
-
-
-# Relaxed
-
-Relaxed accesses are the absolute weakest. They can be freely re-ordered and
-provide no happens-before relationship. Still, relaxed operations are still
-atomic. That is, they don't count as data accesses and any read-modify-write
-operations done to them occur atomically. Relaxed operations are appropriate for
-things that you definitely want to happen, but don't particularly otherwise care
-about. For instance, incrementing a counter can be safely done by multiple
-threads using a relaxed `fetch_add` if you're not using the counter to
-synchronize any other accesses.
-
-There's rarely a benefit in making an operation relaxed on strongly-ordered
-platforms, since they usually provide release-acquire semantics anyway. However
-relaxed operations can be cheaper on weakly-ordered platforms.
-
-
-
-
-
-[C11-busted]: http://plv.mpi-sws.org/c11comp/popl15.pdf
-[C11-model]: http://www.open-std.org/jtc1/sc22/wg14/www/standards.html#9899
diff --git a/src/doc/nomicon/src/borrow-splitting.md b/src/doc/nomicon/src/borrow-splitting.md
deleted file mode 100644 (file)
index 28ddb50..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-# Splitting Borrows
-
-The mutual exclusion property of mutable references can be very limiting when
-working with a composite structure. The borrow checker understands some basic
-stuff, but will fall over pretty easily. It does understand structs
-sufficiently to know that it's possible to borrow disjoint fields of a struct
-simultaneously. So this works today:
-
-```rust
-struct Foo {
-    a: i32,
-    b: i32,
-    c: i32,
-}
-
-let mut x = Foo {a: 0, b: 0, c: 0};
-let a = &mut x.a;
-let b = &mut x.b;
-let c = &x.c;
-*b += 1;
-let c2 = &x.c;
-*a += 10;
-println!("{} {} {} {}", a, b, c, c2);
-```
-
-However borrowck doesn't understand arrays or slices in any way, so this doesn't
-work:
-
-```rust,ignore
-let mut x = [1, 2, 3];
-let a = &mut x[0];
-let b = &mut x[1];
-println!("{} {}", a, b);
-```
-
-```text
-<anon>:4:14: 4:18 error: cannot borrow `x[..]` as mutable more than once at a time
-<anon>:4 let b = &mut x[1];
-                      ^~~~
-<anon>:3:14: 3:18 note: previous borrow of `x[..]` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `x[..]` until the borrow ends
-<anon>:3 let a = &mut x[0];
-                      ^~~~
-<anon>:6:2: 6:2 note: previous borrow ends here
-<anon>:1 fn main() {
-<anon>:2 let mut x = [1, 2, 3];
-<anon>:3 let a = &mut x[0];
-<anon>:4 let b = &mut x[1];
-<anon>:5 println!("{} {}", a, b);
-<anon>:6 }
-         ^
-error: aborting due to 2 previous errors
-```
-
-While it was plausible that borrowck could understand this simple case, it's
-pretty clearly hopeless for borrowck to understand disjointness in general
-container types like a tree, especially if distinct keys actually *do* map
-to the same value.
-
-In order to "teach" borrowck that what we're doing is ok, we need to drop down
-to unsafe code. For instance, mutable slices expose a `split_at_mut` function
-that consumes the slice and returns two mutable slices. One for everything to
-the left of the index, and one for everything to the right. Intuitively we know
-this is safe because the slices don't overlap, and therefore alias. However
-the implementation requires some unsafety:
-
-```rust,ignore
-fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
-    let len = self.len();
-    let ptr = self.as_mut_ptr();
-    assert!(mid <= len);
-    unsafe {
-        (from_raw_parts_mut(ptr, mid),
-         from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
-    }
-}
-```
-
-This is actually a bit subtle. So as to avoid ever making two `&mut`'s to the
-same value, we explicitly construct brand-new slices through raw pointers.
-
-However more subtle is how iterators that yield mutable references work.
-The iterator trait is defined as follows:
-
-```rust
-trait Iterator {
-    type Item;
-
-    fn next(&mut self) -> Option<Self::Item>;
-}
-```
-
-Given this definition, Self::Item has *no* connection to `self`. This means that
-we can call `next` several times in a row, and hold onto all the results
-*concurrently*. This is perfectly fine for by-value iterators, which have
-exactly these semantics. It's also actually fine for shared references, as they
-admit arbitrarily many references to the same thing (although the iterator needs
-to be a separate object from the thing being shared).
-
-But mutable references make this a mess. At first glance, they might seem
-completely incompatible with this API, as it would produce multiple mutable
-references to the same object!
-
-However it actually *does* work, exactly because iterators are one-shot objects.
-Everything an IterMut yields will be yielded at most once, so we don't
-actually ever yield multiple mutable references to the same piece of data.
-
-Perhaps surprisingly, mutable iterators don't require unsafe code to be
-implemented for many types!
-
-For instance here's a singly linked list:
-
-```rust
-# fn main() {}
-type Link<T> = Option<Box<Node<T>>>;
-
-struct Node<T> {
-    elem: T,
-    next: Link<T>,
-}
-
-pub struct LinkedList<T> {
-    head: Link<T>,
-}
-
-pub struct IterMut<'a, T: 'a>(Option<&'a mut Node<T>>);
-
-impl<T> LinkedList<T> {
-    fn iter_mut(&mut self) -> IterMut<T> {
-        IterMut(self.head.as_mut().map(|node| &mut **node))
-    }
-}
-
-impl<'a, T> Iterator for IterMut<'a, T> {
-    type Item = &'a mut T;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.0.take().map(|node| {
-            self.0 = node.next.as_mut().map(|node| &mut **node);
-            &mut node.elem
-        })
-    }
-}
-```
-
-Here's a mutable slice:
-
-```rust
-# fn main() {}
-use std::mem;
-
-pub struct IterMut<'a, T: 'a>(&'a mut[T]);
-
-impl<'a, T> Iterator for IterMut<'a, T> {
-    type Item = &'a mut T;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        let slice = mem::replace(&mut self.0, &mut []);
-        if slice.is_empty() { return None; }
-
-        let (l, r) = slice.split_at_mut(1);
-        self.0 = r;
-        l.get_mut(0)
-    }
-}
-
-impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
-    fn next_back(&mut self) -> Option<Self::Item> {
-        let slice = mem::replace(&mut self.0, &mut []);
-        if slice.is_empty() { return None; }
-
-        let new_len = slice.len() - 1;
-        let (l, r) = slice.split_at_mut(new_len);
-        self.0 = l;
-        r.get_mut(0)
-    }
-}
-```
-
-And here's a binary tree:
-
-```rust
-# fn main() {}
-use std::collections::VecDeque;
-
-type Link<T> = Option<Box<Node<T>>>;
-
-struct Node<T> {
-    elem: T,
-    left: Link<T>,
-    right: Link<T>,
-}
-
-pub struct Tree<T> {
-    root: Link<T>,
-}
-
-struct NodeIterMut<'a, T: 'a> {
-    elem: Option<&'a mut T>,
-    left: Option<&'a mut Node<T>>,
-    right: Option<&'a mut Node<T>>,
-}
-
-enum State<'a, T: 'a> {
-    Elem(&'a mut T),
-    Node(&'a mut Node<T>),
-}
-
-pub struct IterMut<'a, T: 'a>(VecDeque<NodeIterMut<'a, T>>);
-
-impl<T> Tree<T> {
-    pub fn iter_mut(&mut self) -> IterMut<T> {
-        let mut deque = VecDeque::new();
-        self.root.as_mut().map(|root| deque.push_front(root.iter_mut()));
-        IterMut(deque)
-    }
-}
-
-impl<T> Node<T> {
-    pub fn iter_mut(&mut self) -> NodeIterMut<T> {
-        NodeIterMut {
-            elem: Some(&mut self.elem),
-            left: self.left.as_mut().map(|node| &mut **node),
-            right: self.right.as_mut().map(|node| &mut **node),
-        }
-    }
-}
-
-
-impl<'a, T> Iterator for NodeIterMut<'a, T> {
-    type Item = State<'a, T>;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        match self.left.take() {
-            Some(node) => Some(State::Node(node)),
-            None => match self.elem.take() {
-                Some(elem) => Some(State::Elem(elem)),
-                None => match self.right.take() {
-                    Some(node) => Some(State::Node(node)),
-                    None => None,
-                }
-            }
-        }
-    }
-}
-
-impl<'a, T> DoubleEndedIterator for NodeIterMut<'a, T> {
-    fn next_back(&mut self) -> Option<Self::Item> {
-        match self.right.take() {
-            Some(node) => Some(State::Node(node)),
-            None => match self.elem.take() {
-                Some(elem) => Some(State::Elem(elem)),
-                None => match self.left.take() {
-                    Some(node) => Some(State::Node(node)),
-                    None => None,
-                }
-            }
-        }
-    }
-}
-
-impl<'a, T> Iterator for IterMut<'a, T> {
-    type Item = &'a mut T;
-    fn next(&mut self) -> Option<Self::Item> {
-        loop {
-            match self.0.front_mut().and_then(|node_it| node_it.next()) {
-                Some(State::Elem(elem)) => return Some(elem),
-                Some(State::Node(node)) => self.0.push_front(node.iter_mut()),
-                None => if let None = self.0.pop_front() { return None },
-            }
-        }
-    }
-}
-
-impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
-    fn next_back(&mut self) -> Option<Self::Item> {
-        loop {
-            match self.0.back_mut().and_then(|node_it| node_it.next_back()) {
-                Some(State::Elem(elem)) => return Some(elem),
-                Some(State::Node(node)) => self.0.push_back(node.iter_mut()),
-                None => if let None = self.0.pop_back() { return None },
-            }
-        }
-    }
-}
-```
-
-All of these are completely safe and work on stable Rust! This ultimately
-falls out of the simple struct case we saw before: Rust understands that you
-can safely split a mutable reference into subfields. We can then encode
-permanently consuming a reference via Options (or in the case of slices,
-replacing with an empty slice).
diff --git a/src/doc/nomicon/src/casts.md b/src/doc/nomicon/src/casts.md
deleted file mode 100644 (file)
index 31b7858..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-# Casts
-
-Casts are a superset of coercions: every coercion can be explicitly
-invoked via a cast. However some conversions require a cast.
-While coercions are pervasive and largely harmless, these "true casts"
-are rare and potentially dangerous. As such, casts must be explicitly invoked
-using the `as` keyword: `expr as Type`.
-
-True casts generally revolve around raw pointers and the primitive numeric
-types. Even though they're dangerous, these casts are infallible at runtime.
-If a cast triggers some subtle corner case no indication will be given that
-this occurred. The cast will simply succeed. That said, casts must be valid
-at the type level, or else they will be prevented statically. For instance,
-`7u8 as bool` will not compile.
-
-That said, casts aren't `unsafe` because they generally can't violate memory
-safety *on their own*. For instance, converting an integer to a raw pointer can
-very easily lead to terrible things. However the act of creating the pointer
-itself is safe, because actually using a raw pointer is already marked as
-`unsafe`.
-
-Here's an exhaustive list of all the true casts. For brevity, we will use `*`
-to denote either a `*const` or `*mut`, and `integer` to denote any integral
-primitive:
-
- * `*T as *U` where `T, U: Sized`
- * `*T as *U` TODO: explain unsized situation
- * `*T as integer`
- * `integer as *T`
- * `number as number`
- * `C-like-enum as integer`
- * `bool as integer`
- * `char as integer`
- * `u8 as char`
- * `&[T; n] as *const T`
- * `fn as *T` where `T: Sized`
- * `fn as integer`
-
-Note that lengths are not adjusted when casting raw slices -
-`*const [u16] as *const [u8]` creates a slice that only includes
-half of the original memory.
-
-Casting is not transitive, that is, even if `e as U1 as U2` is a valid
-expression, `e as U2` is not necessarily so.
-
-For numeric casts, there are quite a few cases to consider:
-
-* casting between two integers of the same size (e.g. i32 -> u32) is a no-op
-* casting from a larger integer to a smaller integer (e.g. u32 -> u8) will
-  truncate
-* casting from a smaller integer to a larger integer (e.g. u8 -> u32) will
-    * zero-extend if the source is unsigned
-    * sign-extend if the source is signed
-* casting from a float to an integer will round the float towards zero
-    * **[NOTE: currently this will cause Undefined Behavior if the rounded
-      value cannot be represented by the target integer type][float-int]**.
-      This includes Inf and NaN. This is a bug and will be fixed.
-* casting from an integer to float will produce the floating point
-  representation of the integer, rounded if necessary (rounding strategy
-  unspecified)
-* casting from an f32 to an f64 is perfect and lossless
-* casting from an f64 to an f32 will produce the closest possible value
-  (rounding strategy unspecified)
-    * **[NOTE: currently this will cause Undefined Behavior if the value
-      is finite but larger or smaller than the largest or smallest finite
-      value representable by f32][float-float]**. This is a bug and will
-      be fixed.
-
-
-[float-int]: https://github.com/rust-lang/rust/issues/10184
-[float-float]: https://github.com/rust-lang/rust/issues/15536
diff --git a/src/doc/nomicon/src/chapter_1.md b/src/doc/nomicon/src/chapter_1.md
deleted file mode 100644 (file)
index b743fda..0000000
+++ /dev/null
@@ -1 +0,0 @@
-# Chapter 1
diff --git a/src/doc/nomicon/src/checked-uninit.md b/src/doc/nomicon/src/checked-uninit.md
deleted file mode 100644 (file)
index 4423404..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-# Checked Uninitialized Memory
-
-Like C, all stack variables in Rust are uninitialized until a value is
-explicitly assigned to them. Unlike C, Rust statically prevents you from ever
-reading them until you do:
-
-```rust,ignore
-fn main() {
-    let x: i32;
-    println!("{}", x);
-}
-```
-
-```text
-src/main.rs:3:20: 3:21 error: use of possibly uninitialized variable: `x`
-src/main.rs:3     println!("{}", x);
-                                 ^
-```
-
-This is based off of a basic branch analysis: every branch must assign a value
-to `x` before it is first used. Interestingly, Rust doesn't require the variable
-to be mutable to perform a delayed initialization if every branch assigns
-exactly once. However the analysis does not take advantage of constant analysis
-or anything like that. So this compiles:
-
-```rust
-fn main() {
-    let x: i32;
-
-    if true {
-        x = 1;
-    } else {
-        x = 2;
-    }
-
-    println!("{}", x);
-}
-```
-
-but this doesn't:
-
-```rust,ignore
-fn main() {
-    let x: i32;
-    if true {
-        x = 1;
-    }
-    println!("{}", x);
-}
-```
-
-```text
-src/main.rs:6:17: 6:18 error: use of possibly uninitialized variable: `x`
-src/main.rs:6   println!("{}", x);
-```
-
-while this does:
-
-```rust
-fn main() {
-    let x: i32;
-    if true {
-        x = 1;
-        println!("{}", x);
-    }
-    // Don't care that there are branches where it's not initialized
-    // since we don't use the value in those branches
-}
-```
-
-Of course, while the analysis doesn't consider actual values, it does
-have a relatively sophisticated understanding of dependencies and control
-flow. For instance, this works:
-
-```rust
-let x: i32;
-
-loop {
-    // Rust doesn't understand that this branch will be taken unconditionally,
-    // because it relies on actual values.
-    if true {
-        // But it does understand that it will only be taken once because
-        // we unconditionally break out of it. Therefore `x` doesn't
-        // need to be marked as mutable.
-        x = 0;
-        break;
-    }
-}
-// It also knows that it's impossible to get here without reaching the break.
-// And therefore that `x` must be initialized here!
-println!("{}", x);
-```
-
-If a value is moved out of a variable, that variable becomes logically
-uninitialized if the type of the value isn't Copy. That is:
-
-```rust
-fn main() {
-    let x = 0;
-    let y = Box::new(0);
-    let z1 = x; // x is still valid because i32 is Copy
-    let z2 = y; // y is now logically uninitialized because Box isn't Copy
-}
-```
-
-However reassigning `y` in this example *would* require `y` to be marked as
-mutable, as a Safe Rust program could observe that the value of `y` changed:
-
-```rust
-fn main() {
-    let mut y = Box::new(0);
-    let z = y; // y is now logically uninitialized because Box isn't Copy
-    y = Box::new(1); // reinitialize y
-}
-```
-
-Otherwise it's like `y` is a brand new variable.
diff --git a/src/doc/nomicon/src/coercions.md b/src/doc/nomicon/src/coercions.md
deleted file mode 100644 (file)
index 1a51bb5..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-# Coercions
-
-Types can implicitly be coerced to change in certain contexts. These changes are
-generally just *weakening* of types, largely focused around pointers and
-lifetimes. They mostly exist to make Rust "just work" in more cases, and are
-largely harmless.
-
-Here's all the kinds of coercion:
-
-Coercion is allowed between the following types:
-
-* Transitivity: `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to
-  `T_3`
-* Pointer Weakening:
-    * `&mut T` to `&T`
-    * `*mut T` to `*const T`
-    * `&T` to `*const T`
-    * `&mut T` to `*mut T`
-* Unsizing: `T` to `U` if `T` implements `CoerceUnsized<U>`
-* Deref coercion: Expression `&x` of type `&T` to `&*x` of type `&U` if `T` derefs to `U` (i.e. `T: Deref<Target=U>`)
-
-`CoerceUnsized<Pointer<U>> for Pointer<T> where T: Unsize<U>` is implemented
-for all pointer types (including smart pointers like Box and Rc). Unsize is
-only implemented automatically, and enables the following transformations:
-
-* `[T; n]` => `[T]`
-* `T` => `Trait` where `T: Trait`
-* `Foo<..., T, ...>` => `Foo<..., U, ...>` where:
-    * `T: Unsize<U>`
-    * `Foo` is a struct
-    * Only the last field of `Foo` has type involving `T`
-    * `T` is not part of the type of any other fields
-    * `Bar<T>: Unsize<Bar<U>>`, if the last field of `Foo` has type `Bar<T>`
-
-Coercions occur at a *coercion site*. Any location that is explicitly typed
-will cause a coercion to its type. If inference is necessary, the coercion will
-not be performed. Exhaustively, the coercion sites for an expression `e` to
-type `U` are:
-
-* let statements, statics, and consts: `let x: U = e`
-* Arguments to functions: `takes_a_U(e)`
-* Any expression that will be returned: `fn foo() -> U { e }`
-* Struct literals: `Foo { some_u: e }`
-* Array literals: `let x: [U; 10] = [e, ..]`
-* Tuple literals: `let x: (U, ..) = (e, ..)`
-* The last expression in a block: `let x: U = { ..; e }`
-
-Note that we do not perform coercions when matching traits (except for
-receivers, see below). If there is an impl for some type `U` and `T` coerces to
-`U`, that does not constitute an implementation for `T`. For example, the
-following will not type check, even though it is OK to coerce `t` to `&T` and
-there is an impl for `&T`:
-
-```rust,ignore
-trait Trait {}
-
-fn foo<X: Trait>(t: X) {}
-
-impl<'a> Trait for &'a i32 {}
-
-
-fn main() {
-    let t: &mut i32 = &mut 0;
-    foo(t);
-}
-```
-
-```text
-<anon>:10:5: 10:8 error: the trait bound `&mut i32 : Trait` is not satisfied [E0277]
-<anon>:10     foo(t);
-              ^~~
-```
diff --git a/src/doc/nomicon/src/concurrency.md b/src/doc/nomicon/src/concurrency.md
deleted file mode 100644 (file)
index 6205199..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# Concurrency and Parallelism
-
-Rust as a language doesn't *really* have an opinion on how to do concurrency or
-parallelism. The standard library exposes OS threads and blocking sys-calls
-because everyone has those, and they're uniform enough that you can provide
-an abstraction over them in a relatively uncontroversial way. Message passing,
-green threads, and async APIs are all diverse enough that any abstraction over
-them tends to involve trade-offs that we weren't willing to commit to for 1.0.
-
-However the way Rust models concurrency makes it relatively easy to design your own
-concurrency paradigm as a library and have everyone else's code Just Work
-with yours. Just require the right lifetimes and Send and Sync where appropriate
-and you're off to the races. Or rather, off to the... not... having... races.
diff --git a/src/doc/nomicon/src/constructors.md b/src/doc/nomicon/src/constructors.md
deleted file mode 100644 (file)
index b79e72d..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-# Constructors
-
-There is exactly one way to create an instance of a user-defined type: name it,
-and initialize all its fields at once:
-
-```rust
-struct Foo {
-    a: u8,
-    b: u32,
-    c: bool,
-}
-
-enum Bar {
-    X(u32),
-    Y(bool),
-}
-
-struct Unit;
-
-let foo = Foo { a: 0, b: 1, c: false };
-let bar = Bar::X(0);
-let empty = Unit;
-```
-
-That's it. Every other way you make an instance of a type is just calling a
-totally vanilla function that does some stuff and eventually bottoms out to The
-One True Constructor.
-
-Unlike C++, Rust does not come with a slew of built-in kinds of constructor.
-There are no Copy, Default, Assignment, Move, or whatever constructors. The
-reasons for this are varied, but it largely boils down to Rust's philosophy of
-*being explicit*.
-
-Move constructors are meaningless in Rust because we don't enable types to
-"care" about their location in memory. Every type must be ready for it to be
-blindly memcopied to somewhere else in memory. This means pure on-the-stack-but-
-still-movable intrusive linked lists are simply not happening in Rust (safely).
-
-Assignment and copy constructors similarly don't exist because move semantics
-are the only semantics in Rust. At most `x = y` just moves the bits of y into
-the x variable. Rust does provide two facilities for providing C++'s copy-
-oriented semantics: `Copy` and `Clone`. Clone is our moral equivalent of a copy
-constructor, but it's never implicitly invoked. You have to explicitly call
-`clone` on an element you want to be cloned. Copy is a special case of Clone
-where the implementation is just "copy the bits". Copy types *are* implicitly
-cloned whenever they're moved, but because of the definition of Copy this just
-means not treating the old copy as uninitialized -- a no-op.
-
-While Rust provides a `Default` trait for specifying the moral equivalent of a
-default constructor, it's incredibly rare for this trait to be used. This is
-because variables [aren't implicitly initialized][uninit]. Default is basically
-only useful for generic programming. In concrete contexts, a type will provide a
-static `new` method for any kind of "default" constructor. This has no relation
-to `new` in other languages and has no special meaning. It's just a naming
-convention.
-
-TODO: talk about "placement new"?
-
-[uninit]: uninitialized.html
diff --git a/src/doc/nomicon/src/conversions.md b/src/doc/nomicon/src/conversions.md
deleted file mode 100644 (file)
index 388d003..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-# Type Conversions
-
-At the end of the day, everything is just a pile of bits somewhere, and type
-systems are just there to help us use those bits right. There are two common
-problems with typing bits: needing to reinterpret those exact bits as a
-different type, and needing to change the bits to have equivalent meaning for
-a different type. Because Rust encourages encoding important properties in the
-type system, these problems are incredibly pervasive. As such, Rust
-consequently gives you several ways to solve them.
-
-First we'll look at the ways that Safe Rust gives you to reinterpret values.
-The most trivial way to do this is to just destructure a value into its
-constituent parts and then build a new type out of them. e.g.
-
-```rust
-struct Foo {
-    x: u32,
-    y: u16,
-}
-
-struct Bar {
-    a: u32,
-    b: u16,
-}
-
-fn reinterpret(foo: Foo) -> Bar {
-    let Foo { x, y } = foo;
-    Bar { a: x, b: y }
-}
-```
-
-But this is, at best, annoying. For common conversions, Rust provides
-more ergonomic alternatives.
-
diff --git a/src/doc/nomicon/src/data.md b/src/doc/nomicon/src/data.md
deleted file mode 100644 (file)
index bf202ad..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# Data Representation in Rust
-
-Low-level programming cares a lot about data layout. It's a big deal. It also
-pervasively influences the rest of the language, so we're going to start by
-digging into how data is represented in Rust.
diff --git a/src/doc/nomicon/src/destructors.md b/src/doc/nomicon/src/destructors.md
deleted file mode 100644 (file)
index 8c395fe..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-# Destructors
-
-What the language *does* provide is full-blown automatic destructors through the
-`Drop` trait, which provides the following method:
-
-```rust,ignore
-fn drop(&mut self);
-```
-
-This method gives the type time to somehow finish what it was doing.
-
-**After `drop` is run, Rust will recursively try to drop all of the fields
-of `self`.**
-
-This is a convenience feature so that you don't have to write "destructor
-boilerplate" to drop children. If a struct has no special logic for being
-dropped other than dropping its children, then it means `Drop` doesn't need to
-be implemented at all!
-
-**There is no stable way to prevent this behavior in Rust 1.0.**
-
-Note that taking `&mut self` means that even if you could suppress recursive
-Drop, Rust will prevent you from e.g. moving fields out of self. For most types,
-this is totally fine.
-
-For instance, a custom implementation of `Box` might write `Drop` like this:
-
-```rust
-#![feature(alloc, heap_api, unique)]
-
-extern crate alloc;
-
-use std::ptr::{drop_in_place, Unique};
-use std::mem;
-
-use alloc::heap;
-
-struct Box<T>{ ptr: Unique<T> }
-
-impl<T> Drop for Box<T> {
-    fn drop(&mut self) {
-        unsafe {
-            drop_in_place(*self.ptr);
-            heap::deallocate((*self.ptr) as *mut u8,
-                             mem::size_of::<T>(),
-                             mem::align_of::<T>());
-        }
-    }
-}
-# fn main() {}
-```
-
-and this works fine because when Rust goes to drop the `ptr` field it just sees
-a [Unique] that has no actual `Drop` implementation. Similarly nothing can
-use-after-free the `ptr` because when drop exits, it becomes inaccessible.
-
-However this wouldn't work:
-
-```rust
-#![feature(alloc, heap_api, unique)]
-
-extern crate alloc;
-
-use std::ptr::{drop_in_place, Unique};
-use std::mem;
-
-use alloc::heap;
-
-struct Box<T>{ ptr: Unique<T> }
-
-impl<T> Drop for Box<T> {
-    fn drop(&mut self) {
-        unsafe {
-            drop_in_place(*self.ptr);
-            heap::deallocate((*self.ptr) as *mut u8,
-                             mem::size_of::<T>(),
-                             mem::align_of::<T>());
-        }
-    }
-}
-
-struct SuperBox<T> { my_box: Box<T> }
-
-impl<T> Drop for SuperBox<T> {
-    fn drop(&mut self) {
-        unsafe {
-            // Hyper-optimized: deallocate the box's contents for it
-            // without `drop`ing the contents
-            heap::deallocate((*self.my_box.ptr) as *mut u8,
-                             mem::size_of::<T>(),
-                             mem::align_of::<T>());
-        }
-    }
-}
-# fn main() {}
-```
-
-After we deallocate the `box`'s ptr in SuperBox's destructor, Rust will
-happily proceed to tell the box to Drop itself and everything will blow up with
-use-after-frees and double-frees.
-
-Note that the recursive drop behavior applies to all structs and enums
-regardless of whether they implement Drop. Therefore something like
-
-```rust
-struct Boxy<T> {
-    data1: Box<T>,
-    data2: Box<T>,
-    info: u32,
-}
-```
-
-will have its data1 and data2's fields destructors whenever it "would" be
-dropped, even though it itself doesn't implement Drop. We say that such a type
-*needs Drop*, even though it is not itself Drop.
-
-Similarly,
-
-```rust
-enum Link {
-    Next(Box<Link>),
-    None,
-}
-```
-
-will have its inner Box field dropped if and only if an instance stores the
-Next variant.
-
-In general this works really nicely because you don't need to worry about
-adding/removing drops when you refactor your data layout. Still there's
-certainly many valid usecases for needing to do trickier things with
-destructors.
-
-The classic safe solution to overriding recursive drop and allowing moving out
-of Self during `drop` is to use an Option:
-
-```rust
-#![feature(alloc, heap_api, unique)]
-
-extern crate alloc;
-
-use std::ptr::{drop_in_place, Unique};
-use std::mem;
-
-use alloc::heap;
-
-struct Box<T>{ ptr: Unique<T> }
-
-impl<T> Drop for Box<T> {
-    fn drop(&mut self) {
-        unsafe {
-            drop_in_place(*self.ptr);
-            heap::deallocate((*self.ptr) as *mut u8,
-                             mem::size_of::<T>(),
-                             mem::align_of::<T>());
-        }
-    }
-}
-
-struct SuperBox<T> { my_box: Option<Box<T>> }
-
-impl<T> Drop for SuperBox<T> {
-    fn drop(&mut self) {
-        unsafe {
-            // Hyper-optimized: deallocate the box's contents for it
-            // without `drop`ing the contents. Need to set the `box`
-            // field as `None` to prevent Rust from trying to Drop it.
-            let my_box = self.my_box.take().unwrap();
-            heap::deallocate((*my_box.ptr) as *mut u8,
-                             mem::size_of::<T>(),
-                             mem::align_of::<T>());
-            mem::forget(my_box);
-        }
-    }
-}
-# fn main() {}
-```
-
-However this has fairly odd semantics: you're saying that a field that *should*
-always be Some *may* be None, just because that happens in the destructor. Of
-course this conversely makes a lot of sense: you can call arbitrary methods on
-self during the destructor, and this should prevent you from ever doing so after
-deinitializing the field. Not that it will prevent you from producing any other
-arbitrarily invalid state in there.
-
-On balance this is an ok choice. Certainly what you should reach for by default.
-However, in the future we expect there to be a first-class way to announce that
-a field shouldn't be automatically dropped.
-
-[Unique]: phantom-data.html
diff --git a/src/doc/nomicon/src/dot-operator.md b/src/doc/nomicon/src/dot-operator.md
deleted file mode 100644 (file)
index a1fc33b..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# The Dot Operator
-
-The dot operator will perform a lot of magic to convert types. It will perform
-auto-referencing, auto-dereferencing, and coercion until types match.
-
-TODO: steal information from http://stackoverflow.com/questions/28519997/what-are-rusts-exact-auto-dereferencing-rules/28552082#28552082
diff --git a/src/doc/nomicon/src/drop-flags.md b/src/doc/nomicon/src/drop-flags.md
deleted file mode 100644 (file)
index e69264f..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-# Drop Flags
-
-The examples in the previous section introduce an interesting problem for Rust.
-We have seen that it's possible to conditionally initialize, deinitialize, and
-reinitialize locations of memory totally safely. For Copy types, this isn't
-particularly notable since they're just a random pile of bits. However types
-with destructors are a different story: Rust needs to know whether to call a
-destructor whenever a variable is assigned to, or a variable goes out of scope.
-How can it do this with conditional initialization?
-
-Note that this is not a problem that all assignments need worry about. In
-particular, assigning through a dereference unconditionally drops, and assigning
-in a `let` unconditionally doesn't drop:
-
-```
-let mut x = Box::new(0); // let makes a fresh variable, so never need to drop
-let y = &mut x;
-*y = Box::new(1); // Deref assumes the referent is initialized, so always drops
-```
-
-This is only a problem when overwriting a previously initialized variable or
-one of its subfields.
-
-It turns out that Rust actually tracks whether a type should be dropped or not
-*at runtime*. As a variable becomes initialized and uninitialized, a *drop flag*
-for that variable is toggled. When a variable might need to be dropped, this
-flag is evaluated to determine if it should be dropped.
-
-Of course, it is often the case that a value's initialization state can be
-statically known at every point in the program. If this is the case, then the
-compiler can theoretically generate more efficient code! For instance, straight-
-line code has such *static drop semantics*:
-
-```rust
-let mut x = Box::new(0); // x was uninit; just overwrite.
-let mut y = x;           // y was uninit; just overwrite and make x uninit.
-x = Box::new(0);         // x was uninit; just overwrite.
-y = x;                   // y was init; Drop y, overwrite it, and make x uninit!
-                         // y goes out of scope; y was init; Drop y!
-                         // x goes out of scope; x was uninit; do nothing.
-```
-
-Similarly, branched code where all branches have the same behavior with respect
-to initialization has static drop semantics:
-
-```rust
-# let condition = true;
-let mut x = Box::new(0);    // x was uninit; just overwrite.
-if condition {
-    drop(x)                 // x gets moved out; make x uninit.
-} else {
-    println!("{}", x);
-    drop(x)                 // x gets moved out; make x uninit.
-}
-x = Box::new(0);            // x was uninit; just overwrite.
-                            // x goes out of scope; x was init; Drop x!
-```
-
-However code like this *requires* runtime information to correctly Drop:
-
-```rust
-# let condition = true;
-let x;
-if condition {
-    x = Box::new(0);        // x was uninit; just overwrite.
-    println!("{}", x);
-}
-                            // x goes out of scope; x might be uninit;
-                            // check the flag!
-```
-
-Of course, in this case it's trivial to retrieve static drop semantics:
-
-```rust
-# let condition = true;
-if condition {
-    let x = Box::new(0);
-    println!("{}", x);
-}
-```
-
-The drop flags are tracked on the stack and no longer stashed in types that
-implement drop.
diff --git a/src/doc/nomicon/src/dropck.md b/src/doc/nomicon/src/dropck.md
deleted file mode 100644 (file)
index 3903969..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-# Drop Check
-
-We have seen how lifetimes provide us some fairly simple rules for ensuring
-that we never read dangling references. However up to this point we have only ever
-interacted with the *outlives* relationship in an inclusive manner. That is,
-when we talked about `'a: 'b`, it was ok for `'a` to live *exactly* as long as
-`'b`. At first glance, this seems to be a meaningless distinction. Nothing ever
-gets dropped at the same time as another, right? This is why we used the
-following desugaring of `let` statements:
-
-```rust,ignore
-let x;
-let y;
-```
-
-```rust,ignore
-{
-    let x;
-    {
-        let y;
-    }
-}
-```
-
-Each creates its own scope, clearly establishing that one drops before the
-other. However, what if we do the following?
-
-```rust,ignore
-let (x, y) = (vec![], vec![]);
-```
-
-Does either value strictly outlive the other? The answer is in fact *no*,
-neither value strictly outlives the other. Of course, one of x or y will be
-dropped before the other, but the actual order is not specified. Tuples aren't
-special in this regard; composite structures just don't guarantee their
-destruction order as of Rust 1.0.
-
-We *could* specify this for the fields of built-in composites like tuples and
-structs. However, what about something like Vec? Vec has to manually drop its
-elements via pure-library code. In general, anything that implements Drop has
-a chance to fiddle with its innards during its final death knell. Therefore
-the compiler can't sufficiently reason about the actual destruction order
-of the contents of any type that implements Drop.
-
-So why do we care? We care because if the type system isn't careful, it could
-accidentally make dangling pointers. Consider the following simple program:
-
-```rust
-struct Inspector<'a>(&'a u8);
-
-fn main() {
-    let (inspector, days);
-    days = Box::new(1);
-    inspector = Inspector(&days);
-}
-```
-
-This program is totally sound and compiles today. The fact that `days` does
-not *strictly* outlive `inspector` doesn't matter. As long as the `inspector`
-is alive, so is days.
-
-However if we add a destructor, the program will no longer compile!
-
-```rust,ignore
-struct Inspector<'a>(&'a u8);
-
-impl<'a> Drop for Inspector<'a> {
-    fn drop(&mut self) {
-        println!("I was only {} days from retirement!", self.0);
-    }
-}
-
-fn main() {
-    let (inspector, days);
-    days = Box::new(1);
-    inspector = Inspector(&days);
-    // Let's say `days` happens to get dropped first.
-    // Then when Inspector is dropped, it will try to read free'd memory!
-}
-```
-
-```text
-<anon>:12:28: 12:32 error: `days` does not live long enough
-<anon>:12     inspector = Inspector(&days);
-                                     ^~~~
-<anon>:9:11: 15:2 note: reference must be valid for the block at 9:10...
-<anon>:9 fn main() {
-<anon>:10     let (inspector, days);
-<anon>:11     days = Box::new(1);
-<anon>:12     inspector = Inspector(&days);
-<anon>:13     // Let's say `days` happens to get dropped first.
-<anon>:14     // Then when Inspector is dropped, it will try to read free'd memory!
-          ...
-<anon>:10:27: 15:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 10:26
-<anon>:10     let (inspector, days);
-<anon>:11     days = Box::new(1);
-<anon>:12     inspector = Inspector(&days);
-<anon>:13     // Let's say `days` happens to get dropped first.
-<anon>:14     // Then when Inspector is dropped, it will try to read free'd memory!
-<anon>:15 }
-```
-
-Implementing Drop lets the Inspector execute some arbitrary code during its
-death. This means it can potentially observe that types that are supposed to
-live as long as it does actually were destroyed first.
-
-Interestingly, only generic types need to worry about this. If they aren't
-generic, then the only lifetimes they can harbor are `'static`, which will truly
-live *forever*. This is why this problem is referred to as *sound generic drop*.
-Sound generic drop is enforced by the *drop checker*. As of this writing, some
-of the finer details of how the drop checker validates types is totally up in
-the air. However The Big Rule is the subtlety that we have focused on this whole
-section:
-
-**For a generic type to soundly implement drop, its generics arguments must
-strictly outlive it.**
-
-Obeying this rule is (usually) necessary to satisfy the borrow
-checker; obeying it is sufficient but not necessary to be
-sound. That is, if your type obeys this rule then it's definitely
-sound to drop.
-
-The reason that it is not always necessary to satisfy the above rule
-is that some Drop implementations will not access borrowed data even
-though their type gives them the capability for such access.
-
-For example, this variant of the above `Inspector` example will never
-access borrowed data:
-
-```rust,ignore
-struct Inspector<'a>(&'a u8, &'static str);
-
-impl<'a> Drop for Inspector<'a> {
-    fn drop(&mut self) {
-        println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
-    }
-}
-
-fn main() {
-    let (inspector, days);
-    days = Box::new(1);
-    inspector = Inspector(&days, "gadget");
-    // Let's say `days` happens to get dropped first.
-    // Even when Inspector is dropped, its destructor will not access the
-    // borrowed `days`.
-}
-```
-
-Likewise, this variant will also never access borrowed data:
-
-```rust,ignore
-use std::fmt;
-
-struct Inspector<T: fmt::Display>(T, &'static str);
-
-impl<T: fmt::Display> Drop for Inspector<T> {
-    fn drop(&mut self) {
-        println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
-    }
-}
-
-fn main() {
-    let (inspector, days): (Inspector<&u8>, Box<u8>);
-    days = Box::new(1);
-    inspector = Inspector(&days, "gadget");
-    // Let's say `days` happens to get dropped first.
-    // Even when Inspector is dropped, its destructor will not access the
-    // borrowed `days`.
-}
-```
-
-However, *both* of the above variants are rejected by the borrow
-checker during the analysis of `fn main`, saying that `days` does not
-live long enough.
-
-The reason is that the borrow checking analysis of `main` does not
-know about the internals of each Inspector's Drop implementation.  As
-far as the borrow checker knows while it is analyzing `main`, the body
-of an inspector's destructor might access that borrowed data.
-
-Therefore, the drop checker forces all borrowed data in a value to
-strictly outlive that value.
-
-# An Escape Hatch
-
-The precise rules that govern drop checking may be less restrictive in
-the future.
-
-The current analysis is deliberately conservative and trivial; it forces all
-borrowed data in a value to outlive that value, which is certainly sound.
-
-Future versions of the language may make the analysis more precise, to
-reduce the number of cases where sound code is rejected as unsafe.
-This would help address cases such as the two Inspectors above that
-know not to inspect during destruction.
-
-In the meantime, there is an unstable attribute that one can use to
-assert (unsafely) that a generic type's destructor is *guaranteed* to
-not access any expired data, even if its type gives it the capability
-to do so.
-
-That attribute is called `may_dangle` and was introduced in [RFC 1327]
-(https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md).
-To deploy it on the Inspector example from above, we would write:
-
-```rust,ignore
-struct Inspector<'a>(&'a u8, &'static str);
-
-unsafe impl<#[may_dangle] 'a> Drop for Inspector<'a> {
-    fn drop(&mut self) {
-        println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
-    }
-}
-```
-
-Use of this attribute requires the `Drop` impl to be marked `unsafe` because the
-compiler is not checking the implicit assertion that no potentially expired data
-(e.g. `self.0` above) is accessed.
-
-The attribute can be applied to any number of lifetime and type parameters. In
-the following example, we assert that we access no data behind a reference of
-lifetime `'b` and that the only uses of `T` will be moves or drops, but omit
-the attribute from `'a` and `U`, because we do access data with that lifetime
-and that type:
-
-```rust,ignore
-use std::fmt::Display;
-
-struct Inspector<'a, 'b, T, U: Display>(&'a u8, &'b u8, T, U);
-
-unsafe impl<'a, #[may_dangle] 'b, #[may_dangle] T, U: Display> Drop for Inspector<'a, 'b, T, U> {
-    fn drop(&mut self) {
-        println!("Inspector({}, _, _, {})", self.0, self.3);
-    }
-}
-```
-
-It is sometimes obvious that no such access can occur, like the case above.
-However, when dealing with a generic type parameter, such access can
-occur indirectly. Examples of such indirect access are:
-
- * invoking a callback,
- * via a trait method call.
-
-(Future changes to the language, such as impl specialization, may add
-other avenues for such indirect access.)
-
-Here is an example of invoking a callback:
-
-```rust,ignore
-struct Inspector<T>(T, &'static str, Box<for <'r> fn(&'r T) -> String>);
-
-impl<T> Drop for Inspector<T> {
-    fn drop(&mut self) {
-        // The `self.2` call could access a borrow e.g. if `T` is `&'a _`.
-        println!("Inspector({}, {}) unwittingly inspects expired data.",
-                 (self.2)(&self.0), self.1);
-    }
-}
-```
-
-Here is an example of a trait method call:
-
-```rust,ignore
-use std::fmt;
-
-struct Inspector<T: fmt::Display>(T, &'static str);
-
-impl<T: fmt::Display> Drop for Inspector<T> {
-    fn drop(&mut self) {
-        // There is a hidden call to `<T as Display>::fmt` below, which
-        // could access a borrow e.g. if `T` is `&'a _`
-        println!("Inspector({}, {}) unwittingly inspects expired data.",
-                 self.0, self.1);
-    }
-}
-```
-
-And of course, all of these accesses could be further hidden within
-some other method invoked by the destructor, rather than being written
-directly within it.
-
-In all of the above cases where the `&'a u8` is accessed in the
-destructor, adding the `#[may_dangle]`
-attribute makes the type vulnerable to misuse that the borrower
-checker will not catch, inviting havoc. It is better to avoid adding
-the attribute.
-
-# Is that all about drop checker?
-
-It turns out that when writing unsafe code, we generally don't need to
-worry at all about doing the right thing for the drop checker. However there
-is one special case that you need to worry about, which we will look at in
-the next section.
-
diff --git a/src/doc/nomicon/src/exception-safety.md b/src/doc/nomicon/src/exception-safety.md
deleted file mode 100644 (file)
index a3cbc6a..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-# Exception Safety
-
-Although programs should use unwinding sparingly, there's a lot of code that
-*can* panic. If you unwrap a None, index out of bounds, or divide by 0, your
-program will panic. On debug builds, every arithmetic operation can panic
-if it overflows. Unless you are very careful and tightly control what code runs,
-pretty much everything can unwind, and you need to be ready for it.
-
-Being ready for unwinding is often referred to as *exception safety*
-in the broader programming world. In Rust, there are two levels of exception
-safety that one may concern themselves with:
-
-* In unsafe code, we *must* be exception safe to the point of not violating
-  memory safety. We'll call this *minimal* exception safety.
-
-* In safe code, it is *good* to be exception safe to the point of your program
-  doing the right thing. We'll call this *maximal* exception safety.
-
-As is the case in many places in Rust, Unsafe code must be ready to deal with
-bad Safe code when it comes to unwinding. Code that transiently creates
-unsound states must be careful that a panic does not cause that state to be
-used. Generally this means ensuring that only non-panicking code is run while
-these states exist, or making a guard that cleans up the state in the case of
-a panic. This does not necessarily mean that the state a panic witnesses is a
-fully coherent state. We need only guarantee that it's a *safe* state.
-
-Most Unsafe code is leaf-like, and therefore fairly easy to make exception-safe.
-It controls all the code that runs, and most of that code can't panic. However
-it is not uncommon for Unsafe code to work with arrays of temporarily
-uninitialized data while repeatedly invoking caller-provided code. Such code
-needs to be careful and consider exception safety.
-
-
-
-
-
-## Vec::push_all
-
-`Vec::push_all` is a temporary hack to get extending a Vec by a slice reliably
-efficient without specialization. Here's a simple implementation:
-
-```rust,ignore
-impl<T: Clone> Vec<T> {
-    fn push_all(&mut self, to_push: &[T]) {
-        self.reserve(to_push.len());
-        unsafe {
-            // can't overflow because we just reserved this
-            self.set_len(self.len() + to_push.len());
-
-            for (i, x) in to_push.iter().enumerate() {
-                self.ptr().offset(i as isize).write(x.clone());
-            }
-        }
-    }
-}
-```
-
-We bypass `push` in order to avoid redundant capacity and `len` checks on the
-Vec that we definitely know has capacity. The logic is totally correct, except
-there's a subtle problem with our code: it's not exception-safe! `set_len`,
-`offset`, and `write` are all fine; `clone` is the panic bomb we over-looked.
-
-Clone is completely out of our control, and is totally free to panic. If it
-does, our function will exit early with the length of the Vec set too large. If
-the Vec is looked at or dropped, uninitialized memory will be read!
-
-The fix in this case is fairly simple. If we want to guarantee that the values
-we *did* clone are dropped, we can set the `len` every loop iteration. If we
-just want to guarantee that uninitialized memory can't be observed, we can set
-the `len` after the loop.
-
-
-
-
-
-## BinaryHeap::sift_up
-
-Bubbling an element up a heap is a bit more complicated than extending a Vec.
-The pseudocode is as follows:
-
-```text
-bubble_up(heap, index):
-    while index != 0 && heap[index] < heap[parent(index)]:
-        heap.swap(index, parent(index))
-        index = parent(index)
-
-```
-
-A literal transcription of this code to Rust is totally fine, but has an annoying
-performance characteristic: the `self` element is swapped over and over again
-uselessly. We would rather have the following:
-
-```text
-bubble_up(heap, index):
-    let elem = heap[index]
-    while index != 0 && elem < heap[parent(index)]:
-        heap[index] = heap[parent(index)]
-        index = parent(index)
-    heap[index] = elem
-```
-
-This code ensures that each element is copied as little as possible (it is in
-fact necessary that elem be copied twice in general). However it now exposes
-some exception safety trouble! At all times, there exists two copies of one
-value. If we panic in this function something will be double-dropped.
-Unfortunately, we also don't have full control of the code: that comparison is
-user-defined!
-
-Unlike Vec, the fix isn't as easy here. One option is to break the user-defined
-code and the unsafe code into two separate phases:
-
-```text
-bubble_up(heap, index):
-    let end_index = index;
-    while end_index != 0 && heap[end_index] < heap[parent(end_index)]:
-        end_index = parent(end_index)
-
-    let elem = heap[index]
-    while index != end_index:
-        heap[index] = heap[parent(index)]
-        index = parent(index)
-    heap[index] = elem
-```
-
-If the user-defined code blows up, that's no problem anymore, because we haven't
-actually touched the state of the heap yet. Once we do start messing with the
-heap, we're working with only data and functions that we trust, so there's no
-concern of panics.
-
-Perhaps you're not happy with this design. Surely it's cheating! And we have
-to do the complex heap traversal *twice*! Alright, let's bite the bullet. Let's
-intermix untrusted and unsafe code *for reals*.
-
-If Rust had `try` and `finally` like in Java, we could do the following:
-
-```text
-bubble_up(heap, index):
-    let elem = heap[index]
-    try:
-        while index != 0 && elem < heap[parent(index)]:
-            heap[index] = heap[parent(index)]
-            index = parent(index)
-    finally:
-        heap[index] = elem
-```
-
-The basic idea is simple: if the comparison panics, we just toss the loose
-element in the logically uninitialized index and bail out. Anyone who observes
-the heap will see a potentially *inconsistent* heap, but at least it won't
-cause any double-drops! If the algorithm terminates normally, then this
-operation happens to coincide precisely with the how we finish up regardless.
-
-Sadly, Rust has no such construct, so we're going to need to roll our own! The
-way to do this is to store the algorithm's state in a separate struct with a
-destructor for the "finally" logic. Whether we panic or not, that destructor
-will run and clean up after us.
-
-```rust,ignore
-struct Hole<'a, T: 'a> {
-    data: &'a mut [T],
-    /// `elt` is always `Some` from new until drop.
-    elt: Option<T>,
-    pos: usize,
-}
-
-impl<'a, T> Hole<'a, T> {
-    fn new(data: &'a mut [T], pos: usize) -> Self {
-        unsafe {
-            let elt = ptr::read(&data[pos]);
-            Hole {
-                data: data,
-                elt: Some(elt),
-                pos: pos,
-            }
-        }
-    }
-
-    fn pos(&self) -> usize { self.pos }
-
-    fn removed(&self) -> &T { self.elt.as_ref().unwrap() }
-
-    unsafe fn get(&self, index: usize) -> &T { &self.data[index] }
-
-    unsafe fn move_to(&mut self, index: usize) {
-        let index_ptr: *const _ = &self.data[index];
-        let hole_ptr = &mut self.data[self.pos];
-        ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
-        self.pos = index;
-    }
-}
-
-impl<'a, T> Drop for Hole<'a, T> {
-    fn drop(&mut self) {
-        // fill the hole again
-        unsafe {
-            let pos = self.pos;
-            ptr::write(&mut self.data[pos], self.elt.take().unwrap());
-        }
-    }
-}
-
-impl<T: Ord> BinaryHeap<T> {
-    fn sift_up(&mut self, pos: usize) {
-        unsafe {
-            // Take out the value at `pos` and create a hole.
-            let mut hole = Hole::new(&mut self.data, pos);
-
-            while hole.pos() != 0 {
-                let parent = parent(hole.pos());
-                if hole.removed() <= hole.get(parent) { break }
-                hole.move_to(parent);
-            }
-            // Hole will be unconditionally filled here; panic or not!
-        }
-    }
-}
-```
diff --git a/src/doc/nomicon/src/exotic-sizes.md b/src/doc/nomicon/src/exotic-sizes.md
deleted file mode 100644 (file)
index 9f858d1..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-# Exotically Sized Types
-
-Most of the time, we think in terms of types with a fixed, positive size. This
-is not always the case, however.
-
-
-
-
-
-# Dynamically Sized Types (DSTs)
-
-Rust in fact supports Dynamically Sized Types (DSTs): types without a statically
-known size or alignment. On the surface, this is a bit nonsensical: Rust *must*
-know the size and alignment of something in order to correctly work with it! In
-this regard, DSTs are not normal types. Due to their lack of a statically known
-size, these types can only exist behind some kind of pointer. Any pointer to a
-DST consequently becomes a *fat* pointer consisting of the pointer and the
-information that "completes" them (more on this below).
-
-There are two major DSTs exposed by the language: trait objects, and slices.
-
-A trait object represents some type that implements the traits it specifies.
-The exact original type is *erased* in favor of runtime reflection
-with a vtable containing all the information necessary to use the type.
-This is the information that completes a trait object: a pointer to its vtable.
-
-A slice is simply a view into some contiguous storage -- typically an array or
-`Vec`. The information that completes a slice is just the number of elements
-it points to.
-
-Structs can actually store a single DST directly as their last field, but this
-makes them a DST as well:
-
-```rust
-// Can't be stored on the stack directly
-struct Foo {
-    info: u32,
-    data: [u8],
-}
-```
-
-**NOTE: [As of Rust 1.0 struct DSTs are broken if the last field has
-a variable position based on its alignment][dst-issue].**
-
-
-
-
-
-# Zero Sized Types (ZSTs)
-
-Rust actually allows types to be specified that occupy no space:
-
-```rust
-struct Foo; // No fields = no size
-
-// All fields have no size = no size
-struct Baz {
-    foo: Foo,
-    qux: (),      // empty tuple has no size
-    baz: [u8; 0], // empty array has no size
-}
-```
-
-On their own, Zero Sized Types (ZSTs) are, for obvious reasons, pretty useless.
-However as with many curious layout choices in Rust, their potential is realized
-in a generic context: Rust largely understands that any operation that  produces
-or stores a ZST can be reduced to a no-op. First off, storing it  doesn't even
-make sense -- it doesn't occupy any space. Also there's only one  value of that
-type, so anything that loads it can just produce it from the  aether -- which is
-also a no-op since it doesn't occupy any space.
-
-One of the most extreme example's of this is Sets and Maps. Given a
-`Map<Key, Value>`, it is common to implement a `Set<Key>` as just a thin wrapper
-around `Map<Key, UselessJunk>`. In many languages, this would necessitate
-allocating space for UselessJunk and doing work to store and load UselessJunk
-only to discard it. Proving this unnecessary would be a difficult analysis for
-the compiler.
-
-However in Rust, we can just say that  `Set<Key> = Map<Key, ()>`. Now Rust
-statically knows that every load and store is useless, and no allocation has any
-size. The result is that the monomorphized code is basically a custom
-implementation of a HashSet with none of the overhead that HashMap would have to
-support values.
-
-Safe code need not worry about ZSTs, but *unsafe* code must be careful about the
-consequence of types with no size. In particular, pointer offsets are no-ops,
-and standard allocators (including jemalloc, the one used by default in Rust)
-may return `nullptr` when a zero-sized allocation is requested, which is
-indistinguishable from out of memory.
-
-
-
-
-
-# Empty Types
-
-Rust also enables types to be declared that *cannot even be instantiated*. These
-types can only be talked about at the type level, and never at the value level.
-Empty types can be declared by specifying an enum with no variants:
-
-```rust
-enum Void {} // No variants = EMPTY
-```
-
-Empty types are even more marginal than ZSTs. The primary motivating example for
-Void types is type-level unreachability. For instance, suppose an API needs to
-return a Result in general, but a specific case actually is infallible. It's
-actually possible to communicate this at the type level by returning a
-`Result<T, Void>`. Consumers of the API can confidently unwrap such a Result
-knowing that it's *statically impossible* for this value to be an `Err`, as
-this would require providing a value of type `Void`.
-
-In principle, Rust can do some interesting analyses and optimizations based
-on this fact. For instance, `Result<T, Void>` could be represented as just `T`,
-because the `Err` case doesn't actually exist. The following *could* also
-compile:
-
-```rust,ignore
-enum Void {}
-
-let res: Result<u32, Void> = Ok(0);
-
-// Err doesn't exist anymore, so Ok is actually irrefutable.
-let Ok(num) = res;
-```
-
-But neither of these tricks work today, so all Void types get you is
-the ability to be confident that certain situations are statically impossible.
-
-One final subtle detail about empty types is that raw pointers to them are
-actually valid to construct, but dereferencing them is Undefined Behavior
-because that doesn't actually make sense. That is, you could model C's `void *`
-type with `*const Void`, but this doesn't necessarily gain anything over using
-e.g. `*const ()`, which *is* safe to randomly dereference.
-
-
-[dst-issue]: https://github.com/rust-lang/rust/issues/26403
diff --git a/src/doc/nomicon/src/hrtb.md b/src/doc/nomicon/src/hrtb.md
deleted file mode 100644 (file)
index 645986a..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-# Higher-Rank Trait Bounds (HRTBs)
-
-Rust's `Fn` traits are a little bit magic. For instance, we can write the
-following code:
-
-```rust
-struct Closure<F> {
-    data: (u8, u16),
-    func: F,
-}
-
-impl<F> Closure<F>
-    where F: Fn(&(u8, u16)) -> &u8,
-{
-    fn call(&self) -> &u8 {
-        (self.func)(&self.data)
-    }
-}
-
-fn do_it(data: &(u8, u16)) -> &u8 { &data.0 }
-
-fn main() {
-    let clo = Closure { data: (0, 1), func: do_it };
-    println!("{}", clo.call());
-}
-```
-
-If we try to naively desugar this code in the same way that we did in the
-lifetimes section, we run into some trouble:
-
-```rust,ignore
-struct Closure<F> {
-    data: (u8, u16),
-    func: F,
-}
-
-impl<F> Closure<F>
-    // where F: Fn(&'??? (u8, u16)) -> &'??? u8,
-{
-    fn call<'a>(&'a self) -> &'a u8 {
-        (self.func)(&self.data)
-    }
-}
-
-fn do_it<'b>(data: &'b (u8, u16)) -> &'b u8 { &'b data.0 }
-
-fn main() {
-    'x: {
-        let clo = Closure { data: (0, 1), func: do_it };
-        println!("{}", clo.call());
-    }
-}
-```
-
-How on earth are we supposed to express the lifetimes on `F`'s trait bound? We
-need to provide some lifetime there, but the lifetime we care about can't be
-named until we enter the body of `call`! Also, that isn't some fixed lifetime;
-`call` works with *any* lifetime `&self` happens to have at that point.
-
-This job requires The Magic of Higher-Rank Trait Bounds (HRTBs). The way we
-desugar this is as follows:
-
-```rust,ignore
-where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8,
-```
-
-(Where `Fn(a, b, c) -> d` is itself just sugar for the unstable *real* `Fn`
-trait)
-
-`for<'a>` can be read as "for all choices of `'a`", and basically produces an
-*infinite list* of trait bounds that F must satisfy. Intense. There aren't many
-places outside of the `Fn` traits where we encounter HRTBs, and even for
-those we have a nice magic sugar for the common cases.
diff --git a/src/doc/nomicon/src/leaking.md b/src/doc/nomicon/src/leaking.md
deleted file mode 100644 (file)
index 38b70b8..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-# Leaking
-
-Ownership-based resource management is intended to simplify composition. You
-acquire resources when you create the object, and you release the resources when
-it gets destroyed. Since destruction is handled for you, it means you can't
-forget to release the resources, and it happens as soon as possible! Surely this
-is perfect and all of our problems are solved.
-
-Everything is terrible and we have new and exotic problems to try to solve.
-
-Many people like to believe that Rust eliminates resource leaks. In practice,
-this is basically true. You would be surprised to see a Safe Rust program
-leak resources in an uncontrolled way.
-
-However from a theoretical perspective this is absolutely not the case, no
-matter how you look at it. In the strictest sense, "leaking" is so abstract as
-to be unpreventable. It's quite trivial to initialize a collection at the start
-of a program, fill it with tons of objects with destructors, and then enter an
-infinite event loop that never refers to it. The collection will sit around
-uselessly, holding on to its precious resources until the program terminates (at
-which point all those resources would have been reclaimed by the OS anyway).
-
-We may consider a more restricted form of leak: failing to drop a value that is
-unreachable. Rust also doesn't prevent this. In fact Rust *has a function for
-doing this*: `mem::forget`. This function consumes the value it is passed *and
-then doesn't run its destructor*.
-
-In the past `mem::forget` was marked as unsafe as a sort of lint against using
-it, since failing to call a destructor is generally not a well-behaved thing to
-do (though useful for some special unsafe code). However this was generally
-determined to be an untenable stance to take: there are many ways to fail to
-call a destructor in safe code. The most famous example is creating a cycle of
-reference-counted pointers using interior mutability.
-
-It is reasonable for safe code to assume that destructor leaks do not happen, as
-any program that leaks destructors is probably wrong. However *unsafe* code
-cannot rely on destructors to be run in order to be safe. For most types this
-doesn't matter: if you leak the destructor then the type is by definition
-inaccessible, so it doesn't matter, right? For instance, if you leak a `Box<u8>`
-then you waste some memory but that's hardly going to violate memory-safety.
-
-However where we must be careful with destructor leaks are *proxy* types. These
-are types which manage access to a distinct object, but don't actually own it.
-Proxy objects are quite rare. Proxy objects you'll need to care about are even
-rarer. However we'll focus on three interesting examples in the standard
-library:
-
-* `vec::Drain`
-* `Rc`
-* `thread::scoped::JoinGuard`
-
-
-
-## Drain
-
-`drain` is a collections API that moves data out of the container without
-consuming the container. This enables us to reuse the allocation of a `Vec`
-after claiming ownership over all of its contents. It produces an iterator
-(Drain) that returns the contents of the Vec by-value.
-
-Now, consider Drain in the middle of iteration: some values have been moved out,
-and others haven't. This means that part of the Vec is now full of logically
-uninitialized data! We could backshift all the elements in the Vec every time we
-remove a value, but this would have pretty catastrophic performance
-consequences.
-
-Instead, we would like Drain to fix the Vec's backing storage when it is
-dropped. It should run itself to completion, backshift any elements that weren't
-removed (drain supports subranges), and then fix Vec's `len`. It's even
-unwinding-safe! Easy!
-
-Now consider the following:
-
-```rust,ignore
-let mut vec = vec![Box::new(0); 4];
-
-{
-    // start draining, vec can no longer be accessed
-    let mut drainer = vec.drain(..);
-
-    // pull out two elements and immediately drop them
-    drainer.next();
-    drainer.next();
-
-    // get rid of drainer, but don't call its destructor
-    mem::forget(drainer);
-}
-
-// Oops, vec[0] was dropped, we're reading a pointer into free'd memory!
-println!("{}", vec[0]);
-```
-
-This is pretty clearly Not Good. Unfortunately, we're kind of stuck between a
-rock and a hard place: maintaining consistent state at every step has an
-enormous cost (and would negate any benefits of the API). Failing to maintain
-consistent state gives us Undefined Behavior in safe code (making the API
-unsound).
-
-So what can we do? Well, we can pick a trivially consistent state: set the Vec's
-len to be 0 when we start the iteration, and fix it up if necessary in the
-destructor. That way, if everything executes like normal we get the desired
-behavior with minimal overhead. But if someone has the *audacity* to
-mem::forget us in the middle of the iteration, all that does is *leak even more*
-(and possibly leave the Vec in an unexpected but otherwise consistent state).
-Since we've accepted that mem::forget is safe, this is definitely safe. We call
-leaks causing more leaks a *leak amplification*.
-
-
-
-
-## Rc
-
-Rc is an interesting case because at first glance it doesn't appear to be a
-proxy value at all. After all, it manages the data it points to, and dropping
-all the Rcs for a value will drop that value. Leaking an Rc doesn't seem like it
-would be particularly dangerous. It will leave the refcount permanently
-incremented and prevent the data from being freed or dropped, but that seems
-just like Box, right?
-
-Nope.
-
-Let's consider a simplified implementation of Rc:
-
-```rust,ignore
-struct Rc<T> {
-    ptr: *mut RcBox<T>,
-}
-
-struct RcBox<T> {
-    data: T,
-    ref_count: usize,
-}
-
-impl<T> Rc<T> {
-    fn new(data: T) -> Self {
-        unsafe {
-            // Wouldn't it be nice if heap::allocate worked like this?
-            let ptr = heap::allocate::<RcBox<T>>();
-            ptr::write(ptr, RcBox {
-                data: data,
-                ref_count: 1,
-            });
-            Rc { ptr: ptr }
-        }
-    }
-
-    fn clone(&self) -> Self {
-        unsafe {
-            (*self.ptr).ref_count += 1;
-        }
-        Rc { ptr: self.ptr }
-    }
-}
-
-impl<T> Drop for Rc<T> {
-    fn drop(&mut self) {
-        unsafe {
-            (*self.ptr).ref_count -= 1;
-            if (*self.ptr).ref_count == 0 {
-                // drop the data and then free it
-                ptr::read(self.ptr);
-                heap::deallocate(self.ptr);
-            }
-        }
-    }
-}
-```
-
-This code contains an implicit and subtle assumption: `ref_count` can fit in a
-`usize`, because there can't be more than `usize::MAX` Rcs in memory. However
-this itself assumes that the `ref_count` accurately reflects the number of Rcs
-in memory, which we know is false with `mem::forget`. Using `mem::forget` we can
-overflow the `ref_count`, and then get it down to 0 with outstanding Rcs. Then
-we can happily use-after-free the inner data. Bad Bad Not Good.
-
-This can be solved by just checking the `ref_count` and doing *something*. The
-standard library's stance is to just abort, because your program has become
-horribly degenerate. Also *oh my gosh* it's such a ridiculous corner case.
-
-
-
-
-## thread::scoped::JoinGuard
-
-The thread::scoped API intends to allow threads to be spawned that reference
-data on their parent's stack without any synchronization over that data by
-ensuring the parent joins the thread before any of the shared data goes out
-of scope.
-
-```rust,ignore
-pub fn scoped<'a, F>(f: F) -> JoinGuard<'a>
-    where F: FnOnce() + Send + 'a
-```
-
-Here `f` is some closure for the other thread to execute. Saying that
-`F: Send +'a` is saying that it closes over data that lives for `'a`, and it
-either owns that data or the data was Sync (implying `&data` is Send).
-
-Because JoinGuard has a lifetime, it keeps all the data it closes over
-borrowed in the parent thread. This means the JoinGuard can't outlive
-the data that the other thread is working on. When the JoinGuard *does* get
-dropped it blocks the parent thread, ensuring the child terminates before any
-of the closed-over data goes out of scope in the parent.
-
-Usage looked like:
-
-```rust,ignore
-let mut data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-{
-    let guards = vec![];
-    for x in &mut data {
-        // Move the mutable reference into the closure, and execute
-        // it on a different thread. The closure has a lifetime bound
-        // by the lifetime of the mutable reference `x` we store in it.
-        // The guard that is returned is in turn assigned the lifetime
-        // of the closure, so it also mutably borrows `data` as `x` did.
-        // This means we cannot access `data` until the guard goes away.
-        let guard = thread::scoped(move || {
-            *x *= 2;
-        });
-        // store the thread's guard for later
-        guards.push(guard);
-    }
-    // All guards are dropped here, forcing the threads to join
-    // (this thread blocks here until the others terminate).
-    // Once the threads join, the borrow expires and the data becomes
-    // accessible again in this thread.
-}
-// data is definitely mutated here.
-```
-
-In principle, this totally works! Rust's ownership system perfectly ensures it!
-...except it relies on a destructor being called to be safe.
-
-```rust,ignore
-let mut data = Box::new(0);
-{
-    let guard = thread::scoped(|| {
-        // This is at best a data race. At worst, it's also a use-after-free.
-        *data += 1;
-    });
-    // Because the guard is forgotten, expiring the loan without blocking this
-    // thread.
-    mem::forget(guard);
-}
-// So the Box is dropped here while the scoped thread may or may not be trying
-// to access it.
-```
-
-Dang. Here the destructor running was pretty fundamental to the API, and it had
-to be scrapped in favor of a completely different design.
diff --git a/src/doc/nomicon/src/lifetime-elision.md b/src/doc/nomicon/src/lifetime-elision.md
deleted file mode 100644 (file)
index e92d735..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-# Lifetime Elision
-
-In order to make common patterns more ergonomic, Rust allows lifetimes to be
-*elided* in function signatures.
-
-A *lifetime position* is anywhere you can write a lifetime in a type:
-
-```rust,ignore
-&'a T
-&'a mut T
-T<'a>
-```
-
-Lifetime positions can appear as either "input" or "output":
-
-* For `fn` definitions, input refers to the types of the formal arguments
-  in the `fn` definition, while output refers to
-  result types. So `fn foo(s: &str) -> (&str, &str)` has elided one lifetime in
-  input position and two lifetimes in output position.
-  Note that the input positions of a `fn` method definition do not
-  include the lifetimes that occur in the method's `impl` header
-  (nor lifetimes that occur in the trait header, for a default method).
-
-* In the future, it should be possible to elide `impl` headers in the same manner.
-
-Elision rules are as follows:
-
-* Each elided lifetime in input position becomes a distinct lifetime
-  parameter.
-
-* If there is exactly one input lifetime position (elided or not), that lifetime
-  is assigned to *all* elided output lifetimes.
-
-* If there are multiple input lifetime positions, but one of them is `&self` or
-  `&mut self`, the lifetime of `self` is assigned to *all* elided output lifetimes.
-
-* Otherwise, it is an error to elide an output lifetime.
-
-Examples:
-
-```rust,ignore
-fn print(s: &str);                                      // elided
-fn print<'a>(s: &'a str);                               // expanded
-
-fn debug(lvl: uint, s: &str);                           // elided
-fn debug<'a>(lvl: uint, s: &'a str);                    // expanded
-
-fn substr(s: &str, until: uint) -> &str;                // elided
-fn substr<'a>(s: &'a str, until: uint) -> &'a str;      // expanded
-
-fn get_str() -> &str;                                   // ILLEGAL
-
-fn frob(s: &str, t: &str) -> &str;                      // ILLEGAL
-
-fn get_mut(&mut self) -> &mut T;                        // elided
-fn get_mut<'a>(&'a mut self) -> &'a mut T;              // expanded
-
-fn args<T: ToCStr>(&mut self, args: &[T]) -> &mut Command                  // elided
-fn args<'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
-
-fn new(buf: &mut [u8]) -> BufWriter;                    // elided
-fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a>          // expanded
-
-```
diff --git a/src/doc/nomicon/src/lifetime-mismatch.md b/src/doc/nomicon/src/lifetime-mismatch.md
deleted file mode 100644 (file)
index 30b4f09..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-# Limits of Lifetimes
-
-Given the following code:
-
-```rust,ignore
-struct Foo;
-
-impl Foo {
-    fn mutate_and_share(&mut self) -> &Self { &*self }
-    fn share(&self) {}
-}
-
-fn main() {
-    let mut foo = Foo;
-    let loan = foo.mutate_and_share();
-    foo.share();
-}
-```
-
-One might expect it to compile. We call `mutate_and_share`, which mutably borrows
-`foo` temporarily, but then returns only a shared reference. Therefore we
-would expect `foo.share()` to succeed as `foo` shouldn't be mutably borrowed.
-
-However when we try to compile it:
-
-```text
-<anon>:11:5: 11:8 error: cannot borrow `foo` as immutable because it is also borrowed as mutable
-<anon>:11     foo.share();
-              ^~~
-<anon>:10:16: 10:19 note: previous borrow of `foo` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `foo` until the borrow ends
-<anon>:10     let loan = foo.mutate_and_share();
-                         ^~~
-<anon>:12:2: 12:2 note: previous borrow ends here
-<anon>:8 fn main() {
-<anon>:9     let mut foo = Foo;
-<anon>:10     let loan = foo.mutate_and_share();
-<anon>:11     foo.share();
-<anon>:12 }
-          ^
-```
-
-What happened? Well, we got the exact same reasoning as we did for
-[Example 2 in the previous section][ex2]. We desugar the program and we get
-the following:
-
-```rust,ignore
-struct Foo;
-
-impl Foo {
-    fn mutate_and_share<'a>(&'a mut self) -> &'a Self { &'a *self }
-    fn share<'a>(&'a self) {}
-}
-
-fn main() {
-       'b: {
-       let mut foo: Foo = Foo;
-       'c: {
-               let loan: &'c Foo = Foo::mutate_and_share::<'c>(&'c mut foo);
-               'd: {
-                       Foo::share::<'d>(&'d foo);
-               }
-       }
-    }
-}
-```
-
-The lifetime system is forced to extend the `&mut foo` to have lifetime `'c`,
-due to the lifetime of `loan` and mutate_and_share's signature. Then when we
-try to call `share`, and it sees we're trying to alias that `&'c mut foo` and
-blows up in our face!
-
-This program is clearly correct according to the reference semantics we actually
-care about, but the lifetime system is too coarse-grained to handle that.
-
-
-TODO: other common problems? SEME regions stuff, mostly?
-
-
-
-
-[ex2]: lifetimes.html#example-aliasing-a-mutable-reference
diff --git a/src/doc/nomicon/src/lifetimes.md b/src/doc/nomicon/src/lifetimes.md
deleted file mode 100644 (file)
index e2f0cc8..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-# Lifetimes
-
-Rust enforces these rules through *lifetimes*. Lifetimes are effectively
-just names for scopes somewhere in the program. Each reference,
-and anything that contains a reference, is tagged with a lifetime specifying
-the scope it's valid for.
-
-Within a function body, Rust generally doesn't let you explicitly name the
-lifetimes involved. This is because it's generally not really necessary
-to talk about lifetimes in a local context; Rust has all the information and
-can work out everything as optimally as possible. Many anonymous scopes and
-temporaries that you would otherwise have to write are often introduced to
-make your code Just Work.
-
-However once you cross the function boundary, you need to start talking about
-lifetimes. Lifetimes are denoted with an apostrophe: `'a`, `'static`. To dip
-our toes with lifetimes, we're going to pretend that we're actually allowed
-to label scopes with lifetimes, and desugar the examples from the start of
-this chapter.
-
-Originally, our examples made use of *aggressive* sugar -- high fructose corn
-syrup even -- around scopes and lifetimes, because writing everything out
-explicitly is *extremely noisy*. All Rust code relies on aggressive inference
-and elision of "obvious" things.
-
-One particularly interesting piece of sugar is that each `let` statement implicitly
-introduces a scope. For the most part, this doesn't really matter. However it
-does matter for variables that refer to each other. As a simple example, let's
-completely desugar this simple piece of Rust code:
-
-```rust
-let x = 0;
-let y = &x;
-let z = &y;
-```
-
-The borrow checker always tries to minimize the extent of a lifetime, so it will
-likely desugar to the following:
-
-```rust,ignore
-// NOTE: `'a: {` and `&'b x` is not valid syntax!
-'a: {
-    let x: i32 = 0;
-    'b: {
-        // lifetime used is 'b because that's good enough.
-        let y: &'b i32 = &'b x;
-        'c: {
-            // ditto on 'c
-            let z: &'c &'b i32 = &'c y;
-        }
-    }
-}
-```
-
-Wow. That's... awful. Let's all take a moment to thank Rust for making this easier.
-
-Actually passing references to outer scopes will cause Rust to infer
-a larger lifetime:
-
-```rust
-let x = 0;
-let z;
-let y = &x;
-z = y;
-```
-
-```rust,ignore
-'a: {
-    let x: i32 = 0;
-    'b: {
-        let z: &'b i32;
-        'c: {
-            // Must use 'b here because this reference is
-            // being passed to that scope.
-            let y: &'b i32 = &'b x;
-            z = y;
-        }
-    }
-}
-```
-
-
-
-# Example: references that outlive referents
-
-Alright, let's look at some of those examples from before:
-
-```rust,ignore
-fn as_str(data: &u32) -> &str {
-    let s = format!("{}", data);
-    &s
-}
-```
-
-desugars to:
-
-```rust,ignore
-fn as_str<'a>(data: &'a u32) -> &'a str {
-    'b: {
-        let s = format!("{}", data);
-        return &'a s;
-    }
-}
-```
-
-This signature of `as_str` takes a reference to a u32 with *some* lifetime, and
-promises that it can produce a reference to a str that can live *just as long*.
-Already we can see why this signature might be trouble. That basically implies
-that we're going to find a str somewhere in the scope the reference
-to the u32 originated in, or somewhere *even earlier*. That's a bit of a tall
-order.
-
-We then proceed to compute the string `s`, and return a reference to it. Since
-the contract of our function says the reference must outlive `'a`, that's the
-lifetime we infer for the reference. Unfortunately, `s` was defined in the
-scope `'b`, so the only way this is sound is if `'b` contains `'a` -- which is
-clearly false since `'a` must contain the function call itself. We have therefore
-created a reference whose lifetime outlives its referent, which is *literally*
-the first thing we said that references can't do. The compiler rightfully blows
-up in our face.
-
-To make this more clear, we can expand the example:
-
-```rust,ignore
-fn as_str<'a>(data: &'a u32) -> &'a str {
-    'b: {
-        let s = format!("{}", data);
-        return &'a s
-    }
-}
-
-fn main() {
-    'c: {
-        let x: u32 = 0;
-        'd: {
-            // An anonymous scope is introduced because the borrow does not
-            // need to last for the whole scope x is valid for. The return
-            // of as_str must find a str somewhere before this function
-            // call. Obviously not happening.
-            println!("{}", as_str::<'d>(&'d x));
-        }
-    }
-}
-```
-
-Shoot!
-
-Of course, the right way to write this function is as follows:
-
-```rust
-fn to_string(data: &u32) -> String {
-    format!("{}", data)
-}
-```
-
-We must produce an owned value inside the function to return it! The only way
-we could have returned an `&'a str` would have been if it was in a field of the
-`&'a u32`, which is obviously not the case.
-
-(Actually we could have also just returned a string literal, which as a global
-can be considered to reside at the bottom of the stack; though this limits
-our implementation *just a bit*.)
-
-
-
-
-
-# Example: aliasing a mutable reference
-
-How about the other example:
-
-```rust,ignore
-let mut data = vec![1, 2, 3];
-let x = &data[0];
-data.push(4);
-println!("{}", x);
-```
-
-```rust,ignore
-'a: {
-    let mut data: Vec<i32> = vec![1, 2, 3];
-    'b: {
-        // 'b is as big as we need this borrow to be
-        // (just need to get to `println!`)
-        let x: &'b i32 = Index::index::<'b>(&'b data, 0);
-        'c: {
-            // Temporary scope because we don't need the
-            // &mut to last any longer.
-            Vec::push(&'c mut data, 4);
-        }
-        println!("{}", x);
-    }
-}
-```
-
-The problem here is a bit more subtle and interesting. We want Rust to
-reject this program for the following reason: We have a live shared reference `x`
-to a descendant of `data` when we try to take a mutable reference to `data`
-to `push`. This would create an aliased mutable reference, which would
-violate the *second* rule of references.
-
-However this is *not at all* how Rust reasons that this program is bad. Rust
-doesn't understand that `x` is a reference to a subpath of `data`. It doesn't
-understand Vec at all. What it *does* see is that `x` has to live for `'b` to
-be printed. The signature of `Index::index` subsequently demands that the
-reference we take to `data` has to survive for `'b`. When we try to call `push`,
-it then sees us try to make an `&'c mut data`. Rust knows that `'c` is contained
-within `'b`, and rejects our program because the `&'b data` must still be live!
-
-Here we see that the lifetime system is much more coarse than the reference
-semantics we're actually interested in preserving. For the most part, *that's
-totally ok*, because it keeps us from spending all day explaining our program
-to the compiler. However it does mean that several programs that are totally
-correct with respect to Rust's *true* semantics are rejected because lifetimes
-are too dumb.
diff --git a/src/doc/nomicon/src/meet-safe-and-unsafe.md b/src/doc/nomicon/src/meet-safe-and-unsafe.md
deleted file mode 100644 (file)
index d42d0b6..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-# Meet Safe and Unsafe
-
-Programmers in safe "high-level" languages face a fundamental dilemma. On one
-hand, it would be *really* great to just say what you want and not worry about
-how it's done. On the other hand, that can lead to unacceptably poor
-performance. It may be necessary to drop down to less clear or idiomatic
-practices to get the performance characteristics you want. Or maybe you just
-throw up your hands in disgust and decide to shell out to an implementation in
-a less sugary-wonderful *unsafe* language.
-
-Worse, when you want to talk directly to the operating system, you *have* to
-talk to an unsafe language: *C*. C is ever-present and unavoidable. It's the
-lingua-franca of the programming world.
-Even other safe languages generally expose C interfaces for the world at large!
-Regardless of why you're doing it, as soon as your program starts talking to
-C it stops being safe.
-
-With that said, Rust is *totally* a safe programming language.
-
-Well, Rust *has* a safe programming language. Let's step back a bit.
-
-Rust can be thought of as being composed of two programming languages: *Safe
-Rust* and *Unsafe Rust*. Safe Rust is For Reals  Totally Safe. Unsafe Rust,
-unsurprisingly, is *not* For Reals Totally Safe.  In fact, Unsafe Rust lets you
-do some really, *really* unsafe things.
-
-Safe Rust is the *true* Rust programming language. If all you do is write Safe
-Rust, you will never have to worry about type-safety or memory-safety. You will
-never endure a null or dangling pointer, or any of that Undefined Behavior
-nonsense.
-
-*That's totally awesome.*
-
-The standard library also gives you enough utilities out-of-the-box that you'll
-be able to write awesome high-performance applications and libraries in pure
-idiomatic Safe Rust.
-
-But maybe you want to talk to another language. Maybe you're writing a
-low-level abstraction not exposed by the standard library. Maybe you're
-*writing* the standard library (which is written entirely in Rust). Maybe you
-need to do something the type-system doesn't understand and just *frob some dang
-bits*. Maybe you need Unsafe Rust.
-
-Unsafe Rust is exactly like Safe Rust with all the same rules and semantics.
-However Unsafe Rust lets you do some *extra* things that are Definitely Not Safe.
-
-The only things that are different in Unsafe Rust are that you can:
-
-* Dereference raw pointers
-* Call `unsafe` functions (including C functions, intrinsics, and the raw allocator)
-* Implement `unsafe` traits
-* Mutate statics
-
-That's it. The reason these operations are relegated to Unsafe is that misusing
-any of these things will cause the ever dreaded Undefined Behavior. Invoking
-Undefined Behavior gives the compiler full rights to do arbitrarily bad things
-to your program. You definitely *should not* invoke Undefined Behavior.
-
-Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core
-language cares about is preventing the following things:
-
-* Dereferencing null or dangling pointers
-* Reading [uninitialized memory]
-* Breaking the [pointer aliasing rules]
-* Producing invalid primitive values:
-    * dangling/null references
-    * a `bool` that isn't 0 or 1
-    * an undefined `enum` discriminant
-    * a `char` outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF]
-    * A non-utf8 `str`
-* Unwinding into another language
-* Causing a [data race][race]
-
-That's it. That's all the causes of Undefined Behavior baked into Rust. Of
-course, unsafe functions and traits are free to declare arbitrary other
-constraints that a program must maintain to avoid Undefined Behavior. However,
-generally violations of these constraints will just transitively lead to one of
-the above problems. Some additional constraints may also derive from compiler
-intrinsics that make special assumptions about how code can be optimized.
-
-Rust is otherwise quite permissive with respect to other dubious operations.
-Rust considers it "safe" to:
-
-* Deadlock
-* Have a [race condition][race]
-* Leak memory
-* Fail to call destructors
-* Overflow integers
-* Abort the program
-* Delete the production database
-
-However any program that actually manages to do such a thing is *probably*
-incorrect. Rust provides lots of tools to make these things rare, but
-these problems are considered impractical to categorically prevent.
-
-[pointer aliasing rules]: references.html
-[uninitialized memory]: uninitialized.html
-[race]: races.html
diff --git a/src/doc/nomicon/src/obrm.md b/src/doc/nomicon/src/obrm.md
deleted file mode 100644 (file)
index 19e5ec3..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# The Perils Of Ownership Based Resource Management (OBRM)
-
-OBRM (AKA RAII: Resource Acquisition Is Initialization) is something you'll
-interact with a lot in Rust. Especially if you use the standard library.
-
-Roughly speaking the pattern is as follows: to acquire a resource, you create an
-object that manages it. To release the resource, you simply destroy the object,
-and it cleans up the resource for you. The most common "resource" this pattern
-manages is simply *memory*. `Box`, `Rc`, and basically everything in
-`std::collections` is a convenience to enable correctly managing memory. This is
-particularly important in Rust because we have no pervasive GC to rely on for
-memory management. Which is the point, really: Rust is about control. However we
-are not limited to just memory. Pretty much every other system resource like a
-thread, file, or socket is exposed through this kind of API.
diff --git a/src/doc/nomicon/src/other-reprs.md b/src/doc/nomicon/src/other-reprs.md
deleted file mode 100644 (file)
index 02f39e3..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-# Alternative representations
-
-Rust allows you to specify alternative data layout strategies from the default.
-
-
-
-
-# repr(C)
-
-This is the most important `repr`. It has fairly simple intent: do what C does.
-The order, size, and alignment of fields is exactly what you would expect from C
-or C++. Any type you expect to pass through an FFI boundary should have
-`repr(C)`, as C is the lingua-franca of the programming world. This is also
-necessary to soundly do more elaborate tricks with data layout such as
-reinterpreting values as a different type.
-
-However, the interaction with Rust's more exotic data layout features must be
-kept in mind. Due to its dual purpose as "for FFI" and "for layout control",
-`repr(C)` can be applied to types that will be nonsensical or problematic if
-passed through the FFI boundary.
-
-* ZSTs are still zero-sized, even though this is not a standard behavior in
-C, and is explicitly contrary to the behavior of an empty type in C++, which
-still consumes a byte of space.
-
-* DSTs, tuples, and tagged unions are not a concept in C and as such are never
-FFI safe.
-
-* Tuple structs are like structs with regards to `repr(C)`, as the only
-  difference from a struct is that the fields aren’t named.
-
-* **If the type would have any [drop flags], they will still be added**
-
-* This is equivalent to one of `repr(u*)` (see the next section) for enums. The
-chosen size is the default enum size for the target platform's C ABI. Note that
-enum representation in C is implementation defined, so this is really a "best
-guess". In particular, this may be incorrect when the C code of interest is
-compiled with certain flags.
-
-
-
-# repr(u8), repr(u16), repr(u32), repr(u64)
-
-These specify the size to make a C-like enum. If the discriminant overflows the
-integer it has to fit in, it will produce a compile-time error. You can manually
-ask Rust to allow this by setting the overflowing element to explicitly be 0.
-However Rust will not allow you to create an enum where two variants have the
-same discriminant.
-
-On non-C-like enums, this will inhibit certain optimizations like the null-
-pointer optimization.
-
-These reprs have no effect on a struct.
-
-
-
-
-# repr(packed)
-
-`repr(packed)` forces Rust to strip any padding, and only align the type to a
-byte. This may improve the memory footprint, but will likely have other negative
-side-effects.
-
-In particular, most architectures *strongly* prefer values to be aligned. This
-may mean the unaligned loads are penalized (x86), or even fault (some ARM
-chips). For simple cases like directly loading or storing a packed field, the
-compiler might be able to paper over alignment issues with shifts and masks.
-However if you take a reference to a packed field, it's unlikely that the
-compiler will be able to emit code to avoid an unaligned load.
-
-**[As of Rust 1.0 this can cause undefined behavior.][ub loads]**
-
-`repr(packed)` is not to be used lightly. Unless you have extreme requirements,
-this should not be used.
-
-This repr is a modifier on `repr(C)` and `repr(rust)`.
-
-[drop flags]: drop-flags.html
-[ub loads]: https://github.com/rust-lang/rust/issues/27060
diff --git a/src/doc/nomicon/src/ownership.md b/src/doc/nomicon/src/ownership.md
deleted file mode 100644 (file)
index dd9e9db..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-# Ownership and Lifetimes
-
-Ownership is the breakout feature of Rust. It allows Rust to be completely
-memory-safe and efficient, while avoiding garbage collection. Before getting
-into the ownership system in detail, we will consider the motivation of this
-design.
-
-We will assume that you accept that garbage collection (GC) is not always an
-optimal solution, and that it is desirable to manually manage memory in some
-contexts. If you do not accept this, might I interest you in a different
-language?
-
-Regardless of your feelings on GC, it is pretty clearly a *massive* boon to
-making code safe. You never have to worry about things going away *too soon*
-(although whether you still wanted to be pointing at that thing is a different
-issue...). This is a pervasive problem that C and C++ programs need to deal
-with. Consider this simple mistake that all of us who have used a non-GC'd
-language have made at one point:
-
-```rust,ignore
-fn as_str(data: &u32) -> &str {
-    // compute the string
-    let s = format!("{}", data);
-
-    // OH NO! We returned a reference to something that
-    // exists only in this function!
-    // Dangling pointer! Use after free! Alas!
-    // (this does not compile in Rust)
-    &s
-}
-```
-
-This is exactly what Rust's ownership system was built to solve.
-Rust knows the scope in which the `&s` lives, and as such can prevent it from
-escaping. However this is a simple case that even a C compiler could plausibly
-catch. Things get more complicated as code gets bigger and pointers get fed through
-various functions. Eventually, a C compiler will fall down and won't be able to
-perform sufficient escape analysis to prove your code unsound. It will consequently
-be forced to accept your program on the assumption that it is correct.
-
-This will never happen to Rust. It's up to the programmer to prove to the
-compiler that everything is sound.
-
-Of course, Rust's story around ownership is much more complicated than just
-verifying that references don't escape the scope of their referent. That's
-because ensuring pointers are always valid is much more complicated than this.
-For instance in this code,
-
-```rust,ignore
-let mut data = vec![1, 2, 3];
-// get an internal reference
-let x = &data[0];
-
-// OH NO! `push` causes the backing storage of `data` to be reallocated.
-// Dangling pointer! Use after free! Alas!
-// (this does not compile in Rust)
-data.push(4);
-
-println!("{}", x);
-```
-
-naive scope analysis would be insufficient to prevent this bug, because `data`
-does in fact live as long as we needed. However it was *changed* while we had
-a reference into it. This is why Rust requires any references to freeze the
-referent and its owners.
-
diff --git a/src/doc/nomicon/src/phantom-data.md b/src/doc/nomicon/src/phantom-data.md
deleted file mode 100644 (file)
index 32539c2..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-# PhantomData
-
-When working with unsafe code, we can often end up in a situation where
-types or lifetimes are logically associated with a struct, but not actually
-part of a field. This most commonly occurs with lifetimes. For instance, the
-`Iter` for `&'a [T]` is (approximately) defined as follows:
-
-```rust,ignore
-struct Iter<'a, T: 'a> {
-    ptr: *const T,
-    end: *const T,
-}
-```
-
-However because `'a` is unused within the struct's body, it's *unbounded*.
-Because of the troubles this has historically caused, unbounded lifetimes and
-types are *forbidden* in struct definitions. Therefore we must somehow refer
-to these types in the body. Correctly doing this is necessary to have
-correct variance and drop checking.
-
-We do this using `PhantomData`, which is a special marker type. `PhantomData`
-consumes no space, but simulates a field of the given type for the purpose of
-static analysis. This was deemed to be less error-prone than explicitly telling
-the type-system the kind of variance that you want, while also providing other
-useful such as the information needed by drop check.
-
-Iter logically contains a bunch of `&'a T`s, so this is exactly what we tell
-the PhantomData to simulate:
-
-```
-use std::marker;
-
-struct Iter<'a, T: 'a> {
-    ptr: *const T,
-    end: *const T,
-    _marker: marker::PhantomData<&'a T>,
-}
-```
-
-and that's it. The lifetime will be bounded, and your iterator will be variant
-over `'a` and `T`. Everything Just Works.
-
-Another important example is Vec, which is (approximately) defined as follows:
-
-```
-struct Vec<T> {
-    data: *const T, // *const for variance!
-    len: usize,
-    cap: usize,
-}
-```
-
-Unlike the previous example, it *appears* that everything is exactly as we
-want. Every generic argument to Vec shows up in at least one field.
-Good to go!
-
-Nope.
-
-The drop checker will generously determine that `Vec<T>` does not own any values
-of type T. This will in turn make it conclude that it doesn't need to worry
-about Vec dropping any T's in its destructor for determining drop check
-soundness. This will in turn allow people to create unsoundness using
-Vec's destructor.
-
-In order to tell dropck that we *do* own values of type T, and therefore may
-drop some T's when *we* drop, we must add an extra PhantomData saying exactly
-that:
-
-```
-use std::marker;
-
-struct Vec<T> {
-    data: *const T, // *const for covariance!
-    len: usize,
-    cap: usize,
-    _marker: marker::PhantomData<T>,
-}
-```
-
-Raw pointers that own an allocation is such a pervasive pattern that the
-standard library made a utility for itself called `Unique<T>` which:
-
-* wraps a `*const T` for variance
-* includes a `PhantomData<T>`
-* auto-derives `Send`/`Sync` as if T was contained
-* marks the pointer as `NonZero` for the null-pointer optimization
-
-## Table of `PhantomData` patterns
-
-Here’s a table of all the wonderful ways `PhantomData` could be used:
-
-| Phantom type                | `'a`      | `T`                       |
-|-----------------------------|-----------|---------------------------|
-| `PhantomData<T>`            | -         | variant (with drop check) |
-| `PhantomData<&'a T>`        | variant   | variant                   |
-| `PhantomData<&'a mut T>`    | variant   | invariant                 |
-| `PhantomData<*const T>`     | -         | variant                   |
-| `PhantomData<*mut T>`       | -         | invariant                 |
-| `PhantomData<fn(T)>`        | -         | contravariant (*)         |
-| `PhantomData<fn() -> T>`    | -         | variant                   |
-| `PhantomData<fn(T) -> T>`   | -         | invariant                 |
-| `PhantomData<Cell<&'a ()>>` | invariant | -                         |
-
-(*) If contravariance gets scrapped, this would be invariant.
diff --git a/src/doc/nomicon/src/poisoning.md b/src/doc/nomicon/src/poisoning.md
deleted file mode 100644 (file)
index 9b5dec3..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-# Poisoning
-
-Although all unsafe code *must* ensure it has minimal exception safety, not all
-types ensure *maximal* exception safety. Even if the type does, your code may
-ascribe additional meaning to it. For instance, an integer is certainly
-exception-safe, but has no semantics on its own. It's possible that code that
-panics could fail to correctly update the integer, producing an inconsistent
-program state.
-
-This is *usually* fine, because anything that witnesses an exception is about
-to get destroyed. For instance, if you send a Vec to another thread and that
-thread panics, it doesn't matter if the Vec is in a weird state. It will be
-dropped and go away forever. However some types are especially good at smuggling
-values across the panic boundary.
-
-These types may choose to explicitly *poison* themselves if they witness a panic.
-Poisoning doesn't entail anything in particular. Generally it just means
-preventing normal usage from proceeding. The most notable example of this is the
-standard library's Mutex type. A Mutex will poison itself if one of its
-MutexGuards (the thing it returns when a lock is obtained) is dropped during a
-panic. Any future attempts to lock the Mutex will return an `Err` or panic.
-
-Mutex poisons not for true safety in the sense that Rust normally cares about. It
-poisons as a safety-guard against blindly using the data that comes out of a Mutex
-that has witnessed a panic while locked. The data in such a Mutex was likely in the
-middle of being modified, and as such may be in an inconsistent or incomplete state.
-It is important to note that one cannot violate memory safety with such a type
-if it is correctly written. After all, it must be minimally exception-safe!
-
-However if the Mutex contained, say, a BinaryHeap that does not actually have the
-heap property, it's unlikely that any code that uses it will do
-what the author intended. As such, the program should not proceed normally.
-Still, if you're double-plus-sure that you can do *something* with the value,
-the Mutex exposes a method to get the lock anyway. It *is* safe, after all.
-Just maybe nonsense.
diff --git a/src/doc/nomicon/src/races.md b/src/doc/nomicon/src/races.md
deleted file mode 100644 (file)
index c9b8c3d..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-# Data Races and Race Conditions
-
-Safe Rust guarantees an absence of data races, which are defined as:
-
-* two or more threads concurrently accessing a location of memory
-* one of them is a write
-* one of them is unsynchronized
-
-A data race has Undefined Behavior, and is therefore impossible to perform
-in Safe Rust. Data races are *mostly* prevented through rust's ownership system:
-it's impossible to alias a mutable reference, so it's impossible to perform a
-data race. Interior mutability makes this more complicated, which is largely why
-we have the Send and Sync traits (see below).
-
-**However Rust does not prevent general race conditions.**
-
-This is pretty fundamentally impossible, and probably honestly undesirable. Your
-hardware is racy, your OS is racy, the other programs on your computer are racy,
-and the world this all runs in is racy. Any system that could genuinely claim to
-prevent *all* race conditions would be pretty awful to use, if not just
-incorrect.
-
-So it's perfectly "fine" for a Safe Rust program to get deadlocked or do
-something nonsensical with incorrect synchronization. Obviously such a program
-isn't very good, but Rust can only hold your hand so far. Still, a race
-condition can't violate memory safety in a Rust program on its own. Only in
-conjunction with some other unsafe code can a race condition actually violate
-memory safety. For instance:
-
-```rust,no_run
-use std::thread;
-use std::sync::atomic::{AtomicUsize, Ordering};
-use std::sync::Arc;
-
-let data = vec![1, 2, 3, 4];
-// Arc so that the memory the AtomicUsize is stored in still exists for
-// the other thread to increment, even if we completely finish executing
-// before it. Rust won't compile the program without it, because of the
-// lifetime requirements of thread::spawn!
-let idx = Arc::new(AtomicUsize::new(0));
-let other_idx = idx.clone();
-
-// `move` captures other_idx by-value, moving it into this thread
-thread::spawn(move || {
-    // It's ok to mutate idx because this value
-    // is an atomic, so it can't cause a Data Race.
-    other_idx.fetch_add(10, Ordering::SeqCst);
-});
-
-// Index with the value loaded from the atomic. This is safe because we
-// read the atomic memory only once, and then pass a copy of that value
-// to the Vec's indexing implementation. This indexing will be correctly
-// bounds checked, and there's no chance of the value getting changed
-// in the middle. However our program may panic if the thread we spawned
-// managed to increment before this ran. A race condition because correct
-// program execution (panicking is rarely correct) depends on order of
-// thread execution.
-println!("{}", data[idx.load(Ordering::SeqCst)]);
-```
-
-```rust,no_run
-use std::thread;
-use std::sync::atomic::{AtomicUsize, Ordering};
-use std::sync::Arc;
-
-let data = vec![1, 2, 3, 4];
-
-let idx = Arc::new(AtomicUsize::new(0));
-let other_idx = idx.clone();
-
-// `move` captures other_idx by-value, moving it into this thread
-thread::spawn(move || {
-    // It's ok to mutate idx because this value
-    // is an atomic, so it can't cause a Data Race.
-    other_idx.fetch_add(10, Ordering::SeqCst);
-});
-
-if idx.load(Ordering::SeqCst) < data.len() {
-    unsafe {
-        // Incorrectly loading the idx after we did the bounds check.
-        // It could have changed. This is a race condition, *and dangerous*
-        // because we decided to do `get_unchecked`, which is `unsafe`.
-        println!("{}", data.get_unchecked(idx.load(Ordering::SeqCst)));
-    }
-}
-```
diff --git a/src/doc/nomicon/src/references.md b/src/doc/nomicon/src/references.md
deleted file mode 100644 (file)
index 5d80f1e..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-# References
-
-This section gives a high-level view of the memory model that *all* Rust
-programs must satisfy to be correct. Safe code is statically verified
-to obey this model by the borrow checker. Unsafe code may go above
-and beyond the borrow checker while still satisfying this model. The borrow
-checker may also be extended to allow more programs to compile, as long as
-this more fundamental model is satisfied.
-
-There are two kinds of reference:
-
-* Shared reference: `&`
-* Mutable reference: `&mut`
-
-Which obey the following rules:
-
-* A reference cannot outlive its referent
-* A mutable reference cannot be aliased
-
-That's it. That's the whole model. Of course, we should probably define
-what *aliased* means. To define aliasing, we must define the notion of
-*paths* and *liveness*.
-
-
-**NOTE: The model that follows is generally agreed to be dubious and have
-issues. It's ok-ish as an intuitive model, but fails to capture the desired
-semantics. We leave this here to be able to use notions introduced here in later
-sections. This will be significantly changed in the future. TODO: do that.**
-
-
-# Paths
-
-If all Rust had were values (no pointers), then every value would be uniquely
-owned by a variable or composite structure. From this we naturally derive a
-*tree* of ownership. The stack itself is the root of the tree, with every
-variable as its direct children. Each variable's direct children would be their
-fields (if any), and so on.
-
-From this view, every value in Rust has a unique *path* in the tree of
-ownership. Of particular interest are *ancestors* and *descendants*: if `x` owns
-`y`, then `x` is an ancestor of `y`, and `y` is a descendant of `x`. Note
-that this is an inclusive relationship: `x` is a descendant and ancestor of
-itself.
-
-We can then define references as simply *names* for paths. When you create a
-reference, you're declaring that an ownership path exists to this address
-of memory.
-
-Tragically, plenty of data doesn't reside on the stack, and we must also
-accommodate this. Globals and thread-locals are simple enough to model as
-residing at the bottom of the stack (though we must be careful with mutable
-globals). Data on the heap poses a different problem.
-
-If all Rust had on the heap was data uniquely owned by a pointer on the stack,
-then we could just treat such a pointer as a struct that owns the value on the
-heap. Box, Vec, String, and HashMap, are examples of types which uniquely
-own data on the heap.
-
-Unfortunately, data on the heap is not *always* uniquely owned. Rc for instance
-introduces a notion of *shared* ownership. Shared ownership of a value means
-there is no unique path to it. A value with no unique path limits what we can do
-with it.
-
-In general, only shared references can be created to non-unique paths. However
-mechanisms which ensure mutual exclusion may establish One True Owner
-temporarily, establishing a unique path to that value (and therefore all
-its children). If this is done, the value may be mutated. In particular, a
-mutable reference can be taken.
-
-The most common way to establish such a path is through *interior mutability*,
-in contrast to the *inherited mutability* that everything in Rust normally uses.
-Cell, RefCell, Mutex, and RWLock are all examples of interior mutability types.
-These types provide exclusive access through runtime restrictions.
-
-An interesting case of this effect is Rc itself: if an Rc has refcount 1,
-then it is safe to mutate or even move its internals. Note however that the
-refcount itself uses interior mutability.
-
-In order to correctly communicate to the type system that a variable or field of
-a struct can have interior mutability, it must be wrapped in an UnsafeCell. This
-does not in itself make it safe to perform interior mutability operations on
-that value. You still must yourself ensure that mutual exclusion is upheld.
-
-
-
-
-# Liveness
-
-Note: Liveness is not the same thing as a *lifetime*, which will be explained
-in detail in the next section of this chapter.
-
-Roughly, a reference is *live* at some point in a program if it can be
-dereferenced. Shared references are always live unless they are literally
-unreachable (for instance, they reside in freed or leaked memory). Mutable
-references can be reachable but *not* live through the process of *reborrowing*.
-
-A mutable reference can be reborrowed to either a shared or mutable reference to
-one of its descendants. A reborrowed reference will only be live again once all
-reborrows derived from it expire. For instance, a mutable reference can be
-reborrowed to point to a field of its referent:
-
-```rust
-let x = &mut (1, 2);
-{
-    // reborrow x to a subfield
-    let y = &mut x.0;
-    // y is now live, but x isn't
-    *y = 3;
-}
-// y goes out of scope, so x is live again
-*x = (5, 7);
-```
-
-It is also possible to reborrow into *multiple* mutable references, as long as
-they are *disjoint*: no reference is an ancestor of another. Rust
-explicitly enables this to be done with disjoint struct fields, because
-disjointness can be statically proven:
-
-```rust
-let x = &mut (1, 2);
-{
-    // reborrow x to two disjoint subfields
-    let y = &mut x.0;
-    let z = &mut x.1;
-
-    // y and z are now live, but x isn't
-    *y = 3;
-    *z = 4;
-}
-// y and z go out of scope, so x is live again
-*x = (5, 7);
-```
-
-However it's often the case that Rust isn't sufficiently smart to prove that
-multiple borrows are disjoint. *This does not mean it is fundamentally illegal
-to make such a borrow*, just that Rust isn't as smart as you want.
-
-To simplify things, we can model variables as a fake type of reference: *owned*
-references. Owned references have much the same semantics as mutable references:
-they can be re-borrowed in a mutable or shared manner, which makes them no
-longer live. Live owned references have the unique property that they can be
-moved out of (though mutable references *can* be swapped out of). This power is
-only given to *live* owned references because moving its referent would of
-course invalidate all outstanding references prematurely.
-
-As a local lint against inappropriate mutation, only variables that are marked
-as `mut` can be borrowed mutably.
-
-It is interesting to note that Box behaves exactly like an owned reference. It
-can be moved out of, and Rust understands it sufficiently to reason about its
-paths like a normal variable.
-
-
-
-
-# Aliasing
-
-With liveness and paths defined, we can now properly define *aliasing*:
-
-**A mutable reference is aliased if there exists another live reference to one
-of its ancestors or descendants.**
-
-(If you prefer, you may also say the two live references alias *each other*.
-This has no semantic consequences, but is probably a more useful notion when
-verifying the soundness of a construct.)
-
-That's it. Super simple right? Except for the fact that it took us two pages to
-define all of the terms in that definition. You know: Super. Simple.
-
-Actually it's a bit more complicated than that. In addition to references, Rust
-has *raw pointers*: `*const T` and `*mut T`. Raw pointers have no inherent
-ownership or aliasing semantics. As a result, Rust makes absolutely no effort to
-track that they are used correctly, and they are wildly unsafe.
-
-**It is an open question to what degree raw pointers have alias semantics.
-However it is important for these definitions to be sound that the existence of
-a raw pointer does not imply some kind of live path.**
diff --git a/src/doc/nomicon/src/repr-rust.md b/src/doc/nomicon/src/repr-rust.md
deleted file mode 100644 (file)
index c02cf44..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-# repr(Rust)
-
-First and foremost, all types have an alignment specified in bytes. The
-alignment of a type specifies what addresses are valid to store the value at. A
-value of alignment `n` must only be stored at an address that is a multiple of
-`n`. So alignment 2 means you must be stored at an even address, and 1 means
-that you can be stored anywhere. Alignment is at least 1, and always a power of
-2. Most primitives are generally aligned to their size, although this is
-platform-specific behavior. In particular, on x86 `u64` and `f64` may be only
-aligned to 32 bits.
-
-A type's size must always be a multiple of its alignment. This ensures that an
-array of that type may always be indexed by offsetting by a multiple of its
-size. Note that the size and alignment of a type may not be known
-statically in the case of [dynamically sized types][dst].
-
-Rust gives you the following ways to lay out composite data:
-
-* structs (named product types)
-* tuples (anonymous product types)
-* arrays (homogeneous product types)
-* enums (named sum types -- tagged unions)
-
-An enum is said to be *C-like* if none of its variants have associated data.
-
-Composite structures will have an alignment equal to the maximum
-of their fields' alignment. Rust will consequently insert padding where
-necessary to ensure that all fields are properly aligned and that the overall
-type's size is a multiple of its alignment. For instance:
-
-```rust
-struct A {
-    a: u8,
-    b: u32,
-    c: u16,
-}
-```
-
-will be 32-bit aligned on an architecture that aligns these primitives to their
-respective sizes. The whole struct will therefore have a size that is a multiple
-of 32-bits. It will potentially become:
-
-```rust
-struct A {
-    a: u8,
-    _pad1: [u8; 3], // to align `b`
-    b: u32,
-    c: u16,
-    _pad2: [u8; 2], // to make overall size multiple of 4
-}
-```
-
-There is *no indirection* for these types; all data is stored within the struct,
-as you would expect in C. However with the exception of arrays (which are
-densely packed and in-order), the layout of data is not by default specified in
-Rust. Given the two following struct definitions:
-
-```rust
-struct A {
-    a: i32,
-    b: u64,
-}
-
-struct B {
-    a: i32,
-    b: u64,
-}
-```
-
-Rust *does* guarantee that two instances of A have their data laid out in
-exactly the same way. However Rust *does not* currently guarantee that an
-instance of A has the same field ordering or padding as an instance of B, though
-in practice there's no reason why they wouldn't.
-
-With A and B as written, this point would seem to be pedantic, but several other
-features of Rust make it desirable for the language to play with data layout in
-complex ways.
-
-For instance, consider this struct:
-
-```rust
-struct Foo<T, U> {
-    count: u16,
-    data1: T,
-    data2: U,
-}
-```
-
-Now consider the monomorphizations of `Foo<u32, u16>` and `Foo<u16, u32>`. If
-Rust lays out the fields in the order specified, we expect it to pad the
-values in the struct to satisfy their alignment requirements. So if Rust
-didn't reorder fields, we would expect it to produce the following:
-
-```rust,ignore
-struct Foo<u16, u32> {
-    count: u16,
-    data1: u16,
-    data2: u32,
-}
-
-struct Foo<u32, u16> {
-    count: u16,
-    _pad1: u16,
-    data1: u32,
-    data2: u16,
-    _pad2: u16,
-}
-```
-
-The latter case quite simply wastes space. An optimal use of space therefore
-requires different monomorphizations to have *different field orderings*.
-
-**Note: this is a hypothetical optimization that is not yet implemented in Rust
-1.0**
-
-Enums make this consideration even more complicated. Naively, an enum such as:
-
-```rust
-enum Foo {
-    A(u32),
-    B(u64),
-    C(u8),
-}
-```
-
-would be laid out as:
-
-```rust
-struct FooRepr {
-    data: u64, // this is either a u64, u32, or u8 based on `tag`
-    tag: u8,   // 0 = A, 1 = B, 2 = C
-}
-```
-
-And indeed this is approximately how it would be laid out in general (modulo the
-size and position of `tag`).
-
-However there are several cases where such a representation is inefficient. The
-classic case of this is Rust's "null pointer optimization": an enum consisting
-of a single outer unit variant (e.g. `None`) and a (potentially nested) non-
-nullable pointer variant (e.g. `&T`) makes the tag unnecessary, because a null
-pointer value can safely be interpreted to mean that the unit variant is chosen
-instead. The net result is that, for example, `size_of::<Option<&T>>() ==
-size_of::<&T>()`.
-
-There are many types in Rust that are, or contain, non-nullable pointers such as
-`Box<T>`, `Vec<T>`, `String`, `&T`, and `&mut T`. Similarly, one can imagine
-nested enums pooling their tags into a single discriminant, as they are by
-definition known to have a limited range of valid values. In principle enums could
-use fairly elaborate algorithms to cache bits throughout nested types with
-special constrained representations. As such it is *especially* desirable that
-we leave enum layout unspecified today.
-
-[dst]: exotic-sizes.html#dynamically-sized-types-dsts
diff --git a/src/doc/nomicon/src/safe-unsafe-meaning.md b/src/doc/nomicon/src/safe-unsafe-meaning.md
deleted file mode 100644 (file)
index 0a655a3..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-# How Safe and Unsafe Interact
-
-What's the relationship between Safe Rust and Unsafe Rust? How do they
-interact?
-
-The separation between Safe Rust and Unsafe Rust is controlled with the
-`unsafe` keyword, which acts as an interface from one to the other. This is
-why we can say Safe Rust is a safe language: all the unsafe parts are kept
-exclusively behind the boundary.
-
-The `unsafe` keyword has two uses: to declare the existence of contracts the
-compiler can't check, and to declare that the adherence of some code to
-those contracts has been checked by the programmer.
-
-You can use `unsafe` to indicate the existence of unchecked contracts on
-_functions_ and on _trait declarations_. On functions, `unsafe` means that
-users of the function must check that function's documentation to ensure
-they are using it in a way that maintains the contracts the function
-requires. On trait declarations, `unsafe` means that implementors of the
-trait must check the trait documentation to ensure their implementation
-maintains the contracts the trait requires.
-
-You can use `unsafe` on a block to declare that all constraints required
-by an unsafe function within the block have been adhered to, and the code
-can therefore be trusted. You can use `unsafe` on a trait implementation
-to declare that the implementation of that trait has adhered to whatever
-contracts the trait's documentation requires.
-
-The standard library has a number of unsafe functions, including:
-
-* `slice::get_unchecked`, which performs unchecked indexing, allowing
-  memory safety to be freely violated.
-* `mem::transmute` reinterprets some value as having a given type, bypassing
-  type safety in arbitrary ways (see [conversions] for details).
-* Every raw pointer to a sized type has an intrinstic `offset` method that
-  invokes Undefined Behavior if the passed offset is not "in bounds" as
-  defined by LLVM.
-* All FFI functions are `unsafe` because the other language can do arbitrary
-  operations that the Rust compiler can't check.
-
-As of Rust 1.0 there are exactly two unsafe traits:
-
-* `Send` is a marker trait (a trait with no API) that promises implementors are
-  safe to send (move) to another thread.
-* `Sync` is a marker trait that promises threads can safely share implementors
-  through a shared reference.
-
-Much of the Rust standard library also uses Unsafe Rust internally, although
-these implementations are rigorously manually checked, and the Safe Rust
-interfaces provided on top of these implementations can be assumed to be safe.
-
-The need for all of this separation boils down a single fundamental property
-of Safe Rust:
-
-**No matter what, Safe Rust can't cause Undefined Behavior.**
-
-The design of the safe/unsafe split means that Safe Rust inherently has to
-trust that any Unsafe Rust it touches has been written correctly (meaning
-the Unsafe Rust actually maintains whatever contracts it is supposed to
-maintain). On the other hand, Unsafe Rust has to be very careful about
-trusting Safe Rust.
-
-As an example, Rust has the `PartialOrd` and `Ord` traits to differentiate
-between types which can "just" be compared, and those that provide a total
-ordering (where every value of the type is either equal to, greater than,
-or less than any other value of the same type). The sorted map type
-`BTreeMap` doesn't make sense for partially-ordered types, and so it
-requires that any key type for it implements the `Ord` trait. However,
-`BTreeMap` has Unsafe Rust code inside of its implementation, and this
-Unsafe Rust code cannot assume that any `Ord` implementation it gets makes
-sense. The unsafe portions of `BTreeMap`'s internals have to be careful to
-maintain all necessary contracts, even if a key type's `Ord` implementation
-does not implement a total ordering.
-
-Unsafe Rust cannot automatically trust Safe Rust. When writing Unsafe Rust,
-you must be careful to only rely on specific Safe Rust code, and not make
-assumptions about potential future Safe Rust code providing the same
-guarantees.
-
-This is the problem that `unsafe` traits exist to resolve. The `BTreeMap`
-type could theoretically require that keys implement a new trait called
-`UnsafeOrd`, rather than `Ord`, that might look like this:
-
-```rust
-use std::cmp::Ordering;
-
-unsafe trait UnsafeOrd {
-    fn cmp(&self, other: &Self) -> Ordering;
-}
-```
-
-Then, a type would use `unsafe` to implement `UnsafeOrd`, indicating that
-they've ensured their implementation maintains whatever contracts the
-trait expects. In this situation, the Unsafe Rust in the internals of
-`BTreeMap` could trust that the key type's `UnsafeOrd` implementation is
-correct. If it isn't, it's the fault of the unsafe trait implementation
-code, which is consistent with Rust's safety guarantees.
-
-The decision of whether to mark a trait `unsafe` is an API design choice.
-Rust has traditionally avoided marking traits unsafe because it makes Unsafe
-Rust pervasive, which is not desirable. `Send` and `Sync` are marked unsafe
-because thread safety is a *fundamental property* that unsafe code can't
-possibly hope to defend against in the way it could defend against a bad
-`Ord` implementation. The decision of whether to mark your own traits `unsafe`
-depends on the same sort of consideration. If `unsafe` code cannot reasonably
-expect to defend against a bad implementation of the trait, then marking the
-trait `unsafe` is a reasonable choice.
-
-As an aside, while `Send` and `Sync` are `unsafe` traits, they are
-automatically implemented for types when such derivations are provably safe
-to do. `Send` is automatically derived for all types composed only of values
-whose types also implement `Send`. `Sync` is automatically derived for all
-types composed only of values whose types also implement `Sync`.
-
-This is the dance of Safe Rust and Unsafe Rust. It is designed to make using
-Safe Rust as ergonomic as possible, but requires extra effort and care when
-writing Unsafe Rust. The rest of the book is largely a discussion of the sort
-of care that must be taken, and what contracts it is expected of Unsafe Rust
-to uphold.
-
-[drop flags]: drop-flags.html
-[conversions]: conversions.html
-
diff --git a/src/doc/nomicon/src/send-and-sync.md b/src/doc/nomicon/src/send-and-sync.md
deleted file mode 100644 (file)
index 959f870..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-# Send and Sync
-
-Not everything obeys inherited mutability, though. Some types allow you to
-multiply alias a location in memory while mutating it. Unless these types use
-synchronization to manage this access, they are absolutely not thread safe. Rust
-captures this through the `Send` and `Sync` traits.
-
-* A type is Send if it is safe to send it to another thread.
-* A type is Sync if it is safe to share between threads (`&T` is Send).
-
-Send and Sync are fundamental to Rust's concurrency story. As such, a
-substantial amount of special tooling exists to make them work right. First and
-foremost, they're [unsafe traits]. This means that they are unsafe to
-implement, and other unsafe code can assume that they are correctly
-implemented. Since they're *marker traits* (they have no associated items like
-methods), correctly implemented simply means that they have the intrinsic
-properties an implementor should have. Incorrectly implementing Send or Sync can
-cause Undefined Behavior.
-
-Send and Sync are also automatically derived traits. This means that, unlike
-every other trait, if a type is composed entirely of Send or Sync types, then it
-is Send or Sync. Almost all primitives are Send and Sync, and as a consequence
-pretty much all types you'll ever interact with are Send and Sync.
-
-Major exceptions include:
-
-* raw pointers are neither Send nor Sync (because they have no safety guards).
-* `UnsafeCell` isn't Sync (and therefore `Cell` and `RefCell` aren't).
-* `Rc` isn't Send or Sync (because the refcount is shared and unsynchronized).
-
-`Rc` and `UnsafeCell` are very fundamentally not thread-safe: they enable
-unsynchronized shared mutable state. However raw pointers are, strictly
-speaking, marked as thread-unsafe as more of a *lint*. Doing anything useful
-with a raw pointer requires dereferencing it, which is already unsafe. In that
-sense, one could argue that it would be "fine" for them to be marked as thread
-safe.
-
-However it's important that they aren't thread safe to prevent types that
-contain them from being automatically marked as thread safe. These types have
-non-trivial untracked ownership, and it's unlikely that their author was
-necessarily thinking hard about thread safety. In the case of Rc, we have a nice
-example of a type that contains a `*mut` that is definitely not thread safe.
-
-Types that aren't automatically derived can simply implement them if desired:
-
-```rust
-struct MyBox(*mut u8);
-
-unsafe impl Send for MyBox {}
-unsafe impl Sync for MyBox {}
-```
-
-In the *incredibly rare* case that a type is inappropriately automatically
-derived to be Send or Sync, then one can also unimplement Send and Sync:
-
-```rust
-#![feature(optin_builtin_traits)]
-
-// I have some magic semantics for some synchronization primitive!
-struct SpecialThreadToken(u8);
-
-impl !Send for SpecialThreadToken {}
-impl !Sync for SpecialThreadToken {}
-```
-
-Note that *in and of itself* it is impossible to incorrectly derive Send and
-Sync. Only types that are ascribed special meaning by other unsafe code can
-possible cause trouble by being incorrectly Send or Sync.
-
-Most uses of raw pointers should be encapsulated behind a sufficient abstraction
-that Send and Sync can be derived. For instance all of Rust's standard
-collections are Send and Sync (when they contain Send and Sync types) in spite
-of their pervasive use of raw pointers to manage allocations and complex ownership.
-Similarly, most iterators into these collections are Send and Sync because they
-largely behave like an `&` or `&mut` into the collection.
-
-TODO: better explain what can or can't be Send or Sync. Sufficient to appeal
-only to data races?
-
-[unsafe traits]: safe-unsafe-meaning.html
diff --git a/src/doc/nomicon/src/subtyping.md b/src/doc/nomicon/src/subtyping.md
deleted file mode 100644 (file)
index d771712..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-# Subtyping and Variance
-
-Although Rust doesn't have any notion of structural inheritance, it *does*
-include subtyping. In Rust, subtyping derives entirely from lifetimes. Since
-lifetimes are scopes, we can partially order them based on the *contains*
-(outlives) relationship. We can even express this as a generic bound.
-
-Subtyping on lifetimes is in terms of that relationship: if `'a: 'b` ("a contains
-b" or "a outlives b"), then `'a` is a subtype of `'b`. This is a large source of
-confusion, because it seems intuitively backwards to many: the bigger scope is a
-*subtype* of the smaller scope.
-
-This does in fact make sense, though. The intuitive reason for this is that if
-you expect an `&'a u8`, then it's totally fine for me to hand you an `&'static
-u8`, in the same way that if you expect an Animal in Java, it's totally fine for
-me to hand you a Cat. Cats are just Animals *and more*, just as `'static` is
-just `'a` *and more*.
-
-(Note, the subtyping relationship and typed-ness of lifetimes is a fairly
-arbitrary construct that some disagree with. However it simplifies our analysis
-to treat lifetimes and types uniformly.)
-
-Higher-ranked lifetimes are also subtypes of every concrete lifetime. This is
-because taking an arbitrary lifetime is strictly more general than taking a
-specific one.
-
-
-
-# Variance
-
-Variance is where things get a bit complicated.
-
-Variance is a property that *type constructors* have with respect to their
-arguments. A type constructor in Rust is a generic type with unbound arguments.
-For instance `Vec` is a type constructor that takes a `T` and returns a
-`Vec<T>`. `&` and `&mut` are type constructors that take two inputs: a
-lifetime, and a type to point to.
-
-A type constructor's *variance* is how the subtyping of its inputs affects the
-subtyping of its outputs. There are two kinds of variance in Rust:
-
-* F is *variant* over `T` if `T` being a subtype of `U` implies
-  `F<T>` is a subtype of `F<U>` (subtyping "passes through")
-* F is *invariant* over `T` otherwise (no subtyping relation can be derived)
-
-(For those of you who are familiar with variance from other languages, what we
-refer to as "just" variance is in fact *covariance*. Rust has *contravariance*
-for functions. The future of contravariance is uncertain and it may be
-scrapped. For now, `fn(T)` is contravariant in `T`, which is used in matching
-methods in trait implementations to the trait definition. Traits don't have
-inferred variance, so `Fn(T)` is invariant in `T`).
-
-Some important variances:
-
-* `&'a T` is variant over `'a` and `T` (as is `*const T` by metaphor)
-* `&'a mut T` is variant over `'a` but invariant over `T`
-* `Fn(T) -> U` is invariant over `T`, but variant over `U`
-* `Box`, `Vec`, and all other collections are variant over the types of
-  their contents
-* `UnsafeCell<T>`, `Cell<T>`, `RefCell<T>`, `Mutex<T>` and all other
-  interior mutability types are invariant over T (as is `*mut T` by metaphor)
-
-To understand why these variances are correct and desirable, we will consider
-several examples.
-
-
-We have already covered why `&'a T` should be variant over `'a` when
-introducing subtyping: it's desirable to be able to pass longer-lived things
-where shorter-lived things are needed.
-
-Similar reasoning applies to why it should be variant over T. It is reasonable
-to be able to pass `&&'static str` where an `&&'a str` is expected. The
-additional level of indirection does not change the desire to be able to pass
-longer lived things where shorted lived things are expected.
-
-However this logic doesn't apply to `&mut`. To see why `&mut` should
-be invariant over T, consider the following code:
-
-```rust,ignore
-fn overwrite<T: Copy>(input: &mut T, new: &mut T) {
-    *input = *new;
-}
-
-fn main() {
-    let mut forever_str: &'static str = "hello";
-    {
-        let string = String::from("world");
-        overwrite(&mut forever_str, &mut &*string);
-    }
-    // Oops, printing free'd memory
-    println!("{}", forever_str);
-}
-```
-
-The signature of `overwrite` is clearly valid: it takes mutable references to
-two values of the same type, and overwrites one with the other. If `&mut T` was
-variant over T, then `&mut &'static str` would be a subtype of `&mut &'a str`,
-since `&'static str` is a subtype of `&'a str`. Therefore the lifetime of
-`forever_str` would successfully be "shrunk" down to the shorter lifetime of
-`string`, and `overwrite` would be called successfully. `string` would
-subsequently be dropped, and `forever_str` would point to freed memory when we
-print it! Therefore `&mut` should be invariant.
-
-This is the general theme of variance vs invariance: if variance would allow you
-to store a short-lived value into a longer-lived slot, then you must be
-invariant.
-
-However it *is* sound for `&'a mut T` to be variant over `'a`. The key difference
-between `'a` and T is that `'a` is a property of the reference itself,
-while T is something the reference is borrowing. If you change T's type, then
-the source still remembers the original type. However if you change the
-lifetime's type, no one but the reference knows this information, so it's fine.
-Put another way: `&'a mut T` owns `'a`, but only *borrows* T.
-
-`Box` and `Vec` are interesting cases because they're variant, but you can
-definitely store values in them! This is where Rust gets really clever: it's
-fine for them to be variant because you can only store values
-in them *via a mutable reference*! The mutable reference makes the whole type
-invariant, and therefore prevents you from smuggling a short-lived type into
-them.
-
-Being variant allows `Box` and `Vec` to be weakened when shared
-immutably. So you can pass a `&Box<&'static str>` where a `&Box<&'a str>` is
-expected.
-
-However what should happen when passing *by-value* is less obvious. It turns out
-that, yes, you can use subtyping when passing by-value. That is, this works:
-
-```rust
-fn get_box<'a>(str: &'a str) -> Box<&'a str> {
-    // string literals are `&'static str`s
-    Box::new("hello")
-}
-```
-
-Weakening when you pass by-value is fine because there's no one else who
-"remembers" the old lifetime in the Box. The reason a variant `&mut` was
-trouble was because there's always someone else who remembers the original
-subtype: the actual owner.
-
-The invariance of the cell types can be seen as follows: `&` is like an `&mut`
-for a cell, because you can still store values in them through an `&`. Therefore
-cells must be invariant to avoid lifetime smuggling.
-
-`Fn` is the most subtle case because it has mixed variance. To see why
-`Fn(T) -> U` should be invariant over T, consider the following function
-signature:
-
-```rust,ignore
-// 'a is derived from some parent scope
-fn foo(&'a str) -> usize;
-```
-
-This signature claims that it can handle any `&str` that lives at least as
-long as `'a`. Now if this signature was variant over `&'a str`, that
-would mean
-
-```rust,ignore
-fn foo(&'static str) -> usize;
-```
-
-could be provided in its place, as it would be a subtype. However this function
-has a stronger requirement: it says that it can only handle `&'static str`s,
-and nothing else. Giving `&'a str`s to it would be unsound, as it's free to
-assume that what it's given lives forever. Therefore functions are not variant
-over their arguments.
-
-To see why `Fn(T) -> U` should be variant over U, consider the following
-function signature:
-
-```rust,ignore
-// 'a is derived from some parent scope
-fn foo(usize) -> &'a str;
-```
-
-This signature claims that it will return something that outlives `'a`. It is
-therefore completely reasonable to provide
-
-```rust,ignore
-fn foo(usize) -> &'static str;
-```
-
-in its place. Therefore functions are variant over their return type.
-
-`*const` has the exact same semantics as `&`, so variance follows. `*mut` on the
-other hand can dereference to an `&mut` whether shared or not, so it is marked
-as invariant just like cells.
-
-This is all well and good for the types the standard library provides, but
-how is variance determined for type that *you* define? A struct, informally
-speaking, inherits the variance of its fields. If a struct `Foo`
-has a generic argument `A` that is used in a field `a`, then Foo's variance
-over `A` is exactly `a`'s variance. However this is complicated if `A` is used
-in multiple fields.
-
-* If all uses of A are variant, then Foo is variant over A
-* Otherwise, Foo is invariant over A
-
-```rust
-use std::cell::Cell;
-
-struct Foo<'a, 'b, A: 'a, B: 'b, C, D, E, F, G, H> {
-    a: &'a A,     // variant over 'a and A
-    b: &'b mut B, // variant over 'b and invariant over B
-    c: *const C,  // variant over C
-    d: *mut D,    // invariant over D
-    e: Vec<E>,    // variant over E
-    f: Cell<F>,   // invariant over F
-    g: G,         // variant over G
-    h1: H,        // would also be variant over H except...
-    h2: Cell<H>,  // invariant over H, because invariance wins
-}
-```
diff --git a/src/doc/nomicon/src/transmutes.md b/src/doc/nomicon/src/transmutes.md
deleted file mode 100644 (file)
index 043c8fe..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-# Transmutes
-
-Get out of our way type system! We're going to reinterpret these bits or die
-trying! Even though this book is all about doing things that are unsafe, I
-really can't emphasize that you should deeply think about finding Another Way
-than the operations covered in this section. This is really, truly, the most
-horribly unsafe thing you can do in Rust. The railguards here are dental floss.
-
-`mem::transmute<T, U>` takes a value of type `T` and reinterprets it to have
-type `U`. The only restriction is that the `T` and `U` are verified to have the
-same size. The ways to cause Undefined Behavior with this are mind boggling.
-
-* First and foremost, creating an instance of *any* type with an invalid state
-  is going to cause arbitrary chaos that can't really be predicted.
-* Transmute has an overloaded return type. If you do not specify the return type
-  it may produce a surprising type to satisfy inference.
-* Making a primitive with an invalid value is UB
-* Transmuting between non-repr(C) types is UB
-* Transmuting an & to &mut is UB
-    * Transmuting an & to &mut is *always* UB
-    * No you can't do it
-    * No you're not special
-* Transmuting to a reference without an explicitly provided lifetime
-  produces an [unbounded lifetime]
-
-`mem::transmute_copy<T, U>` somehow manages to be *even more* wildly unsafe than
-this. It copies `size_of<U>` bytes out of an `&T` and interprets them as a `U`.
-The size check that `mem::transmute` has is gone (as it may be valid to copy
-out a prefix), though it is Undefined Behavior for `U` to be larger than `T`.
-
-Also of course you can get most of the functionality of these functions using
-pointer casts.
-
-
-[unbounded lifetime]: unbounded-lifetimes.html
diff --git a/src/doc/nomicon/src/unbounded-lifetimes.md b/src/doc/nomicon/src/unbounded-lifetimes.md
deleted file mode 100644 (file)
index b41cf8b..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-# Unbounded Lifetimes
-
-Unsafe code can often end up producing references or lifetimes out of thin air.
-Such lifetimes come into the world as *unbounded*. The most common source of this
-is dereferencing a raw pointer, which produces a reference with an unbounded lifetime.
-Such a lifetime becomes as big as context demands. This is in fact more powerful
-than simply becoming `'static`, because for instance `&'static &'a T`
-will fail to typecheck, but the unbound lifetime will perfectly mold into
-`&'a &'a T` as needed. However for most intents and purposes, such an unbounded
-lifetime can be regarded as `'static`.
-
-Almost no reference is `'static`, so this is probably wrong. `transmute` and
-`transmute_copy` are the two other primary offenders. One should endeavor to
-bound an unbounded lifetime as quickly as possible, especially across function
-boundaries.
-
-Given a function, any output lifetimes that don't derive from inputs are
-unbounded. For instance:
-
-```rust,ignore
-fn get_str<'a>() -> &'a str;
-```
-
-will produce an `&str` with an unbounded lifetime. The easiest way to avoid
-unbounded lifetimes is to use lifetime elision at the function boundary.
-If an output lifetime is elided, then it *must* be bounded by an input lifetime.
-Of course it might be bounded by the *wrong* lifetime, but this will usually
-just cause a compiler error, rather than allow memory safety to be trivially
-violated.
-
-Within a function, bounding lifetimes is more error-prone. The safest and easiest
-way to bound a lifetime is to return it from a function with a bound lifetime.
-However if this is unacceptable, the reference can be placed in a location with
-a specific lifetime. Unfortunately it's impossible to name all lifetimes involved
-in a function.
-
diff --git a/src/doc/nomicon/src/unchecked-uninit.md b/src/doc/nomicon/src/unchecked-uninit.md
deleted file mode 100644 (file)
index ef31a35..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-# Unchecked Uninitialized Memory
-
-One interesting exception to this rule is working with arrays. Safe Rust doesn't
-permit you to partially initialize an array. When you initialize an array, you
-can either set every value to the same thing with `let x = [val; N]`, or you can
-specify each member individually with `let x = [val1, val2, val3]`.
-Unfortunately this is pretty rigid, especially if you need to initialize your
-array in a more incremental or dynamic way.
-
-Unsafe Rust gives us a powerful tool to handle this problem:
-`mem::uninitialized`. This function pretends to return a value when really
-it does nothing at all. Using it, we can convince Rust that we have initialized
-a variable, allowing us to do trickier things with conditional and incremental
-initialization.
-
-Unfortunately, this opens us up to all kinds of problems. Assignment has a
-different meaning to Rust based on whether it believes that a variable is
-initialized or not. If it's believed uninitialized, then Rust will semantically
-just memcopy the bits over the uninitialized ones, and do nothing else. However
-if Rust believes a value to be initialized, it will try to `Drop` the old value!
-Since we've tricked Rust into believing that the value is initialized, we can no
-longer safely use normal assignment.
-
-This is also a problem if you're working with a raw system allocator, which
-returns a pointer to uninitialized memory.
-
-To handle this, we must use the `ptr` module. In particular, it provides
-three functions that allow us to assign bytes to a location in memory without
-dropping the old value: `write`, `copy`, and `copy_nonoverlapping`.
-
-* `ptr::write(ptr, val)` takes a `val` and moves it into the address pointed
-  to by `ptr`.
-* `ptr::copy(src, dest, count)` copies the bits that `count` T's would occupy
-  from src to dest. (this is equivalent to memmove -- note that the argument
-  order is reversed!)
-* `ptr::copy_nonoverlapping(src, dest, count)` does what `copy` does, but a
-  little faster on the assumption that the two ranges of memory don't overlap.
-  (this is equivalent to memcpy -- note that the argument order is reversed!)
-
-It should go without saying that these functions, if misused, will cause serious
-havoc or just straight up Undefined Behavior. The only things that these
-functions *themselves* require is that the locations you want to read and write
-are allocated. However the ways writing arbitrary bits to arbitrary
-locations of memory can break things are basically uncountable!
-
-Putting this all together, we get the following:
-
-```rust
-use std::mem;
-use std::ptr;
-
-// size of the array is hard-coded but easy to change. This means we can't
-// use [a, b, c] syntax to initialize the array, though!
-const SIZE: usize = 10;
-
-let mut x: [Box<u32>; SIZE];
-
-unsafe {
-       // convince Rust that x is Totally Initialized
-       x = mem::uninitialized();
-       for i in 0..SIZE {
-               // very carefully overwrite each index without reading it
-               // NOTE: exception safety is not a concern; Box can't panic
-               ptr::write(&mut x[i], Box::new(i as u32));
-       }
-}
-
-println!("{:?}", x);
-```
-
-It's worth noting that you don't need to worry about `ptr::write`-style
-shenanigans with types which don't implement `Drop` or contain `Drop` types,
-because Rust knows not to try to drop them. Similarly you should be able to
-assign to fields of partially initialized structs directly if those fields don't
-contain any `Drop` types.
-
-However when working with uninitialized memory you need to be ever-vigilant for
-Rust trying to drop values you make like this before they're fully initialized.
-Every control path through that variable's scope must initialize the value
-before it ends, if it has a destructor.
-*[This includes code panicking](unwinding.html)*.
-
-And that's about it for working with uninitialized memory! Basically nothing
-anywhere expects to be handed uninitialized memory, so if you're going to pass
-it around at all, be sure to be *really* careful.
diff --git a/src/doc/nomicon/src/uninitialized.md b/src/doc/nomicon/src/uninitialized.md
deleted file mode 100644 (file)
index eafc679..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# Working With Uninitialized Memory
-
-All runtime-allocated memory in a Rust program begins its life as
-*uninitialized*. In this state the value of the memory is an indeterminate pile
-of bits that may or may not even reflect a valid state for the type that is
-supposed to inhabit that location of memory. Attempting to interpret this memory
-as a value of *any* type will cause Undefined Behavior. Do Not Do This.
-
-Rust provides mechanisms to work with uninitialized memory in checked (safe) and
-unchecked (unsafe) ways.
diff --git a/src/doc/nomicon/src/unwinding.md b/src/doc/nomicon/src/unwinding.md
deleted file mode 100644 (file)
index 6dc396d..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-# Unwinding
-
-Rust has a *tiered* error-handling scheme:
-
-* If something might reasonably be absent, Option is used.
-* If something goes wrong and can reasonably be handled, Result is used.
-* If something goes wrong and cannot reasonably be handled, the thread panics.
-* If something catastrophic happens, the program aborts.
-
-Option and Result are overwhelmingly preferred in most situations, especially
-since they can be promoted into a panic or abort at the API user's discretion.
-Panics cause the thread to halt normal execution and unwind its stack, calling
-destructors as if every function instantly returned.
-
-As of 1.0, Rust is of two minds when it comes to panics. In the long-long-ago,
-Rust was much more like Erlang. Like Erlang, Rust had lightweight tasks,
-and tasks were intended to kill themselves with a panic when they reached an
-untenable state. Unlike an exception in Java or C++, a panic could not be
-caught at any time. Panics could only be caught by the owner of the task, at which
-point they had to be handled or *that* task would itself panic.
-
-Unwinding was important to this story because if a task's
-destructors weren't called, it would cause memory and other system resources to
-leak. Since tasks were expected to die during normal execution, this would make
-Rust very poor for long-running systems!
-
-As the Rust we know today came to be, this style of programming grew out of
-fashion in the push for less-and-less abstraction. Light-weight tasks were
-killed in the name of heavy-weight OS threads. Still, on stable Rust as of 1.0
-panics can only be caught by the parent thread. This means catching a panic
-requires spinning up an entire OS thread! This unfortunately stands in conflict
-to Rust's philosophy of zero-cost abstractions.
-
-There is an unstable API called `catch_panic` that enables catching a panic
-without spawning a thread. Still, we would encourage you to only do this
-sparingly. In particular, Rust's current unwinding implementation is heavily
-optimized for the "doesn't unwind" case. If a program doesn't unwind, there
-should be no runtime cost for the program being *ready* to unwind. As a
-consequence, actually unwinding will be more expensive than in e.g. Java.
-Don't build your programs to unwind under normal circumstances. Ideally, you
-should only panic for programming errors or *extreme* problems.
-
-Rust's unwinding strategy is not specified to be fundamentally compatible
-with any other language's unwinding. As such, unwinding into Rust from another
-language, or unwinding into another language from Rust is Undefined Behavior.
-You must *absolutely* catch any panics at the FFI boundary! What you do at that
-point is up to you, but *something* must be done. If you fail to do this,
-at best, your application will crash and burn. At worst, your application *won't*
-crash and burn, and will proceed with completely clobbered state.
diff --git a/src/doc/nomicon/src/vec-alloc.md b/src/doc/nomicon/src/vec-alloc.md
deleted file mode 100644 (file)
index ef4c527..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-# Allocating Memory
-
-Using Unique throws a wrench in an important feature of Vec (and indeed all of
-the std collections): an empty Vec doesn't actually allocate at all. So if we
-can't allocate, but also can't put a null pointer in `ptr`, what do we do in
-`Vec::new`? Well, we just put some other garbage in there!
-
-This is perfectly fine because we already have `cap == 0` as our sentinel for no
-allocation. We don't even need to handle it specially in almost any code because
-we usually need to check if `cap > len` or `len > 0` anyway. The traditional
-Rust value to put here is `0x01`. The standard library actually exposes this
-as `alloc::heap::EMPTY`. There are quite a few places where we'll
-want to use `heap::EMPTY` because there's no real allocation to talk about but
-`null` would make the compiler do bad things.
-
-All of the `heap` API is totally unstable under the `heap_api` feature, though.
-We could trivially define `heap::EMPTY` ourselves, but we'll want the rest of
-the `heap` API anyway, so let's just get that dependency over with.
-
-So:
-
-```rust,ignore
-#![feature(alloc, heap_api)]
-
-use std::mem;
-
-use alloc::heap::EMPTY;
-
-impl<T> Vec<T> {
-    fn new() -> Self {
-        assert!(mem::size_of::<T>() != 0, "We're not ready to handle ZSTs");
-        unsafe {
-            // need to cast EMPTY to the actual ptr type we want, let
-            // inference handle it.
-            Vec { ptr: Unique::new(heap::EMPTY as *mut _), len: 0, cap: 0 }
-        }
-    }
-}
-```
-
-I slipped in that assert there because zero-sized types will require some
-special handling throughout our code, and I want to defer the issue for now.
-Without this assert, some of our early drafts will do some Very Bad Things.
-
-Next we need to figure out what to actually do when we *do* want space. For
-that, we'll need to use the rest of the heap APIs. These basically allow us to
-talk directly to Rust's allocator (jemalloc by default).
-
-We'll also need a way to handle out-of-memory (OOM) conditions. The standard
-library calls the `abort` intrinsic, which just calls an illegal instruction to
-crash the whole program. The reason we abort and don't panic is because
-unwinding can cause allocations to happen, and that seems like a bad thing to do
-when your allocator just came back with "hey I don't have any more memory".
-
-Of course, this is a bit silly since most platforms don't actually run out of
-memory in a conventional way. Your operating system will probably kill the
-application by another means if you legitimately start using up all the memory.
-The most likely way we'll trigger OOM is by just asking for ludicrous quantities
-of memory at once (e.g. half the theoretical address space). As such it's
-*probably* fine to panic and nothing bad will happen. Still, we're trying to be
-like the standard library as much as possible, so we'll just kill the whole
-program.
-
-We said we don't want to use intrinsics, so doing exactly what `std` does is
-out. Instead, we'll call `std::process::exit` with some random number.
-
-```rust
-fn oom() {
-    ::std::process::exit(-9999);
-}
-```
-
-Okay, now we can write growing. Roughly, we want to have this logic:
-
-```text
-if cap == 0:
-    allocate()
-    cap = 1
-else:
-    reallocate()
-    cap *= 2
-```
-
-But Rust's only supported allocator API is so low level that we'll need to do a
-fair bit of extra work. We also need to guard against some special
-conditions that can occur with really large allocations or empty allocations.
-
-In particular, `ptr::offset` will cause us a lot of trouble, because it has
-the semantics of LLVM's GEP inbounds instruction. If you're fortunate enough to
-not have dealt with this instruction, here's the basic story with GEP: alias
-analysis, alias analysis, alias analysis. It's super important to an optimizing
-compiler to be able to reason about data dependencies and aliasing.
-
-As a simple example, consider the following fragment of code:
-
-```rust
-# let x = &mut 0;
-# let y = &mut 0;
-*x *= 7;
-*y *= 3;
-```
-
-If the compiler can prove that `x` and `y` point to different locations in
-memory, the two operations can in theory be executed in parallel (by e.g.
-loading them into different registers and working on them independently).
-However the compiler can't do this in general because if x and y point to
-the same location in memory, the operations need to be done to the same value,
-and they can't just be merged afterwards.
-
-When you use GEP inbounds, you are specifically telling LLVM that the offsets
-you're about to do are within the bounds of a single "allocated" entity. The
-ultimate payoff being that LLVM can assume that if two pointers are known to
-point to two disjoint objects, all the offsets of those pointers are *also*
-known to not alias (because you won't just end up in some random place in
-memory). LLVM is heavily optimized to work with GEP offsets, and inbounds
-offsets are the best of all, so it's important that we use them as much as
-possible.
-
-So that's what GEP's about, how can it cause us trouble?
-
-The first problem is that we index into arrays with unsigned integers, but
-GEP (and as a consequence `ptr::offset`) takes a signed integer. This means
-that half of the seemingly valid indices into an array will overflow GEP and
-actually go in the wrong direction! As such we must limit all allocations to
-`isize::MAX` elements. This actually means we only need to worry about
-byte-sized objects, because e.g. `> isize::MAX` `u16`s will truly exhaust all of
-the system's memory. However in order to avoid subtle corner cases where someone
-reinterprets some array of `< isize::MAX` objects as bytes, std limits all
-allocations to `isize::MAX` bytes.
-
-On all 64-bit targets that Rust currently supports we're artificially limited
-to significantly less than all 64 bits of the address space (modern x64
-platforms only expose 48-bit addressing), so we can rely on just running out of
-memory first. However on 32-bit targets, particularly those with extensions to
-use more of the address space (PAE x86 or x32), it's theoretically possible to
-successfully allocate more than `isize::MAX` bytes of memory.
-
-However since this is a tutorial, we're not going to be particularly optimal
-here, and just unconditionally check, rather than use clever platform-specific
-`cfg`s.
-
-The other corner-case we need to worry about is empty allocations. There will
-be two kinds of empty allocations we need to worry about: `cap = 0` for all T,
-and `cap > 0` for zero-sized types.
-
-These cases are tricky because they come
-down to what LLVM means by "allocated". LLVM's notion of an
-allocation is significantly more abstract than how we usually use it. Because
-LLVM needs to work with different languages' semantics and custom allocators,
-it can't really intimately understand allocation. Instead, the main idea behind
-allocation is "doesn't overlap with other stuff". That is, heap allocations,
-stack allocations, and globals don't randomly overlap. Yep, it's about alias
-analysis. As such, Rust can technically play a bit fast and loose with the notion of
-an allocation as long as it's *consistent*.
-
-Getting back to the empty allocation case, there are a couple of places where
-we want to offset by 0 as a consequence of generic code. The question is then:
-is it consistent to do so? For zero-sized types, we have concluded that it is
-indeed consistent to do a GEP inbounds offset by an arbitrary number of
-elements. This is a runtime no-op because every element takes up no space,
-and it's fine to pretend that there's infinite zero-sized types allocated
-at `0x01`. No allocator will ever allocate that address, because they won't
-allocate `0x00` and they generally allocate to some minimal alignment higher
-than a byte. Also generally the whole first page of memory is
-protected from being allocated anyway (a whole 4k, on many platforms).
-
-However what about for positive-sized types? That one's a bit trickier. In
-principle, you can argue that offsetting by 0 gives LLVM no information: either
-there's an element before the address or after it, but it can't know which.
-However we've chosen to conservatively assume that it may do bad things. As
-such we will guard against this case explicitly.
-
-*Phew*
-
-Ok with all the nonsense out of the way, let's actually allocate some memory:
-
-```rust,ignore
-fn grow(&mut self) {
-    // this is all pretty delicate, so let's say it's all unsafe
-    unsafe {
-        // current API requires us to specify size and alignment manually.
-        let align = mem::align_of::<T>();
-        let elem_size = mem::size_of::<T>();
-
-        let (new_cap, ptr) = if self.cap == 0 {
-            let ptr = heap::allocate(elem_size, align);
-            (1, ptr)
-        } else {
-            // as an invariant, we can assume that `self.cap < isize::MAX`,
-            // so this doesn't need to be checked.
-            let new_cap = self.cap * 2;
-            // Similarly this can't overflow due to previously allocating this
-            let old_num_bytes = self.cap * elem_size;
-
-            // check that the new allocation doesn't exceed `isize::MAX` at all
-            // regardless of the actual size of the capacity. This combines the
-            // `new_cap <= isize::MAX` and `new_num_bytes <= usize::MAX` checks
-            // we need to make. We lose the ability to allocate e.g. 2/3rds of
-            // the address space with a single Vec of i16's on 32-bit though.
-            // Alas, poor Yorick -- I knew him, Horatio.
-            assert!(old_num_bytes <= (::std::isize::MAX as usize) / 2,
-                    "capacity overflow");
-
-            let new_num_bytes = old_num_bytes * 2;
-            let ptr = heap::reallocate(*self.ptr as *mut _,
-                                        old_num_bytes,
-                                        new_num_bytes,
-                                        align);
-            (new_cap, ptr)
-        };
-
-        // If allocate or reallocate fail, we'll get `null` back
-        if ptr.is_null() { oom(); }
-
-        self.ptr = Unique::new(ptr as *mut _);
-        self.cap = new_cap;
-    }
-}
-```
-
-Nothing particularly tricky here. Just computing sizes and alignments and doing
-some careful multiplication checks.
-
diff --git a/src/doc/nomicon/src/vec-dealloc.md b/src/doc/nomicon/src/vec-dealloc.md
deleted file mode 100644 (file)
index 83ab5b2..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-# Deallocating
-
-Next we should implement Drop so that we don't massively leak tons of resources.
-The easiest way is to just call `pop` until it yields None, and then deallocate
-our buffer. Note that calling `pop` is unneeded if `T: !Drop`. In theory we can
-ask Rust if `T` `needs_drop` and omit the calls to `pop`. However in practice
-LLVM is *really* good at removing simple side-effect free code like this, so I
-wouldn't bother unless you notice it's not being stripped (in this case it is).
-
-We must not call `heap::deallocate` when `self.cap == 0`, as in this case we
-haven't actually allocated any memory.
-
-
-```rust,ignore
-impl<T> Drop for Vec<T> {
-    fn drop(&mut self) {
-        if self.cap != 0 {
-            while let Some(_) = self.pop() { }
-
-            let align = mem::align_of::<T>();
-            let elem_size = mem::size_of::<T>();
-            let num_bytes = elem_size * self.cap;
-            unsafe {
-                heap::deallocate(*self.ptr as *mut _, num_bytes, align);
-            }
-        }
-    }
-}
-```
diff --git a/src/doc/nomicon/src/vec-deref.md b/src/doc/nomicon/src/vec-deref.md
deleted file mode 100644 (file)
index e21542c..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-# Deref
-
-Alright! We've got a decent minimal stack implemented. We can push, we can
-pop, and we can clean up after ourselves. However there's a whole mess of
-functionality we'd reasonably want. In particular, we have a proper array, but
-none of the slice functionality. That's actually pretty easy to solve: we can
-implement `Deref<Target=[T]>`. This will magically make our Vec coerce to, and
-behave like, a slice in all sorts of conditions.
-
-All we need is `slice::from_raw_parts`. It will correctly handle empty slices
-for us. Later once we set up zero-sized type support it will also Just Work
-for those too.
-
-```rust,ignore
-use std::ops::Deref;
-
-impl<T> Deref for Vec<T> {
-    type Target = [T];
-    fn deref(&self) -> &[T] {
-        unsafe {
-            ::std::slice::from_raw_parts(*self.ptr, self.len)
-        }
-    }
-}
-```
-
-And let's do DerefMut too:
-
-```rust,ignore
-use std::ops::DerefMut;
-
-impl<T> DerefMut for Vec<T> {
-    fn deref_mut(&mut self) -> &mut [T] {
-        unsafe {
-            ::std::slice::from_raw_parts_mut(*self.ptr, self.len)
-        }
-    }
-}
-```
-
-Now we have `len`, `first`, `last`, indexing, slicing, sorting, `iter`,
-`iter_mut`, and all other sorts of bells and whistles provided by slice. Sweet!
diff --git a/src/doc/nomicon/src/vec-drain.md b/src/doc/nomicon/src/vec-drain.md
deleted file mode 100644 (file)
index 5bd2bf0..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-# Drain
-
-Let's move on to Drain. Drain is largely the same as IntoIter, except that
-instead of consuming the Vec, it borrows the Vec and leaves its allocation
-untouched. For now we'll only implement the "basic" full-range version.
-
-```rust,ignore
-use std::marker::PhantomData;
-
-struct Drain<'a, T: 'a> {
-    // Need to bound the lifetime here, so we do it with `&'a mut Vec<T>`
-    // because that's semantically what we contain. We're "just" calling
-    // `pop()` and `remove(0)`.
-    vec: PhantomData<&'a mut Vec<T>>
-    start: *const T,
-    end: *const T,
-}
-
-impl<'a, T> Iterator for Drain<'a, T> {
-    type Item = T;
-    fn next(&mut self) -> Option<T> {
-        if self.start == self.end {
-            None
-```
-
--- wait, this is seeming familiar. Let's do some more compression. Both
-IntoIter and Drain have the exact same structure, let's just factor it out.
-
-```rust
-struct RawValIter<T> {
-    start: *const T,
-    end: *const T,
-}
-
-impl<T> RawValIter<T> {
-    // unsafe to construct because it has no associated lifetimes.
-    // This is necessary to store a RawValIter in the same struct as
-    // its actual allocation. OK since it's a private implementation
-    // detail.
-    unsafe fn new(slice: &[T]) -> Self {
-        RawValIter {
-            start: slice.as_ptr(),
-            end: if slice.len() == 0 {
-                // if `len = 0`, then this is not actually allocated memory.
-                // Need to avoid offsetting because that will give wrong
-                // information to LLVM via GEP.
-                slice.as_ptr()
-            } else {
-                slice.as_ptr().offset(slice.len() as isize)
-            }
-        }
-    }
-}
-
-// Iterator and DoubleEndedIterator impls identical to IntoIter.
-```
-
-And IntoIter becomes the following:
-
-```rust,ignore
-pub struct IntoIter<T> {
-    _buf: RawVec<T>, // we don't actually care about this. Just need it to live.
-    iter: RawValIter<T>,
-}
-
-impl<T> Iterator for IntoIter<T> {
-    type Item = T;
-    fn next(&mut self) -> Option<T> { self.iter.next() }
-    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
-}
-
-impl<T> DoubleEndedIterator for IntoIter<T> {
-    fn next_back(&mut self) -> Option<T> { self.iter.next_back() }
-}
-
-impl<T> Drop for IntoIter<T> {
-    fn drop(&mut self) {
-        for _ in &mut self.iter {}
-    }
-}
-
-impl<T> Vec<T> {
-    pub fn into_iter(self) -> IntoIter<T> {
-        unsafe {
-            let iter = RawValIter::new(&self);
-
-            let buf = ptr::read(&self.buf);
-            mem::forget(self);
-
-            IntoIter {
-                iter: iter,
-                _buf: buf,
-            }
-        }
-    }
-}
-```
-
-Note that I've left a few quirks in this design to make upgrading Drain to work
-with arbitrary subranges a bit easier. In particular we *could* have RawValIter
-drain itself on drop, but that won't work right for a more complex Drain.
-We also take a slice to simplify Drain initialization.
-
-Alright, now Drain is really easy:
-
-```rust,ignore
-use std::marker::PhantomData;
-
-pub struct Drain<'a, T: 'a> {
-    vec: PhantomData<&'a mut Vec<T>>,
-    iter: RawValIter<T>,
-}
-
-impl<'a, T> Iterator for Drain<'a, T> {
-    type Item = T;
-    fn next(&mut self) -> Option<T> { self.iter.next() }
-    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
-}
-
-impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
-    fn next_back(&mut self) -> Option<T> { self.iter.next_back() }
-}
-
-impl<'a, T> Drop for Drain<'a, T> {
-    fn drop(&mut self) {
-        for _ in &mut self.iter {}
-    }
-}
-
-impl<T> Vec<T> {
-    pub fn drain(&mut self) -> Drain<T> {
-        unsafe {
-            let iter = RawValIter::new(&self);
-
-            // this is a mem::forget safety thing. If Drain is forgotten, we just
-            // leak the whole Vec's contents. Also we need to do this *eventually*
-            // anyway, so why not do it now?
-            self.len = 0;
-
-            Drain {
-                iter: iter,
-                vec: PhantomData,
-            }
-        }
-    }
-}
-```
-
-For more details on the `mem::forget` problem, see the
-[section on leaks][leaks].
-
-[leaks]: leaking.html
diff --git a/src/doc/nomicon/src/vec-final.md b/src/doc/nomicon/src/vec-final.md
deleted file mode 100644 (file)
index 39746ca..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-# The Final Code
-
-```rust
-#![feature(unique)]
-#![feature(alloc, heap_api)]
-
-extern crate alloc;
-
-use std::ptr::{Unique, self};
-use std::mem;
-use std::ops::{Deref, DerefMut};
-use std::marker::PhantomData;
-
-use alloc::heap;
-
-struct RawVec<T> {
-    ptr: Unique<T>,
-    cap: usize,
-}
-
-impl<T> RawVec<T> {
-    fn new() -> Self {
-        unsafe {
-            // !0 is usize::MAX. This branch should be stripped at compile time.
-            let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
-
-            // heap::EMPTY doubles as "unallocated" and "zero-sized allocation"
-            RawVec { ptr: Unique::new(heap::EMPTY as *mut T), cap: cap }
-        }
-    }
-
-    fn grow(&mut self) {
-        unsafe {
-            let elem_size = mem::size_of::<T>();
-
-            // since we set the capacity to usize::MAX when elem_size is
-            // 0, getting to here necessarily means the Vec is overfull.
-            assert!(elem_size != 0, "capacity overflow");
-
-            let align = mem::align_of::<T>();
-
-            let (new_cap, ptr) = if self.cap == 0 {
-                let ptr = heap::allocate(elem_size, align);
-                (1, ptr)
-            } else {
-                let new_cap = 2 * self.cap;
-                let ptr = heap::reallocate(*self.ptr as *mut _,
-                                            self.cap * elem_size,
-                                            new_cap * elem_size,
-                                            align);
-                (new_cap, ptr)
-            };
-
-            // If allocate or reallocate fail, we'll get `null` back
-            if ptr.is_null() { oom() }
-
-            self.ptr = Unique::new(ptr as *mut _);
-            self.cap = new_cap;
-        }
-    }
-}
-
-impl<T> Drop for RawVec<T> {
-    fn drop(&mut self) {
-        let elem_size = mem::size_of::<T>();
-        if self.cap != 0 && elem_size != 0 {
-            let align = mem::align_of::<T>();
-
-            let num_bytes = elem_size * self.cap;
-            unsafe {
-                heap::deallocate(*self.ptr as *mut _, num_bytes, align);
-            }
-        }
-    }
-}
-
-
-
-
-
-pub struct Vec<T> {
-    buf: RawVec<T>,
-    len: usize,
-}
-
-impl<T> Vec<T> {
-    fn ptr(&self) -> *mut T { *self.buf.ptr }
-
-    fn cap(&self) -> usize { self.buf.cap }
-
-    pub fn new() -> Self {
-        Vec { buf: RawVec::new(), len: 0 }
-    }
-    pub fn push(&mut self, elem: T) {
-        if self.len == self.cap() { self.buf.grow(); }
-
-        unsafe {
-            ptr::write(self.ptr().offset(self.len as isize), elem);
-        }
-
-        // Can't fail, we'll OOM first.
-        self.len += 1;
-    }
-
-    pub fn pop(&mut self) -> Option<T> {
-        if self.len == 0 {
-            None
-        } else {
-            self.len -= 1;
-            unsafe {
-                Some(ptr::read(self.ptr().offset(self.len as isize)))
-            }
-        }
-    }
-
-    pub fn insert(&mut self, index: usize, elem: T) {
-        assert!(index <= self.len, "index out of bounds");
-        if self.cap() == self.len { self.buf.grow(); }
-
-        unsafe {
-            if index < self.len {
-                ptr::copy(self.ptr().offset(index as isize),
-                          self.ptr().offset(index as isize + 1),
-                          self.len - index);
-            }
-            ptr::write(self.ptr().offset(index as isize), elem);
-            self.len += 1;
-        }
-    }
-
-    pub fn remove(&mut self, index: usize) -> T {
-        assert!(index < self.len, "index out of bounds");
-        unsafe {
-            self.len -= 1;
-            let result = ptr::read(self.ptr().offset(index as isize));
-            ptr::copy(self.ptr().offset(index as isize + 1),
-                      self.ptr().offset(index as isize),
-                      self.len - index);
-            result
-        }
-    }
-
-    pub fn into_iter(self) -> IntoIter<T> {
-        unsafe {
-            let iter = RawValIter::new(&self);
-            let buf = ptr::read(&self.buf);
-            mem::forget(self);
-
-            IntoIter {
-                iter: iter,
-                _buf: buf,
-            }
-        }
-    }
-
-    pub fn drain(&mut self) -> Drain<T> {
-        unsafe {
-            let iter = RawValIter::new(&self);
-
-            // this is a mem::forget safety thing. If Drain is forgotten, we just
-            // leak the whole Vec's contents. Also we need to do this *eventually*
-            // anyway, so why not do it now?
-            self.len = 0;
-
-            Drain {
-                iter: iter,
-                vec: PhantomData,
-            }
-        }
-    }
-}
-
-impl<T> Drop for Vec<T> {
-    fn drop(&mut self) {
-        while let Some(_) = self.pop() {}
-        // allocation is handled by RawVec
-    }
-}
-
-impl<T> Deref for Vec<T> {
-    type Target = [T];
-    fn deref(&self) -> &[T] {
-        unsafe {
-            ::std::slice::from_raw_parts(self.ptr(), self.len)
-        }
-    }
-}
-
-impl<T> DerefMut for Vec<T> {
-    fn deref_mut(&mut self) -> &mut [T] {
-        unsafe {
-            ::std::slice::from_raw_parts_mut(self.ptr(), self.len)
-        }
-    }
-}
-
-
-
-
-
-struct RawValIter<T> {
-    start: *const T,
-    end: *const T,
-}
-
-impl<T> RawValIter<T> {
-    unsafe fn new(slice: &[T]) -> Self {
-        RawValIter {
-            start: slice.as_ptr(),
-            end: if mem::size_of::<T>() == 0 {
-                ((slice.as_ptr() as usize) + slice.len()) as *const _
-            } else if slice.len() == 0 {
-                slice.as_ptr()
-            } else {
-                slice.as_ptr().offset(slice.len() as isize)
-            }
-        }
-    }
-}
-
-impl<T> Iterator for RawValIter<T> {
-    type Item = T;
-    fn next(&mut self) -> Option<T> {
-        if self.start == self.end {
-            None
-        } else {
-            unsafe {
-                let result = ptr::read(self.start);
-                self.start = if mem::size_of::<T>() == 0 {
-                    (self.start as usize + 1) as *const _
-                } else {
-                    self.start.offset(1)
-                };
-                Some(result)
-            }
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let elem_size = mem::size_of::<T>();
-        let len = (self.end as usize - self.start as usize)
-                  / if elem_size == 0 { 1 } else { elem_size };
-        (len, Some(len))
-    }
-}
-
-impl<T> DoubleEndedIterator for RawValIter<T> {
-    fn next_back(&mut self) -> Option<T> {
-        if self.start == self.end {
-            None
-        } else {
-            unsafe {
-                self.end = if mem::size_of::<T>() == 0 {
-                    (self.end as usize - 1) as *const _
-                } else {
-                    self.end.offset(-1)
-                };
-                Some(ptr::read(self.end))
-            }
-        }
-    }
-}
-
-
-
-
-pub struct IntoIter<T> {
-    _buf: RawVec<T>, // we don't actually care about this. Just need it to live.
-    iter: RawValIter<T>,
-}
-
-impl<T> Iterator for IntoIter<T> {
-    type Item = T;
-    fn next(&mut self) -> Option<T> { self.iter.next() }
-    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
-}
-
-impl<T> DoubleEndedIterator for IntoIter<T> {
-    fn next_back(&mut self) -> Option<T> { self.iter.next_back() }
-}
-
-impl<T> Drop for IntoIter<T> {
-    fn drop(&mut self) {
-        for _ in &mut *self {}
-    }
-}
-
-
-
-
-pub struct Drain<'a, T: 'a> {
-    vec: PhantomData<&'a mut Vec<T>>,
-    iter: RawValIter<T>,
-}
-
-impl<'a, T> Iterator for Drain<'a, T> {
-    type Item = T;
-    fn next(&mut self) -> Option<T> { self.iter.next_back() }
-    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
-}
-
-impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
-    fn next_back(&mut self) -> Option<T> { self.iter.next_back() }
-}
-
-impl<'a, T> Drop for Drain<'a, T> {
-    fn drop(&mut self) {
-        // pre-drain the iter
-        for _ in &mut self.iter {}
-    }
-}
-
-/// Abort the process, we're out of memory!
-///
-/// In practice this is probably dead code on most OSes
-fn oom() {
-    ::std::process::exit(-9999);
-}
-
-# fn main() {}
-```
diff --git a/src/doc/nomicon/src/vec-insert-remove.md b/src/doc/nomicon/src/vec-insert-remove.md
deleted file mode 100644 (file)
index 2c14bc4..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-# Insert and Remove
-
-Something *not* provided by slice is `insert` and `remove`, so let's do those
-next.
-
-Insert needs to shift all the elements at the target index to the right by one.
-To do this we need to use `ptr::copy`, which is our version of C's `memmove`.
-This copies some chunk of memory from one location to another, correctly
-handling the case where the source and destination overlap (which will
-definitely happen here).
-
-If we insert at index `i`, we want to shift the `[i .. len]` to `[i+1 .. len+1]`
-using the old len.
-
-```rust,ignore
-pub fn insert(&mut self, index: usize, elem: T) {
-    // Note: `<=` because it's valid to insert after everything
-    // which would be equivalent to push.
-    assert!(index <= self.len, "index out of bounds");
-    if self.cap == self.len { self.grow(); }
-
-    unsafe {
-        if index < self.len {
-            // ptr::copy(src, dest, len): "copy from source to dest len elems"
-            ptr::copy(self.ptr.offset(index as isize),
-                      self.ptr.offset(index as isize + 1),
-                      self.len - index);
-        }
-        ptr::write(self.ptr.offset(index as isize), elem);
-        self.len += 1;
-    }
-}
-```
-
-Remove behaves in the opposite manner. We need to shift all the elements from
-`[i+1 .. len + 1]` to `[i .. len]` using the *new* len.
-
-```rust,ignore
-pub fn remove(&mut self, index: usize) -> T {
-    // Note: `<` because it's *not* valid to remove after everything
-    assert!(index < self.len, "index out of bounds");
-    unsafe {
-        self.len -= 1;
-        let result = ptr::read(self.ptr.offset(index as isize));
-        ptr::copy(self.ptr.offset(index as isize + 1),
-                  self.ptr.offset(index as isize),
-                  self.len - index);
-        result
-    }
-}
-```
diff --git a/src/doc/nomicon/src/vec-into-iter.md b/src/doc/nomicon/src/vec-into-iter.md
deleted file mode 100644 (file)
index f2f5995..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-# IntoIter
-
-Let's move on to writing iterators. `iter` and `iter_mut` have already been
-written for us thanks to The Magic of Deref. However there's two interesting
-iterators that Vec provides that slices can't: `into_iter` and `drain`.
-
-IntoIter consumes the Vec by-value, and can consequently yield its elements
-by-value. In order to enable this, IntoIter needs to take control of Vec's
-allocation.
-
-IntoIter needs to be DoubleEnded as well, to enable reading from both ends.
-Reading from the back could just be implemented as calling `pop`, but reading
-from the front is harder. We could call `remove(0)` but that would be insanely
-expensive. Instead we're going to just use ptr::read to copy values out of
-either end of the Vec without mutating the buffer at all.
-
-To do this we're going to use a very common C idiom for array iteration. We'll
-make two pointers; one that points to the start of the array, and one that
-points to one-element past the end. When we want an element from one end, we'll
-read out the value pointed to at that end and move the pointer over by one. When
-the two pointers are equal, we know we're done.
-
-Note that the order of read and offset are reversed for `next` and `next_back`
-For `next_back` the pointer is always after the element it wants to read next,
-while for `next` the pointer is always at the element it wants to read next.
-To see why this is, consider the case where every element but one has been
-yielded.
-
-The array looks like this:
-
-```text
-          S  E
-[X, X, X, O, X, X, X]
-```
-
-If E pointed directly at the element it wanted to yield next, it would be
-indistinguishable from the case where there are no more elements to yield.
-
-Although we don't actually care about it during iteration, we also need to hold
-onto the Vec's allocation information in order to free it once IntoIter is
-dropped.
-
-So we're going to use the following struct:
-
-```rust,ignore
-struct IntoIter<T> {
-    buf: Unique<T>,
-    cap: usize,
-    start: *const T,
-    end: *const T,
-}
-```
-
-And this is what we end up with for initialization:
-
-```rust,ignore
-impl<T> Vec<T> {
-    fn into_iter(self) -> IntoIter<T> {
-        // Can't destructure Vec since it's Drop
-        let ptr = self.ptr;
-        let cap = self.cap;
-        let len = self.len;
-
-        // Make sure not to drop Vec since that will free the buffer
-        mem::forget(self);
-
-        unsafe {
-            IntoIter {
-                buf: ptr,
-                cap: cap,
-                start: *ptr,
-                end: if cap == 0 {
-                    // can't offset off this pointer, it's not allocated!
-                    *ptr
-                } else {
-                    ptr.offset(len as isize)
-                }
-            }
-        }
-    }
-}
-```
-
-Here's iterating forward:
-
-```rust,ignore
-impl<T> Iterator for IntoIter<T> {
-    type Item = T;
-    fn next(&mut self) -> Option<T> {
-        if self.start == self.end {
-            None
-        } else {
-            unsafe {
-                let result = ptr::read(self.start);
-                self.start = self.start.offset(1);
-                Some(result)
-            }
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let len = (self.end as usize - self.start as usize)
-                  / mem::size_of::<T>();
-        (len, Some(len))
-    }
-}
-```
-
-And here's iterating backwards.
-
-```rust,ignore
-impl<T> DoubleEndedIterator for IntoIter<T> {
-    fn next_back(&mut self) -> Option<T> {
-        if self.start == self.end {
-            None
-        } else {
-            unsafe {
-                self.end = self.end.offset(-1);
-                Some(ptr::read(self.end))
-            }
-        }
-    }
-}
-```
-
-Because IntoIter takes ownership of its allocation, it needs to implement Drop
-to free it. However it also wants to implement Drop to drop any elements it
-contains that weren't yielded.
-
-
-```rust,ignore
-impl<T> Drop for IntoIter<T> {
-    fn drop(&mut self) {
-        if self.cap != 0 {
-            // drop any remaining elements
-            for _ in &mut *self {}
-
-            let align = mem::align_of::<T>();
-            let elem_size = mem::size_of::<T>();
-            let num_bytes = elem_size * self.cap;
-            unsafe {
-                heap::deallocate(*self.buf as *mut _, num_bytes, align);
-            }
-        }
-    }
-}
-```
diff --git a/src/doc/nomicon/src/vec-layout.md b/src/doc/nomicon/src/vec-layout.md
deleted file mode 100644 (file)
index 1dc09ae..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-# Layout
-
-First off, we need to come up with the struct layout. A Vec has three parts:
-a pointer to the allocation, the size of the allocation, and the number of
-elements that have been initialized.
-
-Naively, this means we just want this design:
-
-```rust
-pub struct Vec<T> {
-    ptr: *mut T,
-    cap: usize,
-    len: usize,
-}
-# fn main() {}
-```
-
-And indeed this would compile. Unfortunately, it would be incorrect. First, the
-compiler will give us too strict variance. So a `&Vec<&'static str>`
-couldn't be used where an `&Vec<&'a str>` was expected. More importantly, it
-will give incorrect ownership information to the drop checker, as it will
-conservatively assume we don't own any values of type `T`. See [the chapter
-on ownership and lifetimes][ownership] for all the details on variance and
-drop check.
-
-As we saw in the ownership chapter, we should use `Unique<T>` in place of
-`*mut T` when we have a raw pointer to an allocation we own. Unique is unstable,
-so we'd like to not use it if possible, though.
-
-As a recap, Unique is a wrapper around a raw pointer that declares that:
-
-* We are variant over `T`
-* We may own a value of type `T` (for drop check)
-* We are Send/Sync if `T` is Send/Sync
-* We deref to `*mut T` (so it largely acts like a `*mut` in our code)
-* Our pointer is never null (so `Option<Vec<T>>` is null-pointer-optimized)
-
-We can implement all of the above requirements except for the last
-one in stable Rust:
-
-```rust
-use std::marker::PhantomData;
-use std::ops::Deref;
-use std::mem;
-
-struct Unique<T> {
-    ptr: *const T,              // *const for variance
-    _marker: PhantomData<T>,    // For the drop checker
-}
-
-// Deriving Send and Sync is safe because we are the Unique owners
-// of this data. It's like Unique<T> is "just" T.
-unsafe impl<T: Send> Send for Unique<T> {}
-unsafe impl<T: Sync> Sync for Unique<T> {}
-
-impl<T> Unique<T> {
-    pub fn new(ptr: *mut T) -> Self {
-        Unique { ptr: ptr, _marker: PhantomData }
-    }
-}
-
-impl<T> Deref for Unique<T> {
-    type Target = *mut T;
-    fn deref(&self) -> &*mut T {
-        // There's no way to cast the *const to a *mut
-        // while also taking a reference. So we just
-        // transmute it since it's all "just pointers".
-        unsafe { mem::transmute(&self.ptr) }
-    }
-}
-# fn main() {}
-```
-
-Unfortunately the mechanism for stating that your value is non-zero is
-unstable and unlikely to be stabilized soon. As such we're just going to
-take the hit and use std's Unique:
-
-
-```rust
-#![feature(unique)]
-
-use std::ptr::{Unique, self};
-
-pub struct Vec<T> {
-    ptr: Unique<T>,
-    cap: usize,
-    len: usize,
-}
-
-# fn main() {}
-```
-
-If you don't care about the null-pointer optimization, then you can use the
-stable code. However we will be designing the rest of the code around enabling
-the optimization. In particular, `Unique::new` is unsafe to call, because
-putting `null` inside of it is Undefined Behavior. Our stable Unique doesn't
-need `new` to be unsafe because it doesn't make any interesting guarantees about
-its contents.
-
-[ownership]: ownership.html
diff --git a/src/doc/nomicon/src/vec-push-pop.md b/src/doc/nomicon/src/vec-push-pop.md
deleted file mode 100644 (file)
index d31a74c..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-# Push and Pop
-
-Alright. We can initialize. We can allocate. Let's actually implement some
-functionality! Let's start with `push`. All it needs to do is check if we're
-full to grow, unconditionally write to the next index, and then increment our
-length.
-
-To do the write we have to be careful not to evaluate the memory we want to write
-to. At worst, it's truly uninitialized memory from the allocator. At best it's the
-bits of some old value we popped off. Either way, we can't just index to the memory
-and dereference it, because that will evaluate the memory as a valid instance of
-T. Worse, `foo[idx] = x` will try to call `drop` on the old value of `foo[idx]`!
-
-The correct way to do this is with `ptr::write`, which just blindly overwrites the
-target address with the bits of the value we provide. No evaluation involved.
-
-For `push`, if the old len (before push was called) is 0, then we want to write
-to the 0th index. So we should offset by the old len.
-
-```rust,ignore
-pub fn push(&mut self, elem: T) {
-    if self.len == self.cap { self.grow(); }
-
-    unsafe {
-        ptr::write(self.ptr.offset(self.len as isize), elem);
-    }
-
-    // Can't fail, we'll OOM first.
-    self.len += 1;
-}
-```
-
-Easy! How about `pop`? Although this time the index we want to access is
-initialized, Rust won't just let us dereference the location of memory to move
-the value out, because that would leave the memory uninitialized! For this we
-need `ptr::read`, which just copies out the bits from the target address and
-interprets it as a value of type T. This will leave the memory at this address
-logically uninitialized, even though there is in fact a perfectly good instance
-of T there.
-
-For `pop`, if the old len is 1, we want to read out of the 0th index. So we
-should offset by the new len.
-
-```rust,ignore
-pub fn pop(&mut self) -> Option<T> {
-    if self.len == 0 {
-        None
-    } else {
-        self.len -= 1;
-        unsafe {
-            Some(ptr::read(self.ptr.offset(self.len as isize)))
-        }
-    }
-}
-```
diff --git a/src/doc/nomicon/src/vec-raw.md b/src/doc/nomicon/src/vec-raw.md
deleted file mode 100644 (file)
index 20fa8ab..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-# RawVec
-
-We've actually reached an interesting situation here: we've duplicated the logic
-for specifying a buffer and freeing its memory in Vec and IntoIter. Now that
-we've implemented it and identified *actual* logic duplication, this is a good
-time to perform some logic compression.
-
-We're going to abstract out the `(ptr, cap)` pair and give them the logic for
-allocating, growing, and freeing:
-
-```rust,ignore
-struct RawVec<T> {
-    ptr: Unique<T>,
-    cap: usize,
-}
-
-impl<T> RawVec<T> {
-    fn new() -> Self {
-        assert!(mem::size_of::<T>() != 0, "TODO: implement ZST support");
-        unsafe {
-            RawVec { ptr: Unique::new(heap::EMPTY as *mut T), cap: 0 }
-        }
-    }
-
-    // unchanged from Vec
-    fn grow(&mut self) {
-        unsafe {
-            let align = mem::align_of::<T>();
-            let elem_size = mem::size_of::<T>();
-
-            let (new_cap, ptr) = if self.cap == 0 {
-                let ptr = heap::allocate(elem_size, align);
-                (1, ptr)
-            } else {
-                let new_cap = 2 * self.cap;
-                let ptr = heap::reallocate(*self.ptr as *mut _,
-                                            self.cap * elem_size,
-                                            new_cap * elem_size,
-                                            align);
-                (new_cap, ptr)
-            };
-
-            // If allocate or reallocate fail, we'll get `null` back
-            if ptr.is_null() { oom() }
-
-            self.ptr = Unique::new(ptr as *mut _);
-            self.cap = new_cap;
-        }
-    }
-}
-
-
-impl<T> Drop for RawVec<T> {
-    fn drop(&mut self) {
-        if self.cap != 0 {
-            let align = mem::align_of::<T>();
-            let elem_size = mem::size_of::<T>();
-            let num_bytes = elem_size * self.cap;
-            unsafe {
-                heap::deallocate(*self.ptr as *mut _, num_bytes, align);
-            }
-        }
-    }
-}
-```
-
-And change Vec as follows:
-
-```rust,ignore
-pub struct Vec<T> {
-    buf: RawVec<T>,
-    len: usize,
-}
-
-impl<T> Vec<T> {
-    fn ptr(&self) -> *mut T { *self.buf.ptr }
-
-    fn cap(&self) -> usize { self.buf.cap }
-
-    pub fn new() -> Self {
-        Vec { buf: RawVec::new(), len: 0 }
-    }
-
-    // push/pop/insert/remove largely unchanged:
-    // * `self.ptr -> self.ptr()`
-    // * `self.cap -> self.cap()`
-    // * `self.grow -> self.buf.grow()`
-}
-
-impl<T> Drop for Vec<T> {
-    fn drop(&mut self) {
-        while let Some(_) = self.pop() {}
-        // deallocation is handled by RawVec
-    }
-}
-```
-
-And finally we can really simplify IntoIter:
-
-```rust,ignore
-struct IntoIter<T> {
-    _buf: RawVec<T>, // we don't actually care about this. Just need it to live.
-    start: *const T,
-    end: *const T,
-}
-
-// next and next_back literally unchanged since they never referred to the buf
-
-impl<T> Drop for IntoIter<T> {
-    fn drop(&mut self) {
-        // only need to ensure all our elements are read;
-        // buffer will clean itself up afterwards.
-        for _ in &mut *self {}
-    }
-}
-
-impl<T> Vec<T> {
-    pub fn into_iter(self) -> IntoIter<T> {
-        unsafe {
-            // need to use ptr::read to unsafely move the buf out since it's
-            // not Copy, and Vec implements Drop (so we can't destructure it).
-            let buf = ptr::read(&self.buf);
-            let len = self.len;
-            mem::forget(self);
-
-            IntoIter {
-                start: *buf.ptr,
-                end: buf.ptr.offset(len as isize),
-                _buf: buf,
-            }
-        }
-    }
-}
-```
-
-Much better.
diff --git a/src/doc/nomicon/src/vec-zsts.md b/src/doc/nomicon/src/vec-zsts.md
deleted file mode 100644 (file)
index 5ae9bdd..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-# Handling Zero-Sized Types
-
-It's time. We're going to fight the specter that is zero-sized types. Safe Rust
-*never* needs to care about this, but Vec is very intensive on raw pointers and
-raw allocations, which are exactly the two things that care about
-zero-sized types. We need to be careful of two things:
-
-* The raw allocator API has undefined behavior if you pass in 0 for an
-  allocation size.
-* raw pointer offsets are no-ops for zero-sized types, which will break our
-  C-style pointer iterator.
-
-Thankfully we abstracted out pointer-iterators and allocating handling into
-RawValIter and RawVec respectively. How mysteriously convenient.
-
-
-
-
-## Allocating Zero-Sized Types
-
-So if the allocator API doesn't support zero-sized allocations, what on earth
-do we store as our allocation? Why, `heap::EMPTY` of course! Almost every operation
-with a ZST is a no-op since ZSTs have exactly one value, and therefore no state needs
-to be considered to store or load them. This actually extends to `ptr::read` and
-`ptr::write`: they won't actually look at the pointer at all. As such we never need
-to change the pointer.
-
-Note however that our previous reliance on running out of memory before overflow is
-no longer valid with zero-sized types. We must explicitly guard against capacity
-overflow for zero-sized types.
-
-Due to our current architecture, all this means is writing 3 guards, one in each
-method of RawVec.
-
-```rust,ignore
-impl<T> RawVec<T> {
-    fn new() -> Self {
-        unsafe {
-            // !0 is usize::MAX. This branch should be stripped at compile time.
-            let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
-
-            // heap::EMPTY doubles as "unallocated" and "zero-sized allocation"
-            RawVec { ptr: Unique::new(heap::EMPTY as *mut T), cap: cap }
-        }
-    }
-
-    fn grow(&mut self) {
-        unsafe {
-            let elem_size = mem::size_of::<T>();
-
-            // since we set the capacity to usize::MAX when elem_size is
-            // 0, getting to here necessarily means the Vec is overfull.
-            assert!(elem_size != 0, "capacity overflow");
-
-            let align = mem::align_of::<T>();
-
-            let (new_cap, ptr) = if self.cap == 0 {
-                let ptr = heap::allocate(elem_size, align);
-                (1, ptr)
-            } else {
-                let new_cap = 2 * self.cap;
-                let ptr = heap::reallocate(*self.ptr as *mut _,
-                                            self.cap * elem_size,
-                                            new_cap * elem_size,
-                                            align);
-                (new_cap, ptr)
-            };
-
-            // If allocate or reallocate fail, we'll get `null` back
-            if ptr.is_null() { oom() }
-
-            self.ptr = Unique::new(ptr as *mut _);
-            self.cap = new_cap;
-        }
-    }
-}
-
-impl<T> Drop for RawVec<T> {
-    fn drop(&mut self) {
-        let elem_size = mem::size_of::<T>();
-
-        // don't free zero-sized allocations, as they were never allocated.
-        if self.cap != 0 && elem_size != 0 {
-            let align = mem::align_of::<T>();
-
-            let num_bytes = elem_size * self.cap;
-            unsafe {
-                heap::deallocate(*self.ptr as *mut _, num_bytes, align);
-            }
-        }
-    }
-}
-```
-
-That's it. We support pushing and popping zero-sized types now. Our iterators
-(that aren't provided by slice Deref) are still busted, though.
-
-
-
-
-## Iterating Zero-Sized Types
-
-Zero-sized offsets are no-ops. This means that our current design will always
-initialize `start` and `end` as the same value, and our iterators will yield
-nothing. The current solution to this is to cast the pointers to integers,
-increment, and then cast them back:
-
-```rust,ignore
-impl<T> RawValIter<T> {
-    unsafe fn new(slice: &[T]) -> Self {
-        RawValIter {
-            start: slice.as_ptr(),
-            end: if mem::size_of::<T>() == 0 {
-                ((slice.as_ptr() as usize) + slice.len()) as *const _
-            } else if slice.len() == 0 {
-                slice.as_ptr()
-            } else {
-                slice.as_ptr().offset(slice.len() as isize)
-            }
-        }
-    }
-}
-```
-
-Now we have a different bug. Instead of our iterators not running at all, our
-iterators now run *forever*. We need to do the same trick in our iterator impls.
-Also, our size_hint computation code will divide by 0 for ZSTs. Since we'll
-basically be treating the two pointers as if they point to bytes, we'll just
-map size 0 to divide by 1.
-
-```rust,ignore
-impl<T> Iterator for RawValIter<T> {
-    type Item = T;
-    fn next(&mut self) -> Option<T> {
-        if self.start == self.end {
-            None
-        } else {
-            unsafe {
-                let result = ptr::read(self.start);
-                self.start = if mem::size_of::<T>() == 0 {
-                    (self.start as usize + 1) as *const _
-                } else {
-                    self.start.offset(1)
-                };
-                Some(result)
-            }
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let elem_size = mem::size_of::<T>();
-        let len = (self.end as usize - self.start as usize)
-                  / if elem_size == 0 { 1 } else { elem_size };
-        (len, Some(len))
-    }
-}
-
-impl<T> DoubleEndedIterator for RawValIter<T> {
-    fn next_back(&mut self) -> Option<T> {
-        if self.start == self.end {
-            None
-        } else {
-            unsafe {
-                self.end = if mem::size_of::<T>() == 0 {
-                    (self.end as usize - 1) as *const _
-                } else {
-                    self.end.offset(-1)
-                };
-                Some(ptr::read(self.end))
-            }
-        }
-    }
-}
-```
-
-And that's it. Iteration works!
diff --git a/src/doc/nomicon/src/vec.md b/src/doc/nomicon/src/vec.md
deleted file mode 100644 (file)
index ad98e45..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-# Example: Implementing Vec
-
-To bring everything together, we're going to write `std::Vec` from scratch.
-Because all the best tools for writing unsafe code are unstable, this
-project will only work on nightly (as of Rust 1.9.0). With the exception of the
-allocator API, much of the unstable code we'll use is expected to be stabilized
-in a similar form as it is today.
-
-However we will generally try to avoid unstable code where possible. In
-particular we won't use any intrinsics that could make a code a little
-bit nicer or efficient because intrinsics are permanently unstable. Although
-many intrinsics *do* become stabilized elsewhere (`std::ptr` and `str::mem`
-consist of many intrinsics).
-
-Ultimately this means our implementation may not take advantage of all
-possible optimizations, though it will be by no means *naive*. We will
-definitely get into the weeds over nitty-gritty details, even
-when the problem doesn't *really* merit it.
-
-You wanted advanced. We're gonna go advanced.
diff --git a/src/doc/nomicon/src/working-with-unsafe.md b/src/doc/nomicon/src/working-with-unsafe.md
deleted file mode 100644 (file)
index 5724f3d..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-# Working with Unsafe
-
-Rust generally only gives us the tools to talk about Unsafe Rust in a scoped and
-binary manner. Unfortunately, reality is significantly more complicated than
-that. For instance, consider the following toy function:
-
-```rust
-fn index(idx: usize, arr: &[u8]) -> Option<u8> {
-    if idx < arr.len() {
-        unsafe {
-            Some(*arr.get_unchecked(idx))
-        }
-    } else {
-        None
-    }
-}
-```
-
-Clearly, this function is safe. We check that the index is in bounds, and if it
-is, index into the array in an unchecked manner. But even in such a trivial
-function, the scope of the unsafe block is questionable. Consider changing the
-`<` to a `<=`:
-
-```rust
-fn index(idx: usize, arr: &[u8]) -> Option<u8> {
-    if idx <= arr.len() {
-        unsafe {
-            Some(*arr.get_unchecked(idx))
-        }
-    } else {
-        None
-    }
-}
-```
-
-This program is now unsound, and yet *we only modified safe code*. This is the
-fundamental problem of safety: it's non-local. The soundness of our unsafe
-operations necessarily depends on the state established by otherwise
-"safe" operations.
-
-Safety is modular in the sense that opting into unsafety doesn't require you
-to consider arbitrary other kinds of badness. For instance, doing an unchecked
-index into a slice doesn't mean you suddenly need to worry about the slice being
-null or containing uninitialized memory. Nothing fundamentally changes. However
-safety *isn't* modular in the sense that programs are inherently stateful and
-your unsafe operations may depend on arbitrary other state.
-
-Trickier than that is when we get into actual statefulness. Consider a simple
-implementation of `Vec`:
-
-```rust
-use std::ptr;
-
-// Note this definition is insufficient. See the section on implementing Vec.
-pub struct Vec<T> {
-    ptr: *mut T,
-    len: usize,
-    cap: usize,
-}
-
-// Note this implementation does not correctly handle zero-sized types.
-// We currently live in a nice imaginary world of only positive fixed-size
-// types.
-impl<T> Vec<T> {
-    pub fn push(&mut self, elem: T) {
-        if self.len == self.cap {
-            // not important for this example
-            self.reallocate();
-        }
-        unsafe {
-            ptr::write(self.ptr.offset(self.len as isize), elem);
-            self.len += 1;
-        }
-    }
-
-    # fn reallocate(&mut self) { }
-}
-
-# fn main() {}
-```
-
-This code is simple enough to reasonably audit and verify. Now consider
-adding the following method:
-
-```rust,ignore
-fn make_room(&mut self) {
-    // grow the capacity
-    self.cap += 1;
-}
-```
-
-This code is 100% Safe Rust but it is also completely unsound. Changing the
-capacity violates the invariants of Vec (that `cap` reflects the allocated space
-in the Vec). This is not something the rest of Vec can guard against. It *has*
-to trust the capacity field because there's no way to verify it.
-
-`unsafe` does more than pollute a whole function: it pollutes a whole *module*.
-Generally, the only bullet-proof way to limit the scope of unsafe code is at the
-module boundary with privacy.
-
-However this works *perfectly*. The existence of `make_room` is *not* a
-problem for the soundness of Vec because we didn't mark it as public. Only the
-module that defines this function can call it. Also, `make_room` directly
-accesses the private fields of Vec, so it can only be written in the same module
-as Vec.
-
-It is therefore possible for us to write a completely safe abstraction that
-relies on complex invariants. This is *critical* to the relationship between
-Safe Rust and Unsafe Rust. We have already seen that Unsafe code must trust
-*some* Safe code, but can't trust *generic* Safe code. It can't trust an
-arbitrary implementor of a trait or any function that was passed to it to be
-well-behaved in a way that safe code doesn't care about.
-
-However if unsafe code couldn't prevent client safe code from messing with its
-state in arbitrary ways, safety would be a lost cause. Thankfully, it *can*
-prevent arbitrary code from messing with critical state due to privacy.
-
-Safety lives!
-
index d0fce7061286880bd0b0c7006ec1b350d73d6510..43b0d72186a29233d45484a6ac033a4971a70559 100644 (file)
@@ -225,6 +225,8 @@ fn drop(&mut self) {
 impl<T> Box<T> {
     /// Allocates memory on the heap and then places `x` into it.
     ///
+    /// This doesn't actually allocate if `T` is zero-sized.
+    ///
     /// # Examples
     ///
     /// ```
index 87315fff0a07d915f8ac09aeb5d603e946730409..e27c45773441a7a7e114eba1460fdf50fefafd0f 100644 (file)
@@ -1646,6 +1646,10 @@ pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) ->
     /// 'Lowercase' is defined according to the terms of the Unicode Derived Core Property
     /// `Lowercase`.
     ///
+    /// Since some characters can expand into multiple characters when changing
+    /// the case, this function returns a [`String`] instead of modifying the
+    /// parameter in-place.
+    ///
     /// [`String`]: string/struct.String.html
     ///
     /// # Examples
@@ -1718,6 +1722,10 @@ fn case_ignoreable_then_cased<I: Iterator<Item = char>>(iter: I) -> bool {
     /// 'Uppercase' is defined according to the terms of the Unicode Derived Core Property
     /// `Uppercase`.
     ///
+    /// Since some characters can expand into multiple characters when changing
+    /// the case, this function returns a [`String`] instead of modifying the
+    /// parameter in-place.
+    ///
     /// [`String`]: string/struct.String.html
     ///
     /// # Examples
index 4979107ccadc7f9004a3cedd8092e72763fcba1e..43323676ab459b4f39a1233218f6dcc3c63f58dd 100644 (file)
@@ -433,6 +433,10 @@ pub fn from_str(_: &str) -> String {
     ///
     /// [`str::from_utf8()`]: ../../std/str/fn.from_utf8.html
     ///
+    /// The inverse of this method is [`as_bytes`].
+    ///
+    /// [`as_bytes`]: #method.as_bytes
+    ///
     /// # Errors
     ///
     /// Returns `Err` if the slice is not UTF-8 with a description as to why the
@@ -979,6 +983,10 @@ pub fn push(&mut self, ch: char) {
 
     /// Returns a byte slice of this `String`'s contents.
     ///
+    /// The inverse of this method is [`from_utf8`].
+    ///
+    /// [`from_utf8`]: #method.from_utf8
+    ///
     /// # Examples
     ///
     /// Basic usage:
index 3134e3c2ce12f802f56016d207317265208d0fb7..d38c9f6e1cf805f3a82b250e6afeb23e5e4f1f27 100644 (file)
@@ -1335,6 +1335,27 @@ impl<T: PartialEq> Vec<T> {
     pub fn dedup(&mut self) {
         self.dedup_by(|a, b| a == b)
     }
+
+    /// Removes the first instance of `item` from the vector if the item exists.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    ///# #![feature(vec_remove_item)]
+    /// let mut vec = vec![1, 2, 3, 1];
+    ///
+    /// vec.remove_item(&1);
+    ///
+    /// assert_eq!(vec, vec![2, 3, 1]);
+    /// ```
+    #[unstable(feature = "vec_remove_item", reason = "recently added", issue = "40062")]
+    pub fn remove_item(&mut self, item: &T) -> Option<T> {
+        let pos = match self.iter().position(|x| *x == *item) {
+            Some(x) => x,
+            None => return None,
+        };
+        Some(self.remove(pos))
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
index 8d42045ff16372cbaccdfc7b80124488d4c444b2..1985be7f901c6889c2c763be7aa0190f81138cb0 100644 (file)
@@ -22,7 +22,7 @@
 use core::fmt;
 use core::iter::{repeat, FromIterator, FusedIterator};
 use core::mem;
-use core::ops::{Index, IndexMut};
+use core::ops::{Index, IndexMut, Place, Placer, InPlace};
 use core::ptr;
 use core::ptr::Shared;
 use core::slice;
@@ -1087,14 +1087,7 @@ pub fn pop_front(&mut self) -> Option<T> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push_front(&mut self, value: T) {
-        if self.is_full() {
-            let old_cap = self.cap();
-            self.buf.double();
-            unsafe {
-                self.handle_cap_increase(old_cap);
-            }
-            debug_assert!(!self.is_full());
-        }
+        self.grow_if_necessary();
 
         self.tail = self.wrap_sub(self.tail, 1);
         let tail = self.tail;
@@ -1117,14 +1110,7 @@ pub fn push_front(&mut self, value: T) {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push_back(&mut self, value: T) {
-        if self.is_full() {
-            let old_cap = self.cap();
-            self.buf.double();
-            unsafe {
-                self.handle_cap_increase(old_cap);
-            }
-            debug_assert!(!self.is_full());
-        }
+        self.grow_if_necessary();
 
         let head = self.head;
         self.head = self.wrap_add(self.head, 1);
@@ -1257,14 +1243,7 @@ pub fn swap_remove_front(&mut self, index: usize) -> Option<T> {
     #[stable(feature = "deque_extras_15", since = "1.5.0")]
     pub fn insert(&mut self, index: usize, value: T) {
         assert!(index <= self.len(), "index out of bounds");
-        if self.is_full() {
-            let old_cap = self.cap();
-            self.buf.double();
-            unsafe {
-                self.handle_cap_increase(old_cap);
-            }
-            debug_assert!(!self.is_full());
-        }
+        self.grow_if_necessary();
 
         // Move the least number of elements in the ring buffer and insert
         // the given object
@@ -1762,11 +1741,74 @@ pub fn retain<F>(&mut self, mut f: F)
             self.truncate(len - del);
         }
     }
+
+    // This may panic or abort
+    #[inline]
+    fn grow_if_necessary(&mut self) {
+        if self.is_full() {
+            let old_cap = self.cap();
+            self.buf.double();
+            unsafe {
+                self.handle_cap_increase(old_cap);
+            }
+            debug_assert!(!self.is_full());
+        }
+    }
+
+    /// Returns a place for insertion at the back of the `VecDeque`.
+    ///
+    /// Using this method with placement syntax is equivalent to [`push_back`](#method.push_back),
+    /// but may be more efficient.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(collection_placement)]
+    /// #![feature(placement_in_syntax)]
+    ///
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut buf = VecDeque::new();
+    /// buf.place_back() <- 3;
+    /// buf.place_back() <- 4;
+    /// assert_eq!(&buf, &[3, 4]);
+    /// ```
+    #[unstable(feature = "collection_placement",
+               reason = "placement protocol is subject to change",
+               issue = "30172")]
+    pub fn place_back(&mut self) -> PlaceBack<T> {
+        PlaceBack { vec_deque: self }
+    }
+
+    /// Returns a place for insertion at the front of the `VecDeque`.
+    ///
+    /// Using this method with placement syntax is equivalent to [`push_front`](#method.push_front),
+    /// but may be more efficient.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(collection_placement)]
+    /// #![feature(placement_in_syntax)]
+    ///
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut buf = VecDeque::new();
+    /// buf.place_front() <- 3;
+    /// buf.place_front() <- 4;
+    /// assert_eq!(&buf, &[4, 3]);
+    /// ```
+    #[unstable(feature = "collection_placement",
+               reason = "placement protocol is subject to change",
+               issue = "30172")]
+    pub fn place_front(&mut self) -> PlaceFront<T> {
+        PlaceFront { vec_deque: self }
+    }
 }
 
 impl<T: Clone> VecDeque<T> {
     /// Modifies the `VecDeque` in-place so that `len()` is equal to new_len,
-    /// either by removing excess elements or by appending copies of a value to the back.
+    /// either by removing excess elements or by appending clones of `value` to the back.
     ///
     /// # Examples
     ///
@@ -2442,6 +2484,98 @@ fn from(other: VecDeque<T>) -> Self {
     }
 }
 
+/// A place for insertion at the back of a `VecDeque`.
+///
+/// See [`VecDeque::place_back`](struct.VecDeque.html#method.place_back) for details.
+#[must_use = "places do nothing unless written to with `<-` syntax"]
+#[unstable(feature = "collection_placement",
+           reason = "struct name and placement protocol are subject to change",
+           issue = "30172")]
+#[derive(Debug)]
+pub struct PlaceBack<'a, T: 'a> {
+    vec_deque: &'a mut VecDeque<T>,
+}
+
+#[unstable(feature = "collection_placement",
+           reason = "placement protocol is subject to change",
+           issue = "30172")]
+impl<'a, T> Placer<T> for PlaceBack<'a, T> {
+    type Place = PlaceBack<'a, T>;
+
+    fn make_place(self) -> Self {
+        self.vec_deque.grow_if_necessary();
+        self
+    }
+}
+
+#[unstable(feature = "collection_placement",
+           reason = "placement protocol is subject to change",
+           issue = "30172")]
+impl<'a, T> Place<T> for PlaceBack<'a, T> {
+    fn pointer(&mut self) -> *mut T {
+        unsafe { self.vec_deque.ptr().offset(self.vec_deque.head as isize) }
+    }
+}
+
+#[unstable(feature = "collection_placement",
+           reason = "placement protocol is subject to change",
+           issue = "30172")]
+impl<'a, T> InPlace<T> for PlaceBack<'a, T> {
+    type Owner = &'a mut T;
+
+    unsafe fn finalize(mut self) -> &'a mut T {
+        let head = self.vec_deque.head;
+        self.vec_deque.head = self.vec_deque.wrap_add(head, 1);
+        &mut *(self.vec_deque.ptr().offset(head as isize))
+    }
+}
+
+/// A place for insertion at the front of a `VecDeque`.
+///
+/// See [`VecDeque::place_front`](struct.VecDeque.html#method.place_front) for details.
+#[must_use = "places do nothing unless written to with `<-` syntax"]
+#[unstable(feature = "collection_placement",
+           reason = "struct name and placement protocol are subject to change",
+           issue = "30172")]
+#[derive(Debug)]
+pub struct PlaceFront<'a, T: 'a> {
+    vec_deque: &'a mut VecDeque<T>,
+}
+
+#[unstable(feature = "collection_placement",
+           reason = "placement protocol is subject to change",
+           issue = "30172")]
+impl<'a, T> Placer<T> for PlaceFront<'a, T> {
+    type Place = PlaceFront<'a, T>;
+
+    fn make_place(self) -> Self {
+        self.vec_deque.grow_if_necessary();
+        self
+    }
+}
+
+#[unstable(feature = "collection_placement",
+           reason = "placement protocol is subject to change",
+           issue = "30172")]
+impl<'a, T> Place<T> for PlaceFront<'a, T> {
+    fn pointer(&mut self) -> *mut T {
+        let tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1);
+        unsafe { self.vec_deque.ptr().offset(tail as isize) }
+    }
+}
+
+#[unstable(feature = "collection_placement",
+           reason = "placement protocol is subject to change",
+           issue = "30172")]
+impl<'a, T> InPlace<T> for PlaceFront<'a, T> {
+    type Owner = &'a mut T;
+
+    unsafe fn finalize(mut self) -> &'a mut T {
+        self.vec_deque.tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1);
+        &mut *(self.vec_deque.ptr().offset(self.vec_deque.tail as isize))
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use test;
@@ -2797,4 +2931,5 @@ fn create_vec_and_test_convert(cap: usize, offset: usize, len: usize) {
             }
         }
     }
+
 }
index 849d2401691691eb013d0e57736fd29db0d5a496..d97d9b8ab83f67935fcec4a60e48c83f0e924a4c 100644 (file)
@@ -32,6 +32,7 @@
 extern crate collections;
 extern crate test;
 extern crate std_unicode;
+extern crate core;
 
 use std::hash::{Hash, Hasher};
 use std::collections::hash_map::DefaultHasher;
index 1541061a1984214bf70a4260b2ab35136b98d894..f2935c05d4f7a90ac3112b0481fdac7057562652 100644 (file)
@@ -10,7 +10,7 @@
 
 use std::collections::VecDeque;
 use std::fmt::Debug;
-use std::collections::vec_deque::Drain;
+use std::collections::vec_deque::{Drain};
 
 use self::Taggy::*;
 use self::Taggypar::*;
@@ -1000,3 +1000,25 @@ fn test_is_empty() {
     assert!(v.iter_mut().is_empty());
     assert!(v.into_iter().is_empty());
 }
+
+#[test]
+fn test_placement_in() {
+    let mut buf: VecDeque<isize> = VecDeque::new();
+    buf.place_back() <- 1;
+    buf.place_back() <- 2;
+    assert_eq!(buf, [1,2]);
+
+    buf.place_front() <- 3;
+    buf.place_front() <- 4;
+    assert_eq!(buf, [4,3,1,2]);
+
+    {
+        let ptr_head = buf.place_front() <- 5;
+        assert_eq!(*ptr_head, 5);
+    }
+    {
+        let ptr_tail = buf.place_back() <- 6;
+        assert_eq!(*ptr_tail, 6);
+    }
+    assert_eq!(buf, [5,4,3,1,2,6]);
+}
index 482d70895ff89235307cc6e2cb858fef839e4b53..fb42b915c7694a542957d62ea0575f4d38e3c372 100644 (file)
@@ -402,15 +402,16 @@ pub extern "C" fn u128_mul(a: i128, b: i128) -> i128 {
     }
 
     trait AbsExt: Sized {
-        fn uabs(self) -> u128 {
-            self.iabs() as u128
-        }
+        fn uabs(self) -> u128;
         fn iabs(self) -> i128;
     }
 
     impl AbsExt for i128 {
+        fn uabs(self) -> u128 {
+            self.iabs() as u128
+        }
         fn iabs(self) -> i128 {
-            let s = self >> 127;
+            let s = self.wrapping_shr(127);
             ((self ^ s).wrapping_sub(s))
         }
     }
index dc5a662cdb0445fea0fca104923710cb80fbaec8..1657342ff6ac6f8aa567307edc13e9c727147309 100644 (file)
@@ -529,6 +529,26 @@ pub trait Debug {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Display {
     /// Formats the value using the given formatter.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fmt;
+    ///
+    /// struct Position {
+    ///     longitude: f32,
+    ///     latitude: f32,
+    /// }
+    ///
+    /// impl fmt::Display for Position {
+    ///     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    ///         write!(f, "({}, {})", self.longitude, self.latitude)
+    ///     }
+    /// }
+    ///
+    /// assert_eq!("(1.987, 2.983)".to_owned(),
+    ///            format!("{}", Position { longitude: 1.987, latitude: 2.983, }));
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
@@ -930,7 +950,6 @@ pub fn write(output: &mut Write, args: Arguments) -> Result {
 }
 
 impl<'a> Formatter<'a> {
-
     // First up is the collection of functions used to execute a format string
     // at runtime. This consumes all of the compile-time statics generated by
     // the format! syntax extension.
index 66a923f8e588ae33fe11784d12096ab9c0d45010..b22f7fa17077b7890940b0ac82ba331d685d3e7f 100644 (file)
@@ -32,11 +32,11 @@ macro_rules! panic {
 
 /// Ensure that a boolean expression is `true` at runtime.
 ///
-/// This will invoke the `panic!` macro if the provided expression cannot be
+/// This will invoke the [`panic!`] macro if the provided expression cannot be
 /// evaluated to `true` at runtime.
 ///
 /// Assertions are always checked in both debug and release builds, and cannot
-/// be disabled. See `debug_assert!` for assertions that are not enabled in
+/// be disabled. See [`debug_assert!`] for assertions that are not enabled in
 /// release builds by default.
 ///
 /// Unsafe code relies on `assert!` to enforce run-time invariants that, if
@@ -48,6 +48,8 @@ macro_rules! panic {
 /// This macro has a second version, where a custom panic message can
 /// be provided with or without arguments for formatting.
 ///
+/// [`panic!`]: macro.panic.html
+/// [`debug_assert!`]: macro.debug_assert.html
 /// [testing]: ../book/testing.html
 ///
 /// # Examples
@@ -88,9 +90,11 @@ macro_rules! assert {
 /// On panic, this macro will print the values of the expressions with their
 /// debug representations.
 ///
-/// Like `assert!()`, this macro has a second version, where a custom
+/// Like [`assert!()`], this macro has a second version, where a custom
 /// panic message can be provided.
 ///
+/// [`assert!()`]: macro.assert.html
+///
 /// # Examples
 ///
 /// ```
@@ -134,6 +138,8 @@ macro_rules! assert_eq {
 /// Like `assert!()`, this macro has a second version, where a custom
 /// panic message can be provided.
 ///
+/// [`assert!`]: macro.assert.html
+///
 /// # Examples
 ///
 /// ```
@@ -171,13 +177,13 @@ macro_rules! assert_ne {
 
 /// Ensure that a boolean expression is `true` at runtime.
 ///
-/// This will invoke the `panic!` macro if the provided expression cannot be
+/// This will invoke the [`panic!`] macro if the provided expression cannot be
 /// evaluated to `true` at runtime.
 ///
-/// Like `assert!`, this macro also has a second version, where a custom panic
+/// Like [`assert!`], this macro also has a second version, where a custom panic
 /// message can be provided.
 ///
-/// Unlike `assert!`, `debug_assert!` statements are only enabled in non
+/// Unlike [`assert!`], `debug_assert!` statements are only enabled in non
 /// optimized builds by default. An optimized build will omit all
 /// `debug_assert!` statements unless `-C debug-assertions` is passed to the
 /// compiler. This makes `debug_assert!` useful for checks that are too
@@ -187,10 +193,13 @@ macro_rules! assert_ne {
 /// An unchecked assertion allows a program in an inconsistent state to keep
 /// running, which might have unexpected consequences but does not introduce
 /// unsafety as long as this only happens in safe code. The performance cost
-/// of assertions, is however, not measurable in general. Replacing `assert!`
+/// of assertions, is however, not measurable in general. Replacing [`assert!`]
 /// with `debug_assert!` is thus only encouraged after thorough profiling, and
 /// more importantly, only in safe code!
 ///
+/// [`panic!`]: macro.panic.html
+/// [`assert!`]: macro.assert.html
+///
 /// # Examples
 ///
 /// ```
index 02851c224e2e35b019c8cd6a0a06446156916716..260fdab9d58fb5205faa1d1f6aa226c7f5c629cf 100644 (file)
@@ -191,6 +191,10 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 /// allocations or resources, so care must be taken not to overwrite an object
 /// that should be dropped.
 ///
+/// It does not immediately drop the contents of `src` either; it is rather
+/// *moved* into the memory location `dst` and will be dropped whenever that
+/// location goes out of scope.
+///
 /// This is appropriate for initializing uninitialized memory, or overwriting
 /// memory that has previously been `read` from.
 ///
index 8d7fe655c23b2a9b8cf4e30274160660aea1d51a..0d2a467b577027aa79cac6b420bfcd41f9036992 100644 (file)
@@ -21,7 +21,7 @@
 //! This functionality is intended to be expanded over time as more surface
 //! area for macro authors is stabilized.
 //!
-//! See [the book](../../book/procedural-macros.html) for more.
+//! See [the book](../book/procedural-macros.html) for more.
 
 #![crate_name = "proc_macro"]
 #![stable(feature = "proc_macro_lib", since = "1.15.0")]
index e6736ccafbad9271d7f799f4ac6f0d1853918d47..8be5d4327e72ec2c134e7746ecaa11985fc69b3c 100644 (file)
@@ -18,6 +18,7 @@
 use super::dep_node::{DepNode, WorkProductId};
 use super::query::DepGraphQuery;
 use super::raii;
+use super::safe::DepGraphSafe;
 use super::thread::{DepGraphThreadData, DepMessage};
 
 #[derive(Clone)]
@@ -76,11 +77,38 @@ pub fn with_ignore<OP,R>(&self, op: OP) -> R
         op()
     }
 
-    pub fn with_task<OP,R>(&self, key: DepNode<DefId>, op: OP) -> R
-        where OP: FnOnce() -> R
+    /// Starts a new dep-graph task. Dep-graph tasks are specified
+    /// using a free function (`task`) and **not** a closure -- this
+    /// is intentional because we want to exercise tight control over
+    /// what state they have access to. In particular, we want to
+    /// prevent implicit 'leaks' of tracked state into the task (which
+    /// could then be read without generating correct edges in the
+    /// dep-graph -- see the [README] for more details on the
+    /// dep-graph). To this end, the task function gets exactly two
+    /// pieces of state: the context `cx` and an argument `arg`. Both
+    /// of these bits of state must be of some type that implements
+    /// `DepGraphSafe` and hence does not leak.
+    ///
+    /// The choice of two arguments is not fundamental. One argument
+    /// would work just as well, since multiple values can be
+    /// collected using tuples. However, using two arguments works out
+    /// to be quite convenient, since it is common to need a context
+    /// (`cx`) and some argument (e.g., a `DefId` identifying what
+    /// item to process).
+    ///
+    /// For cases where you need some other number of arguments:
+    ///
+    /// - If you only need one argument, just use `()` for the `arg`
+    ///   parameter.
+    /// - If you need 3+ arguments, use a tuple for the
+    ///   `arg` parameter.
+    ///
+    /// [README]: README.md
+    pub fn with_task<C, A, R>(&self, key: DepNode<DefId>, cx: C, arg: A, task: fn(C, A) -> R) -> R
+        where C: DepGraphSafe, A: DepGraphSafe
     {
         let _task = self.in_task(key);
-        op()
+        task(cx, arg)
     }
 
     pub fn read(&self, v: DepNode<DefId>) {
index 7331756f35b8e95da63c8e6667f02de9a7b0caf1..a9f0a44e4208c031f7ade3e7bd5756ba3d103b9a 100644 (file)
@@ -15,6 +15,7 @@
 mod graph;
 mod query;
 mod raii;
+mod safe;
 mod shadow;
 mod thread;
 mod visit;
@@ -25,6 +26,8 @@
 pub use self::graph::DepGraph;
 pub use self::graph::WorkProduct;
 pub use self::query::DepGraphQuery;
+pub use self::safe::AssertDepGraphSafe;
+pub use self::safe::DepGraphSafe;
 pub use self::visit::visit_all_bodies_in_krate;
 pub use self::visit::visit_all_item_likes_in_krate;
 pub use self::raii::DepTask;
diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs
new file mode 100644 (file)
index 0000000..f85f033
--- /dev/null
@@ -0,0 +1,63 @@
+// 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.
+//
+// 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 hir::BodyId;
+use hir::def_id::DefId;
+use syntax::ast::NodeId;
+use ty::TyCtxt;
+
+/// The `DepGraphSafe` trait is used to specify what kinds of values
+/// are safe to "leak" into a task. The idea is that this should be
+/// only be implemented for things like the tcx as well as various id
+/// types, which will create reads in the dep-graph whenever the trait
+/// loads anything that might depend on the input program.
+pub trait DepGraphSafe {
+}
+
+/// A `BodyId` on its own doesn't give access to any particular state.
+/// You must fetch the state from the various maps or generate
+/// on-demand queries, all of which create reads.
+impl DepGraphSafe for BodyId {
+}
+
+/// A `NodeId` on its own doesn't give access to any particular state.
+/// You must fetch the state from the various maps or generate
+/// on-demand queries, all of which create reads.
+impl DepGraphSafe for NodeId {
+}
+
+/// A `DefId` on its own doesn't give access to any particular state.
+/// You must fetch the state from the various maps or generate
+/// on-demand queries, all of which create reads.
+impl DepGraphSafe for DefId {
+}
+
+/// The type context itself can be used to access all kinds of tracked
+/// state, but those accesses should always generate read events.
+impl<'a, 'gcx, 'tcx> DepGraphSafe for TyCtxt<'a, 'gcx, 'tcx> {
+}
+
+/// Tuples make it easy to build up state.
+impl<A, B> DepGraphSafe for (A, B)
+    where A: DepGraphSafe, B: DepGraphSafe
+{
+}
+
+/// No data here! :)
+impl DepGraphSafe for () {
+}
+
+/// A convenient override that lets you pass arbitrary state into a
+/// task. Every use should be accompanied by a comment explaining why
+/// it makes sense (or how it could be refactored away in the future).
+pub struct AssertDepGraphSafe<T>(pub T);
+
+impl<T> DepGraphSafe for AssertDepGraphSafe<T> {
+}
index c835189820e5140aa02ddf5c060d14d4244f2b0c..68e64b8b7bfc827a03bfffd75abd246f7e2d4569 100644 (file)
@@ -152,7 +152,7 @@ course, it depends on the program.
 
 The main case which fails today that I would like to support is:
 
-```text
+```rust
 fn foo<T>(x: T, y: T) { ... }
 
 fn bar() {
@@ -168,6 +168,8 @@ because the type variable `T` is merged with the type variable for
 `X`, and thus inherits its UB/LB of `@mut int`.  This leaves no
 flexibility for `T` to later adjust to accommodate `@int`.
 
+Note: `@` and `@mut` are replaced with `Rc<T>` and `Rc<RefCell<T>>` in current Rust.
+
 ### What to do when not all bounds are present
 
 In the prior discussion we assumed that A.ub was not top and B.lb was
index 80da861139b42fd9acc50f686746219a5f091c4a..b564faf3d0c24c9500c3a56950e3b9f89ca9f8c5 100644 (file)
@@ -121,17 +121,19 @@ every expression, block, and pattern (patterns are considered to
 "execute" by testing the value they are applied to and creating any
 relevant bindings).  So, for example:
 
-    fn foo(x: isize, y: isize) { // -+
-    //  +------------+       //  |
-    //  |      +-----+       //  |
-    //  |  +-+ +-+ +-+       //  |
-    //  |  | | | | | |       //  |
-    //  v  v v v v v v       //  |
-        let z = x + y;       //  |
-        ...                  //  |
-    }                        // -+
-
-    fn bar() { ... }
+```rust
+fn foo(x: isize, y: isize) { // -+
+//  +------------+           //  |
+//  |      +-----+           //  |
+//  |  +-+ +-+ +-+           //  |
+//  |  | | | | | |           //  |
+//  v  v v v v v v           //  |
+    let z = x + y;           //  |
+    ...                      //  |
+}                            // -+
+
+fn bar() { ... }
+```
 
 In this example, there is a region for the fn body block as a whole,
 and then a subregion for the declaration of the local variable.
@@ -160,7 +162,9 @@ this, we get a lot of spurious errors around nested calls, in
 particular when combined with `&mut` functions. For example, a call
 like this one
 
-    self.foo(self.bar())
+```rust
+self.foo(self.bar())
+```
 
 where both `foo` and `bar` are `&mut self` functions will always yield
 an error.
@@ -168,20 +172,22 @@ an error.
 Here is a more involved example (which is safe) so we can see what's
 going on:
 
-    struct Foo { f: usize, g: usize }
-    ...
-    fn add(p: &mut usize, v: usize) {
-        *p += v;
-    }
-    ...
-    fn inc(p: &mut usize) -> usize {
-        *p += 1; *p
-    }
-    fn weird() {
-        let mut x: Box<Foo> = box Foo { ... };
-        'a: add(&mut (*x).f,
-                'b: inc(&mut (*x).f)) // (..)
-    }
+```rust
+struct Foo { f: usize, g: usize }
+// ...
+fn add(p: &mut usize, v: usize) {
+    *p += v;
+}
+// ...
+fn inc(p: &mut usize) -> usize {
+    *p += 1; *p
+}
+fn weird() {
+    let mut x: Box<Foo> = box Foo { /* ... */ };
+    'a: add(&mut (*x).f,
+            'b: inc(&mut (*x).f)) // (..)
+}
+```
 
 The important part is the line marked `(..)` which contains a call to
 `add()`. The first argument is a mutable borrow of the field `f`.  The
@@ -197,16 +203,18 @@ can see that this error is unnecessary. Let's examine the lifetimes
 involved with `'a` in detail. We'll break apart all the steps involved
 in a call expression:
 
-    'a: {
-        'a_arg1: let a_temp1: ... = add;
-        'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f;
-        'a_arg3: let a_temp3: usize = {
-            let b_temp1: ... = inc;
-            let b_temp2: &'b = &'b mut (*x).f;
-            'b_call: b_temp1(b_temp2)
-        };
-        'a_call: a_temp1(a_temp2, a_temp3) // (**)
-    }
+```rust
+'a: {
+    'a_arg1: let a_temp1: ... = add;
+    'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f;
+    'a_arg3: let a_temp3: usize = {
+        let b_temp1: ... = inc;
+        let b_temp2: &'b = &'b mut (*x).f;
+        'b_call: b_temp1(b_temp2)
+    };
+    'a_call: a_temp1(a_temp2, a_temp3) // (**)
+}
+```
 
 Here we see that the lifetime `'a` includes a number of substatements.
 In particular, there is this lifetime I've called `'a_call` that
@@ -225,19 +233,21 @@ it will not be *dereferenced* during the evaluation of the second
 argument, it can still be *invalidated* by that evaluation. Consider
 this similar but unsound example:
 
-    struct Foo { f: usize, g: usize }
-    ...
-    fn add(p: &mut usize, v: usize) {
-        *p += v;
-    }
-    ...
-    fn consume(x: Box<Foo>) -> usize {
-        x.f + x.g
-    }
-    fn weird() {
-        let mut x: Box<Foo> = box Foo { ... };
-        'a: add(&mut (*x).f, consume(x)) // (..)
-    }
+```rust
+struct Foo { f: usize, g: usize }
+// ...
+fn add(p: &mut usize, v: usize) {
+    *p += v;
+}
+// ...
+fn consume(x: Box<Foo>) -> usize {
+    x.f + x.g
+}
+fn weird() {
+    let mut x: Box<Foo> = box Foo { ... };
+    'a: add(&mut (*x).f, consume(x)) // (..)
+}
+```
 
 In this case, the second argument to `add` actually consumes `x`, thus
 invalidating the first argument.
index 95ce8d39ff488b0c7fc099d60528988f94b4ed37..a67049f72852bd99b81ee062c1fed836c875e842 100644 (file)
@@ -91,7 +91,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>(
         };
 
         if output_template.is_empty() {
-            bug!("empty string provided as RUST_REGION_GRAPH");
+            panic!("empty string provided as RUST_REGION_GRAPH");
         }
 
         if output_template.contains('%') {
index 32bc81e947037afaef2030b2f9250f35dd6da22f..9279f24a57ab32d3892a5bd1b0ac54171efd69f5 100644 (file)
@@ -806,6 +806,12 @@ fn visit_nested_body(&mut self, body: hir::BodyId) {
         self.tables = old_tables;
     }
 
+    fn visit_body(&mut self, body: &'tcx hir::Body) {
+        run_lints!(self, check_body, late_passes, body);
+        hir_visit::walk_body(self, body);
+        run_lints!(self, check_body_post, late_passes, body);
+    }
+
     fn visit_item(&mut self, it: &'tcx hir::Item) {
         self.with_lint_attrs(&it.attrs, |cx| {
             run_lints!(cx, check_item, late_passes, it);
index e9f603db15d6214b538c29a71a5aa55454641997..e81d09773701cb7f3e5c90fe8f607bf0d89f844c 100644 (file)
@@ -133,6 +133,8 @@ pub trait LintPass {
 // FIXME: eliminate the duplication with `Visitor`. But this also
 // contains a few lint-specific methods with no equivalent in `Visitor`.
 pub trait LateLintPass<'a, 'tcx>: LintPass {
+    fn check_body(&mut self, _: &LateContext, _: &'tcx hir::Body) { }
+    fn check_body_post(&mut self, _: &LateContext, _: &'tcx hir::Body) { }
     fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { }
     fn check_crate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { }
     fn check_crate_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { }
index ed72fe1801663a4bc0987622180c8cb82ae4b11e..fea576f7067807bf2933906496e5e5610b6df142 100644 (file)
@@ -19,6 +19,7 @@
 use hir::def_id::DefId;
 use ty::subst::Substs;
 use ty::{self, AdtDef, ClosureSubsts, Region, Ty};
+use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use util::ppaux;
 use rustc_back::slice;
 use hir::InlineAsm;
@@ -63,8 +64,7 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
 }
 
 /// Lowered representation of a single function.
-// Do not implement clone for Mir, which can be accidently done and kind of expensive.
-#[derive(RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Mir<'tcx> {
     /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock`
     /// that indexes into this vector.
@@ -1333,3 +1333,347 @@ pub fn dominates(&self, other: &Location, dominators: &Dominators<BasicBlock>) -
         }
     }
 }
+
+
+/*
+ * TypeFoldable implementations for MIR types
+ */
+
+impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        Mir {
+            basic_blocks: self.basic_blocks.fold_with(folder),
+            visibility_scopes: self.visibility_scopes.clone(),
+            promoted: self.promoted.fold_with(folder),
+            return_ty: self.return_ty.fold_with(folder),
+            local_decls: self.local_decls.fold_with(folder),
+            arg_count: self.arg_count,
+            upvar_decls: self.upvar_decls.clone(),
+            spread_arg: self.spread_arg,
+            span: self.span,
+            cache: cache::Cache::new()
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.basic_blocks.visit_with(visitor) ||
+        self.promoted.visit_with(visitor)     ||
+        self.return_ty.visit_with(visitor)    ||
+        self.local_decls.visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        LocalDecl {
+            ty: self.ty.fold_with(folder),
+            ..self.clone()
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.ty.visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        BasicBlockData {
+            statements: self.statements.fold_with(folder),
+            terminator: self.terminator.fold_with(folder),
+            is_cleanup: self.is_cleanup
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.statements.visit_with(visitor) || self.terminator.visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        use mir::StatementKind::*;
+
+        let kind = match self.kind {
+            Assign(ref lval, ref rval) => Assign(lval.fold_with(folder), rval.fold_with(folder)),
+            SetDiscriminant { ref lvalue, variant_index } => SetDiscriminant {
+                lvalue: lvalue.fold_with(folder),
+                variant_index: variant_index
+            },
+            StorageLive(ref lval) => StorageLive(lval.fold_with(folder)),
+            StorageDead(ref lval) => StorageDead(lval.fold_with(folder)),
+            InlineAsm { ref asm, ref outputs, ref inputs } => InlineAsm {
+                asm: asm.clone(),
+                outputs: outputs.fold_with(folder),
+                inputs: inputs.fold_with(folder)
+            },
+            Nop => Nop,
+        };
+        Statement {
+            source_info: self.source_info,
+            kind: kind
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        use mir::StatementKind::*;
+
+        match self.kind {
+            Assign(ref lval, ref rval) => { lval.visit_with(visitor) || rval.visit_with(visitor) }
+            SetDiscriminant { ref lvalue, .. } |
+            StorageLive(ref lvalue) |
+            StorageDead(ref lvalue) => lvalue.visit_with(visitor),
+            InlineAsm { ref outputs, ref inputs, .. } =>
+                outputs.visit_with(visitor) || inputs.visit_with(visitor),
+            Nop => false,
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        use mir::TerminatorKind::*;
+
+        let kind = match self.kind {
+            Goto { target } => Goto { target: target },
+            SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt {
+                discr: discr.fold_with(folder),
+                switch_ty: switch_ty.fold_with(folder),
+                values: values.clone(),
+                targets: targets.clone()
+            },
+            Drop { ref location, target, unwind } => Drop {
+                location: location.fold_with(folder),
+                target: target,
+                unwind: unwind
+            },
+            DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace {
+                location: location.fold_with(folder),
+                value: value.fold_with(folder),
+                target: target,
+                unwind: unwind
+            },
+            Call { ref func, ref args, ref destination, cleanup } => {
+                let dest = destination.as_ref().map(|&(ref loc, dest)| {
+                    (loc.fold_with(folder), dest)
+                });
+
+                Call {
+                    func: func.fold_with(folder),
+                    args: args.fold_with(folder),
+                    destination: dest,
+                    cleanup: cleanup
+                }
+            },
+            Assert { ref cond, expected, ref msg, target, cleanup } => {
+                let msg = if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
+                    AssertMessage::BoundsCheck {
+                        len: len.fold_with(folder),
+                        index: index.fold_with(folder),
+                    }
+                } else {
+                    msg.clone()
+                };
+                Assert {
+                    cond: cond.fold_with(folder),
+                    expected: expected,
+                    msg: msg,
+                    target: target,
+                    cleanup: cleanup
+                }
+            },
+            Resume => Resume,
+            Return => Return,
+            Unreachable => Unreachable,
+        };
+        Terminator {
+            source_info: self.source_info,
+            kind: kind
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        use mir::TerminatorKind::*;
+
+        match self.kind {
+            SwitchInt { ref discr, switch_ty, .. } =>
+                discr.visit_with(visitor) || switch_ty.visit_with(visitor),
+            Drop { ref location, ..} => location.visit_with(visitor),
+            DropAndReplace { ref location, ref value, ..} =>
+                location.visit_with(visitor) || value.visit_with(visitor),
+            Call { ref func, ref args, ref destination, .. } => {
+                let dest = if let Some((ref loc, _)) = *destination {
+                    loc.visit_with(visitor)
+                } else { false };
+                dest || func.visit_with(visitor) || args.visit_with(visitor)
+            },
+            Assert { ref cond, ref msg, .. } => {
+                if cond.visit_with(visitor) {
+                    if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
+                        len.visit_with(visitor) || index.visit_with(visitor)
+                    } else {
+                        false
+                    }
+                } else {
+                    false
+                }
+            },
+            Goto { .. } |
+            Resume |
+            Return |
+            Unreachable => false
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Lvalue<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        match self {
+            &Lvalue::Projection(ref p) => Lvalue::Projection(p.fold_with(folder)),
+            _ => self.clone()
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        if let &Lvalue::Projection(ref p) = self {
+            p.visit_with(visitor)
+        } else {
+            false
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        use mir::Rvalue::*;
+        match *self {
+            Use(ref op) => Use(op.fold_with(folder)),
+            Repeat(ref op, len) => Repeat(op.fold_with(folder), len),
+            Ref(region, bk, ref lval) => Ref(region.fold_with(folder), bk, lval.fold_with(folder)),
+            Len(ref lval) => Len(lval.fold_with(folder)),
+            Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
+            BinaryOp(op, ref rhs, ref lhs) =>
+                BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)),
+            CheckedBinaryOp(op, ref rhs, ref lhs) =>
+                CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)),
+            UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)),
+            Discriminant(ref lval) => Discriminant(lval.fold_with(folder)),
+            Box(ty) => Box(ty.fold_with(folder)),
+            Aggregate(ref kind, ref fields) => {
+                let kind = match *kind {
+                    AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
+                    AggregateKind::Tuple => AggregateKind::Tuple,
+                    AggregateKind::Adt(def, v, substs, n) =>
+                        AggregateKind::Adt(def, v, substs.fold_with(folder), n),
+                    AggregateKind::Closure(id, substs) =>
+                        AggregateKind::Closure(id, substs.fold_with(folder))
+                };
+                Aggregate(kind, fields.fold_with(folder))
+            }
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        use mir::Rvalue::*;
+        match *self {
+            Use(ref op) => op.visit_with(visitor),
+            Repeat(ref op, _) => op.visit_with(visitor),
+            Ref(region, _, ref lval) => region.visit_with(visitor) || lval.visit_with(visitor),
+            Len(ref lval) => lval.visit_with(visitor),
+            Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor),
+            BinaryOp(_, ref rhs, ref lhs) |
+            CheckedBinaryOp(_, ref rhs, ref lhs) =>
+                rhs.visit_with(visitor) || lhs.visit_with(visitor),
+            UnaryOp(_, ref val) => val.visit_with(visitor),
+            Discriminant(ref lval) => lval.visit_with(visitor),
+            Box(ty) => ty.visit_with(visitor),
+            Aggregate(ref kind, ref fields) => {
+                (match *kind {
+                    AggregateKind::Array(ty) => ty.visit_with(visitor),
+                    AggregateKind::Tuple => false,
+                    AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor),
+                    AggregateKind::Closure(_, substs) => substs.visit_with(visitor)
+                }) || fields.visit_with(visitor)
+            }
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        match *self {
+            Operand::Consume(ref lval) => Operand::Consume(lval.fold_with(folder)),
+            Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)),
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match *self {
+            Operand::Consume(ref lval) => lval.visit_with(visitor),
+            Operand::Constant(ref c) => c.visit_with(visitor)
+        }
+    }
+}
+
+impl<'tcx, B, V> TypeFoldable<'tcx> for Projection<'tcx, B, V>
+    where B: TypeFoldable<'tcx>, V: TypeFoldable<'tcx>
+{
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        use mir::ProjectionElem::*;
+
+        let base = self.base.fold_with(folder);
+        let elem = match self.elem {
+            Deref => Deref,
+            Field(f, ty) => Field(f, ty.fold_with(folder)),
+            Index(ref v) => Index(v.fold_with(folder)),
+            ref elem => elem.clone()
+        };
+
+        Projection {
+            base: base,
+            elem: elem
+        }
+    }
+
+    fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
+        use mir::ProjectionElem::*;
+
+        self.base.visit_with(visitor) ||
+            match self.elem {
+                Field(_, ty) => ty.visit_with(visitor),
+                Index(ref v) => v.visit_with(visitor),
+                _ => false
+            }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        Constant {
+            span: self.span.clone(),
+            ty: self.ty.fold_with(folder),
+            literal: self.literal.fold_with(folder)
+        }
+    }
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.ty.visit_with(visitor) || self.literal.visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        match *self {
+            Literal::Item { def_id, substs } => Literal::Item {
+                def_id: def_id,
+                substs: substs.fold_with(folder)
+            },
+            _ => self.clone()
+        }
+    }
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match *self {
+            Literal::Item { substs, .. } => substs.visit_with(visitor),
+            _ => false
+        }
+    }
+}
index 4c4ace0d8baf9629d64a1cb7a0c805405e27d731..38ea1e4a19b91f536e989da9610cc1547384e700 100644 (file)
@@ -2461,7 +2461,7 @@ fn confirm_builtin_unsize_candidate(&mut self,
                 let new_trait = tcx.mk_dynamic(
                     ty::Binder(tcx.mk_existential_predicates(iter)), r_b);
                 let InferOk { obligations, .. } =
-                    self.infcx.sub_types(false, &obligation.cause, new_trait, target)
+                    self.infcx.eq_types(false, &obligation.cause, new_trait, target)
                     .map_err(|_| Unimplemented)?;
                 self.inferred_obligations.extend(obligations);
 
@@ -2520,7 +2520,7 @@ fn confirm_builtin_unsize_candidate(&mut self,
             // [T; n] -> [T].
             (&ty::TyArray(a, _), &ty::TySlice(b)) => {
                 let InferOk { obligations, .. } =
-                    self.infcx.sub_types(false, &obligation.cause, a, b)
+                    self.infcx.eq_types(false, &obligation.cause, a, b)
                     .map_err(|_| Unimplemented)?;
                 self.inferred_obligations.extend(obligations);
             }
@@ -2583,7 +2583,7 @@ fn confirm_builtin_unsize_candidate(&mut self,
                 });
                 let new_struct = tcx.mk_adt(def, tcx.mk_substs(params));
                 let InferOk { obligations, .. } =
-                    self.infcx.sub_types(false, &obligation.cause, new_struct, target)
+                    self.infcx.eq_types(false, &obligation.cause, new_struct, target)
                     .map_err(|_| Unimplemented)?;
                 self.inferred_obligations.extend(obligations);
 
index d7efee06db2b56bb85f17180d3534c80a545094f..3c37c7353d683b739e76b4a4358dd911984481ec 100644 (file)
@@ -1286,7 +1286,7 @@ pub struct Destructor {
     /// invoked even when there are lifetimes in the type-structure of
     /// `adt` that do not strictly outlive the adt value itself.
     /// (This allows programs to make cyclic structures without
-    /// resorting to unasfe means; see RFCs 769 and 1238).
+    /// resorting to unsafe means; see RFCs 769 and 1238).
     pub is_dtorck: bool,
 }
 
@@ -2302,6 +2302,20 @@ pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> {
         queries::mir::get(self, DUMMY_SP, did).borrow()
     }
 
+    /// Given the DefId of an item, returns its MIR, borrowed immutably.
+    /// Returns None if there is no MIR for the DefId
+    pub fn maybe_item_mir(self, did: DefId) -> Option<Ref<'gcx, Mir<'gcx>>> {
+        if did.is_local() && !self.maps.mir.borrow().contains_key(&did) {
+            return None;
+        }
+
+        if !did.is_local() && !self.sess.cstore.is_item_mir_available(did) {
+            return None;
+        }
+
+        Some(self.item_mir(did))
+    }
+
     /// If `type_needs_drop` returns true, then `ty` is definitely
     /// non-copy and *might* have a destructor attached; if it returns
     /// false, then `ty` definitely has no destructor (i.e. no drop glue).
index 48f6fcd11b8acf18b1e221e751e68f90d5113fa7..49824e8a738d7a74e5a5204d31cfa1a5cbc6ef70 100644 (file)
@@ -12,6 +12,7 @@
 use ty::{self, Lift, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
+use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
 use std::rc::Rc;
 use syntax::abi;
@@ -834,3 +835,13 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         self.expected.visit_with(visitor) || self.found.visit_with(visitor)
     }
 }
+
+impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        self.iter().map(|x| x.fold_with(folder)).collect()
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.iter().any(|t| t.visit_with(visitor))
+    }
+}
index be1582066e393c4b99b6884e6b8f9a5c9dbe85ab..a81c3a177f8854070966720631c65aac9e59c62e 100644 (file)
@@ -654,11 +654,12 @@ pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>)
         }
 
         tcx.layout_depth.set(depth+1);
-        let layout = Layout::compute_uncached(self, infcx)?;
+        let layout = Layout::compute_uncached(self, infcx);
+        tcx.layout_depth.set(depth);
+        let layout = layout?;
         if can_cache {
             tcx.layout_cache.borrow_mut().insert(self, layout);
         }
-        tcx.layout_depth.set(depth);
         Ok(layout)
     }
 
index 47b614a81ae251e9009fbb0543832a0082d2e19f..b441a231874a6def39ca5a95e1da7f07aa93869d 100644 (file)
 pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>;
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, || {
+    tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, tcx, (), check_crate_task);
+
+    fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) {
         tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| {
-            tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), || {
-                borrowck_fn(tcx, body_id);
-            });
+            tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id),
+                                    tcx,
+                                    body_id,
+                                    borrowck_fn);
         });
-    });
+    }
 }
 
 /// Collection of conclusions determined via borrow checker analyses.
index 00cea9cbdf6b7100aac27aa01164f32810c28afe..3f478d7c165d13b1b903e35e0f72f2b53678d5d6 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::collections::range::RangeArgument;
 use std::fmt::Debug;
 use std::iter::{self, FromIterator};
 use std::slice;
@@ -145,6 +146,18 @@ pub fn iter_enumerated_mut(&mut self) -> Enumerated<I, slice::IterMut<T>>
         self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData })
     }
 
+    #[inline]
+    pub fn drain<'a, R: RangeArgument<usize>>(
+        &'a mut self, range: R) -> impl Iterator<Item=T> + 'a {
+        self.raw.drain(range)
+    }
+
+    #[inline]
+    pub fn drain_enumerated<'a, R: RangeArgument<usize>>(
+        &'a mut self, range: R) -> impl Iterator<Item=(I, T)> + 'a {
+        self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData })
+    }
+
     #[inline]
     pub fn last(&self) -> Option<I> {
         self.len().checked_sub(1).map(I::new)
@@ -164,6 +177,16 @@ pub fn swap(&mut self, a: usize, b: usize) {
     pub fn truncate(&mut self, a: usize) {
         self.raw.truncate(a)
     }
+
+    #[inline]
+    pub fn get(&self, index: I) -> Option<&T> {
+        self.raw.get(index.index())
+    }
+
+    #[inline]
+    pub fn get_mut(&mut self, index: I) -> Option<&mut T> {
+        self.raw.get_mut(index.index())
+    }
 }
 
 impl<I: Idx, T> Index<I> for IndexVec<I, T> {
index 3dce4398f3b91838a6eec3ef2a3ae3d93ca02c81..f278325ebec74b81281a3ae5d0604b1a686b3366 100644 (file)
@@ -38,6 +38,7 @@
 #![feature(associated_consts)]
 #![feature(unsize)]
 #![feature(i128_type)]
+#![feature(conservative_impl_trait)]
 
 #![cfg_attr(unix, feature(libc))]
 #![cfg_attr(test, feature(test))]
index 9619ba8472404bb70e0a1fffca1e620841dbe528..86722f667413a1d6645535308e9581fc1f12d417 100644 (file)
@@ -125,6 +125,10 @@ macro_rules! controller_entry_point {
         };
 
         write_out_deps(sess, &outputs, &crate_name);
+        if sess.opts.output_types.contains_key(&OutputType::DepInfo) &&
+            sess.opts.output_types.keys().count() == 1 {
+            return Ok(())
+        }
 
         let arena = DroplessArena::new();
         let arenas = GlobalArenas::new();
@@ -604,7 +608,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
 
     let whitelisted_legacy_custom_derives = registry.take_whitelisted_custom_derives();
     let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups,
-                   llvm_passes, attributes, mir_passes, .. } = registry;
+                   llvm_passes, attributes, .. } = registry;
 
     sess.track_errors(|| {
         let mut ls = sess.lint_store.borrow_mut();
@@ -620,7 +624,6 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
         }
 
         *sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
-        sess.mir_passes.borrow_mut().extend(mir_passes);
         *sess.plugin_attributes.borrow_mut() = attributes.clone();
     })?;
 
@@ -1048,6 +1051,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));
 
         // No lifetime analysis based on borrowing can be done from here on out.
+        passes.push_pass(box mir::transform::inline::Inline);
         passes.push_pass(box mir::transform::instcombine::InstCombine::new());
         passes.push_pass(box mir::transform::deaggregator::Deaggregator);
         passes.push_pass(box mir::transform::copy_prop::CopyPropagation);
index 0b0a9e51cacb0f27901c66d4c99178ab51031bbb..431edb3c9bc4d44e828f44f2d9f2421295b6c6b7 100644 (file)
@@ -358,39 +358,45 @@ fn render_source_line(&self,
         let mut annotations_position = vec![];
         let mut line_len = 0;
         let mut p = 0;
-        let mut ann_iter = annotations.iter().peekable();
-        while let Some(annotation) = ann_iter.next() {
-            let peek = ann_iter.peek();
-            if let Some(next) = peek {
-                if overlaps(next, annotation) && !annotation.is_line() && !next.is_line()
+        for (i, annotation) in annotations.iter().enumerate() {
+            for (j, next) in annotations.iter().enumerate() {
+                if overlaps(next, annotation, 0)  // This label overlaps with another one and both
+                    && !annotation.is_line()      // take space (they have text and are not
+                    && !next.is_line()            // multiline lines).
                     && annotation.has_label()
+                    && j > i
+                    && p == 0  // We're currently on the first line, move the label one line down
                 {
                     // This annotation needs a new line in the output.
                     p += 1;
+                    break;
                 }
             }
             annotations_position.push((p, annotation));
-            if let Some(next) = peek {
-                let l = if let Some(ref label) = next.label {
-                    label.len() + 2
-                } else {
-                    0
-                };
-                if (overlaps(next, annotation)  // Do not allow two labels to be in the same line
-                    || next.end_col + l > annotation.start_col)  // if they overlap including
-                                                // padding, to avoid situations like:
-                                                //
-                                                //      fn foo(x: u32) {
-                                                //      -------^------
-                                                //      |      |
-                                                //      fn_spanx_span
-                                                //
-                    && !annotation.is_line()    // Do not add a new line if this annotation or the
-                    && !next.is_line()          // next are vertical line placeholders.
-                    && annotation.has_label()   // Both labels must have some text, otherwise
-                    && next.has_label()         // they are not overlapping.
-                {
-                    p += 1;
+            for (j, next) in annotations.iter().enumerate() {
+                if j > i  {
+                    let l = if let Some(ref label) = next.label {
+                        label.len() + 2
+                    } else {
+                        0
+                    };
+                    if overlaps(next, annotation, l) // Do not allow two labels to be in the same
+                                                     // line if they overlap including padding, to
+                                                     // avoid situations like:
+                                                     //
+                                                     //      fn foo(x: u32) {
+                                                     //      -------^------
+                                                     //      |      |
+                                                     //      fn_spanx_span
+                                                     //
+                        && !annotation.is_line()     // Do not add a new line if this annotation
+                        && !next.is_line()           // or the next are vertical line placeholders.
+                        && annotation.has_label()    // Both labels must have some text, otherwise
+                        && next.has_label()          // they are not overlapping.
+                    {
+                        p += 1;
+                        break;
+                    }
                 }
             }
             if line_len < p {
@@ -1088,8 +1094,8 @@ fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclus
     (b_start..b_end + extra).contains(a_start) ||
     (a_start..a_end + extra).contains(b_start)
 }
-fn overlaps(a1: &Annotation, a2: &Annotation) -> bool {
-    num_overlap(a1.start_col, a1.end_col, a2.start_col, a2.end_col, false)
+fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool {
+    num_overlap(a1.start_col, a1.end_col + padding, a2.start_col, a2.end_col, false)
 }
 
 fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
index d7bd5ed23c2b0af883ce9687447d15d233f63755..4c889dad8ca5050b0803be1a360b84bfda96fbb0 100644 (file)
@@ -90,7 +90,8 @@ fn push_trailing(buf: &mut String,
                          hi_opt: Option<&Loc>) {
             let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
             if let Some(line) = line_opt {
-                if line.len() > lo {
+                if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
+                    let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
                     buf.push_str(match hi_opt {
                         Some(hi) => &line[lo..hi],
                         None => &line[lo..],
index 03411e01a57980e4be577309158eaa431dff956e..2789250649674505d9568b537a7f2899f49d6df9 100644 (file)
@@ -192,7 +192,11 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 clean_work_products.insert(wp.clone());
             }
 
-            tcx.dep_graph.with_task(n, || ()); // create the node with no inputs
+            tcx.dep_graph.with_task(n, (), (), create_node);
+
+            fn create_node((): (), (): ()) {
+                // just create the node with no inputs
+            }
         }
     }
 
index 28ce9126019ebdebb86da7436e62674b52e30474..f9b7c68587678dea4a5f6a0edecbcfe8c5500583 100644 (file)
@@ -189,11 +189,38 @@ fn get_lints(&self) -> LintArray {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedUnsafe {
     fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
+        /// Return the NodeId for an enclosing scope that is also `unsafe`
+        fn is_enclosed(cx: &LateContext, id: ast::NodeId) -> Option<(String, ast::NodeId)> {
+            let parent_id = cx.tcx.hir.get_parent_node(id);
+            if parent_id != id {
+                if cx.tcx.used_unsafe.borrow().contains(&parent_id) {
+                    Some(("block".to_string(), parent_id))
+                } else if let Some(hir::map::NodeItem(&hir::Item {
+                    node: hir::ItemFn(_, hir::Unsafety::Unsafe, _, _, _, _),
+                    ..
+                })) = cx.tcx.hir.find(parent_id) {
+                    Some(("fn".to_string(), parent_id))
+                } else {
+                    is_enclosed(cx, parent_id)
+                }
+            } else {
+                None
+            }
+        }
         if let hir::ExprBlock(ref blk) = e.node {
             // Don't warn about generated blocks, that'll just pollute the output.
             if blk.rules == hir::UnsafeBlock(hir::UserProvided) &&
                !cx.tcx.used_unsafe.borrow().contains(&blk.id) {
-                cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block");
+
+                let mut db = cx.struct_span_lint(UNUSED_UNSAFE, blk.span,
+                                                 "unnecessary `unsafe` block");
+
+                db.span_label(blk.span, &"unnecessary `unsafe` block");
+                if let Some((kind, id)) = is_enclosed(cx, blk.id) {
+                    db.span_note(cx.tcx.hir.span(id),
+                                 &format!("because it's nested under this `unsafe` {}", kind));
+                }
+                db.emit();
             }
         }
     }
index de465ea92f6b81a3dbb2cc38bb718454e9c386d0..a6771083fc34eaf438313e920cbc78707a569ba2 100644 (file)
@@ -639,6 +639,34 @@ fn extract_one(&mut self,
                                                          lib.display()));
                 continue;
             }
+
+            // Ok so at this point we've determined that `(lib, kind)` above is
+            // a candidate crate to load, and that `slot` is either none (this
+            // is the first crate of its kind) or if some the previous path has
+            // the exact same hash (e.g. it's the exact same crate).
+            //
+            // In principle these two candidate crates are exactly the same so
+            // we can choose either of them to link. As a stupidly gross hack,
+            // however, we favor crate in the sysroot.
+            //
+            // You can find more info in rust-lang/rust#39518 and various linked
+            // issues, but the general gist is that during testing libstd the
+            // compilers has two candidates to choose from: one in the sysroot
+            // and one in the deps folder. These two crates are the exact same
+            // crate but if the compiler chooses the one in the deps folder
+            // it'll cause spurious errors on Windows.
+            //
+            // As a result, we favor the sysroot crate here. Note that the
+            // candidates are all canonicalized, so we canonicalize the sysroot
+            // as well.
+            if let Some((ref prev, _)) = ret {
+                let sysroot = self.sess.sysroot();
+                let sysroot = sysroot.canonicalize()
+                                     .unwrap_or(sysroot.to_path_buf());
+                if prev.starts_with(&sysroot) {
+                    continue
+                }
+            }
             *slot = Some((hash, metadata));
             ret = Some((lib, kind));
         }
index 69b95702009213432d1528cd281e09e85e3bc761..42d9ab4d2bf274dde9f1c82b789c70b325220f0c 100644 (file)
@@ -55,7 +55,7 @@ fn expr_as_temp(&mut self,
 (https://github.com/rust-lang/rust/issues/39283)");
         }
 
-        if temp_lifetime.is_some() {
+        if !expr_ty.is_never() && temp_lifetime.is_some() {
             this.cfg.push(block, Statement {
                 source_info: source_info,
                 kind: StatementKind::StorageLive(temp.clone())
diff --git a/src/librustc_mir/callgraph.rs b/src/librustc_mir/callgraph.rs
new file mode 100644 (file)
index 0000000..6941628
--- /dev/null
@@ -0,0 +1,252 @@
+// Copyright 2016 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.
+
+//! MIR-based callgraph.
+//!
+//! This only considers direct calls
+
+use rustc::hir::def_id::DefId;
+use rustc_data_structures::graph;
+
+use rustc::mir::*;
+use rustc::mir::visit::*;
+
+use rustc::ty;
+
+use rustc::util::nodemap::DefIdMap;
+
+pub struct CallGraph {
+    node_map: DefIdMap<graph::NodeIndex>,
+    graph: graph::Graph<DefId, ()>
+}
+
+impl CallGraph {
+    // FIXME: allow for construction of a callgraph that inspects
+    // cross-crate MIRs if available.
+    pub fn build<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> CallGraph {
+        let def_ids = tcx.maps.mir.borrow().keys();
+
+        let mut callgraph = CallGraph {
+            node_map: DefIdMap(),
+            graph: graph::Graph::new()
+        };
+
+        for def_id in def_ids {
+            if !def_id.is_local() { continue; }
+
+            let idx = callgraph.add_node(def_id);
+
+            let mut call_visitor = CallVisitor {
+                caller: idx,
+                graph: &mut callgraph
+            };
+
+            let mir = tcx.item_mir(def_id);
+            call_visitor.visit_mir(&mir);
+        }
+
+        callgraph
+    }
+
+    // Iterate over the strongly-connected components of the graph
+    pub fn scc_iter(&self) -> SCCIterator {
+        SCCIterator::new(&self.graph)
+    }
+
+    // Get the def_id for the given graph node
+    pub fn def_id(&self, node: graph::NodeIndex) -> DefId {
+        *self.graph.node_data(node)
+    }
+
+    fn add_node(&mut self, id: DefId) -> graph::NodeIndex {
+        let graph = &mut self.graph;
+        *self.node_map.entry(id).or_insert_with(|| {
+            graph.add_node(id)
+        })
+    }
+}
+
+struct CallVisitor<'a> {
+    caller: graph::NodeIndex,
+    graph: &'a mut CallGraph
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for CallVisitor<'a> {
+    fn visit_terminator_kind(&mut self, _block: BasicBlock,
+                             kind: &TerminatorKind<'tcx>, _loc: Location) {
+        if let TerminatorKind::Call {
+            func: Operand::Constant(ref f)
+            , .. } = *kind {
+            if let ty::TyFnDef(def_id, _, _) = f.ty.sty {
+                let callee = self.graph.add_node(def_id);
+                self.graph.graph.add_edge(self.caller, callee, ());
+            }
+        }
+    }
+}
+
+struct StackElement<'g> {
+    node: graph::NodeIndex,
+    lowlink: usize,
+    children: graph::AdjacentTargets<'g, DefId, ()>
+}
+
+/**
+ * Iterator over strongly-connected-components using Tarjan's algorithm[1]
+ *
+ * [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
+ */
+pub struct SCCIterator<'g> {
+    graph: &'g graph::Graph<DefId, ()>,
+    index: usize,
+    node_indices: Vec<Option<usize>>,
+    scc_stack: Vec<graph::NodeIndex>,
+    current_scc: Vec<graph::NodeIndex>,
+    visit_stack: Vec<StackElement<'g>>,
+}
+
+impl<'g> SCCIterator<'g> {
+    pub fn new(graph: &'g graph::Graph<DefId, ()>) -> SCCIterator<'g> {
+        if graph.len_nodes() == 0 {
+            return SCCIterator {
+                graph: graph,
+                index: 0,
+                node_indices: Vec::new(),
+                scc_stack: Vec::new(),
+                current_scc: Vec::new(),
+                visit_stack: Vec::new()
+            };
+        }
+
+        let first = graph::NodeIndex(0);
+
+        SCCIterator::with_entry(graph, first)
+    }
+
+    pub fn with_entry(graph: &'g graph::Graph<DefId, ()>,
+                      entry: graph::NodeIndex) -> SCCIterator<'g> {
+        let mut iter = SCCIterator {
+            graph: graph,
+            index: 0,
+            node_indices: Vec::with_capacity(graph.len_nodes()),
+            scc_stack: Vec::new(),
+            current_scc: Vec::new(),
+            visit_stack: Vec::new()
+        };
+
+        iter.visit_one(entry);
+
+        iter
+    }
+
+    fn get_next(&mut self) {
+        self.current_scc.clear();
+
+        while !self.visit_stack.is_empty() {
+            self.visit_children();
+
+            let node = self.visit_stack.pop().unwrap();
+
+            if let Some(last) = self.visit_stack.last_mut() {
+                if last.lowlink > node.lowlink {
+                    last.lowlink = node.lowlink;
+                }
+            }
+
+            debug!("TarjanSCC: Popped node {:?} : lowlink = {:?}; index = {:?}",
+                   node.node, node.lowlink, self.node_index(node.node).unwrap());
+
+            if node.lowlink != self.node_index(node.node).unwrap() {
+                continue;
+            }
+
+            loop {
+                let n = self.scc_stack.pop().unwrap();
+                self.current_scc.push(n);
+                self.set_node_index(n, !0);
+                if n == node.node { return; }
+            }
+        }
+    }
+
+    fn visit_one(&mut self, node: graph::NodeIndex) {
+        self.index += 1;
+        let idx =  self.index;
+        self.set_node_index(node, idx);
+        self.scc_stack.push(node);
+        self.visit_stack.push(StackElement {
+            node: node,
+            lowlink: self.index,
+            children: self.graph.successor_nodes(node)
+        });
+        debug!("TarjanSCC: Node {:?} : index = {:?}", node, idx);
+    }
+
+    fn visit_children(&mut self) {
+        while let Some(child) = self.visit_stack.last_mut().unwrap().children.next() {
+            if let Some(child_num) = self.node_index(child) {
+                let cur = self.visit_stack.last_mut().unwrap();
+                if cur.lowlink > child_num {
+                    cur.lowlink = child_num;
+                }
+            } else {
+                self.visit_one(child);
+            }
+        }
+    }
+
+    fn node_index(&self, node: graph::NodeIndex) -> Option<usize> {
+        self.node_indices.get(node.node_id()).and_then(|&idx| idx)
+    }
+
+    fn set_node_index(&mut self, node: graph::NodeIndex, idx: usize) {
+        let i = node.node_id();
+        if i >= self.node_indices.len() {
+            self.node_indices.resize(i + 1, None);
+        }
+        self.node_indices[i] = Some(idx);
+    }
+}
+
+impl<'g> Iterator for SCCIterator<'g> {
+    type Item = Vec<graph::NodeIndex>;
+
+    fn next(&mut self) -> Option<Vec<graph::NodeIndex>> {
+        self.get_next();
+
+        if self.current_scc.is_empty() {
+            // Try a new root for the next SCC, if the node_indices
+            // map is doesn't contain all nodes, use the smallest one
+            // with no entry, otherwise find the first empty node.
+            //
+            // FIXME: This should probably use a set of precomputed
+            // roots instead
+            if self.node_indices.len() < self.graph.len_nodes() {
+                let idx = graph::NodeIndex(self.node_indices.len());
+                self.visit_one(idx);
+            } else {
+                for idx in 0..self.node_indices.len() {
+                    if self.node_indices[idx].is_none() {
+                        let idx = graph::NodeIndex(idx);
+                        self.visit_one(idx);
+                        break;
+                    }
+                }
+            }
+            self.get_next();
+        }
+
+        if self.current_scc.is_empty() {
+            None
+        } else {
+            Some(self.current_scc.clone())
+        }
+    }
+}
index a97495a0ebcc43d09599dc6606455b2bc28477d4..f21f1881c832e17212dea3ee392641ce0d68589a 100644 (file)
@@ -46,6 +46,7 @@
 pub mod diagnostics;
 
 pub mod build;
+pub mod callgraph;
 pub mod def_use;
 pub mod graphviz;
 mod hair;
@@ -58,4 +59,4 @@
 pub fn provide(providers: &mut Providers) {
     mir_map::provide(providers);
     transform::qualify_consts::provide(providers);
-}
+}
\ No newline at end of file
index a41489ff89ff46a24d804ebb4f1fca59966f5d3d..58f23a5c81bd7fa1cc9f557bf0aab1a994b0cb40 100644 (file)
 use std::mem;
 
 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.dep_graph.with_task(DepNode::MirKrate, || {
+    tcx.dep_graph.with_task(DepNode::MirKrate, tcx, (), build_mir_for_crate_task);
+
+    fn build_mir_for_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) {
         tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
             tcx.item_mir(body_owner_def_id);
         });
-    });
+    }
 }
 
 pub fn provide(providers: &mut Providers) {
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
new file mode 100644 (file)
index 0000000..80a9c06
--- /dev/null
@@ -0,0 +1,836 @@
+// Copyright 2016 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.
+
+//! Inlining pass for MIR functions
+
+use rustc::hir::def_id::DefId;
+
+use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_data_structures::graph;
+
+use rustc::dep_graph::DepNode;
+use rustc::mir::*;
+use rustc::mir::transform::{MirMapPass, MirPassHook, MirSource, Pass};
+use rustc::mir::visit::*;
+use rustc::traits;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::{Subst,Substs};
+use rustc::util::nodemap::{DefIdSet};
+
+use super::simplify::{remove_dead_blocks, CfgSimplifier};
+
+use syntax::{attr};
+use syntax::abi::Abi;
+
+use callgraph;
+
+const DEFAULT_THRESHOLD: usize = 50;
+const HINT_THRESHOLD: usize = 100;
+
+const INSTR_COST: usize = 5;
+const CALL_PENALTY: usize = 25;
+
+const UNKNOWN_SIZE_COST: usize = 10;
+
+pub struct Inline;
+
+impl<'tcx> MirMapPass<'tcx> for Inline {
+    fn run_pass<'a>(
+        &mut self,
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        hooks: &mut [Box<for<'s> MirPassHook<'s>>]) {
+
+        if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; }
+
+        let _ignore = tcx.dep_graph.in_ignore();
+
+        let callgraph = callgraph::CallGraph::build(tcx);
+
+        let mut inliner = Inliner {
+            tcx: tcx,
+        };
+
+        let def_ids = tcx.maps.mir.borrow().keys();
+        for &def_id in &def_ids {
+            if !def_id.is_local() { continue; }
+
+            let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
+            let mut mir = if let Some(mir) = tcx.maps.mir.borrow().get(&def_id) {
+                mir.borrow_mut()
+            } else {
+                continue;
+            };
+
+            tcx.dep_graph.write(DepNode::Mir(def_id));
+
+            let id = tcx.hir.as_local_node_id(def_id).unwrap();
+            let src = MirSource::from_node(tcx, id);
+
+            for hook in &mut *hooks {
+                hook.on_mir_pass(tcx, src, &mut mir, self, false);
+            }
+        }
+
+        for scc in callgraph.scc_iter() {
+            inliner.inline_scc(&callgraph, &scc);
+        }
+
+        for def_id in def_ids {
+            if !def_id.is_local() { continue; }
+
+            let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
+            let mut mir = tcx.maps.mir.borrow()[&def_id].borrow_mut();
+            tcx.dep_graph.write(DepNode::Mir(def_id));
+
+            let id = tcx.hir.as_local_node_id(def_id).unwrap();
+            let src = MirSource::from_node(tcx, id);
+
+            for hook in &mut *hooks {
+                hook.on_mir_pass(tcx, src, &mut mir, self, true);
+            }
+        }
+    }
+}
+
+impl<'tcx> Pass for Inline { }
+
+struct Inliner<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+}
+
+#[derive(Copy, Clone)]
+struct CallSite<'tcx> {
+    caller: DefId,
+    callee: DefId,
+    substs: &'tcx Substs<'tcx>,
+    bb: BasicBlock,
+    location: SourceInfo,
+}
+
+impl<'a, 'tcx> Inliner<'a, 'tcx> {
+    fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeIndex]) -> bool {
+        let mut callsites = Vec::new();
+        let mut in_scc = DefIdSet();
+
+        let mut inlined_into = DefIdSet();
+
+        for &node in scc {
+            let def_id = callgraph.def_id(node);
+
+            // Don't inspect functions from other crates
+            let id = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
+                id
+            } else {
+                continue;
+            };
+            let src = MirSource::from_node(self.tcx, id);
+            if let MirSource::Fn(_) = src {
+                if let Some(mir) = self.tcx.maybe_item_mir(def_id) {
+                    for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
+                        // Don't inline calls that are in cleanup blocks.
+                        if bb_data.is_cleanup { continue; }
+
+                        // Only consider direct calls to functions
+                        let terminator = bb_data.terminator();
+                        if let TerminatorKind::Call {
+                            func: Operand::Constant(ref f), .. } = terminator.kind {
+                            if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty {
+                                callsites.push(CallSite {
+                                    caller: def_id,
+                                    callee: callee_def_id,
+                                    substs: substs,
+                                    bb: bb,
+                                    location: terminator.source_info
+                                });
+                            }
+                        }
+                    }
+
+                    in_scc.insert(def_id);
+                }
+            }
+        }
+
+        // Move callsites that are in the the SCC to the end so
+        // they're inlined after calls to outside the SCC
+        let mut first_call_in_scc = callsites.len();
+
+        let mut i = 0;
+        while i < first_call_in_scc {
+            let f = callsites[i].caller;
+            if in_scc.contains(&f) {
+                first_call_in_scc -= 1;
+                callsites.swap(i, first_call_in_scc);
+            } else {
+                i += 1;
+            }
+        }
+
+        let mut local_change;
+        let mut changed = false;
+
+        loop {
+            local_change = false;
+            let mut csi = 0;
+            while csi < callsites.len() {
+                let callsite = callsites[csi];
+                csi += 1;
+
+                let _task = self.tcx.dep_graph.in_task(DepNode::Mir(callsite.caller));
+                self.tcx.dep_graph.write(DepNode::Mir(callsite.caller));
+
+                let callee_mir = {
+                    if let Some(callee_mir) = self.tcx.maybe_item_mir(callsite.callee) {
+                        if !self.should_inline(callsite, &callee_mir) {
+                            continue;
+                        }
+
+                        callee_mir.subst(self.tcx, callsite.substs)
+                    } else {
+                        continue;
+                    }
+
+                };
+
+                let mut caller_mir = {
+                    let map = self.tcx.maps.mir.borrow();
+                    let mir = map.get(&callsite.caller).unwrap();
+                    mir.borrow_mut()
+                };
+
+                let start = caller_mir.basic_blocks().len();
+
+                if !self.inline_call(callsite, &mut caller_mir, callee_mir) {
+                    continue;
+                }
+
+                inlined_into.insert(callsite.caller);
+
+                // Add callsites from inlined function
+                for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated().skip(start) {
+                    // Only consider direct calls to functions
+                    let terminator = bb_data.terminator();
+                    if let TerminatorKind::Call {
+                        func: Operand::Constant(ref f), .. } = terminator.kind {
+                        if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty {
+                            // Don't inline the same function multiple times.
+                            if callsite.callee != callee_def_id {
+                                callsites.push(CallSite {
+                                    caller: callsite.caller,
+                                    callee: callee_def_id,
+                                    substs: substs,
+                                    bb: bb,
+                                    location: terminator.source_info
+                                });
+                            }
+                        }
+                    }
+                }
+
+                csi -= 1;
+                if scc.len() == 1 {
+                    callsites.swap_remove(csi);
+                } else {
+                    callsites.remove(csi);
+                }
+
+                local_change = true;
+                changed = true;
+            }
+
+            if !local_change {
+                break;
+            }
+        }
+
+        // Simplify functions we inlined into.
+        for def_id in inlined_into {
+            let _task = self.tcx.dep_graph.in_task(DepNode::Mir(def_id));
+            self.tcx.dep_graph.write(DepNode::Mir(def_id));
+
+            let mut caller_mir = {
+                let map = self.tcx.maps.mir.borrow();
+                let mir = map.get(&def_id).unwrap();
+                mir.borrow_mut()
+            };
+
+            debug!("Running simplify cfg on {:?}", def_id);
+            CfgSimplifier::new(&mut caller_mir).simplify();
+            remove_dead_blocks(&mut caller_mir);
+        }
+        changed
+    }
+
+    fn should_inline(&self, callsite: CallSite<'tcx>,
+                     callee_mir: &'a Mir<'tcx>) -> bool {
+
+        let tcx = self.tcx;
+
+        // Don't inline closures that have captures
+        // FIXME: Handle closures better
+        if callee_mir.upvar_decls.len() > 0 {
+            return false;
+        }
+
+
+        let attrs = tcx.get_attrs(callsite.callee);
+        let hint = attr::find_inline_attr(None, &attrs[..]);
+
+        let hinted = match hint {
+            // Just treat inline(always) as a hint for now,
+            // there are cases that prevent inlining that we
+            // need to check for first.
+            attr::InlineAttr::Always => true,
+            attr::InlineAttr::Never => return false,
+            attr::InlineAttr::Hint => true,
+            attr::InlineAttr::None => false,
+        };
+
+        // Only inline local functions if they would be eligible for cross-crate
+        // inlining. This is to ensure that the final crate doesn't have MIR that
+        // reference unexported symbols
+        if callsite.callee.is_local() {
+            if callsite.substs.types().count() == 0 && !hinted {
+                return false;
+            }
+        }
+
+        let mut threshold = if hinted {
+            HINT_THRESHOLD
+        } else {
+            DEFAULT_THRESHOLD
+        };
+
+        // Significantly lower the threshold for inlining cold functions
+        if attr::contains_name(&attrs[..], "cold") {
+            threshold /= 5;
+        }
+
+        // Give a bonus functions with a small number of blocks,
+        // We normally have two or three blocks for even
+        // very small functions.
+        if callee_mir.basic_blocks().len() <= 3 {
+            threshold += threshold / 4;
+        }
+
+        // FIXME: Give a bonus to functions with only a single caller
+
+        let id = tcx.hir.as_local_node_id(callsite.caller).expect("Caller not local");
+        let param_env = ty::ParameterEnvironment::for_item(tcx, id);
+
+        let mut first_block = true;
+        let mut cost = 0;
+
+        // Traverse the MIR manually so we can account for the effects of
+        // inlining on the CFG.
+        let mut work_list = vec![START_BLOCK];
+        let mut visited = BitVector::new(callee_mir.basic_blocks().len());
+        while let Some(bb) = work_list.pop() {
+            if !visited.insert(bb.index()) { continue; }
+            let blk = &callee_mir.basic_blocks()[bb];
+
+            for stmt in &blk.statements {
+                // Don't count StorageLive/StorageDead in the inlining cost.
+                match stmt.kind {
+                    StatementKind::StorageLive(_) |
+                    StatementKind::StorageDead(_) |
+                    StatementKind::Nop => {}
+                    _ => cost += INSTR_COST
+                }
+            }
+            let term = blk.terminator();
+            let mut is_drop = false;
+            match term.kind {
+                TerminatorKind::Drop { ref location, target, unwind } |
+                TerminatorKind::DropAndReplace { ref location, target, unwind, .. } => {
+                    is_drop = true;
+                    work_list.push(target);
+                    // If the location doesn't actually need dropping, treat it like
+                    // a regular goto.
+                    let ty = location.ty(&callee_mir, tcx).subst(tcx, callsite.substs);
+                    let ty = ty.to_ty(tcx);
+                    if tcx.type_needs_drop_given_env(ty, &param_env) {
+                        cost += CALL_PENALTY;
+                        if let Some(unwind) = unwind {
+                            work_list.push(unwind);
+                        }
+                    } else {
+                        cost += INSTR_COST;
+                    }
+                }
+
+                TerminatorKind::Unreachable |
+                TerminatorKind::Call { destination: None, .. } if first_block => {
+                    // If the function always diverges, don't inline
+                    // unless the cost is zero
+                    threshold = 0;
+                }
+
+                TerminatorKind::Call {func: Operand::Constant(ref f), .. } => {
+                    if let ty::TyFnDef(.., f) = f.ty.sty {
+                        // Don't give intrinsics the extra penalty for calls
+                        if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
+                            cost += INSTR_COST;
+                        } else {
+                            cost += CALL_PENALTY;
+                        }
+                    }
+                }
+                TerminatorKind::Assert { .. } => cost += CALL_PENALTY,
+                _ => cost += INSTR_COST
+            }
+
+            if !is_drop {
+                for &succ in &term.successors()[..] {
+                    work_list.push(succ);
+                }
+            }
+
+            first_block = false;
+        }
+
+        // Count up the cost of local variables and temps, if we know the size
+        // use that, otherwise we use a moderately-large dummy cost.
+
+        let ptr_size = tcx.data_layout.pointer_size.bytes();
+
+        for v in callee_mir.vars_and_temps_iter() {
+            let v = &callee_mir.local_decls[v];
+            let ty = v.ty.subst(tcx, callsite.substs);
+            // Cost of the var is the size in machine-words, if we know
+            // it.
+            if let Some(size) = type_size_of(tcx, param_env.clone(), ty) {
+                cost += (size / ptr_size) as usize;
+            } else {
+                cost += UNKNOWN_SIZE_COST;
+            }
+        }
+
+        debug!("Inline cost for {:?} is {}", callsite.callee, cost);
+
+        if let attr::InlineAttr::Always = hint {
+            true
+        } else {
+            cost <= threshold
+        }
+    }
+
+
+    fn inline_call(&self, callsite: CallSite<'tcx>,
+                             caller_mir: &mut Mir<'tcx>, mut callee_mir: Mir<'tcx>) -> bool {
+
+        // Don't inline a function into itself
+        if callsite.caller == callsite.callee { return false; }
+
+        let _task = self.tcx.dep_graph.in_task(DepNode::Mir(callsite.caller));
+
+
+        let terminator = caller_mir[callsite.bb].terminator.take().unwrap();
+        match terminator.kind {
+            // FIXME: Handle inlining of diverging calls
+            TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => {
+
+                debug!("Inlined {:?} into {:?}", callsite.callee, callsite.caller);
+
+                let is_box_free = Some(callsite.callee) == self.tcx.lang_items.box_free_fn();
+
+                let mut local_map = IndexVec::with_capacity(callee_mir.local_decls.len());
+                let mut scope_map = IndexVec::with_capacity(callee_mir.visibility_scopes.len());
+                let mut promoted_map = IndexVec::with_capacity(callee_mir.promoted.len());
+
+                for mut scope in callee_mir.visibility_scopes.iter().cloned() {
+                    if scope.parent_scope.is_none() {
+                        scope.parent_scope = Some(callsite.location.scope);
+                        scope.span = callee_mir.span;
+                    }
+
+                    scope.span = callsite.location.span;
+
+                    let idx = caller_mir.visibility_scopes.push(scope);
+                    scope_map.push(idx);
+                }
+
+                for loc in callee_mir.vars_and_temps_iter() {
+                    let mut local = callee_mir.local_decls[loc].clone();
+
+                    if let Some(ref mut source_info) = local.source_info {
+                        source_info.scope = scope_map[source_info.scope];
+
+                        source_info.span = callsite.location.span;
+                    }
+
+                    let idx = caller_mir.local_decls.push(local);
+                    local_map.push(idx);
+                }
+
+                for p in callee_mir.promoted.iter().cloned() {
+                    let idx = caller_mir.promoted.push(p);
+                    promoted_map.push(idx);
+                }
+
+                // If the call is something like `a[*i] = f(i)`, where
+                // `i : &mut usize`, then just duplicating the `a[*i]`
+                // Lvalue could result in two different locations if `f`
+                // writes to `i`. To prevent this we need to create a temporary
+                // borrow of the lvalue and pass the destination as `*temp` instead.
+                fn dest_needs_borrow(lval: &Lvalue) -> bool {
+                    match *lval {
+                        Lvalue::Projection(ref p) => {
+                            match p.elem {
+                                ProjectionElem::Deref |
+                                ProjectionElem::Index(_) => true,
+                                _ => dest_needs_borrow(&p.base)
+                            }
+                        }
+                        // Static variables need a borrow because the callee
+                        // might modify the same static.
+                        Lvalue::Static(_) => true,
+                        _ => false
+                    }
+                }
+
+                let dest = if dest_needs_borrow(&destination.0) {
+                    debug!("Creating temp for return destination");
+                    let dest = Rvalue::Ref(
+                        self.tcx.mk_region(ty::ReErased),
+                        BorrowKind::Mut,
+                        destination.0);
+
+                    let ty = dest.ty(caller_mir, self.tcx);
+
+                    let temp = LocalDecl::new_temp(ty);
+
+                    let tmp = caller_mir.local_decls.push(temp);
+                    let tmp = Lvalue::Local(tmp);
+
+                    let stmt = Statement {
+                        source_info: callsite.location,
+                        kind: StatementKind::Assign(tmp.clone(), dest)
+                    };
+                    caller_mir[callsite.bb]
+                        .statements.push(stmt);
+                    tmp.deref()
+                } else {
+                    destination.0
+                };
+
+                let return_block = destination.1;
+
+                let args : Vec<_> = if is_box_free {
+                    assert!(args.len() == 1);
+                    // box_free takes a Box, but is defined with a *mut T, inlining
+                    // needs to generate the cast.
+                    // FIXME: we should probably just generate correct MIR in the first place...
+
+                    let arg = if let Operand::Consume(ref lval) = args[0] {
+                        lval.clone()
+                    } else {
+                        bug!("Constant arg to \"box_free\"");
+                    };
+
+                    let ptr_ty = args[0].ty(caller_mir, self.tcx);
+                    vec![self.cast_box_free_arg(arg, ptr_ty, &callsite, caller_mir)]
+                } else {
+                    // Copy the arguments if needed.
+                    self.make_call_args(args, &callsite, caller_mir)
+                };
+
+                let bb_len = caller_mir.basic_blocks().len();
+                let mut integrator = Integrator {
+                    block_idx: bb_len,
+                    args: &args,
+                    local_map: local_map,
+                    scope_map: scope_map,
+                    promoted_map: promoted_map,
+                    _callsite: callsite,
+                    destination: dest,
+                    return_block: return_block,
+                    cleanup_block: cleanup,
+                    in_cleanup_block: false
+                };
+
+
+                for (bb, mut block) in callee_mir.basic_blocks_mut().drain_enumerated(..) {
+                    integrator.visit_basic_block_data(bb, &mut block);
+                    caller_mir.basic_blocks_mut().push(block);
+                }
+
+                let terminator = Terminator {
+                    source_info: callsite.location,
+                    kind: TerminatorKind::Goto { target: BasicBlock::new(bb_len) }
+                };
+
+                caller_mir[callsite.bb].terminator = Some(terminator);
+
+                true
+            }
+            kind => {
+                caller_mir[callsite.bb].terminator = Some(Terminator {
+                    source_info: terminator.source_info,
+                    kind: kind
+                });
+                false
+            }
+        }
+    }
+
+    fn cast_box_free_arg(&self, arg: Lvalue<'tcx>, ptr_ty: Ty<'tcx>,
+                         callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Operand<'tcx> {
+        let arg = Rvalue::Ref(
+            self.tcx.mk_region(ty::ReErased),
+            BorrowKind::Mut,
+            arg.deref());
+
+        let ty = arg.ty(caller_mir, self.tcx);
+        let ref_tmp = LocalDecl::new_temp(ty);
+        let ref_tmp = caller_mir.local_decls.push(ref_tmp);
+        let ref_tmp = Lvalue::Local(ref_tmp);
+
+        let ref_stmt = Statement {
+            source_info: callsite.location,
+            kind: StatementKind::Assign(ref_tmp.clone(), arg)
+        };
+
+        caller_mir[callsite.bb]
+            .statements.push(ref_stmt);
+
+        let pointee_ty = match ptr_ty.sty {
+            ty::TyRawPtr(tm) | ty::TyRef(_, tm) => tm.ty,
+            _ if ptr_ty.is_box() => ptr_ty.boxed_ty(),
+            _ => bug!("Invalid type `{:?}` for call to box_free", ptr_ty)
+        };
+        let ptr_ty = self.tcx.mk_mut_ptr(pointee_ty);
+
+        let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Consume(ref_tmp), ptr_ty);
+
+        let cast_tmp = LocalDecl::new_temp(ptr_ty);
+        let cast_tmp = caller_mir.local_decls.push(cast_tmp);
+        let cast_tmp = Lvalue::Local(cast_tmp);
+
+        let cast_stmt = Statement {
+            source_info: callsite.location,
+            kind: StatementKind::Assign(cast_tmp.clone(), raw_ptr)
+        };
+
+        caller_mir[callsite.bb]
+            .statements.push(cast_stmt);
+
+        Operand::Consume(cast_tmp)
+    }
+
+    fn make_call_args(&self, args: Vec<Operand<'tcx>>,
+                      callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Vec<Operand<'tcx>> {
+        let tcx = self.tcx;
+        // FIXME: Analysis of the usage of the arguments to avoid
+        // unnecessary temporaries.
+        args.into_iter().map(|a| {
+            if let Operand::Consume(Lvalue::Local(local)) = a {
+                if caller_mir.local_kind(local) == LocalKind::Temp {
+                    // Reuse the operand if it's a temporary already
+                    return a;
+                }
+            }
+
+            debug!("Creating temp for argument");
+            // Otherwise, create a temporary for the arg
+            let arg = Rvalue::Use(a);
+
+            let ty = arg.ty(caller_mir, tcx);
+
+            let arg_tmp = LocalDecl::new_temp(ty);
+            let arg_tmp = caller_mir.local_decls.push(arg_tmp);
+            let arg_tmp = Lvalue::Local(arg_tmp);
+
+            let stmt = Statement {
+                source_info: callsite.location,
+                kind: StatementKind::Assign(arg_tmp.clone(), arg)
+            };
+            caller_mir[callsite.bb].statements.push(stmt);
+            Operand::Consume(arg_tmp)
+        }).collect()
+    }
+}
+
+fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParameterEnvironment<'tcx>,
+                          ty: Ty<'tcx>) -> Option<u64> {
+    tcx.infer_ctxt(param_env, traits::Reveal::All).enter(|infcx| {
+        ty.layout(&infcx).ok().map(|layout| {
+            layout.size(&tcx.data_layout).bytes()
+        })
+    })
+}
+
+/**
+ * Integrator.
+ *
+ * Integrates blocks from the callee function into the calling function.
+ * Updates block indices, references to locals and other control flow
+ * stuff.
+ */
+struct Integrator<'a, 'tcx: 'a> {
+    block_idx: usize,
+    args: &'a [Operand<'tcx>],
+    local_map: IndexVec<Local, Local>,
+    scope_map: IndexVec<VisibilityScope, VisibilityScope>,
+    promoted_map: IndexVec<Promoted, Promoted>,
+    _callsite: CallSite<'tcx>,
+    destination: Lvalue<'tcx>,
+    return_block: BasicBlock,
+    cleanup_block: Option<BasicBlock>,
+    in_cleanup_block: bool,
+}
+
+impl<'a, 'tcx> Integrator<'a, 'tcx> {
+    fn update_target(&self, tgt: BasicBlock) -> BasicBlock {
+        let new = BasicBlock::new(tgt.index() + self.block_idx);
+        debug!("Updating target `{:?}`, new: `{:?}`", tgt, new);
+        new
+    }
+
+    fn update_local(&self, local: Local) -> Option<Local> {
+        let idx = local.index();
+        if idx < (self.args.len() + 1) {
+            return None;
+        }
+        let idx = idx - (self.args.len() + 1);
+        let local = Local::new(idx);
+        self.local_map.get(local).cloned()
+    }
+
+    fn arg_index(&self, arg: Local) -> Option<usize> {
+        let idx = arg.index();
+        if idx > 0 && idx <= self.args.len() {
+            Some(idx - 1)
+        } else {
+            None
+        }
+    }
+}
+
+impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
+    fn visit_lvalue(&mut self,
+                    lvalue: &mut Lvalue<'tcx>,
+                    _ctxt: LvalueContext<'tcx>,
+                    _location: Location) {
+        if let Lvalue::Local(ref mut local) = *lvalue {
+            if let Some(l) = self.update_local(*local) {
+                // Temp or Var; update the local reference
+                *local = l;
+                return;
+            }
+        }
+        if let Lvalue::Local(local) = *lvalue {
+            if local == RETURN_POINTER {
+                // Return pointer; update the lvalue itself
+                *lvalue = self.destination.clone();
+            } else if local.index() < (self.args.len() + 1) {
+                // Argument, once again update the the lvalue itself
+                let idx = local.index() - 1;
+                if let Operand::Consume(ref lval) = self.args[idx] {
+                    *lvalue = lval.clone();
+                } else {
+                    bug!("Arg operand `{:?}` is not an Lvalue use.", idx)
+                }
+            }
+        } else {
+            self.super_lvalue(lvalue, _ctxt, _location)
+        }
+    }
+
+    fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
+        if let Operand::Consume(Lvalue::Local(arg)) = *operand {
+            if let Some(idx) = self.arg_index(arg) {
+                let new_arg = self.args[idx].clone();
+                *operand = new_arg;
+                return;
+            }
+        }
+        self.super_operand(operand, location);
+    }
+
+    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
+        self.in_cleanup_block = data.is_cleanup;
+        self.super_basic_block_data(block, data);
+        self.in_cleanup_block = false;
+    }
+
+    fn visit_terminator_kind(&mut self, block: BasicBlock,
+                             kind: &mut TerminatorKind<'tcx>, loc: Location) {
+        self.super_terminator_kind(block, kind, loc);
+
+        match *kind {
+            TerminatorKind::Goto { ref mut target} => {
+                *target = self.update_target(*target);
+            }
+            TerminatorKind::SwitchInt { ref mut targets, .. } => {
+                for tgt in targets {
+                    *tgt = self.update_target(*tgt);
+                }
+            }
+            TerminatorKind::Drop { ref mut target, ref mut unwind, .. } |
+            TerminatorKind::DropAndReplace { ref mut target, ref mut unwind, .. } => {
+                *target = self.update_target(*target);
+                if let Some(tgt) = *unwind {
+                    *unwind = Some(self.update_target(tgt));
+                } else if !self.in_cleanup_block {
+                    // Unless this drop is in a cleanup block, add an unwind edge to
+                    // the orignal call's cleanup block
+                    *unwind = self.cleanup_block;
+                }
+            }
+            TerminatorKind::Call { ref mut destination, ref mut cleanup, .. } => {
+                if let Some((_, ref mut tgt)) = *destination {
+                    *tgt = self.update_target(*tgt);
+                }
+                if let Some(tgt) = *cleanup {
+                    *cleanup = Some(self.update_target(tgt));
+                } else if !self.in_cleanup_block {
+                    // Unless this call is in a cleanup block, add an unwind edge to
+                    // the orignal call's cleanup block
+                    *cleanup = self.cleanup_block;
+                }
+            }
+            TerminatorKind::Assert { ref mut target, ref mut cleanup, .. } => {
+                *target = self.update_target(*target);
+                if let Some(tgt) = *cleanup {
+                    *cleanup = Some(self.update_target(tgt));
+                } else if !self.in_cleanup_block {
+                    // Unless this assert is in a cleanup block, add an unwind edge to
+                    // the orignal call's cleanup block
+                    *cleanup = self.cleanup_block;
+                }
+            }
+            TerminatorKind::Return => {
+                *kind = TerminatorKind::Goto { target: self.return_block };
+            }
+            TerminatorKind::Resume => {
+                if let Some(tgt) = self.cleanup_block {
+                    *kind = TerminatorKind::Goto { target: tgt }
+                }
+            }
+            TerminatorKind::Unreachable => { }
+        }
+    }
+
+    fn visit_visibility_scope(&mut self, scope: &mut VisibilityScope) {
+        *scope = self.scope_map[*scope];
+    }
+
+    fn visit_literal(&mut self, literal: &mut Literal<'tcx>, loc: Location) {
+        if let Literal::Promoted { ref mut index } = *literal {
+            if let Some(p) = self.promoted_map.get(*index).cloned() {
+                *index = p;
+            }
+        } else {
+            self.super_literal(literal, loc);
+        }
+    }
+}
index ae255f70fb78892ac21ca8e0e813427692053639..cbd054a72499b9adbdf5c044b7aa48f08a77f3b5 100644 (file)
@@ -20,3 +20,4 @@
 pub mod deaggregator;
 pub mod instcombine;
 pub mod copy_prop;
+pub mod inline;
index e93a412dc744fcb6ddb4f8ef9a16d957ec4733b6..a762507f35e7ecccdaf994db4667df34048b5266 100644 (file)
@@ -79,7 +79,7 @@ pub struct CfgSimplifier<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
-    fn new(mir: &'a mut Mir<'tcx>) -> Self {
+    pub fn new(mir: &'a mut Mir<'tcx>) -> Self {
         let mut pred_count = IndexVec::from_elem(0u32, mir.basic_blocks());
 
         // we can't use mir.predecessors() here because that counts
@@ -102,7 +102,7 @@ fn new(mir: &'a mut Mir<'tcx>) -> Self {
         }
     }
 
-    fn simplify(mut self) {
+    pub fn simplify(mut self) {
         loop {
             let mut changed = false;
 
@@ -137,6 +137,8 @@ fn simplify(mut self) {
 
             if !changed { break }
         }
+
+        self.strip_nops()
     }
 
     // Collapse a goto chain starting from `start`
@@ -231,9 +233,19 @@ fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
         terminator.kind = TerminatorKind::Goto { target: first_succ };
         true
     }
+
+    fn strip_nops(&mut self) {
+        for blk in self.basic_blocks.iter_mut() {
+            blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind {
+                false
+            } else {
+                true
+            })
+        }
+    }
 }
 
-fn remove_dead_blocks(mir: &mut Mir) {
+pub fn remove_dead_blocks(mir: &mut Mir) {
     let mut seen = BitVector::new(mir.basic_blocks().len());
     for (bb, _) in traversal::preorder(mir) {
         seen.insert(bb.index());
index 3700d0295e9639dd50a7a08a85a3263a0d3c92f8..cdde56f5f634be75a2d0917a5a1885bf59606e2d 100644 (file)
@@ -13,8 +13,6 @@
 use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
 use rustc::session::Session;
 
-use rustc::mir::transform::MirMapPass;
-
 use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT};
 use syntax::ext::base::MacroExpanderFn;
 use syntax::symbol::Symbol;
@@ -53,9 +51,6 @@ pub struct Registry<'a> {
     #[doc(hidden)]
     pub late_lint_passes: Vec<LateLintPassObject>,
 
-    #[doc(hidden)]
-    pub mir_passes: Vec<Box<for<'pcx> MirMapPass<'pcx>>>,
-
     #[doc(hidden)]
     pub lint_groups: HashMap<&'static str, Vec<LintId>>,
 
@@ -81,7 +76,6 @@ pub fn new(sess: &'a Session, krate_span: Span) -> Registry<'a> {
             lint_groups: HashMap::new(),
             llvm_passes: vec![],
             attributes: vec![],
-            mir_passes: Vec::new(),
             whitelisted_custom_derives: Vec::new(),
         }
     }
@@ -157,11 +151,6 @@ pub fn register_lint_group(&mut self, name: &'static str, to: Vec<&'static Lint>
         self.lint_groups.insert(name, to.into_iter().map(|x| LintId::of(x)).collect());
     }
 
-    /// Register a MIR pass
-    pub fn register_mir_pass(&mut self, pass: Box<for<'pcx> MirMapPass<'pcx>>) {
-        self.mir_passes.push(pass);
-    }
-
     /// Register an LLVM pass.
     ///
     /// Registration with LLVM itself is handled through static C++ objects with
index 0a6281bf8c54ccaf4357f956fc97844fe136a41d..6caf81380e40dad51f8c33c1d90a51c7dd5f7065 100644 (file)
@@ -15,7 +15,7 @@
 
 use rustc::hir;
 use rustc::hir::def_id::{CrateNum, DefId};
-use syntax::ast::{self, NodeId};
+use syntax::ast::{self, Attribute, NodeId};
 use syntax_pos::Span;
 
 pub struct CrateData {
@@ -136,6 +136,7 @@ pub struct EnumData {
     pub visibility: Visibility,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 /// Data for extern crates.
@@ -171,6 +172,7 @@ pub struct FunctionData {
     pub parent: Option<DefId>,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 /// Data about a function call.
@@ -256,6 +258,7 @@ pub struct MethodData {
     pub visibility: Visibility,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 /// Data for modules.
@@ -271,6 +274,7 @@ pub struct ModData {
     pub visibility: Visibility,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 /// Data for a reference to a module.
@@ -295,6 +299,7 @@ pub struct StructData {
     pub visibility: Visibility,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -309,6 +314,7 @@ pub struct StructVariantData {
     pub parent: Option<DefId>,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -323,6 +329,7 @@ pub struct TraitData {
     pub visibility: Visibility,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -337,6 +344,7 @@ pub struct TupleVariantData {
     pub parent: Option<DefId>,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 /// Data for a typedef.
@@ -351,6 +359,7 @@ pub struct TypeDefData {
     pub parent: Option<DefId>,
     pub docs: String,
     pub sig: Option<Signature>,
+    pub attributes: Vec<Attribute>,
 }
 
 /// Data for a reference to a type or trait.
@@ -396,6 +405,7 @@ pub struct VariableData {
     pub visibility: Visibility,
     pub docs: String,
     pub sig: Option<Signature>,
+    pub attributes: Vec<Attribute>,
 }
 
 #[derive(Debug, RustcEncodable)]
index 3c275e0996dac0c3877c693f5bad6a7763cf0274..61956e5cd9d66e4abfd1e411e7b30d1a7ccfedf8 100644 (file)
@@ -327,6 +327,9 @@ fn process_def_kind(&mut self,
                     scope: scope
                 }.lower(self.tcx));
             }
+            // With macros 2.0, we can legitimately get a ref to a macro, but
+            // we don't handle it properly for now (FIXME).
+            Def::Macro(..) => {}
             Def::Local(..) |
             Def::Upvar(..) |
             Def::SelfTy(..) |
@@ -336,7 +339,6 @@ fn process_def_kind(&mut self,
             Def::AssociatedTy(..) |
             Def::AssociatedConst(..) |
             Def::PrimTy(_) |
-            Def::Macro(..) |
             Def::Err => {
                span_bug!(span,
                          "process_def_kind for unexpected item: {:?}",
@@ -373,6 +375,7 @@ fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) {
                         visibility: Visibility::Inherited,
                         docs: String::new(),
                         sig: None,
+                        attributes: vec![],
                     }.lower(self.tcx));
                 }
             }
@@ -448,6 +451,7 @@ fn process_method(&mut self,
                     visibility: vis,
                     docs: docs_for_attrs(attrs),
                     sig: method_data.sig,
+                    attributes: attrs.to_vec(),
                 }.lower(self.tcx));
             }
 
@@ -519,6 +523,7 @@ fn process_generic_params(&mut self,
                     parent: None,
                     docs: String::new(),
                     sig: None,
+                    attributes: vec![],
                 }.lower(self.tcx));
             }
         }
@@ -592,6 +597,7 @@ fn process_assoc_const(&mut self,
                 visibility: vis,
                 docs: docs_for_attrs(attrs),
                 sig: None,
+                attributes: attrs.to_vec(),
             }.lower(self.tcx));
         }
 
@@ -636,6 +642,7 @@ fn process_struct(&mut self,
                 visibility: From::from(&item.vis),
                 docs: docs_for_attrs(&item.attrs),
                 sig: self.save_ctxt.sig_base(item),
+                attributes: item.attrs.clone(),
             }.lower(self.tcx));
         }
 
@@ -701,6 +708,7 @@ fn process_enum(&mut self,
                             parent: Some(make_def_id(item.id, &self.tcx.hir)),
                             docs: docs_for_attrs(&variant.node.attrs),
                             sig: sig,
+                            attributes: variant.node.attrs.clone(),
                         }.lower(self.tcx));
                     }
                 }
@@ -727,6 +735,7 @@ fn process_enum(&mut self,
                             parent: Some(make_def_id(item.id, &self.tcx.hir)),
                             docs: docs_for_attrs(&variant.node.attrs),
                             sig: sig,
+                            attributes: variant.node.attrs.clone(),
                         }.lower(self.tcx));
                     }
                 }
@@ -798,6 +807,7 @@ fn process_trait(&mut self,
                 visibility: From::from(&item.vis),
                 docs: docs_for_attrs(&item.attrs),
                 sig: self.save_ctxt.sig_base(item),
+                attributes: item.attrs.clone(),
             }.lower(self.tcx));
         }
 
@@ -1064,6 +1074,7 @@ fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) {
                     visibility: Visibility::Inherited,
                     docs: String::new(),
                     sig: None,
+                    attributes: vec![],
                 }.lower(self.tcx));
             }
         }
@@ -1305,6 +1316,7 @@ fn visit_item(&mut self, item: &'l ast::Item) {
                         parent: None,
                         docs: docs_for_attrs(&item.attrs),
                         sig: Some(self.save_ctxt.sig_base(item)),
+                        attributes: item.attrs.clone(),
                     }.lower(self.tcx));
                 }
 
@@ -1527,6 +1539,7 @@ fn visit_arm(&mut self, arm: &'l ast::Arm) {
                             visibility: Visibility::Inherited,
                             docs: String::new(),
                             sig: None,
+                            attributes: vec![],
                         }.lower(self.tcx));
                     }
                 }
index fccb56e88b3de801a55eb08a7e77f6f175b072e2..41658dc5b1b48b043b9faf344768803a1db2b52b 100644 (file)
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex};
 use rustc::hir::map::Map;
 use rustc::ty::TyCtxt;
-use syntax::ast::NodeId;
+use syntax::ast::{self, NodeId};
 use syntax::codemap::CodeMap;
+use syntax::print::pprust;
+use syntax::symbol::Symbol;
 use syntax_pos::Span;
 
 use data::{self, Visibility, SigElement};
@@ -64,6 +66,39 @@ pub fn from_span(span: Span, cm: &CodeMap) -> SpanData {
     }
 }
 
+/// Represent an arbitrary attribute on a code element
+#[derive(Clone, Debug, RustcEncodable)]
+pub struct Attribute {
+    value: String,
+    span: SpanData,
+}
+
+impl Lower for Vec<ast::Attribute> {
+    type Target = Vec<Attribute>;
+
+    fn lower(self, tcx: TyCtxt) -> Vec<Attribute> {
+        let doc = Symbol::intern("doc");
+        self.into_iter()
+        // Only retain real attributes. Doc comments are lowered separately.
+        .filter(|attr| attr.name() != doc)
+        .map(|mut attr| {
+            // Remove the surrounding '#[..]' or '#![..]' of the pretty printed
+            // attribute. First normalize all inner attribute (#![..]) to outer
+            // ones (#[..]), then remove the two leading and the one trailing character.
+            attr.style = ast::AttrStyle::Outer;
+            let value = pprust::attribute_to_string(&attr);
+            // This str slicing works correctly, because the leading and trailing characters
+            // are in the ASCII range and thus exactly one byte each.
+            let value = value[2..value.len()-1].to_string();
+
+            Attribute {
+                value: value,
+                span: SpanData::from_span(attr.span, tcx.sess.codemap()),
+            }
+        }).collect()
+    }
+}
+
 #[derive(Debug, RustcEncodable)]
 pub struct CratePreludeData {
     pub crate_name: String,
@@ -98,6 +133,7 @@ pub struct EnumData {
     pub visibility: Visibility,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 impl Lower for data::EnumData {
@@ -115,6 +151,7 @@ fn lower(self, tcx: TyCtxt) -> EnumData {
             visibility: self.visibility,
             docs: self.docs,
             sig: self.sig.lower(tcx),
+            attributes: self.attributes.lower(tcx),
         }
     }
 }
@@ -179,6 +216,7 @@ pub struct FunctionData {
     pub parent: Option<DefId>,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 impl Lower for data::FunctionData {
@@ -197,6 +235,7 @@ fn lower(self, tcx: TyCtxt) -> FunctionData {
             parent: self.parent,
             docs: self.docs,
             sig: self.sig.lower(tcx),
+            attributes: self.attributes.lower(tcx),
         }
     }
 }
@@ -346,6 +385,7 @@ pub struct MethodData {
     pub parent: Option<DefId>,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 impl Lower for data::MethodData {
@@ -364,6 +404,7 @@ fn lower(self, tcx: TyCtxt) -> MethodData {
             parent: self.parent,
             docs: self.docs,
             sig: self.sig.lower(tcx),
+            attributes: self.attributes.lower(tcx),
         }
     }
 }
@@ -381,6 +422,7 @@ pub struct ModData {
     pub visibility: Visibility,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 impl Lower for data::ModData {
@@ -398,6 +440,7 @@ fn lower(self, tcx: TyCtxt) -> ModData {
             visibility: self.visibility,
             docs: self.docs,
             sig: self.sig.lower(tcx),
+            attributes: self.attributes.lower(tcx),
         }
     }
 }
@@ -437,6 +480,7 @@ pub struct StructData {
     pub visibility: Visibility,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 impl Lower for data::StructData {
@@ -455,6 +499,7 @@ fn lower(self, tcx: TyCtxt) -> StructData {
             visibility: self.visibility,
             docs: self.docs,
             sig: self.sig.lower(tcx),
+            attributes: self.attributes.lower(tcx),
         }
     }
 }
@@ -471,6 +516,7 @@ pub struct StructVariantData {
     pub parent: Option<DefId>,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 impl Lower for data::StructVariantData {
@@ -488,6 +534,7 @@ fn lower(self, tcx: TyCtxt) -> StructVariantData {
             parent: self.parent,
             docs: self.docs,
             sig: self.sig.lower(tcx),
+            attributes: self.attributes.lower(tcx),
         }
     }
 }
@@ -504,6 +551,7 @@ pub struct TraitData {
     pub visibility: Visibility,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 impl Lower for data::TraitData {
@@ -521,6 +569,7 @@ fn lower(self, tcx: TyCtxt) -> TraitData {
             visibility: self.visibility,
             docs: self.docs,
             sig: self.sig.lower(tcx),
+            attributes: self.attributes.lower(tcx),
         }
     }
 }
@@ -537,6 +586,7 @@ pub struct TupleVariantData {
     pub parent: Option<DefId>,
     pub docs: String,
     pub sig: Signature,
+    pub attributes: Vec<Attribute>,
 }
 
 impl Lower for data::TupleVariantData {
@@ -554,6 +604,7 @@ fn lower(self, tcx: TyCtxt) -> TupleVariantData {
             parent: self.parent,
             docs: self.docs,
             sig: self.sig.lower(tcx),
+            attributes: self.attributes.lower(tcx),
         }
     }
 }
@@ -570,6 +621,7 @@ pub struct TypeDefData {
     pub parent: Option<DefId>,
     pub docs: String,
     pub sig: Option<Signature>,
+    pub attributes: Vec<Attribute>,
 }
 
 impl Lower for data::TypeDefData {
@@ -586,6 +638,7 @@ fn lower(self, tcx: TyCtxt) -> TypeDefData {
             parent: self.parent,
             docs: self.docs,
             sig: self.sig.map(|s| s.lower(tcx)),
+            attributes: self.attributes.lower(tcx),
         }
     }
 }
@@ -675,6 +728,7 @@ pub struct VariableData {
     pub visibility: Visibility,
     pub docs: String,
     pub sig: Option<Signature>,
+    pub attributes: Vec<Attribute>,
 }
 
 impl Lower for data::VariableData {
@@ -694,6 +748,7 @@ fn lower(self, tcx: TyCtxt) -> VariableData {
             visibility: self.visibility,
             docs: self.docs,
             sig: self.sig.map(|s| s.lower(tcx)),
+            attributes: self.attributes.lower(tcx),
         }
     }
 }
index 09752994290c9c3490ec0ec4f1a4397c98740992..1b72489f83c67da2d611710b757001966994c3f5 100644 (file)
@@ -87,6 +87,7 @@ fn mod_data(&mut self, data: ModData) {
             decl_id: None,
             docs: data.docs,
             sig: Some(From::from(data.sig)),
+            attributes: data.attributes,
         };
         if def.span.file_name != def.value {
             // If the module is an out-of-line defintion, then we'll make the
@@ -232,6 +233,7 @@ struct Def {
     decl_id: Option<Id>,
     docs: String,
     sig: Option<JsonSignature>,
+    attributes: Vec<Attribute>,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -274,6 +276,7 @@ fn from(data: EnumData) -> Def {
             decl_id: None,
             docs: data.docs,
             sig: Some(From::from(data.sig)),
+            attributes: data.attributes,
         }
     }
 }
@@ -291,6 +294,7 @@ fn from(data: TupleVariantData) -> Def {
             decl_id: None,
             docs: data.docs,
             sig: Some(From::from(data.sig)),
+            attributes: data.attributes,
         }
     }
 }
@@ -307,6 +311,7 @@ fn from(data: StructVariantData) -> Def {
             decl_id: None,
             docs: data.docs,
             sig: Some(From::from(data.sig)),
+            attributes: data.attributes,
         }
     }
 }
@@ -323,6 +328,7 @@ fn from(data: StructData) -> Def {
             decl_id: None,
             docs: data.docs,
             sig: Some(From::from(data.sig)),
+            attributes: data.attributes,
         }
     }
 }
@@ -339,6 +345,7 @@ fn from(data: TraitData) -> Def {
             decl_id: None,
             docs: data.docs,
             sig: Some(From::from(data.sig)),
+            attributes: data.attributes,
         }
     }
 }
@@ -355,6 +362,7 @@ fn from(data: FunctionData) -> Def {
             decl_id: None,
             docs: data.docs,
             sig: Some(From::from(data.sig)),
+            attributes: data.attributes,
         }
     }
 }
@@ -371,6 +379,7 @@ fn from(data: MethodData) -> Def {
             decl_id: data.decl_id.map(|id| From::from(id)),
             docs: data.docs,
             sig: Some(From::from(data.sig)),
+            attributes: data.attributes,
         }
     }
 }
@@ -387,6 +396,7 @@ fn from(data: MacroData) -> Def {
             decl_id: None,
             docs: data.docs,
             sig: None,
+            attributes: vec![],
         }
     }
 }
@@ -403,6 +413,7 @@ fn from(data: TypeDefData) -> Def {
             decl_id: None,
             docs: String::new(),
             sig: data.sig.map(|s| From::from(s)),
+            attributes: data.attributes,
         }
     }
 }
@@ -424,6 +435,7 @@ fn from(data: VariableData) -> Def {
             decl_id: None,
             docs: data.docs,
             sig: None,
+            attributes: data.attributes,
         }
     }
 }
index b1e435dcc751c40b1bdff58ed027eb1f212f1a84..111c8370be2b1ca2582c113537cf006cd8cc6c59 100644 (file)
@@ -136,6 +136,7 @@ pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> {
                     parent: None,
                     docs: docs_for_attrs(&item.attrs),
                     sig: self.sig_base(item),
+                    attributes: item.attrs.clone(),
                 }))
             }
             ast::ItemKind::Static(ref typ, mt, ref expr) => {
@@ -164,6 +165,7 @@ pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> {
                     visibility: From::from(&item.vis),
                     docs: docs_for_attrs(&item.attrs),
                     sig: Some(self.sig_base(item)),
+                    attributes: item.attrs.clone(),
                 }))
             }
             ast::ItemKind::Const(ref typ, ref expr) => {
@@ -183,6 +185,7 @@ pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> {
                     visibility: From::from(&item.vis),
                     docs: docs_for_attrs(&item.attrs),
                     sig: Some(self.sig_base(item)),
+                    attributes: item.attrs.clone(),
                 }))
             }
             ast::ItemKind::Mod(ref m) => {
@@ -205,6 +208,7 @@ pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> {
                     visibility: From::from(&item.vis),
                     docs: docs_for_attrs(&item.attrs),
                     sig: self.sig_base(item),
+                    attributes: item.attrs.clone(),
                 }))
             }
             ast::ItemKind::Enum(ref def, _) => {
@@ -228,6 +232,7 @@ pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> {
                     visibility: From::from(&item.vis),
                     docs: docs_for_attrs(&item.attrs),
                     sig: self.sig_base(item),
+                    attributes: item.attrs.clone(),
                 }))
             }
             ast::ItemKind::Impl(.., ref trait_ref, ref typ, _) => {
@@ -315,6 +320,7 @@ pub fn get_field_data(&self,
                 visibility: From::from(&field.vis),
                 docs: docs_for_attrs(&field.attrs),
                 sig: Some(sig),
+                attributes: field.attrs.clone(),
             })
         } else {
             None
@@ -327,7 +333,7 @@ pub fn get_method_data(&self, id: ast::NodeId,
                            name: ast::Name, span: Span) -> Option<FunctionData> {
         // 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 (qualname, parent_scope, decl_id, vis, docs) =
+        let (qualname, parent_scope, decl_id, vis, docs, attributes) =
           match self.tcx.impl_of_method(self.tcx.hir.local_def_id(id)) {
             Some(impl_id) => match self.tcx.hir.get_if_local(impl_id) {
                 Some(Node::NodeItem(item)) => {
@@ -349,7 +355,8 @@ pub fn get_method_data(&self, id: ast::NodeId,
 
                             (result, trait_id, decl_id,
                              From::from(&item.vis),
-                             docs_for_attrs(&item.attrs))
+                             docs_for_attrs(&item.attrs),
+                             item.attrs.to_vec())
                         }
                         _ => {
                             span_bug!(span,
@@ -374,7 +381,8 @@ pub fn get_method_data(&self, id: ast::NodeId,
                             (format!("::{}", self.tcx.item_path_str(def_id)),
                              Some(def_id), None,
                              From::from(&item.vis),
-                             docs_for_attrs(&item.attrs))
+                             docs_for_attrs(&item.attrs),
+                             item.attrs.to_vec())
                         }
                         r => {
                             span_bug!(span,
@@ -387,7 +395,10 @@ pub fn get_method_data(&self, id: ast::NodeId,
                     }
                 }
                 None => {
-                    span_bug!(span, "Could not find container for method {}", id);
+                    debug!("Could not find container for method {} at {:?}", id, span);
+                    // This is not necessarily a bug, if there was a compilation error, the tables
+                    // we need might not exist.
+                    return None;
                 }
             },
         };
@@ -423,6 +434,7 @@ pub fn get_method_data(&self, id: ast::NodeId,
             parent: parent_scope,
             docs: docs,
             sig: sig,
+            attributes: attributes,
         })
     }
 
index b58f96033bf5b5dc2404c31657ac89dda25ea00e..a1703b1c155eb0535410d5002c3221c070721b40 100644 (file)
@@ -752,8 +752,54 @@ fn link_natively(sess: &Session,
     sess.abort_if_errors();
 
     // Invoke the system linker
+    //
+    // Note that there's a terribly awful hack that really shouldn't be present
+    // in any compiler. Here an environment variable is supported to
+    // automatically retry the linker invocation if the linker looks like it
+    // segfaulted.
+    //
+    // Gee that seems odd, normally segfaults are things we want to know about!
+    // Unfortunately though in rust-lang/rust#38878 we're experiencing the
+    // linker segfaulting on Travis quite a bit which is causing quite a bit of
+    // pain to land PRs when they spuriously fail due to a segfault.
+    //
+    // The issue #38878 has some more debugging information on it as well, but
+    // this unfortunately looks like it's just a race condition in OSX's linker
+    // with some thread pool working in the background. It seems that no one
+    // currently knows a fix for this so in the meantime we're left with this...
     info!("{:?}", &cmd);
-    let prog = time(sess.time_passes(), "running linker", || cmd.output());
+    let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok();
+    let mut prog;
+    let mut i = 0;
+    loop {
+        i += 1;
+        prog = time(sess.time_passes(), "running linker", || cmd.output());
+        if !retry_on_segfault || i > 3 {
+            break
+        }
+        let output = match prog {
+            Ok(ref output) => output,
+            Err(_) => break,
+        };
+        if output.status.success() {
+            break
+        }
+        let mut out = output.stderr.clone();
+        out.extend(&output.stdout);
+        let out = String::from_utf8_lossy(&out);
+        let msg = "clang: error: unable to execute command: \
+                   Segmentation fault: 11";
+        if !out.contains(msg) {
+            break
+        }
+
+        sess.struct_warn("looks like the linker segfaulted when we tried to \
+                          call it, automatically retrying again")
+            .note(&format!("{:?}", cmd))
+            .note(&out)
+            .emit();
+    }
+
     match prog {
         Ok(prog) => {
             fn escape_string(s: &[u8]) -> String {
index 36f6fa764390929a6647ca0880e217e817d8c302..1b43491e73c8f420e6efafcb5c308e46483ad2fa 100644 (file)
@@ -41,7 +41,7 @@
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::adjustment::CustomCoerceUnsized;
-use rustc::dep_graph::{DepNode, WorkProduct};
+use rustc::dep_graph::{AssertDepGraphSafe, DepNode, WorkProduct};
 use rustc::hir::map as hir_map;
 use rustc::util::common::time;
 use session::config::{self, NoDebugInfo};
@@ -1211,21 +1211,40 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     // Instantiate translation items without filling out definitions yet...
     for ccx in crate_context_list.iter_need_trans() {
-        let cgu = ccx.codegen_unit();
-        let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map);
-
-        tcx.dep_graph.with_task(cgu.work_product_dep_node(), || {
+        let dep_node = ccx.codegen_unit().work_product_dep_node();
+        tcx.dep_graph.with_task(dep_node,
+                                ccx,
+                                AssertDepGraphSafe(symbol_map.clone()),
+                                trans_decl_task);
+
+        fn trans_decl_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>,
+                                     symbol_map: AssertDepGraphSafe<Rc<SymbolMap<'tcx>>>) {
+            // FIXME(#40304): Instead of this, the symbol-map should be an
+            // on-demand thing that we compute.
+            let AssertDepGraphSafe(symbol_map) = symbol_map;
+            let cgu = ccx.codegen_unit();
+            let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map);
             for (trans_item, linkage) in trans_items {
                 trans_item.predefine(&ccx, linkage);
             }
-        });
+        }
     }
 
     // ... and now that we have everything pre-defined, fill out those definitions.
     for ccx in crate_context_list.iter_need_trans() {
-        let cgu = ccx.codegen_unit();
-        let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map);
-        tcx.dep_graph.with_task(cgu.work_product_dep_node(), || {
+        let dep_node = ccx.codegen_unit().work_product_dep_node();
+        tcx.dep_graph.with_task(dep_node,
+                                ccx,
+                                AssertDepGraphSafe(symbol_map.clone()),
+                                trans_def_task);
+
+        fn trans_def_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>,
+                                    symbol_map: AssertDepGraphSafe<Rc<SymbolMap<'tcx>>>) {
+            // FIXME(#40304): Instead of this, the symbol-map should be an
+            // on-demand thing that we compute.
+            let AssertDepGraphSafe(symbol_map) = symbol_map;
+            let cgu = ccx.codegen_unit();
+            let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map);
             for (trans_item, _) in trans_items {
                 trans_item.define(&ccx);
             }
@@ -1247,7 +1266,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             if ccx.sess().opts.debuginfo != NoDebugInfo {
                 debuginfo::finalize(&ccx);
             }
-        });
+        }
     }
 
     symbol_names_test::report_symbol_names(&shared_ccx);
index d5f7549ece07b21134587e71f1c9fd10a55084be..52851ea995d4b7c42edd769695931a5fc707a064 100644 (file)
@@ -10,7 +10,8 @@
 
 use llvm;
 use llvm::{ContextRef, ModuleRef, ValueRef};
-use rustc::dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig, WorkProduct};
+use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap,
+                       DepTrackingMapConfig, WorkProduct};
 use middle::cstore::LinkMeta;
 use rustc::hir;
 use rustc::hir::def::ExportMap;
@@ -274,6 +275,9 @@ pub struct CrateContext<'a, 'tcx: 'a> {
     index: usize,
 }
 
+impl<'a, 'tcx> DepGraphSafe for CrateContext<'a, 'tcx> {
+}
+
 pub struct CrateContextIterator<'a, 'tcx: 'a> {
     shared: &'a SharedCrateContext<'a, 'tcx>,
     local_ccxs: &'a [LocalCrateContext<'tcx>],
index ca0ab8f1e8c7742b4310816e7a1a6efdc6125430..1aab4853a4f641f6efd096c191365258b75d46c9 100644 (file)
@@ -12,6 +12,7 @@
 
 use super::FnCtxt;
 
+use rustc::infer::InferOk;
 use rustc::traits;
 use rustc::ty::{self, Ty, TraitRef};
 use rustc::ty::{ToPredicate, TypeFoldable};
@@ -149,6 +150,14 @@ pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
 
     pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I)
         where I: IntoIterator<Item = &'b hir::Expr>
+    {
+        let fcx = self.fcx;
+        fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, exprs));
+    }
+
+    pub fn finalize_as_infer_ok<'b, I>(self, pref: LvaluePreference, exprs: I)
+                                       -> InferOk<'tcx, ()>
+        where I: IntoIterator<Item = &'b hir::Expr>
     {
         let methods: Vec<_> = self.steps
             .iter()
@@ -176,8 +185,9 @@ pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I)
             }
         }
 
-        for obligation in self.obligations {
-            self.fcx.register_predicate(obligation);
+        InferOk {
+            value: (),
+            obligations: self.obligations
         }
     }
 }
index 53759cc115d1cb69039a9473cdb2fc04c5b1446b..c43291557f7fa4034959ac0f2fb1eb06a89c03ac 100644 (file)
@@ -64,7 +64,8 @@
 
 use rustc::hir;
 use rustc::hir::def_id::DefId;
-use rustc::infer::{Coercion, InferOk, TypeTrace};
+use rustc::infer::{Coercion, InferResult, InferOk, TypeTrace};
+use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
 use rustc::ty::{self, LvaluePreference, TypeAndMut,
@@ -75,9 +76,7 @@
 use rustc::ty::subst::Subst;
 use syntax::abi;
 use syntax::feature_gate;
-use util::common::indent;
 
-use std::cell::RefCell;
 use std::collections::VecDeque;
 use std::ops::Deref;
 
@@ -85,7 +84,6 @@ struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
     cause: ObligationCause<'tcx>,
     use_lub: bool,
-    unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
 }
 
 impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> {
@@ -95,7 +93,7 @@ fn deref(&self) -> &Self::Target {
     }
 }
 
-type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, Adjust<'tcx>)>;
+type CoerceResult<'tcx> = InferResult<'tcx, Adjustment<'tcx>>;
 
 fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
                        to_mutbl: hir::Mutability)
@@ -108,44 +106,53 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
     }
 }
 
+fn identity<'tcx>() -> Adjust<'tcx> {
+    Adjust::DerefRef {
+        autoderefs: 0,
+        autoref: None,
+        unsize: false,
+    }
+}
+
+fn success<'tcx>(kind: Adjust<'tcx>,
+                 target: Ty<'tcx>,
+                 obligations: traits::PredicateObligations<'tcx>)
+                 -> CoerceResult<'tcx> {
+    Ok(InferOk {
+        value: Adjustment {
+            kind,
+            target
+        },
+        obligations
+    })
+}
+
 impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
     fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self {
         Coerce {
             fcx: fcx,
             cause: cause,
             use_lub: false,
-            unsizing_obligations: RefCell::new(vec![]),
         }
     }
 
-    fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+    fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
         self.commit_if_ok(|_| {
             let trace = TypeTrace::types(&self.cause, false, a, b);
             if self.use_lub {
                 self.lub(false, trace, &a, &b)
-                    .map(|ok| self.register_infer_ok_obligations(ok))
             } else {
                 self.sub(false, trace, &a, &b)
-                    .map(|InferOk { value, obligations }| {
-                        self.fcx.register_predicates(obligations);
-                        value
-                    })
             }
         })
     }
 
-    /// Unify two types (using sub or lub) and produce a noop coercion.
-    fn unify_and_identity(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
-        self.unify(&a, &b).and_then(|ty| self.identity(ty))
-    }
-
-    /// Synthesize an identity adjustment.
-    fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> {
-        Ok((ty, Adjust::DerefRef {
-            autoderefs: 0,
-            autoref: None,
-            unsize: false,
-        }))
+    /// Unify two types (using sub or lub) and produce a specific coercion.
+    fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, kind: Adjust<'tcx>)
+                 -> CoerceResult<'tcx> {
+        self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| {
+            success(kind, ty, obligations)
+        })
     }
 
     fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx>
@@ -158,11 +165,11 @@ fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<
 
         // Just ignore error types.
         if a.references_error() || b.references_error() {
-            return self.identity(b);
+            return success(identity(), b, vec![]);
         }
 
         if a.is_never() {
-            return Ok((b, Adjust::NeverToAny));
+            return success(Adjust::NeverToAny, b, vec![]);
         }
 
         // Consider coercing the subtype to a DST
@@ -208,7 +215,7 @@ fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<
             }
             _ => {
                 // Otherwise, just use unification rules.
-                self.unify_and_identity(a, b)
+                self.unify_and(a, b, identity())
             }
         }
     }
@@ -240,7 +247,7 @@ fn coerce_borrowed_pointer<'a, E, I>(&self,
                 coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
                 (r_a, mt_a)
             }
-            _ => return self.unify_and_identity(a, b),
+            _ => return self.unify_and(a, b, identity()),
         };
 
         let span = self.cause.span;
@@ -248,7 +255,7 @@ fn coerce_borrowed_pointer<'a, E, I>(&self,
         let mut first_error = None;
         let mut r_borrow_var = None;
         let mut autoderef = self.autoderef(span, a);
-        let mut success = None;
+        let mut found = None;
 
         for (referent_ty, autoderefs) in autoderef.by_ref() {
             if autoderefs == 0 {
@@ -346,8 +353,8 @@ fn coerce_borrowed_pointer<'a, E, I>(&self,
                                                   mutbl: mt_b.mutbl, // [1] above
                                               });
             match self.unify(derefd_ty_a, b) {
-                Ok(ty) => {
-                    success = Some((ty, autoderefs));
+                Ok(ok) => {
+                    found = Some((ok, autoderefs));
                     break;
                 }
                 Err(err) => {
@@ -363,7 +370,7 @@ fn coerce_borrowed_pointer<'a, E, I>(&self,
         // (e.g., in example above, the failure from relating `Vec<T>`
         // to the target type), since that should be the least
         // confusing.
-        let (ty, autoderefs) = match success {
+        let (InferOk { value: ty, mut obligations }, autoderefs) = match found {
             Some(d) => d,
             None => {
                 let err = first_error.expect("coerce_borrowed_pointer had no error");
@@ -372,12 +379,6 @@ fn coerce_borrowed_pointer<'a, E, I>(&self,
             }
         };
 
-        // This commits the obligations to the fulfillcx. After this succeeds,
-        // this snapshot can't be rolled back.
-        autoderef.finalize(LvaluePreference::from_mutbl(mt_b.mutbl), exprs());
-
-        // Now apply the autoref. We have to extract the region out of
-        // the final ref type we got.
         if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 {
             // As a special case, if we would produce `&'a *x`, that's
             // a total no-op. We end up with the type `&'a T` just as
@@ -391,8 +392,11 @@ fn coerce_borrowed_pointer<'a, E, I>(&self,
             // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
             // which is a borrow.
             assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U
-            return self.identity(ty);
+            return success(identity(), ty, obligations);
         }
+
+        // Now apply the autoref. We have to extract the region out of
+        // the final ref type we got.
         let r_borrow = match ty.sty {
             ty::TyRef(r_borrow, _) => r_borrow,
             _ => span_bug!(span, "expected a ref type, got {:?}", ty),
@@ -402,11 +406,15 @@ fn coerce_borrowed_pointer<'a, E, I>(&self,
                ty,
                autoderefs,
                autoref);
-        Ok((ty, Adjust::DerefRef {
+
+        let pref = LvaluePreference::from_mutbl(mt_b.mutbl);
+        obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs()).obligations);
+
+        success(Adjust::DerefRef {
             autoderefs: autoderefs,
             autoref: autoref,
             unsize: false,
-        }))
+        }, ty, obligations)
     }
 
 
@@ -445,18 +453,32 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
             }
             _ => (source, None),
         };
-        let source = source.adjust_for_autoref(self.tcx, reborrow);
+        let coerce_source = source.adjust_for_autoref(self.tcx, reborrow);
+
+        let adjust = Adjust::DerefRef {
+            autoderefs: if reborrow.is_some() { 1 } else { 0 },
+            autoref: reborrow,
+            unsize: true,
+        };
+
+        // Setup either a subtyping or a LUB relationship between
+        // the `CoerceUnsized` target type and the expected type.
+        // We only have the latter, so we use an inference variable
+        // for the former and let type inference do the rest.
+        let origin = TypeVariableOrigin::MiscVariable(self.cause.span);
+        let coerce_target = self.next_ty_var(origin);
+        let mut coercion = self.unify_and(coerce_target, target, adjust)?;
 
         let mut selcx = traits::SelectionContext::new(self);
 
         // Use a FIFO queue for this custom fulfillment procedure.
         let mut queue = VecDeque::new();
-        let mut leftover_predicates = vec![];
 
         // Create an obligation for `Source: CoerceUnsized<Target>`.
         let cause = ObligationCause::misc(self.cause.span, self.body_id);
         queue.push_back(self.tcx
-            .predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target]));
+            .predicate_for_trait_def(cause, coerce_unsized_did, 0,
+                                     coerce_source, &[coerce_target]));
 
         // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
         // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@@ -467,7 +489,7 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
             let trait_ref = match obligation.predicate {
                 ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(),
                 _ => {
-                    leftover_predicates.push(obligation);
+                    coercion.obligations.push(obligation);
                     continue;
                 }
             };
@@ -495,33 +517,26 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
             }
         }
 
-        *self.unsizing_obligations.borrow_mut() = leftover_predicates;
-
-        let adjustment = Adjust::DerefRef {
-            autoderefs: if reborrow.is_some() { 1 } else { 0 },
-            autoref: reborrow,
-            unsize: true,
-        };
-        debug!("Success, coerced with {:?}", adjustment);
-        Ok((target, adjustment))
+        Ok(coercion)
     }
 
     fn coerce_from_safe_fn(&self,
                            a: Ty<'tcx>,
                            fn_ty_a: ty::PolyFnSig<'tcx>,
-                           b: Ty<'tcx>)
+                           b: Ty<'tcx>,
+                           to_unsafe: Adjust<'tcx>,
+                           normal: Adjust<'tcx>)
                            -> CoerceResult<'tcx> {
         if let ty::TyFnPtr(fn_ty_b) = b.sty {
             match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) {
                 (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
                     let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
-                    return self.unify_and_identity(unsafe_a, b)
-                        .map(|(ty, _)| (ty, Adjust::UnsafeFnPointer));
+                    return self.unify_and(unsafe_a, b, to_unsafe);
                 }
                 _ => {}
             }
         }
-        self.unify_and_identity(a, b)
+        self.unify_and(a, b, normal)
     }
 
     fn coerce_from_fn_pointer(&self,
@@ -536,7 +551,8 @@ fn coerce_from_fn_pointer(&self,
         let b = self.shallow_resolve(b);
         debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
 
-        self.coerce_from_safe_fn(a, fn_ty_a, b)
+        self.coerce_from_safe_fn(a, fn_ty_a, b,
+            Adjust::UnsafeFnPointer, identity())
     }
 
     fn coerce_from_fn_item(&self,
@@ -554,10 +570,10 @@ fn coerce_from_fn_item(&self,
         match b.sty {
             ty::TyFnPtr(_) => {
                 let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a);
-                self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b)
-                    .map(|(ty, _)| (ty, Adjust::ReifyFnPointer))
+                self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b,
+                    Adjust::ReifyFnPointer, Adjust::ReifyFnPointer)
             }
-            _ => self.unify_and_identity(a, b),
+            _ => self.unify_and(a, b, identity()),
         }
     }
 
@@ -582,7 +598,7 @@ fn coerce_closure_to_fn(&self,
                                                    self.cause.span,
                                                    feature_gate::GateIssue::Language,
                                                    feature_gate::CLOSURE_TO_FN_COERCION);
-                    return self.unify_and_identity(a, b);
+                    return self.unify_and(a, b, identity());
                 }
                 // We coerce the closure, which has fn type
                 //     `extern "rust-call" fn((arg0,arg1,...)) -> _`
@@ -607,10 +623,9 @@ fn coerce_closure_to_fn(&self,
                 let pointer_ty = self.tcx.mk_fn_ptr(converted_sig);
                 debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})",
                        a, b, pointer_ty);
-                self.unify_and_identity(pointer_ty, b)
-                    .map(|(ty, _)| (ty, Adjust::ClosureFnPointer))
+                self.unify_and(pointer_ty, b, Adjust::ClosureFnPointer)
             }
-            _ => self.unify_and_identity(a, b),
+            _ => self.unify_and(a, b, identity()),
         }
     }
 
@@ -625,7 +640,7 @@ fn coerce_unsafe_ptr(&self,
             ty::TyRef(_, mt) => (true, mt),
             ty::TyRawPtr(mt) => (false, mt),
             _ => {
-                return self.unify_and_identity(a, b);
+                return self.unify_and(a, b, identity());
             }
         };
 
@@ -634,50 +649,22 @@ fn coerce_unsafe_ptr(&self,
             mutbl: mutbl_b,
             ty: mt_a.ty,
         });
-        let (ty, noop) = self.unify_and_identity(a_unsafe, b)?;
         coerce_mutbls(mt_a.mutbl, mutbl_b)?;
-
         // Although references and unsafe ptrs have the same
         // representation, we still register an Adjust::DerefRef so that
         // regionck knows that the region for `a` must be valid here.
-        Ok((ty,
-            if is_ref {
-                Adjust::DerefRef {
-                    autoderefs: 1,
-                    autoref: Some(AutoBorrow::RawPtr(mutbl_b)),
-                    unsize: false,
-                }
-            } else if mt_a.mutbl != mutbl_b {
-                Adjust::MutToConstPointer
-            } else {
-                noop
-            }))
-    }
-}
-
-fn apply<'a, 'b, 'gcx, 'tcx, E, I>(coerce: &mut Coerce<'a, 'gcx, 'tcx>,
-                                   exprs: &E,
-                                   a: Ty<'tcx>,
-                                   b: Ty<'tcx>)
-                                   -> RelateResult<'tcx, Adjustment<'tcx>>
-    where E: Fn() -> I,
-          I: IntoIterator<Item = &'b hir::Expr>
-{
-
-    let (ty, adjust) = indent(|| coerce.coerce(exprs, a, b))?;
-
-    let fcx = coerce.fcx;
-    if let Adjust::DerefRef { unsize: true, .. } = adjust {
-        let mut obligations = coerce.unsizing_obligations.borrow_mut();
-        for obligation in obligations.drain(..) {
-            fcx.register_predicate(obligation);
-        }
+        self.unify_and(a_unsafe, b, if is_ref {
+            Adjust::DerefRef {
+                autoderefs: 1,
+                autoref: Some(AutoBorrow::RawPtr(mutbl_b)),
+                unsize: false,
+            }
+        } else if mt_a.mutbl != mutbl_b {
+            Adjust::MutToConstPointer
+        } else {
+            identity()
+        })
     }
-
-    Ok(Adjustment {
-        kind: adjust,
-        target: ty
-    })
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
@@ -694,9 +681,10 @@ pub fn try_coerce(&self,
         debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
 
         let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
-        let mut coerce = Coerce::new(self, cause);
+        let coerce = Coerce::new(self, cause);
         self.commit_if_ok(|_| {
-            let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?;
+            let ok = coerce.coerce(&|| Some(expr), source, target)?;
+            let adjustment = self.register_infer_ok_obligations(ok);
             if !adjustment.is_identity() {
                 debug!("Success, coerced with {:?}", adjustment);
                 match self.tables.borrow().adjustments.get(&expr.id) {
@@ -773,9 +761,10 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
         // but only if the new expression has no coercion already applied to it.
         let mut first_error = None;
         if !self.tables.borrow().adjustments.contains_key(&new.id) {
-            let result = self.commit_if_ok(|_| apply(&mut coerce, &|| Some(new), new_ty, prev_ty));
+            let result = self.commit_if_ok(|_| coerce.coerce(&|| Some(new), new_ty, prev_ty));
             match result {
-                Ok(adjustment) => {
+                Ok(ok) => {
+                    let adjustment = self.register_infer_ok_obligations(ok);
                     if !adjustment.is_identity() {
                         self.write_adjustment(new.id, adjustment);
                     }
@@ -816,7 +805,7 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
             }
         }
 
-        match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) {
+        match self.commit_if_ok(|_| coerce.coerce(&exprs, prev_ty, new_ty)) {
             Err(_) => {
                 // Avoid giving strange errors on failed attempts.
                 if let Some(e) = first_error {
@@ -828,7 +817,8 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
                     })
                 }
             }
-            Ok(adjustment) => {
+            Ok(ok) => {
+                let adjustment = self.register_infer_ok_obligations(ok);
                 if !adjustment.is_identity() {
                     let mut tables = self.tables.borrow_mut();
                     for expr in exprs() {
index e8957bad0986c28e380da5d2bc0284a88a03821b..5a582a523ea1c910a6c52102b4104b2ec352ccfc 100644 (file)
@@ -539,13 +539,15 @@ pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult
 }
 
 pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
-    tcx.sess.track_errors(|| {
-        tcx.dep_graph.with_task(DepNode::TypeckBodiesKrate, || {
-            tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
-                tcx.item_tables(body_owner_def_id);
-            });
+    return tcx.sess.track_errors(|| {
+        tcx.dep_graph.with_task(DepNode::TypeckBodiesKrate, tcx, (), check_item_bodies_task);
+    });
+
+    fn check_item_bodies_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) {
+        tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
+            tcx.item_tables(body_owner_def_id);
         });
-    })
+    }
 }
 
 pub fn provide(providers: &mut Providers) {
@@ -1935,10 +1937,10 @@ fn new_select_all_obligations_and_apply_defaults(&self) {
             // We must collect the defaults *before* we do any unification. Because we have
             // directly attached defaults to the type variables any unification that occurs
             // will erase defaults causing conflicting defaults to be completely ignored.
-            let default_map: FxHashMap<_, _> =
+            let default_map: FxHashMap<Ty<'tcx>, _> =
                 unsolved_variables
                     .iter()
-                    .filter_map(|t| self.default(t).map(|d| (t, d)))
+                    .filter_map(|t| self.default(t).map(|d| (*t, d)))
                     .collect();
 
             let mut unbound_tyvars = FxHashSet();
@@ -2007,37 +2009,10 @@ fn new_select_all_obligations_and_apply_defaults(&self) {
             // we will rollback the inference context to its prior state so we can probe
             // for conflicts and correctly report them.
 
-
             let _ = self.commit_if_ok(|_: &infer::CombinedSnapshot| {
-                for ty in &unbound_tyvars {
-                    if self.type_var_diverges(ty) {
-                        self.demand_eqtype(syntax_pos::DUMMY_SP, *ty,
-                                           self.tcx.mk_diverging_default());
-                    } else {
-                        match self.type_is_unconstrained_numeric(ty) {
-                            UnconstrainedInt => {
-                                self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.i32)
-                            },
-                            UnconstrainedFloat => {
-                                self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.f64)
-                            }
-                            Neither => {
-                                if let Some(default) = default_map.get(ty) {
-                                    let default = default.clone();
-                                    let default_ty = self.normalize_associated_types_in(
-                                        default.origin_span, &default.ty);
-                                    match self.eq_types(false,
-                                                        &self.misc(default.origin_span),
-                                                        ty,
-                                                        default_ty) {
-                                        Ok(ok) => self.register_infer_ok_obligations(ok),
-                                        Err(_) => conflicts.push((*ty, default)),
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
+                conflicts.extend(
+                    self.apply_defaults_and_return_conflicts(&unbound_tyvars, &default_map, None)
+                );
 
                 // If there are conflicts we rollback, otherwise commit
                 if conflicts.len() > 0 {
@@ -2047,37 +2022,41 @@ fn new_select_all_obligations_and_apply_defaults(&self) {
                 }
             });
 
-            if conflicts.len() > 0 {
-                // Loop through each conflicting default, figuring out the default that caused
-                // a unification failure and then report an error for each.
-                for (conflict, default) in conflicts {
-                    let conflicting_default =
-                        self.find_conflicting_default(&unbound_tyvars, &default_map, conflict)
-                            .unwrap_or(type_variable::Default {
-                                ty: self.next_ty_var(
-                                    TypeVariableOrigin::MiscVariable(syntax_pos::DUMMY_SP)),
-                                origin_span: syntax_pos::DUMMY_SP,
-                                // what do I put here?
-                                def_id: self.tcx.hir.local_def_id(ast::CRATE_NODE_ID)
-                            });
-
-                    // This is to ensure that we elimnate any non-determinism from the error
-                    // reporting by fixing an order, it doesn't matter what order we choose
-                    // just that it is consistent.
-                    let (first_default, second_default) =
-                        if default.def_id < conflicting_default.def_id {
-                            (default, conflicting_default)
-                        } else {
-                            (conflicting_default, default)
-                        };
+            // Loop through each conflicting default, figuring out the default that caused
+            // a unification failure and then report an error for each.
+            for (conflict, default) in conflicts {
+                let conflicting_default =
+                    self.apply_defaults_and_return_conflicts(
+                            &unbound_tyvars,
+                            &default_map,
+                            Some(conflict)
+                        )
+                        .last()
+                        .map(|(_, tv)| tv)
+                        .unwrap_or(type_variable::Default {
+                            ty: self.next_ty_var(
+                                TypeVariableOrigin::MiscVariable(syntax_pos::DUMMY_SP)),
+                            origin_span: syntax_pos::DUMMY_SP,
+                            // what do I put here?
+                            def_id: self.tcx.hir.local_def_id(ast::CRATE_NODE_ID)
+                        });
+
+                // This is to ensure that we elimnate any non-determinism from the error
+                // reporting by fixing an order, it doesn't matter what order we choose
+                // just that it is consistent.
+                let (first_default, second_default) =
+                    if default.def_id < conflicting_default.def_id {
+                        (default, conflicting_default)
+                    } else {
+                        (conflicting_default, default)
+                    };
 
 
-                    self.report_conflicting_default_types(
-                        first_default.origin_span,
-                        self.body_id,
-                        first_default,
-                        second_default)
-                }
+                self.report_conflicting_default_types(
+                    first_default.origin_span,
+                    self.body_id,
+                    first_default,
+                    second_default)
             }
         }
 
@@ -2088,56 +2067,48 @@ fn new_select_all_obligations_and_apply_defaults(&self) {
     // apply the default that caused conflict first to a local version of the type variable
     // table then apply defaults until we find a conflict. That default must be the one
     // that caused conflict earlier.
-    fn find_conflicting_default(&self,
-                                unbound_vars: &FxHashSet<Ty<'tcx>>,
-                                default_map: &FxHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>,
-                                conflict: Ty<'tcx>)
-                                -> Option<type_variable::Default<'tcx>> {
+    fn apply_defaults_and_return_conflicts<'b>(
+        &'b self,
+        unbound_vars: &'b FxHashSet<Ty<'tcx>>,
+        default_map: &'b FxHashMap<Ty<'tcx>, type_variable::Default<'tcx>>,
+        conflict: Option<Ty<'tcx>>,
+    ) -> impl Iterator<Item=(Ty<'tcx>, type_variable::Default<'tcx>)> + 'b {
         use rustc::ty::error::UnconstrainedNumeric::Neither;
         use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
 
-        // Ensure that we apply the conflicting default first
-        let mut unbound_tyvars = Vec::with_capacity(unbound_vars.len() + 1);
-        unbound_tyvars.push(conflict);
-        unbound_tyvars.extend(unbound_vars.iter());
-
-        let mut result = None;
-        // We run the same code as above applying defaults in order, this time when
-        // we find the conflict we just return it for error reporting above.
-
-        // We also run this inside snapshot that never commits so we can do error
-        // reporting for more then one conflict.
-        for ty in &unbound_tyvars {
+        conflict.into_iter().chain(unbound_vars.iter().cloned()).flat_map(move |ty| {
             if self.type_var_diverges(ty) {
-                self.demand_eqtype(syntax_pos::DUMMY_SP, *ty,
+                self.demand_eqtype(syntax_pos::DUMMY_SP, ty,
                                    self.tcx.mk_diverging_default());
             } else {
                 match self.type_is_unconstrained_numeric(ty) {
                     UnconstrainedInt => {
-                        self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.i32)
+                        self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.types.i32)
                     },
                     UnconstrainedFloat => {
-                        self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.f64)
+                        self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.types.f64)
                     },
                     Neither => {
                         if let Some(default) = default_map.get(ty) {
                             let default = default.clone();
+                            let default_ty = self.normalize_associated_types_in(
+                                default.origin_span, &default.ty);
                             match self.eq_types(false,
                                                 &self.misc(default.origin_span),
                                                 ty,
-                                                default.ty) {
+                                                default_ty) {
                                 Ok(ok) => self.register_infer_ok_obligations(ok),
                                 Err(_) => {
-                                    result = Some(default);
+                                    return Some((ty, default));
                                 }
                             }
                         }
                     }
                 }
             }
-        }
 
-        return result;
+            None
+        })
     }
 
     fn select_all_obligations_or_error(&self) {
index db7cf3c000ba4cae91f45e0567edf4b9b4423365..2417745571910b3c848b213ff12d57f696b358d4 100644 (file)
@@ -165,15 +165,10 @@ impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> {
     /// 4. This is added by the code in `visit_expr` when we write to `item_types`.
     /// 5. This is added by the code in `convert_item` when we write to `item_types`;
     ///    note that this write occurs inside the `CollectItemSig` task.
-    /// 6. Added by explicit `read` below
-    fn with_collect_item_sig<OP>(&self, id: ast::NodeId, op: OP)
-        where OP: FnOnce()
-    {
+    /// 6. Added by reads from within `op`.
+    fn with_collect_item_sig(&self, id: ast::NodeId, op: fn(TyCtxt<'a, 'tcx, 'tcx>, ast::NodeId)) {
         let def_id = self.tcx.hir.local_def_id(id);
-        self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || {
-            self.tcx.hir.read(id);
-            op();
-        });
+        self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), self.tcx, id, op);
     }
 }
 
@@ -183,7 +178,7 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item) {
-        self.with_collect_item_sig(item.id, || convert_item(self.tcx, item));
+        self.with_collect_item_sig(item.id, convert_item);
         intravisit::walk_item(self, item);
     }
 
@@ -216,16 +211,12 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
     }
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
-        self.with_collect_item_sig(trait_item.id, || {
-            convert_trait_item(self.tcx, trait_item)
-        });
+        self.with_collect_item_sig(trait_item.id, convert_trait_item);
         intravisit::walk_trait_item(self, trait_item);
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
-        self.with_collect_item_sig(impl_item.id, || {
-            convert_impl_item(self.tcx, impl_item)
-        });
+        self.with_collect_item_sig(impl_item.id, convert_impl_item);
         intravisit::walk_impl_item(self, impl_item);
     }
 }
@@ -493,9 +484,10 @@ fn ensure_no_ty_param_bounds(tcx: TyCtxt,
     }
 }
 
-fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) {
+fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) {
+    let it = tcx.hir.expect_item(item_id);
     debug!("convert: item {} with id {}", it.name, it.id);
-    let def_id = tcx.hir.local_def_id(it.id);
+    let def_id = tcx.hir.local_def_id(item_id);
     match it.node {
         // These don't define types.
         hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => {
@@ -560,7 +552,8 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) {
     }
 }
 
-fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::TraitItem) {
+fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item_id: ast::NodeId) {
+    let trait_item = tcx.hir.expect_trait_item(trait_item_id);
     let def_id = tcx.hir.local_def_id(trait_item.id);
     tcx.item_generics(def_id);
 
@@ -577,8 +570,8 @@ fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::T
     tcx.item_predicates(def_id);
 }
 
-fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item: &hir::ImplItem) {
-    let def_id = tcx.hir.local_def_id(impl_item.id);
+fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item_id: ast::NodeId) {
+    let def_id = tcx.hir.local_def_id(impl_item_id);
     tcx.item_generics(def_id);
     tcx.item_type(def_id);
     tcx.item_predicates(def_id);
index b0bf69b0181f22ae2de2705e1a333788bda169d5..4047f6045bcc5fae61b401cf6e8b182edb714228 100644 (file)
@@ -167,7 +167,11 @@ nav.sub {
        position: absolute;
        left: 0;
        top: 0;
-       min-height: 100%;
+       min-height: 100vh;
+}
+
+.sidebar .current {
+       margin-right: -20px;
 }
 
 .content, nav { max-width: 960px; }
@@ -185,11 +189,16 @@ nav.sub {
 }
 
 .sidebar .location {
+       border: 1px solid;
        font-size: 17px;
        margin: 30px 0 20px 0;
        text-align: center;
 }
 
+.location:empty {
+       border: none;
+}
+
 .location a:first-child { font-weight: 500; }
 
 .block {
@@ -368,13 +377,13 @@ h4 > code, h3 > code, .invisible > code {
 .content .method .where,
 .content .fn .where,
 .content .where.fmt-newline {
-    display: block;
+       display: block;
 }
 /* Bit of whitespace to indent it */
 .content .method .where::before,
 .content .fn .where::before,
 .content .where.fmt-newline::before {
-    content: '  ';
+       content: '  ';
 }
 
 .content .methods > div { margin-left: 40px; }
@@ -497,17 +506,15 @@ body.blur > :not(#help) {
 }
 #help > div {
        flex: 0 0 auto;
-       background: #e9e9e9;
        box-shadow: 0 0 6px rgba(0,0,0,.2);
        width: 550px;
        height: 330px;
-       border: 1px solid #bfbfbf;
+       border: 1px solid;
 }
 #help dt {
        float: left;
        border-radius: 4px;
-       border: 1px solid #bfbfbf;
-       background: #fff;
+       border: 1px solid;
        width: 23px;
        text-align: center;
        clear: left;
@@ -558,7 +565,6 @@ body.blur > :not(#help) {
 .since {
        font-weight: normal;
        font-size: initial;
-       color: grey;
        position: absolute;
        right: 0;
        top: 0;
@@ -580,24 +586,12 @@ td.summary-column {
        padding-right: 0px;
 }
 
-.line-numbers :target { background-color: transparent; }
-
-/* Code highlighting */
-pre.rust .kw { color: #8959A8; }
-pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; }
-pre.rust .number, pre.rust .string { color: #718C00; }
-pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val,
-pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
-pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
-pre.rust .lifetime { color: #B76514; }
 pre.rust .question-mark {
-       color: #ff9011;
        font-weight: bold;
 }
 
 pre.rust { position: relative; }
 a.test-arrow {
-       background-color: rgba(78, 139, 202, 0.2);
        display: inline-block;
        position: absolute;
        padding: 5px 10px 5px 10px;
@@ -607,7 +601,6 @@ a.test-arrow {
        right: 5px;
 }
 a.test-arrow:hover{
-       background-color: #4e8bca;
        text-decoration: none;
 }
 
@@ -651,10 +644,6 @@ a.test-arrow:hover{
        text-align: center;
 }
 
-.toggle-label {
-       color: #999;
-}
-
 .ghost {
        display: none;
 }
@@ -710,8 +699,7 @@ span.since {
 }
 
 :target > code {
-   background: #FDFFD3;
-   opacity: 1;
+       opacity: 1;
 }
 
 /* Media Queries */
@@ -784,4 +772,4 @@ span.since {
        nav.sub, .content .out-of-band, .collapse-toggle {
                display: none;
        }
-}
+}
\ No newline at end of file
index 862d6d12b9ad99f28489d34bdda597a430fb477e..40561597e93e09be91c1eb555ab9e7b9319ad834 100644 (file)
 /* General structure and fonts */
 
 body {
-    background-color: white;
-    color: black;
+       background-color: white;
+       color: black;
 }
 
 h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {
-    color: black;
+       color: black;
 }
 h1.fqn {
-    border-bottom-color: #D5D5D5;
+       border-bottom-color: #D5D5D5;
 }
 h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {
-    border-bottom-color: #DDDDDD;
+       border-bottom-color: #DDDDDD;
 }
 .in-band {
-    background-color: white;
+       background-color: white;
 }
 
 .docblock code, .docblock-short code {
-    background-color: #F5F5F5;
+       background-color: #F5F5F5;
 }
 pre {
-    background-color: #F5F5F5;
+       background-color: #F5F5F5;
+}
+
+.sidebar {
+       background-color: #F1F1F1;
+}
+
+.sidebar .current {
+       background-color: #fff;
+}
+
+.sidebar {
+    background-color: #F1F1F1;
+}
+
+.sidebar .current {
+    background-color: #fff;
 }
 
 .sidebar .location {
-    background: #e1e1e1;
-    color: #333;
+       border-color: #000;
+       background-color: #fff;
+       color: #333;
 }
 
 .block a:hover {
-    background: #F5F5F5;
+       background: #F5F5F5;
 }
 
 .line-numbers span { color: #c67e2d; }
 .line-numbers .line-highlighted {
-    background-color: #f6fdb0 !important;
+       background-color: #f6fdb0 !important;
 }
 
 :target { background: #FDFFD3; }
 .content .highlighted {
-    color: #000 !important;
-    background-color: #ccc;
+       color: #000 !important;
+       background-color: #ccc;
 }
 .content .highlighted a, .content .highlighted span { color: #000 !important; }
 .content .highlighted.trait { background-color: #fece7e; }
@@ -67,21 +84,21 @@ pre {
 .content .highlighted.type { background-color: #c6afb3; }
 
 .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
-    border-bottom-color: #DDD;
+       border-bottom-color: #DDD;
 }
 
 .docblock table {
-    border-color: #ddd;
+       border-color: #ddd;
 }
 
 .docblock table td {
-    border-top-color: #ddd;
-    border-bottom-color: #ddd;
+       border-top-color: #ddd;
+       border-bottom-color: #ddd;
 }
 
 .docblock table th {
-    border-top-color: #ddd;
-    border-bottom-color: #ddd;
+       border-top-color: #ddd;
+       border-bottom-color: #ddd;
 }
 
 .content span.primitive, .content a.primitive, .block a.current.primitive { color: #39a7bf; }
@@ -96,34 +113,78 @@ pre.rust .comment { color: #8E908C; }
 pre.rust .doccomment { color: #4D4D4C; }
 
 nav {
-    border-bottom-color: #e0e0e0;
+       border-bottom-color: #e0e0e0;
 }
 nav.main .current {
-    border-top-color: #000;
-    border-bottom-color: #000;
+       border-top-color: #000;
+       border-bottom-color: #000;
 }
 nav.main .separator {
-    border: 1px solid #000;
+       border: 1px solid #000;
 }
 a {
-    color: #000;
+       color: #000;
 }
 
 .docblock a, .docblock-short a, .stability a {
-    color: #3873AD;
+       color: #3873AD;
 }
 
 a.test-arrow {
-    color: #f5f5f5;
+       color: #f5f5f5;
 }
 
 .content span.trait, .content a.trait, .block a.current.trait { color: #7c5af3; }
 
 .search-input {
-    color: #555;
-    box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent;
-    background-color: white;
+       color: #555;
+       box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent;
+       background-color: white;
 }
 
 .stab.unstable { background: #FFF5D6; border-color: #FFC600; }
 .stab.deprecated { background: #F3DFFF; border-color: #7F0087; }
+
+#help > div {
+       background: #e9e9e9;
+       border-color: #bfbfbf;;
+}
+
+#help dt {
+       border-color: #bfbfbf;
+       background: #fff;
+}
+
+.since {
+       color: grey;
+}
+
+.line-numbers :target { background-color: transparent; }
+
+/* Code highlighting */
+pre.rust .kw { color: #8959A8; }
+pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; }
+pre.rust .number, pre.rust .string { color: #718C00; }
+pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val,
+pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
+pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
+pre.rust .lifetime { color: #B76514; }
+pre.rust .question-mark {
+       color: #ff9011;
+}
+
+a.test-arrow {
+       background-color: rgba(78, 139, 202, 0.2);
+}
+
+a.test-arrow:hover{
+       background-color: #4e8bca;
+}
+
+.toggle-label {
+       color: #999;
+}
+
+:target > code {
+       background: #FDFFD3;
+}
\ No newline at end of file
index c7000ee1e40e764f5a79837cd2149cc24d891a71..c1ecc241b7b63d4d52aa9f9ca06cb8b9e40cd8ff 100644 (file)
@@ -422,8 +422,11 @@ pub fn add_test(&mut self, test: String,
                     as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>,
                     line: usize, filename: String) {
         let name = if self.use_headers {
-            let s = self.current_header.as_ref().map(|s| &**s).unwrap_or("");
-            format!("{} - {} (line {})", filename, s, line)
+            if let Some(ref header) = self.current_header {
+                format!("{} - {} (line {})", filename, header, line)
+            } else {
+                format!("{} - (line {})", filename, line)
+            }
         } else {
             format!("{} - {} (line {})", filename, self.names.join("::"), line)
         };
index f0738fe9b7033fea50795eaccb0dbe33238f4760..f9b0ec479d70115768328111f24537acbb979453 100644 (file)
@@ -396,8 +396,6 @@ pub struct HashMap<K, V, S = RandomState> {
     table: RawTable<K, V>,
 
     resize_policy: DefaultResizePolicy,
-
-    long_probes: bool,
 }
 
 /// Search for a pre-hashed key.
@@ -655,7 +653,6 @@ pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
             hash_builder: hash_builder,
             resize_policy: DefaultResizePolicy::new(),
             table: RawTable::new(0),
-            long_probes: false,
         }
     }
 
@@ -688,7 +685,6 @@ pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap<K,
             hash_builder: hash_builder,
             resize_policy: resize_policy,
             table: RawTable::new(raw_cap),
-            long_probes: false,
         }
     }
 
@@ -746,7 +742,7 @@ pub fn reserve(&mut self, additional: usize) {
             let min_cap = self.len().checked_add(additional).expect("reserve overflow");
             let raw_cap = self.resize_policy.raw_capacity(min_cap);
             self.resize(raw_cap);
-        } else if self.long_probes && remaining <= self.len() {
+        } else if self.table.tag() && remaining <= self.len() {
             // Probe sequence is too long and table is half full,
             // resize early to reduce probing length.
             let new_capacity = self.table.capacity() * 2;
@@ -763,7 +759,6 @@ fn resize(&mut self, new_raw_cap: usize) {
         assert!(self.table.size() <= new_raw_cap);
         assert!(new_raw_cap.is_power_of_two() || new_raw_cap == 0);
 
-        self.long_probes = false;
         let mut old_table = replace(&mut self.table, RawTable::new(new_raw_cap));
         let old_size = old_table.size();
 
@@ -844,8 +839,7 @@ pub fn shrink_to_fit(&mut self) {
     /// If the key already exists, the hashtable will be returned untouched
     /// and a reference to the existing element will be returned.
     fn insert_hashed_nocheck(&mut self, hash: SafeHash, k: K, v: V) -> Option<V> {
-        let entry = search_hashed(&mut self.table, hash, |key| *key == k)
-            .into_entry(k, &mut self.long_probes);
+        let entry = search_hashed(&mut self.table, hash, |key| *key == k).into_entry(k);
         match entry {
             Some(Occupied(mut elem)) => Some(elem.insert(v)),
             Some(Vacant(elem)) => {
@@ -1002,7 +996,7 @@ pub fn entry(&mut self, key: K) -> Entry<K, V> {
         self.reserve(1);
         let hash = self.make_hash(&key);
         search_hashed(&mut self.table, hash, |q| q.eq(&key))
-            .into_entry(key, &mut self.long_probes).expect("unreachable")
+            .into_entry(key).expect("unreachable")
     }
 
     /// Returns the number of elements in the map.
@@ -1456,7 +1450,7 @@ fn into_occupied_bucket(self) -> Option<FullBucket<K, V, M>> {
 
 impl<'a, K, V> InternalEntry<K, V, &'a mut RawTable<K, V>> {
     #[inline]
-    fn into_entry(self, key: K, long_probes: &'a mut bool) -> Option<Entry<'a, K, V>> {
+    fn into_entry(self, key: K) -> Option<Entry<'a, K, V>> {
         match self {
             InternalEntry::Occupied { elem } => {
                 Some(Occupied(OccupiedEntry {
@@ -1469,7 +1463,6 @@ fn into_entry(self, key: K, long_probes: &'a mut bool) -> Option<Entry<'a, K, V>
                     hash: hash,
                     key: key,
                     elem: elem,
-                    long_probes: long_probes,
                 }))
             }
             InternalEntry::TableIsEmpty => None,
@@ -1542,7 +1535,6 @@ pub struct VacantEntry<'a, K: 'a, V: 'a> {
     hash: SafeHash,
     key: K,
     elem: VacantEntryState<K, V, &'a mut RawTable<K, V>>,
-    long_probes: &'a mut bool,
 }
 
 #[stable(feature= "debug_hash_map", since = "1.12.0")]
@@ -2117,15 +2109,15 @@ pub fn into_key(self) -> K {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(self, value: V) -> &'a mut V {
         match self.elem {
-            NeqElem(bucket, disp) => {
+            NeqElem(mut bucket, disp) => {
                 if disp >= DISPLACEMENT_THRESHOLD {
-                    *self.long_probes = true;
+                    bucket.table_mut().set_tag(true);
                 }
                 robin_hood(bucket, disp, self.hash, self.key, value)
             },
-            NoElem(bucket, disp) => {
+            NoElem(mut bucket, disp) => {
                 if disp >= DISPLACEMENT_THRESHOLD {
-                    *self.long_probes = true;
+                    bucket.table_mut().set_tag(true);
                 }
                 bucket.put(self.hash, self.key, value).into_mut_refs().1
             },
index 9e92b4750145e79b31ea9949214c7a51e407a840..0e225b2964f63752246b7a30d6fc26096b425e98 100644 (file)
 
 const EMPTY_BUCKET: HashUint = 0;
 
+/// Special `Unique<HashUint>` that uses the lower bit of the pointer
+/// to expose a boolean tag.
+/// Note: when the pointer is initialized to EMPTY `.ptr()` will return
+/// null and the tag functions shouldn't be used.
+struct TaggedHashUintPtr(Unique<HashUint>);
+
+impl TaggedHashUintPtr {
+    #[inline]
+    unsafe fn new(ptr: *mut HashUint) -> Self {
+        debug_assert!(ptr as usize & 1 == 0 || ptr as usize == EMPTY as usize);
+        TaggedHashUintPtr(Unique::new(ptr))
+    }
+
+    #[inline]
+    fn set_tag(&mut self, value: bool) {
+        let usize_ptr = &*self.0 as *const *mut HashUint as *mut usize;
+        unsafe {
+            if value {
+                *usize_ptr |= 1;
+            } else {
+                *usize_ptr &= !1;
+            }
+        }
+    }
+
+    #[inline]
+    fn tag(&self) -> bool {
+        (*self.0 as usize) & 1 == 1
+    }
+
+    #[inline]
+    fn ptr(&self) -> *mut HashUint {
+        (*self.0 as usize & !1) as *mut HashUint
+    }
+}
+
 /// The raw hashtable, providing safe-ish access to the unzipped and highly
 /// optimized arrays of hashes, and key-value pairs.
 ///
 /// around just the "table" part of the hashtable. It enforces some
 /// invariants at the type level and employs some performance trickery,
 /// but in general is just a tricked out `Vec<Option<(u64, K, V)>>`.
+///
+/// The hashtable also exposes a special boolean tag. The tag defaults to false
+/// when the RawTable is created and is accessible with the `tag` and `set_tag`
+/// functions.
 pub struct RawTable<K, V> {
     capacity: usize,
     size: usize,
-    hashes: Unique<HashUint>,
+    hashes: TaggedHashUintPtr,
 
     // Because K/V do not appear directly in any of the types in the struct,
     // inform rustc that in fact instances of K and V are reachable from here.
@@ -208,6 +248,10 @@ impl<K, V, M> FullBucket<K, V, M> {
     pub fn table(&self) -> &M {
         &self.table
     }
+    /// Borrow a mutable reference to the table.
+    pub fn table_mut(&mut self) -> &mut M {
+        &mut self.table
+    }
     /// Move out the reference to the table.
     pub fn into_table(self) -> M {
         self.table
@@ -227,6 +271,10 @@ impl<K, V, M> EmptyBucket<K, V, M> {
     pub fn table(&self) -> &M {
         &self.table
     }
+    /// Borrow a mutable reference to the table.
+    pub fn table_mut(&mut self) -> &mut M {
+        &mut self.table
+    }
 }
 
 impl<K, V, M> Bucket<K, V, M> {
@@ -687,7 +735,7 @@ unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> {
             return RawTable {
                 size: 0,
                 capacity: 0,
-                hashes: Unique::new(EMPTY as *mut HashUint),
+                hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint),
                 marker: marker::PhantomData,
             };
         }
@@ -728,7 +776,7 @@ unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> {
         RawTable {
             capacity: capacity,
             size: 0,
-            hashes: Unique::new(hashes),
+            hashes: TaggedHashUintPtr::new(hashes),
             marker: marker::PhantomData,
         }
     }
@@ -737,13 +785,13 @@ fn first_bucket_raw(&self) -> RawBucket<K, V> {
         let hashes_size = self.capacity * size_of::<HashUint>();
         let pairs_size = self.capacity * size_of::<(K, V)>();
 
-        let buffer = *self.hashes as *mut u8;
+        let buffer = self.hashes.ptr() as *mut u8;
         let (pairs_offset, _, oflo) =
             calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>());
         debug_assert!(!oflo, "capacity overflow");
         unsafe {
             RawBucket {
-                hash: *self.hashes,
+                hash: self.hashes.ptr(),
                 pair: buffer.offset(pairs_offset as isize) as *const _,
                 _marker: marker::PhantomData,
             }
@@ -755,7 +803,7 @@ fn first_bucket_raw(&self) -> RawBucket<K, V> {
     pub fn new(capacity: usize) -> RawTable<K, V> {
         unsafe {
             let ret = RawTable::new_uninitialized(capacity);
-            ptr::write_bytes(*ret.hashes, 0, capacity);
+            ptr::write_bytes(ret.hashes.ptr(), 0, capacity);
             ret
         }
     }
@@ -774,7 +822,7 @@ pub fn size(&self) -> usize {
     fn raw_buckets(&self) -> RawBuckets<K, V> {
         RawBuckets {
             raw: self.first_bucket_raw(),
-            hashes_end: unsafe { self.hashes.offset(self.capacity as isize) },
+            hashes_end: unsafe { self.hashes.ptr().offset(self.capacity as isize) },
             marker: marker::PhantomData,
         }
     }
@@ -832,6 +880,16 @@ unsafe fn rev_move_buckets(&mut self) -> RevMoveBuckets<K, V> {
             marker: marker::PhantomData,
         }
     }
+
+    /// Set the table tag
+    pub fn set_tag(&mut self, value: bool) {
+        self.hashes.set_tag(value)
+    }
+
+    /// Get the table tag
+    pub fn tag(&self) -> bool {
+        self.hashes.tag()
+    }
 }
 
 /// A raw iterator. The basis for some other iterators in this module. Although
@@ -1156,7 +1214,7 @@ fn drop(&mut self) {
         debug_assert!(!oflo, "should be impossible");
 
         unsafe {
-            deallocate(*self.hashes as *mut u8, size, align);
+            deallocate(self.hashes.ptr() as *mut u8, size, align);
             // Remember how everything was allocated out of one buffer
             // during initialization? We only need one call to free here.
         }
index dd4f1ff4f5ed7318c33850b9f341848fed948837..64eb52e28bc42d2ce075c5938c9b1f1614c4c795 100644 (file)
@@ -590,6 +590,10 @@ pub fn current_exe() -> io::Result<PathBuf> {
 ///
 /// This structure is created through the [`std::env::args`] function.
 ///
+/// The first element is traditionally the path of the executable, but it can be
+/// set to arbitrary text, and may not even exist. This means this property should
+/// not be relied upon for security purposes.
+///
 /// [`String`]: ../string/struct.String.html
 /// [`std::env::args`]: ./fn.args.html
 #[stable(feature = "env", since = "1.0.0")]
@@ -600,6 +604,10 @@ pub struct Args { inner: ArgsOs }
 ///
 /// This structure is created through the [`std::env::args_os`] function.
 ///
+/// The first element is traditionally the path of the executable, but it can be
+/// set to arbitrary text, and may not even exist. This means this property should
+/// not be relied upon for security purposes.
+///
 /// [`OsString`]: ../ffi/struct.OsString.html
 /// [`std::env::args_os`]: ./fn.args_os.html
 #[stable(feature = "env", since = "1.0.0")]
index bc678fcb8385b0a9a640afdc285fe8de2eebf8e3..bfb0aa6e1a122410e6fe6acfd1e9b612e2c76710 100644 (file)
@@ -154,7 +154,28 @@ pub struct CStr {
 /// byte was found too early in the slice provided or one wasn't found at all.
 #[derive(Clone, PartialEq, Eq, Debug)]
 #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-pub struct FromBytesWithNulError { _a: () }
+pub struct FromBytesWithNulError {
+    kind: FromBytesWithNulErrorKind,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+enum FromBytesWithNulErrorKind {
+    InteriorNul(usize),
+    NotNulTerminated,
+}
+
+impl FromBytesWithNulError {
+    fn interior_nul(pos: usize) -> FromBytesWithNulError {
+        FromBytesWithNulError {
+            kind: FromBytesWithNulErrorKind::InteriorNul(pos),
+        }
+    }
+    fn not_nul_terminated() -> FromBytesWithNulError {
+        FromBytesWithNulError {
+            kind: FromBytesWithNulErrorKind::NotNulTerminated,
+        }
+    }
+}
 
 /// An error returned from `CString::into_string` to indicate that a UTF-8 error
 /// was encountered during the conversion.
@@ -458,14 +479,23 @@ fn from(_: NulError) -> io::Error {
 #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
 impl Error for FromBytesWithNulError {
     fn description(&self) -> &str {
-        "data provided is not null terminated or contains an interior nul byte"
+        match self.kind {
+            FromBytesWithNulErrorKind::InteriorNul(..) =>
+                "data provided contains an interior nul byte",
+            FromBytesWithNulErrorKind::NotNulTerminated =>
+                "data provided is not nul terminated",
+        }
     }
 }
 
 #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
 impl fmt::Display for FromBytesWithNulError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.description().fmt(f)
+        f.write_str(self.description())?;
+        if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
+            write!(f, " at byte pos {}", pos)?;
+        }
+        Ok(())
     }
 }
 
@@ -559,10 +589,14 @@ pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
     #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
     pub fn from_bytes_with_nul(bytes: &[u8])
                                -> Result<&CStr, FromBytesWithNulError> {
-        if bytes.is_empty() || memchr::memchr(0, &bytes) != Some(bytes.len() - 1) {
-            Err(FromBytesWithNulError { _a: () })
+        let nul_pos = memchr::memchr(0, bytes);
+        if let Some(nul_pos) = nul_pos {
+            if nul_pos + 1 != bytes.len() {
+                return Err(FromBytesWithNulError::interior_nul(nul_pos));
+            }
+            Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) })
         } else {
-            Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+            Err(FromBytesWithNulError::not_nul_terminated())
         }
     }
 
index 7b8bf42e0a74a5d3f1d485f8553c8a8ef1e34fe4..41bdd9c51d458e1c9d85f34cfdd1f0cc1ec6386a 100644 (file)
@@ -205,6 +205,12 @@ pub fn reserve_exact(&mut self, additional: usize) {
         self.inner.reserve_exact(additional)
     }
 
+    /// Shrinks the capacity of the `OsString` to match its length.
+    #[unstable(feature = "osstring_shrink_to_fit", issue = "40421")]
+    pub fn shrink_to_fit(&mut self) {
+        self.inner.shrink_to_fit()
+    }
+
     /// Converts this `OsString` into a boxed `OsStr`.
     #[unstable(feature = "into_boxed_os_str", issue = "0")]
     pub fn into_boxed_os_str(self) -> Box<OsStr> {
index 0f967863899cb071f3565e39b3ece9e4fa0290ac..474d59eed83d1daa3bf3b8b00b6e73edec840688 100644 (file)
@@ -83,6 +83,11 @@ pub fn reserve_exact(&mut self, additional: usize) {
         self.inner.reserve_exact(additional)
     }
 
+    #[inline]
+    pub fn shrink_to_fit(&mut self) {
+        self.inner.shrink_to_fit()
+    }
+
     pub fn as_slice(&self) -> &Slice {
         unsafe { mem::transmute(&*self.inner) }
     }
index 938bcfc6d162e958903a34d65db4078d4de0e352..c27599ec0206f8ae46b581c658e80fa215b7ebe2 100644 (file)
@@ -83,6 +83,11 @@ pub fn reserve_exact(&mut self, additional: usize) {
         self.inner.reserve_exact(additional)
     }
 
+    #[inline]
+    pub fn shrink_to_fit(&mut self) {
+        self.inner.shrink_to_fit()
+    }
+
     pub fn as_slice(&self) -> &Slice {
         unsafe { mem::transmute(&*self.inner) }
     }
index 04e45dcf549631df7a0ce6436c3cd0c574ebb5ca..b02b06e1ef2e1510aed1b7885a9efaf70655f9ac 100644 (file)
@@ -89,6 +89,10 @@ pub fn reserve_exact(&mut self, additional: usize) {
         self.inner.reserve_exact(additional)
     }
 
+    pub fn shrink_to_fit(&mut self) {
+        self.inner.shrink_to_fit()
+    }
+
     #[inline]
     pub fn into_box(self) -> Box<Slice> {
         unsafe { mem::transmute(self.inner.into_box()) }
index 1ea5cca44c7e40154f383bce344187a8b703a94e..14c0e8699bc060b2cbbf9255e4fbff86701ce1b7 100644 (file)
@@ -105,9 +105,6 @@ pub fn resolve_symname<F>(frame: Frame,
               msg: *const libc::c_char,
               errnum: libc::c_int);
 enum backtrace_state {}
-#[link(name = "backtrace", kind = "static")]
-#[cfg(all(not(test), not(cargobuild)))]
-extern {}
 
 extern {
     fn backtrace_create_state(filename: *const libc::c_char,
index 1d61181a4ee0f96db5f8a4a063410a837f61176f..b486d4ffda3fd61c239b94d61f9a03e9b758e52e 100644 (file)
@@ -236,6 +236,11 @@ pub fn reserve_exact(&mut self, additional: usize) {
         self.bytes.reserve_exact(additional)
     }
 
+    #[inline]
+    pub fn shrink_to_fit(&mut self) {
+        self.bytes.shrink_to_fit()
+    }
+
     /// Returns the number of bytes that this string buffer can hold without reallocating.
     #[inline]
     pub fn capacity(&self) -> usize {
index f1662284a88206657283952e9c444e4c5ea39397..f7dcd00e40976d7ba8f16464ca4428dcdc95ce1c 100644 (file)
@@ -464,8 +464,20 @@ fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
                 let attr_toks = stream_for_attr_args(&attr, &self.cx.parse_sess);
                 let item_toks = stream_for_item(&item, &self.cx.parse_sess);
 
+                let span = Span {
+                    expn_id: self.cx.codemap().record_expansion(ExpnInfo {
+                        call_site: attr.span,
+                        callee: NameAndSpan {
+                            format: MacroAttribute(name),
+                            span: None,
+                            allow_internal_unstable: false,
+                        },
+                    }),
+                    ..attr.span
+                };
+
                 let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks);
-                self.parse_expansion(tok_result, kind, name, attr.span)
+                self.parse_expansion(tok_result, kind, name, span)
             }
             SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
                 self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name));
index 6eb7d449f269287afe915646535552840b0ec16d..e7bf16eae9ee660bd6bbf06f70bccb096a683116 100644 (file)
@@ -330,8 +330,7 @@ pub fn new() -> Features {
     // `extern "msp430-interrupt" fn()`
     (active, abi_msp430_interrupt, "1.16.0", Some(38487)),
 
-    // Used to identify crates that contain sanitizer runtimes
-    // rustc internal
+    // Coerces non capturing closures to function pointers
     (active, closure_to_fn_coercion, "1.17.0", Some(39817)),
 
     // Used to identify crates that contain sanitizer runtimes
index cda9a5a96432b9e308c9add87f2a1f0b216a07cd..772029ab0c253fc571578706b069de4057765555 100644 (file)
@@ -13,4 +13,4 @@
 # released on `$date`
 
 rustc: beta-2017-02-01
-cargo: bfee18f73287687c543bda8c35e4e33808792715
+cargo: 407edef22e894266eb562618cba5ca9757051946
diff --git a/src/test/codegen/issue-15953.rs b/src/test/codegen/issue-15953.rs
new file mode 100644 (file)
index 0000000..320ea6b
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2017 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 llvm generates `memcpy` for moving a value
+// inside a function and moving an argument.
+
+struct Foo {
+    x: Vec<i32>,
+}
+
+#[inline(never)]
+#[no_mangle]
+// CHECK: memcpy
+fn interior(x: Vec<i32>) -> Vec<i32> {
+    let Foo { x } = Foo { x: x };
+    x
+}
+
+#[inline(never)]
+#[no_mangle]
+// CHECK: memcpy
+fn exterior(x: Vec<i32>) -> Vec<i32> {
+    x
+}
+
+fn main() {
+    let x = interior(Vec::new());
+    println!("{:?}", x);
+
+    let x = exterior(Vec::new());
+    println!("{:?}", x);
+}
diff --git a/src/test/compile-fail/auxiliary/cfg-target-thread-local.rs b/src/test/compile-fail/auxiliary/cfg-target-thread-local.rs
new file mode 100644 (file)
index 0000000..d1971a5
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2016 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(thread_local)]
+#![feature(cfg_target_thread_local)]
+#![crate_type = "lib"]
+
+#[no_mangle]
+#[cfg_attr(target_thread_local, thread_local)]
+pub static FOO: u32 = 3;
diff --git a/src/test/compile-fail/feature-gate-cfg-target-thread-local.rs b/src/test/compile-fail/feature-gate-cfg-target-thread-local.rs
new file mode 100644 (file)
index 0000000..985bd83
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-windows
+// aux-build:cfg-target-thread-local.rs
+
+#![feature(thread_local)]
+
+extern crate cfg_target_thread_local;
+
+extern {
+    #[cfg_attr(target_thread_local, thread_local)]
+    //~^ `cfg(target_thread_local)` is experimental and subject to change (see issue #29594)
+
+    static FOO: u32;
+}
+
+fn main() {
+    assert_eq!(FOO, 3);
+}
diff --git a/src/test/compile-fail/feature-gate-unwind-attributes.rs b/src/test/compile-fail/feature-gate-unwind-attributes.rs
new file mode 100644 (file)
index 0000000..c8f9cd9
--- /dev/null
@@ -0,0 +1,28 @@
+// 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.
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+extern {
+// CHECK: Function Attrs: nounwind
+// CHECK-NEXT: declare void @extern_fn
+    fn extern_fn();
+// CHECK-NOT: Function Attrs: nounwind
+// CHECK: declare void @unwinding_extern_fn
+    #[unwind] //~ ERROR #[unwind] is experimental
+    fn unwinding_extern_fn();
+}
+
+pub unsafe fn force_declare() {
+    extern_fn();
+    unwinding_extern_fn();
+}
diff --git a/src/test/compile-fail/issue-18446.rs b/src/test/compile-fail/issue-18446.rs
new file mode 100644 (file)
index 0000000..60afea5
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2017 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 name clashes between the method in an impl for the type
+// and the method in the trait when both are in the same scope.
+
+trait T {
+    fn foo(&self);
+}
+
+impl<'a> T + 'a {
+    fn foo(&self) {}
+}
+
+impl T for i32 {
+    fn foo(&self) {}
+}
+
+fn main() {
+    let x: &T = &0i32;
+    x.foo(); //~ ERROR multiple applicable items in scope [E0034]
+}
diff --git a/src/test/compile-fail/issue-22874.rs b/src/test/compile-fail/issue-22874.rs
new file mode 100644 (file)
index 0000000..0df84a4
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2017 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 Table {
+    rows: [[String]],
+    //~^ ERROR the trait bound `[std::string::String]: std::marker::Sized` is not satisfied [E0277]
+}
+
+fn f(table: &Table) -> &[String] {
+    &table.rows[0]
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-40288-2.rs b/src/test/compile-fail/issue-40288-2.rs
new file mode 100644 (file)
index 0000000..c1e8cb8
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2017 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 prove_static<T: 'static + ?Sized>(_: &'static T) {}
+
+fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T {
+    let mut out = [x];
+    //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements
+    {
+        let slice: &mut [_] = &mut out;
+        slice[0] = y;
+    }
+    out[0]
+}
+
+struct Struct<T, U: ?Sized> {
+    head: T,
+    _tail: U
+}
+
+fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T {
+    let mut out = Struct { head: x, _tail: [()] };
+    //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements
+    {
+        let dst: &mut Struct<_, [()]> = &mut out;
+        dst.head = y;
+    }
+    out.head
+}
+
+fn main() {
+    prove_static(lifetime_transmute_slice("", &String::from("foo")));
+    prove_static(lifetime_transmute_struct("", &String::from("bar")));
+}
diff --git a/src/test/compile-fail/issue-40288.rs b/src/test/compile-fail/issue-40288.rs
new file mode 100644 (file)
index 0000000..b5418e8
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2017 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 save_ref<'a>(refr: &'a i32, to: &mut [&'a i32]) {
+    for val in &mut *to {
+        *val = refr;
+    }
+}
+
+fn main() {
+    let ref init = 0i32;
+    let ref mut refr = 1i32;
+
+    let mut out = [init];
+
+    save_ref(&*refr, &mut out);
+
+    // This shouldn't be allowed as `refr` is borrowed
+    *refr = 3; //~ ERROR cannot assign to `*refr` because it is borrowed
+
+    // Prints 3?!
+    println!("{:?}", out[0]);
+}
diff --git a/src/test/compile-fail/lint-unused-unsafe.rs b/src/test/compile-fail/lint-unused-unsafe.rs
deleted file mode 100644 (file)
index 5c8e73e..0000000
+++ /dev/null
@@ -1,66 +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.
-
-// Exercise the unused_unsafe attribute in some positive and negative cases
-
-#![allow(dead_code)]
-#![deny(unused_unsafe)]
-
-
-mod foo {
-    extern {
-        pub fn bar();
-    }
-}
-
-fn callback<T, F>(_f: F) -> T where F: FnOnce() -> T { panic!() }
-unsafe fn unsf() {}
-
-fn bad1() { unsafe {} }                  //~ ERROR: unnecessary `unsafe` block
-fn bad2() { unsafe { bad1() } }          //~ ERROR: unnecessary `unsafe` block
-unsafe fn bad3() { unsafe {} }           //~ ERROR: unnecessary `unsafe` block
-fn bad4() { unsafe { callback(||{}) } }  //~ ERROR: unnecessary `unsafe` block
-unsafe fn bad5() { unsafe { unsf() } }   //~ ERROR: unnecessary `unsafe` block
-fn bad6() {
-    unsafe {                             // don't put the warning here
-        unsafe {                         //~ ERROR: unnecessary `unsafe` block
-            unsf()
-        }
-    }
-}
-unsafe fn bad7() {
-    unsafe {                             //~ ERROR: unnecessary `unsafe` block
-        unsafe {                         //~ ERROR: unnecessary `unsafe` block
-            unsf()
-        }
-    }
-}
-
-unsafe fn good0() { unsf() }
-fn good1() { unsafe { unsf() } }
-fn good2() {
-    /* bug uncovered when implementing warning about unused unsafe blocks. Be
-       sure that when purity is inherited that the source of the unsafe-ness
-       is tracked correctly */
-    unsafe {
-        unsafe fn what() -> Vec<String> { panic!() }
-
-        callback(|| {
-            what();
-        });
-    }
-}
-
-unsafe fn good3() { foo::bar() }
-fn good4() { unsafe { foo::bar() } }
-
-#[allow(unused_unsafe)] fn allowed() { unsafe {} }
-
-fn main() {}
index fb75b9aa1dd941ac83d9537b1f714f4c5743ad6d..e37b6a2bb9c99aa0993c5c3525edc5c322efc696 100644 (file)
@@ -79,7 +79,7 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
     // which fails to type check.
 
     ss
-        //~^ ERROR lifetime bound not satisfied
+        //~^ ERROR cannot infer
         //~| ERROR cannot infer
 }
 
index dd94dfe1e0823463701bafc0f68dba06963dc831..c0dd5200f6cb4e97be5e24eddf6f1d699f27052a 100644 (file)
@@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
     // `Box<SomeTrait>` defaults to a `'static` bound, so this return
     // is illegal.
 
-    ss.r //~ ERROR lifetime bound not satisfied
+    ss.r //~ ERROR cannot infer an appropriate lifetime
 }
 
 fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
@@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
 fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
     // Here we override the lifetimes explicitly, and so naturally we get an error.
 
-    ss.r = b; //~ ERROR lifetime bound not satisfied
+    ss.r = b; //~ ERROR cannot infer an appropriate lifetime
 }
 
 fn main() {
index c5cf43e355d5aae777bef840103e56e29cf40c33..ad6c5a31bbbd3fbc4076af08cde2723acd0992ad 100644 (file)
@@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'b> {
 
 fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> {
     // A outlives 'a AND 'b...but not 'c.
-    box v as Box<SomeTrait+'a> //~ ERROR lifetime bound not satisfied
+    box v as Box<SomeTrait+'a> //~ ERROR cannot infer an appropriate lifetime
 }
 
 fn main() {
index fb726e31af586a5ba81e434d086ccf8d3f7af9d1..17fd55b031b61463513dc077928a330bb5ffe6ac 100644 (file)
@@ -16,7 +16,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box<FnMut()->(isize) + 'a> {
 
 fn static_proc(x: &isize) -> Box<FnMut()->(isize) + 'static> {
     // This is illegal, because the region bound on `proc` is 'static.
-    Box::new(move|| { *x }) //~ ERROR does not fulfill the required lifetime
+    Box::new(move|| { *x }) //~ ERROR cannot infer an appropriate lifetime
 }
 
 fn main() { }
index b4e527972e4765b6339e457ed769e6ab1e844301..e8ada6a1755719205422e74f43591b9bf8ea138f 100644 (file)
@@ -22,8 +22,8 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) {
 
 fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
     // Without knowing 'a:'b, we can't coerce
-    x //~ ERROR lifetime bound not satisfied
-     //~^ ERROR cannot infer
+    x //~ ERROR cannot infer an appropriate lifetime
+     //~^ ERROR cannot infer an appropriate lifetime
 }
 
 struct Wrapper<T>(T);
index 1795ac95358d7c6c29c2bde494f0212b16ad6076..d3bf92e85f411a5207e03786dc844487d7417dcf 100644 (file)
@@ -21,7 +21,7 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
                                 -> Box<Get<&'min i32>>
     where 'max : 'min
 {
-    v //~ ERROR mismatched types
+    v //~ ERROR cannot infer an appropriate lifetime
 }
 
 fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
@@ -29,7 +29,7 @@ fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
     where 'max : 'min
 {
     // Previously OK:
-    v //~ ERROR mismatched types
+    v //~ ERROR cannot infer an appropriate lifetime
 }
 
 fn main() { }
index ad059a467f570bb2d4b9e5ef872d907ff1f8522c..0e94e35df2839895fdc389f970eeb6396db708e0 100644 (file)
@@ -22,14 +22,14 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
     where 'max : 'min
 {
     // Previously OK, now an error as traits are invariant.
-    v //~ ERROR mismatched types
+    v //~ ERROR cannot infer an appropriate lifetime
 }
 
 fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
                                    -> Box<Get<&'max i32>>
     where 'max : 'min
 {
-    v //~ ERROR mismatched types
+    v //~ ERROR cannot infer an appropriate lifetime
 }
 
 fn main() { }
index 9edb510b826a12df92df2fe2ea40966ca9ac98fa..aa3e06c015d503829e89c839c2beb07e52a40e4e 100644 (file)
@@ -18,14 +18,14 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
                                 -> Box<Get<&'min i32>>
     where 'max : 'min
 {
-    v //~ ERROR mismatched types
+    v //~ ERROR cannot infer an appropriate lifetime
 }
 
 fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
                                    -> Box<Get<&'max i32>>
     where 'max : 'min
 {
-    v //~ ERROR mismatched types
+    v //~ ERROR cannot infer an appropriate lifetime
 }
 
 fn main() { }
index 1d452907cf59acad2c58c4fedb74da2b66e302cb..fbbffe8953b38959a550565ba3fcd80128315e47 100644 (file)
@@ -35,7 +35,6 @@ fn main() {
 //     }
 //
 //     bb2: {
-//         StorageLive(_6);
 //         _0 = ();
 //         StorageDead(_4);
 //         StorageDead(_1);
diff --git a/src/test/run-make/dep-info-doesnt-run-much/Makefile b/src/test/run-make/dep-info-doesnt-run-much/Makefile
new file mode 100644 (file)
index 0000000..2fd8463
--- /dev/null
@@ -0,0 +1,4 @@
+-include ../tools.mk
+
+all:
+       $(RUSTC) foo.rs --emit dep-info
diff --git a/src/test/run-make/dep-info-doesnt-run-much/foo.rs b/src/test/run-make/dep-info-doesnt-run-much/foo.rs
new file mode 100644 (file)
index 0000000..3591182
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2017 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.
+
+// We're only emitting dep info, so we shouldn't be running static analysis to
+// figure out that this program is erroneous.
+fn main() {
+    let a: u8 = "a";
+}
diff --git a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs
deleted file mode 100644 (file)
index 3bc4a40..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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.
-
-// force-host
-
-#![feature(plugin_registrar, rustc_private)]
-#![feature(box_syntax)]
-
-#[macro_use] extern crate rustc;
-extern crate rustc_plugin;
-extern crate rustc_const_math;
-extern crate syntax;
-
-use rustc::mir::transform::{self, MirPass, MirSource};
-use rustc::mir::{Mir, Literal, Location};
-use rustc::mir::visit::MutVisitor;
-use rustc::ty::TyCtxt;
-use rustc::middle::const_val::ConstVal;
-use rustc_const_math::ConstInt;
-use rustc_plugin::Registry;
-
-struct Pass;
-
-impl transform::Pass for Pass {}
-
-impl<'tcx> MirPass<'tcx> for Pass {
-    fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>,
-                    _: MirSource, mir: &mut Mir<'tcx>) {
-        Visitor.visit_mir(mir)
-    }
-}
-
-struct Visitor;
-
-impl<'tcx> MutVisitor<'tcx> for Visitor {
-    fn visit_literal(&mut self, literal: &mut Literal<'tcx>, _: Location) {
-        if let Literal::Value { ref mut value } = *literal {
-            if let ConstVal::Integral(ConstInt::I32(ref mut i @ 11)) = *value {
-                *i = 42;
-            }
-        }
-    }
-}
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_mir_pass(box Pass);
-}
diff --git a/src/test/run-pass-fulldeps/mir-pass.rs b/src/test/run-pass-fulldeps/mir-pass.rs
deleted file mode 100644 (file)
index 8ac4bf9..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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:dummy_mir_pass.rs
-// ignore-stage1
-
-#![feature(plugin)]
-#![plugin(dummy_mir_pass)]
-
-fn math() -> i32 {
-    11
-}
-
-pub fn main() {
-    assert_eq!(math(), 42);
-}
diff --git a/src/test/run-pass/coerce-unsize-subtype.rs b/src/test/run-pass/coerce-unsize-subtype.rs
new file mode 100644 (file)
index 0000000..b19708f
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2017 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.
+
+// pretty-expanded FIXME #23616
+
+use std::rc::Rc;
+
+fn lub_short<'a, T>(_: &[&'a T], _: &[&'a T]) {}
+
+// The two arguments are a subtype of their LUB, after coercion.
+fn long_and_short<'a, T>(xs: &[&'static T; 1], ys: &[&'a T; 1]) {
+    lub_short(xs, ys);
+}
+
+// The argument coerces to a subtype of the return type.
+fn long_to_short<'a, 'b, T>(xs: &'b [&'static T; 1]) -> &'b [&'a T] {
+    xs
+}
+
+// Rc<T> is covariant over T just like &T.
+fn long_to_short_rc<'a, T>(xs: Rc<[&'static T; 1]>) -> Rc<[&'a T]> {
+    xs
+}
+
+// LUB-coercion (if-else/match/array) coerces `xs: &'b [&'static T: N]`
+// to a subtype of the LUB of `xs` and `ys` (i.e. `&'b [&'a T]`),
+// regardless of the order they appear (in if-else/match/array).
+fn long_and_short_lub1<'a, 'b, T>(xs: &'b [&'static T; 1], ys: &'b [&'a T]) {
+    let _order1 = [xs, ys];
+    let _order2 = [ys, xs];
+}
+
+// LUB-coercion should also have the exact same effect when `&'b [&'a T; N]`
+// needs to be coerced, i.e. the resulting type is not &'b [&'static T], but
+// rather the `&'b [&'a T]` LUB.
+fn long_and_short_lub2<'a, 'b, T>(xs: &'b [&'static T], ys: &'b [&'a T; 1]) {
+    let _order1 = [xs, ys];
+    let _order2 = [ys, xs];
+}
+
+fn main() {}
diff --git a/src/test/run-pass/issue-18446.rs b/src/test/run-pass/issue-18446.rs
new file mode 100644 (file)
index 0000000..eb321e0
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2017 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 methods in trait impls should override default methods.
+
+trait T {
+    fn foo(&self) -> i32 { 0 }
+}
+
+impl<'a> T + 'a {
+    fn foo(&self) -> i32 { 1 }
+}
+
+fn main() {}
diff --git a/src/test/run-pass/issue-23311.rs b/src/test/run-pass/issue-23311.rs
new file mode 100644 (file)
index 0000000..fc28618
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2017 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 ICE when pattern matching an array against a slice.
+
+#![feature(slice_patterns)]
+
+fn main() {
+    match "foo".as_bytes() {
+        b"food" => (),
+        &[b'f', ..] => (),
+        _ => ()
+    }
+}
diff --git a/src/test/ui/span/issue-40157.rs b/src/test/ui/span/issue-40157.rs
new file mode 100644 (file)
index 0000000..8f3a7ae
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2017 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 () {
+    {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });}
+}
diff --git a/src/test/ui/span/issue-40157.stderr b/src/test/ui/span/issue-40157.stderr
new file mode 100644 (file)
index 0000000..ad1c149
--- /dev/null
@@ -0,0 +1,14 @@
+error: `foo` does not live long enough
+  --> $DIR/issue-40157.rs:12:64
+   |
+12 |     {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });}
+   |      ----------------------------------------------------------^-------------
+   |      |                                              |          |
+   |      |                                              |          `foo` dropped here while still borrowed
+   |      |                                              borrow occurs here
+   |      borrowed value needs to live until here
+   |
+   = note: this error originates in a macro outside of the current crate
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/span/lint-unused-unsafe.rs b/src/test/ui/span/lint-unused-unsafe.rs
new file mode 100644 (file)
index 0000000..5c8e73e
--- /dev/null
@@ -0,0 +1,66 @@
+// 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.
+
+// Exercise the unused_unsafe attribute in some positive and negative cases
+
+#![allow(dead_code)]
+#![deny(unused_unsafe)]
+
+
+mod foo {
+    extern {
+        pub fn bar();
+    }
+}
+
+fn callback<T, F>(_f: F) -> T where F: FnOnce() -> T { panic!() }
+unsafe fn unsf() {}
+
+fn bad1() { unsafe {} }                  //~ ERROR: unnecessary `unsafe` block
+fn bad2() { unsafe { bad1() } }          //~ ERROR: unnecessary `unsafe` block
+unsafe fn bad3() { unsafe {} }           //~ ERROR: unnecessary `unsafe` block
+fn bad4() { unsafe { callback(||{}) } }  //~ ERROR: unnecessary `unsafe` block
+unsafe fn bad5() { unsafe { unsf() } }   //~ ERROR: unnecessary `unsafe` block
+fn bad6() {
+    unsafe {                             // don't put the warning here
+        unsafe {                         //~ ERROR: unnecessary `unsafe` block
+            unsf()
+        }
+    }
+}
+unsafe fn bad7() {
+    unsafe {                             //~ ERROR: unnecessary `unsafe` block
+        unsafe {                         //~ ERROR: unnecessary `unsafe` block
+            unsf()
+        }
+    }
+}
+
+unsafe fn good0() { unsf() }
+fn good1() { unsafe { unsf() } }
+fn good2() {
+    /* bug uncovered when implementing warning about unused unsafe blocks. Be
+       sure that when purity is inherited that the source of the unsafe-ness
+       is tracked correctly */
+    unsafe {
+        unsafe fn what() -> Vec<String> { panic!() }
+
+        callback(|| {
+            what();
+        });
+    }
+}
+
+unsafe fn good3() { foo::bar() }
+fn good4() { unsafe { foo::bar() } }
+
+#[allow(unused_unsafe)] fn allowed() { unsafe {} }
+
+fn main() {}
diff --git a/src/test/ui/span/lint-unused-unsafe.stderr b/src/test/ui/span/lint-unused-unsafe.stderr
new file mode 100644 (file)
index 0000000..0df3fa4
--- /dev/null
@@ -0,0 +1,116 @@
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:26:13
+   |
+26 | fn bad1() { unsafe {} }                  //~ ERROR: unnecessary `unsafe` block
+   |             ^^^^^^^^^ unnecessary `unsafe` block
+   |
+note: lint level defined here
+  --> $DIR/lint-unused-unsafe.rs:14:9
+   |
+14 | #![deny(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:27:13
+   |
+27 | fn bad2() { unsafe { bad1() } }          //~ ERROR: unnecessary `unsafe` block
+   |             ^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:28:20
+   |
+28 | unsafe fn bad3() { unsafe {} }           //~ ERROR: unnecessary `unsafe` block
+   |                    ^^^^^^^^^ unnecessary `unsafe` block
+   |
+note: because it's nested under this `unsafe` fn
+  --> $DIR/lint-unused-unsafe.rs:28:1
+   |
+28 | unsafe fn bad3() { unsafe {} }           //~ ERROR: unnecessary `unsafe` block
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:29:13
+   |
+29 | fn bad4() { unsafe { callback(||{}) } }  //~ ERROR: unnecessary `unsafe` block
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:30:20
+   |
+30 | unsafe fn bad5() { unsafe { unsf() } }   //~ ERROR: unnecessary `unsafe` block
+   |                    ^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block
+   |
+note: because it's nested under this `unsafe` fn
+  --> $DIR/lint-unused-unsafe.rs:30:1
+   |
+30 | unsafe fn bad5() { unsafe { unsf() } }   //~ ERROR: unnecessary `unsafe` block
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:33:9
+   |
+33 |           unsafe {                         //~ ERROR: unnecessary `unsafe` block
+   |  _________^ starting here...
+34 | |             unsf()
+35 | |         }
+   | |_________^ ...ending here: unnecessary `unsafe` block
+   |
+note: because it's nested under this `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:32:5
+   |
+32 |       unsafe {                             // don't put the warning here
+   |  _____^ starting here...
+33 | |         unsafe {                         //~ ERROR: unnecessary `unsafe` block
+34 | |             unsf()
+35 | |         }
+36 | |     }
+   | |_____^ ...ending here
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:39:5
+   |
+39 |       unsafe {                             //~ ERROR: unnecessary `unsafe` block
+   |  _____^ starting here...
+40 | |         unsafe {                         //~ ERROR: unnecessary `unsafe` block
+41 | |             unsf()
+42 | |         }
+43 | |     }
+   | |_____^ ...ending here: unnecessary `unsafe` block
+   |
+note: because it's nested under this `unsafe` fn
+  --> $DIR/lint-unused-unsafe.rs:38:1
+   |
+38 |   unsafe fn bad7() {
+   |  _^ starting here...
+39 | |     unsafe {                             //~ ERROR: unnecessary `unsafe` block
+40 | |         unsafe {                         //~ ERROR: unnecessary `unsafe` block
+41 | |             unsf()
+42 | |         }
+43 | |     }
+44 | | }
+   | |_^ ...ending here
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:40:9
+   |
+40 |           unsafe {                         //~ ERROR: unnecessary `unsafe` block
+   |  _________^ starting here...
+41 | |             unsf()
+42 | |         }
+   | |_________^ ...ending here: unnecessary `unsafe` block
+   |
+note: because it's nested under this `unsafe` fn
+  --> $DIR/lint-unused-unsafe.rs:38:1
+   |
+38 |   unsafe fn bad7() {
+   |  _^ starting here...
+39 | |     unsafe {                             //~ ERROR: unnecessary `unsafe` block
+40 | |         unsafe {                         //~ ERROR: unnecessary `unsafe` block
+41 | |             unsf()
+42 | |         }
+43 | |     }
+44 | | }
+   | |_^ ...ending here
+
+error: aborting due to 8 previous errors
+
diff --git a/src/test/ui/span/suggestion-non-ascii.rs b/src/test/ui/span/suggestion-non-ascii.rs
new file mode 100644 (file)
index 0000000..67dbe1d
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2017 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 tup = (1,);
+    println!("☃{}", tup[0]);
+}
+
diff --git a/src/test/ui/span/suggestion-non-ascii.stderr b/src/test/ui/span/suggestion-non-ascii.stderr
new file mode 100644 (file)
index 0000000..385c211
--- /dev/null
@@ -0,0 +1,11 @@
+error: cannot index a value of type `({integer},)`
+  --> $DIR/suggestion-non-ascii.rs:14:21
+   |
+14 |     println!("☃{}", tup[0]);
+   |                     ^^^^^^
+   |
+help: to access tuple elements, use tuple indexing syntax as shown
+   |     println!("☃{}", tup.0);
+
+error: aborting due to previous error
+
index ceefcc9e0ec46b80c0c07ea491f967ee96c15104..c2ec42195fcb7e16a76601780e46a10334e1ac60 100644 (file)
@@ -45,6 +45,7 @@
 
 static TARGETS: &'static [&'static str] = &[
     "aarch64-apple-ios",
+    "aarch64-unknown-fuchsia",
     "aarch64-linux-android",
     "aarch64-unknown-linux-gnu",
     "arm-linux-androideabi",
@@ -86,6 +87,7 @@
     "x86_64-pc-windows-msvc",
     "x86_64-rumprun-netbsd",
     "x86_64-unknown-freebsd",
+    "x86_64-unknown-fuchsia",
     "x86_64-unknown-linux-gnu",
     "x86_64-unknown-linux-musl",
     "x86_64-unknown-netbsd",
@@ -183,15 +185,19 @@ fn build(&mut self) {
         let mut manifest = BTreeMap::new();
         manifest.insert("manifest-version".to_string(),
                         toml::Value::String(manifest_version));
-        manifest.insert("date".to_string(), toml::Value::String(date));
+        manifest.insert("date".to_string(), toml::Value::String(date.clone()));
         manifest.insert("pkg".to_string(), toml::encode(&pkg));
         let manifest = toml::Value::Table(manifest).to_string();
 
         let filename = format!("channel-rust-{}.toml", self.rust_release);
         self.write_manifest(&manifest, &filename);
 
+        let filename = format!("channel-rust-{}-date.txt", self.rust_release);
+        self.write_date_stamp(&date, &filename);
+
         if self.rust_release != "beta" && self.rust_release != "nightly" {
             self.write_manifest(&manifest, "channel-rust-stable.toml");
+            self.write_date_stamp(&date, "channel-rust-stable-date.txt");
         }
     }
 
@@ -218,7 +224,7 @@ fn build_manifest(&mut self) -> Manifest {
         self.package("rust-docs", &mut manifest.pkg, TARGETS);
         self.package("rust-src", &mut manifest.pkg, &["*"]);
 
-        if self.channel == "nightly" {
+        if self.rust_release == "nightly" {
             self.package("rust-analysis", &mut manifest.pkg, TARGETS);
         }
 
@@ -271,7 +277,7 @@ fn build_manifest(&mut self) -> Manifest {
                         target: target.to_string(),
                     });
                 }
-                if self.channel == "nightly" {
+                if self.rust_release == "nightly" {
                     extensions.push(Component {
                         pkg: "rust-analysis".to_string(),
                         target: target.to_string(),
@@ -411,4 +417,11 @@ fn write_manifest(&self, manifest: &str, name: &str) {
         self.hash(&dst);
         self.sign(&dst);
     }
+
+    fn write_date_stamp(&self, date: &str, name: &str) {
+        let dst = self.output.join(name);
+        t!(t!(File::create(&dst)).write_all(date.as_bytes()));
+        self.hash(&dst);
+        self.sign(&dst);
+    }
 }
diff --git a/src/tools/cargo b/src/tools/cargo
deleted file mode 160000 (submodule)
index d17b61a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit d17b61aa5a2ca790f268a043bffdb0ffb04f0ec7
index 93593b97555a01e73fcd195c2550b62fa315fa6d..9b323c95fc3c8eace38e78d7a5605bd23c9b1541 100644 (file)
@@ -165,17 +165,11 @@ pub fn check(path: &Path, bad: &mut bool) {
         }
     });
 
-    // FIXME get this whitelist empty.
-    let whitelist = vec![
-        "cfg_target_thread_local", "unwind_attributes",
-    ];
-
     // Only check the number of lang features.
     // Obligatory testing for library features is dumb.
     let gate_untested = features.iter()
                                 .filter(|&(_, f)| f.level == Status::Unstable)
                                 .filter(|&(_, f)| !f.has_gate_test)
-                                .filter(|&(n, _)| !whitelist.contains(&n.as_str()))
                                 .collect::<Vec<_>>();
 
     for &(name, _) in gate_untested.iter() {