]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #32811 - alexcrichton:check-lints, r=nrc
authorbors <bors@rust-lang.org>
Tue, 12 Apr 2016 14:14:55 +0000 (07:14 -0700)
committerbors <bors@rust-lang.org>
Tue, 12 Apr 2016 14:14:55 +0000 (07:14 -0700)
rustdoc: Fix testing no_run code blocks

This was a regression introduced by #31250 where the compiler deferred returning
the results of compilation a little too late (after the `Stop` check was looked
at). This commit alters the stop point to first try to return an erroneous
`result` and only if it was successful return the sentinel `Err(0)`.

Closes #31576

173 files changed:
RELEASES.md
configure
mk/crates.mk
mk/main.mk
mk/tests.mk
src/bootstrap/Cargo.lock
src/bootstrap/build/check.rs
src/bootstrap/build/compile.rs
src/bootstrap/build/dist.rs
src/bootstrap/build/doc.rs
src/bootstrap/build/sanity.rs
src/bootstrap/build/step.rs
src/bootstrap/build/util.rs
src/build_helper/lib.rs
src/compiletest/common.rs
src/compiletest/compiletest.rs
src/compiletest/errors.rs
src/compiletest/runtest.rs
src/doc/book/concurrency.md
src/liballoc/arc.rs
src/liballoc/rc.rs
src/libcollections/btree/set.rs
src/libcollections/lib.rs
src/libcollections/slice.rs
src/libcollections/str.rs
src/libcollections/string.rs
src/libcollectionstest/lib.rs
src/libcollectionstest/str.rs
src/libcore/cell.rs
src/libcore/num/mod.rs
src/libcore/ptr.rs
src/libcore/raw.rs
src/libcore/result.rs
src/libcore/slice.rs
src/libcore/str/mod.rs
src/libcoretest/char.rs
src/libcoretest/lib.rs
src/libgetopts/lib.rs
src/librbml/lib.rs
src/librustc/dep_graph/dep_node.rs [new file with mode: 0644]
src/librustc/dep_graph/dep_tracking_map.rs
src/librustc/dep_graph/edges.rs
src/librustc/dep_graph/graph.rs [new file with mode: 0644]
src/librustc/dep_graph/mod.rs
src/librustc/dep_graph/query.rs
src/librustc/dep_graph/raii.rs
src/librustc/dep_graph/thread.rs
src/librustc/dep_graph/visit.rs [new file with mode: 0644]
src/librustc/hir/map/definitions.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/print.rs
src/librustc/hir/svh.rs
src/librustc/lib.rs
src/librustc/middle/region.rs
src/librustc/mir/visit.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc/ty/ivar.rs
src/librustc/ty/maps.rs
src/librustc/ty/mod.rs
src/librustc_back/lib.rs
src/librustc_back/target/mod.rs
src/librustc_driver/Cargo.toml
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_incremental/Cargo.toml [new file with mode: 0644]
src/librustc_incremental/assert_dep_graph.rs [new file with mode: 0644]
src/librustc_incremental/calculate_svh.rs [new file with mode: 0644]
src/librustc_incremental/lib.rs [new file with mode: 0644]
src/librustc_incremental/persist/README.md [new file with mode: 0644]
src/librustc_incremental/persist/data.rs [new file with mode: 0644]
src/librustc_incremental/persist/directory.rs [new file with mode: 0644]
src/librustc_incremental/persist/dirty_clean.rs [new file with mode: 0644]
src/librustc_incremental/persist/load.rs [new file with mode: 0644]
src/librustc_incremental/persist/mod.rs [new file with mode: 0644]
src/librustc_incremental/persist/save.rs [new file with mode: 0644]
src/librustc_incremental/persist/serialize.rs [new file with mode: 0644]
src/librustc_incremental/persist/util.rs [new file with mode: 0644]
src/librustc_lint/bad_style.rs
src/librustc_lint/lib.rs
src/librustc_metadata/decoder.rs
src/librustc_mir/transform/type_check.rs
src/librustc_resolve/resolve_imports.rs
src/librustc_trans/Cargo.toml
src/librustc_trans/abi.rs
src/librustc_trans/assert_dep_graph.rs [deleted file]
src/librustc_trans/back/link.rs
src/librustc_trans/base.rs
src/librustc_trans/cabi_aarch64.rs
src/librustc_trans/cabi_arm.rs
src/librustc_trans/cabi_mips.rs
src/librustc_trans/cabi_powerpc.rs
src/librustc_trans/cabi_powerpc64.rs
src/librustc_trans/cabi_x86.rs
src/librustc_trans/cabi_x86_64.rs
src/librustc_trans/cabi_x86_win64.rs
src/librustc_trans/context.rs
src/librustc_trans/debuginfo/metadata.rs
src/librustc_trans/lib.rs
src/librustc_trans/mir/analyze.rs
src/librustc_trans/mir/block.rs
src/librustc_trans/mir/lvalue.rs
src/librustc_trans/type_of.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/diagnostics.rs
src/librustc_unicode/char.rs
src/librustdoc/clean/mod.rs
src/librustdoc/lib.rs
src/librustdoc/passes.rs
src/librustdoc/plugins.rs
src/librustdoc/test.rs
src/libserialize/hex.rs
src/libserialize/lib.rs
src/libstd/ascii.rs
src/libstd/collections/hash/map.rs
src/libstd/collections/hash/set.rs
src/libstd/error.rs
src/libstd/ffi/os_str.rs
src/libstd/fs.rs
src/libstd/io/mod.rs
src/libstd/lib.rs
src/libstd/net/addr.rs
src/libstd/os/dragonfly/fs.rs
src/libstd/panic.rs
src/libstd/path.rs
src/libstd/rt.rs
src/libstd/sync/once.rs
src/libstd/sys/common/backtrace.rs
src/libstd/sys/common/unwind/gcc.rs
src/libstd/sys/common/wtf8.rs
src/libstd/sys/unix/ext/mod.rs
src/libstd/sys/unix/ext/process.rs
src/libstd/sys/unix/ext/thread.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/unix/time.rs
src/libstd/sys/windows/ext/thread.rs
src/libsyntax/feature_gate.rs
src/libsyntax/lib.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax_ext/asm.rs
src/libsyntax_ext/lib.rs
src/rt/rust_test_helpers.c
src/test/compile-fail/dep-graph-assoc-type-trans.rs
src/test/compile-fail/dep-graph-caller-callee.rs
src/test/compile-fail/dep-graph-struct-signature.rs
src/test/compile-fail/dep-graph-trait-impl-two-traits-same-method.rs
src/test/compile-fail/dep-graph-trait-impl-two-traits.rs
src/test/compile-fail/dep-graph-trait-impl.rs
src/test/compile-fail/dep-graph-unrelated.rs
src/test/compile-fail/deprecation-in-staged-api.rs
src/test/compile-fail/deprecation-lint.rs
src/test/compile-fail/deprecation-sanity.rs
src/test/compile-fail/extern-crate-visibility.rs
src/test/compile-fail/issue-24883.rs [new file with mode: 0644]
src/test/compile-fail/issue-26930.rs [new file with mode: 0644]
src/test/compile-fail/issue-32201.rs [new file with mode: 0644]
src/test/compile-fail/issue-32833.rs [new file with mode: 0644]
src/test/compile-fail/not-panic-safe.rs
src/test/compile-fail/placement-expr-unstable.rs
src/test/compile-fail/symbol-names/issue-32709.rs [new file with mode: 0644]
src/test/compile-fail/use-mod-2.rs
src/test/compile-fail/variadic-ffi-3.rs
src/test/incremental/dirty_clean.rs [new file with mode: 0644]
src/test/incremental/hello_world.rs [new file with mode: 0644]
src/test/incremental/string_constant.rs [new file with mode: 0644]
src/test/parse-fail/issue-32505.rs [new file with mode: 0644]
src/test/run-make/execution-engine/test.rs
src/test/run-make/rustdoc-json/Makefile [deleted file]
src/test/run-make/rustdoc-json/foo.rs [deleted file]
src/test/run-pass/cabi-int-widening.rs [new file with mode: 0644]
src/test/run-pass/panic-safe.rs
src/tools/cargotest/main.rs

index a5e307ac0d018773d304737100f976349ff5104c..5682960709ffa9024c9642110925f37f9ce08b2b 100644 (file)
@@ -1,3 +1,211 @@
+Version 1.8.0 (2016-04-14)
+==========================
+
+Language
+--------
+
+* Rust supports overloading of compound assignment statements like
+  `+=` by implementing the [`AddAssign`], [`SubAssign`],
+  [`MulAssign`], [`DivAssign`], [`RemAssign`], [`BitAndAssign`],
+  [`BitOrAssign`], [`BitXorAssign`], [`ShlAssign`], or [`ShrAssign`]
+  traits. [RFC 953].
+* Empty structs can be defined with braces, as in `struct Foo { }`, in
+  addition to the non-braced form, `struct Foo;`. [RFC 218].
+
+Libraries
+---------
+
+* Stabilized APIs:
+  * [`str::encode_utf16`][] (renamed from `utf16_units`)
+  * [`str::EncodeUtf16`][] (renamed from `Utf16Units`)
+  * [`Ref::map`]
+  * [`RefMut::map`]
+  * [`ptr::drop_in_place`]
+  * [`time::Instant`]
+  * [`time::SystemTime`]
+  * [`Instant::now`]
+  * [`Instant::duration_since`][] (renamed from `duration_from_earlier`)
+  * [`Instant::elapsed`]
+  * [`SystemTime::now`]
+  * [`SystemTime::duration_since`][] (renamed from `duration_from_earlier`)
+  * [`SystemTime::elapsed`]
+  * Various `Add`/`Sub` impls for `Time` and `SystemTime`
+  * [`SystemTimeError`]
+  * [`SystemTimeError::duration`]
+  * Various impls for `SystemTimeError`
+  * [`UNIX_EPOCH`]
+  * [`AddAssign`], [`SubAssign`], [`MulAssign`], [`DivAssign`],
+    [`RemAssign`], [`BitAndAssign`], [`BitOrAssign`],
+    [`BitXorAssign`], [`ShlAssign`], [`ShrAssign`].
+* [The `write!` and `writeln!` macros correctly emit errors if any of
+  their arguments can't be formatted][1.8w].
+* [Various I/O functions support large files on 32-bit Linux][1.8l].
+* [The Unix-specific `raw` modules, which contain a number of
+  redefined C types are deprecated][1.8r], including `os::raw::unix`,
+  `os::raw::macos`, and `os::raw::linux`. These modules defined types
+  such as `ino_t` and `dev_t`. The inconsistency of these definitions
+  across platforms was making it difficult to implement `std`
+  correctly. Those that need these definitions should use the `libc`
+  crate. [RFC 1415].
+* The Unix-specific `MetadataExt` traits, including
+  `os::unix::fs::MetadataExt`, which expose values such as inode
+  numbers [no longer return platform-specific types][1.8r], but
+  instead return widened integers. [RFC 1415].
+* [`btree_set::{IntoIter, Iter, Range}` are covariant][1.8cv].
+* [Atomic loads and stores are not volatile][1.8a].
+* [All types in `sync::mpsc` implement `fmt::Debug`][1.8mp].
+
+Performance
+-----------
+
+* [Inlining hash functions lead to a 3% compile-time improvement in
+  some workloads][1.8h].
+* When using jemalloc, its symbols are [unprefixed so that it
+  overrides the libc malloc implementation][1.8h]. This means that for
+  rustc, LLVM is now using jemalloc, which results in a 6%
+  compile-time improvement on a specific workload.
+* [Avoid quadratic growth in function size due to cleanups][1.8cu].
+
+Misc
+----
+
+* [32-bit MSVC builds finally implement unwinding][1.8ms].
+  i686-pc-windows-msvc is now considered a tier-1 platform.
+* [The `--print targets` flag prints a list of supported targets][1.8t].
+* [The `--print cfg` flag prints the `cfg`s defined for the current
+  target][1.8cf].
+* [`rustc` can be built with an new Cargo-based build system, written
+  in Rust][1.8b].  It will eventually replace Rust's Makefile-based
+  build system. To enable it configure with `configure --rustbuild`.
+* [Errors for non-exhaustive `match` patterns now list up to 3 missing
+  variants while also indicating the total number of missing variants
+  if more than 3][1.8m].
+* [Executable stacks are disabled on Linux and BSD][1.8nx].
+* The Rust Project now publishes binary releases of the standard
+  library for a number of tier-2 targets:
+  `armv7-unknown-linux-gnueabihf`, `powerpc-unknown-linux-gnu`,
+  `powerpc64-unknown-linux-gnu`, `powerpc64le-unknown-linux-gnu`
+  `x86_64-rumprun-netbsd`. These can be installed with
+  tools such as [multirust][1.8mr].
+
+Cargo
+-----
+
+* [`cargo init` creates a new Cargo project in the current
+  directory][1.8ci].  It is otherwise like `cargo new`.
+* [Cargo has configuration keys for `-v` and
+  `--color`][1.8cc]. `verbose` and `color`, respectively, go in the
+  `[term]` section of `.cargo/config`.
+* [Configuration keys that evaluate to strings or integers can be set
+  via environment variables][1.8ce]. For example the `build.jobs` key
+  can be set via `CARGO_BUILD_JOBS`. Environment variables take
+  precedence over config files.
+* [Target-specific dependencies support Rust `cfg` syntax for
+  describing targets][1.8cfg] so that dependencies for multiple
+  targets can be specified together. [RFC 1361].
+* [The environment variables `CARGO_TARGET_ROOT`, `RUSTC`, and
+  `RUSTDOC` take precedence over the `build.target-dir`,
+  `build.rustc`, and `build.rustdoc` configuration values][1.8cv].
+* [The child process tree is killed on Windows when Cargo is
+  killed][1.8ck].
+* [The `build.target` configuration value sets the target platform,
+  like `--target`][1.8ct].
+
+Compatibility Notes
+-------------------
+
+* [Unstable compiler flags have been further restricted][1.8u]. Since
+  1.0 `-Z` flags have been considered unstable, and other flags that
+  were considered unstable additionally required passing `-Z
+  unstable-options` to access. Unlike unstable language and library
+  features though, these options have been accessible on the stable
+  release channel. Going forward, *new unstable flags will not be
+  available on the stable release channel*, and old unstable flags
+  will warn about their usage. In the future, all unstable flags will
+  be unavailable on the stable release channel.
+* [It is no longer possible to `match` on empty enum variants using
+  the `Variant(..)` syntax][1.8v]. This has been a warning since 1.6.
+* The Unix-specific `MetadataExt` traits, including
+  `os::unix::fs::MetadataExt`, which expose values such as inode
+  numbers [no longer return platform-specific types][1.8r], but
+  instead return widened integers. [RFC 1415].
+* [Modules sourced from the filesystem cannot appear within arbitrary
+  blocks, but only within other modules][1.8m].
+* [`--cfg` compiler flags are parsed strictly as identifiers][1.8c].
+* On Unix, [stack overflow triggers a runtime abort instead of a
+  SIGSEGV][1.8so].
+* [`Command::spawn` and its equivalents return an error if any of
+  its command-line arguments contain interior `NUL`s][1.8n].
+* [Tuple and unit enum variants from other crates are in the type
+  namespace][1.8tn].
+* [On Windows `rustc` emits `.lib` files for the `staticlib` library
+  type instead of `.a` files][1.8st]. Additionally, for the MSVC
+  toolchain, `rustc` emits import libraries named `foo.dll.lib`
+  instead of `foo.lib`.
+
+
+[1.8a]: https://github.com/rust-lang/rust/pull/30962
+[1.8b]: https://github.com/rust-lang/rust/pull/31123
+[1.8c]: https://github.com/rust-lang/rust/pull/31530
+[1.8cc]: https://github.com/rust-lang/cargo/pull/2397
+[1.8ce]: https://github.com/rust-lang/cargo/pull/2398
+[1.8cf]: https://github.com/rust-lang/rust/pull/31278
+[1.8cfg]: https://github.com/rust-lang/cargo/pull/2328
+[1.8ci]: https://github.com/rust-lang/cargo/pull/2081
+[1.8ck]: https://github.com/rust-lang/cargo/pull/2370
+[1.8ct]: https://github.com/rust-lang/cargo/pull/2335
+[1.8cu]: https://github.com/rust-lang/rust/pull/31390
+[1.8cv]: https://github.com/rust-lang/cargo/issues/2365
+[1.8cv]: https://github.com/rust-lang/rust/pull/30998
+[1.8h]: https://github.com/rust-lang/rust/pull/31460
+[1.8l]: https://github.com/rust-lang/rust/pull/31668
+[1.8m]: https://github.com/rust-lang/rust/pull/31020
+[1.8m]: https://github.com/rust-lang/rust/pull/31534
+[1.8mp]: https://github.com/rust-lang/rust/pull/30894
+[1.8mr]: https://users.rust-lang.org/t/multirust-0-8-with-cross-std-installation/4901
+[1.8ms]: https://github.com/rust-lang/rust/pull/30448
+[1.8n]: https://github.com/rust-lang/rust/pull/31056
+[1.8nx]: https://github.com/rust-lang/rust/pull/30859
+[1.8r]: https://github.com/rust-lang/rust/pull/31551
+[1.8so]: https://github.com/rust-lang/rust/pull/31333
+[1.8st]: https://github.com/rust-lang/rust/pull/29520
+[1.8t]: https://github.com/rust-lang/rust/pull/31358
+[1.8tn]: https://github.com/rust-lang/rust/pull/30882
+[1.8u]: https://github.com/rust-lang/rust/pull/31793
+[1.8v]: https://github.com/rust-lang/rust/pull/31757
+[1.8w]: https://github.com/rust-lang/rust/pull/31904
+[RFC 1361]: https://github.com/rust-lang/rfcs/blob/master/text/1361-cargo-cfg-dependencies.md
+[RFC 1415]: https://github.com/rust-lang/rfcs/blob/master/text/1415-trim-std-os.md
+[RFC 218]: https://github.com/rust-lang/rfcs/blob/master/text/0218-empty-struct-with-braces.md
+[RFC 953]: https://github.com/rust-lang/rfcs/blob/master/text/0953-op-assign.md
+[`AddAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.AddAssign.html
+[`BitAndAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.BitAndAssign.html
+[`BitOrAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.BitOrAssign.html
+[`BitXorAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.BitXorAssign.html
+[`DivAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.DivAssign.html
+[`Instant::duration_since`]: http://doc.rust-lang.org/nightly/std/time/struct.Instant.html#method.duration_since
+[`Instant::elapsed`]: http://doc.rust-lang.org/nightly/std/time/struct.Instant.html#method.elapsed
+[`Instant::now`]: http://doc.rust-lang.org/nightly/std/time/struct.Instant.html#method.now
+[`MulAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.MulAssign.html
+[`Ref::map`]: http://doc.rust-lang.org/nightly/std/cell/struct.Ref.html#method.map
+[`RefMut::map`]: http://doc.rust-lang.org/nightly/std/cell/struct.RefMut.html#method.map
+[`RemAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.RemAssign.html
+[`ShlAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.ShlAssign.html
+[`ShrAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.ShrAssign.html
+[`SubAssign`]: http://doc.rust-lang.org/nightly/std/ops/trait.SubAssign.html
+[`SystemTime::duration_since`]: http://doc.rust-lang.org/nightly/std/time/struct.SystemTime.html#method.duration_since
+[`SystemTime::elapsed`]: http://doc.rust-lang.org/nightly/std/time/struct.SystemTime.html#method.elapsed
+[`SystemTime::now`]: http://doc.rust-lang.org/nightly/std/time/struct.SystemTime.html#method.now
+[`SystemTimeError::duration`]: http://doc.rust-lang.org/nightly/std/time/struct.SystemTimeError.html#method.duration
+[`SystemTimeError`]: http://doc.rust-lang.org/nightly/std/time/struct.SystemTimeError.html
+[`UNIX_EPOCH`]: http://doc.rust-lang.org/nightly/std/time/constant.UNIX_EPOCH.html
+[`ptr::drop_in_place`]: http://doc.rust-lang.org/nightly/std/ptr/fn.drop_in_place.html
+[`str::EncodeUtf16`]: http://doc.rust-lang.org/nightly/std/str/struct.EncodeUtf16.html
+[`str::encode_utf16`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.encode_utf16
+[`time::Instant`]: http://doc.rust-lang.org/nightly/std/time/struct.Instant.html
+[`time::SystemTime`]: http://doc.rust-lang.org/nightly/std/time/struct.SystemTime.html
+
+
 Version 1.7.0 (2016-03-03)
 ==========================
 
index da5468a0ce61dbc6657c1f727c2d1351704a4864..fdef550a6451aa520079776b0e26d3a58be8314e 100755 (executable)
--- a/configure
+++ b/configure
@@ -717,18 +717,6 @@ if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; f
 
 if [ -n "$CFG_ENABLE_ORBIT" ]; then putvar CFG_ENABLE_ORBIT; fi
 
-# A magic value that allows the compiler to use unstable features
-# during the bootstrap even when doing so would normally be an error
-# because of feature staging or because the build turns on
-# warnings-as-errors and unstable features default to warnings.  The
-# build has to match this key in an env var. Meant to be a mild
-# deterrent from users just turning on unstable features on the stable
-# channel.
-# Basing CFG_BOOTSTRAP_KEY on CFG_BOOTSTRAP_KEY lets it get picked up
-# during a Makefile reconfig.
-CFG_BOOTSTRAP_KEY="${CFG_BOOTSTRAP_KEY-`date +%H:%M:%S`}"
-putvar CFG_BOOTSTRAP_KEY
-
 step_msg "looking for build programs"
 
 probe_need CFG_CURLORWGET  curl wget
index 4c06afcae0c420534131ac6c97d1b102e6151bcf..dafda75f5fe7d883ba564bd2b5003828ab1486c3 100644 (file)
@@ -58,7 +58,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_
                 rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
                 rustc_data_structures rustc_platform_intrinsics \
                 rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \
-                rustc_const_eval rustc_const_math
+                rustc_const_eval rustc_const_math rustc_incremental
 HOST_CRATES := syntax syntax_ext $(RUSTC_CRATES) rustdoc fmt_macros \
                flate arena graphviz rbml log serialize
 TOOLS := compiletest rustdoc rustc rustbook error_index_generator
@@ -105,7 +105,8 @@ DEPS_rustc_data_structures := std log serialize
 DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
                      rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
                     rustc_trans rustc_privacy rustc_lint rustc_plugin \
-                     rustc_metadata syntax_ext rustc_passes rustc_save_analysis rustc_const_eval
+                     rustc_metadata syntax_ext rustc_passes rustc_save_analysis rustc_const_eval \
+                     rustc_incremental
 DEPS_rustc_lint := rustc log syntax rustc_const_eval
 DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
 DEPS_rustc_metadata := rustc syntax rbml rustc_const_math
@@ -117,7 +118,8 @@ DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
 DEPS_rustc_privacy := rustc log syntax
 DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
                     log syntax serialize rustc_llvm rustc_platform_intrinsics \
-                    rustc_const_math rustc_const_eval
+                    rustc_const_math rustc_const_eval rustc_incremental
+DEPS_rustc_incremental := rbml rustc serialize rustc_data_structures
 DEPS_rustc_save_analysis := rustc log syntax
 DEPS_rustc_typeck := rustc syntax rustc_platform_intrinsics rustc_const_math \
                      rustc_const_eval
index a32658ddcefdc86d76699e31e2f1714e57fe80fb..9b8080f96610f3d763acab25fe67fdf8ea82dc9c 100644 (file)
@@ -24,6 +24,17 @@ CFG_PRERELEASE_VERSION=.1
 # versions in the same place
 CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE)$(CFG_EXTRA_FILENAME) | $(CFG_HASH_COMMAND))
 
+# A magic value that allows the compiler to use unstable features during the
+# bootstrap even when doing so would normally be an error because of feature
+# staging or because the build turns on warnings-as-errors and unstable features
+# default to warnings. The build has to match this key in an env var.
+#
+# This value is keyed off the release to ensure that all compilers for one
+# particular release have the same bootstrap key. Note that this is
+# intentionally not "secure" by any definition, this is largely just a deterrent
+# from users enabling unstable features on the stable compiler.
+CFG_BOOTSTRAP_KEY=$(CFG_FILENAME_EXTRA)
+
 ifeq ($(CFG_RELEASE_CHANNEL),stable)
 # This is the normal semver version string, e.g. "0.12.0", "0.12.0-nightly"
 CFG_RELEASE=$(CFG_RELEASE_NUM)
index 1a02b5c228104dd4d6e2db4058712fdd91fe53c5..20736165b73b0beb9b441cf6f640da17687a3d55 100644 (file)
@@ -305,6 +305,7 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
        check-stage$(1)-T-$(2)-H-$(3)-doc-crates-exec \
        check-stage$(1)-T-$(2)-H-$(3)-debuginfo-gdb-exec \
        check-stage$(1)-T-$(2)-H-$(3)-debuginfo-lldb-exec \
+       check-stage$(1)-T-$(2)-H-$(3)-incremental-exec \
        check-stage$(1)-T-$(2)-H-$(3)-doc-exec \
        check-stage$(1)-T-$(2)-H-$(3)-pretty-exec
 
@@ -481,6 +482,7 @@ DEBUGINFO_LLDB_RS := $(call rwildcard,$(S)src/test/debuginfo/,*.rs)
 CODEGEN_RS := $(call rwildcard,$(S)src/test/codegen/,*.rs)
 CODEGEN_CC := $(call rwildcard,$(S)src/test/codegen/,*.cc)
 CODEGEN_UNITS_RS := $(call rwildcard,$(S)src/test/codegen-units/,*.rs)
+INCREMENTAL_RS := $(call rwildcard,$(S)src/test/incremental/,*.rs)
 RUSTDOCCK_RS := $(call rwildcard,$(S)src/test/rustdoc/,*.rs)
 
 RPASS_TESTS := $(RPASS_RS)
@@ -496,6 +498,7 @@ DEBUGINFO_GDB_TESTS := $(DEBUGINFO_GDB_RS)
 DEBUGINFO_LLDB_TESTS := $(DEBUGINFO_LLDB_RS)
 CODEGEN_TESTS := $(CODEGEN_RS) $(CODEGEN_CC)
 CODEGEN_UNITS_TESTS := $(CODEGEN_UNITS_RS)
+INCREMENTAL_TESTS := $(INCREMENTAL_RS)
 RUSTDOCCK_TESTS := $(RUSTDOCCK_RS)
 
 CTEST_SRC_BASE_rpass = run-pass
@@ -558,6 +561,11 @@ CTEST_BUILD_BASE_codegen-units = codegen-units
 CTEST_MODE_codegen-units = codegen-units
 CTEST_RUNTOOL_codegen-units = $(CTEST_RUNTOOL)
 
+CTEST_SRC_BASE_incremental = incremental
+CTEST_BUILD_BASE_incremental = incremental
+CTEST_MODE_incremental = incremental
+CTEST_RUNTOOL_incremental = $(CTEST_RUNTOOL)
+
 CTEST_SRC_BASE_rustdocck = rustdoc
 CTEST_BUILD_BASE_rustdocck = rustdoc
 CTEST_MODE_rustdocck = rustdoc
@@ -681,6 +689,7 @@ CTEST_DEPS_debuginfo-lldb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_LLDB_TESTS) \
                                                $(S)src/etc/lldb_rust_formatters.py
 CTEST_DEPS_codegen_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_TESTS)
 CTEST_DEPS_codegen-units_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_UNITS_TESTS)
+CTEST_DEPS_incremental_$(1)-T-$(2)-H-$(3) = $$(INCREMENTAL_TESTS)
 CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \
                $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
                $(S)src/etc/htmldocck.py
@@ -747,7 +756,7 @@ endif
 endef
 
 CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \
-       debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck
+       debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck incremental
 
 $(foreach host,$(CFG_HOST), \
  $(eval $(foreach target,$(CFG_TARGET), \
@@ -945,6 +954,7 @@ TEST_GROUPS = \
        debuginfo-lldb \
        codegen \
        codegen-units \
+       incremental \
        doc \
        $(foreach docname,$(DOC_NAMES),doc-$(docname)) \
        pretty \
index 05186d48ce2d1c9851f1d98a7214287695d597b3..c33838a146c2c570f01f8ab1d81e76a0fe71139f 100644 (file)
@@ -3,16 +3,16 @@ name = "bootstrap"
 version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
- "cmake 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -21,10 +21,10 @@ version = "0.1.0"
 
 [[package]]
 name = "cmake"
-version = "0.1.13"
+version = "0.1.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -32,12 +32,12 @@ name = "filetime"
 version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gcc"
-version = "0.3.25"
+version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -50,13 +50,13 @@ name = "kernel32-sys"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.6 (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 = "libc"
-version = "0.2.7"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -64,25 +64,25 @@ name = "num_cpus"
 version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "rustc-serialize"
-version = "0.3.18"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "toml"
-version = "0.1.27"
+version = "0.1.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "winapi"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
index 4e2ee4752851a7332a485da1255d4bafb49c32e4..a2445ae498a77451b960c3458706e08fcfd3c385 100644 (file)
@@ -18,9 +18,18 @@ pub fn linkcheck(build: &Build, stage: u32, host: &str) {
 }
 
 pub fn cargotest(build: &Build, stage: u32, host: &str) {
+
     let ref compiler = Compiler::new(stage, host);
+
+    // Configure PATH to find the right rustc. NB. we have to use PATH
+    // and not RUSTC because the Cargo test suite has tests that will
+    // fail if rustc is not spelled `rustc`.
+    let path = build.sysroot(compiler).join("bin");
+    let old_path = ::std::env::var("PATH").expect("");
+    let sep = if cfg!(windows) { ";" } else {":" };
+    let ref newpath = format!("{}{}{}", path.display(), sep, old_path);
+
     build.run(build.tool_cmd(compiler, "cargotest")
-              .env("RUSTC", build.compiler_path(compiler))
-              .env("RUSTDOC", build.rustdoc(compiler))
+              .env("PATH", newpath)
               .arg(&build.cargo));
 }
index dee586c76993668e09797cb0a90fc79f1dcfe066..a67f1ba48b560acbf36a5c33bd6d47163de1a1a0 100644 (file)
@@ -15,7 +15,7 @@
 
 use build_helper::output;
 
-use build::util::{exe, staticlib, libdir, mtime, is_dylib};
+use build::util::{exe, staticlib, libdir, mtime, is_dylib, copy};
 use build::{Build, Compiler, Mode};
 
 /// Build the standard library.
@@ -32,8 +32,8 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
     let libdir = build.sysroot_libdir(compiler, target);
     let _ = fs::remove_dir_all(&libdir);
     t!(fs::create_dir_all(&libdir));
-    t!(fs::hard_link(&build.compiler_rt_built.borrow()[target],
-                     libdir.join(staticlib("compiler-rt", target))));
+    copy(&build.compiler_rt_built.borrow()[target],
+         &libdir.join(staticlib("compiler-rt", target)));
 
     build_startup_objects(build, target, &libdir);
 
@@ -77,8 +77,8 @@ pub fn std_link(build: &Build,
     if host != compiler.host {
         let _ = fs::remove_dir_all(&libdir);
         t!(fs::create_dir_all(&libdir));
-        t!(fs::hard_link(&build.compiler_rt_built.borrow()[target],
-                         libdir.join(staticlib("compiler-rt", target))));
+        copy(&build.compiler_rt_built.borrow()[target],
+             &libdir.join(staticlib("compiler-rt", target)));
     }
     add_to_sysroot(&out_dir, &libdir);
 
@@ -93,7 +93,7 @@ pub fn std_link(build: &Build,
 /// Only required for musl targets that statically link to libc
 fn copy_third_party_objects(build: &Build, target: &str, into: &Path) {
     for &obj in &["crt1.o", "crti.o", "crtn.o"] {
-        t!(fs::copy(compiler_file(build.cc(target), obj), into.join(obj)));
+        copy(&compiler_file(build.cc(target), obj), &into.join(obj));
     }
 }
 
@@ -119,7 +119,7 @@ fn build_startup_objects(build: &Build, target: &str, into: &Path) {
     }
 
     for obj in ["crt2.o", "dllcrt2.o"].iter() {
-        t!(fs::copy(compiler_file(build.cc(target), obj), into.join(obj)));
+        copy(&compiler_file(build.cc(target), obj), &into.join(obj));
     }
 }
 
@@ -240,9 +240,10 @@ fn libtest_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
     build.cargo_out(compiler, Mode::Libtest, target).join("libtest_shim.rlib")
 }
 
-fn compiler_file(compiler: &Path, file: &str) -> String {
-    output(Command::new(compiler)
-                   .arg(format!("-print-file-name={}", file))).trim().to_string()
+fn compiler_file(compiler: &Path, file: &str) -> PathBuf {
+    let out = output(Command::new(compiler)
+                            .arg(format!("-print-file-name={}", file)));
+    PathBuf::from(out.trim())
 }
 
 /// Prepare a new compiler from the artifacts in `stage`
@@ -270,7 +271,7 @@ pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
     for f in t!(fs::read_dir(&src_libdir)).map(|f| t!(f)) {
         let filename = f.file_name().into_string().unwrap();
         if is_dylib(&filename) {
-            t!(fs::hard_link(&f.path(), sysroot_libdir.join(&filename)));
+            copy(&f.path(), &sysroot_libdir.join(&filename));
         }
     }
 
@@ -282,7 +283,7 @@ pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
     t!(fs::create_dir_all(&bindir));
     let compiler = build.compiler_path(&Compiler::new(stage, host));
     let _ = fs::remove_file(&compiler);
-    t!(fs::hard_link(rustc, compiler));
+    copy(&rustc, &compiler);
 
     // See if rustdoc exists to link it into place
     let rustdoc = exe("rustdoc", host);
@@ -290,7 +291,7 @@ pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
     let rustdoc_dst = bindir.join(&rustdoc);
     if fs::metadata(&rustdoc_src).is_ok() {
         let _ = fs::remove_file(&rustdoc_dst);
-        t!(fs::hard_link(&rustdoc_src, &rustdoc_dst));
+        copy(&rustdoc_src, &rustdoc_dst);
     }
 }
 
@@ -329,8 +330,7 @@ fn add_to_sysroot(out_dir: &Path, sysroot_dst: &Path) {
         let (_, path) = paths.iter().map(|path| {
             (mtime(&path).seconds(), path)
         }).max().unwrap();
-        t!(fs::hard_link(&path,
-                         sysroot_dst.join(path.file_name().unwrap())));
+        copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
     }
 }
 
index 855528ea4409fe383df5e3b44a20f7db947e9935..6ae652bd66da6f9df687c0918deb7c5cd2e15b97 100644 (file)
@@ -52,7 +52,7 @@ pub fn docs(build: &Build, stage: u32, host: &str) {
        .arg(format!("--image-dir={}", sanitize_sh(&image)))
        .arg(format!("--work-dir={}", sanitize_sh(&tmpdir(build))))
        .arg(format!("--output-dir={}", sanitize_sh(&distdir(build))))
-       .arg(format!("--package-name={}", name))
+       .arg(format!("--package-name={}-{}", name, host))
        .arg("--component-name=rust-docs")
        .arg("--legacy-manifest-dirs=rustlib,cargo")
        .arg("--bulk-dirs=share/doc/rust/html");
@@ -61,9 +61,11 @@ pub fn docs(build: &Build, stage: u32, host: &str) {
 
     // As part of this step, *also* copy the docs directory to a directory which
     // buildbot typically uploads.
-    let dst = distdir(build).join("doc").join(&build.package_vers);
-    t!(fs::create_dir_all(&dst));
-    cp_r(&src, &dst);
+    if host == build.config.build {
+        let dst = distdir(build).join("doc").join(&build.package_vers);
+        t!(fs::create_dir_all(&dst));
+        cp_r(&src, &dst);
+    }
 }
 
 pub fn mingw(build: &Build, host: &str) {
index 50c0c56807bc205361a5f3724179b341e4ae998d..5782dd5ec28dd0c23b98ee9fc0e5b75e17458774 100644 (file)
 use build::{Build, Compiler, Mode};
 use build::util::{up_to_date, cp_r};
 
-pub fn rustbook(build: &Build, stage: u32, host: &str, name: &str, out: &Path) {
+pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str, out: &Path) {
     t!(fs::create_dir_all(out));
 
     let out = out.join(name);
-    let compiler = Compiler::new(stage, host);
+    let compiler = Compiler::new(stage, &build.config.build);
     let src = build.src.join("src/doc").join(name);
     let index = out.join("index.html");
     let rustbook = build.tool(&compiler, "rustbook");
     if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
         return
     }
-    println!("Rustbook stage{} ({}) - {}", stage, host, name);
+    println!("Rustbook stage{} ({}) - {}", stage, target, name);
     let _ = fs::remove_dir_all(&out);
     build.run(build.tool_cmd(&compiler, "rustbook")
                    .arg("build")
@@ -35,11 +35,11 @@ pub fn rustbook(build: &Build, stage: u32, host: &str, name: &str, out: &Path) {
                    .arg(out));
 }
 
-pub fn standalone(build: &Build, stage: u32, host: &str, out: &Path) {
-    println!("Documenting stage{} standalone ({})", stage, host);
+pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) {
+    println!("Documenting stage{} standalone ({})", stage, target);
     t!(fs::create_dir_all(out));
 
-    let compiler = Compiler::new(stage, host);
+    let compiler = Compiler::new(stage, &build.config.build);
 
     let favicon = build.src.join("src/doc/favicon.inc");
     let footer = build.src.join("src/doc/footer.inc");
@@ -105,16 +105,17 @@ pub fn standalone(build: &Build, stage: u32, host: &str, out: &Path) {
     }
 }
 
-pub fn std(build: &Build, stage: u32, host: &str, out: &Path) {
-    println!("Documenting stage{} std ({})", stage, host);
-    let compiler = Compiler::new(stage, host);
+pub fn std(build: &Build, stage: u32, target: &str, out: &Path) {
+    println!("Documenting stage{} std ({})", stage, target);
+    t!(fs::create_dir_all(out));
+    let compiler = Compiler::new(stage, &build.config.build);
     let out_dir = build.stage_out(&compiler, Mode::Libstd)
-                       .join(host).join("doc");
+                       .join(target).join("doc");
     let rustdoc = build.rustdoc(&compiler);
 
     build.clear_if_dirty(&out_dir, &rustdoc);
 
-    let mut cargo = build.cargo(&compiler, Mode::Libstd, host, "doc");
+    let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc");
     cargo.arg("--manifest-path")
          .arg(build.src.join("src/rustc/std_shim/Cargo.toml"))
          .arg("--features").arg(build.std_features());
@@ -122,32 +123,32 @@ pub fn std(build: &Build, stage: u32, host: &str, out: &Path) {
     cp_r(&out_dir, out)
 }
 
-pub fn test(build: &Build, stage: u32, host: &str, out: &Path) {
-    println!("Documenting stage{} test ({})", stage, host);
-    let compiler = Compiler::new(stage, host);
+pub fn test(build: &Build, stage: u32, target: &str, out: &Path) {
+    println!("Documenting stage{} test ({})", stage, target);
+    let compiler = Compiler::new(stage, &build.config.build);
     let out_dir = build.stage_out(&compiler, Mode::Libtest)
-                       .join(host).join("doc");
+                       .join(target).join("doc");
     let rustdoc = build.rustdoc(&compiler);
 
     build.clear_if_dirty(&out_dir, &rustdoc);
 
-    let mut cargo = build.cargo(&compiler, Mode::Libtest, host, "doc");
+    let mut cargo = build.cargo(&compiler, Mode::Libtest, target, "doc");
     cargo.arg("--manifest-path")
          .arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
     build.run(&mut cargo);
     cp_r(&out_dir, out)
 }
 
-pub fn rustc(build: &Build, stage: u32, host: &str, out: &Path) {
-    println!("Documenting stage{} compiler ({})", stage, host);
-    let compiler = Compiler::new(stage, host);
+pub fn rustc(build: &Build, stage: u32, target: &str, out: &Path) {
+    println!("Documenting stage{} compiler ({})", stage, target);
+    let compiler = Compiler::new(stage, &build.config.build);
     let out_dir = build.stage_out(&compiler, Mode::Librustc)
-                       .join(host).join("doc");
+                       .join(target).join("doc");
     let rustdoc = build.rustdoc(&compiler);
     if !up_to_date(&rustdoc, &out_dir.join("rustc/index.html")) {
         t!(fs::remove_dir_all(&out_dir));
     }
-    let mut cargo = build.cargo(&compiler, Mode::Librustc, host, "doc");
+    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());
@@ -155,9 +156,10 @@ pub fn rustc(build: &Build, stage: u32, host: &str, out: &Path) {
     cp_r(&out_dir, out)
 }
 
-pub fn error_index(build: &Build, stage: u32, host: &str, out: &Path) {
-    println!("Documenting stage{} error index ({})", stage, host);
-    let compiler = Compiler::new(stage, host);
+pub fn error_index(build: &Build, stage: u32, target: &str, out: &Path) {
+    println!("Documenting stage{} error index ({})", stage, target);
+    t!(fs::create_dir_all(out));
+    let compiler = Compiler::new(stage, &build.config.build);
     let mut index = build.tool_cmd(&compiler, "error_index_generator");
     index.arg("html");
     index.arg(out.join("error-index.html"));
index be4416c697c561d0d796862e206bf43bf5b5307a..6ce2749638841b4e86cdc9dd64b56926bb9d257c 100644 (file)
@@ -119,4 +119,16 @@ pub fn check(build: &mut Build) {
             }
         }
     }
+
+    for host in build.flags.host.iter() {
+        if !build.config.host.contains(host) {
+            panic!("specified host `{}` is not in the ./configure list", host);
+        }
+    }
+    for target in build.flags.target.iter() {
+        if !build.config.target.contains(target) {
+            panic!("specified target `{}` is not in the ./configure list",
+                   target);
+        }
+    }
 }
index 4e3aacd3720ff7d3c607784e91dba324665068e7..80fcc32e5371d5c4504e9d911750c0b6bee139a4 100644 (file)
@@ -274,22 +274,28 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
                 vec![self.llvm(()).target(&build.config.build)]
             }
             Source::Llvm { _dummy } => Vec::new(),
+
+            // Note that all doc targets depend on artifacts from the build
+            // architecture, not the target (which is where we're generating
+            // docs into).
             Source::DocStd { stage } => {
-                vec![self.libstd(self.compiler(stage))]
+                let compiler = self.target(&build.config.build).compiler(stage);
+                vec![self.libstd(compiler)]
             }
             Source::DocTest { stage } => {
-                vec![self.libtest(self.compiler(stage))]
+                let compiler = self.target(&build.config.build).compiler(stage);
+                vec![self.libtest(compiler)]
             }
             Source::DocBook { stage } |
             Source::DocNomicon { stage } |
             Source::DocStyle { stage } => {
-                vec![self.tool_rustbook(stage)]
+                vec![self.target(&build.config.build).tool_rustbook(stage)]
             }
             Source::DocErrorIndex { stage } => {
-                vec![self.tool_error_index(stage)]
+                vec![self.target(&build.config.build).tool_error_index(stage)]
             }
             Source::DocStandalone { stage } => {
-                vec![self.rustc(stage)]
+                vec![self.target(&build.config.build).rustc(stage)]
             }
             Source::DocRustc { stage } => {
                 vec![self.doc_test(stage)]
@@ -319,7 +325,7 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
                 vec![self.librustc(self.compiler(stage))]
             }
             Source::ToolCargoTest { stage } => {
-                vec![self.libstd(self.compiler(stage))]
+                vec![self.librustc(self.compiler(stage))]
             }
 
             Source::DistDocs { stage } => vec![self.doc(stage)],
@@ -333,7 +339,6 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
 
             Source::Dist { stage } => {
                 let mut base = Vec::new();
-                base.push(self.dist_docs(stage));
 
                 for host in build.config.host.iter() {
                     let host = self.target(host);
@@ -344,7 +349,9 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
 
                     let compiler = self.compiler(stage);
                     for target in build.config.target.iter() {
-                        base.push(self.target(target).dist_std(compiler));
+                        let target = self.target(target);
+                        base.push(target.dist_docs(stage));
+                        base.push(target.dist_std(compiler));
                     }
                 }
                 return base
index 35d22ee5d2658ecedd01abc92cc22b11b4f8a7f1..41cf924d44a92dcf85ddce41ff058e3c5040398c 100644 (file)
@@ -30,6 +30,15 @@ pub fn mtime(path: &Path) -> FileTime {
     }).unwrap_or(FileTime::zero())
 }
 
+pub fn copy(src: &Path, dst: &Path) {
+    let res = fs::hard_link(src, dst);
+    let res = res.or_else(|_| fs::copy(src, dst).map(|_| ()));
+    if let Err(e) = res {
+        panic!("failed to copy `{}` to `{}`: {}", src.display(),
+               dst.display(), e)
+    }
+}
+
 pub fn cp_r(src: &Path, dst: &Path) {
     for f in t!(fs::read_dir(src)) {
         let f = t!(f);
@@ -42,7 +51,7 @@ pub fn cp_r(src: &Path, dst: &Path) {
             cp_r(&path, &dst);
         } else {
             let _ = fs::remove_file(&dst);
-            t!(fs::hard_link(&path, dst));
+            copy(&path, &dst);
         }
     }
 }
index 092a1cabc746fb8ab44139c76e565eb8be397c09..8e1da69cf02e752e2a4c5622549092408b37bd70 100644 (file)
@@ -43,10 +43,16 @@ pub fn cc2ar(cc: &Path, target: &str) -> PathBuf {
     if target.contains("musl") || target.contains("msvc") {
         PathBuf::from("ar")
     } else {
+        let parent = cc.parent().unwrap();
         let file = cc.file_name().unwrap().to_str().unwrap();
-        cc.parent().unwrap().join(file.replace("gcc", "ar")
-                                      .replace("cc", "ar")
-                                      .replace("clang", "ar"))
+        for suffix in &["gcc", "cc", "clang"] {
+            if let Some(idx) = file.rfind(suffix) {
+                let mut file = file[..idx].to_owned();
+                file.push_str("ar");
+                return parent.join(&file);
+            }
+        }
+        parent.join(file)
     }
 }
 
index bfcc1759b955d4aa6256ea5706bb3a17b4988537..a6960ff17854ecf27f0bda277f3e4c702f484f65 100644 (file)
@@ -25,7 +25,8 @@ pub enum Mode {
     DebugInfoLldb,
     Codegen,
     Rustdoc,
-    CodegenUnits
+    CodegenUnits,
+    Incremental,
 }
 
 impl FromStr for Mode {
@@ -43,6 +44,7 @@ fn from_str(s: &str) -> Result<Mode, ()> {
           "codegen" => Ok(Codegen),
           "rustdoc" => Ok(Rustdoc),
           "codegen-units" => Ok(CodegenUnits),
+          "incremental" => Ok(Incremental),
           _ => Err(()),
         }
     }
@@ -62,6 +64,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             Codegen => "codegen",
             Rustdoc => "rustdoc",
             CodegenUnits => "codegen-units",
+            Incremental => "incremental",
         }, f)
     }
 }
index 787d77bc56c3833985b584729f00553b06b5e79c..8d2558e4344e631fd1fde74c4eaea9660f50ed66 100644 (file)
@@ -13,7 +13,6 @@
 #![feature(box_syntax)]
 #![feature(libc)]
 #![feature(rustc_private)]
-#![feature(str_char)]
 #![feature(test)]
 #![feature(question_mark)]
 
@@ -71,7 +70,8 @@ pub fn parse_config(args: Vec<String> ) -> Config {
           reqopt("", "aux-base", "directory to find auxiliary test files", "PATH"),
           reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"),
           reqopt("", "mode", "which sort of compile tests to run",
-                 "(compile-fail|parse-fail|run-fail|run-pass|run-pass-valgrind|pretty|debug-info)"),
+                 "(compile-fail|parse-fail|run-fail|run-pass|\
+                  run-pass-valgrind|pretty|debug-info|incremental)"),
           optflag("", "ignored", "run tests marked as ignored"),
           optopt("", "runtool", "supervisor program to run tests under \
                                  (eg. emulator, valgrind)", "PROGRAM"),
@@ -411,16 +411,26 @@ fn extract_gdb_version(full_version_line: Option<String>) -> Option<String> {
 
             // used to be a regex "(^|[^0-9])([0-9]\.[0-9]+)"
             for (pos, c) in full_version_line.char_indices() {
-                if !c.is_digit(10) { continue }
-                if pos + 2 >= full_version_line.len() { continue }
-                if full_version_line.char_at(pos + 1) != '.' { continue }
-                if !full_version_line.char_at(pos + 2).is_digit(10) { continue }
-                if pos > 0 && full_version_line.char_at_reverse(pos).is_digit(10) {
+                if !c.is_digit(10) {
+                    continue
+                }
+                if pos + 2 >= full_version_line.len() {
+                    continue
+                }
+                if full_version_line[pos + 1..].chars().next().unwrap() != '.' {
+                    continue
+                }
+                if !full_version_line[pos + 2..].chars().next().unwrap().is_digit(10) {
+                    continue
+                }
+                if pos > 0 && full_version_line[..pos].chars().next_back()
+                                                      .unwrap().is_digit(10) {
                     continue
                 }
                 let mut end = pos + 3;
                 while end < full_version_line.len() &&
-                      full_version_line.char_at(end).is_digit(10) {
+                      full_version_line[end..].chars().next()
+                                              .unwrap().is_digit(10) {
                     end += 1;
                 }
                 return Some(full_version_line[pos..end].to_owned());
@@ -452,13 +462,13 @@ fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
             for (pos, l) in full_version_line.char_indices() {
                 if l != 'l' && l != 'L' { continue }
                 if pos + 5 >= full_version_line.len() { continue }
-                let l = full_version_line.char_at(pos + 1);
+                let l = full_version_line[pos + 1..].chars().next().unwrap();
                 if l != 'l' && l != 'L' { continue }
-                let d = full_version_line.char_at(pos + 2);
+                let d = full_version_line[pos + 2..].chars().next().unwrap();
                 if d != 'd' && d != 'D' { continue }
-                let b = full_version_line.char_at(pos + 3);
+                let b = full_version_line[pos + 3..].chars().next().unwrap();
                 if b != 'b' && b != 'B' { continue }
-                let dash = full_version_line.char_at(pos + 4);
+                let dash = full_version_line[pos + 4..].chars().next().unwrap();
                 if dash != '-' { continue }
 
                 let vers = full_version_line[pos + 5..].chars().take_while(|c| {
index 7ad0cd2a95d4bedd8b7966b4f0af52c5cd5bcff8..418a0bc7121cbd624be4797e47fd78b5226b59be 100644 (file)
@@ -115,7 +115,7 @@ fn parse_expected(last_nonfollow_error: Option<usize>,
                   tag: &str)
                   -> Option<(WhichLine, ExpectedError)> {
     let start = match line.find(tag) { Some(i) => i, None => return None };
-    let (follow, adjusts) = if line.char_at(start + tag.len()) == '|' {
+    let (follow, adjusts) = if line[start + tag.len()..].chars().next().unwrap() == '|' {
         (true, 0)
     } else {
         (false, line[start + tag.len()..].chars().take_while(|c| *c == '^').count())
index 24fd413ef09c2df7c58ac346af9eb5c4e626a120..6773c34c7d76da8cadaafb314c9e2f3bbfdc3364 100644 (file)
@@ -11,6 +11,7 @@
 use common::Config;
 use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
 use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits};
+use common::{Incremental};
 use errors::{self, ErrorKind};
 use header::TestProps;
 use header;
@@ -59,6 +60,7 @@ pub fn run(config: Config, testpaths: &TestPaths) {
         Codegen => run_codegen_test(&config, &props, &testpaths),
         Rustdoc => run_rustdoc_test(&config, &props, &testpaths),
         CodegenUnits => run_codegen_units_test(&config, &props, &testpaths),
+        Incremental => run_incremental_test(&config, &props, &testpaths),
     }
 }
 
@@ -1175,7 +1177,7 @@ fn scan_char(haystack: &str, needle: char, idx: &mut usize) -> bool {
     if *idx >= haystack.len() {
         return false;
     }
-    let ch = haystack.char_at(*idx);
+    let ch = haystack[*idx..].chars().next().unwrap();
     if ch != needle {
         return false;
     }
@@ -1186,7 +1188,7 @@ fn scan_char(haystack: &str, needle: char, idx: &mut usize) -> bool {
 fn scan_integer(haystack: &str, idx: &mut usize) -> bool {
     let mut i = *idx;
     while i < haystack.len() {
-        let ch = haystack.char_at(i);
+        let ch = haystack[i..].chars().next().unwrap();
         if ch < '0' || '9' < ch {
             break;
         }
@@ -1206,7 +1208,7 @@ fn scan_string(haystack: &str, needle: &str, idx: &mut usize) -> bool {
         if haystack_i >= haystack.len() {
             return false;
         }
-        let ch = haystack.char_at(haystack_i);
+        let ch = haystack[haystack_i..].chars().next().unwrap();
         haystack_i += ch.len_utf8();
         if !scan_char(needle, ch, &mut needle_i) {
             return false;
@@ -1966,3 +1968,67 @@ fn run_codegen_units_test(config: &Config, props: &TestProps, testpaths: &TestPa
         panic!();
     }
 }
+
+fn run_incremental_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
+    // Basic plan for a test incremental/foo/bar.rs:
+    // - load list of revisions pass1, fail2, pass3
+    //   - each should begin with `rpass`, `rfail`, or `cfail`
+    //   - if `rpass`, expect compile and execution to succeed
+    //   - if `cfail`, expect compilation to fail
+    //   - if `rfail`, expect execution to fail
+    // - create a directory build/foo/bar.incremental
+    // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C pass1
+    //   - because name of revision starts with "pass", expect success
+    // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C fail2
+    //   - because name of revision starts with "fail", expect an error
+    //   - load expected errors as usual, but filter for those that end in `[fail2]`
+    // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C pass3
+    //   - because name of revision starts with "pass", expect success
+    // - execute build/foo/bar.exe and save output
+    //
+    // FIXME -- use non-incremental mode as an oracle? That doesn't apply
+    // to #[rustc_dirty] and clean tests I guess
+
+    assert!(!props.revisions.is_empty(), "incremental tests require a list of revisions");
+
+    let output_base_name = output_base_name(config, testpaths);
+
+    // Create the incremental workproduct directory.
+    let incremental_dir = output_base_name.with_extension("incremental");
+    if incremental_dir.exists() {
+        fs::remove_dir_all(&incremental_dir).unwrap();
+    }
+    fs::create_dir_all(&incremental_dir).unwrap();
+
+    if config.verbose {
+        print!("incremental_dir={}", incremental_dir.display());
+    }
+
+    for revision in &props.revisions {
+        let mut revision_props = props.clone();
+        header::load_props_into(&mut revision_props, &testpaths.file, Some(&revision));
+
+        revision_props.compile_flags.extend(vec![
+            format!("-Z"),
+            format!("incremental={}", incremental_dir.display()),
+            format!("--cfg"),
+            format!("{}", revision),
+        ]);
+
+        if config.verbose {
+            print!("revision={:?} revision_props={:#?}", revision, revision_props);
+        }
+
+        if revision.starts_with("rpass") {
+            run_rpass_test_revision(config, &revision_props, testpaths, Some(&revision));
+        } else if revision.starts_with("rfail") {
+            run_rfail_test_revision(config, &revision_props, testpaths, Some(&revision));
+        } else if revision.starts_with("cfail") {
+            run_cfail_test_revision(config, &revision_props, testpaths, Some(&revision));
+        } else {
+            fatal(
+                Some(revision),
+                "revision name must begin with rpass, rfail, or cfail");
+        }
+    }
+}
index ba4496b93f3a18be9a7fbf86a7b23a075a75b236..c179629a79a720d724952e2ef0ef1b636b0ff0eb 100644 (file)
@@ -162,7 +162,7 @@ The same [ownership system](ownership.html) that helps prevent using pointers
 incorrectly also helps rule out data races, one of the worst kinds of
 concurrency bugs.
 
-As an example, here is a Rust program that could have a data race in many
+As an example, here is a Rust program that would have a data race in many
 languages. It will not compile:
 
 ```ignore
@@ -174,7 +174,7 @@ fn main() {
 
     for i in 0..3 {
         thread::spawn(move || {
-            data[i] += 1;
+            data[0] += i;
         });
     }
 
@@ -186,7 +186,7 @@ This gives us an error:
 
 ```text
 8:17 error: capture of moved value: `data`
-        data[i] += 1;
+        data[0] += i;
         ^~~~
 ```
 
@@ -195,11 +195,6 @@ thread, and the thread takes ownership of the reference, we'd have three owners!
 `data` gets moved out of `main` in the first call to `spawn()`, so subsequent
 calls in the loop cannot use this variable.
 
-Note that this specific example will not cause a data race since different array
-indices are being accessed. But this can't be determined at compile time, and in
-a similar situation where `i` is a constant or is random, you would have a data
-race.
-
 So, we need some type that lets us have more than one owning reference to a
 value. Usually, we'd use `Rc<T>` for this, which is a reference counted type
 that provides shared ownership. It has some runtime bookkeeping that keeps track
@@ -223,7 +218,7 @@ fn main() {
 
         // use it in a thread
         thread::spawn(move || {
-            data_ref[i] += 1;
+            data_ref[0] += i;
         });
     }
 
@@ -266,7 +261,7 @@ fn main() {
     for i in 0..3 {
         let data = data.clone();
         thread::spawn(move || {
-            data[i] += 1;
+            data[0] += i;
         });
     }
 
@@ -281,7 +276,7 @@ And... still gives us an error.
 
 ```text
 <anon>:11:24 error: cannot borrow immutable borrowed content as mutable
-<anon>:11                    data[i] += 1;
+<anon>:11                    data[0] += i;
                              ^~~~
 ```
 
@@ -317,7 +312,7 @@ fn main() {
         let data = data.clone();
         thread::spawn(move || {
             let mut data = data.lock().unwrap();
-            data[i] += 1;
+            data[0] += i;
         });
     }
 
@@ -360,7 +355,7 @@ Let's examine the body of the thread more closely:
 #         let data = data.clone();
 thread::spawn(move || {
     let mut data = data.lock().unwrap();
-    data[i] += 1;
+    data[0] += i;
 });
 #     }
 #     thread::sleep(Duration::from_millis(50));
index e1f698cb484c1ef3cd2604e5c4112b04cee226be..4aba567fa1c202215b361bba0db7ea1b6f913124 100644 (file)
 #[unsafe_no_drop_flag]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Arc<T: ?Sized> {
-    // FIXME #12808: strange name to try to avoid interfering with
-    // field accesses of the contained type via Deref
-    _ptr: Shared<ArcInner<T>>,
+    ptr: Shared<ArcInner<T>>,
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -144,9 +142,7 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
 #[unsafe_no_drop_flag]
 #[stable(feature = "arc_weak", since = "1.4.0")]
 pub struct Weak<T: ?Sized> {
-    // FIXME #12808: strange name to try to avoid interfering with
-    // field accesses of the contained type via Deref
-    _ptr: Shared<ArcInner<T>>,
+    ptr: Shared<ArcInner<T>>,
 }
 
 #[stable(feature = "arc_weak", since = "1.4.0")]
@@ -198,7 +194,7 @@ pub fn new(data: T) -> Arc<T> {
             weak: atomic::AtomicUsize::new(1),
             data: data,
         };
-        Arc { _ptr: unsafe { Shared::new(Box::into_raw(x)) } }
+        Arc { ptr: unsafe { Shared::new(Box::into_raw(x)) } }
     }
 
     /// Unwraps the contained value if the `Arc<T>` has exactly one strong reference.
@@ -230,11 +226,11 @@ pub fn try_unwrap(this: Self) -> Result<T, Self> {
         atomic::fence(Acquire);
 
         unsafe {
-            let ptr = *this._ptr;
+            let ptr = *this.ptr;
             let elem = ptr::read(&(*ptr).data);
 
             // Make a weak pointer to clean up the implicit strong-weak reference
-            let _weak = Weak { _ptr: this._ptr };
+            let _weak = Weak { ptr: this.ptr };
             mem::forget(this);
 
             Ok(elem)
@@ -275,7 +271,7 @@ pub fn downgrade(this: &Self) -> Weak<T> {
             // synchronize with the write coming from `is_unique`, so that the
             // events prior to that write happen before this read.
             match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) {
-                Ok(_) => return Weak { _ptr: this._ptr },
+                Ok(_) => return Weak { ptr: this.ptr },
                 Err(old) => cur = old,
             }
         }
@@ -304,13 +300,13 @@ fn inner(&self) -> &ArcInner<T> {
         // `ArcInner` structure itself is `Sync` because the inner data is
         // `Sync` as well, so we're ok loaning out an immutable pointer to these
         // contents.
-        unsafe { &**self._ptr }
+        unsafe { &**self.ptr }
     }
 
     // Non-inlined part of `drop`.
     #[inline(never)]
     unsafe fn drop_slow(&mut self) {
-        let ptr = *self._ptr;
+        let ptr = *self.ptr;
 
         // Destroy the data at this time, even though we may not free the box
         // allocation itself (there may still be weak pointers lying around).
@@ -368,7 +364,7 @@ fn clone(&self) -> Arc<T> {
             }
         }
 
-        Arc { _ptr: self._ptr }
+        Arc { ptr: self.ptr }
     }
 }
 
@@ -436,7 +432,7 @@ pub fn make_mut(this: &mut Self) -> &mut T {
 
             // Materialize our own implicit weak pointer, so that it can clean
             // up the ArcInner as needed.
-            let weak = Weak { _ptr: this._ptr };
+            let weak = Weak { ptr: this.ptr };
 
             // mark the data itself as already deallocated
             unsafe {
@@ -444,7 +440,7 @@ pub fn make_mut(this: &mut Self) -> &mut T {
                 // here (due to zeroing) because data is no longer accessed by
                 // other threads (due to there being no more strong refs at this
                 // point).
-                let mut swap = Arc::new(ptr::read(&(**weak._ptr).data));
+                let mut swap = Arc::new(ptr::read(&(**weak.ptr).data));
                 mem::swap(this, &mut swap);
                 mem::forget(swap);
             }
@@ -457,7 +453,7 @@ pub fn make_mut(this: &mut Self) -> &mut T {
         // As with `get_mut()`, the unsafety is ok because our reference was
         // either unique to begin with, or became one upon cloning the contents.
         unsafe {
-            let inner = &mut **this._ptr;
+            let inner = &mut **this.ptr;
             &mut inner.data
         }
     }
@@ -489,7 +485,7 @@ pub fn get_mut(this: &mut Self) -> Option<&mut T> {
             // the Arc itself to be `mut`, so we're returning the only possible
             // reference to the inner data.
             unsafe {
-                let inner = &mut **this._ptr;
+                let inner = &mut **this.ptr;
                 Some(&mut inner.data)
             }
         } else {
@@ -558,7 +554,7 @@ fn drop(&mut self) {
         // This structure has #[unsafe_no_drop_flag], so this drop glue may run
         // more than once (but it is guaranteed to be zeroed after the first if
         // it's run more than once)
-        let thin = *self._ptr as *const ();
+        let thin = *self.ptr as *const ();
 
         if thin as usize == mem::POST_DROP_USIZE {
             return;
@@ -639,7 +635,7 @@ pub fn upgrade(&self) -> Option<Arc<T>> {
 
             // Relaxed is valid for the same reason it is on Arc's Clone impl
             match inner.strong.compare_exchange_weak(n, n + 1, Relaxed, Relaxed) {
-                Ok(_) => return Some(Arc { _ptr: self._ptr }),
+                Ok(_) => return Some(Arc { ptr: self.ptr }),
                 Err(old) => n = old,
             }
         }
@@ -648,7 +644,7 @@ pub fn upgrade(&self) -> Option<Arc<T>> {
     #[inline]
     fn inner(&self) -> &ArcInner<T> {
         // See comments above for why this is "safe"
-        unsafe { &**self._ptr }
+        unsafe { &**self.ptr }
     }
 }
 
@@ -682,7 +678,7 @@ fn clone(&self) -> Weak<T> {
             }
         }
 
-        return Weak { _ptr: self._ptr };
+        return Weak { ptr: self.ptr };
     }
 }
 
@@ -714,7 +710,7 @@ impl<T: ?Sized> Drop for Weak<T> {
     /// } // implicit drop
     /// ```
     fn drop(&mut self) {
-        let ptr = *self._ptr;
+        let ptr = *self.ptr;
         let thin = ptr as *const ();
 
         // see comments above for why this check is here
@@ -886,7 +882,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> fmt::Pointer for Arc<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Pointer::fmt(&*self._ptr, f)
+        fmt::Pointer::fmt(&*self.ptr, f)
     }
 }
 
@@ -931,7 +927,7 @@ impl<T> Weak<T> {
                issue = "30425")]
     pub fn new() -> Weak<T> {
         unsafe {
-            Weak { _ptr: Shared::new(Box::into_raw(box ArcInner {
+            Weak { ptr: Shared::new(Box::into_raw(box ArcInner {
                 strong: atomic::AtomicUsize::new(0),
                 weak: atomic::AtomicUsize::new(1),
                 data: uninitialized(),
index da803f57a59d3a2324ca9e0189975861745ab61b..c2f0a96132733221514a09f067ad59e8b4aca1a8 100644 (file)
@@ -184,9 +184,7 @@ struct RcBox<T: ?Sized> {
 #[unsafe_no_drop_flag]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Rc<T: ?Sized> {
-    // FIXME #12808: strange names to try to avoid interfering with field
-    // accesses of the contained type via Deref
-    _ptr: Shared<RcBox<T>>,
+    ptr: Shared<RcBox<T>>,
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -215,7 +213,7 @@ pub fn new(value: T) -> Rc<T> {
                 // pointers, which ensures that the weak destructor never frees
                 // the allocation while the strong destructor is running, even
                 // if the weak pointer is stored inside the strong one.
-                _ptr: Shared::new(Box::into_raw(box RcBox {
+                ptr: Shared::new(Box::into_raw(box RcBox {
                     strong: Cell::new(1),
                     weak: Cell::new(1),
                     value: value,
@@ -254,7 +252,7 @@ pub fn try_unwrap(this: Self) -> Result<T, Self> {
                 // pointer while also handling drop logic by just crafting a
                 // fake Weak.
                 this.dec_strong();
-                let _weak = Weak { _ptr: this._ptr };
+                let _weak = Weak { ptr: this.ptr };
                 forget(this);
                 Ok(val)
             }
@@ -287,7 +285,7 @@ impl<T: ?Sized> Rc<T> {
     #[stable(feature = "rc_weak", since = "1.4.0")]
     pub fn downgrade(this: &Self) -> Weak<T> {
         this.inc_weak();
-        Weak { _ptr: this._ptr }
+        Weak { ptr: this.ptr }
     }
 
     /// Get the number of weak references to this value.
@@ -348,7 +346,7 @@ pub fn is_unique(this: &Self) -> bool {
     #[stable(feature = "rc_unique", since = "1.4.0")]
     pub fn get_mut(this: &mut Self) -> Option<&mut T> {
         if Rc::is_unique(this) {
-            let inner = unsafe { &mut **this._ptr };
+            let inner = unsafe { &mut **this.ptr };
             Some(&mut inner.value)
         } else {
             None
@@ -390,7 +388,7 @@ pub fn make_mut(this: &mut Self) -> &mut T {
         } else if Rc::weak_count(this) != 0 {
             // Can just steal the data, all that's left is Weaks
             unsafe {
-                let mut swap = Rc::new(ptr::read(&(**this._ptr).value));
+                let mut swap = Rc::new(ptr::read(&(**this.ptr).value));
                 mem::swap(this, &mut swap);
                 swap.dec_strong();
                 // Remove implicit strong-weak ref (no need to craft a fake
@@ -404,7 +402,7 @@ pub fn make_mut(this: &mut Self) -> &mut T {
         // reference count is guaranteed to be 1 at this point, and we required
         // the `Rc<T>` itself to be `mut`, so we're returning the only possible
         // reference to the inner value.
-        let inner = unsafe { &mut **this._ptr };
+        let inner = unsafe { &mut **this.ptr };
         &mut inner.value
     }
 }
@@ -449,7 +447,7 @@ impl<T: ?Sized> Drop for Rc<T> {
     #[unsafe_destructor_blind_to_params]
     fn drop(&mut self) {
         unsafe {
-            let ptr = *self._ptr;
+            let ptr = *self.ptr;
             let thin = ptr as *const ();
 
             if thin as usize != mem::POST_DROP_USIZE {
@@ -490,7 +488,7 @@ impl<T: ?Sized> Clone for Rc<T> {
     #[inline]
     fn clone(&self) -> Rc<T> {
         self.inc_strong();
-        Rc { _ptr: self._ptr }
+        Rc { ptr: self.ptr }
     }
 }
 
@@ -691,7 +689,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> fmt::Pointer for Rc<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Pointer::fmt(&*self._ptr, f)
+        fmt::Pointer::fmt(&*self.ptr, f)
     }
 }
 
@@ -711,9 +709,7 @@ fn from(t: T) -> Self {
 #[unsafe_no_drop_flag]
 #[stable(feature = "rc_weak", since = "1.4.0")]
 pub struct Weak<T: ?Sized> {
-    // FIXME #12808: strange names to try to avoid interfering with
-    // field accesses of the contained type via Deref
-    _ptr: Shared<RcBox<T>>,
+    ptr: Shared<RcBox<T>>,
 }
 
 #[stable(feature = "rc_weak", since = "1.4.0")]
@@ -749,7 +745,7 @@ pub fn upgrade(&self) -> Option<Rc<T>> {
             None
         } else {
             self.inc_strong();
-            Some(Rc { _ptr: self._ptr })
+            Some(Rc { ptr: self.ptr })
         }
     }
 }
@@ -783,7 +779,7 @@ impl<T: ?Sized> Drop for Weak<T> {
     /// ```
     fn drop(&mut self) {
         unsafe {
-            let ptr = *self._ptr;
+            let ptr = *self.ptr;
             let thin = ptr as *const ();
 
             if thin as usize != mem::POST_DROP_USIZE {
@@ -816,7 +812,7 @@ impl<T: ?Sized> Clone for Weak<T> {
     #[inline]
     fn clone(&self) -> Weak<T> {
         self.inc_weak();
-        Weak { _ptr: self._ptr }
+        Weak { ptr: self.ptr }
     }
 }
 
@@ -848,7 +844,7 @@ impl<T> Weak<T> {
     pub fn new() -> Weak<T> {
         unsafe {
             Weak {
-                _ptr: Shared::new(Box::into_raw(box RcBox {
+                ptr: Shared::new(Box::into_raw(box RcBox {
                     strong: Cell::new(0),
                     weak: Cell::new(1),
                     value: uninitialized(),
@@ -910,8 +906,8 @@ fn inner(&self) -> &RcBox<T> {
             // the contract anyway.
             // This allows the null check to be elided in the destructor if we
             // manipulated the reference count in the same function.
-            assume(!(*(&self._ptr as *const _ as *const *const ())).is_null());
-            &(**self._ptr)
+            assume(!(*(&self.ptr as *const _ as *const *const ())).is_null());
+            &(**self.ptr)
         }
     }
 }
@@ -924,8 +920,8 @@ fn inner(&self) -> &RcBox<T> {
             // the contract anyway.
             // This allows the null check to be elided in the destructor if we
             // manipulated the reference count in the same function.
-            assume(!(*(&self._ptr as *const _ as *const *const ())).is_null());
-            &(**self._ptr)
+            assume(!(*(&self.ptr as *const _ as *const *const ())).is_null());
+            &(**self.ptr)
         }
     }
 }
index 23e0af8113bf11f95d5dd8445e04b39b9562283d..e679381f223f8a97624c21efefbc1f49b9d28c90 100644 (file)
@@ -379,7 +379,7 @@ pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool
     /// The value may be any borrowed form of the set's value type,
     /// but the ordering on the borrowed form *must* match the
     /// ordering on the value type.
-    #[unstable(feature = "set_recovery", issue = "28050")]
+    #[stable(feature = "set_recovery", since = "1.9.0")]
     pub fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T>
         where T: Borrow<Q>,
               Q: Ord
@@ -502,7 +502,7 @@ pub fn insert(&mut self, value: T) -> bool {
 
     /// Adds a value to the set, replacing the existing value, if any, that is equal to the given
     /// one. Returns the replaced value.
-    #[unstable(feature = "set_recovery", issue = "28050")]
+    #[stable(feature = "set_recovery", since = "1.9.0")]
     pub fn replace(&mut self, value: T) -> Option<T> {
         Recover::replace(&mut self.map, value)
     }
@@ -538,7 +538,7 @@ pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool
     /// The value may be any borrowed form of the set's value type,
     /// but the ordering on the borrowed form *must* match the
     /// ordering on the value type.
-    #[unstable(feature = "set_recovery", issue = "28050")]
+    #[stable(feature = "set_recovery", since = "1.9.0")]
     pub fn take<Q: ?Sized>(&mut self, value: &Q) -> Option<T>
         where T: Borrow<Q>,
               Q: Ord
index 8e62b389a6e3f290f701eed42683531bb6628b1c..7540c51e236d226b18343352e9bce5649d6d6d1b 100644 (file)
@@ -27,7 +27,6 @@
        test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
 
 #![cfg_attr(test, allow(deprecated))] // rand
-#![cfg_attr(not(test), feature(copy_from_slice))] // impl [T]
 #![cfg_attr(not(stage0), deny(warnings))]
 
 #![feature(alloc)]
@@ -35,7 +34,6 @@
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(core_intrinsics)]
-#![feature(decode_utf16)]
 #![feature(dropck_parametricity)]
 #![feature(fmt_internals)]
 #![feature(heap_api)]
index 8fa594c967cf7c0c54715706c0fdc09a57270cb2..db91d911c7355d0a68b07bb2b70ac073a406953c 100644 (file)
@@ -845,14 +845,13 @@ pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
     /// # Example
     ///
     /// ```rust
-    /// #![feature(copy_from_slice)]
     /// let mut dst = [0, 0, 0];
     /// let src = [1, 2, 3];
     ///
     /// dst.copy_from_slice(&src);
     /// assert_eq!(src, dst);
     /// ```
-    #[unstable(feature = "copy_from_slice", issue = "31755")]
+    #[stable(feature = "copy_from_slice", since = "1.9.0")]
     pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy {
         core_slice::SliceExt::copy_from_slice(self, src)
     }
index 9798e323a6140c782c6cb8606e3686fe339d1dff..b2b1e019a1b899f1887c2e436ac87993b177154d 100644 (file)
@@ -228,8 +228,6 @@ pub fn is_empty(&self) -> bool {
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_char)]
-    ///
     /// let s = "Löwe 老虎 Léopard";
     /// assert!(s.is_char_boundary(0));
     /// // start of `老`
@@ -242,12 +240,7 @@ pub fn is_empty(&self) -> bool {
     /// // third byte of `老`
     /// assert!(!s.is_char_boundary(8));
     /// ```
-    #[unstable(feature = "str_char",
-               reason = "it is unclear whether this method pulls its weight \
-                         with the existence of the char_indices iterator or \
-                         this method may want to be replaced with checked \
-                         slicing",
-               issue = "27754")]
+    #[stable(feature = "is_char_boundary", since = "1.9.0")]
     #[inline]
     pub fn is_char_boundary(&self, index: usize) -> bool {
         core_str::StrExt::is_char_boundary(self, index)
@@ -374,6 +367,7 @@ pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut s
     ///
     /// ```
     /// #![feature(str_char)]
+    /// #![allow(deprecated)]
     ///
     /// use std::str::CharRange;
     ///
@@ -408,6 +402,9 @@ pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut s
                          removed altogether",
                issue = "27754")]
     #[inline]
+    #[rustc_deprecated(reason = "use slicing plus chars() plus len_utf8",
+                       since = "1.9.0")]
+    #[allow(deprecated)]
     pub fn char_range_at(&self, start: usize) -> CharRange {
         core_str::StrExt::char_range_at(self, start)
     }
@@ -432,6 +429,7 @@ pub fn char_range_at(&self, start: usize) -> CharRange {
     ///
     /// ```
     /// #![feature(str_char)]
+    /// #![allow(deprecated)]
     ///
     /// use std::str::CharRange;
     ///
@@ -466,6 +464,9 @@ pub fn char_range_at(&self, start: usize) -> CharRange {
                          eventually removed altogether",
                issue = "27754")]
     #[inline]
+    #[rustc_deprecated(reason = "use slicing plus chars().rev() plus len_utf8",
+                       since = "1.9.0")]
+    #[allow(deprecated)]
     pub fn char_range_at_reverse(&self, start: usize) -> CharRange {
         core_str::StrExt::char_range_at_reverse(self, start)
     }
@@ -481,6 +482,7 @@ pub fn char_range_at_reverse(&self, start: usize) -> CharRange {
     ///
     /// ```
     /// #![feature(str_char)]
+    /// #![allow(deprecated)]
     ///
     /// let s = "abπc";
     /// assert_eq!(s.char_at(1), 'b');
@@ -495,6 +497,9 @@ pub fn char_range_at_reverse(&self, start: usize) -> CharRange {
                          subslice",
                issue = "27754")]
     #[inline]
+    #[allow(deprecated)]
+    #[rustc_deprecated(reason = "use slicing plus chars()",
+                       since = "1.9.0")]
     pub fn char_at(&self, i: usize) -> char {
         core_str::StrExt::char_at(self, i)
     }
@@ -511,6 +516,7 @@ pub fn char_at(&self, i: usize) -> char {
     ///
     /// ```
     /// #![feature(str_char)]
+    /// #![allow(deprecated)]
     ///
     /// let s = "abπc";
     /// assert_eq!(s.char_at_reverse(1), 'a');
@@ -523,6 +529,9 @@ pub fn char_at(&self, i: usize) -> char {
                          cases generate panics",
                issue = "27754")]
     #[inline]
+    #[rustc_deprecated(reason = "use slicing plus chars().rev()",
+                       since = "1.9.0")]
+    #[allow(deprecated)]
     pub fn char_at_reverse(&self, i: usize) -> char {
         core_str::StrExt::char_at_reverse(self, i)
     }
@@ -541,6 +550,7 @@ pub fn char_at_reverse(&self, i: usize) -> char {
     ///
     /// ```
     /// #![feature(str_char)]
+    /// #![allow(deprecated)]
     ///
     /// let s = "Łódź"; // \u{141}o\u{301}dz\u{301}
     /// let (c, s1) = s.slice_shift_char().unwrap();
@@ -559,6 +569,9 @@ pub fn char_at_reverse(&self, i: usize) -> char {
                          and/or char_indices iterators",
                issue = "27754")]
     #[inline]
+    #[rustc_deprecated(reason = "use chars() plus Chars::as_str",
+                       since = "1.9.0")]
+    #[allow(deprecated)]
     pub fn slice_shift_char(&self) -> Option<(char, &str)> {
         core_str::StrExt::slice_shift_char(self)
     }
index c84d84959dbc22edb06bd17ae6371c689a066b47..2226116585fcb072550d4fa6ce90faf43d8a5180 100644 (file)
@@ -1037,14 +1037,13 @@ pub fn truncate(&mut self, new_len: usize) {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn pop(&mut self) -> Option<char> {
-        let len = self.len();
-        if len == 0 {
-            return None;
-        }
-
-        let ch = self.char_at_reverse(len);
+        let ch = match self.chars().rev().next() {
+            Some(ch) => ch,
+            None => return None,
+        };
+        let newlen = self.len() - ch.len_utf8();
         unsafe {
-            self.vec.set_len(len - ch.len_utf8());
+            self.vec.set_len(newlen);
         }
         Some(ch)
     }
@@ -1075,11 +1074,13 @@ pub fn pop(&mut self) -> Option<char> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn remove(&mut self, idx: usize) -> char {
-        let len = self.len();
-        assert!(idx < len);
+        let ch = match self[idx..].chars().next() {
+            Some(ch) => ch,
+            None => panic!("cannot remove a char from the end of a string"),
+        };
 
-        let ch = self.char_at(idx);
         let next = idx + ch.len_utf8();
+        let len = self.len();
         unsafe {
             ptr::copy(self.vec.as_ptr().offset(next as isize),
                       self.vec.as_mut_ptr().offset(idx as isize),
index 045ac1ce977fcc9399e5f05b0ffec1b3d5afae3f..211942f2294ecd165246ecb95e43dd7782cdbaca 100644 (file)
 
 #![deny(warnings)]
 
-#![feature(ascii)]
 #![feature(binary_heap_extras)]
 #![feature(box_syntax)]
 #![feature(btree_range)]
 #![feature(collections)]
 #![feature(collections_bound)]
-#![feature(copy_from_slice)]
 #![feature(const_fn)]
 #![feature(fn_traits)]
 #![feature(enumset)]
@@ -25,7 +23,6 @@
 #![feature(map_values_mut)]
 #![feature(pattern)]
 #![feature(rand)]
-#![feature(set_recovery)]
 #![feature(step_by)]
 #![feature(str_char)]
 #![feature(str_escape)]
index 1150035eb425545775063fb2b49ad7a24b1fa0e2..929ac7a52ab2786a3a0945a7237c37db9c7767d5 100644 (file)
@@ -464,12 +464,14 @@ fn test_is_whitespace() {
 }
 
 #[test]
+#[allow(deprecated)]
 fn test_slice_shift_char() {
     let data = "ประเทศไทย中";
     assert_eq!(data.slice_shift_char(), Some(('ป', "ระเทศไทย中")));
 }
 
 #[test]
+#[allow(deprecated)]
 fn test_slice_shift_char_2() {
     let empty = "";
     assert_eq!(empty.slice_shift_char(), None);
@@ -657,6 +659,7 @@ fn test_contains_char() {
 }
 
 #[test]
+#[allow(deprecated)]
 fn test_char_at() {
     let s = "ศไทย中华Việt Nam";
     let v = vec!['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m'];
@@ -668,6 +671,7 @@ fn test_char_at() {
 }
 
 #[test]
+#[allow(deprecated)]
 fn test_char_at_reverse() {
     let s = "ศไทย中华Việt Nam";
     let v = vec!['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m'];
@@ -745,6 +749,7 @@ fn test_total_ord() {
 }
 
 #[test]
+#[allow(deprecated)]
 fn test_char_range_at() {
     let data = "b¢€𤭢𤭢€¢b";
     assert_eq!('b', data.char_range_at(0).ch);
@@ -758,6 +763,7 @@ fn test_char_range_at() {
 }
 
 #[test]
+#[allow(deprecated)]
 fn test_char_range_at_reverse_underflow() {
     assert_eq!("abc".char_range_at_reverse(0).next, 0);
 }
index b2cbc29b1c74c146bfef4bb62a6649eb80f6fe54..a1c7a293af0b3d759a8b828c1a74b0e0a3ee81c7 100644 (file)
@@ -390,8 +390,8 @@ pub fn borrow_state(&self) -> BorrowState {
     pub fn borrow(&self) -> Ref<T> {
         match BorrowRef::new(&self.borrow) {
             Some(b) => Ref {
-                _value: unsafe { &*self.value.get() },
-                _borrow: b,
+                value: unsafe { &*self.value.get() },
+                borrow: b,
             },
             None => panic!("RefCell<T> already mutably borrowed"),
         }
@@ -438,8 +438,8 @@ pub fn borrow(&self) -> Ref<T> {
     pub fn borrow_mut(&self) -> RefMut<T> {
         match BorrowRefMut::new(&self.borrow) {
             Some(b) => RefMut {
-                _value: unsafe { &mut *self.value.get() },
-                _borrow: b,
+                value: unsafe { &mut *self.value.get() },
+                borrow: b,
             },
             None => panic!("RefCell<T> already borrowed"),
         }
@@ -491,7 +491,7 @@ fn eq(&self, other: &RefCell<T>) -> bool {
 impl<T: ?Sized + Eq> Eq for RefCell<T> {}
 
 struct BorrowRef<'b> {
-    _borrow: &'b Cell<BorrowFlag>,
+    borrow: &'b Cell<BorrowFlag>,
 }
 
 impl<'b> BorrowRef<'b> {
@@ -501,7 +501,7 @@ fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRef<'b>> {
             WRITING => None,
             b => {
                 borrow.set(b + 1);
-                Some(BorrowRef { _borrow: borrow })
+                Some(BorrowRef { borrow: borrow })
             },
         }
     }
@@ -510,9 +510,9 @@ fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRef<'b>> {
 impl<'b> Drop for BorrowRef<'b> {
     #[inline]
     fn drop(&mut self) {
-        let borrow = self._borrow.get();
+        let borrow = self.borrow.get();
         debug_assert!(borrow != WRITING && borrow != UNUSED);
-        self._borrow.set(borrow - 1);
+        self.borrow.set(borrow - 1);
     }
 }
 
@@ -521,10 +521,10 @@ impl<'b> Clone for BorrowRef<'b> {
     fn clone(&self) -> BorrowRef<'b> {
         // Since this Ref exists, we know the borrow flag
         // is not set to WRITING.
-        let borrow = self._borrow.get();
+        let borrow = self.borrow.get();
         debug_assert!(borrow != WRITING && borrow != UNUSED);
-        self._borrow.set(borrow + 1);
-        BorrowRef { _borrow: self._borrow }
+        self.borrow.set(borrow + 1);
+        BorrowRef { borrow: self.borrow }
     }
 }
 
@@ -534,10 +534,8 @@ fn clone(&self) -> BorrowRef<'b> {
 /// See the [module-level documentation](index.html) for more.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Ref<'b, T: ?Sized + 'b> {
-    // FIXME #12808: strange name to try to avoid interfering with
-    // field accesses of the contained type via Deref
-    _value: &'b T,
-    _borrow: BorrowRef<'b>,
+    value: &'b T,
+    borrow: BorrowRef<'b>,
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -546,7 +544,7 @@ impl<'b, T: ?Sized> Deref for Ref<'b, T> {
 
     #[inline]
     fn deref(&self) -> &T {
-        self._value
+        self.value
     }
 }
 
@@ -565,8 +563,8 @@ impl<'b, T: ?Sized> Ref<'b, T> {
     #[inline]
     pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
         Ref {
-            _value: orig._value,
-            _borrow: orig._borrow.clone(),
+            value: orig.value,
+            borrow: orig.borrow.clone(),
         }
     }
 
@@ -594,8 +592,8 @@ pub fn map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Ref<'b, U>
         where F: FnOnce(&T) -> &U
     {
         Ref {
-            _value: f(orig._value),
-            _borrow: orig._borrow,
+            value: f(orig.value),
+            borrow: orig.borrow,
         }
     }
 
@@ -627,9 +625,9 @@ pub fn map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Ref<'b, U>
     pub fn filter_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Option<Ref<'b, U>>
         where F: FnOnce(&T) -> Option<&U>
     {
-        f(orig._value).map(move |new| Ref {
-            _value: new,
-            _borrow: orig._borrow,
+        f(orig.value).map(move |new| Ref {
+            value: new,
+            borrow: orig.borrow,
         })
     }
 }
@@ -667,8 +665,8 @@ pub fn map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> RefMut<'b, U>
         where F: FnOnce(&mut T) -> &mut U
     {
         RefMut {
-            _value: f(orig._value),
-            _borrow: orig._borrow,
+            value: f(orig.value),
+            borrow: orig.borrow,
         }
     }
 
@@ -706,24 +704,24 @@ pub fn map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> RefMut<'b, U>
     pub fn filter_map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> Option<RefMut<'b, U>>
         where F: FnOnce(&mut T) -> Option<&mut U>
     {
-        let RefMut { _value, _borrow } = orig;
-        f(_value).map(move |new| RefMut {
-            _value: new,
-            _borrow: _borrow,
+        let RefMut { value, borrow } = orig;
+        f(value).map(move |new| RefMut {
+            value: new,
+            borrow: borrow,
         })
     }
 }
 
 struct BorrowRefMut<'b> {
-    _borrow: &'b Cell<BorrowFlag>,
+    borrow: &'b Cell<BorrowFlag>,
 }
 
 impl<'b> Drop for BorrowRefMut<'b> {
     #[inline]
     fn drop(&mut self) {
-        let borrow = self._borrow.get();
+        let borrow = self.borrow.get();
         debug_assert!(borrow == WRITING);
-        self._borrow.set(UNUSED);
+        self.borrow.set(UNUSED);
     }
 }
 
@@ -733,7 +731,7 @@ fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRefMut<'b>> {
         match borrow.get() {
             UNUSED => {
                 borrow.set(WRITING);
-                Some(BorrowRefMut { _borrow: borrow })
+                Some(BorrowRefMut { borrow: borrow })
             },
             _ => None,
         }
@@ -745,10 +743,8 @@ fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRefMut<'b>> {
 /// See the [module-level documentation](index.html) for more.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RefMut<'b, T: ?Sized + 'b> {
-    // FIXME #12808: strange name to try to avoid interfering with
-    // field accesses of the contained type via Deref
-    _value: &'b mut T,
-    _borrow: BorrowRefMut<'b>,
+    value: &'b mut T,
+    borrow: BorrowRefMut<'b>,
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -757,7 +753,7 @@ impl<'b, T: ?Sized> Deref for RefMut<'b, T> {
 
     #[inline]
     fn deref(&self) -> &T {
-        self._value
+        self.value
     }
 }
 
@@ -765,7 +761,7 @@ fn deref(&self) -> &T {
 impl<'b, T: ?Sized> DerefMut for RefMut<'b, T> {
     #[inline]
     fn deref_mut(&mut self) -> &mut T {
-        self._value
+        self.value
     }
 }
 
index 229a864d712c5cf4f07e17439c420ed879d58f78..9af8ef53851db986bc48556ebe74f3fa8c40eda7 100644 (file)
@@ -149,7 +149,7 @@ pub const fn max_value() -> Self {
         /// Basic usage:
         ///
         /// ```
-        /// assert_eq!(u32::from_str_radix("A", 16), Ok(10));
+        /// assert_eq!(i32::from_str_radix("A", 16), Ok(10));
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
@@ -163,9 +163,9 @@ pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
         /// Basic usage:
         ///
         /// ```
-        /// let n = 0b01001100u8;
+        /// let n = -0b1000_0000i8;
         ///
-        /// assert_eq!(n.count_ones(), 3);
+        /// assert_eq!(n.count_ones(), 1);
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
@@ -178,9 +178,9 @@ pub fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() }
         /// Basic usage:
         ///
         /// ```
-        /// let n = 0b01001100u8;
+        /// let n = -0b1000_0000i8;
         ///
-        /// assert_eq!(n.count_zeros(), 5);
+        /// assert_eq!(n.count_zeros(), 7);
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
@@ -196,9 +196,9 @@ pub fn count_zeros(self) -> u32 {
         /// Basic usage:
         ///
         /// ```
-        /// let n = 0b0101000u16;
+        /// let n = -1i16;
         ///
-        /// assert_eq!(n.leading_zeros(), 10);
+        /// assert_eq!(n.leading_zeros(), 0);
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
@@ -214,9 +214,9 @@ pub fn leading_zeros(self) -> u32 {
         /// Basic usage:
         ///
         /// ```
-        /// let n = 0b0101000u16;
+        /// let n = -4i8;
         ///
-        /// assert_eq!(n.trailing_zeros(), 3);
+        /// assert_eq!(n.trailing_zeros(), 2);
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
@@ -232,10 +232,10 @@ pub fn trailing_zeros(self) -> u32 {
         /// Basic usage:
         ///
         /// ```
-        /// let n = 0x0123456789ABCDEFu64;
-        /// let m = 0x3456789ABCDEF012u64;
+        /// let n = 0x0123456789ABCDEFi64;
+        /// let m = -0x76543210FEDCBA99i64;
         ///
-        /// assert_eq!(n.rotate_left(12), m);
+        /// assert_eq!(n.rotate_left(32), m);
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
@@ -252,10 +252,10 @@ pub fn rotate_left(self, n: u32) -> Self {
         /// Basic usage:
         ///
         /// ```
-        /// let n = 0x0123456789ABCDEFu64;
-        /// let m = 0xDEF0123456789ABCu64;
+        /// let n = 0x0123456789ABCDEFi64;
+        /// let m = -0xFEDCBA987654322i64;
         ///
-        /// assert_eq!(n.rotate_right(12), m);
+        /// assert_eq!(n.rotate_right(4), m);
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
@@ -270,8 +270,8 @@ pub fn rotate_right(self, n: u32) -> Self {
         /// Basic usage:
         ///
         /// ```
-        /// let n = 0x0123456789ABCDEFu64;
-        /// let m = 0xEFCDAB8967452301u64;
+        /// let n =  0x0123456789ABCDEFi64;
+        /// let m = -0x1032547698BADCFFi64;
         ///
         /// assert_eq!(n.swap_bytes(), m);
         /// ```
@@ -291,12 +291,12 @@ pub fn swap_bytes(self) -> Self {
         /// Basic usage:
         ///
         /// ```
-        /// let n = 0x0123456789ABCDEFu64;
+        /// let n = 0x0123456789ABCDEFi64;
         ///
         /// if cfg!(target_endian = "big") {
-        ///     assert_eq!(u64::from_be(n), n)
+        ///     assert_eq!(i64::from_be(n), n)
         /// } else {
-        ///     assert_eq!(u64::from_be(n), n.swap_bytes())
+        ///     assert_eq!(i64::from_be(n), n.swap_bytes())
         /// }
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -315,12 +315,12 @@ pub fn from_be(x: Self) -> Self {
         /// Basic usage:
         ///
         /// ```
-        /// let n = 0x0123456789ABCDEFu64;
+        /// let n = 0x0123456789ABCDEFi64;
         ///
         /// if cfg!(target_endian = "little") {
-        ///     assert_eq!(u64::from_le(n), n)
+        ///     assert_eq!(i64::from_le(n), n)
         /// } else {
-        ///     assert_eq!(u64::from_le(n), n.swap_bytes())
+        ///     assert_eq!(i64::from_le(n), n.swap_bytes())
         /// }
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -339,7 +339,7 @@ pub fn from_le(x: Self) -> Self {
         /// Basic usage:
         ///
         /// ```
-        /// let n = 0x0123456789ABCDEFu64;
+        /// let n = 0x0123456789ABCDEFi64;
         ///
         /// if cfg!(target_endian = "big") {
         ///     assert_eq!(n.to_be(), n)
@@ -363,7 +363,7 @@ pub fn to_be(self) -> Self { // or not to be?
         /// Basic usage:
         ///
         /// ```
-        /// let n = 0x0123456789ABCDEFu64;
+        /// let n = 0x0123456789ABCDEFi64;
         ///
         /// if cfg!(target_endian = "little") {
         ///     assert_eq!(n.to_le(), n)
@@ -385,8 +385,8 @@ pub fn to_le(self) -> Self {
         /// Basic usage:
         ///
         /// ```
-        /// assert_eq!(5u16.checked_add(65530), Some(65535));
-        /// assert_eq!(6u16.checked_add(65530), None);
+        /// assert_eq!(7i16.checked_add(32760), Some(32767));
+        /// assert_eq!(8i16.checked_add(32760), None);
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
@@ -421,8 +421,8 @@ pub fn checked_sub(self, other: Self) -> Option<Self> {
         /// Basic usage:
         ///
         /// ```
-        /// assert_eq!(5u8.checked_mul(51), Some(255));
-        /// assert_eq!(5u8.checked_mul(52), None);
+        /// assert_eq!(6i8.checked_mul(21), Some(126));
+        /// assert_eq!(6i8.checked_mul(22), None);
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
@@ -753,8 +753,8 @@ pub fn wrapping_neg(self) -> Self {
         /// Basic usage:
         ///
         /// ```
-        /// assert_eq!(1u8.wrapping_shl(7), 128);
-        /// assert_eq!(1u8.wrapping_shl(8), 1);
+        /// assert_eq!((-1i8).wrapping_shl(7), -128);
+        /// assert_eq!((-1i8).wrapping_shl(8), -1);
         /// ```
         #[stable(feature = "num_wrapping", since = "1.2.0")]
         #[inline(always)]
@@ -778,8 +778,8 @@ pub fn wrapping_shl(self, rhs: u32) -> Self {
         /// Basic usage:
         ///
         /// ```
-        /// assert_eq!(128u8.wrapping_shr(7), 1);
-        /// assert_eq!(128u8.wrapping_shr(8), 128);
+        /// assert_eq!((-128i8).wrapping_shr(7), -1);
+        /// assert_eq!((-128i8).wrapping_shr(8), -128);
         /// ```
         #[stable(feature = "num_wrapping", since = "1.2.0")]
         #[inline(always)]
@@ -1193,15 +1193,13 @@ pub const fn max_value() -> Self { !0 }
         ///
         /// Leading and trailing whitespace represent an error.
         ///
-        /// # Arguments
-        ///
-        /// * src - A string slice
-        /// * radix - The base to use. Must lie in the range [2 .. 36]
+        /// # Examples
         ///
-        /// # Return value
+        /// Basic usage:
         ///
-        /// `Err(ParseIntError)` if the string did not represent a valid number.
-        /// Otherwise, `Ok(n)` where `n` is the integer represented by `src`.
+        /// ```
+        /// assert_eq!(u32::from_str_radix("A", 16), Ok(10));
+        /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
             from_str_radix(src, radix)
@@ -1745,7 +1743,7 @@ pub fn wrapping_div(self, rhs: Self) -> Self {
         /// Basic usage:
         ///
         /// ```
-        /// assert_eq!(100i8.wrapping_rem(10), 0);
+        /// assert_eq!(100u8.wrapping_rem(10), 0);
         /// ```
         #[stable(feature = "num_wrapping", since = "1.2.0")]
         #[inline(always)]
@@ -1783,6 +1781,13 @@ pub fn wrapping_neg(self) -> Self {
         /// where `mask` removes any high-order bits of `rhs` that
         /// would cause the shift to exceed the bitwidth of the type.
         ///
+        /// Note that this is *not* the same as a rotate-left; the
+        /// RHS of a wrapping shift-left is restricted to the range
+        /// of the type, rather than the bits shifted out of the LHS
+        /// being returned to the other end. The primitive integer
+        /// types all implement a `rotate_left` function, which may
+        /// be what you want instead.
+        ///
         /// # Examples
         ///
         /// Basic usage:
@@ -1801,6 +1806,13 @@ pub fn wrapping_shl(self, rhs: u32) -> Self {
         /// where `mask` removes any high-order bits of `rhs` that
         /// would cause the shift to exceed the bitwidth of the type.
         ///
+        /// Note that this is *not* the same as a rotate-right; the
+        /// RHS of a wrapping shift-right is restricted to the range
+        /// of the type, rather than the bits shifted out of the LHS
+        /// being returned to the other end. The primitive integer
+        /// types all implement a `rotate_right` function, which may
+        /// be what you want instead.
+        ///
         /// # Examples
         ///
         /// Basic usage:
index 42aef3ab3dd7503e22689c45ac4fb7638d873e14..a6b5355d947860be655fd50118510c222b1b4ed8 100644 (file)
@@ -166,9 +166,16 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
 ///
 /// Volatile operations are intended to act on I/O memory, and are guaranteed
 /// to not be elided or reordered by the compiler across other volatile
-/// operations. See the LLVM documentation on [[volatile]].
+/// operations.
 ///
-/// [volatile]: http://llvm.org/docs/LangRef.html#volatile-memory-accesses
+/// # Notes
+///
+/// Rust does not currently have a rigorously and formally defined memory model,
+/// so the precise semantics of what "volatile" means here is subject to change
+/// over time. That being said, the semantics will almost always end up pretty
+/// similar to [C11's definition of volatile][c11].
+///
+/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
 ///
 /// # Safety
 ///
@@ -179,7 +186,7 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
 /// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use
 /// because it will attempt to drop the value previously at `*src`.
 #[inline]
-#[unstable(feature = "volatile", reason = "recently added", issue = "31756")]
+#[stable(feature = "volatile", since = "1.9.0")]
 pub unsafe fn read_volatile<T>(src: *const T) -> T {
     intrinsics::volatile_load(src)
 }
@@ -189,9 +196,16 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 ///
 /// Volatile operations are intended to act on I/O memory, and are guaranteed
 /// to not be elided or reordered by the compiler across other volatile
-/// operations. See the LLVM documentation on [[volatile]].
+/// operations.
+///
+/// # Notes
 ///
-/// [volatile]: http://llvm.org/docs/LangRef.html#volatile-memory-accesses
+/// Rust does not currently have a rigorously and formally defined memory model,
+/// so the precise semantics of what "volatile" means here is subject to change
+/// over time. That being said, the semantics will almost always end up pretty
+/// similar to [C11's definition of volatile][c11].
+///
+/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
 ///
 /// # Safety
 ///
@@ -204,7 +218,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 /// This is appropriate for initializing uninitialized memory, or overwriting
 /// memory that has previously been `read` from.
 #[inline]
-#[unstable(feature = "volatile", reason = "recently added", issue = "31756")]
+#[stable(feature = "volatile", since = "1.9.0")]
 pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
     intrinsics::volatile_store(dst, src);
 }
@@ -238,6 +252,9 @@ pub fn is_null(self) -> bool where T: Sized {
     /// operation because the returned value could be pointing to invalid
     /// memory.
     ///
+    /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does
+    /// not necessarily reflect the actual lifetime of the data.
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -251,17 +268,13 @@ pub fn is_null(self) -> bool where T: Sized {
     ///     }
     /// }
     /// ```
-    #[unstable(feature = "ptr_as_ref",
-               reason = "Option is not clearly the right return type, and we \
-                         may want to tie the return lifetime to a borrow of \
-                         the raw pointer",
-               issue = "27780")]
+    #[stable(feature = "ptr_as_ref", since = "1.9.0")]
     #[inline]
-    pub unsafe fn as_ref<'a>(&self) -> Option<&'a T> where T: Sized {
+    pub unsafe fn as_ref<'a>(self) -> Option<&'a T> where T: Sized {
         if self.is_null() {
             None
         } else {
-            Some(&**self)
+            Some(&*self)
         }
     }
 
@@ -324,6 +337,9 @@ pub fn is_null(self) -> bool where T: Sized {
     /// operation because the returned value could be pointing to invalid
     /// memory.
     ///
+    /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does
+    /// not necessarily reflect the actual lifetime of the data.
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -337,17 +353,13 @@ pub fn is_null(self) -> bool where T: Sized {
     ///     }
     /// }
     /// ```
-    #[unstable(feature = "ptr_as_ref",
-               reason = "Option is not clearly the right return type, and we \
-                         may want to tie the return lifetime to a borrow of \
-                         the raw pointer",
-               issue = "27780")]
+    #[stable(feature = "ptr_as_ref", since = "1.9.0")]
     #[inline]
-    pub unsafe fn as_ref<'a>(&self) -> Option<&'a T> where T: Sized {
+    pub unsafe fn as_ref<'a>(self) -> Option<&'a T> where T: Sized {
         if self.is_null() {
             None
         } else {
-            Some(&**self)
+            Some(&*self)
         }
     }
 
@@ -385,7 +397,8 @@ pub unsafe fn offset(self, count: isize) -> *mut T where T: Sized {
     /// # Safety
     ///
     /// As with `as_ref`, this is unsafe because it cannot verify the validity
-    /// of the returned pointer.
+    /// of the returned pointer, nor can it ensure that the lifetime `'a`
+    /// returned is indeed a valid lifetime for the contained data.
     ///
     /// # Examples
     ///
@@ -395,16 +408,13 @@ pub unsafe fn offset(self, count: isize) -> *mut T where T: Sized {
     /// let mut s = [1, 2, 3];
     /// let ptr: *mut u32 = s.as_mut_ptr();
     /// ```
-    #[unstable(feature = "ptr_as_ref",
-               reason = "return value does not necessarily convey all possible \
-                         information",
-               issue = "27780")]
+    #[stable(feature = "ptr_as_ref", since = "1.9.0")]
     #[inline]
-    pub unsafe fn as_mut<'a>(&self) -> Option<&'a mut T> where T: Sized {
+    pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> where T: Sized {
         if self.is_null() {
             None
         } else {
-            Some(&mut **self)
+            Some(&mut *self)
         }
     }
 }
index 20c85b5efc116cdc03cc7b62c0de5e9e3670745b..19226d81f16882000966fcd514a046d1f16abe86 100644 (file)
 /// ```
 #[repr(C)]
 #[allow(missing_debug_implementations)]
+#[rustc_deprecated(reason = "use raw accessors/constructors in `slice` module",
+                   since = "1.9.0")]
+#[unstable(feature = "raw", issue = "27751")]
 pub struct Slice<T> {
     pub data: *const T,
     pub len: usize,
 }
 
+#[allow(deprecated)]
 impl<T> Copy for Slice<T> {}
+#[allow(deprecated)]
 impl<T> Clone for Slice<T> {
     fn clone(&self) -> Slice<T> { *self }
 }
@@ -152,6 +157,9 @@ pub struct TraitObject {
 
 /// This trait is meant to map equivalences between raw structs and their
 /// corresponding rust values.
+#[rustc_deprecated(reason = "use raw accessors/constructors in `slice` module",
+                   since = "1.9.0")]
+#[unstable(feature = "raw", issue = "27751")]
 pub unsafe trait Repr<T> {
     /// This function "unwraps" a rust value (without consuming it) into its raw
     /// struct representation. This can be used to read/write different values
@@ -161,5 +169,7 @@ pub unsafe trait Repr<T> {
     fn repr(&self) -> T { unsafe { mem::transmute_copy(&self) } }
 }
 
+#[allow(deprecated)]
 unsafe impl<T> Repr<Slice<T>> for [T] {}
+#[allow(deprecated)]
 unsafe impl Repr<Slice<u8>> for str {}
index 7f8cf531d26176bc7a8e52739892bef13cb8f129..4d9f042fddedc03db74c4647848032836efdae04 100644 (file)
@@ -19,7 +19,7 @@
 //! # #[allow(dead_code)]
 //! enum Result<T, E> {
 //!    Ok(T),
-//!    Err(E)
+//!    Err(E),
 //! }
 //! ```
 //!
@@ -39,7 +39,7 @@
 //!         None => Err("invalid header length"),
 //!         Some(&1) => Ok(Version::Version1),
 //!         Some(&2) => Ok(Version::Version2),
-//!         Some(_) => Err("invalid version")
+//!         Some(_) => Err("invalid version"),
 //!     }
 //! }
 //!
@@ -254,7 +254,7 @@ pub enum Result<T, E> {
 
     /// Contains the error value
     #[stable(feature = "rust1", since = "1.0.0")]
-    Err(#[stable(feature = "rust1", since = "1.0.0")] E)
+    Err(#[stable(feature = "rust1", since = "1.0.0")] E),
 }
 
 /////////////////////////////////////////////////////////////////////////////
@@ -270,6 +270,8 @@ impl<T, E> Result<T, E> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// let x: Result<i32, &str> = Ok(-3);
     /// assert_eq!(x.is_ok(), true);
@@ -290,6 +292,8 @@ pub fn is_ok(&self) -> bool {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// let x: Result<i32, &str> = Ok(-3);
     /// assert_eq!(x.is_err(), false);
@@ -314,6 +318,8 @@ pub fn is_err(&self) -> bool {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// let x: Result<u32, &str> = Ok(2);
     /// assert_eq!(x.ok(), Some(2));
@@ -337,6 +343,8 @@ pub fn ok(self) -> Option<T> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// let x: Result<u32, &str> = Ok(2);
     /// assert_eq!(x.err(), None);
@@ -362,6 +370,10 @@ pub fn err(self) -> Option<E> {
     /// Produces a new `Result`, containing a reference
     /// into the original, leaving the original in place.
     ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
     /// ```
     /// let x: Result<u32, &str> = Ok(2);
     /// assert_eq!(x.as_ref(), Ok(&2));
@@ -380,6 +392,10 @@ pub fn as_ref(&self) -> Result<&T, &E> {
 
     /// Converts from `Result<T, E>` to `Result<&mut T, &mut E>`
     ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
     /// ```
     /// fn mutate(r: &mut Result<i32, i32>) {
     ///     match r.as_mut() {
@@ -445,6 +461,8 @@ pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Result<U,E> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// fn stringify(x: u32) -> String { format!("error code: {}", x) }
     ///
@@ -471,6 +489,8 @@ pub fn map_err<F, O: FnOnce(E) -> F>(self, op: O) -> Result<T,F> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// let x: Result<u32, &str> = Ok(7);
     /// assert_eq!(x.iter().next(), Some(&7));
@@ -488,6 +508,8 @@ pub fn iter(&self) -> Iter<T> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// let mut x: Result<u32, &str> = Ok(7);
     /// match x.iter_mut().next() {
@@ -513,6 +535,8 @@ pub fn iter_mut(&mut self) -> IterMut<T> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// let x: Result<u32, &str> = Ok(2);
     /// let y: Result<&str, &str> = Err("late error");
@@ -545,6 +569,8 @@ pub fn and<U>(self, res: Result<U, E>) -> Result<U, E> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
     /// fn err(x: u32) -> Result<u32, u32> { Err(x) }
@@ -567,6 +593,8 @@ pub fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// let x: Result<u32, &str> = Ok(2);
     /// let y: Result<u32, &str> = Err("late error");
@@ -599,6 +627,8 @@ pub fn or<F>(self, res: Result<T, F>) -> Result<T, F> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
     /// fn err(x: u32) -> Result<u32, u32> { Err(x) }
@@ -622,6 +652,8 @@ pub fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// let optb = 2;
     /// let x: Result<u32, &str> = Ok(9);
@@ -644,6 +676,8 @@ pub fn unwrap_or(self, optb: T) -> T {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// fn count(x: &str) -> usize { x.len() }
     ///
@@ -670,6 +704,8 @@ impl<T, E: fmt::Debug> Result<T, E> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// let x: Result<u32, &str> = Ok(2);
     /// assert_eq!(x.unwrap(), 2);
@@ -696,6 +732,9 @@ pub fn unwrap(self) -> T {
     /// passed message, and the content of the `Err`.
     ///
     /// # Examples
+    ///
+    /// Basic usage:
+    ///
     /// ```{.should_panic}
     /// let x: Result<u32, &str> = Err("emergency failure");
     /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure`
@@ -759,6 +798,8 @@ impl<T, E> IntoIterator for Result<T, E> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// let x: Result<u32, &str> = Ok(5);
     /// let v: Vec<u32> = x.into_iter().collect();
index 25082eed2fe6f4b7843eb06064110157f8366f00..2e91238bff3cc1966b54b88728511a9b13885725 100644 (file)
 use ptr;
 use mem;
 use marker::{Copy, Send, Sync, self};
-use raw::Repr;
-// Avoid conflicts with *both* the Slice trait (buggy) and the `slice::raw` module.
-use raw::Slice as RawSlice;
 
+#[repr(C)]
+struct Repr<T> {
+    pub data: *const T,
+    pub len: usize,
+}
 
 //
 // Extension traits
@@ -152,8 +154,8 @@ fn rsplitn_mut<P>(&mut self,  n: usize, pred: P) -> RSplitNMut<Self::Item, P>
     fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq;
 
     #[stable(feature = "clone_from_slice", since = "1.7.0")]
-    fn clone_from_slice(&mut self, &[Self::Item]) where Self::Item: Clone;
-    #[unstable(feature = "copy_from_slice", issue = "31755")]
+    fn clone_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Clone;
+    #[stable(feature = "copy_from_slice", since = "1.9.0")]
     fn copy_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Copy;
 }
 
@@ -317,7 +319,11 @@ fn binary_search_by<F>(&self, mut f: F) -> Result<usize, usize> where
     }
 
     #[inline]
-    fn len(&self) -> usize { self.repr().len }
+    fn len(&self) -> usize {
+        unsafe {
+            mem::transmute::<&[T], Repr<T>>(self).len
+        }
+    }
 
     #[inline]
     fn get_mut(&mut self, index: usize) -> Option<&mut T> {
@@ -871,6 +877,20 @@ macro_rules! make_mut_slice {
 }
 
 /// Immutable slice iterator
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// // First, we declare a type which has `iter` method to get the `Iter` struct (&[usize here]):
+/// let slice = &[1, 2, 3];
+///
+/// // Then, we iterate over it:
+/// for element in slice.iter() {
+///     println!("{}", element);
+/// }
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, T: 'a> {
     ptr: *const T,
@@ -897,6 +917,26 @@ impl<'a, T> Iter<'a, T> {
     ///
     /// This has the same lifetime as the original slice, and so the
     /// iterator can continue to be used while this exists.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// // First, we declare a type which has the `iter` method to get the `Iter`
+    /// // struct (&[usize here]):
+    /// let slice = &[1, 2, 3];
+    ///
+    /// // Then, we get the iterator:
+    /// let mut iter = slice.iter();
+    /// // So if we print what `as_slice` method returns here, we have "[1, 2, 3]":
+    /// println!("{:?}", iter.as_slice());
+    ///
+    /// // Next, we move to the second element of the slice:
+    /// iter.next();
+    /// // Now `as_slice` returns "[2, 3]":
+    /// println!("{:?}", iter.as_slice());
+    /// ```
     #[stable(feature = "iter_to_slice", since = "1.4.0")]
     pub fn as_slice(&self) -> &'a [T] {
         make_slice!(self.ptr, self.end)
@@ -928,6 +968,24 @@ fn clone(&self) -> Iter<'a, T> { Iter { ptr: self.ptr, end: self.end, _marker: s
 }
 
 /// Mutable slice iterator.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// // First, we declare a type which has `iter_mut` method to get the `IterMut`
+/// // struct (&[usize here]):
+/// let mut slice = &mut [1, 2, 3];
+///
+/// // Then, we iterate over it and increment each element value:
+/// for element in slice.iter_mut() {
+///     *element += 1;
+/// }
+///
+/// // We now have "[2, 3, 4]":
+/// println!("{:?}", slice);
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IterMut<'a, T: 'a> {
     ptr: *mut T,
@@ -956,6 +1014,35 @@ impl<'a, T> IterMut<'a, T> {
     /// to consume the iterator. Consider using the `Slice` and
     /// `SliceMut` implementations for obtaining slices with more
     /// restricted lifetimes that do not consume the iterator.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// // First, we declare a type which has `iter_mut` method to get the `IterMut`
+    /// // struct (&[usize here]):
+    /// let mut slice = &mut [1, 2, 3];
+    ///
+    /// {
+    ///     // Then, we get the iterator:
+    ///     let mut iter = slice.iter_mut();
+    ///     // We move to next element:
+    ///     iter.next();
+    ///     // So if we print what `into_slice` method returns here, we have "[2, 3]":
+    ///     println!("{:?}", iter.into_slice());
+    /// }
+    ///
+    /// // Now let's modify a value of the slice:
+    /// {
+    ///     // First we get back the iterator:
+    ///     let mut iter = slice.iter_mut();
+    ///     // We change the value of the first element of the slice returned by the `next` method:
+    ///     *iter.next().unwrap() += 1;
+    /// }
+    /// // Now slice is "[2, 2, 3]":
+    /// println!("{:?}", slice);
+    /// ```
     #[stable(feature = "iter_to_slice", since = "1.4.0")]
     pub fn into_slice(self) -> &'a mut [T] {
         make_mut_slice!(self.ptr, self.end)
@@ -1614,7 +1701,7 @@ impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {}
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] {
-    mem::transmute(RawSlice { data: p, len: len })
+    mem::transmute(Repr { data: p, len: len })
 }
 
 /// Performs the same functionality as `from_raw_parts`, except that a mutable
@@ -1626,7 +1713,7 @@ pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] {
-    mem::transmute(RawSlice { data: p, len: len })
+    mem::transmute(Repr { data: p, len: len })
 }
 
 //
index 305546df5be2da171140dd5aaad372dae1ea6ba2..f3c31d59fc4671717be8f1628c52b2d74bbbf08c 100644 (file)
@@ -29,7 +29,6 @@
 use mem;
 use ops::{Fn, FnMut, FnOnce};
 use option::Option::{self, None, Some};
-use raw::{Repr, Slice};
 use result::Result::{self, Ok, Err};
 use slice::{self, SliceExt};
 
@@ -1664,24 +1663,23 @@ fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
     #[stable(feature = "core", since = "1.6.0")]
     fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
         where P::Searcher: ReverseSearcher<'a>;
-    #[unstable(feature = "str_char",
-               reason = "it is unclear whether this method pulls its weight \
-                         with the existence of the char_indices iterator or \
-                         this method may want to be replaced with checked \
-                         slicing",
-               issue = "27754")]
+    #[stable(feature = "is_char_boundary", since = "1.9.0")]
     fn is_char_boundary(&self, index: usize) -> bool;
     #[unstable(feature = "str_char",
                reason = "often replaced by char_indices, this method may \
                          be removed in favor of just char_at() or eventually \
                          removed altogether",
                issue = "27754")]
+    #[rustc_deprecated(reason = "use slicing plus chars() plus len_utf8",
+                       since = "1.9.0")]
     fn char_range_at(&self, start: usize) -> CharRange;
     #[unstable(feature = "str_char",
                reason = "often replaced by char_indices, this method may \
                          be removed in favor of just char_at_reverse() or \
                          eventually removed altogether",
                issue = "27754")]
+    #[rustc_deprecated(reason = "use slicing plus chars().rev() plus len_utf8",
+                       since = "1.9.0")]
     fn char_range_at_reverse(&self, start: usize) -> CharRange;
     #[unstable(feature = "str_char",
                reason = "frequently replaced by the chars() iterator, this \
@@ -1690,12 +1688,16 @@ fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
                          iterators or by getting the first char from a \
                          subslice",
                issue = "27754")]
+    #[rustc_deprecated(reason = "use slicing plus chars()",
+                       since = "1.9.0")]
     fn char_at(&self, i: usize) -> char;
     #[unstable(feature = "str_char",
                reason = "see char_at for more details, but reverse semantics \
                          are also somewhat unclear, especially with which \
                          cases generate panics",
                issue = "27754")]
+    #[rustc_deprecated(reason = "use slicing plus chars().rev()",
+                       since = "1.9.0")]
     fn char_at_reverse(&self, i: usize) -> char;
     #[stable(feature = "core", since = "1.6.0")]
     fn as_bytes(&self) -> &[u8];
@@ -1714,6 +1716,8 @@ fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
                          may not be warranted with the existence of the chars \
                          and/or char_indices iterators",
                issue = "27754")]
+    #[rustc_deprecated(reason = "use chars() plus Chars::as_str",
+                       since = "1.9.0")]
     fn slice_shift_char(&self) -> Option<(char, &str)>;
     #[stable(feature = "core", since = "1.6.0")]
     fn as_ptr(&self) -> *const u8;
@@ -1857,18 +1861,16 @@ fn lines_any(&self) -> LinesAny {
 
     #[inline]
     unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
-        mem::transmute(Slice {
-            data: self.as_ptr().offset(begin as isize),
-            len: end - begin,
-        })
+        let ptr = self.as_ptr().offset(begin as isize);
+        let len = end - begin;
+        from_utf8_unchecked(slice::from_raw_parts(ptr, len))
     }
 
     #[inline]
     unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
-        mem::transmute(Slice {
-            data: self.as_ptr().offset(begin as isize),
-            len: end - begin,
-        })
+        let ptr = self.as_ptr().offset(begin as isize);
+        let len = end - begin;
+        mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len))
     }
 
     #[inline]
@@ -1940,7 +1942,8 @@ fn is_char_boundary(&self, index: usize) -> bool {
         if index == 0 || index == self.len() { return true; }
         match self.as_bytes().get(index) {
             None => false,
-            Some(&b) => b < 128 || b >= 192,
+            // This is bit magic equivalent to: b < 128 || b >= 192
+            Some(&b) => (b as i8) >= -0x40,
         }
     }
 
@@ -1982,11 +1985,13 @@ fn multibyte_char_range_at_reverse(s: &str, mut i: usize) -> CharRange {
     }
 
     #[inline]
+    #[allow(deprecated)]
     fn char_at(&self, i: usize) -> char {
         self.char_range_at(i).ch
     }
 
     #[inline]
+    #[allow(deprecated)]
     fn char_at_reverse(&self, i: usize) -> char {
         self.char_range_at_reverse(i).ch
     }
@@ -2038,6 +2043,7 @@ fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
     }
 
     #[inline]
+    #[allow(deprecated)]
     fn slice_shift_char(&self) -> Option<(char, &str)> {
         if self.is_empty() {
             None
@@ -2054,7 +2060,9 @@ fn as_ptr(&self) -> *const u8 {
     }
 
     #[inline]
-    fn len(&self) -> usize { self.repr().len }
+    fn len(&self) -> usize {
+        self.as_bytes().len()
+    }
 
     #[inline]
     fn is_empty(&self) -> bool { self.len() == 0 }
index ba8918fc6cb4528742e96e4534c4f2fb27d35c96..41fd742c9e011f48094edd8b250b1857ebc3ed33 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::char;
+
 #[test]
 fn test_is_lowercase() {
     assert!('a'.is_lowercase());
@@ -213,7 +215,10 @@ fn test_len_utf16() {
 #[test]
 fn test_decode_utf16() {
     fn check(s: &[u16], expected: &[Result<char, u16>]) {
-        assert_eq!(::std::char::decode_utf16(s.iter().cloned()).collect::<Vec<_>>(), expected);
+        let v = char::decode_utf16(s.iter().cloned())
+                     .map(|r| r.map_err(|e| e.unpaired_surrogate()))
+                     .collect::<Vec<_>>();
+        assert_eq!(v, expected);
     }
     check(&[0xD800, 0x41, 0x42], &[Err(0xD800), Ok('A'), Ok('B')]);
     check(&[0xD800, 0], &[Err(0xD800), Ok('\0')]);
index 506f9e9b7a5764ddac10ec74bce14c94d220aa93..aa7ab4b4e3f85c82eee639a02bae62b213baf687 100644 (file)
 #![feature(box_syntax)]
 #![feature(cell_extras)]
 #![feature(const_fn)]
-#![feature(copy_from_slice)]
 #![feature(core_float)]
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
 #![feature(dec2flt)]
-#![feature(decode_utf16)]
 #![feature(fixed_size_array)]
 #![feature(float_extras)]
 #![feature(flt2dec)]
@@ -28,7 +26,6 @@
 #![feature(libc)]
 #![feature(nonzero)]
 #![feature(peekable_is_empty)]
-#![feature(ptr_as_ref)]
 #![feature(rand)]
 #![feature(raw)]
 #![feature(slice_patterns)]
index 884f4490d9f4b379d6e9bf10c9542f8e9d834ea1..eda20699755a18e89d9749627074c66a50547def 100644 (file)
@@ -91,7 +91,6 @@
 
 #![deny(missing_docs)]
 #![feature(staged_api)]
-#![feature(str_char)]
 
 use self::Name::*;
 use self::HasArg::*;
@@ -223,7 +222,7 @@ pub enum FailType {
 impl Name {
     fn from_str(nm: &str) -> Name {
         if nm.len() == 1 {
-            Short(nm.char_at(0))
+            Short(nm.chars().next().unwrap())
         } else {
             Long(nm.to_owned())
         }
@@ -261,7 +260,7 @@ pub fn long_to_short(&self) -> Opt {
             }
             (1, 0) => {
                 Opt {
-                    name: Short(short_name.char_at(0)),
+                    name: Short(short_name.chars().next().unwrap()),
                     hasarg: hasarg,
                     occur: occur,
                     aliases: Vec::new(),
@@ -273,7 +272,7 @@ pub fn long_to_short(&self) -> Opt {
                     hasarg: hasarg,
                     occur: occur,
                     aliases: vec![Opt {
-                                      name: Short(short_name.char_at(0)),
+                                      name: Short(short_name.chars().next().unwrap()),
                                       hasarg: hasarg,
                                       occur: occur,
                                       aliases: Vec::new(),
@@ -599,7 +598,7 @@ fn f(_x: usize) -> Vec<Optval> {
                 let mut j = 1;
                 names = Vec::new();
                 while j < curlen {
-                    let ch = cur.char_at(j);
+                    let ch = cur[j..].chars().next().unwrap();
                     let opt = Short(ch);
 
                     // In a series of potential options (eg. -aheJ), if we
index ef89b5d25b8875b04b443af9e220b01371524f76..4edbeab5dfb11049cbedf1255d30608c16abcc6f 100644 (file)
        test(attr(deny(warnings))))]
 #![cfg_attr(not(stage0), deny(warnings))]
 
-#![feature(copy_from_slice)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
 #![feature(question_mark)]
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
new file mode 100644 (file)
index 0000000..446313f
--- /dev/null
@@ -0,0 +1,207 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::fmt::Debug;
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub enum DepNode<D: Clone + Debug> {
+    // The `D` type is "how definitions are identified".
+    // During compilation, it is always `DefId`, but when serializing
+    // it is mapped to `DefPath`.
+
+    // Represents the `Krate` as a whole (the `hir::Krate` value) (as
+    // distinct from the krate module). This is basically a hash of
+    // the entire krate, so if you read from `Krate` (e.g., by calling
+    // `tcx.map.krate()`), we will have to assume that any change
+    // means that you need to be recompiled. This is because the
+    // `Krate` value gives you access to all other items. To avoid
+    // this fate, do not call `tcx.map.krate()`; instead, prefer
+    // wrappers like `tcx.visit_all_items_in_krate()`.  If there is no
+    // suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
+    // access to the krate, but you must remember to add suitable
+    // edges yourself for the individual items that you read.
+    Krate,
+
+    // Represents the HIR node with the given node-id
+    Hir(D),
+
+    // Represents different phases in the compiler.
+    CrateReader,
+    CollectLanguageItems,
+    CheckStaticRecursion,
+    ResolveLifetimes,
+    RegionResolveCrate,
+    CheckLoops,
+    PluginRegistrar,
+    StabilityIndex,
+    CollectItem(D),
+    Coherence,
+    EffectCheck,
+    Liveness,
+    Resolve,
+    EntryPoint,
+    CheckEntryFn,
+    CoherenceCheckImpl(D),
+    CoherenceOverlapCheck(D),
+    CoherenceOverlapCheckSpecial(D),
+    CoherenceOverlapInherentCheck(D),
+    CoherenceOrphanCheck(D),
+    Variance,
+    WfCheck(D),
+    TypeckItemType(D),
+    TypeckItemBody(D),
+    Dropck,
+    DropckImpl(D),
+    CheckConst(D),
+    Privacy,
+    IntrinsicCheck(D),
+    MatchCheck(D),
+    MirMapConstruction(D),
+    MirTypeck(D),
+    BorrowCheck(D),
+    RvalueCheck(D),
+    Reachability,
+    DeadCheck,
+    StabilityCheck,
+    LateLintCheck,
+    IntrinsicUseCheck,
+    TransCrate,
+    TransCrateItem(D),
+    TransInlinedItem(D),
+    TransWriteMetadata,
+
+    // Nodes representing bits of computed IR in the tcx. Each shared
+    // table in the tcx (or elsewhere) maps to one of these
+    // nodes. Often we map multiple tables to the same node if there
+    // is no point in distinguishing them (e.g., both the type and
+    // predicates for an item wind up in `ItemSignature`). Other
+    // times, such as `ImplItems` vs `TraitItemDefIds`, tables which
+    // might be mergable are kept distinct because the sets of def-ids
+    // to which they apply are disjoint, and hence we might as well
+    // have distinct labels for easier debugging.
+    ImplOrTraitItems(D),
+    ItemSignature(D),
+    FieldTy(D),
+    TraitItemDefIds(D),
+    InherentImpls(D),
+    ImplItems(D),
+
+    // The set of impls for a given trait. Ultimately, it would be
+    // nice to get more fine-grained here (e.g., to include a
+    // simplified type), but we can't do that until we restructure the
+    // HIR to distinguish the *header* of an impl from its body.  This
+    // is because changes to the header may change the self-type of
+    // the impl and hence would require us to be more conservative
+    // than changes in the impl body.
+    TraitImpls(D),
+
+    // Nodes representing caches. To properly handle a true cache, we
+    // don't use a DepTrackingMap, but rather we push a task node.
+    // Otherwise the write into the map would be incorrectly
+    // attributed to the first task that happened to fill the cache,
+    // which would yield an overly conservative dep-graph.
+    TraitItems(D),
+    ReprHints(D),
+    TraitSelect(D),
+}
+
+impl<D: Clone + Debug> DepNode<D> {
+    /// Used in testing
+    pub fn from_label_string(label: &str, data: D) -> Result<DepNode<D>, ()> {
+        macro_rules! check {
+            ($($name:ident,)*) => {
+                match label {
+                    $(stringify!($name) => Ok(DepNode::$name(data)),)*
+                    _ => Err(())
+                }
+            }
+        }
+
+        check! {
+            CollectItem,
+            BorrowCheck,
+            TransCrateItem,
+            TypeckItemType,
+            TypeckItemBody,
+            ImplOrTraitItems,
+            ItemSignature,
+            FieldTy,
+            TraitItemDefIds,
+            InherentImpls,
+            ImplItems,
+            TraitImpls,
+            ReprHints,
+        }
+    }
+
+    pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
+        where OP: FnMut(&D) -> Option<E>, E: Clone + Debug
+    {
+        use self::DepNode::*;
+
+        match *self {
+            Krate => Some(Krate),
+            CrateReader => Some(CrateReader),
+            CollectLanguageItems => Some(CollectLanguageItems),
+            CheckStaticRecursion => Some(CheckStaticRecursion),
+            ResolveLifetimes => Some(ResolveLifetimes),
+            RegionResolveCrate => Some(RegionResolveCrate),
+            CheckLoops => Some(CheckLoops),
+            PluginRegistrar => Some(PluginRegistrar),
+            StabilityIndex => Some(StabilityIndex),
+            Coherence => Some(Coherence),
+            EffectCheck => Some(EffectCheck),
+            Liveness => Some(Liveness),
+            Resolve => Some(Resolve),
+            EntryPoint => Some(EntryPoint),
+            CheckEntryFn => Some(CheckEntryFn),
+            Variance => Some(Variance),
+            Dropck => Some(Dropck),
+            Privacy => Some(Privacy),
+            Reachability => Some(Reachability),
+            DeadCheck => Some(DeadCheck),
+            StabilityCheck => Some(StabilityCheck),
+            LateLintCheck => Some(LateLintCheck),
+            IntrinsicUseCheck => Some(IntrinsicUseCheck),
+            TransCrate => Some(TransCrate),
+            TransWriteMetadata => Some(TransWriteMetadata),
+            Hir(ref d) => op(d).map(Hir),
+            CollectItem(ref d) => op(d).map(CollectItem),
+            CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
+            CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
+            CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
+            CoherenceOverlapInherentCheck(ref d) => op(d).map(CoherenceOverlapInherentCheck),
+            CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck),
+            WfCheck(ref d) => op(d).map(WfCheck),
+            TypeckItemType(ref d) => op(d).map(TypeckItemType),
+            TypeckItemBody(ref d) => op(d).map(TypeckItemBody),
+            DropckImpl(ref d) => op(d).map(DropckImpl),
+            CheckConst(ref d) => op(d).map(CheckConst),
+            IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck),
+            MatchCheck(ref d) => op(d).map(MatchCheck),
+            MirMapConstruction(ref d) => op(d).map(MirMapConstruction),
+            MirTypeck(ref d) => op(d).map(MirTypeck),
+            BorrowCheck(ref d) => op(d).map(BorrowCheck),
+            RvalueCheck(ref d) => op(d).map(RvalueCheck),
+            TransCrateItem(ref d) => op(d).map(TransCrateItem),
+            TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
+            ImplOrTraitItems(ref d) => op(d).map(ImplOrTraitItems),
+            ItemSignature(ref d) => op(d).map(ItemSignature),
+            FieldTy(ref d) => op(d).map(FieldTy),
+            TraitItemDefIds(ref d) => op(d).map(TraitItemDefIds),
+            InherentImpls(ref d) => op(d).map(InherentImpls),
+            ImplItems(ref d) => op(d).map(ImplItems),
+            TraitImpls(ref d) => op(d).map(TraitImpls),
+            TraitItems(ref d) => op(d).map(TraitItems),
+            ReprHints(ref d) => op(d).map(ReprHints),
+            TraitSelect(ref d) => op(d).map(TraitSelect),
+        }
+    }
+}
index c49e64f0f543b593ec551ae181cecb5dae395653..922d32a3067969f626a299f4a19d01ddbc83f69b 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use hir::def_id::DefId;
 use rustc_data_structures::fnv::FnvHashMap;
 use std::cell::RefCell;
 use std::ops::Index;
@@ -29,7 +30,7 @@ pub struct DepTrackingMap<M: DepTrackingMapConfig> {
 pub trait DepTrackingMapConfig {
     type Key: Eq + Hash + Clone;
     type Value: Clone;
-    fn to_dep_node(key: &Self::Key) -> DepNode;
+    fn to_dep_node(key: &Self::Key) -> DepNode<DefId>;
 }
 
 impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
index d3ced8aa518bbb3f6e9a1d21aaaad3bbacf43188..10f3d21f2af6d37eeb265f293278785543b99dfb 100644 (file)
@@ -9,11 +9,13 @@
 // except according to those terms.
 
 use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet};
+use std::fmt::Debug;
+use std::hash::Hash;
 use super::{DepGraphQuery, DepNode};
 
-pub struct DepGraphEdges {
-    nodes: Vec<DepNode>,
-    indices: FnvHashMap<DepNode, IdIndex>,
+pub struct DepGraphEdges<D: Clone + Debug + Eq + Hash> {
+    nodes: Vec<DepNode<D>>,
+    indices: FnvHashMap<DepNode<D>, IdIndex>,
     edges: FnvHashSet<(IdIndex, IdIndex)>,
     open_nodes: Vec<OpenNode>,
 }
@@ -40,8 +42,8 @@ enum OpenNode {
     Ignore,
 }
 
-impl DepGraphEdges {
-    pub fn new() -> DepGraphEdges {
+impl<D: Clone + Debug + Eq + Hash> DepGraphEdges<D> {
+    pub fn new() -> DepGraphEdges<D> {
         DepGraphEdges {
             nodes: vec![],
             indices: FnvHashMap(),
@@ -50,12 +52,12 @@ pub fn new() -> DepGraphEdges {
         }
     }
 
-    fn id(&self, index: IdIndex) -> DepNode {
-        self.nodes[index.index()]
+    fn id(&self, index: IdIndex) -> DepNode<D> {
+        self.nodes[index.index()].clone()
     }
 
     /// Creates a node for `id` in the graph.
-    fn make_node(&mut self, id: DepNode) -> IdIndex {
+    fn make_node(&mut self, id: DepNode<D>) -> IdIndex {
         if let Some(&i) = self.indices.get(&id) {
             return i;
         }
@@ -80,7 +82,7 @@ pub fn pop_ignore(&mut self) {
         assert_eq!(popped_node, OpenNode::Ignore);
     }
 
-    pub fn push_task(&mut self, key: DepNode) {
+    pub fn push_task(&mut self, key: DepNode<D>) {
         let top_node = self.current_node();
 
         let new_node = self.make_node(key);
@@ -93,7 +95,7 @@ pub fn push_task(&mut self, key: DepNode) {
         }
     }
 
-    pub fn pop_task(&mut self, key: DepNode) {
+    pub fn pop_task(&mut self, key: DepNode<D>) {
         let popped_node = self.open_nodes.pop().unwrap();
         assert_eq!(OpenNode::Node(self.indices[&key]), popped_node);
     }
@@ -101,7 +103,7 @@ pub fn pop_task(&mut self, key: DepNode) {
     /// Indicates that the current task `C` reads `v` by adding an
     /// edge from `v` to `C`. If there is no current task, panics. If
     /// you want to suppress this edge, use `ignore`.
-    pub fn read(&mut self, v: DepNode) {
+    pub fn read(&mut self, v: DepNode<D>) {
         let source = self.make_node(v);
         self.add_edge_from_current_node(|current| (source, current))
     }
@@ -109,7 +111,7 @@ pub fn read(&mut self, v: DepNode) {
     /// Indicates that the current task `C` writes `v` by adding an
     /// edge from `C` to `v`. If there is no current task, panics. If
     /// you want to suppress this edge, use `ignore`.
-    pub fn write(&mut self, v: DepNode) {
+    pub fn write(&mut self, v: DepNode<D>) {
         let target = self.make_node(v);
         self.add_edge_from_current_node(|current| (current, target))
     }
@@ -153,7 +155,7 @@ fn add_edge_from_open_node<OP>(&mut self,
         }
     }
 
-    pub fn query(&self) -> DepGraphQuery {
+    pub fn query(&self) -> DepGraphQuery<D> {
         let edges: Vec<_> = self.edges.iter()
                                       .map(|&(i, j)| (self.id(i), self.id(j)))
                                       .collect();
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
new file mode 100644 (file)
index 0000000..741ad65
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use hir::def_id::DefId;
+use std::rc::Rc;
+
+use super::dep_node::DepNode;
+use super::query::DepGraphQuery;
+use super::raii;
+use super::thread::{DepGraphThreadData, DepMessage};
+
+#[derive(Clone)]
+pub struct DepGraph {
+    data: Rc<DepGraphThreadData>
+}
+
+impl DepGraph {
+    pub fn new(enabled: bool) -> DepGraph {
+        DepGraph {
+            data: Rc::new(DepGraphThreadData::new(enabled))
+        }
+    }
+
+    /// True if we are actually building a dep-graph. If this returns false,
+    /// then the other methods on this `DepGraph` will have no net effect.
+    #[inline]
+    pub fn enabled(&self) -> bool {
+        self.data.enabled()
+    }
+
+    pub fn query(&self) -> DepGraphQuery<DefId> {
+        self.data.query()
+    }
+
+    pub fn in_ignore<'graph>(&'graph self) -> raii::IgnoreTask<'graph> {
+        raii::IgnoreTask::new(&self.data)
+    }
+
+    pub fn in_task<'graph>(&'graph self, key: DepNode<DefId>) -> raii::DepTask<'graph> {
+        raii::DepTask::new(&self.data, key)
+    }
+
+    pub fn with_ignore<OP,R>(&self, op: OP) -> R
+        where OP: FnOnce() -> R
+    {
+        let _task = self.in_ignore();
+        op()
+    }
+
+    pub fn with_task<OP,R>(&self, key: DepNode<DefId>, op: OP) -> R
+        where OP: FnOnce() -> R
+    {
+        let _task = self.in_task(key);
+        op()
+    }
+
+    pub fn read(&self, v: DepNode<DefId>) {
+        self.data.enqueue(DepMessage::Read(v));
+    }
+
+    pub fn write(&self, v: DepNode<DefId>) {
+        self.data.enqueue(DepMessage::Write(v));
+    }
+}
index 55ec56a4bbe669a5597f42d630129cd9080b580e..49481dcb79672faecec8a671dc2f05c515b8b5c3 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use self::thread::{DepGraphThreadData, DepMessage};
-use hir::def_id::DefId;
-use syntax::ast::NodeId;
-use ty::TyCtxt;
-use hir;
-use hir::intravisit::Visitor;
-use std::rc::Rc;
-
+mod dep_node;
 mod dep_tracking_map;
 mod edges;
+mod graph;
 mod query;
 mod raii;
 mod thread;
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub enum DepNode {
-    // Represents the `Krate` as a whole (the `hir::Krate` value) (as
-    // distinct from the krate module). This is basically a hash of
-    // the entire krate, so if you read from `Krate` (e.g., by calling
-    // `tcx.map.krate()`), we will have to assume that any change
-    // means that you need to be recompiled. This is because the
-    // `Krate` value gives you access to all other items. To avoid
-    // this fate, do not call `tcx.map.krate()`; instead, prefer
-    // wrappers like `tcx.visit_all_items_in_krate()`.  If there is no
-    // suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
-    // access to the krate, but you must remember to add suitable
-    // edges yourself for the individual items that you read.
-    Krate,
-
-    // Represents the HIR node with the given node-id
-    Hir(DefId),
-
-    // Represents different phases in the compiler.
-    CrateReader,
-    CollectLanguageItems,
-    CheckStaticRecursion,
-    ResolveLifetimes,
-    RegionResolveCrate,
-    CheckLoops,
-    PluginRegistrar,
-    StabilityIndex,
-    CollectItem(DefId),
-    Coherence,
-    EffectCheck,
-    Liveness,
-    Resolve,
-    EntryPoint,
-    CheckEntryFn,
-    CoherenceCheckImpl(DefId),
-    CoherenceOverlapCheck(DefId),
-    CoherenceOverlapCheckSpecial(DefId),
-    CoherenceOverlapInherentCheck(DefId),
-    CoherenceOrphanCheck(DefId),
-    Variance,
-    WfCheck(DefId),
-    TypeckItemType(DefId),
-    TypeckItemBody(DefId),
-    Dropck,
-    DropckImpl(DefId),
-    CheckConst(DefId),
-    Privacy,
-    IntrinsicCheck(DefId),
-    MatchCheck(DefId),
-    MirMapConstruction(DefId),
-    MirTypeck(NodeId),
-    BorrowCheck(DefId),
-    RvalueCheck(DefId),
-    Reachability,
-    DeadCheck,
-    StabilityCheck,
-    LateLintCheck,
-    IntrinsicUseCheck,
-    TransCrate,
-    TransCrateItem(DefId),
-    TransInlinedItem(DefId),
-    TransWriteMetadata,
-
-    // Nodes representing bits of computed IR in the tcx. Each shared
-    // table in the tcx (or elsewhere) maps to one of these
-    // nodes. Often we map multiple tables to the same node if there
-    // is no point in distinguishing them (e.g., both the type and
-    // predicates for an item wind up in `ItemSignature`). Other
-    // times, such as `ImplItems` vs `TraitItemDefIds`, tables which
-    // might be mergable are kept distinct because the sets of def-ids
-    // to which they apply are disjoint, and hence we might as well
-    // have distinct labels for easier debugging.
-    ImplOrTraitItems(DefId),
-    ItemSignature(DefId),
-    FieldTy(DefId),
-    TraitItemDefIds(DefId),
-    InherentImpls(DefId),
-    ImplItems(DefId),
-
-    // The set of impls for a given trait. Ultimately, it would be
-    // nice to get more fine-grained here (e.g., to include a
-    // simplified type), but we can't do that until we restructure the
-    // HIR to distinguish the *header* of an impl from its body.  This
-    // is because changes to the header may change the self-type of
-    // the impl and hence would require us to be more conservative
-    // than changes in the impl body.
-    TraitImpls(DefId),
-
-    // Nodes representing caches. To properly handle a true cache, we
-    // don't use a DepTrackingMap, but rather we push a task node.
-    // Otherwise the write into the map would be incorrectly
-    // attributed to the first task that happened to fill the cache,
-    // which would yield an overly conservative dep-graph.
-    TraitItems(DefId),
-    ReprHints(DefId),
-    TraitSelect(DefId),
-}
-
-#[derive(Clone)]
-pub struct DepGraph {
-    data: Rc<DepGraphThreadData>
-}
-
-impl DepGraph {
-    pub fn new(enabled: bool) -> DepGraph {
-        DepGraph {
-            data: Rc::new(DepGraphThreadData::new(enabled))
-        }
-    }
-
-    /// True if we are actually building a dep-graph. If this returns false,
-    /// then the other methods on this `DepGraph` will have no net effect.
-    #[inline]
-    pub fn enabled(&self) -> bool {
-        self.data.enabled()
-    }
-
-    pub fn query(&self) -> DepGraphQuery {
-        self.data.query()
-    }
-
-    pub fn in_ignore<'graph>(&'graph self) -> raii::IgnoreTask<'graph> {
-        raii::IgnoreTask::new(&self.data)
-    }
-
-    pub fn in_task<'graph>(&'graph self, key: DepNode) -> raii::DepTask<'graph> {
-        raii::DepTask::new(&self.data, key)
-    }
-
-    pub fn with_ignore<OP,R>(&self, op: OP) -> R
-        where OP: FnOnce() -> R
-    {
-        let _task = self.in_ignore();
-        op()
-    }
-
-    pub fn with_task<OP,R>(&self, key: DepNode, op: OP) -> R
-        where OP: FnOnce() -> R
-    {
-        let _task = self.in_task(key);
-        op()
-    }
-
-    pub fn read(&self, v: DepNode) {
-        self.data.enqueue(DepMessage::Read(v));
-    }
-
-    pub fn write(&self, v: DepNode) {
-        self.data.enqueue(DepMessage::Write(v));
-    }
-}
+mod visit;
 
 pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
-
+pub use self::dep_node::DepNode;
+pub use self::graph::DepGraph;
 pub use self::query::DepGraphQuery;
-
-/// Visit all the items in the krate in some order. When visiting a
-/// particular item, first create a dep-node by calling `dep_node_fn`
-/// and push that onto the dep-graph stack of tasks, and also create a
-/// read edge from the corresponding AST node. This is used in
-/// compiler passes to automatically record the item that they are
-/// working on.
-pub fn visit_all_items_in_krate<'tcx,V,F>(tcx: &TyCtxt<'tcx>,
-                                          mut dep_node_fn: F,
-                                          visitor: &mut V)
-    where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx>
-{
-    struct TrackingVisitor<'visit, 'tcx: 'visit, F: 'visit, V: 'visit> {
-        tcx: &'visit TyCtxt<'tcx>,
-        dep_node_fn: &'visit mut F,
-        visitor: &'visit mut V
-    }
-
-    impl<'visit, 'tcx, F, V> Visitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V>
-        where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx>
-    {
-        fn visit_item(&mut self, i: &'tcx hir::Item) {
-            let item_def_id = self.tcx.map.local_def_id(i.id);
-            let task_id = (self.dep_node_fn)(item_def_id);
-            let _task = self.tcx.dep_graph.in_task(task_id);
-            debug!("Started task {:?}", task_id);
-            self.tcx.dep_graph.read(DepNode::Hir(item_def_id));
-            self.visitor.visit_item(i)
-        }
-    }
-
-    let krate = tcx.dep_graph.with_ignore(|| tcx.map.krate());
-    let mut tracking_visitor = TrackingVisitor {
-        tcx: tcx,
-        dep_node_fn: &mut dep_node_fn,
-        visitor: visitor
-    };
-    krate.visit_all_items(&mut tracking_visitor)
-}
+pub use self::visit::visit_all_items_in_krate;
index 74a054acb4fa05c98aabf3c5a4afab035626ce3e..acc6660da6e8934ae144aa78e6d4456490681d48 100644 (file)
 
 use rustc_data_structures::fnv::FnvHashMap;
 use rustc_data_structures::graph::{Graph, NodeIndex};
+use std::fmt::Debug;
+use std::hash::Hash;
 
 use super::DepNode;
 
-pub struct DepGraphQuery {
-    pub graph: Graph<DepNode, ()>,
-    pub indices: FnvHashMap<DepNode, NodeIndex>,
+pub struct DepGraphQuery<D: Clone + Debug + Hash + Eq> {
+    pub graph: Graph<DepNode<D>, ()>,
+    pub indices: FnvHashMap<DepNode<D>, NodeIndex>,
 }
 
-impl DepGraphQuery {
-    pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery {
+impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> {
+    pub fn new(nodes: &[DepNode<D>],
+               edges: &[(DepNode<D>, DepNode<D>)])
+               -> DepGraphQuery<D> {
         let mut graph = Graph::new();
         let mut indices = FnvHashMap();
         for node in nodes {
@@ -39,27 +43,43 @@ pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery {
         }
     }
 
-    pub fn nodes(&self) -> Vec<DepNode> {
+    pub fn contains_node(&self, node: &DepNode<D>) -> bool {
+        self.indices.contains_key(&node)
+    }
+
+    pub fn nodes(&self) -> Vec<DepNode<D>> {
         self.graph.all_nodes()
                   .iter()
                   .map(|n| n.data.clone())
                   .collect()
     }
 
-    pub fn edges(&self) -> Vec<(DepNode,DepNode)> {
+    pub fn edges(&self) -> Vec<(DepNode<D>,DepNode<D>)> {
         self.graph.all_edges()
                   .iter()
                   .map(|edge| (edge.source(), edge.target()))
-                  .map(|(s, t)| (self.graph.node_data(s).clone(), self.graph.node_data(t).clone()))
+                  .map(|(s, t)| (self.graph.node_data(s).clone(),
+                                 self.graph.node_data(t).clone()))
                   .collect()
     }
 
     /// All nodes reachable from `node`. In other words, things that
     /// will have to be recomputed if `node` changes.
-    pub fn dependents(&self, node: DepNode) -> Vec<DepNode> {
+    pub fn transitive_dependents(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
         if let Some(&index) = self.indices.get(&node) {
             self.graph.depth_traverse(index)
-                      .map(|dependent_node| self.graph.node_data(dependent_node).clone())
+                      .map(|s| self.graph.node_data(s).clone())
+                      .collect()
+        } else {
+            vec![]
+        }
+    }
+
+    /// Just the outgoing edges from `node`.
+    pub fn immediate_dependents(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
+        if let Some(&index) = self.indices.get(&node) {
+            self.graph.successor_nodes(index)
+                      .map(|s| self.graph.node_data(s).clone())
                       .collect()
         } else {
             vec![]
index dd7ff92f9c360d2b9d2d878a0bc272258c81b9ed..13151d169fc3f78843405d5a1829ec9d2823d985 100644 (file)
@@ -8,16 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use hir::def_id::DefId;
 use super::DepNode;
 use super::thread::{DepGraphThreadData, DepMessage};
 
 pub struct DepTask<'graph> {
     data: &'graph DepGraphThreadData,
-    key: DepNode,
+    key: DepNode<DefId>,
 }
 
 impl<'graph> DepTask<'graph> {
-    pub fn new(data: &'graph DepGraphThreadData, key: DepNode) -> DepTask<'graph> {
+    pub fn new(data: &'graph DepGraphThreadData, key: DepNode<DefId>)
+               -> DepTask<'graph> {
         data.enqueue(DepMessage::PushTask(key));
         DepTask { data: data, key: key }
     }
index 1b1d3469bc53f6428a9fc6c1f12c0a82a7a7f8dd..5b0e4a909c8d3d7aeeade5edc26361eb2da149ae 100644 (file)
@@ -18,6 +18,7 @@
 //! to accumulate more messages. This way we only ever have two vectors
 //! allocated (and both have a fairly large capacity).
 
+use hir::def_id::DefId;
 use rustc_data_structures::veccell::VecCell;
 use std::cell::Cell;
 use std::sync::mpsc::{self, Sender, Receiver};
 use super::edges::DepGraphEdges;
 
 pub enum DepMessage {
-    Read(DepNode),
-    Write(DepNode),
-    PushTask(DepNode),
-    PopTask(DepNode),
+    Read(DepNode<DefId>),
+    Write(DepNode<DefId>),
+    PushTask(DepNode<DefId>),
+    PopTask(DepNode<DefId>),
     PushIgnore,
     PopIgnore,
     Query,
@@ -57,7 +58,7 @@ pub struct DepGraphThreadData {
     swap_out: Sender<Vec<DepMessage>>,
 
     // where to receive query results
-    query_in: Receiver<DepGraphQuery>,
+    query_in: Receiver<DepGraphQuery<DefId>>,
 }
 
 const INITIAL_CAPACITY: usize = 2048;
@@ -105,7 +106,7 @@ fn swap(&self) {
         self.swap_out.send(old_messages).unwrap();
     }
 
-    pub fn query(&self) -> DepGraphQuery {
+    pub fn query(&self) -> DepGraphQuery<DefId> {
         assert!(self.enabled, "cannot query if dep graph construction not enabled");
         self.enqueue(DepMessage::Query);
         self.swap();
@@ -155,7 +156,7 @@ fn invalid_message(&self, string: &str) {
 /// Definition of the depgraph thread.
 pub fn main(swap_in: Receiver<Vec<DepMessage>>,
             swap_out: Sender<Vec<DepMessage>>,
-            query_out: Sender<DepGraphQuery>) {
+            query_out: Sender<DepGraphQuery<DefId>>) {
     let mut edges = DepGraphEdges::new();
 
     // the compiler thread always expects a fresh buffer to be
diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs
new file mode 100644 (file)
index 0000000..cdc1621
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use hir;
+use hir::def_id::DefId;
+use hir::intravisit::Visitor;
+use ty::TyCtxt;
+
+use super::dep_node::DepNode;
+
+
+/// Visit all the items in the krate in some order. When visiting a
+/// particular item, first create a dep-node by calling `dep_node_fn`
+/// and push that onto the dep-graph stack of tasks, and also create a
+/// read edge from the corresponding AST node. This is used in
+/// compiler passes to automatically record the item that they are
+/// working on.
+pub fn visit_all_items_in_krate<'tcx,V,F>(tcx: &TyCtxt<'tcx>,
+                                          mut dep_node_fn: F,
+                                          visitor: &mut V)
+    where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'tcx>
+{
+    struct TrackingVisitor<'visit, 'tcx: 'visit, F: 'visit, V: 'visit> {
+        tcx: &'visit TyCtxt<'tcx>,
+        dep_node_fn: &'visit mut F,
+        visitor: &'visit mut V
+    }
+
+    impl<'visit, 'tcx, F, V> Visitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V>
+        where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'tcx>
+    {
+        fn visit_item(&mut self, i: &'tcx hir::Item) {
+            let item_def_id = self.tcx.map.local_def_id(i.id);
+            let task_id = (self.dep_node_fn)(item_def_id);
+            let _task = self.tcx.dep_graph.in_task(task_id);
+            debug!("Started task {:?}", task_id);
+            self.tcx.dep_graph.read(DepNode::Hir(item_def_id));
+            self.visitor.visit_item(i)
+        }
+    }
+
+    let krate = tcx.dep_graph.with_ignore(|| tcx.map.krate());
+    let mut tracking_visitor = TrackingVisitor {
+        tcx: tcx,
+        dep_node_fn: &mut dep_node_fn,
+        visitor: visitor
+    };
+    krate.visit_all_items(&mut tracking_visitor)
+}
index d045313cb1e972f29925baebde6e5a52beab816f..2e26fe5057e2f6913bad177ded8c74e75a652f7f 100644 (file)
@@ -203,17 +203,56 @@ pub fn as_local_node_id(&self, def_id: DefId) -> Option<ast::NodeId> {
         }
     }
 
+    pub fn retrace_path(&self, path: &DefPath) -> Option<DefIndex> {
+        debug!("retrace_path(path={:?})", path);
+
+        // we assume that we only want to retrace paths relative to
+        // the crate root
+        assert!(path.is_local());
+
+        let root_key = DefKey {
+            parent: None,
+            disambiguated_data: DisambiguatedDefPathData {
+                data: DefPathData::CrateRoot,
+                disambiguator: 0,
+            },
+        };
+        let root_id = self.key_map[&root_key];
+
+        debug!("retrace_path: root_id={:?}", root_id);
+
+        let mut id = root_id;
+        for data in &path.data {
+            let key = DefKey { parent: Some(id), disambiguated_data: data.clone() };
+            debug!("key = {:?}", key);
+            id = match self.key_map.get(&key) {
+                Some(&id) => id,
+                None => return None
+            };
+        }
+
+        Some(id)
+    }
+
     pub fn create_def_with_parent(&mut self,
                                   parent: Option<DefIndex>,
                                   node_id: ast::NodeId,
                                   data: DefPathData)
                                   -> DefIndex {
+        debug!("create_def_with_parent(parent={:?}, node_id={:?}, data={:?})",
+               parent, node_id, data);
+
         assert!(!self.node_map.contains_key(&node_id),
                 "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
                 node_id,
                 data,
                 self.data[self.node_map[&node_id].as_usize()]);
 
+        assert!(parent.is_some() ^ match data {
+            DefPathData::CrateRoot | DefPathData::InlinedRoot(_) => true,
+            _ => false,
+        });
+
         // Find a unique DefKey. This basically means incrementing the disambiguator
         // until we get no match.
         let mut key = DefKey {
@@ -228,12 +267,17 @@ pub fn create_def_with_parent(&mut self,
             key.disambiguated_data.disambiguator += 1;
         }
 
+        debug!("create_def_with_parent: after disambiguation, key = {:?}", key);
+
         // Create the definition.
         let index = DefIndex::new(self.data.len());
         self.data.push(DefData { key: key.clone(), node_id: node_id });
+        debug!("create_def_with_parent: node_map[{:?}] = {:?}", node_id, index);
         self.node_map.insert(node_id, index);
+        debug!("create_def_with_parent: key_map[{:?}] = {:?}", key, index);
         self.key_map.insert(key, index);
 
+
         index
     }
 }
index fc1c4aeb226012b09c0d33ad314e00497eb38822..7b8ddee0e23cbb9e582fc35c492afe4d675c41aa 100644 (file)
@@ -208,7 +208,7 @@ fn read(&self, id: NodeId) {
         self.dep_graph.read(self.dep_node(id));
     }
 
-    fn dep_node(&self, id0: NodeId) -> DepNode {
+    fn dep_node(&self, id0: NodeId) -> DepNode<DefId> {
         let map = self.map.borrow();
         let mut id = id0;
         loop {
@@ -282,6 +282,11 @@ pub fn def_path(&self, def_id: DefId) -> DefPath {
         self.definitions.borrow().def_path(def_id.index)
     }
 
+    pub fn retrace_path(&self, path: &DefPath) -> Option<DefId> {
+        self.definitions.borrow().retrace_path(path)
+                                 .map(DefId::local)
+    }
+
     pub fn local_def_id(&self, node: NodeId) -> DefId {
         self.opt_local_def_id(node).unwrap_or_else(|| {
             bug!("local_def_id: no entry for `{}`, which has a map of `{:?}`",
index 7affb129313c886015b53931c07bbd570bd21acc..e9ed0ed574eaffb9c2f7aa69e099af529644e9ad 100644 (file)
@@ -1494,11 +1494,14 @@ pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
 
                 let mut out_idx = 0;
                 self.commasep(Inconsistent, &a.outputs, |s, out| {
-                    match out.constraint.slice_shift_char() {
-                        Some(('=', operand)) if out.is_rw => {
-                            s.print_string(&format!("+{}", operand), ast::StrStyle::Cooked)?
+                    let mut ch = out.constraint.chars();
+                    match ch.next() {
+                        Some('=') if out.is_rw => {
+                            s.print_string(&format!("+{}", ch.as_str()),
+                                           ast::StrStyle::Cooked)?
                         }
-                        _ => s.print_string(&out.constraint, ast::StrStyle::Cooked)?,
+                        _ => s.print_string(&out.constraint,
+                                            ast::StrStyle::Cooked)?,
                     }
                     s.popen()?;
                     s.print_expr(&outputs[out_idx])?;
index 7ae20f68ad0c2af3969f765c949c04013893ee7a..08c3d70034a0de516ea5cf918c6f653de869c2c6 100644 (file)
@@ -47,9 +47,6 @@
 //! Original issue: https://github.com/rust-lang/rust/issues/10207
 
 use std::fmt;
-use std::hash::{Hash, SipHasher, Hasher};
-use hir;
-use hir::intravisit as visit;
 
 #[derive(Clone, PartialEq, Debug)]
 pub struct Svh {
@@ -57,53 +54,16 @@ pub struct Svh {
 }
 
 impl Svh {
-    pub fn new(hash: &str) -> Svh {
+    /// Create a new `Svh` given the hash. If you actually want to
+    /// compute the SVH from some HIR, you want the `calculate_svh`
+    /// function found in `librustc_trans`.
+    pub fn new(hash: String) -> Svh {
         assert!(hash.len() == 16);
-        Svh { hash: hash.to_string() }
+        Svh { hash: hash }
     }
 
-    pub fn as_str<'a>(&'a self) -> &'a str {
-        &self.hash
-    }
-
-    pub fn calculate(crate_disambiguator: &str, krate: &hir::Crate) -> Svh {
-        // FIXME (#14132): This is better than it used to be, but it still not
-        // ideal. We now attempt to hash only the relevant portions of the
-        // Crate AST as well as the top-level crate attributes. (However,
-        // the hashing of the crate attributes should be double-checked
-        // to ensure it is not incorporating implementation artifacts into
-        // the hash that are not otherwise visible.)
-
-        // FIXME: this should use SHA1, not SipHash. SipHash is not built to
-        //        avoid collisions.
-        let mut state = SipHasher::new();
-
-        "crate_disambiguator".hash(&mut state);
-        crate_disambiguator.len().hash(&mut state);
-        crate_disambiguator.hash(&mut state);
-
-        {
-            let mut visit = svh_visitor::make(&mut state, krate);
-            visit::walk_crate(&mut visit, krate);
-        }
-
-        // FIXME (#14132): This hash is still sensitive to e.g. the
-        // spans of the crate Attributes and their underlying
-        // MetaItems; we should make ContentHashable impl for those
-        // types and then use hash_content.  But, since all crate
-        // attributes should appear near beginning of the file, it is
-        // not such a big deal to be sensitive to their spans for now.
-        //
-        // We hash only the MetaItems instead of the entire Attribute
-        // to avoid hashing the AttrId
-        for attr in &krate.attrs {
-            attr.node.value.hash(&mut state);
-        }
-
-        let hash = state.finish();
-        return Svh {
-            hash: (0..64).step_by(4).map(|i| hex(hash >> i)).collect()
-        };
+    pub fn from_hash(hash: u64) -> Svh {
+        return Svh::new((0..64).step_by(4).map(|i| hex(hash >> i)).collect());
 
         fn hex(b: u64) -> char {
             let b = (b & 0xf) as u8;
@@ -114,6 +74,10 @@ fn hex(b: u64) -> char {
             b as char
         }
     }
+
+    pub fn as_str<'a>(&'a self) -> &'a str {
+        &self.hash
+    }
 }
 
 impl fmt::Display for Svh {
@@ -121,319 +85,3 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.pad(self.as_str())
     }
 }
-
-// FIXME (#14132): Even this SVH computation still has implementation
-// artifacts: namely, the order of item declaration will affect the
-// hash computation, but for many kinds of items the order of
-// declaration should be irrelevant to the ABI.
-
-mod svh_visitor {
-    pub use self::SawExprComponent::*;
-    pub use self::SawStmtComponent::*;
-    use self::SawAbiComponent::*;
-    use syntax::ast::{self, Name, NodeId};
-    use syntax::codemap::Span;
-    use syntax::parse::token;
-    use hir::intravisit as visit;
-    use hir::intravisit::{Visitor, FnKind};
-    use hir::*;
-    use hir;
-
-    use std::hash::{Hash, SipHasher};
-
-    pub struct StrictVersionHashVisitor<'a> {
-        pub krate: &'a Crate,
-        pub st: &'a mut SipHasher,
-    }
-
-    pub fn make<'a>(st: &'a mut SipHasher, krate: &'a Crate) -> StrictVersionHashVisitor<'a> {
-        StrictVersionHashVisitor { st: st, krate: krate }
-    }
-
-    // To off-load the bulk of the hash-computation on #[derive(Hash)],
-    // we define a set of enums corresponding to the content that our
-    // crate visitor will encounter as it traverses the ast.
-    //
-    // The important invariant is that all of the Saw*Component enums
-    // do not carry any Spans, Names, or Idents.
-    //
-    // Not carrying any Names/Idents is the important fix for problem
-    // noted on PR #13948: using the ident.name as the basis for a
-    // hash leads to unstable SVH, because ident.name is just an index
-    // into intern table (i.e. essentially a random address), not
-    // computed from the name content.
-    //
-    // With the below enums, the SVH computation is not sensitive to
-    // artifacts of how rustc was invoked nor of how the source code
-    // was laid out.  (Or at least it is *less* sensitive.)
-
-    // This enum represents the different potential bits of code the
-    // visitor could encounter that could affect the ABI for the crate,
-    // and assigns each a distinct tag to feed into the hash computation.
-    #[derive(Hash)]
-    enum SawAbiComponent<'a> {
-
-        // FIXME (#14132): should we include (some function of)
-        // ident.ctxt as well?
-        SawIdent(token::InternedString),
-        SawStructDef(token::InternedString),
-
-        SawLifetime(token::InternedString),
-        SawLifetimeDef(token::InternedString),
-
-        SawMod,
-        SawForeignItem,
-        SawItem,
-        SawDecl,
-        SawTy,
-        SawGenerics,
-        SawFn,
-        SawTraitItem,
-        SawImplItem,
-        SawStructField,
-        SawVariant,
-        SawExplicitSelf,
-        SawPath,
-        SawBlock,
-        SawPat,
-        SawLocal,
-        SawArm,
-        SawExpr(SawExprComponent<'a>),
-        SawStmt(SawStmtComponent),
-    }
-
-    /// SawExprComponent carries all of the information that we want
-    /// to include in the hash that *won't* be covered by the
-    /// subsequent recursive traversal of the expression's
-    /// substructure by the visitor.
-    ///
-    /// We know every Expr_ variant is covered by a variant because
-    /// `fn saw_expr` maps each to some case below.  Ensuring that
-    /// each variant carries an appropriate payload has to be verified
-    /// by hand.
-    ///
-    /// (However, getting that *exactly* right is not so important
-    /// because the SVH is just a developer convenience; there is no
-    /// guarantee of collision-freedom, hash collisions are just
-    /// (hopefully) unlikely.)
-    #[derive(Hash)]
-    pub enum SawExprComponent<'a> {
-
-        SawExprLoop(Option<token::InternedString>),
-        SawExprField(token::InternedString),
-        SawExprTupField(usize),
-        SawExprBreak(Option<token::InternedString>),
-        SawExprAgain(Option<token::InternedString>),
-
-        SawExprBox,
-        SawExprVec,
-        SawExprCall,
-        SawExprMethodCall,
-        SawExprTup,
-        SawExprBinary(hir::BinOp_),
-        SawExprUnary(hir::UnOp),
-        SawExprLit(ast::LitKind),
-        SawExprCast,
-        SawExprType,
-        SawExprIf,
-        SawExprWhile,
-        SawExprMatch,
-        SawExprClosure,
-        SawExprBlock,
-        SawExprAssign,
-        SawExprAssignOp(hir::BinOp_),
-        SawExprIndex,
-        SawExprPath(Option<usize>),
-        SawExprAddrOf(hir::Mutability),
-        SawExprRet,
-        SawExprInlineAsm(&'a hir::InlineAsm),
-        SawExprStruct,
-        SawExprRepeat,
-    }
-
-    fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
-        match *node {
-            ExprBox(..)              => SawExprBox,
-            ExprVec(..)              => SawExprVec,
-            ExprCall(..)             => SawExprCall,
-            ExprMethodCall(..)       => SawExprMethodCall,
-            ExprTup(..)              => SawExprTup,
-            ExprBinary(op, _, _)     => SawExprBinary(op.node),
-            ExprUnary(op, _)         => SawExprUnary(op),
-            ExprLit(ref lit)         => SawExprLit(lit.node.clone()),
-            ExprCast(..)             => SawExprCast,
-            ExprType(..)             => SawExprType,
-            ExprIf(..)               => SawExprIf,
-            ExprWhile(..)            => SawExprWhile,
-            ExprLoop(_, id)          => SawExprLoop(id.map(|id| id.name.as_str())),
-            ExprMatch(..)            => SawExprMatch,
-            ExprClosure(..)          => SawExprClosure,
-            ExprBlock(..)            => SawExprBlock,
-            ExprAssign(..)           => SawExprAssign,
-            ExprAssignOp(op, _, _)   => SawExprAssignOp(op.node),
-            ExprField(_, name)       => SawExprField(name.node.as_str()),
-            ExprTupField(_, id)      => SawExprTupField(id.node),
-            ExprIndex(..)            => SawExprIndex,
-            ExprPath(ref qself, _)   => SawExprPath(qself.as_ref().map(|q| q.position)),
-            ExprAddrOf(m, _)         => SawExprAddrOf(m),
-            ExprBreak(id)            => SawExprBreak(id.map(|id| id.node.name.as_str())),
-            ExprAgain(id)            => SawExprAgain(id.map(|id| id.node.name.as_str())),
-            ExprRet(..)              => SawExprRet,
-            ExprInlineAsm(ref a,_,_) => SawExprInlineAsm(a),
-            ExprStruct(..)           => SawExprStruct,
-            ExprRepeat(..)           => SawExprRepeat,
-        }
-    }
-
-    /// SawStmtComponent is analogous to SawExprComponent, but for statements.
-    #[derive(Hash)]
-    pub enum SawStmtComponent {
-        SawStmtDecl,
-        SawStmtExpr,
-        SawStmtSemi,
-    }
-
-    fn saw_stmt(node: &Stmt_) -> SawStmtComponent {
-        match *node {
-            StmtDecl(..) => SawStmtDecl,
-            StmtExpr(..) => SawStmtExpr,
-            StmtSemi(..) => SawStmtSemi,
-        }
-    }
-
-    impl<'a> Visitor<'a> for StrictVersionHashVisitor<'a> {
-        fn visit_nested_item(&mut self, item: ItemId) {
-            self.visit_item(self.krate.item(item.id))
-        }
-
-        fn visit_variant_data(&mut self, s: &'a VariantData, name: Name,
-                              g: &'a Generics, _: NodeId, _: Span) {
-            SawStructDef(name.as_str()).hash(self.st);
-            visit::walk_generics(self, g);
-            visit::walk_struct_def(self, s)
-        }
-
-        fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
-            SawVariant.hash(self.st);
-            // walk_variant does not call walk_generics, so do it here.
-            visit::walk_generics(self, g);
-            visit::walk_variant(self, v, g, item_id)
-        }
-
-        // All of the remaining methods just record (in the hash
-        // SipHasher) that the visitor saw that particular variant
-        // (with its payload), and continue walking as the default
-        // visitor would.
-        //
-        // Some of the implementations have some notes as to how one
-        // might try to make their SVH computation less discerning
-        // (e.g. by incorporating reachability analysis).  But
-        // currently all of their implementations are uniform and
-        // uninteresting.
-        //
-        // (If you edit a method such that it deviates from the
-        // pattern, please move that method up above this comment.)
-
-        fn visit_name(&mut self, _: Span, name: Name) {
-            SawIdent(name.as_str()).hash(self.st);
-        }
-
-        fn visit_lifetime(&mut self, l: &'a Lifetime) {
-            SawLifetime(l.name.as_str()).hash(self.st);
-        }
-
-        fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) {
-            SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st);
-        }
-
-        // We do recursively walk the bodies of functions/methods
-        // (rather than omitting their bodies from the hash) since
-        // monomorphization and cross-crate inlining generally implies
-        // that a change to a crate body will require downstream
-        // crates to be recompiled.
-        fn visit_expr(&mut self, ex: &'a Expr) {
-            SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex)
-        }
-
-        fn visit_stmt(&mut self, s: &'a Stmt) {
-            SawStmt(saw_stmt(&s.node)).hash(self.st); visit::walk_stmt(self, s)
-        }
-
-        fn visit_foreign_item(&mut self, i: &'a ForeignItem) {
-            // FIXME (#14132) ideally we would incorporate privacy (or
-            // perhaps reachability) somewhere here, so foreign items
-            // that do not leak into downstream crates would not be
-            // part of the ABI.
-            SawForeignItem.hash(self.st); visit::walk_foreign_item(self, i)
-        }
-
-        fn visit_item(&mut self, i: &'a Item) {
-            // FIXME (#14132) ideally would incorporate reachability
-            // analysis somewhere here, so items that never leak into
-            // downstream crates (e.g. via monomorphisation or
-            // inlining) would not be part of the ABI.
-            SawItem.hash(self.st); visit::walk_item(self, i)
-        }
-
-        fn visit_mod(&mut self, m: &'a Mod, _s: Span, _n: NodeId) {
-            SawMod.hash(self.st); visit::walk_mod(self, m)
-        }
-
-        fn visit_decl(&mut self, d: &'a Decl) {
-            SawDecl.hash(self.st); visit::walk_decl(self, d)
-        }
-
-        fn visit_ty(&mut self, t: &'a Ty) {
-            SawTy.hash(self.st); visit::walk_ty(self, t)
-        }
-
-        fn visit_generics(&mut self, g: &'a Generics) {
-            SawGenerics.hash(self.st); visit::walk_generics(self, g)
-        }
-
-        fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl,
-                    b: &'a Block, s: Span, _: NodeId) {
-            SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s)
-        }
-
-        fn visit_trait_item(&mut self, ti: &'a TraitItem) {
-            SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti)
-        }
-
-        fn visit_impl_item(&mut self, ii: &'a ImplItem) {
-            SawImplItem.hash(self.st); visit::walk_impl_item(self, ii)
-        }
-
-        fn visit_struct_field(&mut self, s: &'a StructField) {
-            SawStructField.hash(self.st); visit::walk_struct_field(self, s)
-        }
-
-        fn visit_explicit_self(&mut self, es: &'a ExplicitSelf) {
-            SawExplicitSelf.hash(self.st); visit::walk_explicit_self(self, es)
-        }
-
-        fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) {
-            SawPath.hash(self.st); visit::walk_path(self, path)
-        }
-
-        fn visit_path_list_item(&mut self, prefix: &'a Path, item: &'a PathListItem) {
-            SawPath.hash(self.st); visit::walk_path_list_item(self, prefix, item)
-        }
-
-        fn visit_block(&mut self, b: &'a Block) {
-            SawBlock.hash(self.st); visit::walk_block(self, b)
-        }
-
-        fn visit_pat(&mut self, p: &'a Pat) {
-            SawPat.hash(self.st); visit::walk_pat(self, p)
-        }
-
-        fn visit_local(&mut self, l: &'a Local) {
-            SawLocal.hash(self.st); visit::walk_local(self, l)
-        }
-
-        fn visit_arm(&mut self, a: &'a Arm) {
-            SawArm.hash(self.st); visit::walk_arm(self, a)
-        }
-    }
-}
index deb206277722071cfbd8f903aca237d5f9b67a56..d1bbbf08ac230f5a261a619c7a74aaf433bb563f 100644 (file)
@@ -28,7 +28,6 @@
 #![feature(box_syntax)]
 #![feature(collections)]
 #![feature(const_fn)]
-#![feature(copy_from_slice)]
 #![feature(enumset)]
 #![feature(iter_arith)]
 #![feature(libc)]
@@ -39,7 +38,6 @@
 #![feature(slice_patterns)]
 #![feature(staged_api)]
 #![feature(step_by)]
-#![feature(str_char)]
 #![feature(question_mark)]
 #![cfg_attr(test, feature(test))]
 
index f8c0b63bf11bd41d36c1acc3d1b45912c603c83f..de349917258815ba538a176f83f3e48794f5d78a 100644 (file)
@@ -44,8 +44,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
         ty::tls::with_opt(|opt_tcx| {
             if let Some(tcx) = opt_tcx {
-                let data = tcx.region_maps.code_extents.borrow()[self.0 as usize];
-                write!(f, "/{:?}", data)?;
+                if let Some(data) = tcx.region_maps.code_extents.borrow().get(self.0 as usize) {
+                    write!(f, "/{:?}", data)?;
+                }
             }
             Ok(())
         })?;
index ae803f502318e394285d26ee2551d5638d354344..450d25b60671942be2ca8f4ac9d5b4d5f141974e 100644 (file)
@@ -407,7 +407,7 @@ fn super_terminator_kind(&mut self,
                             self.visit_operand(arg);
                         }
                         if let Some((ref $($mutability)* destination, target)) = *destination {
-                            self.visit_lvalue(destination, LvalueContext::Store);
+                            self.visit_lvalue(destination, LvalueContext::Call);
                             self.visit_branch(block, target);
                         }
                         cleanup.map(|t| self.visit_branch(block, t));
@@ -692,9 +692,12 @@ fn super_const_usize(&mut self, _substs: & $($mutability)* ConstUsize) {
 
 #[derive(Copy, Clone, Debug)]
 pub enum LvalueContext {
-    // Appears as LHS of an assignment or as dest of a call
+    // Appears as LHS of an assignment
     Store,
 
+    // Dest of a call
+    Call,
+
     // Being dropped
     Drop,
 
index 500cc24db211eff281b7a45b4bff2beef5241907..574c927bd75d2cca969fbe58db01866c46cd0896 100644 (file)
@@ -139,11 +139,9 @@ pub struct Options {
     pub continue_parse_after_error: bool,
     pub mir_opt_level: usize,
 
-    /// if true, build up the dep-graph
-    pub build_dep_graph: bool,
-
-    /// if true, -Z dump-dep-graph was passed to dump out the dep-graph
-    pub dump_dep_graph: bool,
+    /// if Some, enable incremental compilation, using the given
+    /// directory to store intermediate results
+    pub incremental: Option<PathBuf>,
 
     pub no_analysis: bool,
     pub debugging_opts: DebuggingOptions,
@@ -260,8 +258,7 @@ pub fn basic_options() -> Options {
         treat_err_as_bug: false,
         continue_parse_after_error: false,
         mir_opt_level: 1,
-        build_dep_graph: false,
-        dump_dep_graph: false,
+        incremental: None,
         no_analysis: false,
         debugging_opts: basic_debugging_options(),
         prints: Vec::new(),
@@ -276,6 +273,15 @@ pub fn basic_options() -> Options {
     }
 }
 
+impl Options {
+    /// True if there is a reason to build the dep graph.
+    pub fn build_dep_graph(&self) -> bool {
+        self.incremental.is_some() ||
+            self.debugging_opts.dump_dep_graph ||
+            self.debugging_opts.query_dep_graph
+    }
+}
+
 // The type of entry function, so
 // users can have their own entry
 // functions that don't start a
@@ -635,10 +641,12 @@ fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
           "treat all errors that occur as bugs"),
     continue_parse_after_error: bool = (false, parse_bool,
           "attempt to recover from parse errors (experimental)"),
-    incr_comp: bool = (false, parse_bool,
+    incremental: Option<String> = (None, parse_opt_string,
           "enable incremental compilation (experimental)"),
     dump_dep_graph: bool = (false, parse_bool,
           "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
+    query_dep_graph: bool = (false, parse_bool,
+          "enable queries of the dependency graph for regression testing"),
     no_analysis: bool = (false, parse_bool,
           "parse and expand the source, but run no analysis"),
     extra_plugins: Vec<String> = (Vec::new(), parse_list,
@@ -1050,8 +1058,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     let treat_err_as_bug = debugging_opts.treat_err_as_bug;
     let continue_parse_after_error = debugging_opts.continue_parse_after_error;
     let mir_opt_level = debugging_opts.mir_opt_level.unwrap_or(1);
-    let incremental_compilation = debugging_opts.incr_comp;
-    let dump_dep_graph = debugging_opts.dump_dep_graph;
     let no_analysis = debugging_opts.no_analysis;
 
     let mut output_types = HashMap::new();
@@ -1211,6 +1217,8 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     let crate_name = matches.opt_str("crate-name");
 
+    let incremental = debugging_opts.incremental.as_ref().map(|m| PathBuf::from(m));
+
     Options {
         crate_types: crate_types,
         gc: gc,
@@ -1230,8 +1238,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         treat_err_as_bug: treat_err_as_bug,
         continue_parse_after_error: continue_parse_after_error,
         mir_opt_level: mir_opt_level,
-        build_dep_graph: incremental_compilation || dump_dep_graph,
-        dump_dep_graph: dump_dep_graph,
+        incremental: incremental,
         no_analysis: no_analysis,
         debugging_opts: debugging_opts,
         prints: prints,
index d3005ff2ded251e4c68ea560d36febb8f16f953a..815e60a8e0342a1a25960cfdf426a1e50b808504 100644 (file)
@@ -351,11 +351,11 @@ fn split_msg_into_multilines(msg: &str) -> Option<String> {
             return None
     }
     let first = msg.match_indices("expected").filter(|s| {
-        s.0 > 0 && (msg.char_at_reverse(s.0) == ' ' ||
-                    msg.char_at_reverse(s.0) == '(')
+        let last = msg[..s.0].chars().rev().next();
+        last == Some(' ') || last == Some('(')
     }).map(|(a, b)| (a - 1, a + b.len()));
     let second = msg.match_indices("found").filter(|s| {
-        msg.char_at_reverse(s.0) == ' '
+        msg[..s.0].chars().rev().next() == Some(' ')
     }).map(|(a, b)| (a - 1, a + b.len()));
 
     let mut new_msg = String::new();
index b0f443fc19b4262ca2f1ee9f172a23597920a0c8..88327ab19a5cb66350a06e707fa9954766d62b55 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use dep_graph::DepNode;
+use hir::def_id::DefId;
 use ty::{Ty, TyS};
 use ty::tls;
 
@@ -46,7 +47,7 @@ pub fn new() -> Self {
     }
 
     #[inline]
-    pub fn get(&self, dep_node: DepNode) -> Option<Ty<'tcx>> {
+    pub fn get(&self, dep_node: DepNode<DefId>) -> Option<Ty<'tcx>> {
         tls::with(|tcx| tcx.dep_graph.read(dep_node));
         self.untracked_get()
     }
@@ -61,11 +62,11 @@ fn untracked_get(&self) -> Option<Ty<'tcx>> {
     }
 
     #[inline]
-    pub fn unwrap(&self, dep_node: DepNode) -> Ty<'tcx> {
+    pub fn unwrap(&self, dep_node: DepNode<DefId>) -> Ty<'tcx> {
         self.get(dep_node).unwrap()
     }
 
-    pub fn fulfill(&self, dep_node: DepNode, value: Ty<'lt>) {
+    pub fn fulfill(&self, dep_node: DepNode<DefId>, value: Ty<'lt>) {
         tls::with(|tcx| tcx.dep_graph.write(dep_node));
 
         // Invariant (A) is fulfilled, because by (B), every alias
index 65a96e79ff43c609d3c03349098ba1cc68011165..57b1dd66bea9d353185e7ab3f2f43304e589cf30 100644 (file)
@@ -24,7 +24,7 @@ pub struct $ty_name<'tcx> {
         impl<'tcx> DepTrackingMapConfig for $ty_name<'tcx> {
             type Key = $key;
             type Value = $value;
-            fn to_dep_node(key: &$key) -> DepNode { DepNode::$node_name(*key) }
+            fn to_dep_node(key: &$key) -> DepNode<DefId> { DepNode::$node_name(*key) }
         }
     }
 }
index 47e8f91b48c61bc22ad2aaa76d892c69c641b841..cba3a9e2ebb5ccfadf418572c2a398ae25e9def7 100644 (file)
@@ -937,7 +937,7 @@ pub fn def_id(&self) -> DefId {
     }
 
     /// Creates the dep-node for selecting/evaluating this trait reference.
-    fn dep_node(&self) -> DepNode {
+    fn dep_node(&self) -> DepNode<DefId> {
         DepNode::TraitSelect(self.def_id())
     }
 
@@ -956,7 +956,7 @@ pub fn def_id(&self) -> DefId {
         self.0.def_id()
     }
 
-    pub fn dep_node(&self) -> DepNode {
+    pub fn dep_node(&self) -> DepNode<DefId> {
         // ok to skip binder since depnode does not care about regions
         self.0.dep_node()
     }
@@ -2716,7 +2716,7 @@ pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
     pub fn visit_all_items_in_krate<V,F>(&self,
                                          dep_node_fn: F,
                                          visitor: &mut V)
-        where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx>
+        where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'tcx>
     {
         dep_graph::visit_all_items_in_krate(self, dep_node_fn, visitor);
     }
index 25edaf4b8e4e9774740a34513f18934797b2b3f4..67b11a930d6f7fbbef6da55e3ef4bf84752d6b0f 100644 (file)
@@ -32,7 +32,6 @@
 
 #![feature(box_syntax)]
 #![feature(const_fn)]
-#![feature(copy_from_slice)]
 #![feature(libc)]
 #![feature(rand)]
 #![feature(rustc_private)]
index a8eac524971ba7107a1d242fdb744ee1b33100a6..bde88605e88cdc1daabed3d31e8616ba715b3009 100644 (file)
@@ -436,6 +436,7 @@ macro_rules! key {
         key!(target_family, optional);
         key!(is_like_osx, bool);
         key!(is_like_windows, bool);
+        key!(is_like_msvc, bool);
         key!(linker_is_gnu, bool);
         key!(has_rpath, bool);
         key!(no_compiler_rt, bool);
index bac5900f3edafda51dc18b7aefa6ee140c5e5fec..4533946d26ea404fb0d9daae4d4e584cb9f96357 100644 (file)
@@ -23,6 +23,7 @@ rustc_mir = { path = "../librustc_mir" }
 rustc_plugin = { path = "../librustc_plugin" }
 rustc_passes = { path = "../librustc_passes" }
 rustc_privacy = { path = "../librustc_privacy" }
+rustc_incremental = { path = "../librustc_incremental" }
 rustc_resolve = { path = "../librustc_resolve" }
 rustc_save_analysis = { path = "../librustc_save_analysis" }
 rustc_trans = { path = "../librustc_trans" }
index 496cc4e8b26fa936758153fad23c58b986c9182e..de1a740e0bba486e752c5d12f9137ed5b7007ee6 100644 (file)
@@ -24,6 +24,7 @@
 use rustc::util::nodemap::NodeSet;
 use rustc_back::sha2::{Sha256, Digest};
 use rustc_borrowck as borrowck;
+use rustc_incremental;
 use rustc_resolve as resolve;
 use rustc_metadata::macro_import;
 use rustc_metadata::creader::LocalCrateReader;
@@ -121,7 +122,7 @@ macro_rules! controller_entry_point {
         let expanded_crate = assign_node_ids(sess, expanded_crate);
         // Lower ast -> hir.
         let lcx = LoweringContext::new(sess, Some(&expanded_crate));
-        let dep_graph = DepGraph::new(sess.opts.build_dep_graph);
+        let dep_graph = DepGraph::new(sess.opts.build_dep_graph());
         let mut hir_forest = time(sess.time_passes(),
                                   "lowering ast -> hir",
                                   || hir_map::Forest::new(lower_crate(&lcx, &expanded_crate),
@@ -828,6 +829,10 @@ macro_rules! try_with_f {
                                index,
                                name,
                                |tcx| {
+        time(time_passes,
+             "load_dep_graph",
+             || rustc_incremental::load_dep_graph(tcx));
+
         // passes are timed inside typeck
         try_with_f!(typeck::check_crate(tcx, trait_map), (tcx, None, analysis));
 
@@ -952,9 +957,20 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'tcx>,
         passes.run_passes(tcx, &mut mir_map);
     });
 
+    let translation =
+        time(time_passes,
+             "translation",
+             move || trans::trans_crate(tcx, &mir_map, analysis));
+
     time(time_passes,
-         "translation",
-         move || trans::trans_crate(tcx, &mir_map, analysis))
+         "assert dep graph",
+         move || rustc_incremental::assert_dep_graph(tcx));
+
+    time(time_passes,
+         "serialize dep graph",
+         move || rustc_incremental::save_dep_graph(tcx));
+
+    translation
 }
 
 /// Run LLVM itself, producing a bitcode file, assembly file or object file
index 33b83ec78a3d1367321ef8a0d41242592f47a559..769449b96d2b1ed66e424576abf8cf779acaedbc 100644 (file)
@@ -45,6 +45,7 @@
 extern crate rustc_lint;
 extern crate rustc_plugin;
 extern crate rustc_privacy;
+extern crate rustc_incremental;
 extern crate rustc_metadata;
 extern crate rustc_mir;
 extern crate rustc_resolve;
diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml
new file mode 100644 (file)
index 0000000..927e412
--- /dev/null
@@ -0,0 +1,18 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_incremental"
+version = "0.0.0"
+
+[lib]
+name = "rustc_incremental"
+path = "lib.rs"
+crate-type = ["dylib"]
+
+[dependencies]
+graphviz = { path = "../libgraphviz" }
+rbml = { path = "../librbml" }
+rustc = { path = "../librustc" }
+rustc_data_structures = { path = "../librustc_data_structures" }
+serialize = { path = "../libserialize" }
+log = { path = "../liblog" }
+syntax = { path = "../libsyntax" }
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
new file mode 100644 (file)
index 0000000..88d8ed8
--- /dev/null
@@ -0,0 +1,438 @@
+// 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.
+
+//! This pass is only used for the UNIT TESTS and DEBUGGING NEEDS
+//! around dependency graph construction. It serves two purposes; it
+//! will dump graphs in graphviz form to disk, and it searches for
+//! `#[rustc_if_this_changed]` and `#[rustc_then_this_would_need]`
+//! annotations. These annotations can be used to test whether paths
+//! exist in the graph. These checks run after trans, so they view the
+//! the final state of the dependency graph. Note that there are
+//! similar assertions found in `persist::dirty_clean` which check the
+//! **initial** state of the dependency graph, just after it has been
+//! loaded from disk.
+//!
+//! In this code, we report errors on each `rustc_if_this_changed`
+//! annotation. If a path exists in all cases, then we would report
+//! "all path(s) exist". Otherwise, we report: "no path to `foo`" for
+//! each case where no path exists.  `compile-fail` tests can then be
+//! used to check when paths exist or do not.
+//!
+//! The full form of the `rustc_if_this_changed` annotation is
+//! `#[rustc_if_this_changed(id)]`. The `"id"` is optional and
+//! defaults to `"id"` if omitted.
+//!
+//! Example:
+//!
+//! ```
+//! #[rustc_if_this_changed]
+//! fn foo() { }
+//!
+//! #[rustc_then_this_would_need("trans")] //~ ERROR no path from `foo`
+//! fn bar() { }
+//!
+//! #[rustc_then_this_would_need("trans")] //~ ERROR OK
+//! fn baz() { foo(); }
+//! ```
+
+use graphviz as dot;
+use rustc::dep_graph::{DepGraphQuery, DepNode};
+use rustc::hir::def_id::DefId;
+use rustc::ty::TyCtxt;
+use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet};
+use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex};
+use rustc::hir;
+use rustc::hir::intravisit::Visitor;
+use graphviz::IntoCow;
+use std::env;
+use std::fs::File;
+use std::io::Write;
+use syntax::ast;
+use syntax::attr::AttrMetaMethods;
+use syntax::codemap::Span;
+use syntax::parse::token::InternedString;
+
+const IF_THIS_CHANGED: &'static str = "rustc_if_this_changed";
+const THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need";
+const ID: &'static str = "id";
+
+pub fn assert_dep_graph(tcx: &TyCtxt) {
+    let _ignore = tcx.dep_graph.in_ignore();
+
+    if tcx.sess.opts.debugging_opts.dump_dep_graph {
+        dump_graph(tcx);
+    }
+
+    // Find annotations supplied by user (if any).
+    let (if_this_changed, then_this_would_need) = {
+        let mut visitor = IfThisChanged { tcx: tcx,
+                                          if_this_changed: FnvHashMap(),
+                                          then_this_would_need: FnvHashMap() };
+        tcx.map.krate().visit_all_items(&mut visitor);
+        (visitor.if_this_changed, visitor.then_this_would_need)
+    };
+
+    if !if_this_changed.is_empty() || !then_this_would_need.is_empty() {
+        assert!(tcx.sess.opts.debugging_opts.query_dep_graph,
+                "cannot use the `#[{}]` or `#[{}]` annotations \
+                 without supplying `-Z query-dep-graph`",
+                IF_THIS_CHANGED, THEN_THIS_WOULD_NEED);
+    }
+
+    // Check paths.
+    check_paths(tcx, &if_this_changed, &then_this_would_need);
+}
+
+type SourceHashMap =
+    FnvHashMap<InternedString,
+               FnvHashSet<(Span, DefId, DepNode<DefId>)>>;
+type TargetHashMap =
+    FnvHashMap<InternedString,
+               FnvHashSet<(Span, InternedString, ast::NodeId, DepNode<DefId>)>>;
+
+struct IfThisChanged<'a, 'tcx:'a> {
+    tcx: &'a TyCtxt<'tcx>,
+    if_this_changed: SourceHashMap,
+    then_this_would_need: TargetHashMap,
+}
+
+impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
+    fn process_attrs(&mut self, node_id: ast::NodeId, def_id: DefId) {
+        for attr in self.tcx.get_attrs(def_id).iter() {
+            if attr.check_name(IF_THIS_CHANGED) {
+                let mut id = None;
+                for meta_item in attr.meta_item_list().unwrap_or_default() {
+                    match meta_item.node {
+                        ast::MetaItemKind::Word(ref s) if id.is_none() => id = Some(s.clone()),
+                        _ => {
+                            self.tcx.sess.span_err(
+                                meta_item.span,
+                                &format!("unexpected meta-item {:?}", meta_item.node));
+                        }
+                    }
+                }
+                let id = id.unwrap_or(InternedString::new(ID));
+                self.if_this_changed.entry(id)
+                                    .or_insert(FnvHashSet())
+                                    .insert((attr.span, def_id, DepNode::Hir(def_id)));
+            } else if attr.check_name(THEN_THIS_WOULD_NEED) {
+                let mut dep_node_interned = None;
+                let mut id = None;
+                for meta_item in attr.meta_item_list().unwrap_or_default() {
+                    match meta_item.node {
+                        ast::MetaItemKind::Word(ref s) if dep_node_interned.is_none() =>
+                            dep_node_interned = Some(s.clone()),
+                        ast::MetaItemKind::Word(ref s) if id.is_none() =>
+                            id = Some(s.clone()),
+                        _ => {
+                            self.tcx.sess.span_err(
+                                meta_item.span,
+                                &format!("unexpected meta-item {:?}", meta_item.node));
+                        }
+                    }
+                }
+                let dep_node = match dep_node_interned {
+                    Some(ref n) => {
+                        match DepNode::from_label_string(&n[..], def_id) {
+                            Ok(n) => n,
+                            Err(()) => {
+                                self.tcx.sess.span_fatal(
+                                    attr.span,
+                                    &format!("unrecognized DepNode variant {:?}", n));
+                            }
+                        }
+                    }
+                    None => {
+                        self.tcx.sess.span_fatal(
+                            attr.span,
+                            &format!("missing DepNode variant"));
+                    }
+                };
+                let id = id.unwrap_or(InternedString::new(ID));
+                self.then_this_would_need
+                    .entry(id)
+                    .or_insert(FnvHashSet())
+                    .insert((attr.span, dep_node_interned.clone().unwrap(), node_id, dep_node));
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for IfThisChanged<'a, 'tcx> {
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        let def_id = self.tcx.map.local_def_id(item.id);
+        self.process_attrs(item.id, def_id);
+    }
+}
+
+fn check_paths(tcx: &TyCtxt,
+               if_this_changed: &SourceHashMap,
+               then_this_would_need: &TargetHashMap)
+{
+    // Return early here so as not to construct the query, which is not cheap.
+    if if_this_changed.is_empty() {
+        return;
+    }
+    let query = tcx.dep_graph.query();
+    for (id, sources) in if_this_changed {
+        let targets = match then_this_would_need.get(id) {
+            Some(targets) => targets,
+            None => {
+                for &(source_span, _, _) in sources.iter().take(1) {
+                    tcx.sess.span_err(
+                        source_span,
+                        &format!("no targets for id `{}`", id));
+                }
+                continue;
+            }
+        };
+
+        for &(_, source_def_id, source_dep_node) in sources {
+            let dependents = query.transitive_dependents(source_dep_node);
+            for &(target_span, ref target_pass, _, ref target_dep_node) in targets {
+                if !dependents.contains(&target_dep_node) {
+                    tcx.sess.span_err(
+                        target_span,
+                        &format!("no path from `{}` to `{}`",
+                                 tcx.item_path_str(source_def_id),
+                                 target_pass));
+                } else {
+                    tcx.sess.span_err(
+                        target_span,
+                        &format!("OK"));
+                }
+            }
+        }
+    }
+}
+
+fn dump_graph(tcx: &TyCtxt) {
+    let path: String = env::var("RUST_DEP_GRAPH").unwrap_or_else(|_| format!("dep_graph"));
+    let query = tcx.dep_graph.query();
+
+    let nodes = match env::var("RUST_DEP_GRAPH_FILTER") {
+        Ok(string) => {
+            // Expect one of: "-> target", "source -> target", or "source ->".
+            let parts: Vec<_> = string.split("->").collect();
+            if parts.len() > 2 {
+                bug!("Invalid RUST_DEP_GRAPH_FILTER: expected '[source] -> [target]'");
+            }
+            let sources = node_set(&query, &parts[0]);
+            let targets = node_set(&query, &parts[1]);
+            filter_nodes(&query, &sources, &targets)
+        }
+        Err(_) => {
+            query.nodes()
+                 .into_iter()
+                 .collect()
+        }
+    };
+    let edges = filter_edges(&query, &nodes);
+
+    { // dump a .txt file with just the edges:
+        let txt_path = format!("{}.txt", path);
+        let mut file = File::create(&txt_path).unwrap();
+        for &(source, target) in &edges {
+            write!(file, "{:?} -> {:?}\n", source, target).unwrap();
+        }
+    }
+
+    { // dump a .dot file in graphviz format:
+        let dot_path = format!("{}.dot", path);
+        let mut v = Vec::new();
+        dot::render(&GraphvizDepGraph(nodes, edges), &mut v).unwrap();
+        File::create(&dot_path).and_then(|mut f| f.write_all(&v)).unwrap();
+    }
+}
+
+pub struct GraphvizDepGraph(FnvHashSet<DepNode<DefId>>,
+                            Vec<(DepNode<DefId>, DepNode<DefId>)>);
+
+impl<'a, 'tcx> dot::GraphWalk<'a> for GraphvizDepGraph {
+    type Node = DepNode<DefId>;
+    type Edge = (DepNode<DefId>, DepNode<DefId>);
+    fn nodes(&self) -> dot::Nodes<DepNode<DefId>> {
+        let nodes: Vec<_> = self.0.iter().cloned().collect();
+        nodes.into_cow()
+    }
+    fn edges(&self) -> dot::Edges<(DepNode<DefId>, DepNode<DefId>)> {
+        self.1[..].into_cow()
+    }
+    fn source(&self, edge: &(DepNode<DefId>, DepNode<DefId>)) -> DepNode<DefId> {
+        edge.0
+    }
+    fn target(&self, edge: &(DepNode<DefId>, DepNode<DefId>)) -> DepNode<DefId> {
+        edge.1
+    }
+}
+
+impl<'a, 'tcx> dot::Labeller<'a> for GraphvizDepGraph {
+    type Node = DepNode<DefId>;
+    type Edge = (DepNode<DefId>, DepNode<DefId>);
+    fn graph_id(&self) -> dot::Id {
+        dot::Id::new("DependencyGraph").unwrap()
+    }
+    fn node_id(&self, n: &DepNode<DefId>) -> dot::Id {
+        let s: String =
+            format!("{:?}", n).chars()
+                              .map(|c| if c == '_' || c.is_alphanumeric() { c } else { '_' })
+                              .collect();
+        debug!("n={:?} s={:?}", n, s);
+        dot::Id::new(s).unwrap()
+    }
+    fn node_label(&self, n: &DepNode<DefId>) -> dot::LabelText {
+        dot::LabelText::label(format!("{:?}", n))
+    }
+}
+
+// Given an optional filter like `"x,y,z"`, returns either `None` (no
+// filter) or the set of nodes whose labels contain all of those
+// substrings.
+fn node_set(query: &DepGraphQuery<DefId>, filter: &str)
+            -> Option<FnvHashSet<DepNode<DefId>>>
+{
+    debug!("node_set(filter={:?})", filter);
+
+    if filter.trim().is_empty() {
+        return None;
+    }
+
+    let filters: Vec<&str> = filter.split("&").map(|s| s.trim()).collect();
+
+    debug!("node_set: filters={:?}", filters);
+
+    Some(query.nodes()
+         .into_iter()
+         .filter(|n| {
+             let s = format!("{:?}", n);
+             filters.iter().all(|f| s.contains(f))
+         })
+        .collect())
+}
+
+fn filter_nodes(query: &DepGraphQuery<DefId>,
+                sources: &Option<FnvHashSet<DepNode<DefId>>>,
+                targets: &Option<FnvHashSet<DepNode<DefId>>>)
+                -> FnvHashSet<DepNode<DefId>>
+{
+    if let &Some(ref sources) = sources {
+        if let &Some(ref targets) = targets {
+            walk_between(query, sources, targets)
+        } else {
+            walk_nodes(query, sources, OUTGOING)
+        }
+    } else if let &Some(ref targets) = targets {
+        walk_nodes(query, targets, INCOMING)
+    } else {
+        query.nodes().into_iter().collect()
+    }
+}
+
+fn walk_nodes(query: &DepGraphQuery<DefId>,
+              starts: &FnvHashSet<DepNode<DefId>>,
+              direction: Direction)
+              -> FnvHashSet<DepNode<DefId>>
+{
+    let mut set = FnvHashSet();
+    for start in starts {
+        debug!("walk_nodes: start={:?} outgoing?={:?}", start, direction == OUTGOING);
+        if set.insert(*start) {
+            let mut stack = vec![query.indices[start]];
+            while let Some(index) = stack.pop() {
+                for (_, edge) in query.graph.adjacent_edges(index, direction) {
+                    let neighbor_index = edge.source_or_target(direction);
+                    let neighbor = query.graph.node_data(neighbor_index);
+                    if set.insert(*neighbor) {
+                        stack.push(neighbor_index);
+                    }
+                }
+            }
+        }
+    }
+    set
+}
+
+fn walk_between(query: &DepGraphQuery<DefId>,
+                sources: &FnvHashSet<DepNode<DefId>>,
+                targets: &FnvHashSet<DepNode<DefId>>)
+                -> FnvHashSet<DepNode<DefId>>
+{
+    // This is a bit tricky. We want to include a node only if it is:
+    // (a) reachable from a source and (b) will reach a target. And we
+    // have to be careful about cycles etc.  Luckily efficiency is not
+    // a big concern!
+
+    #[derive(Copy, Clone, PartialEq)]
+    enum State { Undecided, Deciding, Included, Excluded }
+
+    let mut node_states = vec![State::Undecided; query.graph.len_nodes()];
+
+    for &target in targets {
+        node_states[query.indices[&target].0] = State::Included;
+    }
+
+    for source in sources.iter().map(|n| query.indices[n]) {
+        recurse(query, &mut node_states, source);
+    }
+
+    return query.nodes()
+                .into_iter()
+                .filter(|n| {
+                    let index = query.indices[n];
+                    node_states[index.0] == State::Included
+                })
+                .collect();
+
+    fn recurse(query: &DepGraphQuery<DefId>,
+               node_states: &mut [State],
+               node: NodeIndex)
+               -> bool
+    {
+        match node_states[node.0] {
+            // known to reach a target
+            State::Included => return true,
+
+            // known not to reach a target
+            State::Excluded => return false,
+
+            // backedge, not yet known, say false
+            State::Deciding => return false,
+
+            State::Undecided => { }
+        }
+
+        node_states[node.0] = State::Deciding;
+
+        for neighbor_index in query.graph.successor_nodes(node) {
+            if recurse(query, node_states, neighbor_index) {
+                node_states[node.0] = State::Included;
+            }
+        }
+
+        // if we didn't find a path to target, then set to excluded
+        if node_states[node.0] == State::Deciding {
+            node_states[node.0] = State::Excluded;
+            false
+        } else {
+            assert!(node_states[node.0] == State::Included);
+            true
+        }
+    }
+}
+
+fn filter_edges(query: &DepGraphQuery<DefId>,
+                nodes: &FnvHashSet<DepNode<DefId>>)
+                -> Vec<(DepNode<DefId>, DepNode<DefId>)>
+{
+    query.edges()
+         .into_iter()
+         .filter(|&(source, target)| nodes.contains(&source) && nodes.contains(&target))
+         .collect()
+}
diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs
new file mode 100644 (file)
index 0000000..ab1c6f5
--- /dev/null
@@ -0,0 +1,422 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Calculation of a Strict Version Hash for crates.  For a length
+//! comment explaining the general idea, see `librustc/middle/svh.rs`.
+
+use std::hash::{Hash, SipHasher, Hasher};
+use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::hir::svh::Svh;
+use rustc::ty;
+use rustc::hir::intravisit::{self, Visitor};
+
+use self::svh_visitor::StrictVersionHashVisitor;
+
+pub trait SvhCalculate {
+    /// Calculate the SVH for an entire krate.
+    fn calculate_krate_hash(&self) -> Svh;
+
+    /// Calculate the SVH for a particular item.
+    fn calculate_item_hash(&self, def_id: DefId) -> u64;
+}
+
+impl<'tcx> SvhCalculate for ty::TyCtxt<'tcx> {
+    fn calculate_krate_hash(&self) -> Svh {
+        // FIXME (#14132): This is better than it used to be, but it still not
+        // ideal. We now attempt to hash only the relevant portions of the
+        // Crate AST as well as the top-level crate attributes. (However,
+        // the hashing of the crate attributes should be double-checked
+        // to ensure it is not incorporating implementation artifacts into
+        // the hash that are not otherwise visible.)
+
+        let crate_disambiguator = self.sess.crate_disambiguator.get();
+        let krate = self.map.krate();
+
+        // FIXME: this should use SHA1, not SipHash. SipHash is not built to
+        //        avoid collisions.
+        let mut state = SipHasher::new();
+        debug!("state: {:?}", state);
+
+        // FIXME(#32753) -- at (*) we `to_le` for endianness, but is
+        // this enough, and does it matter anyway?
+        "crate_disambiguator".hash(&mut state);
+        crate_disambiguator.as_str().len().to_le().hash(&mut state); // (*)
+        crate_disambiguator.as_str().hash(&mut state);
+
+        debug!("crate_disambiguator: {:?}", crate_disambiguator.as_str());
+        debug!("state: {:?}", state);
+
+        {
+            let mut visit = StrictVersionHashVisitor::new(&mut state, self);
+            krate.visit_all_items(&mut visit);
+        }
+
+        // FIXME (#14132): This hash is still sensitive to e.g. the
+        // spans of the crate Attributes and their underlying
+        // MetaItems; we should make ContentHashable impl for those
+        // types and then use hash_content.  But, since all crate
+        // attributes should appear near beginning of the file, it is
+        // not such a big deal to be sensitive to their spans for now.
+        //
+        // We hash only the MetaItems instead of the entire Attribute
+        // to avoid hashing the AttrId
+        for attr in &krate.attrs {
+            debug!("krate attr {:?}", attr);
+            attr.node.value.hash(&mut state);
+        }
+
+        Svh::from_hash(state.finish())
+    }
+
+    fn calculate_item_hash(&self, def_id: DefId) -> u64 {
+        assert!(def_id.is_local());
+
+        let mut state = SipHasher::new();
+
+        {
+            let mut visit = StrictVersionHashVisitor::new(&mut state, self);
+            if def_id.index == CRATE_DEF_INDEX {
+                // the crate root itself is not registered in the map
+                // as an item, so we have to fetch it this way
+                let krate = self.map.krate();
+                intravisit::walk_crate(&mut visit, krate);
+            } else {
+                let node_id = self.map.as_local_node_id(def_id).unwrap();
+                visit.visit_item(self.map.expect_item(node_id));
+            }
+        }
+
+        state.finish()
+    }
+}
+
+// FIXME (#14132): Even this SVH computation still has implementation
+// artifacts: namely, the order of item declaration will affect the
+// hash computation, but for many kinds of items the order of
+// declaration should be irrelevant to the ABI.
+
+mod svh_visitor {
+    pub use self::SawExprComponent::*;
+    pub use self::SawStmtComponent::*;
+    use self::SawAbiComponent::*;
+    use syntax::ast::{self, Name, NodeId};
+    use syntax::codemap::Span;
+    use syntax::parse::token;
+    use rustc::ty;
+    use rustc::hir;
+    use rustc::hir::*;
+    use rustc::hir::intravisit as visit;
+    use rustc::hir::intravisit::{Visitor, FnKind};
+
+    use std::hash::{Hash, SipHasher};
+
+    pub struct StrictVersionHashVisitor<'a, 'tcx: 'a> {
+        pub tcx: &'a ty::TyCtxt<'tcx>,
+        pub st: &'a mut SipHasher,
+    }
+
+    impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> {
+        pub fn new(st: &'a mut SipHasher,
+                   tcx: &'a ty::TyCtxt<'tcx>)
+                   -> Self {
+            StrictVersionHashVisitor { st: st, tcx: tcx }
+        }
+    }
+
+    // To off-load the bulk of the hash-computation on #[derive(Hash)],
+    // we define a set of enums corresponding to the content that our
+    // crate visitor will encounter as it traverses the ast.
+    //
+    // The important invariant is that all of the Saw*Component enums
+    // do not carry any Spans, Names, or Idents.
+    //
+    // Not carrying any Names/Idents is the important fix for problem
+    // noted on PR #13948: using the ident.name as the basis for a
+    // hash leads to unstable SVH, because ident.name is just an index
+    // into intern table (i.e. essentially a random address), not
+    // computed from the name content.
+    //
+    // With the below enums, the SVH computation is not sensitive to
+    // artifacts of how rustc was invoked nor of how the source code
+    // was laid out.  (Or at least it is *less* sensitive.)
+
+    // This enum represents the different potential bits of code the
+    // visitor could encounter that could affect the ABI for the crate,
+    // and assigns each a distinct tag to feed into the hash computation.
+    #[derive(Hash)]
+    enum SawAbiComponent<'a> {
+
+        // FIXME (#14132): should we include (some function of)
+        // ident.ctxt as well?
+        SawIdent(token::InternedString),
+        SawStructDef(token::InternedString),
+
+        SawLifetime(token::InternedString),
+        SawLifetimeDef(token::InternedString),
+
+        SawMod,
+        SawForeignItem,
+        SawItem,
+        SawDecl,
+        SawTy,
+        SawGenerics,
+        SawFn,
+        SawTraitItem,
+        SawImplItem,
+        SawStructField,
+        SawVariant,
+        SawExplicitSelf,
+        SawPath,
+        SawBlock,
+        SawPat,
+        SawLocal,
+        SawArm,
+        SawExpr(SawExprComponent<'a>),
+        SawStmt(SawStmtComponent),
+    }
+
+    /// SawExprComponent carries all of the information that we want
+    /// to include in the hash that *won't* be covered by the
+    /// subsequent recursive traversal of the expression's
+    /// substructure by the visitor.
+    ///
+    /// We know every Expr_ variant is covered by a variant because
+    /// `fn saw_expr` maps each to some case below.  Ensuring that
+    /// each variant carries an appropriate payload has to be verified
+    /// by hand.
+    ///
+    /// (However, getting that *exactly* right is not so important
+    /// because the SVH is just a developer convenience; there is no
+    /// guarantee of collision-freedom, hash collisions are just
+    /// (hopefully) unlikely.)
+    #[derive(Hash)]
+    pub enum SawExprComponent<'a> {
+
+        SawExprLoop(Option<token::InternedString>),
+        SawExprField(token::InternedString),
+        SawExprTupField(usize),
+        SawExprBreak(Option<token::InternedString>),
+        SawExprAgain(Option<token::InternedString>),
+
+        SawExprBox,
+        SawExprVec,
+        SawExprCall,
+        SawExprMethodCall,
+        SawExprTup,
+        SawExprBinary(hir::BinOp_),
+        SawExprUnary(hir::UnOp),
+        SawExprLit(ast::LitKind),
+        SawExprCast,
+        SawExprType,
+        SawExprIf,
+        SawExprWhile,
+        SawExprMatch,
+        SawExprClosure,
+        SawExprBlock,
+        SawExprAssign,
+        SawExprAssignOp(hir::BinOp_),
+        SawExprIndex,
+        SawExprPath(Option<usize>),
+        SawExprAddrOf(hir::Mutability),
+        SawExprRet,
+        SawExprInlineAsm(&'a hir::InlineAsm),
+        SawExprStruct,
+        SawExprRepeat,
+    }
+
+    fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
+        match *node {
+            ExprBox(..)              => SawExprBox,
+            ExprVec(..)              => SawExprVec,
+            ExprCall(..)             => SawExprCall,
+            ExprMethodCall(..)       => SawExprMethodCall,
+            ExprTup(..)              => SawExprTup,
+            ExprBinary(op, _, _)     => SawExprBinary(op.node),
+            ExprUnary(op, _)         => SawExprUnary(op),
+            ExprLit(ref lit)         => SawExprLit(lit.node.clone()),
+            ExprCast(..)             => SawExprCast,
+            ExprType(..)             => SawExprType,
+            ExprIf(..)               => SawExprIf,
+            ExprWhile(..)            => SawExprWhile,
+            ExprLoop(_, id)          => SawExprLoop(id.map(|id| id.name.as_str())),
+            ExprMatch(..)            => SawExprMatch,
+            ExprClosure(..)          => SawExprClosure,
+            ExprBlock(..)            => SawExprBlock,
+            ExprAssign(..)           => SawExprAssign,
+            ExprAssignOp(op, _, _)   => SawExprAssignOp(op.node),
+            ExprField(_, name)       => SawExprField(name.node.as_str()),
+            ExprTupField(_, id)      => SawExprTupField(id.node),
+            ExprIndex(..)            => SawExprIndex,
+            ExprPath(ref qself, _)   => SawExprPath(qself.as_ref().map(|q| q.position)),
+            ExprAddrOf(m, _)         => SawExprAddrOf(m),
+            ExprBreak(id)            => SawExprBreak(id.map(|id| id.node.name.as_str())),
+            ExprAgain(id)            => SawExprAgain(id.map(|id| id.node.name.as_str())),
+            ExprRet(..)              => SawExprRet,
+            ExprInlineAsm(ref a,_,_) => SawExprInlineAsm(a),
+            ExprStruct(..)           => SawExprStruct,
+            ExprRepeat(..)           => SawExprRepeat,
+        }
+    }
+
+    /// SawStmtComponent is analogous to SawExprComponent, but for statements.
+    #[derive(Hash)]
+    pub enum SawStmtComponent {
+        SawStmtDecl,
+        SawStmtExpr,
+        SawStmtSemi,
+    }
+
+    fn saw_stmt(node: &Stmt_) -> SawStmtComponent {
+        match *node {
+            StmtDecl(..) => SawStmtDecl,
+            StmtExpr(..) => SawStmtExpr,
+            StmtSemi(..) => SawStmtSemi,
+        }
+    }
+
+    impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> {
+        fn visit_nested_item(&mut self, item: ItemId) {
+            debug!("visit_nested_item: {:?} st={:?}", item, self.st);
+            let def_path = self.tcx.map.def_path_from_id(item.id);
+            def_path.hash(self.st);
+        }
+
+        fn visit_variant_data(&mut self, s: &'a VariantData, name: Name,
+                              g: &'a Generics, _: NodeId, _: Span) {
+            SawStructDef(name.as_str()).hash(self.st);
+            visit::walk_generics(self, g);
+            visit::walk_struct_def(self, s)
+        }
+
+        fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
+            SawVariant.hash(self.st);
+            // walk_variant does not call walk_generics, so do it here.
+            visit::walk_generics(self, g);
+            visit::walk_variant(self, v, g, item_id)
+        }
+
+        // All of the remaining methods just record (in the hash
+        // SipHasher) that the visitor saw that particular variant
+        // (with its payload), and continue walking as the default
+        // visitor would.
+        //
+        // Some of the implementations have some notes as to how one
+        // might try to make their SVH computation less discerning
+        // (e.g. by incorporating reachability analysis).  But
+        // currently all of their implementations are uniform and
+        // uninteresting.
+        //
+        // (If you edit a method such that it deviates from the
+        // pattern, please move that method up above this comment.)
+
+        fn visit_name(&mut self, _: Span, name: Name) {
+            SawIdent(name.as_str()).hash(self.st);
+        }
+
+        fn visit_lifetime(&mut self, l: &'a Lifetime) {
+            SawLifetime(l.name.as_str()).hash(self.st);
+        }
+
+        fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) {
+            SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st);
+        }
+
+        // We do recursively walk the bodies of functions/methods
+        // (rather than omitting their bodies from the hash) since
+        // monomorphization and cross-crate inlining generally implies
+        // that a change to a crate body will require downstream
+        // crates to be recompiled.
+        fn visit_expr(&mut self, ex: &'a Expr) {
+            SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex)
+        }
+
+        fn visit_stmt(&mut self, s: &'a Stmt) {
+            SawStmt(saw_stmt(&s.node)).hash(self.st); visit::walk_stmt(self, s)
+        }
+
+        fn visit_foreign_item(&mut self, i: &'a ForeignItem) {
+            // FIXME (#14132) ideally we would incorporate privacy (or
+            // perhaps reachability) somewhere here, so foreign items
+            // that do not leak into downstream crates would not be
+            // part of the ABI.
+            SawForeignItem.hash(self.st); visit::walk_foreign_item(self, i)
+        }
+
+        fn visit_item(&mut self, i: &'a Item) {
+            debug!("visit_item: {:?} st={:?}", i, self.st);
+            // FIXME (#14132) ideally would incorporate reachability
+            // analysis somewhere here, so items that never leak into
+            // downstream crates (e.g. via monomorphisation or
+            // inlining) would not be part of the ABI.
+            SawItem.hash(self.st); visit::walk_item(self, i)
+        }
+
+        fn visit_mod(&mut self, m: &'a Mod, _s: Span, _n: NodeId) {
+            SawMod.hash(self.st); visit::walk_mod(self, m)
+        }
+
+        fn visit_decl(&mut self, d: &'a Decl) {
+            SawDecl.hash(self.st); visit::walk_decl(self, d)
+        }
+
+        fn visit_ty(&mut self, t: &'a Ty) {
+            SawTy.hash(self.st); visit::walk_ty(self, t)
+        }
+
+        fn visit_generics(&mut self, g: &'a Generics) {
+            SawGenerics.hash(self.st); visit::walk_generics(self, g)
+        }
+
+        fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl,
+                    b: &'a Block, s: Span, _: NodeId) {
+            SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s)
+        }
+
+        fn visit_trait_item(&mut self, ti: &'a TraitItem) {
+            SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti)
+        }
+
+        fn visit_impl_item(&mut self, ii: &'a ImplItem) {
+            SawImplItem.hash(self.st); visit::walk_impl_item(self, ii)
+        }
+
+        fn visit_struct_field(&mut self, s: &'a StructField) {
+            SawStructField.hash(self.st); visit::walk_struct_field(self, s)
+        }
+
+        fn visit_explicit_self(&mut self, es: &'a ExplicitSelf) {
+            SawExplicitSelf.hash(self.st); visit::walk_explicit_self(self, es)
+        }
+
+        fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) {
+            SawPath.hash(self.st); visit::walk_path(self, path)
+        }
+
+        fn visit_path_list_item(&mut self, prefix: &'a Path, item: &'a PathListItem) {
+            SawPath.hash(self.st); visit::walk_path_list_item(self, prefix, item)
+        }
+
+        fn visit_block(&mut self, b: &'a Block) {
+            SawBlock.hash(self.st); visit::walk_block(self, b)
+        }
+
+        fn visit_pat(&mut self, p: &'a Pat) {
+            SawPat.hash(self.st); visit::walk_pat(self, p)
+        }
+
+        fn visit_local(&mut self, l: &'a Local) {
+            SawLocal.hash(self.st); visit::walk_local(self, l)
+        }
+
+        fn visit_arm(&mut self, a: &'a Arm) {
+            SawArm.hash(self.st); visit::walk_arm(self, a)
+        }
+    }
+}
diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs
new file mode 100644 (file)
index 0000000..005146d
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2012-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.
+
+//! Support for serializing the dep-graph and reloading it.
+
+#![crate_name = "rustc_incremental"]
+#![unstable(feature = "rustc_private", issue = "27812")]
+#![crate_type = "dylib"]
+#![crate_type = "rlib"]
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+      html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
+
+#![feature(rustc_private)]
+#![feature(staged_api)]
+
+extern crate graphviz;
+extern crate rbml;
+#[macro_use] extern crate rustc;
+extern crate rustc_data_structures;
+extern crate serialize as rustc_serialize;
+
+#[macro_use] extern crate log;
+#[macro_use] extern crate syntax;
+
+mod assert_dep_graph;
+mod calculate_svh;
+mod persist;
+
+pub use assert_dep_graph::assert_dep_graph;
+pub use calculate_svh::SvhCalculate;
+pub use persist::load_dep_graph;
+pub use persist::save_dep_graph;
diff --git a/src/librustc_incremental/persist/README.md b/src/librustc_incremental/persist/README.md
new file mode 100644 (file)
index 0000000..95e0940
--- /dev/null
@@ -0,0 +1,13 @@
+This is the code to load/save the dependency graph. Loading is assumed
+to run early in compilation, and saving at the very end. When loading,
+the basic idea is that we will load up the dependency graph from the
+previous compilation and compare the hashes of our HIR nodes to the
+hashes of the HIR nodes that existed at the time. For each node whose
+hash has changed, or which no longer exists in the new HIR, we can
+remove that node from the old graph along with any nodes that depend
+on it. Then we add what's left to the new graph (if any such nodes or
+edges already exist, then there would be no effect, but since we do
+this first thing, they do not).
+
+
+
diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs
new file mode 100644 (file)
index 0000000..8be8bd6
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The data that we will serialize and deserialize.
+
+use rustc::dep_graph::DepNode;
+use rustc_serialize::{Decoder as RustcDecoder,
+                      Encodable as RustcEncodable, Encoder as RustcEncoder};
+
+use super::directory::DefPathIndex;
+
+#[derive(Debug, RustcEncodable, RustcDecodable)]
+pub struct SerializedDepGraph {
+    pub nodes: Vec<DepNode<DefPathIndex>>,
+    pub edges: Vec<SerializedEdge>,
+    pub hashes: Vec<SerializedHash>,
+}
+
+pub type SerializedEdge = (DepNode<DefPathIndex>, DepNode<DefPathIndex>);
+
+#[derive(Debug, RustcEncodable, RustcDecodable)]
+pub struct SerializedHash {
+    pub index: DefPathIndex,
+
+    /// the hash itself, computed by `calculate_item_hash`
+    pub hash: u64,
+}
+
diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs
new file mode 100644 (file)
index 0000000..0d0054c
--- /dev/null
@@ -0,0 +1,118 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Code to convert a DefId into a DefPath (when serializing) and then
+//! back again (when deserializing). Note that the new DefId
+//! necessarily will not be the same as the old (and of course the
+//! item might even be removed in the meantime).
+
+use rustc::dep_graph::DepNode;
+use rustc::hir::map::DefPath;
+use rustc::hir::def_id::DefId;
+use rustc::ty;
+use rustc::util::nodemap::DefIdMap;
+use rustc_serialize::{Decoder as RustcDecoder,
+                      Encodable as RustcEncodable, Encoder as RustcEncoder};
+use std::fmt::{self, Debug};
+
+/// Index into the DefIdDirectory
+#[derive(Copy, Clone, Debug, PartialOrd, Ord, Hash, PartialEq, Eq,
+         RustcEncodable, RustcDecodable)]
+pub struct DefPathIndex {
+    index: u32
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct DefIdDirectory {
+    // N.B. don't use Removable here because these def-ids are loaded
+    // directly without remapping, so loading them should not fail.
+    paths: Vec<DefPath>
+}
+
+impl DefIdDirectory {
+    pub fn new() -> DefIdDirectory {
+        DefIdDirectory { paths: vec![] }
+    }
+
+    pub fn retrace(&self, tcx: &ty::TyCtxt) -> RetracedDefIdDirectory {
+        let ids = self.paths.iter()
+                            .map(|path| tcx.map.retrace_path(path))
+                            .collect();
+        RetracedDefIdDirectory { ids: ids }
+    }
+}
+
+#[derive(Debug, RustcEncodable, RustcDecodable)]
+pub struct RetracedDefIdDirectory {
+    ids: Vec<Option<DefId>>
+}
+
+impl RetracedDefIdDirectory {
+    pub fn def_id(&self, index: DefPathIndex) -> Option<DefId> {
+        self.ids[index.index as usize]
+    }
+
+    pub fn map(&self, node: DepNode<DefPathIndex>) -> Option<DepNode<DefId>> {
+        node.map_def(|&index| self.def_id(index))
+    }
+}
+
+pub struct DefIdDirectoryBuilder<'a,'tcx:'a> {
+    tcx: &'a ty::TyCtxt<'tcx>,
+    hash: DefIdMap<Option<DefPathIndex>>,
+    directory: DefIdDirectory,
+}
+
+impl<'a,'tcx> DefIdDirectoryBuilder<'a,'tcx> {
+    pub fn new(tcx: &'a ty::TyCtxt<'tcx>) -> DefIdDirectoryBuilder<'a, 'tcx> {
+        DefIdDirectoryBuilder {
+            tcx: tcx,
+            hash: DefIdMap(),
+            directory: DefIdDirectory::new()
+        }
+    }
+
+    pub fn add(&mut self, def_id: DefId) -> Option<DefPathIndex> {
+        if !def_id.is_local() {
+            // FIXME(#32015) clarify story about cross-crate dep tracking
+            return None;
+        }
+
+        let tcx = self.tcx;
+        let paths = &mut self.directory.paths;
+        self.hash.entry(def_id)
+                 .or_insert_with(|| {
+                     let def_path = tcx.def_path(def_id);
+                     if !def_path.is_local() {
+                         return None;
+                     }
+                     let index = paths.len() as u32;
+                     paths.push(def_path);
+                     Some(DefPathIndex { index: index })
+                 })
+                 .clone()
+    }
+
+    pub fn map(&mut self, node: DepNode<DefId>) -> Option<DepNode<DefPathIndex>> {
+        node.map_def(|&def_id| self.add(def_id))
+    }
+
+    pub fn into_directory(self) -> DefIdDirectory {
+        self.directory
+    }
+}
+
+impl Debug for DefIdDirectory {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        fmt.debug_list()
+           .entries(self.paths.iter().enumerate())
+           .finish()
+    }
+}
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
new file mode 100644 (file)
index 0000000..35fa695
--- /dev/null
@@ -0,0 +1,151 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Debugging code to test the state of the dependency graph just
+//! after it is loaded from disk. For each node marked with
+//! `#[rustc_clean]` or `#[rustc_dirty]`, we will check that a
+//! suitable node for that item either appears or does not appear in
+//! the dep-graph, as appropriate:
+//!
+//! - `#[rustc_dirty(label="TypeckItemBody", cfg="rev2")]` if we are
+//!   in `#[cfg(rev2)]`, then there MUST NOT be a node
+//!   `DepNode::TypeckItemBody(X)` where `X` is the def-id of the
+//!   current node.
+//! - `#[rustc_clean(label="TypeckItemBody", cfg="rev2")]` same as above,
+//!   except that the node MUST exist.
+//!
+//! Errors are reported if we are in the suitable configuration but
+//! the required condition is not met.
+
+use rustc::dep_graph::{DepGraphQuery, DepNode};
+use rustc::hir;
+use rustc::hir::def_id::DefId;
+use rustc::hir::intravisit::Visitor;
+use syntax::ast::{self, Attribute, MetaItem};
+use syntax::attr::AttrMetaMethods;
+use syntax::parse::token::InternedString;
+use rustc::ty;
+
+const DIRTY: &'static str = "rustc_dirty";
+const CLEAN: &'static str = "rustc_clean";
+const LABEL: &'static str = "label";
+const CFG: &'static str = "cfg";
+
+pub fn check_dirty_clean_annotations(tcx: &ty::TyCtxt) {
+    let _ignore = tcx.dep_graph.in_ignore();
+    let query = tcx.dep_graph.query();
+    let krate = tcx.map.krate();
+    krate.visit_all_items(&mut DirtyCleanVisitor {
+        tcx: tcx,
+        query: &query,
+    });
+}
+
+pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
+    tcx: &'a ty::TyCtxt<'tcx>,
+    query: &'a DepGraphQuery<DefId>,
+}
+
+impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
+    fn expect_associated_value(&self, item: &MetaItem) -> InternedString {
+        if let Some(value) = item.value_str() {
+            value
+        } else {
+            self.tcx.sess.span_fatal(
+                item.span,
+                &format!("associated value expected for `{}`", item.name()));
+        }
+    }
+
+    /// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan
+    /// for a `cfg="foo"` attribute and check whether we have a cfg
+    /// flag called `foo`.
+    fn check_config(&self, attr: &ast::Attribute) -> bool {
+        debug!("check_config(attr={:?})", attr);
+        let config = &self.tcx.map.krate().config;
+        debug!("check_config: config={:?}", config);
+        for item in attr.meta_item_list().unwrap_or(&[]) {
+            if item.check_name(CFG) {
+                let value = self.expect_associated_value(item);
+                debug!("check_config: searching for cfg {:?}", value);
+                for cfg in &config[..] {
+                    if cfg.check_name(&value[..]) {
+                        debug!("check_config: matched {:?}", cfg);
+                        return true;
+                    }
+                }
+            }
+        }
+        debug!("check_config: no match found");
+        return false;
+    }
+
+    fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode<DefId> {
+        for item in attr.meta_item_list().unwrap_or(&[]) {
+            if item.check_name(LABEL) {
+                let value = self.expect_associated_value(item);
+                match DepNode::from_label_string(&value[..], def_id) {
+                    Ok(def_id) => return def_id,
+                    Err(()) => {
+                        self.tcx.sess.span_fatal(
+                            item.span,
+                            &format!("dep-node label `{}` not recognized", value));
+                    }
+                }
+            }
+        }
+
+        self.tcx.sess.span_fatal(attr.span, "no `label` found");
+    }
+
+    fn dep_node_str(&self, dep_node: DepNode<DefId>) -> DepNode<String> {
+        dep_node.map_def(|&def_id| Some(self.tcx.item_path_str(def_id))).unwrap()
+    }
+
+    fn assert_dirty(&self, item: &hir::Item, dep_node: DepNode<DefId>) {
+        debug!("assert_dirty({:?})", dep_node);
+
+        if self.query.contains_node(&dep_node) {
+            let dep_node_str = self.dep_node_str(dep_node);
+            self.tcx.sess.span_err(
+                item.span,
+                &format!("`{:?}` found in dep graph, but should be dirty", dep_node_str));
+        }
+    }
+
+    fn assert_clean(&self, item: &hir::Item, dep_node: DepNode<DefId>) {
+        debug!("assert_clean({:?})", dep_node);
+
+        if !self.query.contains_node(&dep_node) {
+            let dep_node_str = self.dep_node_str(dep_node);
+            self.tcx.sess.span_err(
+                item.span,
+                &format!("`{:?}` not found in dep graph, but should be clean", dep_node_str));
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        let def_id = self.tcx.map.local_def_id(item.id);
+        for attr in self.tcx.get_attrs(def_id).iter() {
+            if attr.check_name(DIRTY) {
+                if self.check_config(attr) {
+                    self.assert_dirty(item, self.dep_node(attr, def_id));
+                }
+            } else if attr.check_name(CLEAN) {
+                if self.check_config(attr) {
+                    self.assert_clean(item, self.dep_node(attr, def_id));
+                }
+            }
+        }
+    }
+}
+
diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs
new file mode 100644 (file)
index 0000000..196c451
--- /dev/null
@@ -0,0 +1,214 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Code to save/load the dep-graph from files.
+
+use calculate_svh::SvhCalculate;
+use rbml::Error;
+use rbml::opaque::Decoder;
+use rustc::dep_graph::DepNode;
+use rustc::hir::def_id::DefId;
+use rustc::ty;
+use rustc_data_structures::fnv::FnvHashSet;
+use rustc_serialize::Decodable as RustcDecodable;
+use std::io::Read;
+use std::fs::File;
+use std::path::Path;
+
+use super::data::*;
+use super::directory::*;
+use super::dirty_clean;
+use super::util::*;
+
+type DirtyNodes = FnvHashSet<DepNode<DefId>>;
+
+type CleanEdges = Vec<(DepNode<DefId>, DepNode<DefId>)>;
+
+/// If we are in incremental mode, and a previous dep-graph exists,
+/// then load up those nodes/edges that are still valid into the
+/// dep-graph for this session. (This is assumed to be running very
+/// early in compilation, before we've really done any work, but
+/// actually it doesn't matter all that much.) See `README.md` for
+/// more general overview.
+pub fn load_dep_graph<'tcx>(tcx: &ty::TyCtxt<'tcx>) {
+    let _ignore = tcx.dep_graph.in_ignore();
+
+    if let Some(dep_graph) = dep_graph_path(tcx) {
+        // FIXME(#32754) lock file?
+        load_dep_graph_if_exists(tcx, &dep_graph);
+        dirty_clean::check_dirty_clean_annotations(tcx);
+    }
+}
+
+pub fn load_dep_graph_if_exists<'tcx>(tcx: &ty::TyCtxt<'tcx>, path: &Path) {
+    if !path.exists() {
+        return;
+    }
+
+    let mut data = vec![];
+    match
+        File::open(path)
+        .and_then(|mut file| file.read_to_end(&mut data))
+    {
+        Ok(_) => { }
+        Err(err) => {
+            tcx.sess.err(
+                &format!("could not load dep-graph from `{}`: {}",
+                         path.display(), err));
+            return;
+        }
+    }
+
+    match decode_dep_graph(tcx, &data) {
+        Ok(dirty) => dirty,
+        Err(err) => {
+            bug!("decoding error in dep-graph from `{}`: {}", path.display(), err);
+        }
+    }
+}
+
+pub fn decode_dep_graph<'tcx>(tcx: &ty::TyCtxt<'tcx>, data: &[u8])
+                              -> Result<(), Error>
+{
+    // Deserialize the directory and dep-graph.
+    let mut decoder = Decoder::new(data, 0);
+    let directory = try!(DefIdDirectory::decode(&mut decoder));
+    let serialized_dep_graph = try!(SerializedDepGraph::decode(&mut decoder));
+
+    debug!("decode_dep_graph: directory = {:#?}", directory);
+    debug!("decode_dep_graph: serialized_dep_graph = {:#?}", serialized_dep_graph);
+
+    // Retrace the paths in the directory to find their current location (if any).
+    let retraced = directory.retrace(tcx);
+
+    debug!("decode_dep_graph: retraced = {:#?}", retraced);
+
+    // Compute the set of Hir nodes whose data has changed.
+    let mut dirty_nodes =
+        initial_dirty_nodes(tcx, &serialized_dep_graph.hashes, &retraced);
+
+    debug!("decode_dep_graph: initial dirty_nodes = {:#?}", dirty_nodes);
+
+    // Find all DepNodes reachable from that core set. This loop
+    // iterates repeatedly over the list of edges whose source is not
+    // known to be dirty (`clean_edges`). If it finds an edge whose
+    // source is dirty, it removes it from that list and adds the
+    // target to `dirty_nodes`. It stops when it reaches a fixed
+    // point.
+    let clean_edges = compute_clean_edges(&serialized_dep_graph.edges,
+                                          &retraced,
+                                          &mut dirty_nodes);
+
+    // Add synthetic `foo->foo` edges for each clean node `foo` that
+    // we had before. This is sort of a hack to create clean nodes in
+    // the graph, since the existence of a node is a signal that the
+    // work it represents need not be repeated.
+    let clean_nodes =
+        serialized_dep_graph.nodes
+                            .iter()
+                            .filter_map(|&node| retraced.map(node))
+                            .filter(|node| !dirty_nodes.contains(node))
+                            .map(|node| (node, node));
+
+    // Add nodes and edges that are not dirty into our main graph.
+    let dep_graph = tcx.dep_graph.clone();
+    for (source, target) in clean_edges.into_iter().chain(clean_nodes) {
+        let _task = dep_graph.in_task(target);
+        dep_graph.read(source);
+
+        debug!("decode_dep_graph: clean edge: {:?} -> {:?}", source, target);
+    }
+
+    Ok(())
+}
+
+fn initial_dirty_nodes<'tcx>(tcx: &ty::TyCtxt<'tcx>,
+                             hashed_items: &[SerializedHash],
+                             retraced: &RetracedDefIdDirectory)
+                             -> DirtyNodes {
+    let mut items_removed = false;
+    let mut dirty_nodes = FnvHashSet();
+    for hashed_item in hashed_items {
+        match retraced.def_id(hashed_item.index) {
+            Some(def_id) => {
+                // FIXME(#32753) -- should we use a distinct hash here
+                let current_hash = tcx.calculate_item_hash(def_id);
+                debug!("initial_dirty_nodes: hash of {:?} is {:?}, was {:?}",
+                       def_id, current_hash, hashed_item.hash);
+                if current_hash != hashed_item.hash {
+                    dirty_nodes.insert(DepNode::Hir(def_id));
+                }
+            }
+            None => {
+                items_removed = true;
+            }
+        }
+    }
+
+    // If any of the items in the krate have changed, then we consider
+    // the meta-node `Krate` to be dirty, since that means something
+    // which (potentially) read the contents of every single item.
+    if items_removed || !dirty_nodes.is_empty() {
+        dirty_nodes.insert(DepNode::Krate);
+    }
+
+    dirty_nodes
+}
+
+fn compute_clean_edges(serialized_edges: &[(SerializedEdge)],
+                       retraced: &RetracedDefIdDirectory,
+                       dirty_nodes: &mut DirtyNodes)
+                       -> CleanEdges {
+    // Build up an initial list of edges. Include an edge (source,
+    // target) if neither node has been removed. If the source has
+    // been removed, add target to the list of dirty nodes.
+    let mut clean_edges = Vec::with_capacity(serialized_edges.len());
+    for &(serialized_source, serialized_target) in serialized_edges {
+        if let Some(target) = retraced.map(serialized_target) {
+            if let Some(source) = retraced.map(serialized_source) {
+                clean_edges.push((source, target))
+            } else {
+                // source removed, target must be dirty
+                dirty_nodes.insert(target);
+            }
+        } else {
+            // target removed, ignore the edge
+        }
+    }
+
+    debug!("compute_clean_edges: dirty_nodes={:#?}", dirty_nodes);
+
+    // Propagate dirty marks by iterating repeatedly over
+    // `clean_edges`. If we find an edge `(source, target)` where
+    // `source` is dirty, add `target` to the list of dirty nodes and
+    // remove it. Keep doing this until we find no more dirty nodes.
+    let mut previous_size = 0;
+    while dirty_nodes.len() > previous_size {
+        debug!("compute_clean_edges: previous_size={}", previous_size);
+        previous_size = dirty_nodes.len();
+        let mut i = 0;
+        while i < clean_edges.len() {
+            if dirty_nodes.contains(&clean_edges[i].0) {
+                let (source, target) = clean_edges.swap_remove(i);
+                debug!("compute_clean_edges: dirty source {:?} -> {:?}",
+                       source, target);
+                dirty_nodes.insert(target);
+            } else if dirty_nodes.contains(&clean_edges[i].1) {
+                let (source, target) = clean_edges.swap_remove(i);
+                debug!("compute_clean_edges: dirty target {:?} -> {:?}",
+                       source, target);
+            } else {
+                i += 1;
+            }
+        }
+    }
+
+    clean_edges
+}
diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs
new file mode 100644 (file)
index 0000000..8d04fd3
--- /dev/null
@@ -0,0 +1,23 @@
+// 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.
+
+//! When in incremental mode, this pass dumps out the dependency graph
+//! into the given directory. At the same time, it also hashes the
+//! various HIR nodes.
+
+mod data;
+mod directory;
+mod dirty_clean;
+mod load;
+mod save;
+mod util;
+
+pub use self::load::load_dep_graph;
+pub use self::save::save_dep_graph;
diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs
new file mode 100644 (file)
index 0000000..d88f9e4
--- /dev/null
@@ -0,0 +1,136 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use calculate_svh::SvhCalculate;
+use rbml::opaque::Encoder;
+use rustc::dep_graph::DepNode;
+use rustc::ty;
+use rustc_serialize::{Encodable as RustcEncodable};
+use std::io::{self, Cursor, Write};
+use std::fs::{self, File};
+
+use super::data::*;
+use super::directory::*;
+use super::util::*;
+
+pub fn save_dep_graph<'tcx>(tcx: &ty::TyCtxt<'tcx>) {
+    let _ignore = tcx.dep_graph.in_ignore();
+
+    if let Some(dep_graph) = dep_graph_path(tcx) {
+        // FIXME(#32754) lock file?
+
+        // delete the old dep-graph, if any
+        if dep_graph.exists() {
+            match fs::remove_file(&dep_graph) {
+                Ok(()) => { }
+                Err(err) => {
+                    tcx.sess.err(
+                        &format!("unable to delete old dep-graph at `{}`: {}",
+                                 dep_graph.display(), err));
+                    return;
+                }
+            }
+        }
+
+        // generate the data in a memory buffer
+        let mut wr = Cursor::new(Vec::new());
+        match encode_dep_graph(tcx, &mut Encoder::new(&mut wr)) {
+            Ok(()) => { }
+            Err(err) => {
+                tcx.sess.err(
+                    &format!("could not encode dep-graph to `{}`: {}",
+                             dep_graph.display(), err));
+                return;
+            }
+        }
+
+        // write the data out
+        let data = wr.into_inner();
+        match
+            File::create(&dep_graph)
+            .and_then(|mut file| file.write_all(&data))
+        {
+            Ok(_) => { }
+            Err(err) => {
+                tcx.sess.err(
+                    &format!("failed to write dep-graph to `{}`: {}",
+                             dep_graph.display(), err));
+                return;
+            }
+        }
+    }
+}
+
+pub fn encode_dep_graph<'tcx>(tcx: &ty::TyCtxt<'tcx>,
+                              encoder: &mut Encoder)
+                              -> io::Result<()>
+{
+    // Here we take advantage of how RBML allows us to skip around
+    // and encode the depgraph as a two-part structure:
+    //
+    // ```
+    // <dep-graph>[SerializedDepGraph]</dep-graph> // tag 0
+    // <directory>[DefIdDirectory]</directory>     // tag 1
+    // ```
+    //
+    // Then later we can load the directory by skipping to find tag 1.
+
+    let query = tcx.dep_graph.query();
+
+    let mut builder = DefIdDirectoryBuilder::new(tcx);
+
+    // Create hashes for things we can persist.
+    let hashes =
+        query.nodes()
+             .into_iter()
+             .filter_map(|dep_node| match dep_node {
+                 DepNode::Hir(def_id) => {
+                     assert!(def_id.is_local());
+                     builder.add(def_id)
+                            .map(|index| {
+                                // FIXME(#32753) -- should we use a distinct hash here
+                                let hash = tcx.calculate_item_hash(def_id);
+                                SerializedHash { index: index, hash: hash }
+                            })
+                 }
+                 _ => None
+             })
+             .collect();
+
+    // Create the serialized dep-graph, dropping nodes that are
+    // from other crates or from inlined items.
+    //
+    // FIXME(#32015) fix handling of other crates
+    let graph = SerializedDepGraph {
+        nodes: query.nodes().into_iter()
+                            .flat_map(|node| builder.map(node))
+                            .collect(),
+        edges: query.edges().into_iter()
+                            .flat_map(|(source_node, target_node)| {
+                                builder.map(source_node)
+                                       .and_then(|source| {
+                                           builder.map(target_node)
+                                                  .map(|target| (source, target))
+                                       })
+                            })
+                            .collect(),
+        hashes: hashes,
+    };
+
+    debug!("graph = {:#?}", graph);
+
+    // Encode the directory and then the graph data.
+    let directory = builder.into_directory();
+    try!(directory.encode(encoder));
+    try!(graph.encode(encoder));
+
+    Ok(())
+}
+
diff --git a/src/librustc_incremental/persist/serialize.rs b/src/librustc_incremental/persist/serialize.rs
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/librustc_incremental/persist/util.rs b/src/librustc_incremental/persist/util.rs
new file mode 100644 (file)
index 0000000..9b4e599
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::ty;
+use std::fs;
+use std::path::PathBuf;
+
+pub fn dep_graph_path<'tcx>(tcx: &ty::TyCtxt<'tcx>) -> Option<PathBuf> {
+    // For now, just save/load dep-graph from
+    // directory/dep_graph.rbml
+    tcx.sess.opts.incremental.as_ref().and_then(|incr_dir| {
+        match fs::create_dir_all(&incr_dir){
+            Ok(()) => {}
+            Err(err) => {
+                tcx.sess.err(
+                    &format!("could not create the directory `{}`: {}",
+                             incr_dir.display(), err));
+                return None;
+            }
+        }
+
+        Some(incr_dir.join("dep_graph.rbml"))
+    })
+}
+
index d10691d12ed970c1d71c61e63e6692a04c0fab84..f4fb226d3525f7aaf598530dcf940cdd3a04018e 100644 (file)
@@ -63,7 +63,9 @@ fn is_camel_case(name: ast::Name) -> bool {
 
             // start with a non-lowercase letter rather than non-uppercase
             // ones (some scripts don't have a concept of upper/lowercase)
-            !name.is_empty() && !name.char_at(0).is_lowercase() && !name.contains('_')
+            !name.is_empty() &&
+                !name.chars().next().unwrap().is_lowercase() &&
+                !name.contains('_')
         }
 
         fn to_camel_case(s: &str) -> String {
index 2075bd5edcaeb913c3dfc002b651c4c23d789a47..e7c9097a56a58ea27bf26a1548c9a3db6edb0705 100644 (file)
@@ -36,7 +36,6 @@
 #![feature(rustc_private)]
 #![feature(slice_patterns)]
 #![feature(staged_api)]
-#![feature(str_char)]
 
 #[macro_use]
 extern crate syntax;
index a0881f1153e39eec45eb4037852eb2115436b3cf..6a634d061fa92f86778d3d022dca31e1ebda7cd4 100644 (file)
@@ -1242,7 +1242,7 @@ fn docstr(doc: rbml::Doc, tag_: usize) -> String {
 
     reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| {
         let name = docstr(depdoc, tag_crate_dep_crate_name);
-        let hash = Svh::new(&docstr(depdoc, tag_crate_dep_hash));
+        let hash = Svh::new(docstr(depdoc, tag_crate_dep_hash));
         let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked);
         let explicitly_linked = reader::doc_as_u8(doc) != 0;
         CrateDep {
@@ -1266,14 +1266,14 @@ fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> {
 pub fn maybe_get_crate_hash(data: &[u8]) -> Option<Svh> {
     let cratedoc = rbml::Doc::new(data);
     reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| {
-        Svh::new(doc.as_str_slice())
+        Svh::new(doc.as_str_slice().to_string())
     })
 }
 
 pub fn get_crate_hash(data: &[u8]) -> Svh {
     let cratedoc = rbml::Doc::new(data);
     let hashdoc = reader::get_doc(cratedoc, tag_crate_hash);
-    Svh::new(hashdoc.as_str_slice())
+    Svh::new(hashdoc.as_str_slice().to_string())
 }
 
 pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> {
index ce8ede7f4b9592be12d82a5caf829bc507c81e67..11ac1fa8f82a18e30a7116198afc42695a4d7838 100644 (file)
@@ -584,7 +584,8 @@ fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, id: NodeId, mir: &mut Mir<'tcx>) {
             // broken MIR, so try not to report duplicate errors.
             return;
         }
-        let _task = tcx.dep_graph.in_task(DepNode::MirTypeck(id));
+        let def_id = tcx.map.local_def_id(id);
+        let _task = tcx.dep_graph.in_task(DepNode::MirTypeck(def_id));
         let param_env = ty::ParameterEnvironment::for_item(tcx, id);
         let infcx = infer::new_infer_ctxt(tcx,
                                           &tcx.tables,
index 738a99fbe9200d5d3b7f935153b032c3089ef158..f0e834d43032516b0888f8a5bacbc8b1963ae5e5 100644 (file)
@@ -539,6 +539,7 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResul
             (&Failed(_), &Failed(_)) => {
                 let resolutions = target_module.resolutions.borrow();
                 let names = resolutions.iter().filter_map(|(&(ref name, _), resolution)| {
+                    if *name == source { return None; } // Never suggest the same name
                     match *resolution.borrow() {
                         NameResolution { binding: Some(_), .. } => Some(name),
                         NameResolution { single_imports: SingleImports::None, .. } => None,
@@ -549,9 +550,12 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResul
                     Some(name) => format!(". Did you mean to use `{}`?", name),
                     None => "".to_owned(),
                 };
-                let msg = format!("There is no `{}` in `{}`{}",
-                                  source,
-                                  module_to_string(target_module), lev_suggestion);
+                let module_str = module_to_string(target_module);
+                let msg = if &module_str == "???" {
+                    format!("There is no `{}` in the crate root{}", source, lev_suggestion)
+                } else {
+                    format!("There is no `{}` in `{}`{}", source, module_str, lev_suggestion)
+                };
                 return Failed(Some((directive.span, msg)));
             }
             _ => (),
index ea4cef03b707a688b0e528d93f1e9c8ace5d746d..ccb430fbb782fe3d8e777319e6645177ba610f8b 100644 (file)
@@ -18,6 +18,7 @@ rustc_back = { path = "../librustc_back" }
 rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_incremental = { path = "../librustc_incremental" }
 rustc_llvm = { path = "../librustc_llvm" }
 rustc_mir = { path = "../librustc_mir" }
 rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
index 961a32170d0df80895171622dbdd62a3f9c29c43..cb29f27b83fd7a15ac173be75be667ff9c3a4e96 100644 (file)
@@ -80,6 +80,8 @@ pub struct ArgType {
     /// Only later will `original_ty` aka `%Foo` be used in the LLVM function
     /// pointer type, without ever having introspected it.
     pub ty: Type,
+    /// Signedness for integer types, None for other types
+    pub signedness: Option<bool>,
     /// Coerced LLVM Type
     pub cast: Option<Type>,
     /// Dummy argument, which is emitted before the real argument
@@ -94,6 +96,7 @@ fn new(original_ty: Type, ty: Type) -> ArgType {
             kind: ArgKind::Direct,
             original_ty: original_ty,
             ty: ty,
+            signedness: None,
             cast: None,
             pad: None,
             attrs: llvm::Attributes::default()
@@ -123,6 +126,19 @@ pub fn ignore(&mut self) {
         self.kind = ArgKind::Ignore;
     }
 
+    pub fn extend_integer_width_to(&mut self, bits: u64) {
+        // Only integers have signedness
+        if let Some(signed) = self.signedness {
+            if self.ty.int_width() < bits {
+                self.attrs.set(if signed {
+                    llvm::Attribute::SExt
+                } else {
+                    llvm::Attribute::ZExt
+                });
+            }
+        }
+    }
+
     pub fn is_indirect(&self) -> bool {
         self.kind == ArgKind::Indirect
     }
@@ -268,6 +284,9 @@ pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             } else {
                 let mut arg = ArgType::new(type_of::type_of(ccx, ty),
                                            type_of::sizing_type_of(ccx, ty));
+                if ty.is_integral() {
+                    arg.signedness = Some(ty.is_signed());
+                }
                 if llsize_of_real(ccx, arg.ty) == 0 {
                     // For some forsaken reason, x86_64-pc-windows-gnu
                     // doesn't ignore zero-sized struct arguments.
diff --git a/src/librustc_trans/assert_dep_graph.rs b/src/librustc_trans/assert_dep_graph.rs
deleted file mode 100644 (file)
index 932f66f..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-// 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.
-
-//! This pass is only used for the UNIT TESTS and DEBUGGING NEEDS
-//! around dependency graph construction. It serves two purposes; it
-//! will dump graphs in graphviz form to disk, and it searches for
-//! `#[rustc_if_this_changed]` and `#[rustc_then_this_would_need]`
-//! annotations. These annotations can be used to test whether paths
-//! exist in the graph. We report errors on each
-//! `rustc_if_this_changed` annotation. If a path exists in all
-//! cases, then we would report "all path(s) exist". Otherwise, we
-//! report: "no path to `foo`" for each case where no path exists.
-//! `compile-fail` tests can then be used to check when paths exist or
-//! do not.
-//!
-//! The full form of the `rustc_if_this_changed` annotation is
-//! `#[rustc_if_this_changed(id)]`. The `"id"` is optional and
-//! defaults to `"id"` if omitted.
-//!
-//! Example:
-//!
-//! ```
-//! #[rustc_if_this_changed]
-//! fn foo() { }
-//!
-//! #[rustc_then_this_would_need("trans")] //~ ERROR no path from `foo`
-//! fn bar() { }
-//!
-//! #[rustc_then_this_would_need("trans")] //~ ERROR OK
-//! fn baz() { foo(); }
-//! ```
-
-use graphviz as dot;
-use rustc::dep_graph::{DepGraphQuery, DepNode};
-use rustc::hir::def_id::DefId;
-use rustc::ty::TyCtxt;
-use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet};
-use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex};
-use rustc::hir;
-use rustc::hir::intravisit::Visitor;
-use graphviz::IntoCow;
-use std::env;
-use std::fs::File;
-use std::io::Write;
-use syntax::ast;
-use syntax::attr::AttrMetaMethods;
-use syntax::codemap::Span;
-use syntax::parse::token::InternedString;
-
-const IF_THIS_CHANGED: &'static str = "rustc_if_this_changed";
-const THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need";
-const ID: &'static str = "id";
-
-pub fn assert_dep_graph(tcx: &TyCtxt) {
-    let _ignore = tcx.dep_graph.in_ignore();
-
-    if tcx.sess.opts.dump_dep_graph {
-        dump_graph(tcx);
-    }
-
-    // Find annotations supplied by user (if any).
-    let (if_this_changed, then_this_would_need) = {
-        let mut visitor = IfThisChanged { tcx: tcx,
-                                          if_this_changed: FnvHashMap(),
-                                          then_this_would_need: FnvHashMap() };
-        tcx.map.krate().visit_all_items(&mut visitor);
-        (visitor.if_this_changed, visitor.then_this_would_need)
-    };
-
-    // Check paths.
-    check_paths(tcx, &if_this_changed, &then_this_would_need);
-}
-
-type SourceHashMap = FnvHashMap<InternedString,
-                                FnvHashSet<(Span, DefId, DepNode)>>;
-type TargetHashMap = FnvHashMap<InternedString,
-                                FnvHashSet<(Span, InternedString, ast::NodeId, DepNode)>>;
-
-struct IfThisChanged<'a, 'tcx:'a> {
-    tcx: &'a TyCtxt<'tcx>,
-    if_this_changed: SourceHashMap,
-    then_this_would_need: TargetHashMap,
-}
-
-impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
-    fn process_attrs(&mut self, node_id: ast::NodeId, def_id: DefId) {
-        for attr in self.tcx.get_attrs(def_id).iter() {
-            if attr.check_name(IF_THIS_CHANGED) {
-                let mut id = None;
-                for meta_item in attr.meta_item_list().unwrap_or_default() {
-                    match meta_item.node {
-                        ast::MetaItemKind::Word(ref s) if id.is_none() => id = Some(s.clone()),
-                        _ => {
-                            self.tcx.sess.span_err(
-                                meta_item.span,
-                                &format!("unexpected meta-item {:?}", meta_item.node));
-                        }
-                    }
-                }
-                let id = id.unwrap_or(InternedString::new(ID));
-                self.if_this_changed.entry(id)
-                                    .or_insert(FnvHashSet())
-                                    .insert((attr.span, def_id, DepNode::Hir(def_id)));
-            } else if attr.check_name(THEN_THIS_WOULD_NEED) {
-                let mut dep_node_interned = None;
-                let mut id = None;
-                for meta_item in attr.meta_item_list().unwrap_or_default() {
-                    match meta_item.node {
-                        ast::MetaItemKind::Word(ref s) if dep_node_interned.is_none() =>
-                            dep_node_interned = Some(s.clone()),
-                        ast::MetaItemKind::Word(ref s) if id.is_none() =>
-                            id = Some(s.clone()),
-                        _ => {
-                            self.tcx.sess.span_err(
-                                meta_item.span,
-                                &format!("unexpected meta-item {:?}", meta_item.node));
-                        }
-                    }
-                }
-                let dep_node_str = dep_node_interned.as_ref().map(|s| &**s);
-                macro_rules! match_depnode_name {
-                    ($input:expr, $def_id:expr, match { $($variant:ident,)* } else $y:expr) => {
-                        match $input {
-                            $(Some(stringify!($variant)) => DepNode::$variant($def_id),)*
-                            _ => $y
-                        }
-                    }
-                }
-                let dep_node = match_depnode_name! {
-                    dep_node_str, def_id, match {
-                        CollectItem,
-                        BorrowCheck,
-                        TransCrateItem,
-                        TypeckItemType,
-                        TypeckItemBody,
-                        ImplOrTraitItems,
-                        ItemSignature,
-                        FieldTy,
-                        TraitItemDefIds,
-                        InherentImpls,
-                        ImplItems,
-                        TraitImpls,
-                        ReprHints,
-                    } else {
-                        self.tcx.sess.span_fatal(
-                            attr.span,
-                            &format!("unrecognized DepNode variant {:?}", dep_node_str));
-                    }
-                };
-                let id = id.unwrap_or(InternedString::new(ID));
-                self.then_this_would_need
-                    .entry(id)
-                    .or_insert(FnvHashSet())
-                    .insert((attr.span, dep_node_interned.clone().unwrap(), node_id, dep_node));
-            }
-        }
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for IfThisChanged<'a, 'tcx> {
-    fn visit_item(&mut self, item: &'tcx hir::Item) {
-        let def_id = self.tcx.map.local_def_id(item.id);
-        self.process_attrs(item.id, def_id);
-    }
-}
-
-fn check_paths(tcx: &TyCtxt,
-               if_this_changed: &SourceHashMap,
-               then_this_would_need: &TargetHashMap)
-{
-    // Return early here so as not to construct the query, which is not cheap.
-    if if_this_changed.is_empty() {
-        return;
-    }
-    let query = tcx.dep_graph.query();
-    for (id, sources) in if_this_changed {
-        let targets = match then_this_would_need.get(id) {
-            Some(targets) => targets,
-            None => {
-                for &(source_span, _, _) in sources.iter().take(1) {
-                    tcx.sess.span_err(
-                        source_span,
-                        &format!("no targets for id `{}`", id));
-                }
-                continue;
-            }
-        };
-
-        for &(_, source_def_id, source_dep_node) in sources {
-            let dependents = query.dependents(source_dep_node);
-            for &(target_span, ref target_pass, _, ref target_dep_node) in targets {
-                if !dependents.contains(&target_dep_node) {
-                    tcx.sess.span_err(
-                        target_span,
-                        &format!("no path from `{}` to `{}`",
-                                 tcx.item_path_str(source_def_id),
-                                 target_pass));
-                } else {
-                    tcx.sess.span_err(
-                        target_span,
-                        &format!("OK"));
-                }
-            }
-        }
-    }
-}
-
-fn dump_graph(tcx: &TyCtxt) {
-    let path: String = env::var("RUST_DEP_GRAPH").unwrap_or_else(|_| format!("dep_graph"));
-    let query = tcx.dep_graph.query();
-
-    let nodes = match env::var("RUST_DEP_GRAPH_FILTER") {
-        Ok(string) => {
-            // Expect one of: "-> target", "source -> target", or "source ->".
-            let parts: Vec<_> = string.split("->").collect();
-            if parts.len() > 2 {
-                bug!("Invalid RUST_DEP_GRAPH_FILTER: expected '[source] -> [target]'");
-            }
-            let sources = node_set(&query, &parts[0]);
-            let targets = node_set(&query, &parts[1]);
-            filter_nodes(&query, &sources, &targets)
-        }
-        Err(_) => {
-            query.nodes()
-                 .into_iter()
-                 .collect()
-        }
-    };
-    let edges = filter_edges(&query, &nodes);
-
-    { // dump a .txt file with just the edges:
-        let txt_path = format!("{}.txt", path);
-        let mut file = File::create(&txt_path).unwrap();
-        for &(source, target) in &edges {
-            write!(file, "{:?} -> {:?}\n", source, target).unwrap();
-        }
-    }
-
-    { // dump a .dot file in graphviz format:
-        let dot_path = format!("{}.dot", path);
-        let mut v = Vec::new();
-        dot::render(&GraphvizDepGraph(nodes, edges), &mut v).unwrap();
-        File::create(&dot_path).and_then(|mut f| f.write_all(&v)).unwrap();
-    }
-}
-
-pub struct GraphvizDepGraph(FnvHashSet<DepNode>, Vec<(DepNode, DepNode)>);
-
-impl<'a, 'tcx> dot::GraphWalk<'a> for GraphvizDepGraph {
-    type Node = DepNode;
-    type Edge = (DepNode, DepNode);
-    fn nodes(&self) -> dot::Nodes<DepNode> {
-        let nodes: Vec<_> = self.0.iter().cloned().collect();
-        nodes.into_cow()
-    }
-    fn edges(&self) -> dot::Edges<(DepNode, DepNode)> {
-        self.1[..].into_cow()
-    }
-    fn source(&self, edge: &(DepNode, DepNode)) -> DepNode {
-        edge.0
-    }
-    fn target(&self, edge: &(DepNode, DepNode)) -> DepNode {
-        edge.1
-    }
-}
-
-impl<'a, 'tcx> dot::Labeller<'a> for GraphvizDepGraph {
-    type Node = DepNode;
-    type Edge = (DepNode, DepNode);
-    fn graph_id(&self) -> dot::Id {
-        dot::Id::new("DependencyGraph").unwrap()
-    }
-    fn node_id(&self, n: &DepNode) -> dot::Id {
-        let s: String =
-            format!("{:?}", n).chars()
-                              .map(|c| if c == '_' || c.is_alphanumeric() { c } else { '_' })
-                              .collect();
-        debug!("n={:?} s={:?}", n, s);
-        dot::Id::new(s).unwrap()
-    }
-    fn node_label(&self, n: &DepNode) -> dot::LabelText {
-        dot::LabelText::label(format!("{:?}", n))
-    }
-}
-
-// Given an optional filter like `"x,y,z"`, returns either `None` (no
-// filter) or the set of nodes whose labels contain all of those
-// substrings.
-fn node_set(query: &DepGraphQuery, filter: &str) -> Option<FnvHashSet<DepNode>> {
-    debug!("node_set(filter={:?})", filter);
-
-    if filter.trim().is_empty() {
-        return None;
-    }
-
-    let filters: Vec<&str> = filter.split("&").map(|s| s.trim()).collect();
-
-    debug!("node_set: filters={:?}", filters);
-
-    Some(query.nodes()
-         .into_iter()
-         .filter(|n| {
-             let s = format!("{:?}", n);
-             filters.iter().all(|f| s.contains(f))
-         })
-        .collect())
-}
-
-fn filter_nodes(query: &DepGraphQuery,
-                sources: &Option<FnvHashSet<DepNode>>,
-                targets: &Option<FnvHashSet<DepNode>>)
-                -> FnvHashSet<DepNode>
-{
-    if let &Some(ref sources) = sources {
-        if let &Some(ref targets) = targets {
-            walk_between(query, sources, targets)
-        } else {
-            walk_nodes(query, sources, OUTGOING)
-        }
-    } else if let &Some(ref targets) = targets {
-        walk_nodes(query, targets, INCOMING)
-    } else {
-        query.nodes().into_iter().collect()
-    }
-}
-
-fn walk_nodes(query: &DepGraphQuery,
-              starts: &FnvHashSet<DepNode>,
-              direction: Direction)
-              -> FnvHashSet<DepNode>
-{
-    let mut set = FnvHashSet();
-    for start in starts {
-        debug!("walk_nodes: start={:?} outgoing?={:?}", start, direction == OUTGOING);
-        if set.insert(*start) {
-            let mut stack = vec![query.indices[start]];
-            while let Some(index) = stack.pop() {
-                for (_, edge) in query.graph.adjacent_edges(index, direction) {
-                    let neighbor_index = edge.source_or_target(direction);
-                    let neighbor = query.graph.node_data(neighbor_index);
-                    if set.insert(*neighbor) {
-                        stack.push(neighbor_index);
-                    }
-                }
-            }
-        }
-    }
-    set
-}
-
-fn walk_between(query: &DepGraphQuery,
-                sources: &FnvHashSet<DepNode>,
-                targets: &FnvHashSet<DepNode>)
-                -> FnvHashSet<DepNode>
-{
-    // This is a bit tricky. We want to include a node only if it is:
-    // (a) reachable from a source and (b) will reach a target. And we
-    // have to be careful about cycles etc.  Luckily efficiency is not
-    // a big concern!
-
-    #[derive(Copy, Clone, PartialEq)]
-    enum State { Undecided, Deciding, Included, Excluded }
-
-    let mut node_states = vec![State::Undecided; query.graph.len_nodes()];
-
-    for &target in targets {
-        node_states[query.indices[&target].0] = State::Included;
-    }
-
-    for source in sources.iter().map(|n| query.indices[n]) {
-        recurse(query, &mut node_states, source);
-    }
-
-    return query.nodes()
-                .into_iter()
-                .filter(|n| {
-                    let index = query.indices[n];
-                    node_states[index.0] == State::Included
-                })
-                .collect();
-
-    fn recurse(query: &DepGraphQuery,
-               node_states: &mut [State],
-               node: NodeIndex)
-               -> bool
-    {
-        match node_states[node.0] {
-            // known to reach a target
-            State::Included => return true,
-
-            // known not to reach a target
-            State::Excluded => return false,
-
-            // backedge, not yet known, say false
-            State::Deciding => return false,
-
-            State::Undecided => { }
-        }
-
-        node_states[node.0] = State::Deciding;
-
-        for neighbor_index in query.graph.successor_nodes(node) {
-            if recurse(query, node_states, neighbor_index) {
-                node_states[node.0] = State::Included;
-            }
-        }
-
-        // if we didn't find a path to target, then set to excluded
-        if node_states[node.0] == State::Deciding {
-            node_states[node.0] = State::Excluded;
-            false
-        } else {
-            assert!(node_states[node.0] == State::Included);
-            true
-        }
-    }
-}
-
-fn filter_edges(query: &DepGraphQuery,
-                nodes: &FnvHashSet<DepNode>)
-                -> Vec<(DepNode, DepNode)>
-{
-    query.edges()
-         .into_iter()
-         .filter(|&(source, target)| nodes.contains(&source) && nodes.contains(&target))
-         .collect()
-}
index 130499603e7a710839c86c5f5a9fd16a88532c06..4e77b2bc06940b78c1312addb2edd098b07f62bd 100644 (file)
@@ -13,7 +13,6 @@
 use super::rpath::RPathConfig;
 use super::rpath;
 use super::msvc;
-use super::svh::Svh;
 use session::config;
 use session::config::NoDebugInfo;
 use session::config::{OutputFilenames, Input, OutputType};
 use CrateTranslation;
 use util::common::time;
 use util::fs::fix_windows_verbatim_for_gcc;
+use rustc::ty::TyCtxt;
 use rustc_back::tempdir::TempDir;
 
+use rustc_incremental::SvhCalculate;
 use std::ascii;
 use std::char;
 use std::env;
@@ -43,8 +44,6 @@
 use syntax::codemap::Span;
 use syntax::attr::AttrMetaMethods;
 
-use rustc::hir;
-
 // RLIB LLVM-BYTECODE OBJECT LAYOUT
 // Version 1
 // Bytes    Data
@@ -122,15 +121,15 @@ pub fn find_crate_name(sess: Option<&Session>,
     }
 
     "rust_out".to_string()
+
 }
 
-pub fn build_link_meta(sess: &Session,
-                       krate: &hir::Crate,
+pub fn build_link_meta(tcx: &TyCtxt,
                        name: &str)
                        -> LinkMeta {
     let r = LinkMeta {
         crate_name: name.to_owned(),
-        crate_hash: Svh::calculate(&sess.crate_disambiguator.get().as_str(), krate),
+        crate_hash: tcx.calculate_krate_hash(),
     };
     info!("{:?}", r);
     return r;
index c8ed4e629e4c1e39f7cdb2098d5e3f9349b51238..17230eff6e639aa382f89c98d252a7a99950a83e 100644 (file)
@@ -54,7 +54,6 @@
 use _match;
 use abi::{self, Abi, FnType};
 use adt;
-use assert_dep_graph;
 use attributes;
 use build::*;
 use builder::{Builder, noname};
@@ -2730,7 +2729,7 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>,
         }
     }
 
-    let link_meta = link::build_link_meta(&tcx.sess, krate, name);
+    let link_meta = link::build_link_meta(&tcx, name);
 
     let codegen_units = tcx.sess.opts.cg.codegen_units;
     let shared_ccx = SharedCrateContext::new(&link_meta.crate_name,
@@ -2856,8 +2855,6 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>,
     };
     let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
 
-    assert_dep_graph::assert_dep_graph(tcx);
-
     CrateTranslation {
         modules: modules,
         metadata_module: metadata_module,
index 4903af2a6ff7df5442aa848b4dfc6412f97a3057..fc11e3888d3c2e6cfcf72d42e3384ff25d11c39e 100644 (file)
@@ -163,6 +163,7 @@ fn check_struct(ty: Type) -> Option<(Type, u64)> {
 
 fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
     if is_reg_ty(ret.ty) {
+        ret.extend_integer_width_to(32);
         return;
     }
     if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
@@ -190,6 +191,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
 
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
     if is_reg_ty(arg.ty) {
+        arg.extend_integer_width_to(32);
         return;
     }
     if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
index 35099399e317c3c86673a2af67881eebffd802fc..68a2e8aa8ce95d8c38bfd91ad30db2cc08927a39 100644 (file)
@@ -131,6 +131,7 @@ fn ty_size(ty: Type, align_fn: TyAlignFn) -> usize {
 
 fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) {
     if is_reg_ty(ret.ty) {
+        ret.extend_integer_width_to(32);
         return;
     }
     let size = ty_size(ret.ty, align_fn);
@@ -150,6 +151,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) {
 
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, align_fn: TyAlignFn) {
     if is_reg_ty(arg.ty) {
+        arg.extend_integer_width_to(32);
         return;
     }
     let align = align_fn(arg.ty);
index be9d4cad1db684af77eed434f5f9e37da7fbba4d..680310e195a41536d18554af0a994b095f79951d 100644 (file)
@@ -86,6 +86,14 @@ fn ty_size(ty: Type) -> usize {
     }
 }
 
+fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
+    if is_reg_ty(ret.ty) {
+        ret.extend_integer_width_to(32);
+    } else {
+        ret.make_indirect(ccx);
+    }
+}
+
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
     let orig_offset = *offset;
     let size = ty_size(arg.ty) * 8;
@@ -98,6 +106,8 @@ fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
     if !is_reg_ty(arg.ty) {
         arg.cast = Some(struct_ty(ccx, arg.ty));
         arg.pad = padding_ty(ccx, align, orig_offset);
+    } else {
+        arg.extend_integer_width_to(32);
     }
 }
 
@@ -146,8 +156,8 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
 }
 
 pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
-    if !fty.ret.is_ignore() && !is_reg_ty(fty.ret.ty) {
-        fty.ret.make_indirect(ccx);
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(ccx, &mut fty.ret);
     }
 
     let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
index d118cc86f2443056bc8051568fc99601b917eb90..efbdce67a8b2ad911cd837b3d016a20be58cce46 100644 (file)
@@ -82,6 +82,14 @@ fn ty_size(ty: Type) -> usize {
     }
 }
 
+fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
+    if is_reg_ty(ret.ty) {
+        ret.extend_integer_width_to(32);
+    } else {
+        ret.make_indirect(ccx);
+    }
+}
+
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
     let orig_offset = *offset;
     let size = ty_size(arg.ty) * 8;
@@ -94,6 +102,8 @@ fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
     if !is_reg_ty(arg.ty) {
         arg.cast = Some(struct_ty(ccx, arg.ty));
         arg.pad = padding_ty(ccx, align, orig_offset);
+    } else {
+        arg.extend_integer_width_to(32);
     }
 }
 
@@ -141,8 +151,8 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
 }
 
 pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
-    if !fty.ret.is_ignore() && !is_reg_ty(fty.ret.ty) {
-        fty.ret.make_indirect(ccx);
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(ccx, &mut fty.ret);
     }
 
     let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
index 7bc41d26f8b757b41ab446d0dc4a29900d1d1cc3..ba54e369fd8382779b9ee6bfd567ccc82b4d2834 100644 (file)
@@ -153,6 +153,7 @@ fn check_struct(ty: Type) -> Option<(Type, u64)> {
 
 fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
     if is_reg_ty(ret.ty) {
+        ret.extend_integer_width_to(64);
         return;
     }
 
@@ -187,6 +188,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
 
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
     if is_reg_ty(arg.ty) {
+        arg.extend_integer_width_to(64);
         return;
     }
 
index 415579eb221dda071cd0c7e49e563e6c10700b43..b52231fa6b432f8aaca36d346d29368f2ea024c4 100644 (file)
 use super::machine::*;
 
 pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
-    if !fty.ret.is_ignore() && fty.ret.ty.kind() == Struct {
-        // Returning a structure. Most often, this will use
-        // a hidden first argument. On some platforms, though,
-        // small structs are returned as integers.
-        //
-        // Some links:
-        // http://www.angelcode.com/dev/callconv/callconv.html
-        // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
-        let t = &ccx.sess().target.target;
-        if t.options.is_like_osx || t.options.is_like_windows {
-            match llsize_of_alloc(ccx, fty.ret.ty) {
-                1 => fty.ret.cast = Some(Type::i8(ccx)),
-                2 => fty.ret.cast = Some(Type::i16(ccx)),
-                4 => fty.ret.cast = Some(Type::i32(ccx)),
-                8 => fty.ret.cast = Some(Type::i64(ccx)),
-                _ => fty.ret.make_indirect(ccx)
+    if !fty.ret.is_ignore() {
+        if fty.ret.ty.kind() == Struct {
+            // Returning a structure. Most often, this will use
+            // a hidden first argument. On some platforms, though,
+            // small structs are returned as integers.
+            //
+            // Some links:
+            // http://www.angelcode.com/dev/callconv/callconv.html
+            // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
+            let t = &ccx.sess().target.target;
+            if t.options.is_like_osx || t.options.is_like_windows {
+                match llsize_of_alloc(ccx, fty.ret.ty) {
+                    1 => fty.ret.cast = Some(Type::i8(ccx)),
+                    2 => fty.ret.cast = Some(Type::i16(ccx)),
+                    4 => fty.ret.cast = Some(Type::i32(ccx)),
+                    8 => fty.ret.cast = Some(Type::i64(ccx)),
+                    _ => fty.ret.make_indirect(ccx)
+                }
+            } else {
+                fty.ret.make_indirect(ccx);
             }
         } else {
-            fty.ret.make_indirect(ccx);
+            fty.ret.extend_integer_width_to(32);
         }
     }
 
@@ -42,6 +46,8 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
         if arg.ty.kind() == Struct {
             arg.make_indirect(ccx);
             arg.attrs.set(Attribute::ByVal);
+        } else {
+            arg.extend_integer_width_to(32);
         }
     }
 }
index e9e9e266c77863ea61794edc516a30cb01e90e69..805c7d345a0e72d2de3a47209f325937e74d7c83 100644 (file)
@@ -400,6 +400,8 @@ fn x86_64_ty<F>(ccx: &CrateContext,
             } else {
                 arg.cast = Some(llreg_ty(ccx, &cls));
             }
+        } else {
+            arg.extend_integer_width_to(32);
         }
     }
 
index a5077f68fb58c22f4419909d260301c58e7e4ec2..71ecb6e9ca104593024e0b10a04be9874f9c6b73 100644 (file)
@@ -26,6 +26,8 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
                 8 => a.cast = Some(Type::i64(ccx)),
                 _ => a.make_indirect(ccx)
             }
+        } else {
+            a.extend_integer_width_to(32);
         }
     };
 
index 9bbc72eba36ef2ac0bfac561573b4d5c5bc8c582..c1802a5f0a9c2c3114ce887353dad818bd4968e3 100644 (file)
@@ -179,7 +179,7 @@ pub struct TraitSelectionCache<'tcx> {
 impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
     type Key = ty::PolyTraitRef<'tcx>;
     type Value = traits::Vtable<'tcx, ()>;
-    fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode {
+    fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode<DefId> {
         ty::tls::with(|tcx| {
             let lifted_key = tcx.lift(key).unwrap();
             lifted_key.to_poly_trait_predicate().dep_node()
index 822155f8c36a940028dd67c2a3ec1a6989053597..8471b6a274c266d5270fb8135a7c57c180d01054 100644 (file)
@@ -50,7 +50,9 @@
 use syntax::parse::token;
 
 
-const DW_LANG_RUST: c_uint = 0x9000;
+// From DWARF 5.
+// See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1
+const DW_LANG_RUST: c_uint = 0x1c;
 #[allow(non_upper_case_globals)]
 const DW_ATE_boolean: c_uint = 0x02;
 #[allow(non_upper_case_globals)]
@@ -324,7 +326,7 @@ fn from_def_id_and_substs<'a, 'tcx>(type_map: &mut TypeMap<'tcx>,
                                             output: &mut String) {
             // First, find out the 'real' def_id of the type. Items inlined from
             // other crates have to be mapped back to their source.
-            let source_def_id = if let Some(node_id) = cx.tcx().map.as_local_node_id(def_id) {
+            let def_id = if let Some(node_id) = cx.tcx().map.as_local_node_id(def_id) {
                 match cx.external_srcs().borrow().get(&node_id).cloned() {
                     Some(source_def_id) => {
                         // The given def_id identifies the inlined copy of a
@@ -337,19 +339,21 @@ fn from_def_id_and_substs<'a, 'tcx>(type_map: &mut TypeMap<'tcx>,
                 def_id
             };
 
-            // Get the crate hash as first part of the identifier.
-            let crate_hash = if source_def_id.is_local() {
-                cx.link_meta().crate_hash.clone()
+            // Get the crate name/disambiguator as first part of the identifier.
+            let crate_name = if def_id.is_local() {
+                cx.tcx().crate_name.clone()
             } else {
-                cx.sess().cstore.crate_hash(source_def_id.krate)
+                cx.sess().cstore.original_crate_name(def_id.krate)
             };
+            let crate_disambiguator = cx.tcx().crate_disambiguator(def_id.krate);
 
-            output.push_str(crate_hash.as_str());
+            output.push_str(&crate_name[..]);
             output.push_str("/");
+            output.push_str(&crate_disambiguator[..]);
+            output.push_str("/");
+            // Add the def-index as the second part
             output.push_str(&format!("{:x}", def_id.index.as_usize()));
 
-            // Maybe check that there is no self type here.
-
             let tps = substs.types.get_slice(subst::TypeSpace);
             if !tps.is_empty() {
                 output.push('<');
index 19a172e7f102b136c19fd5acf283399ba7230a7b..cb421b6be472b077a3be091b2d1030cb6a002f84 100644 (file)
@@ -46,6 +46,7 @@
 #[macro_use] extern crate rustc;
 extern crate rustc_back;
 extern crate rustc_data_structures;
+extern crate rustc_incremental;
 pub extern crate rustc_llvm as llvm;
 extern crate rustc_mir;
 extern crate rustc_platform_intrinsics as intrinsics;
@@ -85,7 +86,6 @@ pub mod back {
 mod abi;
 mod adt;
 mod asm;
-mod assert_dep_graph;
 mod attributes;
 mod base;
 mod basic_block;
index 9aa3d6c7dd08e764ce50f5057a6d12ff8fd595ce..f721e88a954139138cc03e3bb9a84950dfdad1db 100644 (file)
@@ -105,6 +105,9 @@ fn visit_lvalue(&mut self,
         match *lvalue {
             mir::Lvalue::Temp(index) => {
                 match context {
+                    LvalueContext::Call => {
+                        self.mark_assigned(index as usize);
+                    }
                     LvalueContext::Consume => {
                     }
                     LvalueContext::Store |
index 3fabdd8fd4226027e315c5078c8ac0e71c1d2d18..303cf61ad3379e81cf271a88e7caf5a804d2bc41 100644 (file)
 use llvm::{self, BasicBlockRef, ValueRef, OperandBundleDef};
 use rustc::ty;
 use rustc::mir::repr as mir;
-use abi::{Abi, FnType};
+use abi::{Abi, FnType, ArgType};
 use adt;
 use base;
 use build;
 use callee::{Callee, CalleeData, Fn, Intrinsic, NamedTupleConstructor, Virtual};
-use common::{self, Block, BlockAndBuilder, C_undef};
+use common::{self, type_is_fat_ptr, Block, BlockAndBuilder, C_undef};
 use debuginfo::DebugLoc;
 use Disr;
 use machine::{llalign_of_min, llbitsize_of_real};
@@ -25,7 +25,7 @@
 use glue;
 use type_::Type;
 
-use super::{MirContext, drop};
+use super::{MirContext, TempRef, drop};
 use super::lvalue::{LvalueRef, load_fat_ptr};
 use super::operand::OperandRef;
 use super::operand::OperandValue::{self, FatPtr, Immediate, Ref};
@@ -169,6 +169,8 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                     _ => bug!("{} is not callable", callee.ty)
                 };
 
+                let sig = bcx.tcx().erase_late_bound_regions(sig);
+
                 // Handle intrinsics old trans wants Expr's for, ourselves.
                 let intrinsic = match (&callee.ty.sty, &callee.data) {
                     (&ty::TyFnDef(def_id, _, _), &Intrinsic) => {
@@ -191,31 +193,16 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
 
                 if intrinsic == Some("transmute") {
                     let &(ref dest, target) = destination.as_ref().unwrap();
-                    let dst = self.trans_lvalue(&bcx, dest);
-                    let mut val = self.trans_operand(&bcx, &args[0]);
-                    if let ty::TyFnDef(def_id, substs, _) = val.ty.sty {
-                        let llouttype = type_of::type_of(bcx.ccx(), dst.ty.to_ty(bcx.tcx()));
-                        let out_type_size = llbitsize_of_real(bcx.ccx(), llouttype);
-                        if out_type_size != 0 {
-                            // FIXME #19925 Remove this hack after a release cycle.
-                            let f = Callee::def(bcx.ccx(), def_id, substs);
-                            let datum = f.reify(bcx.ccx());
-                            val = OperandRef {
-                                val: OperandValue::Immediate(datum.val),
-                                ty: datum.ty
-                            };
-                        }
-                    }
+                    self.with_lvalue_ref(&bcx, dest, |this, dest| {
+                        this.trans_transmute(&bcx, &args[0], dest);
+                    });
 
-                    let llty = type_of::type_of(bcx.ccx(), val.ty);
-                    let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to());
-                    self.store_operand(&bcx, cast_ptr, val);
                     self.set_operand_dropped(&bcx, &args[0]);
                     funclet_br(bcx, self.llblock(target));
                     return;
                 }
 
-                let extra_args = &args[sig.0.inputs.len()..];
+                let extra_args = &args[sig.inputs.len()..];
                 let extra_args = extra_args.iter().map(|op_arg| {
                     self.mir.operand_ty(bcx.tcx(), op_arg)
                 }).collect::<Vec<_>>();
@@ -226,18 +213,15 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                 let mut llargs = Vec::with_capacity(arg_count);
 
                 // Prepare the return value destination
-                let ret_dest = if let Some((ref d, _)) = *destination {
-                    let dest = self.trans_lvalue(&bcx, d);
-                    if fn_ty.ret.is_indirect() {
-                        llargs.push(dest.llval);
-                        None
-                    } else if fn_ty.ret.is_ignore() {
-                        None
+                let ret_dest = if let Some((ref dest, _)) = *destination {
+                    let is_intrinsic = if let Intrinsic = callee.data {
+                        true
                     } else {
-                        Some(dest)
-                    }
+                        false
+                    };
+                    self.make_return_dest(&bcx, dest, &fn_ty.ret, &mut llargs, is_intrinsic)
                 } else {
-                    None
+                    ReturnDest::Nothing
                 };
 
                 // Split the rust-call tupled arguments off.
@@ -269,29 +253,42 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                         use expr::{Ignore, SaveIn};
                         use intrinsic::trans_intrinsic_call;
 
-                        let (dest, llargs) = if fn_ty.ret.is_indirect() {
-                            (SaveIn(llargs[0]), &llargs[1..])
-                        } else if let Some(dest) = ret_dest {
-                            (SaveIn(dest.llval), &llargs[..])
-                        } else {
-                            (Ignore, &llargs[..])
+                        let (dest, llargs) = match ret_dest {
+                            _ if fn_ty.ret.is_indirect() => {
+                                (SaveIn(llargs[0]), &llargs[1..])
+                            }
+                            ReturnDest::Nothing => (Ignore, &llargs[..]),
+                            ReturnDest::IndirectOperand(dst, _) |
+                            ReturnDest::Store(dst) => (SaveIn(dst), &llargs[..]),
+                            ReturnDest::DirectOperand(_) =>
+                                bug!("Cannot use direct operand with an intrinsic call")
                         };
 
                         bcx.with_block(|bcx| {
-                            let res = trans_intrinsic_call(bcx, callee.ty, &fn_ty,
+                            trans_intrinsic_call(bcx, callee.ty, &fn_ty,
                                                            ArgVals(llargs), dest,
                                                            DebugLoc::None);
-                            let bcx = res.bcx.build();
-                            if let Some((_, target)) = *destination {
-                                for op in args {
-                                    self.set_operand_dropped(&bcx, op);
-                                }
-                                funclet_br(bcx, self.llblock(target));
-                            } else {
-                                // trans_intrinsic_call already used Unreachable.
-                                // bcx.unreachable();
-                            }
                         });
+
+                        if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
+                            // Make a fake operand for store_return
+                            let op = OperandRef {
+                                val: OperandValue::Ref(dst),
+                                ty: sig.output.unwrap()
+                            };
+                            self.store_return(&bcx, ret_dest, fn_ty.ret, op);
+                        }
+
+                        if let Some((_, target)) = *destination {
+                            for op in args {
+                                self.set_operand_dropped(&bcx, op);
+                            }
+                            funclet_br(bcx, self.llblock(target));
+                        } else {
+                            // trans_intrinsic_call already used Unreachable.
+                            // bcx.unreachable();
+                        }
+
                         return;
                     }
                     Fn(f) => f,
@@ -321,9 +318,11 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                     if destination.is_some() {
                         let ret_bcx = ret_bcx.build();
                         ret_bcx.at_start(|ret_bcx| {
-                            if let Some(ret_dest) = ret_dest {
-                                fn_ty.ret.store(&ret_bcx, invokeret, ret_dest.llval);
-                            }
+                            let op = OperandRef {
+                                val: OperandValue::Immediate(invokeret),
+                                ty: sig.output.unwrap()
+                            };
+                            self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op);
                             for op in args {
                                 self.set_operand_dropped(&ret_bcx, op);
                             }
@@ -333,9 +332,11 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                     let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle.as_ref());
                     fn_ty.apply_attrs_callsite(llret);
                     if let Some((_, target)) = *destination {
-                        if let Some(ret_dest) = ret_dest {
-                            fn_ty.ret.store(&bcx, llret, ret_dest.llval);
-                        }
+                        let op = OperandRef {
+                            val: OperandValue::Immediate(llret),
+                            ty: sig.output.unwrap()
+                        };
+                        self.store_return(&bcx, ret_dest, fn_ty.ret, op);
                         for op in args {
                             self.set_operand_dropped(&bcx, op);
                         }
@@ -544,4 +545,122 @@ fn bcx(&self, bb: mir::BasicBlock) -> BlockAndBuilder<'bcx, 'tcx> {
     pub fn llblock(&self, bb: mir::BasicBlock) -> BasicBlockRef {
         self.blocks[bb.index()].llbb
     }
+
+    fn make_return_dest(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                        dest: &mir::Lvalue<'tcx>, fn_ret_ty: &ArgType,
+                        llargs: &mut Vec<ValueRef>, is_intrinsic: bool) -> ReturnDest {
+        // If the return is ignored, we can just return a do-nothing ReturnDest
+        if fn_ret_ty.is_ignore() {
+            return ReturnDest::Nothing;
+        }
+        let dest = match *dest {
+            mir::Lvalue::Temp(idx) => {
+                let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), dest);
+                let lvalue_ty = bcx.monomorphize(&lvalue_ty);
+                let ret_ty = lvalue_ty.to_ty(bcx.tcx());
+                match self.temps[idx as usize] {
+                    TempRef::Lvalue(dest) => dest,
+                    TempRef::Operand(None) => {
+                        // Handle temporary lvalues, specifically Operand ones, as
+                        // they don't have allocas
+                        return if fn_ret_ty.is_indirect() {
+                            // Odd, but possible, case, we have an operand temporary,
+                            // but the calling convention has an indirect return.
+                            let tmp = bcx.with_block(|bcx| {
+                                base::alloc_ty(bcx, ret_ty, "tmp_ret")
+                            });
+                            llargs.push(tmp);
+                            ReturnDest::IndirectOperand(tmp, idx)
+                        } else if is_intrinsic {
+                            // Currently, intrinsics always need a location to store
+                            // the result. so we create a temporary alloca for the
+                            // result
+                            let tmp = bcx.with_block(|bcx| {
+                                base::alloc_ty(bcx, ret_ty, "tmp_ret")
+                            });
+                            ReturnDest::IndirectOperand(tmp, idx)
+                        } else {
+                            ReturnDest::DirectOperand(idx)
+                        };
+                    }
+                    TempRef::Operand(Some(_)) => {
+                        bug!("lvalue temp already assigned to");
+                    }
+                }
+            }
+            _ => self.trans_lvalue(bcx, dest)
+        };
+        if fn_ret_ty.is_indirect() {
+            llargs.push(dest.llval);
+            ReturnDest::Nothing
+        } else {
+            ReturnDest::Store(dest.llval)
+        }
+    }
+
+    fn trans_transmute(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                       src: &mir::Operand<'tcx>, dst: LvalueRef<'tcx>) {
+        let mut val = self.trans_operand(bcx, src);
+        if let ty::TyFnDef(def_id, substs, _) = val.ty.sty {
+            let llouttype = type_of::type_of(bcx.ccx(), dst.ty.to_ty(bcx.tcx()));
+            let out_type_size = llbitsize_of_real(bcx.ccx(), llouttype);
+            if out_type_size != 0 {
+                // FIXME #19925 Remove this hack after a release cycle.
+                let f = Callee::def(bcx.ccx(), def_id, substs);
+                let datum = f.reify(bcx.ccx());
+                val = OperandRef {
+                    val: OperandValue::Immediate(datum.val),
+                    ty: datum.ty
+                };
+            }
+        }
+
+        let llty = type_of::type_of(bcx.ccx(), val.ty);
+        let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to());
+        self.store_operand(bcx, cast_ptr, val);
+    }
+
+    // Stores the return value of a function call into it's final location.
+    fn store_return(&mut self,
+                    bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                    dest: ReturnDest,
+                    ret_ty: ArgType,
+                    op: OperandRef<'tcx>) {
+        use self::ReturnDest::*;
+
+        match dest {
+            Nothing => (),
+            Store(dst) => ret_ty.store(bcx, op.immediate(), dst),
+            IndirectOperand(tmp, idx) => {
+                let op = self.trans_load(bcx, tmp, op.ty);
+                self.temps[idx as usize] = TempRef::Operand(Some(op));
+            }
+            DirectOperand(idx) => {
+                let op = if type_is_fat_ptr(bcx.tcx(), op.ty) {
+                    let llval = op.immediate();
+                    let ptr = bcx.extract_value(llval, 0);
+                    let meta = bcx.extract_value(llval, 1);
+
+                    OperandRef {
+                        val: OperandValue::FatPtr(ptr, meta),
+                        ty: op.ty
+                    }
+                } else {
+                    op
+                };
+                self.temps[idx as usize] = TempRef::Operand(Some(op));
+            }
+        }
+    }
+}
+
+enum ReturnDest {
+    // Do nothing, the return value is indirect or ignored
+    Nothing,
+    // Store the return value to the pointer
+    Store(ValueRef),
+    // Stores an indirect return value to an operand temporary lvalue
+    IndirectOperand(ValueRef, u32),
+    // Stores a direct return value to an operand temporary lvalue
+    DirectOperand(u32)
 }
index c9087181f9ddcea7d0b3db273dae8adaa64264a6..695806aa82cee0393800de13b20280994c143c44 100644 (file)
@@ -207,6 +207,40 @@ pub fn trans_lvalue(&mut self,
         }
     }
 
+    // Perform an action using the given Lvalue.
+    // If the Lvalue is an empty TempRef::Operand, then a temporary stack slot
+    // is created first, then used as an operand to update the Lvalue.
+    pub fn with_lvalue_ref<F, U>(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                                 lvalue: &mir::Lvalue<'tcx>, f: F) -> U
+    where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U
+    {
+        match *lvalue {
+            mir::Lvalue::Temp(idx) => {
+                match self.temps[idx as usize] {
+                    TempRef::Lvalue(lvalue) => f(self, lvalue),
+                    TempRef::Operand(None) => {
+                        let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), lvalue);
+                        let lvalue_ty = bcx.monomorphize(&lvalue_ty);
+                        let lvalue = LvalueRef::alloca(bcx,
+                                                       lvalue_ty.to_ty(bcx.tcx()),
+                                                       "lvalue_temp");
+                        let ret = f(self, lvalue);
+                        let op = self.trans_load(bcx, lvalue.llval, lvalue_ty.to_ty(bcx.tcx()));
+                        self.temps[idx as usize] = TempRef::Operand(Some(op));
+                        ret
+                    }
+                    TempRef::Operand(Some(_)) => {
+                        bug!("Lvalue temp already set");
+                    }
+                }
+            }
+            _ => {
+                let lvalue = self.trans_lvalue(bcx, lvalue);
+                f(self, lvalue)
+            }
+        }
+    }
+
     /// Adjust the bitwidth of an index since LLVM is less forgiving
     /// than we are.
     ///
index 500eda2624ce7cb712b66e50d5d63cbf5897a9c9..1f0a18ad4faa2d28bb6077a2836f327ac08d2f96 100644 (file)
@@ -182,7 +182,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
 
     debug!("type_of {:?}", t);
 
-    assert!(!t.has_escaping_regions());
+    assert!(!t.has_escaping_regions(), "{:?} has escaping regions", t);
 
     // Replace any typedef'd types with their equivalent non-typedef
     // type. This ensures that all LLVM nominal types that contain
index 45877d7099bbf70de70ed88ecbb0b4c3bc973ddb..67b91f7838c6644616ab0de8f66c96f3b9bd8a5f 100644 (file)
@@ -2578,24 +2578,33 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 ty::TyFloat(ast::FloatTy::F32) => {
                     fcx.type_error_message(arg.span,
                                            |t| {
-                        format!("can't pass an {} to variadic \
-                                 function, cast to c_double", t)
+                        format!("can't pass an `{}` to variadic \
+                                 function, cast to `c_double`", t)
                     }, arg_ty, None);
                 }
                 ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => {
                     fcx.type_error_message(arg.span, |t| {
-                        format!("can't pass {} to variadic \
-                                 function, cast to c_int",
+                        format!("can't pass `{}` to variadic \
+                                 function, cast to `c_int`",
                                        t)
                     }, arg_ty, None);
                 }
                 ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => {
                     fcx.type_error_message(arg.span, |t| {
-                        format!("can't pass {} to variadic \
-                                 function, cast to c_uint",
+                        format!("can't pass `{}` to variadic \
+                                 function, cast to `c_uint`",
                                        t)
                     }, arg_ty, None);
                 }
+                ty::TyFnDef(_, _, f) => {
+                    let ptr_ty = fcx.tcx().mk_ty(ty::TyFnPtr(f));
+                    let ptr_ty = fcx.infcx().resolve_type_vars_if_possible(&ptr_ty);
+                    fcx.type_error_message(arg.span,
+                                           |t| {
+                        format!("can't pass `{}` to variadic \
+                                 function, cast to `{}`", t, ptr_ty)
+                    }, arg_ty, None);
+                }
                 _ => {}
             }
         }
index 4a4bcd96ad06c0fb58dd0ea79bf58d9f9e32b5c4..1cfbfb37d34bd3fb2131429eb165717d26159fc9 100644 (file)
@@ -3644,6 +3644,68 @@ fn main() {
 ```
 "##,
 
+E0520: r##"
+A non-default implementation was already made on this type so it cannot be
+specialized further. Erroneous code example:
+
+```compile_fail
+#![feature(specialization)]
+
+trait SpaceLlama {
+    fn fly(&self);
+}
+
+// applies to all T
+impl<T> SpaceLlama for T {
+    default fn fly(&self) {}
+}
+
+// non-default impl
+// applies to all `Clone` T and overrides the previous impl
+impl<T: Clone> SpaceLlama for T {
+    fn fly(&self) {}
+}
+
+// since `i32` is clone, this conflicts with the previous implementation
+impl SpaceLlama for i32 {
+    default fn fly(&self) {}
+    // error: item `fly` is provided by an `impl` that specializes
+    //        another, but the item in the parent `impl` is not marked
+    //        `default` and so it cannot be specialized.
+}
+```
+
+Specialization only allows you to override `default` functions in
+implementations.
+
+To fix this error, you need to mark all the parent implementations as default.
+Example:
+
+```
+#![feature(specialization)]
+
+trait SpaceLlama {
+    fn fly(&self);
+}
+
+// applies to all T
+impl<T> SpaceLlama for T {
+    default fn fly(&self) {} // This is a parent implementation.
+}
+
+// applies to all `Clone` T; overrides the previous impl
+impl<T: Clone> SpaceLlama for T {
+    default fn fly(&self) {} // This is a parent implementation but was
+                             // previously not a default one, causing the error
+}
+
+// applies to i32, overrides the previous two impls
+impl SpaceLlama for i32 {
+    fn fly(&self) {} // And now that's ok!
+}
+```
+"##,
+
 }
 
 register_diagnostics! {
@@ -3720,6 +3782,5 @@ fn main() {
            // type `{}` was overridden
     E0436, // functional record update requires a struct
     E0513, // no type for local variable ..
-    E0520, // cannot specialize non-default item
     E0521  // redundant default implementations of trait
 }
index 4d8021138a0d5f62e8ff7b8299cca69a9480cc78..863cada5b88090f09a9eb434c37b93add48ca19d 100644 (file)
@@ -29,8 +29,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use core::char::CharExt as C;
-use core::option::Option::{self, Some, None};
-use core::iter::Iterator;
+use core::fmt;
 use tables::{derived_property, property, general_category, conversions};
 
 // stable reexports
@@ -739,7 +738,7 @@ pub fn to_uppercase(self) -> ToUppercase {
 }
 
 /// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s.
-#[unstable(feature = "decode_utf16", reason = "recently exposed", issue = "27830")]
+#[stable(feature = "decode_utf16", since = "1.9.0")]
 #[derive(Clone)]
 pub struct DecodeUtf16<I>
     where I: Iterator<Item = u16>
@@ -748,6 +747,13 @@ pub struct DecodeUtf16<I>
     buf: Option<u16>,
 }
 
+/// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s.
+#[stable(feature = "decode_utf16", since = "1.9.0")]
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct DecodeUtf16Error {
+    code: u16,
+}
+
 /// Create an iterator over the UTF-16 encoded code points in `iter`,
 /// returning unpaired surrogates as `Err`s.
 ///
@@ -756,8 +762,6 @@ pub struct DecodeUtf16<I>
 /// Basic usage:
 ///
 /// ```
-/// #![feature(decode_utf16)]
-///
 /// use std::char::decode_utf16;
 ///
 /// fn main() {
@@ -766,7 +770,9 @@ pub struct DecodeUtf16<I>
 ///              0x0073, 0xDD1E, 0x0069, 0x0063,
 ///              0xD834];
 ///
-///     assert_eq!(decode_utf16(v.iter().cloned()).collect::<Vec<_>>(),
+///     assert_eq!(decode_utf16(v.iter().cloned())
+///                            .map(|r| r.map_err(|e| e.unpaired_surrogate()))
+///                            .collect::<Vec<_>>(),
 ///                vec![Ok('𝄞'),
 ///                     Ok('m'), Ok('u'), Ok('s'),
 ///                     Err(0xDD1E),
@@ -778,8 +784,6 @@ pub struct DecodeUtf16<I>
 /// A lossy decoder can be obtained by replacing `Err` results with the replacement character:
 ///
 /// ```
-/// #![feature(decode_utf16)]
-///
 /// use std::char::{decode_utf16, REPLACEMENT_CHARACTER};
 ///
 /// fn main() {
@@ -794,7 +798,7 @@ pub struct DecodeUtf16<I>
 ///                "𝄞mus�ic�");
 /// }
 /// ```
-#[unstable(feature = "decode_utf16", reason = "recently exposed", issue = "27830")]
+#[stable(feature = "decode_utf16", since = "1.9.0")]
 #[inline]
 pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> {
     DecodeUtf16 {
@@ -803,11 +807,11 @@ pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::Into
     }
 }
 
-#[unstable(feature = "decode_utf16", reason = "recently exposed", issue = "27830")]
+#[stable(feature = "decode_utf16", since = "1.9.0")]
 impl<I: Iterator<Item=u16>> Iterator for DecodeUtf16<I> {
-    type Item = Result<char, u16>;
+    type Item = Result<char, DecodeUtf16Error>;
 
-    fn next(&mut self) -> Option<Result<char, u16>> {
+    fn next(&mut self) -> Option<Result<char, DecodeUtf16Error>> {
         let u = match self.buf.take() {
             Some(buf) => buf,
             None => match self.iter.next() {
@@ -821,18 +825,18 @@ fn next(&mut self) -> Option<Result<char, u16>> {
             Some(Ok(unsafe { from_u32_unchecked(u as u32) }))
         } else if u >= 0xDC00 {
             // a trailing surrogate
-            Some(Err(u))
+            Some(Err(DecodeUtf16Error { code: u }))
         } else {
             let u2 = match self.iter.next() {
                 Some(u2) => u2,
                 // eof
-                None => return Some(Err(u)),
+                None => return Some(Err(DecodeUtf16Error { code: u })),
             };
             if u2 < 0xDC00 || u2 > 0xDFFF {
                 // not a trailing surrogate so we're not a valid
                 // surrogate pair, so rewind to redecode u2 next time.
                 self.buf = Some(u2);
-                return Some(Err(u));
+                return Some(Err(DecodeUtf16Error { code: u }));
             }
 
             // all ok, so lets decode it.
@@ -850,8 +854,25 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
-/// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a decoding error.
+impl DecodeUtf16Error {
+    /// Returns the unpaired surrogate which caused this error.
+    #[stable(feature = "decode_utf16", since = "1.9.0")]
+    pub fn unpaired_surrogate(&self) -> u16 {
+        self.code
+    }
+}
+
+#[stable(feature = "decode_utf16", since = "1.9.0")]
+impl fmt::Display for DecodeUtf16Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "unpaired surrogate found: {:x}", self.code)
+    }
+}
+
+/// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a
+/// decoding error.
+///
 /// It can occur, for example, when giving ill-formed UTF-8 bytes to
 /// [`String::from_utf8_lossy`](../../std/string/struct.String.html#method.from_utf8_lossy).
-#[unstable(feature = "decode_utf16", reason = "recently added", issue = "27830")]
+#[stable(feature = "decode_utf16", since = "1.9.0")]
 pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}';
index 673aa17ecd1455b89c4ae2f2851ef26727447e9a..d8d1472560d825211b71bbe2d5fcd9983651f552 100644 (file)
 use visit_ast;
 use html::item_type::ItemType;
 
-/// A stable identifier to the particular version of JSON output.
-/// Increment this when the `Crate` and related structures change.
-pub const SCHEMA_VERSION: &'static str = "0.8.3";
-
 mod inline;
 mod simplify;
 
index 9953fd4b5d8aabc4c289a9a417e9516e9ebeefed..bc7c7c5e0caf06d80ce8e6d6bd8e175b5cb6bdb0 100644 (file)
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(libc)]
-#![feature(recover)]
 #![feature(rustc_private)]
 #![feature(set_stdio)]
 #![feature(slice_patterns)]
 #![feature(staged_api)]
-#![feature(std_panic)]
 #![feature(test)]
 #![feature(unicode)]
 #![feature(question_mark)]
 use std::collections::HashMap;
 use std::default::Default;
 use std::env;
-use std::fs::File;
-use std::io::{self, Read, Write};
+use std::io::Read;
 use std::path::PathBuf;
 use std::process;
 use std::rc::Rc;
 use std::sync::mpsc::channel;
 
 use externalfiles::ExternalHtml;
-use serialize::Decodable;
-use serialize::json::{self, Json};
 use rustc::session::search_paths::SearchPaths;
 use rustc::session::config::{ErrorOutputType, RustcOptGroup, nightly_options};
 
-// reexported from `clean` so it can be easily updated with the mod itself
-pub use clean::SCHEMA_VERSION;
-
 #[macro_use]
 pub mod externalfiles;
 
@@ -127,7 +119,6 @@ pub mod html {
 
 struct Output {
     krate: clean::Crate,
-    json_plugins: Vec<plugins::PluginJson>,
     passes: Vec<String>,
 }
 
@@ -150,9 +141,9 @@ pub fn opts() -> Vec<RustcOptGroup> {
         stable(optflag("V", "version", "print rustdoc's version")),
         stable(optflag("v", "verbose", "use verbose output")),
         stable(optopt("r", "input-format", "the input type of the specified file",
-                      "[rust|json]")),
+                      "[rust]")),
         stable(optopt("w", "output-format", "the output type to write",
-                      "[html|json]")),
+                      "[html]")),
         stable(optopt("o", "output", "where to place the output", "PATH")),
         stable(optopt("", "crate-name", "specify the name of this crate", "NAME")),
         stable(optmulti("L", "library-path", "directory to add to crate search path",
@@ -311,7 +302,7 @@ pub fn main_args(args: &[String]) -> isize {
             return 1;
         }
     };
-    let Output { krate, json_plugins, passes, } = out;
+    let Output { krate, passes, } = out;
     info!("going to format");
     match matches.opt_str("w").as_ref().map(|s| &**s) {
         Some("html") | None => {
@@ -321,11 +312,6 @@ pub fn main_args(args: &[String]) -> isize {
                               css_file_extension)
                 .expect("failed to generate documentation")
         }
-        Some("json") => {
-            json_output(krate, json_plugins,
-                        output.unwrap_or(PathBuf::from("doc.json")))
-                .expect("failed to write json")
-        }
         Some(s) => {
             println!("unknown output format: {}", s);
             return 1;
@@ -342,14 +328,9 @@ fn acquire_input(input: &str,
                  matches: &getopts::Matches) -> Result<Output, String> {
     match matches.opt_str("r").as_ref().map(|s| &**s) {
         Some("rust") => Ok(rust_input(input, externs, matches)),
-        Some("json") => json_input(input),
         Some(s) => Err(format!("unknown input format: {}", s)),
         None => {
-            if input.ends_with(".json") {
-                json_input(input)
-            } else {
-                Ok(rust_input(input, externs, matches))
-            }
+            Ok(rust_input(input, externs, matches))
         }
     }
 }
@@ -461,76 +442,6 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche
 
     // Run everything!
     info!("Executing passes/plugins");
-    let (krate, json) = pm.run_plugins(krate);
-    Output { krate: krate, json_plugins: json, passes: passes }
-}
-
-/// This input format purely deserializes the json output file. No passes are
-/// run over the deserialized output.
-fn json_input(input: &str) -> Result<Output, String> {
-    let mut bytes = Vec::new();
-    if let Err(e) = File::open(input).and_then(|mut f| f.read_to_end(&mut bytes)) {
-        return Err(format!("couldn't open {}: {}", input, e))
-    }
-    match json::from_reader(&mut &bytes[..]) {
-        Err(s) => Err(format!("{:?}", s)),
-        Ok(Json::Object(obj)) => {
-            let mut obj = obj;
-            // Make sure the schema is what we expect
-            match obj.remove(&"schema".to_string()) {
-                Some(Json::String(version)) => {
-                    if version != SCHEMA_VERSION {
-                        return Err(format!(
-                                "sorry, but I only understand version {}",
-                                SCHEMA_VERSION))
-                    }
-                }
-                Some(..) => return Err("malformed json".to_string()),
-                None => return Err("expected a schema version".to_string()),
-            }
-            let krate = match obj.remove(&"crate".to_string()) {
-                Some(json) => {
-                    let mut d = json::Decoder::new(json);
-                    Decodable::decode(&mut d).unwrap()
-                }
-                None => return Err("malformed json".to_string()),
-            };
-            // FIXME: this should read from the "plugins" field, but currently
-            //      Json doesn't implement decodable...
-            let plugin_output = Vec::new();
-            Ok(Output { krate: krate, json_plugins: plugin_output, passes: Vec::new(), })
-        }
-        Ok(..) => {
-            Err("malformed json input: expected an object at the \
-                 top".to_string())
-        }
-    }
-}
-
-/// Outputs the crate/plugin json as a giant json blob at the specified
-/// destination.
-fn json_output(krate: clean::Crate, res: Vec<plugins::PluginJson> ,
-               dst: PathBuf) -> io::Result<()> {
-    // {
-    //   "schema": version,
-    //   "crate": { parsed crate ... },
-    //   "plugins": { output of plugins ... }
-    // }
-    let mut json = std::collections::BTreeMap::new();
-    json.insert("schema".to_string(), Json::String(SCHEMA_VERSION.to_string()));
-    let plugins_json = res.into_iter()
-                          .filter_map(|opt| {
-                              opt.map(|(string, json)| (string.to_string(), json))
-                          }).collect();
-
-    // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode
-    // straight to the Rust JSON representation.
-    let crate_json_str = format!("{}", json::as_json(&krate));
-    let crate_json = json::from_str(&crate_json_str).expect("Rust generated JSON is invalid");
-
-    json.insert("crate".to_string(), crate_json);
-    json.insert("plugins".to_string(), Json::Object(plugins_json));
-
-    let mut file = File::create(&dst)?;
-    write!(&mut file, "{}", Json::Object(json))
+    let krate = pm.run_plugins(krate);
+    Output { krate: krate, passes: passes }
 }
index ff2a9f13e8a1287d39425c78d169d9700aebf89f..adc39b69986d62fe230e4332b17ee31fed62cf3f 100644 (file)
@@ -54,7 +54,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
     };
 
     // strip any traits implemented on stripped items
-    let krate = {
+    {
         struct ImplStripper<'a> {
             stripped: &'a mut DefIdSet
         }
@@ -80,9 +80,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
         }
         let mut stripper = ImplStripper{ stripped: &mut stripped };
         stripper.fold_crate(krate)
-    };
-
-    (krate, None)
+    }
 }
 
 /// Strip private items from the point of view of a crate or externally from a
@@ -107,9 +105,8 @@ pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
     // strip all private implementations of traits
     {
         let mut stripper = ImplStripper(&retained);
-        krate = stripper.fold_crate(krate);
+        stripper.fold_crate(krate)
     }
-    (krate, None)
 }
 
 struct Stripper<'a> {
@@ -192,17 +189,19 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             self.fold_item_recur(i)
         };
 
-        i.and_then(|i| { match i.inner {
-            // emptied modules/impls have no need to exist
-            clean::ModuleItem(ref m)
-                if m.items.is_empty() &&
-                   i.doc_value().is_none() => None,
-            clean::ImplItem(ref i) if i.items.is_empty() => None,
-            _ => {
-                self.retained.insert(i.def_id);
-                Some(i)
+        i.and_then(|i| {
+            match i.inner {
+                // emptied modules/impls have no need to exist
+                clean::ModuleItem(ref m)
+                    if m.items.is_empty() &&
+                       i.doc_value().is_none() => None,
+                clean::ImplItem(ref i) if i.items.is_empty() => None,
+                _ => {
+                    self.retained.insert(i.def_id);
+                    Some(i)
+                }
             }
-        }})
+        })
     }
 }
 
@@ -234,7 +233,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
 }
 
 pub fn strip_priv_imports(krate: clean::Crate)  -> plugins::PluginResult {
-    (ImportStripper.fold_crate(krate), None)
+    ImportStripper.fold_crate(krate)
 }
 
 pub fn unindent_comments(krate: clean::Crate) -> plugins::PluginResult {
@@ -258,7 +257,7 @@ fn fold_item(&mut self, mut i: Item) -> Option<Item> {
     }
     let mut cleaner = CommentCleaner;
     let krate = cleaner.fold_crate(krate);
-    (krate, None)
+    krate
 }
 
 pub fn collapse_docs(krate: clean::Crate) -> plugins::PluginResult {
@@ -287,7 +286,7 @@ fn fold_item(&mut self, mut i: Item) -> Option<Item> {
     }
     let mut collapser = Collapser;
     let krate = collapser.fold_crate(krate);
-    (krate, None)
+    krate
 }
 
 pub fn unindent(s: &str) -> String {
index 83ce3e61ab281af14801bbc6afaa9757794813c7..b8be84825c9ccf88e29c43a2edfbee73deb650f4 100644 (file)
 
 use clean;
 
-use serialize::json;
 use std::mem;
 use std::string::String;
 use std::path::PathBuf;
 
 use rustc_back::dynamic_lib as dl;
 
-pub type PluginJson = Option<(String, json::Json)>;
-pub type PluginResult = (clean::Crate, PluginJson);
+pub type PluginResult = clean::Crate;
 pub type PluginCallback = fn (clean::Crate) -> PluginResult;
 
 /// Manages loading and running of plugins
@@ -65,15 +63,11 @@ pub fn add_plugin(&mut self, plugin: PluginCallback) {
         self.callbacks.push(plugin);
     }
     /// Run all the loaded plugins over the crate, returning their results
-    pub fn run_plugins(&self, krate: clean::Crate) -> (clean::Crate, Vec<PluginJson> ) {
-        let mut out_json = Vec::new();
-        let mut krate = krate;
+    pub fn run_plugins(&self, mut krate: clean::Crate) -> clean::Crate {
         for &callback in &self.callbacks {
-            let (c, res) = callback(krate);
-            krate = c;
-            out_json.push(res);
+            krate = callback(krate);
         }
-        (krate, out_json)
+        krate
     }
 }
 
index 3810fb87acf6a9dac20599551f9fb7a1f4e401c9..982f477fc4ae1c0c5429551048c989711e9da4ec 100644 (file)
@@ -15,7 +15,7 @@
 use std::io::prelude::*;
 use std::io;
 use std::path::PathBuf;
-use std::panic::{self, AssertRecoverSafe};
+use std::panic::{self, AssertUnwindSafe};
 use std::process::Command;
 use std::rc::Rc;
 use std::str;
@@ -122,8 +122,8 @@ pub fn run(input: &str,
     if let Some(name) = crate_name {
         krate.name = name;
     }
-    let (krate, _) = passes::collapse_docs(krate);
-    let (krate, _) = passes::unindent_comments(krate);
+    let krate = passes::collapse_docs(krate);
+    let krate = passes::unindent_comments(krate);
 
     let mut collector = Collector::new(krate.name.to_string(),
                                        cfgs,
@@ -256,18 +256,13 @@ fn drop(&mut self) {
         control.after_analysis.stop = Compilation::Stop;
     }
 
-    match {
-        let b_sess = AssertRecoverSafe(&sess);
-        let b_cstore = AssertRecoverSafe(&cstore);
-        let b_cfg = AssertRecoverSafe(cfg.clone());
-        let b_control = AssertRecoverSafe(&control);
-
-        panic::recover(|| {
-            driver::compile_input(&b_sess, &b_cstore, (*b_cfg).clone(),
-                                  &input, &out,
-                                  &None, None, &b_control)
-        })
-    } {
+    let res = panic::catch_unwind(AssertUnwindSafe(|| {
+        driver::compile_input(&sess, &cstore, cfg.clone(),
+                              &input, &out,
+                              &None, None, &control)
+    }));
+
+    match res {
         Ok(r) => {
             match r {
                 Err(count) if count > 0 && compile_fail == false => {
index 609ebe8546164d1872790a48c32a6bb0a8e0107c..31b71dbc80b62c2bd3ce75f5e78778d6b0567590 100644 (file)
@@ -132,7 +132,10 @@ fn from_hex(&self) -> Result<Vec<u8>, FromHexError> {
                     buf >>= 4;
                     continue
                 }
-                _ => return Err(InvalidHexCharacter(self.char_at(idx), idx)),
+                _ => {
+                    let ch = self[idx..].chars().next().unwrap();
+                    return Err(InvalidHexCharacter(ch, idx))
+                }
             }
 
             modulus += 1;
index 173ecca648c4141376a058f8c368f780a095ed57..80cd47c85ccdfd64e5b5764a12b9d4aaa11f3e04 100644 (file)
@@ -32,7 +32,6 @@
 #![feature(enumset)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(str_char)]
 #![feature(unicode)]
 #![feature(question_mark)]
 #![cfg_attr(test, feature(test))]
index 3ae3cf8504ea4b3f57c0ac58fcdb331dbe8608e4..0db91034eb5ac8eed231b5d28b9c3f4f9bc06347 100644 (file)
@@ -128,8 +128,6 @@ pub trait AsciiExt {
     /// # Examples
     ///
     /// ```
-    /// #![feature(ascii)]
-    ///
     /// use std::ascii::AsciiExt;
     ///
     /// let mut ascii = 'a';
@@ -138,7 +136,7 @@ pub trait AsciiExt {
     ///
     /// assert_eq!('A', ascii);
     /// ```
-    #[unstable(feature = "ascii", issue = "27809")]
+    #[stable(feature = "ascii", since = "1.9.0")]
     fn make_ascii_uppercase(&mut self);
 
     /// Converts this type to its ASCII lower case equivalent in-place.
@@ -148,8 +146,6 @@ pub trait AsciiExt {
     /// # Examples
     ///
     /// ```
-    /// #![feature(ascii)]
-    ///
     /// use std::ascii::AsciiExt;
     ///
     /// let mut ascii = 'A';
@@ -158,7 +154,7 @@ pub trait AsciiExt {
     ///
     /// assert_eq!('a', ascii);
     /// ```
-    #[unstable(feature = "ascii", issue = "27809")]
+    #[stable(feature = "ascii", since = "1.9.0")]
     fn make_ascii_lowercase(&mut self);
 }
 
index 234042ab011bc6a5cb30b8005a2b0d28ba8821c2..c20270e830665d4ee0eb36d3bef5b9352f62166d 100644 (file)
@@ -620,8 +620,7 @@ pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S)
     }
 
     /// Returns a reference to the map's hasher.
-    #[unstable(feature = "hashmap_public_hasher", reason = "don't want to make insta-stable",
-               issue = "31262")]
+    #[stable(feature = "hashmap_public_hasher", since = "1.9.0")]
     pub fn hasher(&self) -> &S {
         &self.hash_builder
     }
index 954adf313be0db086de984ac1f8797ff1e2ff90f..b353a4c1ba120ca6521e0bf8cf6133336c911af1 100644 (file)
@@ -194,8 +194,7 @@ pub fn with_capacity_and_hasher(capacity: usize, hasher: S)
     }
 
     /// Returns a reference to the set's hasher.
-    #[unstable(feature = "hashmap_public_hasher", reason = "don't want to make insta-stable",
-               issue = "31262")]
+    #[stable(feature = "hashmap_public_hasher", since = "1.9.0")]
     pub fn hasher(&self) -> &S {
         self.map.hasher()
     }
@@ -459,7 +458,7 @@ pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool
     /// The value may be any borrowed form of the set's value type, but
     /// `Hash` and `Eq` on the borrowed form *must* match those for
     /// the value type.
-    #[unstable(feature = "set_recovery", issue = "28050")]
+    #[stable(feature = "set_recovery", since = "1.9.0")]
     pub fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T>
         where T: Borrow<Q>, Q: Hash + Eq
     {
@@ -556,7 +555,7 @@ pub fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()).is_none(
 
     /// Adds a value to the set, replacing the existing value, if any, that is equal to the given
     /// one. Returns the replaced value.
-    #[unstable(feature = "set_recovery", issue = "28050")]
+    #[stable(feature = "set_recovery", since = "1.9.0")]
     pub fn replace(&mut self, value: T) -> Option<T> {
         Recover::replace(&mut self.map, value)
     }
@@ -591,7 +590,7 @@ pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool
     /// The value may be any borrowed form of the set's value type, but
     /// `Hash` and `Eq` on the borrowed form *must* match those for
     /// the value type.
-    #[unstable(feature = "set_recovery", issue = "28050")]
+    #[stable(feature = "set_recovery", since = "1.9.0")]
     pub fn take<Q: ?Sized>(&mut self, value: &Q) -> Option<T>
         where T: Borrow<Q>, Q: Hash + Eq
     {
index 660948b0accac4c38808906cacf071d4ca6c1b7d..35cd4a5ec5292076fef8fc29d4d8dd2f5883199f 100644 (file)
 
 use any::TypeId;
 use boxed::Box;
-use convert::From;
+use char;
 use fmt::{self, Debug, Display};
 use marker::{Send, Sync, Reflect};
 use mem::transmute;
 use num;
-use option::Option::{self, Some, None};
-use result::Result::{self, Ok, Err};
 use raw::TraitObject;
 use str;
 use string::{self, String};
@@ -189,6 +187,13 @@ fn description(&self) -> &str {
     }
 }
 
+#[stable(feature = "decode_utf16", since = "1.9.0")]
+impl Error for char::DecodeUtf16Error {
+    fn description(&self) -> &str {
+        "unpaired surrogate found"
+    }
+}
+
 #[stable(feature = "box_error", since = "1.7.0")]
 impl<T: Error> Error for Box<T> {
     fn description(&self) -> &str {
index de840457a01f471c31e30d665818d204b5bd1204..0d29e62485abb8035fa3c7a404174790cc6d61c9 100644 (file)
@@ -86,13 +86,14 @@ pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
         self.inner.push_slice(&s.as_ref().inner)
     }
 
-    /// Creates a new `OsString` with the given capacity. The string will be
-    /// able to hold exactly `capacity` bytes without reallocating. If
-    /// `capacity` is 0, the string will not allocate.
+    /// Creates a new `OsString` with the given capacity.
+    ///
+    /// The string will be able to hold exactly `capacity` lenth units of other
+    /// OS strings without reallocating. If `capacity` is 0, the string will not
+    /// allocate.
     ///
     /// See main `OsString` documentation information about encoding.
-    #[unstable(feature = "osstring_simple_functions",
-               reason = "recently added", issue = "29453")]
+    #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
     pub fn with_capacity(capacity: usize) -> OsString {
         OsString {
             inner: Buf::with_capacity(capacity)
@@ -100,40 +101,36 @@ pub fn with_capacity(capacity: usize) -> OsString {
     }
 
     /// Truncates the `OsString` to zero length.
-    #[unstable(feature = "osstring_simple_functions",
-               reason = "recently added", issue = "29453")]
+    #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
     pub fn clear(&mut self) {
         self.inner.clear()
     }
 
-    /// Returns the number of bytes this `OsString` can hold without
-    /// reallocating.
+    /// Returns the capacity this `OsString` can hold without reallocating.
     ///
     /// See `OsString` introduction for information about encoding.
-    #[unstable(feature = "osstring_simple_functions",
-               reason = "recently added", issue = "29453")]
+    #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
     pub fn capacity(&self) -> usize {
         self.inner.capacity()
     }
 
-    /// Reserves capacity for at least `additional` more bytes to be inserted
-    /// in the given `OsString`. The collection may reserve more space to avoid
-    /// frequent reallocations.
-    #[unstable(feature = "osstring_simple_functions",
-               reason = "recently added", issue = "29453")]
+    /// Reserves capacity for at least `additional` more capacity to be inserted
+    /// in the given `OsString`.
+    ///
+    /// The collection may reserve more space to avoid frequent reallocations.
+    #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
     pub fn reserve(&mut self, additional: usize) {
         self.inner.reserve(additional)
     }
 
-    /// Reserves the minimum capacity for exactly `additional` more bytes to be
-    /// inserted in the given `OsString`. Does nothing if the capacity is
+    /// Reserves the minimum capacity for exactly `additional` more capacity to
+    /// be inserted in the given `OsString`. Does nothing if the capacity is
     /// already sufficient.
     ///
     /// Note that the allocator may give the collection more space than it
     /// requests. Therefore capacity can not be relied upon to be precisely
     /// minimal. Prefer reserve if future insertions are expected.
-    #[unstable(feature = "osstring_simple_functions",
-               reason = "recently added", issue = "29453")]
+    #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
     pub fn reserve_exact(&mut self, additional: usize) {
         self.inner.reserve_exact(additional)
     }
@@ -286,17 +283,20 @@ pub fn to_os_string(&self) -> OsString {
     }
 
     /// Checks whether the `OsStr` is empty.
-    #[unstable(feature = "osstring_simple_functions",
-               reason = "recently added", issue = "29453")]
+    #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
     pub fn is_empty(&self) -> bool {
         self.inner.inner.is_empty()
     }
 
-    /// Returns the number of bytes in this `OsStr`.
+    /// Returns the length of this `OsStr`.
+    ///
+    /// Note that this does **not** return the number of bytes in this string
+    /// as, for example, OS strings on Windows are encoded as a list of `u16`
+    /// rather than a list of bytes. This number is simply useful for passing to
+    /// other methods like `OsString::with_capacity` to avoid reallocations.
     ///
-    /// See `OsStr` introduction for information about encoding.
-    #[unstable(feature = "osstring_simple_functions",
-               reason = "recently added", issue = "29453")]
+    /// See `OsStr` introduction for more information about encoding.
+    #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
     pub fn len(&self) -> usize {
         self.inner.inner.len()
     }
index c4d6cb33365d0f90038ce642f916f25b997d024e..f5a51e974272754541ac5813ed6c0ecec3cad521 100644 (file)
@@ -302,7 +302,7 @@ pub fn metadata(&self) -> io::Result<Metadata> {
     /// The returned `File` is a reference to the same state that this object
     /// references. Both handles will read and write with the same cursor
     /// position.
-    #[unstable(feature = "file_try_clone", reason = "newly added", issue = "31405")]
+    #[stable(feature = "file_try_clone", since = "1.9.0")]
     pub fn try_clone(&self) -> io::Result<File> {
         Ok(File {
             inner: self.inner.duplicate()?
@@ -523,16 +523,13 @@ pub fn create(&mut self, create: bool) -> &mut OpenOptions {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(expand_open_options)]
     /// use std::fs::OpenOptions;
     ///
     /// let file = OpenOptions::new().write(true)
     ///                              .create_new(true)
     ///                              .open("foo.txt");
     /// ```
-    #[unstable(feature = "expand_open_options",
-               reason = "recently added",
-               issue = "30014")]
+    #[stable(feature = "expand_open_options2", since = "1.9.0")]
     pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
         self.0.create_new(create_new); self
     }
index 0f988c7623e389432660afba4846c46881bfd57c..6dd7273c17fe7b614cebcc67cc4cac7c68e0468f 100644 (file)
 mod util;
 mod stdio;
 
-const DEFAULT_BUF_SIZE: usize = 64 * 1024;
+const DEFAULT_BUF_SIZE: usize = 8 * 1024;
 
 // A few methods below (read_to_string, read_line) will append data into a
 // `String` buffer, but we need to be pretty careful when doing this. The
@@ -1596,7 +1596,7 @@ fn next(&mut self) -> Option<result::Result<char, CharsError>> {
             }
         }
         Some(match str::from_utf8(&buf[..width]).ok() {
-            Some(s) => Ok(s.char_at(0)),
+            Some(s) => Ok(s.chars().next().unwrap()),
             None => Err(CharsError::NotUtf8),
         })
     }
index 8dcac51417224795178f43ed77147bf182fdb4c8..e14a31453d381601f4ccf4e860f8fc4c95bcadef 100644 (file)
 #![feature(collections)]
 #![feature(collections_bound)]
 #![feature(const_fn)]
-#![feature(copy_from_slice)]
 #![feature(core_float)]
 #![feature(core_intrinsics)]
-#![feature(decode_utf16)]
 #![feature(dropck_parametricity)]
 #![feature(float_extras)]
 #![feature(float_from_str_radix)]
index a915872d8ac94166df960dfd05ab5ef51cb3d934..d510339f1c5b492d29941a9cbfe10bc7e4e926d5 100644 (file)
@@ -68,7 +68,7 @@ pub fn ip(&self) -> IpAddr {
     }
 
     /// Change the IP address associated with this socket address.
-    #[unstable(feature = "sockaddr_setters", reason = "recent addition", issue = "31572")]
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     pub fn set_ip(&mut self, new_ip: IpAddr) {
         // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
         match (self, new_ip) {
@@ -88,7 +88,7 @@ pub fn port(&self) -> u16 {
     }
 
     /// Change the port number associated with this socket address.
-    #[unstable(feature = "sockaddr_setters", reason = "recent addition", issue = "31572")]
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     pub fn set_port(&mut self, new_port: u16) {
         match *self {
             SocketAddr::V4(ref mut a) => a.set_port(new_port),
@@ -120,16 +120,22 @@ pub fn ip(&self) -> &Ipv4Addr {
     }
 
     /// Change the IP address associated with this socket address.
-    #[unstable(feature = "sockaddr_setters", reason = "recent addition", issue = "31572")]
-    pub fn set_ip(&mut self, new_ip: Ipv4Addr) { self.inner.sin_addr = *new_ip.as_inner() }
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
+        self.inner.sin_addr = *new_ip.as_inner()
+    }
 
     /// Returns the port number associated with this socket address.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn port(&self) -> u16 { ntoh(self.inner.sin_port) }
+    pub fn port(&self) -> u16 {
+        ntoh(self.inner.sin_port)
+    }
 
     /// Change the port number associated with this socket address.
-    #[unstable(feature = "sockaddr_setters", reason = "recent addition", issue = "31572")]
-    pub fn set_port(&mut self, new_port: u16) { self.inner.sin_port = hton(new_port) }
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_port(&mut self, new_port: u16) {
+        self.inner.sin_port = hton(new_port);
+    }
 }
 
 impl SocketAddrV6 {
@@ -159,24 +165,32 @@ pub fn ip(&self) -> &Ipv6Addr {
     }
 
     /// Change the IP address associated with this socket address.
-    #[unstable(feature = "sockaddr_setters", reason = "recent addition", issue = "31572")]
-    pub fn set_ip(&mut self, new_ip: Ipv6Addr) { self.inner.sin6_addr = *new_ip.as_inner() }
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
+        self.inner.sin6_addr = *new_ip.as_inner()
+    }
 
     /// Returns the port number associated with this socket address.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn port(&self) -> u16 { ntoh(self.inner.sin6_port) }
+    pub fn port(&self) -> u16 {
+        ntoh(self.inner.sin6_port)
+    }
 
     /// Change the port number associated with this socket address.
-    #[unstable(feature = "sockaddr_setters", reason = "recent addition", issue = "31572")]
-    pub fn set_port(&mut self, new_port: u16) { self.inner.sin6_port = hton(new_port) }
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_port(&mut self, new_port: u16) {
+        self.inner.sin6_port = hton(new_port);
+    }
 
     /// Returns the flow information associated with this address,
     /// corresponding to the `sin6_flowinfo` field in C.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn flowinfo(&self) -> u32 { self.inner.sin6_flowinfo }
+    pub fn flowinfo(&self) -> u32 {
+        self.inner.sin6_flowinfo
+    }
 
     /// Change the flow information associated with this socket address.
-    #[unstable(feature = "sockaddr_setters", reason = "recent addition", issue = "31572")]
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
         self.inner.sin6_flowinfo = new_flowinfo;
     }
@@ -184,10 +198,12 @@ pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
     /// Returns the scope ID associated with this address,
     /// corresponding to the `sin6_scope_id` field in C.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn scope_id(&self) -> u32 { self.inner.sin6_scope_id }
+    pub fn scope_id(&self) -> u32 {
+        self.inner.sin6_scope_id
+    }
 
     /// Change the scope ID associated with this socket address.
-    #[unstable(feature = "sockaddr_setters", reason = "recent addition", issue = "31572")]
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     pub fn set_scope_id(&mut self, new_scope_id: u32) {
         self.inner.sin6_scope_id = new_scope_id;
     }
index eb09800a18cb04a4a79872a19952f8e9a5149f09..db672e5643531181fb59b0759274cc81d74c7e50 100644 (file)
@@ -63,10 +63,6 @@ pub trait MetadataExt {
     #[stable(feature = "metadata_ext2", since = "1.8.0")]
     fn st_ctime_nsec(&self) -> i64;
     #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_birthtime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_birthtime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
     fn st_blksize(&self) -> u64;
     #[stable(feature = "metadata_ext2", since = "1.8.0")]
     fn st_blocks(&self) -> u64;
@@ -129,12 +125,6 @@ fn st_ctime(&self) -> i64 {
     fn st_ctime_nsec(&self) -> i64 {
         self.as_inner().as_inner().st_ctime_nsec as i64
     }
-    fn st_birthtime(&self) -> i64 {
-        self.as_inner().as_inner().st_birthtime as i64
-    }
-    fn st_birthtime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_birthtime_nsec as i64
-    }
     fn st_blksize(&self) -> u64 {
         self.as_inner().as_inner().st_blksize as u64
     }
index 4462ce24dce048d268c2c966b9e153d6e20bde54..16401c4527f160b15dab692c8872aeff10018ccf 100644 (file)
@@ -10,8 +10,7 @@
 
 //! Panic support in the standard library
 
-#![unstable(feature = "std_panic", reason = "awaiting feedback",
-            issue = "27719")]
+#![stable(feature = "std_panic", since = "1.9.0")]
 
 use any::Any;
 use boxed::Box;
@@ -23,6 +22,7 @@
 use sys_common::unwind;
 use thread::Result;
 
+#[unstable(feature = "panic_handler", issue = "30449")]
 pub use panicking::{take_hook, set_hook, PanicInfo, Location};
 
 ///
@@ -92,7 +92,7 @@ pub fn take_handler() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
 /// "speed bump" to alert users of `recover` that broken invariants may be
 /// witnessed and may need to be accounted for.
 ///
-/// ## Who implements `RecoverSafe`?
+/// ## Who implements `UnwindSafe`?
 ///
 /// Types such as `&mut T` and `&RefCell<T>` are examples which are **not**
 /// recover safe. The general idea is that any mutable state which can be shared
@@ -104,7 +104,7 @@ pub fn take_handler() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
 /// poisoning by default. They still allow witnessing a broken invariant, but
 /// they already provide their own "speed bumps" to do so.
 ///
-/// ## When should `RecoverSafe` be used?
+/// ## When should `UnwindSafe` be used?
 ///
 /// Is not intended that most types or functions need to worry about this trait.
 /// It is only used as a bound on the `recover` function and as mentioned above,
@@ -112,10 +112,18 @@ pub fn take_handler() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
 /// wrapper struct in this module can be used to force this trait to be
 /// implemented for any closed over variables passed to the `recover` function
 /// (more on this below).
-#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
+#[stable(feature = "catch_unwind", since = "1.9.0")]
 #[rustc_on_unimplemented = "the type {Self} may not be safely transferred \
                             across a recover boundary"]
+pub trait UnwindSafe {}
+
+/// Deprecated, renamed to UnwindSafe
+#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
+#[rustc_deprecated(reason = "renamed to `UnwindSafe`", since = "1.9.0")]
 pub trait RecoverSafe {}
+#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
+#[allow(deprecated)]
+impl<T: UnwindSafe> RecoverSafe for T {}
 
 /// A marker trait representing types where a shared reference is considered
 /// recover safe.
@@ -124,12 +132,12 @@ pub trait RecoverSafe {}
 /// interior mutability.
 ///
 /// This is a "helper marker trait" used to provide impl blocks for the
-/// `RecoverSafe` trait, for more information see that documentation.
-#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
+/// `UnwindSafe` trait, for more information see that documentation.
+#[stable(feature = "catch_unwind", since = "1.9.0")]
 #[rustc_on_unimplemented = "the type {Self} contains interior mutability \
                             and a reference may not be safely transferrable \
                             across a recover boundary"]
-pub trait RefRecoverSafe {}
+pub trait RefUnwindSafe {}
 
 /// A simple wrapper around a type to assert that it is panic safe.
 ///
@@ -143,90 +151,141 @@ pub trait RefRecoverSafe {}
 ///
 /// # Examples
 ///
-/// One way to use `AssertRecoverSafe` is to assert that the entire closure
+/// One way to use `AssertUnwindSafe` is to assert that the entire closure
 /// itself is recover safe, bypassing all checks for all variables:
 ///
 /// ```
-/// #![feature(recover, std_panic)]
-///
-/// use std::panic::{self, AssertRecoverSafe};
+/// use std::panic::{self, AssertUnwindSafe};
 ///
 /// let mut variable = 4;
 ///
 /// // This code will not compile because the closure captures `&mut variable`
 /// // which is not considered panic safe by default.
 ///
-/// // panic::recover(|| {
+/// // panic::catch_unwind(|| {
 /// //     variable += 3;
 /// // });
 ///
-/// // This, however, will compile due to the `AssertRecoverSafe` wrapper
-/// let result = panic::recover(AssertRecoverSafe(|| {
+/// // This, however, will compile due to the `AssertUnwindSafe` wrapper
+/// let result = panic::catch_unwind(AssertUnwindSafe(|| {
 ///     variable += 3;
 /// }));
 /// // ...
 /// ```
 ///
 /// Wrapping the entire closure amounts to a blanket assertion that all captured
-/// variables are recover safe. This has the downside that if new captures are
-/// added in the future, they will also be considered recover safe. Therefore,
+/// variables are unwind safe. This has the downside that if new captures are
+/// added in the future, they will also be considered unwind safe. Therefore,
 /// you may prefer to just wrap individual captures, as shown below. This is
 /// more annotation, but it ensures that if a new capture is added which is not
-/// recover safe, you will get a compilation error at that time, which will
+/// unwind safe, you will get a compilation error at that time, which will
 /// allow you to consider whether that new capture in fact represent a bug or
 /// not.
 ///
 /// ```
-/// #![feature(recover, std_panic)]
-///
-/// use std::panic::{self, AssertRecoverSafe};
+/// use std::panic::{self, AssertUnwindSafe};
 ///
 /// let mut variable = 4;
 /// let other_capture = 3;
 ///
 /// let result = {
-///     let mut wrapper = AssertRecoverSafe(&mut variable);
-///     panic::recover(move || {
+///     let mut wrapper = AssertUnwindSafe(&mut variable);
+///     panic::catch_unwind(move || {
 ///         **wrapper += other_capture;
 ///     })
 /// };
 /// // ...
 /// ```
-#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+pub struct AssertUnwindSafe<T>(
+    #[stable(feature = "catch_unwind", since = "1.9.0")]
+    pub T
+);
+
+/// Deprecated, renamed to `AssertUnwindSafe`
+#[unstable(feature = "recover", issue = "27719")]
+#[rustc_deprecated(reason = "renamed to `AssertUnwindSafe`", since = "1.9.0")]
 pub struct AssertRecoverSafe<T>(pub T);
 
-// Implementations of the `RecoverSafe` trait:
+// Implementations of the `UnwindSafe` trait:
 //
-// * By default everything is recover safe
-// * pointers T contains mutability of some form are not recover safe
+// * By default everything is unwind safe
+// * pointers T contains mutability of some form are not unwind safe
 // * Unique, an owning pointer, lifts an implementation
-// * Types like Mutex/RwLock which are explicilty poisoned are recover safe
-// * Our custom AssertRecoverSafe wrapper is indeed recover safe
-impl RecoverSafe for .. {}
-impl<'a, T: ?Sized> !RecoverSafe for &'a mut T {}
-impl<'a, T: RefRecoverSafe + ?Sized> RecoverSafe for &'a T {}
-impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *const T {}
-impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *mut T {}
-impl<T: RecoverSafe> RecoverSafe for Unique<T> {}
-impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Shared<T> {}
-impl<T: ?Sized> RecoverSafe for Mutex<T> {}
-impl<T: ?Sized> RecoverSafe for RwLock<T> {}
-impl<T> RecoverSafe for AssertRecoverSafe<T> {}
+// * Types like Mutex/RwLock which are explicilty poisoned are unwind safe
+// * Our custom AssertUnwindSafe wrapper is indeed unwind safe
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl UnwindSafe for .. {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<'a, T: ?Sized> !UnwindSafe for &'a mut T {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<'a, T: RefUnwindSafe + ?Sized> UnwindSafe for &'a T {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: UnwindSafe> UnwindSafe for Unique<T> {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Shared<T> {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: ?Sized> UnwindSafe for Mutex<T> {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: ?Sized> UnwindSafe for RwLock<T> {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T> UnwindSafe for AssertUnwindSafe<T> {}
+#[unstable(feature = "recover", issue = "27719")]
+#[allow(deprecated)]
+impl<T> UnwindSafe for AssertRecoverSafe<T> {}
 
 // not covered via the Shared impl above b/c the inner contents use
 // Cell/AtomicUsize, but the usage here is recover safe so we can lift the
 // impl up one level to Arc/Rc itself
-impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Rc<T> {}
-impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Arc<T> {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Rc<T> {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Arc<T> {}
 
 // Pretty simple implementations for the `RefRecoverSafe` marker trait,
 // basically just saying that this is a marker trait and `UnsafeCell` is the
 // only thing which doesn't implement it (which then transitively applies to
 // everything else).
-impl RefRecoverSafe for .. {}
-impl<T: ?Sized> !RefRecoverSafe for UnsafeCell<T> {}
-impl<T> RefRecoverSafe for AssertRecoverSafe<T> {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl RefUnwindSafe for .. {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: ?Sized> !RefUnwindSafe for UnsafeCell<T> {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T> RefUnwindSafe for AssertUnwindSafe<T> {}
+#[unstable(feature = "recover", issue = "27719")]
+#[allow(deprecated)]
+impl<T> RefUnwindSafe for AssertRecoverSafe<T> {}
+
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T> Deref for AssertUnwindSafe<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &self.0
+    }
+}
+
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T> DerefMut for AssertUnwindSafe<T> {
+    fn deref_mut(&mut self) -> &mut T {
+        &mut self.0
+    }
+}
 
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<R, F: FnOnce() -> R> FnOnce<()> for AssertUnwindSafe<F> {
+    type Output = R;
+
+    extern "rust-call" fn call_once(self, _args: ()) -> R {
+        (self.0)()
+    }
+}
+
+#[allow(deprecated)]
 impl<T> AssertRecoverSafe<T> {
     /// Creates a new `AssertRecoverSafe` wrapper around the provided type.
     #[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
@@ -245,6 +304,8 @@ pub fn into_inner(self) -> T {
     }
 }
 
+#[unstable(feature = "recover", issue = "27719")]
+#[allow(deprecated)]
 impl<T> Deref for AssertRecoverSafe<T> {
     type Target = T;
 
@@ -253,12 +314,16 @@ fn deref(&self) -> &T {
     }
 }
 
+#[unstable(feature = "recover", issue = "27719")]
+#[allow(deprecated)]
 impl<T> DerefMut for AssertRecoverSafe<T> {
     fn deref_mut(&mut self) -> &mut T {
         &mut self.0
     }
 }
 
+#[unstable(feature = "recover", issue = "27719")]
+#[allow(deprecated)]
 impl<R, F: FnOnce() -> R> FnOnce<()> for AssertRecoverSafe<F> {
     type Output = R;
 
@@ -267,7 +332,7 @@ extern "rust-call" fn call_once(self, _args: ()) -> R {
     }
 }
 
-/// Invokes a closure, capturing the cause of panic if one occurs.
+/// Invokes a closure, capturing the cause of an unwinding panic if one occurs.
 ///
 /// This function will return `Ok` with the closure's result if the closure
 /// does not panic, and will return `Err(cause)` if the closure panics. The
@@ -280,38 +345,44 @@ extern "rust-call" fn call_once(self, _args: ()) -> R {
 ///
 /// It is **not** recommended to use this function for a general try/catch
 /// mechanism. The `Result` type is more appropriate to use for functions that
-/// can fail on a regular basis.
-///
-/// The closure provided is required to adhere to the `RecoverSafe` to ensure
-/// that all captured variables are safe to cross this recover boundary. The
-/// purpose of this bound is to encode the concept of [exception safety][rfc] in
-/// the type system. Most usage of this function should not need to worry about
-/// this bound as programs are naturally panic safe without `unsafe` code. If it
-/// becomes a problem the associated `AssertRecoverSafe` wrapper type in this
+/// can fail on a regular basis. Additionally, this function is not guaranteed
+/// to catch all panics, see the "Notes" sectino below.
+///
+/// The closure provided is required to adhere to the `UnwindSafe` to ensure
+/// that all captured variables are safe to cross this boundary. The purpose of
+/// this bound is to encode the concept of [exception safety][rfc] in the type
+/// system. Most usage of this function should not need to worry about this
+/// bound as programs are naturally panic safe without `unsafe` code. If it
+/// becomes a problem the associated `AssertUnwindSafe` wrapper type in this
 /// module can be used to quickly assert that the usage here is indeed exception
 /// safe.
 ///
 /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
 ///
+/// # Notes
+///
+/// Note that this function **may not catch all panics** in Rust. A panic in
+/// Rust is not always implemented via unwinding, but can be implemented by
+/// aborting the process as well. This function *only* catches unwinding panics,
+/// not those that abort the process.
+///
 /// # Examples
 ///
 /// ```
-/// #![feature(recover, std_panic)]
-///
 /// use std::panic;
 ///
-/// let result = panic::recover(|| {
+/// let result = panic::catch_unwind(|| {
 ///     println!("hello!");
 /// });
 /// assert!(result.is_ok());
 ///
-/// let result = panic::recover(|| {
+/// let result = panic::catch_unwind(|| {
 ///     panic!("oh no!");
 /// });
 /// assert!(result.is_err());
 /// ```
-#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
-pub fn recover<F: FnOnce() -> R + RecoverSafe, R>(f: F) -> Result<R> {
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
     let mut result = None;
     unsafe {
         let result = &mut result;
@@ -320,27 +391,46 @@ pub fn recover<F: FnOnce() -> R + RecoverSafe, R>(f: F) -> Result<R> {
     Ok(result.unwrap())
 }
 
+/// Deprecated, renamed to `catch_unwind`
+#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
+#[rustc_deprecated(reason = "renamed to `catch_unwind`", since = "1.9.0")]
+pub fn recover<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
+    catch_unwind(f)
+}
+
 /// Triggers a panic without invoking the panic handler.
 ///
-/// This is designed to be used in conjunction with `recover` to, for example,
-/// carry a panic across a layer of C code.
+/// This is designed to be used in conjunction with `catch_unwind` to, for
+/// example, carry a panic across a layer of C code.
+///
+/// # Notes
+///
+/// Note that panics in Rust are not always implemented via unwinding, but they
+/// may be implemented by aborting the process. If this function is called when
+/// panics are implemented this way then this function will abort the process,
+/// not trigger an unwind.
 ///
 /// # Examples
 ///
 /// ```should_panic
-/// #![feature(std_panic, recover, panic_propagate)]
-///
 /// use std::panic;
 ///
-/// let result = panic::recover(|| {
+/// let result = panic::catch_unwind(|| {
 ///     panic!("oh no!");
 /// });
 ///
 /// if let Err(err) = result {
-///     panic::propagate(err);
+///     panic::resume_unwind(err);
 /// }
 /// ```
+#[stable(feature = "resume_unwind", since = "1.9.0")]
+pub fn resume_unwind(payload: Box<Any + Send>) -> ! {
+    unwind::rust_panic(payload)
+}
+
+/// Deprecated, use resume_unwind instead
 #[unstable(feature = "panic_propagate", reason = "awaiting feedback", issue = "30752")]
+#[rustc_deprecated(reason = "renamed to `resume_unwind`", since = "1.9.0")]
 pub fn propagate(payload: Box<Any + Send>) -> ! {
-    unwind::rust_panic(payload)
+    resume_unwind(payload)
 }
index 5309cc3c858f6536b9d15dd1378c46d2537c1fbe..f413bed86a8534d3c67844d380629ea49cf756bc 100644 (file)
@@ -466,7 +466,7 @@ enum State {
     Done = 3,
 }
 
-/// A Windows path prefix, e.g. `C:` or `\server\share`.
+/// A Windows path prefix, e.g. `C:` or `\\server\share`.
 ///
 /// Does not occur on Unix.
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -528,7 +528,7 @@ fn hash<H: Hasher>(&self, h: &mut H) {
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum Component<'a> {
-    /// A Windows path prefix, e.g. `C:` or `\server\share`.
+    /// A Windows path prefix, e.g. `C:` or `\\server\share`.
     ///
     /// Does not occur on Unix.
     #[stable(feature = "rust1", since = "1.0.0")]
index fcd827e2a8b722e9b4e18d17299d90cf12192ee0..83091c72c0d6bea2a2c4a0a990679effac0fd93e 100644 (file)
@@ -60,7 +60,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
         sys_common::args::init(argc, argv);
 
         // Let's run some code!
-        let res = panic::recover(mem::transmute::<_, fn()>(main));
+        let res = panic::catch_unwind(mem::transmute::<_, fn()>(main));
         sys_common::cleanup();
         res.is_err()
     };
index e673879d20db28c887149b8c48e5d1b222244359..e228d236a3ca716317dd709ecd79471c508dc971 100644 (file)
@@ -425,13 +425,13 @@ fn poison_bad() {
         static O: Once = Once::new();
 
         // poison the once
-        let t = panic::recover(|| {
+        let t = panic::catch_unwind(|| {
             O.call_once(|| panic!());
         });
         assert!(t.is_err());
 
         // poisoning propagates
-        let t = panic::recover(|| {
+        let t = panic::catch_unwind(|| {
             O.call_once(|| {});
         });
         assert!(t.is_err());
@@ -453,7 +453,7 @@ fn wait_for_force_to_finish() {
         static O: Once = Once::new();
 
         // poison the once
-        let t = panic::recover(|| {
+        let t = panic::catch_unwind(|| {
             O.call_once(|| panic!());
         });
         assert!(t.is_err());
index 24e1a82a593bad2d248a3da706e55a5fb07d50c8..6f185437e50af47b3d4b7966210fbaa636284e78 100644 (file)
@@ -131,7 +131,7 @@ pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> {
                 first = false;
             }
             let mut rest = inner;
-            while rest.char_at(0).is_numeric() {
+            while rest.chars().next().unwrap().is_numeric() {
                 rest = &rest[1..];
             }
             let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap();
index ff6a11951dc5e57f59615394758c2cdedd8fe5bc..da7a340af351525ac6a766722b9d921b7295d66d 100644 (file)
@@ -224,8 +224,13 @@ fn __gcc_personality_v0(state: uw::_Unwind_State,
         context: *mut uw::_Unwind_Context
     ) -> uw::_Unwind_Reason_Code
     {
+        // Backtraces on ARM will call the personality routine with
+        // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
+        // we want to continue unwinding the stack, otherwise all our backtraces
+        // would end at __rust_try.
         if (state as c_int & uw::_US_ACTION_MASK as c_int)
-                           == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // search phase
+                           == uw::_US_VIRTUAL_UNWIND_FRAME as c_int
+               && (state as c_int & uw::_US_FORCE_UNWIND as c_int) == 0 { // search phase
             uw::_URC_HANDLER_FOUND // catch!
         }
         else { // cleanup phase
index f64f835e198541e720f3b899cc8673cede7a3551..55e485e5811acc687dce80d57e2f43571489f3d3 100644 (file)
@@ -191,8 +191,11 @@ pub fn from_wide(v: &[u16]) -> Wtf8Buf {
             match item {
                 Ok(ch) => string.push_char(ch),
                 Err(surrogate) => {
+                    let surrogate = surrogate.unpaired_surrogate();
                     // Surrogates are known to be in the code point range.
-                    let code_point = unsafe { CodePoint::from_u32_unchecked(surrogate as u32) };
+                    let code_point = unsafe {
+                        CodePoint::from_u32_unchecked(surrogate as u32)
+                    };
                     // Skip the WTF-8 concatenation check,
                     // surrogate pairs are already decoded by decode_utf16
                     string.push_code_point_unchecked(code_point)
index 4d8f12c2d7c42f2bf0f3d2c38f2cb444d0a21bd3..1be3d75d866dd7123c663604a142fb9f8ffcfeed 100644 (file)
@@ -49,7 +49,9 @@ pub mod prelude {
     #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
     #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::fs::{DirEntryExt};
+    pub use super::fs::DirEntryExt;
+    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::thread::JoinHandleExt;
     #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::process::{CommandExt, ExitStatusExt};
 }
index 8cc291d00ee027cf4cca947a1db1b0a6829ed556..7f31cf9f3bf80690b7f01506e9bdf317b3b07b78 100644 (file)
@@ -45,6 +45,8 @@ pub trait CommandExt {
     /// (the daemon) in the same session.
     #[unstable(feature = "process_session_leader", reason = "recently added",
                issue = "27811")]
+    #[rustc_deprecated(reason = "use `before_exec` instead",
+                       since = "1.9.0")]
     fn session_leader(&mut self, on: bool) -> &mut process::Command;
 
     /// Schedules a closure to be run just before the `exec` function is
@@ -94,7 +96,7 @@ fn before_exec<F>(&mut self, f: F) -> &mut process::Command
     /// file descriptors may have changed. If a "transactional spawn" is
     /// required to gracefully handle errors it is recommended to use the
     /// cross-platform `spawn` instead.
-    #[unstable(feature = "process_exec", issue = "31398")]
+    #[stable(feature = "process_exec2", since = "1.9.0")]
     fn exec(&mut self) -> io::Error;
 }
 
index c98e42faba7c2591d22ab452dae488d383661ab3..fe2a48764dc3a99799373cf3f0878a8b61d6dca7 100644 (file)
@@ -8,37 +8,41 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Unix-specific extensions to primitives in the `std::process` module.
+//! Unix-specific extensions to primitives in the `std::thread` module.
 
-#![unstable(feature = "thread_extensions", issue = "29791")]
+#![stable(feature = "thread_extensions", since = "1.9.0")]
 
 #[allow(deprecated)]
 use os::unix::raw::pthread_t;
 use sys_common::{AsInner, IntoInner};
 use thread::JoinHandle;
 
-#[unstable(feature = "thread_extensions", issue = "29791")]
+#[stable(feature = "thread_extensions", since = "1.9.0")]
 #[allow(deprecated)]
 pub type RawPthread = pthread_t;
 
 /// Unix-specific extensions to `std::thread::JoinHandle`
-#[unstable(feature = "thread_extensions", issue = "29791")]
+#[stable(feature = "thread_extensions", since = "1.9.0")]
 pub trait JoinHandleExt {
     /// Extracts the raw pthread_t without taking ownership
+    #[stable(feature = "thread_extensions", since = "1.9.0")]
     fn as_pthread_t(&self) -> RawPthread;
+
     /// Consumes the thread, returning the raw pthread_t
     ///
     /// This function **transfers ownership** of the underlying pthread_t to
     /// the caller. Callers are then the unique owners of the pthread_t and
     /// must either detach or join the pthread_t once it's no longer needed.
+    #[stable(feature = "thread_extensions", since = "1.9.0")]
     fn into_pthread_t(self) -> RawPthread;
 }
 
-#[unstable(feature = "thread_extensions", issue = "29791")]
+#[stable(feature = "thread_extensions", since = "1.9.0")]
 impl<T> JoinHandleExt for JoinHandle<T> {
     fn as_pthread_t(&self) -> RawPthread {
         self.as_inner().id() as RawPthread
     }
+
     fn into_pthread_t(self) -> RawPthread {
         self.into_inner().into_id() as RawPthread
     }
index eed62c9ecfd1588080ec3ba125fe906cf280cfd7..94ebbd70ae83deb5c6194460c96aa613ee6997a2 100644 (file)
@@ -36,6 +36,7 @@
 static ENV_LOCK: StaticMutex = StaticMutex::new();
 
 /// Returns the platform-specific value of errno
+#[cfg(not(target_os = "dragonfly"))]
 pub fn errno() -> i32 {
     extern {
         #[cfg_attr(any(target_os = "linux", target_os = "emscripten"),
@@ -47,7 +48,6 @@ pub fn errno() -> i32 {
                        target_env = "newlib"),
                    link_name = "__errno")]
         #[cfg_attr(target_os = "solaris", link_name = "___errno")]
-        #[cfg_attr(target_os = "dragonfly", link_name = "__dfly_error")]
         #[cfg_attr(any(target_os = "macos",
                        target_os = "ios",
                        target_os = "freebsd"),
@@ -60,6 +60,16 @@ pub fn errno() -> i32 {
     }
 }
 
+#[cfg(target_os = "dragonfly")]
+pub fn errno() -> i32 {
+    extern {
+        #[thread_local]
+        static errno: c_int;
+    }
+
+    errno as i32
+}
+
 /// Gets a detailed string description for the given error number.
 pub fn error_string(errno: i32) -> String {
     extern {
index 1444cf31e853be87a1fe655e42f3cdf73f2540b3..cc7abe25e35e5a1edc902e6608996a8da7344172 100644 (file)
@@ -303,8 +303,13 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         }
     }
 
+    #[cfg(not(target_os = "dragonfly"))]
+    pub type clock_t = libc::c_int;
+    #[cfg(target_os = "dragonfly")]
+    pub type clock_t = libc::c_ulong;
+
     impl Timespec {
-        pub fn now(clock: libc::c_int) -> Timespec {
+        pub fn now(clock: clock_t) -> Timespec {
             let mut t = Timespec {
                 t: libc::timespec {
                     tv_sec: 0,
index 3a07204b2bcf80f43cd514ec6b35f3b50ffabe11..36b3a3d4bdec8570f839bf1a580276f1c16973b7 100644 (file)
 
 //! Extensions to `std::thread` for Windows.
 
-#![unstable(feature = "thread_extensions", issue = "29791")]
+#![stable(feature = "thread_extensions", since = "1.9.0")]
 
 use os::windows::io::{RawHandle, AsRawHandle, IntoRawHandle};
 use thread;
 use sys_common::{AsInner, IntoInner};
 
+#[stable(feature = "thread_extensions", since = "1.9.0")]
 impl<T> AsRawHandle for thread::JoinHandle<T> {
     fn as_raw_handle(&self) -> RawHandle {
         self.as_inner().handle().raw() as *mut _
     }
 }
 
+#[stable(feature = "thread_extensions", since = "1.9.0")]
 impl<T> IntoRawHandle for thread::JoinHandle<T>  {
     fn into_raw_handle(self) -> RawHandle {
         self.into_inner().into_handle().into_raw() as *mut _
index 5ade636a3271d8cd9858393e7e1e8df492bed03c..fc18ef407ab2f9e138f5bb435a793959bf959c47 100644 (file)
     ("naked_functions", "1.9.0", Some(32408), Active),
 
     // allow empty structs and enum variants with braces
-    ("braced_empty_structs", "1.5.0", Some(29720), Accepted),
+    ("braced_empty_structs", "1.8.0", Some(29720), Accepted),
 
     // allow overloading augmented assignment operations like `a += b`
-    ("augmented_assignments", "1.5.0", Some(28235), Accepted),
+    ("augmented_assignments", "1.8.0", Some(28235), Accepted),
 
     // allow `#[no_debug]`
     ("no_debug", "1.5.0", Some(29721), Active),
     ("stmt_expr_attributes", "1.6.0", Some(15701), Active),
 
     // Allows `#[deprecated]` attribute
-    ("deprecated", "1.6.0", Some(29935), Active),
+    ("deprecated", "1.9.0", Some(29935), Accepted),
 
     // allow using type ascription in expressions
     ("type_ascription", "1.6.0", Some(23416), Active),
@@ -356,6 +356,14 @@ enum Status {
                                        "the `#[rustc_if_this_changed]` attribute \
                                         is just used for rustc unit tests \
                                         and will never be stable")),
+    ("rustc_dirty", Whitelisted, Gated("rustc_attrs",
+                                       "the `#[rustc_dirty]` attribute \
+                                        is just used for rustc unit tests \
+                                        and will never be stable")),
+    ("rustc_clean", Whitelisted, Gated("rustc_attrs",
+                                       "the `#[rustc_clean]` attribute \
+                                        is just used for rustc unit tests \
+                                        and will never be stable")),
     ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs",
                                        "internal rustc attributes will never be stable")),
     ("rustc_item_path", Whitelisted, Gated("rustc_attrs",
@@ -427,7 +435,7 @@ enum Status {
     ("must_use", Whitelisted, Ungated),
     ("stable", Whitelisted, Ungated),
     ("unstable", Whitelisted, Ungated),
-    ("deprecated", Normal, Gated("deprecated", "`#[deprecated]` attribute is unstable")),
+    ("deprecated", Normal, Ungated),
 
     ("rustc_paren_sugar", Normal, Gated("unboxed_closures",
                                         "unboxed_closures are still evolving")),
index ab14e21e251cb00cfb30172e4e7cdaffb7ed32ea..ca7e5729c0b7a176dd83ac415e85e2acf08dd07a 100644 (file)
@@ -29,7 +29,6 @@
 #![feature(libc)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(str_char)]
 #![feature(str_escape)]
 #![feature(unicode)]
 #![feature(question_mark)]
index b8c926f8de9cb7b693025153067bc6d8a94ffc49..c4997348537f4222ffc188b83582742b2ad72f87 100644 (file)
@@ -2578,7 +2578,7 @@ fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: BytePos) -> PResult<
         loop {
             // expr?
             while self.eat(&token::Question) {
-                let hi = self.span.hi;
+                let hi = self.last_span.hi;
                 e = self.mk_expr(lo, hi, ExprKind::Try(e), None);
             }
 
index e2b1d2f5e7abeb85f9b3c7536e746a3ef1ad11e3..fcd83b4104130294b1f0a471e487287572031e25 100644 (file)
@@ -2209,12 +2209,14 @@ fn print_expr_outer_attr_style(&mut self,
 
                 self.commasep(Inconsistent, &a.outputs,
                                    |s, out| {
-                    match out.constraint.slice_shift_char() {
-                        Some(('=', operand)) if out.is_rw => {
-                            s.print_string(&format!("+{}", operand),
+                    let mut ch = out.constraint.chars();
+                    match ch.next() {
+                        Some('=') if out.is_rw => {
+                            s.print_string(&format!("+{}", ch.as_str()),
                                            ast::StrStyle::Cooked)?
                         }
-                        _ => s.print_string(&out.constraint, ast::StrStyle::Cooked)?
+                        _ => s.print_string(&out.constraint,
+                                            ast::StrStyle::Cooked)?
                     }
                     s.popen()?;
                     s.print_expr(&out.expr)?;
index b9ba1f107ad7aefa8867eb59e13d0d8a1111831f..50d2b9d31fe010b396ad1dff085d8307387bf455 100644 (file)
@@ -131,11 +131,12 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                     // It's the opposite of '=&' which means that the memory
                     // cannot be shared with any other operand (usually when
                     // a register is clobbered early.)
-                    let output = match constraint.slice_shift_char() {
-                        Some(('=', _)) => None,
-                        Some(('+', operand)) => {
+                    let mut ch = constraint.chars();
+                    let output = match ch.next() {
+                        Some('=') => None,
+                        Some('+') => {
                             Some(token::intern_and_get_ident(&format!(
-                                        "={}", operand)))
+                                        "={}", ch.as_str())))
                         }
                         _ => {
                             cx.span_err(span, "output operand constraint lacks '=' or '+'");
@@ -146,7 +147,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                     let is_rw = output.is_some();
                     let is_indirect = constraint.contains("*");
                     outputs.push(ast::InlineAsmOutput {
-                        constraint: output.unwrap_or(constraint),
+                        constraint: output.unwrap_or(constraint.clone()),
                         expr: out,
                         is_rw: is_rw,
                         is_indirect: is_indirect,
index f214ecdc3368dd4278ee4565b070b46c0bafb30c..8f5362b4d2895c270ca10440b0459d76b9793089 100644 (file)
@@ -21,7 +21,6 @@
 
 #![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(str_char)]
 
 extern crate fmt_macros;
 #[macro_use] extern crate log;
index 00bfa63e6fea8204714719ea3b318a580416eeab..d2ebdcca80cf0cb6b44a037b1b3c08fa7e1921b7 100644 (file)
@@ -243,3 +243,7 @@ double rust_interesting_average(uint64_t n, ...) {
     va_end(pairs);
     return sum / n;
 }
+
+int32_t rust_int8_to_int32(int8_t x) {
+    return (int32_t)x;
+}
index d1ecff5984ac5d76f83f8fb01aabe8edff31fd17..b56be9e5683a851a5576eb93152faf1eba7e0e91 100644 (file)
@@ -11,7 +11,7 @@
 // Test that when a trait impl changes, fns whose body uses that trait
 // must also be recompiled.
 
-// compile-flags: -Z incr-comp
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(warnings)]
index acd6091cbdd482c93319d7474ecaa14473dcfac5..0d6954ab9df6229e5390d647b1c0aabf62fc39c1 100644 (file)
@@ -11,7 +11,7 @@
 // Test that immediate callers have to change when callee changes, but
 // not callers' callers.
 
-// compile-flags: -Z incr-comp
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
index c16998cd33c644cfdc15d4eaef027359eb5ef2d7..235fc5051d780f78a50b91a8c06bfd8c063acbb8 100644 (file)
@@ -11,7 +11,7 @@
 // Test cases where a changing struct appears in the signature of fns
 // and methods.
 
-// compile-flags: -Z incr-comp
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
index 57e83586d8d37b79c5b32c87fb0c5081b21e8127..1afecd80ff5ad05309bc0b9c88b04cc43aff5c23 100644 (file)
@@ -11,7 +11,7 @@
 // Test that adding an impl to a trait `Foo` DOES affect functions
 // that only use `Bar` if they have methods in common.
 
-// compile-flags: -Z incr-comp
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
index ba54a056209454720f1012c6233b723140fb7ed7..2ec7573cb81dc133e32acfcbd7281fe53247d394 100644 (file)
@@ -11,7 +11,7 @@
 // Test that adding an impl to a trait `Foo` does not affect functions
 // that only use `Bar`, so long as they do not have methods in common.
 
-// compile-flags: -Z incr-comp
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(warnings)]
index b38fdad9809ed1cb4b57f80a9d6d88e8d163216b..d87d7a6be1c280f65018f3bbbecec38514bd6a8e 100644 (file)
@@ -11,7 +11,7 @@
 // Test that when a trait impl changes, fns whose body uses that trait
 // must also be recompiled.
 
-// compile-flags: -Z incr-comp
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(warnings)]
index 8feec12a2f76c975d9cb284db890445c65771870..079f2b52fd462a21c1107363fdca4636b34d6736 100644 (file)
@@ -10,7 +10,7 @@
 
 // Test that two unrelated functions have no trans dependency.
 
-// compile-flags: -Z incr-comp
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
index 4f4aed21f994d8383c109e69ebd305862528457f..8170c9fd8f161db0ebf4bceafd079d94576c804c 100644 (file)
@@ -10,7 +10,7 @@
 
 // #[deprecated] can't be used in staged api
 
-#![feature(deprecated, staged_api)]
+#![feature(staged_api)]
 
 #![stable(feature = "test_feature", since = "1.0.0")]
 
index 58fa00fb41086d2f09a621bbfb42047dcac29491..5fc8f684a66fe01f678fdc4cb3bde67a7f15a6f3 100644 (file)
@@ -10,8 +10,6 @@
 
 // aux-build:deprecation-lint.rs
 
-#![feature(deprecated)]
-
 #![deny(deprecated)]
 #![allow(warnings)]
 
index 6ee5cd2c7e3cf171887d12ce69db6bbc325c4266..af2ac79ea80721808bcc49e694f9ba8e6c9f52a0 100644 (file)
@@ -10,8 +10,6 @@
 
 // Various checks that deprecation attributes are used correctly
 
-#![feature(deprecated)]
-
 mod bogus_attribute_types_1 {
     #[deprecated(since = "a", note = "a", reason)] //~ ERROR unknown meta item 'reason'
     fn f1() { }
index 56a41a15ab3c0b63317895c62c3295fd3c884779..86aae47214804b28888f106310b8e8099354dd29 100644 (file)
@@ -30,5 +30,14 @@ fn f() {
     mod core {} // Check that private crates are not glob imported
 }
 
+mod bar {
+    pub extern crate core;
+}
+
+mod baz {
+    pub use bar::*;
+    use self::core::cell; // Check that public extern crates are glob imported
+}
+
 #[rustc_error]
 fn main() {} //~ ERROR compilation successful
diff --git a/src/test/compile-fail/issue-24883.rs b/src/test/compile-fail/issue-24883.rs
new file mode 100644 (file)
index 0000000..097f2a5
--- /dev/null
@@ -0,0 +1,28 @@
+// 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(rustc_attrs)]
+
+mod a {
+    pub mod b { pub struct Foo; }
+
+    pub mod c {
+        use super::b;
+        pub struct Bar(pub b::Foo);
+    }
+
+    pub use self::c::*;
+}
+
+#[rustc_error]
+fn main() {  //~ ERROR compilation successful
+    let _ = a::c::Bar(a::b::Foo);
+    let _ = a::Bar(a::b::Foo);
+}
diff --git a/src/test/compile-fail/issue-26930.rs b/src/test/compile-fail/issue-26930.rs
new file mode 100644 (file)
index 0000000..6c98f3e
--- /dev/null
@@ -0,0 +1,20 @@
+// 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(rustc_attrs)]
+#![allow(unused)]
+
+extern crate core;
+use core as core_export;
+use self::x::*;
+mod x {}
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
diff --git a/src/test/compile-fail/issue-32201.rs b/src/test/compile-fail/issue-32201.rs
new file mode 100644 (file)
index 0000000..bcc53df
--- /dev/null
@@ -0,0 +1,22 @@
+// 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.
+
+extern {
+    fn foo(a: i32, ...);
+}
+
+fn bar(_: *const u8) {}
+
+fn main() {
+    unsafe {
+        foo(0, bar);
+        //~^ ERROR can't pass `fn(*const u8) {bar}` to variadic function, cast to `fn(*const u8)`
+    }
+}
diff --git a/src/test/compile-fail/issue-32833.rs b/src/test/compile-fail/issue-32833.rs
new file mode 100644 (file)
index 0000000..22261d9
--- /dev/null
@@ -0,0 +1,16 @@
+// 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.
+
+use bar::Foo; //~ ERROR There is no `Foo` in `bar` [E0432]
+mod bar {
+    use Foo; //~ ERROR There is no `Foo` in the crate root [E0432]
+}
+
+fn main() {}
index fd0f830a17d877ec79beb9383dd85de6a50e9de2..ece8fa7dc47bb12da8a4ffdbdad81c48a9a513e7 100644 (file)
 #![allow(dead_code)]
 #![feature(recover)]
 
-use std::panic::RecoverSafe;
+use std::panic::UnwindSafe;
 
-fn assert<T: RecoverSafe + ?Sized>() {}
+fn assert<T: UnwindSafe + ?Sized>() {}
 
 fn main() {
-    assert::<&mut i32>(); //~ ERROR: RecoverSafe` is not satisfied
+    assert::<&mut i32>(); //~ ERROR: UnwindSafe` is not satisfied
 }
index b3aa4e9187d34dc7fdb4cdb8ec18fac2c8514e7c..cc73cbe15fe5f9f16dfe8aa62b98fc895ac3b2e8 100644 (file)
@@ -18,9 +18,6 @@ fn main() {
     use std::boxed::HEAP; //~ ERROR use of unstable library feature
 
     let _ = HEAP <- { //~ ERROR use of unstable library feature
-        ::core::raw::Slice { //~ ERROR use of unstable library feature
-            data: &42, //~ ERROR use of unstable library feature
-            len: 1 //~ ERROR use of unstable library feature
-        }
+        HEAP //~ ERROR use of unstable library feature
     };
 }
diff --git a/src/test/compile-fail/symbol-names/issue-32709.rs b/src/test/compile-fail/symbol-names/issue-32709.rs
new file mode 100644 (file)
index 0000000..f9d11f3
--- /dev/null
@@ -0,0 +1,20 @@
+// 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(question_mark)]
+
+// Make sure that the span of try shorthand does not include the trailing
+// semicolon;
+fn a() -> Result<i32, ()> {
+    Err(5)?; //~ ERROR 16:5: 16:12
+    Ok(1)
+}
+
+fn main() {}
index e98224bee02f8000b3ec691f76afa03f8e622842..f2384912cdba31c924d5723f55a25a1a82d031dd 100644 (file)
 
 mod foo {
     use self::{self};
-    //~^ ERROR unresolved import `self`. There is no `self` in `???`
+    //~^ ERROR unresolved import `self`. There is no `self` in the crate root
 
     use super::{self};
-    //~^ ERROR unresolved import `super`. There is no `super` in `???`
+    //~^ ERROR unresolved import `super`. There is no `super` in the crate root
 }
 
 fn main() {}
index 1d5ebdbae3e2e959fa182046412a33f3bf7334a7..6e60562da67495513b829dec5462f0474d23f4d0 100644 (file)
@@ -33,11 +33,11 @@ fn main() {
         //~| expected variadic fn
         //~| found non-variadic function
 
-        foo(1, 2, 3f32); //~ ERROR: can't pass an f32 to variadic function, cast to c_double
-        foo(1, 2, true); //~ ERROR: can't pass bool to variadic function, cast to c_int
-        foo(1, 2, 1i8); //~ ERROR: can't pass i8 to variadic function, cast to c_int
-        foo(1, 2, 1u8); //~ ERROR: can't pass u8 to variadic function, cast to c_uint
-        foo(1, 2, 1i16); //~ ERROR: can't pass i16 to variadic function, cast to c_int
-        foo(1, 2, 1u16); //~ ERROR: can't pass u16 to variadic function, cast to c_uint
+        foo(1, 2, 3f32); //~ ERROR: can't pass an `f32` to variadic function, cast to `c_double`
+        foo(1, 2, true); //~ ERROR: can't pass `bool` to variadic function, cast to `c_int`
+        foo(1, 2, 1i8); //~ ERROR: can't pass `i8` to variadic function, cast to `c_int`
+        foo(1, 2, 1u8); //~ ERROR: can't pass `u8` to variadic function, cast to `c_uint`
+        foo(1, 2, 1i16); //~ ERROR: can't pass `i16` to variadic function, cast to `c_int`
+        foo(1, 2, 1u16); //~ ERROR: can't pass `u16` to variadic function, cast to `c_uint`
     }
 }
diff --git a/src/test/incremental/dirty_clean.rs b/src/test/incremental/dirty_clean.rs
new file mode 100644 (file)
index 0000000..9a30978
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// revisions: rpass1 cfail2
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+// Sanity check for the dirty-clean system. Give the opposite
+// annotations that we expect to see, so that we check that errors are
+// reported.
+
+fn main() { }
+
+mod x {
+    #[cfg(rpass1)]
+    pub fn x() -> usize {
+        22
+    }
+
+    #[cfg(cfail2)]
+    pub fn x() -> u32 {
+        22
+    }
+}
+
+mod y {
+    use x;
+
+    #[rustc_clean(label="TypeckItemBody", cfg="cfail2")]
+    #[rustc_clean(label="TransCrateItem", cfg="cfail2")]
+    pub fn y() {
+        //[cfail2]~^ ERROR `TypeckItemBody("y::y")` not found in dep graph, but should be clean
+        //[cfail2]~| ERROR `TransCrateItem("y::y")` not found in dep graph, but should be clean
+        x::x();
+    }
+}
+
+mod z {
+    #[rustc_dirty(label="TypeckItemBody", cfg="cfail2")]
+    #[rustc_dirty(label="TransCrateItem", cfg="cfail2")]
+    pub fn z() {
+        //[cfail2]~^ ERROR `TypeckItemBody("z::z")` found in dep graph, but should be dirty
+        //[cfail2]~| ERROR `TransCrateItem("z::z")` found in dep graph, but should be dirty
+    }
+}
diff --git a/src/test/incremental/hello_world.rs b/src/test/incremental/hello_world.rs
new file mode 100644 (file)
index 0000000..f98ae18
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// revisions: rpass1 rpass2
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+fn main() { }
+
+mod x {
+    #[cfg(rpass1)]
+    pub fn x() -> i32 {
+        1
+    }
+
+    #[cfg(rpass2)]
+    pub fn x() -> i32 {
+        2
+    }
+}
+
+mod y {
+    use x;
+
+    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    pub fn y() {
+        x::x();
+    }
+}
+
+mod z {
+    use y;
+
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
+    pub fn z() {
+        y::y();
+    }
+}
diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs
new file mode 100644 (file)
index 0000000..0aa728b
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// revisions: rpass1 rpass2
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+// Here the only thing which changes is the string constant in `x`.
+// Therefore, the compiler deduces (correctly) that typeck is not
+// needed even for callers of `x`.
+//
+// It is not entirely clear why `TransCrateItem` invalidates `y` and
+// `z`, actually, I think it's because of the structure of
+// trans. -nmatsakis
+
+fn main() { }
+
+mod x {
+    #[cfg(rpass1)]
+    pub fn x() {
+        println!("1");
+    }
+
+    #[cfg(rpass2)]
+    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_dirty(label="TransCrateItem", cfg="rpass2")]
+    pub fn x() {
+        println!("2");
+    }
+}
+
+mod y {
+    use x;
+
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TransCrateItem", cfg="rpass2")]
+    pub fn y() {
+        x::x();
+    }
+}
+
+mod z {
+    use y;
+
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TransCrateItem", cfg="rpass2")]
+    pub fn z() {
+        y::y();
+    }
+}
diff --git a/src/test/parse-fail/issue-32505.rs b/src/test/parse-fail/issue-32505.rs
new file mode 100644 (file)
index 0000000..e697e98
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z parse-only -Z continue-parse-after-error
+
+pub fn test() {
+    foo(|_|) //~ ERROR unexpected token: `)`
+}
+
+fn main() { }
index 91b4f5f30ad0d1f0d4313b5e3b843135fe66ef9b..12cc475f121f6fbe0608ee73c8e8c9e0fae53733 100644 (file)
@@ -239,7 +239,7 @@ fn compile_program(input: &str, sysroot: PathBuf)
 
         let krate = driver::assign_node_ids(&sess, krate);
         let lcx = LoweringContext::new(&sess, Some(&krate));
-        let dep_graph = DepGraph::new(sess.opts.build_dep_graph);
+        let dep_graph = DepGraph::new(sess.opts.build_dep_graph());
         let mut hir_forest = ast_map::Forest::new(lower_crate(&lcx, &krate), dep_graph);
         let arenas = ty::CtxtArenas::new();
         let ast_map = driver::make_map(&sess, &mut hir_forest);
diff --git a/src/test/run-make/rustdoc-json/Makefile b/src/test/run-make/rustdoc-json/Makefile
deleted file mode 100644 (file)
index e49ab64..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
--include ../tools.mk
-all:
-       $(HOST_RPATH_ENV) $(RUSTDOC) -w json -o $(TMPDIR)/doc.json foo.rs
-       $(HOST_RPATH_ENV) $(RUSTDOC) -o $(TMPDIR)/doc $(TMPDIR)/doc.json
diff --git a/src/test/run-make/rustdoc-json/foo.rs b/src/test/run-make/rustdoc-json/foo.rs
deleted file mode 100644 (file)
index 3bd56c1..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![crate_name = "foo"]
-
-//! Very docs
-
-pub mod bar {
-
-    /// So correct
-    pub mod baz {
-        /// Much detail
-        pub fn baz() { }
-    }
-
-    /// *wow*
-    pub trait Doge { fn dummy(&self) { } }
-}
diff --git a/src/test/run-pass/cabi-int-widening.rs b/src/test/run-pass/cabi-int-widening.rs
new file mode 100644 (file)
index 0000000..c7a2275
--- /dev/null
@@ -0,0 +1,22 @@
+// 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.
+
+#[link(name = "rust_test_helpers")]
+extern {
+    fn rust_int8_to_int32(_: i8) -> i32;
+}
+
+fn main() {
+    let x = unsafe {
+        rust_int8_to_int32(-1)
+    };
+
+    assert!(x == -1);
+}
index 9949b79278c11a2ecb871557a17ce481302d57d1..b918f79f2d5d6fc71f147d68a8459dc14a393f1b 100644 (file)
 #![allow(dead_code)]
 #![feature(recover)]
 
-use std::panic::{RecoverSafe, AssertRecoverSafe};
+use std::panic::{UnwindSafe, AssertUnwindSafe};
 use std::cell::RefCell;
 use std::sync::{Mutex, RwLock, Arc};
 use std::rc::Rc;
 
 struct Foo { a: i32 }
 
-fn assert<T: RecoverSafe + ?Sized>() {}
+fn assert<T: UnwindSafe + ?Sized>() {}
 
 fn main() {
     assert::<i32>();
@@ -43,13 +43,13 @@ fn bar<T>() {
         assert::<Mutex<T>>();
         assert::<RwLock<T>>();
     }
-    fn baz<T: RecoverSafe>() {
+    fn baz<T: UnwindSafe>() {
         assert::<Box<T>>();
         assert::<Vec<T>>();
         assert::<RefCell<T>>();
-        assert::<AssertRecoverSafe<T>>();
-        assert::<&AssertRecoverSafe<T>>();
-        assert::<Rc<AssertRecoverSafe<T>>>();
-        assert::<Arc<AssertRecoverSafe<T>>>();
+        assert::<AssertUnwindSafe<T>>();
+        assert::<&AssertUnwindSafe<T>>();
+        assert::<Rc<AssertUnwindSafe<T>>>();
+        assert::<Arc<AssertUnwindSafe<T>>>();
     }
 }
index 69ec9299d68e895a6cb474f7fcdafe9b58710d28..87a0103867595fd192418febe6297f8d752a6473 100644 (file)
@@ -19,7 +19,7 @@
 
 const TEST_REPOS: &'static [(&'static str, &'static str, Option<&'static str>)] = &[
     ("https://github.com/rust-lang/cargo",
-     "ff02b156f094fb83e70acd965c83c9286411914e",
+     "fae9c539388f1b7c70c31fd0a21b5dd9cd071177",
      None),
     ("https://github.com/iron/iron",
      "16c858ec2901e2992fe5e529780f59fa8ed12903",