]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #30781 - dhuseby:add_dragonflybsd_snapshot_3391630, r=alexcrichton
authorManish Goregaokar <manishsmail@gmail.com>
Fri, 15 Jan 2016 11:58:28 +0000 (17:28 +0530)
committerManish Goregaokar <manishsmail@gmail.com>
Fri, 15 Jan 2016 11:58:28 +0000 (17:28 +0530)
@alexcrichton please upload the following snapshots:

https://github.com/dhuseby/rust-manual-snapshots/raw/master/rust-stage0-2015-12-18-3391630-dragonfly-x86_64-e74d79488e88ac2de3bd03afd5959d2ae6e2b628.tar.bz2

thanks!

260 files changed:
CONTRIBUTING.md
README.md
configure
mk/cfg/arm-unknown-linux-gnueabi.mk
mk/cfg/powerpc64-unknown-linux-gnu.mk [new file with mode: 0644]
mk/cfg/powerpc64le-unknown-linux-gnu.mk [new file with mode: 0644]
mk/cfg/x86_64-unknown-bitrig.mk
mk/crates.mk
mk/main.mk
src/compiletest/util.rs
src/doc/book/README.md
src/doc/book/SUMMARY.md
src/doc/book/associated-types.md
src/doc/book/bibliography.md
src/doc/book/casting-between-types.md
src/doc/book/choosing-your-guarantees.md
src/doc/book/closures.md
src/doc/book/concurrency.md
src/doc/book/crates-and-modules.md
src/doc/book/custom-allocators.md
src/doc/book/documentation.md
src/doc/book/effective-rust.md
src/doc/book/enums.md
src/doc/book/error-handling.md
src/doc/book/ffi.md
src/doc/book/functions.md
src/doc/book/generics.md
src/doc/book/getting-started.md
src/doc/book/guessing-game.md
src/doc/book/iterators.md
src/doc/book/learn-rust.md
src/doc/book/lifetimes.md
src/doc/book/method-syntax.md
src/doc/book/nightly-rust.md
src/doc/book/no-stdlib.md
src/doc/book/operators-and-overloading.md
src/doc/book/ownership.md
src/doc/book/patterns.md
src/doc/book/primitive-types.md
src/doc/book/references-and-borrowing.md
src/doc/book/strings.md
src/doc/book/structs.md
src/doc/book/syntax-and-semantics.md
src/doc/book/testing.md
src/doc/book/the-stack-and-the-heap.md
src/doc/book/trait-objects.md
src/doc/book/traits.md
src/doc/book/unsafe.md
src/doc/book/unsized-types.md
src/doc/book/using-rust-without-the-standard-library.md [new file with mode: 0644]
src/doc/book/variable-bindings.md
src/doc/index.md
src/doc/nomicon/vec-insert-remove.md
src/doc/reference.md
src/etc/dec2flt_table.py
src/etc/unicode.py
src/liballoc/boxed.rs
src/liballoc/lib.rs
src/liballoc/oom.rs [new file with mode: 0644]
src/liballoc/raw_vec.rs
src/liballoc_jemalloc/lib.rs
src/liballoc_system/lib.rs
src/libarena/lib.rs
src/libbacktrace/ChangeLog.jit
src/libbacktrace/Makefile.am
src/libbacktrace/Makefile.in
src/libbacktrace/alloc.c
src/libbacktrace/atomic.c
src/libbacktrace/backtrace-supported.h.in
src/libbacktrace/backtrace.c
src/libbacktrace/backtrace.h
src/libbacktrace/btest.c
src/libbacktrace/configure.ac
src/libbacktrace/dwarf.c
src/libbacktrace/dwarf2.def
src/libbacktrace/dwarf2.h
src/libbacktrace/elf.c
src/libbacktrace/fileline.c
src/libbacktrace/internal.h
src/libbacktrace/mmap.c
src/libbacktrace/mmapio.c
src/libbacktrace/nounwind.c
src/libbacktrace/posix.c
src/libbacktrace/print.c
src/libbacktrace/read.c
src/libbacktrace/simple.c
src/libbacktrace/sort.c
src/libbacktrace/state.c
src/libbacktrace/stest.c
src/libbacktrace/unknown.c
src/libcollections/binary_heap.rs
src/libcollections/lib.rs
src/libcollections/range.rs
src/libcollections/str.rs
src/libcollections/string.rs
src/libcollectionstest/str.rs
src/libcore/fmt/mod.rs
src/libcore/iter.rs
src/libcore/marker.rs
src/libcore/mem.rs
src/libcore/num/dec2flt/algorithm.rs
src/libcore/num/dec2flt/rawfp.rs
src/libcore/num/dec2flt/table.rs
src/libcore/num/mod.rs
src/liblibc
src/librustc/diagnostics.rs
src/librustc/lint/builtin.rs
src/librustc/lint/context.rs
src/librustc/middle/check_match.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/traits/coherence.rs
src/librustc/middle/traits/project.rs
src/librustc/middle/traits/select.rs
src/librustc/mir/repr.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc/session/search_paths.rs
src/librustc_back/target/aarch64_unknown_linux_gnu.rs
src/librustc_back/target/android_base.rs
src/librustc_back/target/arm_linux_androideabi.rs
src/librustc_back/target/mod.rs
src/librustc_back/target/powerpc64_unknown_linux_gnu.rs [new file with mode: 0644]
src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs [new file with mode: 0644]
src/librustc_borrowck/borrowck/check_loans.rs
src/librustc_borrowck/borrowck/move_data.rs
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_lint/lib.rs
src/librustc_lint/types.rs
src/librustc_metadata/encoder.rs
src/librustc_mir/build/block.rs
src/librustc_mir/build/cfg.rs
src/librustc_mir/build/expr/into.rs
src/librustc_mir/build/into.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/pretty.rs
src/librustc_mir/transform/erase_regions.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/record_exports.rs
src/librustc_resolve/resolve_imports.rs
src/librustc_trans/back/link.rs
src/librustc_trans/back/linker.rs
src/librustc_trans/back/write.rs
src/librustc_trans/trans/_match.rs
src/librustc_trans/trans/adt.rs
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/cabi.rs
src/librustc_trans/trans/cabi_powerpc64.rs [new file with mode: 0644]
src/librustc_trans/trans/datum.rs
src/librustc_trans/trans/debuginfo/metadata.rs
src/librustc_trans/trans/debuginfo/mod.rs
src/librustc_trans/trans/expr.rs
src/librustc_trans/trans/mir/block.rs
src/librustc_trans/trans/mir/constant.rs
src/librustc_trans/trans/mir/operand.rs
src/librustc_trans/trans/mir/rvalue.rs
src/librustc_trans/trans/mod.rs
src/librustc_trans/trans/tvec.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/coherence/mod.rs
src/librustc_unicode/char.rs
src/librustc_unicode/tables.rs
src/librustdoc/clean/inline.rs
src/librustdoc/core.rs
src/librustdoc/html/render.rs
src/librustdoc/lib.rs
src/librustdoc/test.rs
src/libstd/env.rs
src/libstd/error.rs
src/libstd/ffi/os_str.rs
src/libstd/io/buffered.rs
src/libstd/io/mod.rs
src/libstd/lib.rs
src/libstd/num/f32.rs
src/libstd/os/linux/raw.rs
src/libstd/os/raw.rs
src/libstd/panicking.rs
src/libstd/rand/os.rs
src/libstd/sys/common/libunwind.rs
src/libstd/sys/common/util.rs
src/libstd/sys/unix/fs.rs
src/libstd/sys/unix/mod.rs
src/libstd/sys/unix/process.rs
src/libstd/sys/unix/stack_overflow.rs
src/libstd/sys/windows/mod.rs
src/libstd/thread/scoped_tls.rs
src/libstd/time/duration.rs
src/libstd/time/mod.rs
src/libsyntax/errors/emitter.rs
src/libsyntax/errors/json.rs [new file with mode: 0644]
src/libsyntax/errors/mod.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/feature_gate.rs
src/libsyntax/parse/lexer/comments.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libtest/lib.rs
src/test/auxiliary/extern_calling_convention.rs
src/test/codegen/mir_zst_stores.rs [new file with mode: 0644]
src/test/compile-fail/coherence-projection-conflict-orphan.rs [new file with mode: 0644]
src/test/compile-fail/coherence-projection-conflict-ty-param.rs [new file with mode: 0644]
src/test/compile-fail/coherence-projection-conflict.rs [new file with mode: 0644]
src/test/compile-fail/coherence-projection-ok-orphan.rs [new file with mode: 0644]
src/test/compile-fail/coherence-projection-ok.rs [new file with mode: 0644]
src/test/compile-fail/const-eval-overflow-4b.rs
src/test/compile-fail/const-eval-overflow.rs
src/test/compile-fail/const-eval-overflow0.rs [new file with mode: 0644]
src/test/compile-fail/empty-struct-unit-pat.rs
src/test/compile-fail/enum-discrim-too-small.rs
src/test/compile-fail/feature-gate-negate-unsigned.rs
src/test/compile-fail/issue-19692.rs
src/test/compile-fail/issue-21950.rs
src/test/compile-fail/issue-23966.rs
src/test/compile-fail/issue-24352.rs
src/test/compile-fail/issue-29857.rs [new file with mode: 0644]
src/test/compile-fail/issue-30589.rs [new file with mode: 0644]
src/test/compile-fail/issue-30715.rs
src/test/compile-fail/issue-3973.rs
src/test/compile-fail/lint-type-limits.rs
src/test/compile-fail/macro-input-future-proofing.rs
src/test/compile-fail/macro-seq-followed-by-seq.rs [deleted file]
src/test/compile-fail/match-pattern-field-mismatch-2.rs
src/test/compile-fail/pattern-error-continue.rs
src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs
src/test/parse-fail/lex-bad-char-literals-1.rs [new file with mode: 0644]
src/test/parse-fail/lex-bad-char-literals-2.rs [new file with mode: 0644]
src/test/parse-fail/lex-bad-char-literals-3.rs [new file with mode: 0644]
src/test/parse-fail/lex-bad-char-literals-4.rs [new file with mode: 0644]
src/test/parse-fail/lex-bad-char-literals-5.rs [new file with mode: 0644]
src/test/parse-fail/lex-bad-char-literals.rs [deleted file]
src/test/parse-fail/lifetime-semicolon.rs [new file with mode: 0644]
src/test/run-make/execution-engine/test.rs
src/test/run-make/json-errors/Makefile [new file with mode: 0644]
src/test/run-make/json-errors/foo.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/compiler-calls.rs
src/test/run-pass/bitwise.rs
src/test/run-pass/conditional-compile-arch.rs
src/test/run-pass/intrinsic-alignment.rs
src/test/run-pass/intrinsics-integer.rs
src/test/run-pass/issue-2895.rs
src/test/run-pass/issue-29092.rs [new file with mode: 0644]
src/test/run-pass/issue-30018-nopanic.rs [new file with mode: 0644]
src/test/run-pass/issue-30018-panic.rs [new file with mode: 0644]
src/test/run-pass/issue-30490.rs [new file with mode: 0644]
src/test/run-pass/issue-30530.rs [new file with mode: 0644]
src/test/run-pass/macro-pat-follow.rs
src/test/run-pass/macro-seq-followed-by-seq.rs [new file with mode: 0644]
src/test/run-pass/mir_constval_adts.rs [new file with mode: 0644]
src/test/run-pass/mir_trans_calls.rs
src/test/run-pass/rec-align-u32.rs
src/test/run-pass/rec-align-u64.rs
src/test/run-pass/string-box-error.rs [new file with mode: 0644]
src/test/run-pass/struct-return.rs
src/test/run-pass/unary-minus-suffix-inference.rs

index c3851dcc8f1ede74bbf1af7cb0c73f033c1b1031..e864172e813320ff2167b69fbbd74f6dc4cfb92f 100644 (file)
@@ -174,7 +174,7 @@ labels to triage issues:
 * Yellow, **A**-prefixed labels state which **area** of the project an issue
   relates to.
 
-* Magenta, **B**-prefixed labels identify bugs which **belong** elsewhere.
+* Magenta, **B**-prefixed labels identify bugs which are **blockers**.
 
 * Green, **E**-prefixed labels explain the level of **experience** necessary
   to fix the issue.
index 7558065831ace3e52982e76bf9f849d6f7232ff2..636c8adfa91e9f0d9236506d49869220e58780a4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ Read ["Installing Rust"] from [The Book].
 1. Make sure you have installed the dependencies:
 
    * `g++` 4.7 or `clang++` 3.x
-   * `python` 2.6 or later (but not 3.x)
+   * `python` 2.7 or later (but not 3.x)
    * GNU `make` 3.81 or later
    * `curl`
    * `git`
index df76d805f824b4038d8dd84615f3999c0d0b2657..0255b04caa3163a331f1a406b590234ce92e211b 100755 (executable)
--- a/configure
+++ b/configure
@@ -499,13 +499,18 @@ case $CFG_CPUTYPE in
         CFG_CPUTYPE=aarch64
         ;;
 
-    # At some point, when ppc64[le] support happens, this will need to do
-    # something clever. For now it's safe to assume that we're only ever
-    # interested in building 32 bit.
-    powerpc | ppc | ppc64)
+    powerpc | ppc)
         CFG_CPUTYPE=powerpc
         ;;
 
+    powerpc64 | ppc64)
+        CFG_CPUTYPE=powerpc64
+        ;;
+
+    powerpc64le | ppc64le)
+        CFG_CPUTYPE=powerpc64le
+        ;;
+
     x86_64 | x86-64 | x64 | amd64)
         CFG_CPUTYPE=x86_64
         ;;
@@ -622,6 +627,7 @@ valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path"
 valopt nacl-cross-path  "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!"
 valopt release-channel "dev" "the name of the release channel to build"
 valopt musl-root "/usr/local" "MUSL root installation directory"
+valopt extra-filename "" "Additional data that is hashed and passed to the -C extra-filename flag"
 
 # Used on systems where "cc" and "ar" are unavailable
 valopt default-linker "cc" "the default linker"
index 9a91097458e90fdd101dbafc0d51e777935b78ad..9244cc43650fe706901690107abc605256b16ef0 100644 (file)
@@ -8,8 +8,8 @@ CFG_LIB_NAME_arm-unknown-linux-gnueabi=lib$(1).so
 CFG_STATIC_LIB_NAME_arm-unknown-linux-gnueabi=lib$(1).a
 CFG_LIB_GLOB_arm-unknown-linux-gnueabi=lib$(1)-*.so
 CFG_LIB_DSYM_GLOB_arm-unknown-linux-gnueabi=lib$(1)-*.dylib.dSYM
-CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabi := -D__arm__ -mfpu=vfp $(CFLAGS)
-CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__ -mfpu=vfp $(CFLAGS)
+CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabi := -D__arm__ -mfloat-abi=soft $(CFLAGS)
+CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__ -mfloat-abi=soft $(CFLAGS)
 CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabi := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabi := -shared -fPIC -g
 CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabi := -Wl,--export-dynamic,--dynamic-list=
diff --git a/mk/cfg/powerpc64-unknown-linux-gnu.mk b/mk/cfg/powerpc64-unknown-linux-gnu.mk
new file mode 100644 (file)
index 0000000..a9e8585
--- /dev/null
@@ -0,0 +1,24 @@
+# powerpc64-unknown-linux-gnu configuration
+CROSS_PREFIX_powerpc64-unknown-linux-gnu=powerpc64-linux-gnu-
+CC_powerpc64-unknown-linux-gnu=$(CC)
+CXX_powerpc64-unknown-linux-gnu=$(CXX)
+CPP_powerpc64-unknown-linux-gnu=$(CPP)
+AR_powerpc64-unknown-linux-gnu=$(AR)
+CFG_LIB_NAME_powerpc64-unknown-linux-gnu=lib$(1).so
+CFG_STATIC_LIB_NAME_powerpc64-unknown-linux-gnu=lib$(1).a
+CFG_LIB_GLOB_powerpc64-unknown-linux-gnu=lib$(1)-*.so
+CFG_LIB_DSYM_GLOB_powerpc64-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
+CFG_CFLAGS_powerpc64-unknown-linux-gnu := -m64 $(CFLAGS)
+CFG_GCCISH_CFLAGS_powerpc64-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64 $(CFLAGS)
+CFG_GCCISH_CXXFLAGS_powerpc64-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
+CFG_GCCISH_LINK_FLAGS_powerpc64-unknown-linux-gnu := -shared -fPIC -ldl -pthread  -lrt -g -m64
+CFG_GCCISH_DEF_FLAG_powerpc64-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
+CFG_LLC_FLAGS_powerpc64-unknown-linux-gnu :=
+CFG_INSTALL_NAME_powerpc64-unknown-linux-gnu =
+CFG_EXE_SUFFIX_powerpc64-unknown-linux-gnu =
+CFG_WINDOWSY_powerpc64-unknown-linux-gnu :=
+CFG_UNIXY_powerpc64-unknown-linux-gnu := 1
+CFG_LDPATH_powerpc64-unknown-linux-gnu :=
+CFG_RUN_powerpc64-unknown-linux-gnu=$(2)
+CFG_RUN_TARG_powerpc64-unknown-linux-gnu=$(call CFG_RUN_powerpc64-unknown-linux-gnu,,$(2))
+CFG_GNU_TRIPLE_powerpc64-unknown-linux-gnu := powerpc64-unknown-linux-gnu
diff --git a/mk/cfg/powerpc64le-unknown-linux-gnu.mk b/mk/cfg/powerpc64le-unknown-linux-gnu.mk
new file mode 100644 (file)
index 0000000..a204933
--- /dev/null
@@ -0,0 +1,24 @@
+# powerpc64le-unknown-linux-gnu configuration
+CROSS_PREFIX_powerpc64le-unknown-linux-gnu=powerpc64le-linux-gnu-
+CC_powerpc64le-unknown-linux-gnu=$(CC)
+CXX_powerpc64le-unknown-linux-gnu=$(CXX)
+CPP_powerpc64le-unknown-linux-gnu=$(CPP)
+AR_powerpc64le-unknown-linux-gnu=$(AR)
+CFG_LIB_NAME_powerpc64le-unknown-linux-gnu=lib$(1).so
+CFG_STATIC_LIB_NAME_powerpc64le-unknown-linux-gnu=lib$(1).a
+CFG_LIB_GLOB_powerpc64le-unknown-linux-gnu=lib$(1)-*.so
+CFG_LIB_DSYM_GLOB_powerpc64le-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
+CFG_CFLAGS_powerpc64le-unknown-linux-gnu := -m64 $(CFLAGS)
+CFG_GCCISH_CFLAGS_powerpc64le-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64 $(CFLAGS)
+CFG_GCCISH_CXXFLAGS_powerpc64le-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
+CFG_GCCISH_LINK_FLAGS_powerpc64le-unknown-linux-gnu := -shared -fPIC -ldl -pthread  -lrt -g -m64
+CFG_GCCISH_DEF_FLAG_powerpc64le-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
+CFG_LLC_FLAGS_powerpc64le-unknown-linux-gnu :=
+CFG_INSTALL_NAME_powerpc64le-unknown-linux-gnu =
+CFG_EXE_SUFFIX_powerpc64le-unknown-linux-gnu =
+CFG_WINDOWSY_powerpc64le-unknown-linux-gnu :=
+CFG_UNIXY_powerpc64le-unknown-linux-gnu := 1
+CFG_LDPATH_powerpc64le-unknown-linux-gnu :=
+CFG_RUN_powerpc64le-unknown-linux-gnu=$(2)
+CFG_RUN_TARG_powerpc64le-unknown-linux-gnu=$(call CFG_RUN_powerpc64le-unknown-linux-gnu,,$(2))
+CFG_GNU_TRIPLE_powerpc64le-unknown-linux-gnu := powerpc64le-unknown-linux-gnu
index dd6d19f7491bb688d8f7c588392afd18c9a6a4c5..afffec1a53a913a398f3c34da36e475314f0a845 100644 (file)
@@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_x86_64-unknown-bitrig=lib$(1).a
 CFG_LIB_GLOB_x86_64-unknown-bitrig=lib$(1)-*.so
 CFG_LIB_DSYM_GLOB_x86_64-unknown-bitrig=$(1)-*.dylib.dSYM
 CFG_JEMALLOC_CFLAGS_x86_64-unknown-bitrig := -m64 -I/usr/include $(CFLAGS)
-CFG_GCCISH_CFLAGS_x86_64-unknown-bitrig := -Wall -Werror -fPIC -m64 -I/usr/include $(CFLAGS)
+CFG_GCCISH_CFLAGS_x86_64-unknown-bitrig := -Wall -Werror -fPIE -fPIC -m64 -I/usr/include $(CFLAGS)
 CFG_GCCISH_LINK_FLAGS_x86_64-unknown-bitrig := -shared -pic -pthread -m64 $(LDFLAGS)
 CFG_GCCISH_DEF_FLAG_x86_64-unknown-bitrig := -Wl,--export-dynamic,--dynamic-list=
 CFG_LLC_FLAGS_x86_64-unknown-bitrig :=
index 2597c724da96fd7ad4aa096d7633bc6e3bc80635..be53234cb02e2ca402f07197251ae7b435696f8e 100644 (file)
@@ -103,7 +103,7 @@ DEPS_rustc_lint := rustc log syntax
 DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
 DEPS_rustc_metadata := rustc rustc_front syntax rbml
 DEPS_rustc_mir := rustc rustc_front syntax
-DEPS_rustc_resolve := rustc rustc_front log syntax
+DEPS_rustc_resolve := arena rustc rustc_front log syntax
 DEPS_rustc_platform_intrinsics := rustc rustc_llvm
 DEPS_rustc_plugin := rustc rustc_metadata syntax
 DEPS_rustc_privacy := rustc rustc_front log syntax
@@ -175,9 +175,5 @@ endef
 
 $(foreach crate,$(TOOLS),$(eval $(call RUST_TOOL,$(crate))))
 
-ifdef CFG_DISABLE_ELF_TLS
-RUSTFLAGS_std := --cfg no_elf_tls
-endif
-
 CRATEFILE_libc := $(SREL)src/liblibc/src/lib.rs
 RUSTFLAGS_libc := --cfg stdbuild
index 4c4722a76b93943b90981d4d4aed98812532b48e..a478cafd6b95880e004059896a96134cb5276aa0 100644 (file)
@@ -22,7 +22,7 @@ CFG_PRERELEASE_VERSION=.1
 
 # Append a version-dependent hash to each library, so we can install different
 # versions in the same place
-CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE) | $(CFG_HASH_COMMAND))
+CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE)$(CFG_EXTRA_FILENAME) | $(CFG_HASH_COMMAND))
 
 ifeq ($(CFG_RELEASE_CHANNEL),stable)
 # This is the normal semver version string, e.g. "0.12.0", "0.12.0-nightly"
index fbafee102e4b2a59e3ba05934f1c9be865560c74..103ca463f7a58e2755a50e198070ecdfd8507073 100644 (file)
@@ -38,6 +38,8 @@
     ("mips", "mips"),
     ("msp430", "msp430"),
     ("powerpc", "powerpc"),
+    ("powerpc64", "powerpc64"),
+    ("powerpc64le", "powerpc64le"),
     ("s390x", "systemz"),
     ("sparc", "sparc"),
     ("x86_64", "x86_64"),
index d16746e777a3ac8c28e4d91519438ec1d5f24816..9f9b6a9b043dde75197310bf764f1338f75acc29 100644 (file)
@@ -14,7 +14,7 @@ Even then, Rust still allows precise control like a low-level language would.
 
 [rust]: https://www.rust-lang.org
 
-“The Rust Programming Language” is split into sections. This introduction
+“The Rust Programming Language” is split into chapters. This introduction
 is the first. After this:
 
 * [Getting started][gs] - Set up your computer for Rust development.
index 3df791fd51bf6dcfc101a4ccd3b393942690db5b..fe5e1c3990c5c8412a41fd3efe9c6b7835531c03 100644 (file)
@@ -51,6 +51,7 @@
     * [FFI](ffi.md)
     * [Borrow and AsRef](borrow-and-asref.md)
     * [Release Channels](release-channels.md)
+    * [Using Rust without the standard library](using-rust-without-the-standard-library.md)
 * [Nightly Rust](nightly-rust.md)
     * [Compiler Plugins](compiler-plugins.md)
     * [Inline Assembly](inline-assembly.md)
index fe4f27b9d954cb6e3b341c148f3e8b259cf445e2..a0676a33996fc34bf83a380806db5a3acaa11373 100644 (file)
@@ -24,7 +24,7 @@ fn distance<N, E, G: Graph<N, E>>(graph: &G, start: &N, end: &N) -> u32 { ... }
 ```
 
 Our distance calculation works regardless of our `Edge` type, so the `E` stuff in
-this signature is just a distraction.
+this signature is a distraction.
 
 What we really want to say is that a certain `E`dge and `N`ode type come together
 to form each kind of `Graph`. We can do that with associated types:
@@ -118,10 +118,10 @@ impl Graph for MyGraph {
 This silly implementation always returns `true` and an empty `Vec<Edge>`, but it
 gives you an idea of how to implement this kind of thing. We first need three
 `struct`s, one for the graph, one for the node, and one for the edge. If it made
-more sense to use a different type, that would work as well, we’re just going to
+more sense to use a different type, that would work as well, we’re going to
 use `struct`s for all three here.
 
-Next is the `impl` line, which is just like implementing any other trait.
+Next is the `impl` line, which is an implementation like any other trait.
 
 From here, we use `=` to define our associated types. The name the trait uses
 goes on the left of the `=`, and the concrete type we’re `impl`ementing this
index ba02053b6b8944761e85f9b9cd5feded040cebed..d32b1a91944e46366a5100f62808386619a959ef 100644 (file)
@@ -33,7 +33,7 @@ Rust, as well as publications about Rust.
 * [Non-blocking steal-half work queues](http://www.cs.bgu.ac.il/%7Ehendlerd/papers/p280-hendler.pdf)
 * [Reagents: expressing and composing fine-grained concurrency](http://www.mpi-sws.org/~turon/reagents.pdf)
 * [Algorithms for scalable synchronization of shared-memory multiprocessors](https://www.cs.rochester.edu/u/scott/papers/1991_TOCS_synch.pdf)
-* [Epoc-based reclamation](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf).
+* [Epoch-based reclamation](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf).
 
 ### Others
 
index 7108d957eddccccd6fe573fd34b8a73551c184d5..5cafe1693690ddf1a3b9a1524295b5f9906b42ad 100644 (file)
@@ -154,7 +154,7 @@ implemented. For this, we need something more dangerous.
 The `transmute` function is provided by a [compiler intrinsic][intrinsics], and
 what it does is very simple, but very scary. It tells Rust to treat a value of
 one type as though it were another type. It does this regardless of the
-typechecking system, and just completely trusts you.
+typechecking system, and completely trusts you.
 
 [intrinsics]: intrinsics.html
 
index edf5e2ff738187aaeb9302e024b76d95c9b907c1..f2b92e6dec4ddd664d48b0be1834353557783709 100644 (file)
@@ -52,7 +52,7 @@ These pointers cannot be copied in such a way that they outlive the lifetime ass
 
 ## `*const T` and `*mut T`
 
-These are C-like raw pointers with no lifetime or ownership attached to them. They just point to
+These are C-like raw pointers with no lifetime or ownership attached to them. They point to
 some location in memory with no other restrictions. The only guarantee that these provide is that
 they cannot be dereferenced except in code marked `unsafe`.
 
@@ -255,7 +255,7 @@ major ones will be covered below.
 
 ## `Arc<T>`
 
-[`Arc<T>`][arc] is just a version of `Rc<T>` that uses an atomic reference count (hence, "Arc").
+[`Arc<T>`][arc] is a version of `Rc<T>` that uses an atomic reference count (hence, "Arc").
 This can be sent freely between threads.
 
 C++'s `shared_ptr` is similar to `Arc`, however in the case of C++ the inner data is always mutable.
index 7d4452a4c847047d9478913034bcef43148ff17b..237545edc05bbf9231b516116bffdb1cba4a6f89 100644 (file)
@@ -208,7 +208,7 @@ different.
 
 Rust’s implementation of closures is a bit different than other languages. They
 are effectively syntax sugar for traits. You’ll want to make sure to have read
-the [traits chapter][traits] before this one, as well as the chapter on [trait
+the [traits][traits] section before this one, as well as the section on [trait
 objects][trait-objects].
 
 [traits]: traits.html
@@ -253,7 +253,7 @@ use it.
 # Taking closures as arguments
 
 Now that we know that closures are traits, we already know how to accept and
-return closures: just like any other trait!
+return closures: the same as any other trait!
 
 This also means that we can choose static vs dynamic dispatch as well. First,
 let’s write a function which takes something callable, calls it, and returns
@@ -271,7 +271,7 @@ let answer = call_with_one(|x| x + 2);
 assert_eq!(3, answer);
 ```
 
-We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it
+We pass our closure, `|x| x + 2`, to `call_with_one`. It does what it
 suggests: it calls the closure, giving it `1` as an argument.
 
 Let’s examine the signature of `call_with_one` in more depth:
@@ -448,7 +448,7 @@ This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
 we have a `[closure@<anon>:7:9: 7:20]`. Wait, what?
 
 Because each closure generates its own environment `struct` and implementation
-of `Fn` and friends, these types are anonymous. They exist just solely for
+of `Fn` and friends, these types are anonymous. They exist solely for
 this closure. So Rust shows them as `closure@<anon>`, rather than some
 autogenerated name.
 
index 8ea6f4f6fcc2864cbbd32d4cf00979f644226a79..44569a04b98243e0f3b3ce2bb87bcf63f30f63a9 100644 (file)
@@ -305,10 +305,10 @@ fn main() {
 }
 ```
 
-We use the `mpsc::channel()` method to construct a new channel. We just `send`
+We use the `mpsc::channel()` method to construct a new channel. We `send`
 a simple `()` down the channel, and then wait for ten of them to come back.
 
-While this channel is just sending a generic signal, we can send any data that
+While this channel is sending a generic signal, we can send any data that
 is `Send` over the channel!
 
 ```rust
index 4a4648c7b563f4fe4bbcab815e54dbc9da7d6eb5..2b6297640d09faab59f7edbd6786602ba026ee85 100644 (file)
@@ -222,7 +222,7 @@ fn hello() -> String {
 }
 ```
 
-Of course, you can copy and paste this from this web page, or just type
+Of course, you can copy and paste this from this web page, or type
 something else. It’s not important that you actually put ‘konnichiwa’ to learn
 about the module system.
 
@@ -299,7 +299,7 @@ depth.
 Rust allows you to precisely control which aspects of your interface are
 public, and so private is the default. To make things public, you use the `pub`
 keyword. Let’s focus on the `english` module first, so let’s reduce our `src/main.rs`
-to just this:
+to only this:
 
 ```rust,ignore
 extern crate phrases;
@@ -447,7 +447,7 @@ use phrases::english::{greetings, farewells};
 
 ## Re-exporting with `pub use`
 
-You don’t just use `use` to shorten identifiers. You can also use it inside of your crate
+You don’t only use `use` to shorten identifiers. You can also use it inside of your crate
 to re-export a function inside another module. This allows you to present an external
 interface that may not directly map to your internal code organization.
 
@@ -584,5 +584,5 @@ use sayings::english::farewells as en_farewells;
 ```
 
 As you can see, the curly brackets compress `use` statements for several items
-under the same path, and in this context `self` just refers back to that path.
+under the same path, and in this context `self` refers back to that path.
 Note: The curly brackets cannot be nested or mixed with star globbing.
index 65626c11462365995369692962387952161f4fe8..d69ef6cf7e83acfd24fb741a34cba8a2ad5f3199 100644 (file)
@@ -13,7 +13,7 @@ own allocator up and running.
 
 The compiler currently ships two default allocators: `alloc_system` and
 `alloc_jemalloc` (some targets don't have jemalloc, however). These allocators
-are just normal Rust crates and contain an implementation of the routines to
+are normal Rust crates and contain an implementation of the routines to
 allocate and deallocate memory. The standard library is not compiled assuming
 either one, and the compiler will decide which allocator is in use at
 compile-time depending on the type of output artifact being produced.
@@ -134,7 +134,7 @@ pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
     size
 }
 
-# // just needed to get rustdoc to test this
+# // only needed to get rustdoc to test this
 # fn main() {}
 # #[lang = "panic_fmt"] fn panic_fmt() {}
 # #[lang = "eh_personality"] fn eh_personality() {}
index 86c07f9cf6c18673d70361c9a3b067e19b8bcf77..4053e5776e39f89982e5e2cacde47d52adb3245f 100644 (file)
@@ -193,7 +193,7 @@ If you want something that's not Rust code, you can add an annotation:
 ```
 
 This will highlight according to whatever language you're showing off.
-If you're just showing plain text, choose `text`.
+If you're only showing plain text, choose `text`.
 
 It's important to choose the correct annotation here, because `rustdoc` uses it
 in an interesting way: It can be used to actually test your examples in a
@@ -273,7 +273,7 @@ be hidden from the output, but will be used when compiling your code. You
 can use this to your advantage. In this case, documentation comments need
 to apply to some kind of function, so if I want to show you just a
 documentation comment, I need to add a little function definition below
-it. At the same time, it's just there to satisfy the compiler, so hiding
+it. At the same time, it's only there to satisfy the compiler, so hiding
 it makes the example more clear. You can use this technique to explain
 longer examples in detail, while still preserving the testability of your
 documentation.
@@ -512,7 +512,7 @@ the documentation with comments. For example:
 # fn foo() {}
 ```
 
-is just
+is:
 
 ~~~markdown
 # Examples
index 582ed3b7e65c56a256c60f8a76e0fc3629328f5d..65873c80e55e4364e13ac2107463088b2760d673 100644 (file)
@@ -3,6 +3,6 @@
 So you’ve learned how to write some Rust code. But there’s a difference between
 writing *any* Rust code and writing *good* Rust code.
 
-This section consists of relatively independent tutorials which show you how to
+This chapter consists of relatively independent tutorials which show you how to
 take your Rust to the next level. Common patterns and standard library features
 will be introduced. Read these sections in any order of your choosing.
index e17d3f762b9e8cec4592ed6ccb92dffea05d114e..5e05b4ebbdfa9a004c40c24aff106937fbf06da1 100644 (file)
@@ -62,7 +62,6 @@ learn in the next section. We don’t know enough about Rust to implement
 equality yet, but we’ll find out in the [`traits`][traits] section.
 
 [match]: match.html
-[if-let]: if-let.html
 [traits]: traits.html
 
 # Constructors as functions
index 17eb91852664f3f69b389544caed9b091d57dc5b..9b1d16170b97f1c879e6c6c85169f8f6f807d761 100644 (file)
@@ -5,18 +5,18 @@ errors in a particular way. Generally speaking, error handling is divided into
 two broad categories: exceptions and return values. Rust opts for return
 values.
 
-In this chapter, we intend to provide a comprehensive treatment of how to deal
+In this section, we intend to provide a comprehensive treatment of how to deal
 with errors in Rust. More than that, we will attempt to introduce error handling
 one piece at a time so that you'll come away with a solid working knowledge of
 how everything fits together.
 
 When done naïvely, error handling in Rust can be verbose and annoying. This
-chapter will explore those stumbling blocks and demonstrate how to use the
+section will explore those stumbling blocks and demonstrate how to use the
 standard library to make error handling concise and ergonomic.
 
 # Table of Contents
 
-This chapter is very long, mostly because we start at the very beginning with
+This section is very long, mostly because we start at the very beginning with
 sum types and combinators, and try to motivate the way Rust does error handling
 incrementally. As such, programmers with experience in other expressive type
 systems may want to jump around.
@@ -117,8 +117,8 @@ the first example. This is because the
 panic is embedded in the calls to `unwrap`.
 
 To “unwrap” something in Rust is to say, “Give me the result of the
-computation, and if there was an error, just panic and stop the program.”
-It would be better if we just showed the code for unwrapping because it is so
+computation, and if there was an error, panic and stop the program.”
+It would be better if we showed the code for unwrapping because it is so
 simple, but to do that, we will first need to explore the `Option` and `Result`
 types. Both of these types have a method called `unwrap` defined on them.
 
@@ -154,7 +154,7 @@ fn find(haystack: &str, needle: char) -> Option<usize> {
 }
 ```
 
-Notice that when this function finds a matching character, it doesn't just
+Notice that when this function finds a matching character, it doesn't only
 return the `offset`. Instead, it returns `Some(offset)`. `Some` is a variant or
 a *value constructor* for the `Option` type. You can think of it as a function
 with the type `fn<T>(value: T) -> Option<T>`. Correspondingly, `None` is also a
@@ -216,7 +216,7 @@ we saw how to use `find` to discover the extension in a file name. Of course,
 not all file names have a `.` in them, so it's possible that the file name has
 no extension. This *possibility of absence* is encoded into the types using
 `Option<T>`. In other words, the compiler will force us to address the
-possibility that an extension does not exist. In our case, we just print out a
+possibility that an extension does not exist. In our case, we only print out a
 message saying as such.
 
 Getting the extension of a file name is a pretty common operation, so it makes
@@ -248,7 +248,7 @@ tiresome.
 
 In fact, the case analysis in `extension_explicit` follows a very common
 pattern: *map* a function on to the value inside of an `Option<T>`, unless the
-option is `None`, in which case, just return `None`.
+option is `None`, in which case, return `None`.
 
 Rust has parametric polymorphism, so it is very easy to define a combinator
 that abstracts this pattern:
@@ -350,7 +350,7 @@ fn file_name(file_path: &str) -> Option<&str> {
 }
 ```
 
-You might think that we could just use the `map` combinator to reduce the case
+You might think that we could use the `map` combinator to reduce the case
 analysis, but its type doesn't quite fit. Namely, `map` takes a function that
 does something only with the inner value. The result of that function is then
 *always* [rewrapped with `Some`](#code-option-map). Instead, we need something
@@ -636,7 +636,7 @@ Thus far, we've looked at error handling where everything was either an
 `Option` and a `Result`? Or what if you have a `Result<T, Error1>` and a
 `Result<T, Error2>`? Handling *composition of distinct error types* is the next
 challenge in front of us, and it will be the major theme throughout the rest of
-this chapter.
+this section.
 
 ## Composing `Option` and `Result`
 
@@ -648,7 +648,7 @@ Of course, in real code, things aren't always as clean. Sometimes you have a
 mix of `Option` and `Result` types. Must we resort to explicit case analysis,
 or can we continue using combinators?
 
-For now, let's revisit one of the first examples in this chapter:
+For now, let's revisit one of the first examples in this section:
 
 ```rust,should_panic
 use std::env;
@@ -670,7 +670,7 @@ The tricky aspect here is that `argv.nth(1)` produces an `Option` while
 with both an `Option` and a `Result`, the solution is *usually* to convert the
 `Option` to a `Result`. In our case, the absence of a command line parameter
 (from `env::args()`) means the user didn't invoke the program correctly. We
-could just use a `String` to describe the error. Let's try:
+could use a `String` to describe the error. Let's try:
 
 <span id="code-error-double-string"></span>
 
@@ -709,7 +709,7 @@ fn ok_or<T, E>(option: Option<T>, err: E) -> Result<T, E> {
 
 The other new combinator used here is
 [`Result::map_err`](../std/result/enum.Result.html#method.map_err).
-This is just like `Result::map`, except it maps a function on to the *error*
+This is like `Result::map`, except it maps a function on to the *error*
 portion of a `Result` value. If the `Result` is an `Ok(...)` value, then it is
 returned unmodified.
 
@@ -841,7 +841,7 @@ example, the very last call to `map` multiplies the `Ok(...)` value (which is
 an `i32`) by `2`. If an error had occurred before that point, this operation
 would have been skipped because of how `map` is defined.
 
-`map_err` is the trick that makes all of this work. `map_err` is just like
+`map_err` is the trick that makes all of this work. `map_err` is like
 `map`, except it applies a function to the `Err(...)` value of a `Result`. In
 this case, we want to convert all of our errors to one type: `String`. Since
 both `io::Error` and `num::ParseIntError` implement `ToString`, we can call the
@@ -901,7 +901,7 @@ reduce explicit case analysis. Combinators aren't the only way.
 ## The `try!` macro
 
 A cornerstone of error handling in Rust is the `try!` macro. The `try!` macro
-abstracts case analysis just like combinators, but unlike combinators, it also
+abstracts case analysis like combinators, but unlike combinators, it also
 abstracts *control flow*. Namely, it can abstract the *early return* pattern
 seen above.
 
@@ -1319,7 +1319,7 @@ and [`cause`](../std/error/trait.Error.html#method.cause), but the
 limitation remains: `Box<Error>` is opaque. (N.B. This isn't entirely
 true because Rust does have runtime reflection, which is useful in
 some scenarios that are [beyond the scope of this
-chapter](https://crates.io/crates/error).)
+section](https://crates.io/crates/error).)
 
 It's time to revisit our custom `CliError` type and tie everything together.
 
@@ -1461,7 +1461,7 @@ expose its representation (like
 [`ErrorKind`](../std/io/enum.ErrorKind.html)) or keep it hidden (like
 [`ParseIntError`](../std/num/struct.ParseIntError.html)). Regardless
 of how you do it, it's usually good practice to at least provide some
-information about the error beyond just its `String`
+information about the error beyond its `String`
 representation. But certainly, this will vary depending on use cases.
 
 At a minimum, you should probably implement the
@@ -1486,7 +1486,7 @@ and [`fmt::Result`](../std/fmt/type.Result.html).
 
 # Case study: A program to read population data
 
-This chapter was long, and depending on your background, it might be
+This section was long, and depending on your background, it might be
 rather dense. While there is plenty of example code to go along with
 the prose, most of it was specifically designed to be pedagogical. So,
 we're going to do something new: a case study.
@@ -1499,7 +1499,7 @@ that can go wrong!
 The data we'll be using comes from the [Data Science
 Toolkit][11]. I've prepared some data from it for this exercise. You
 can either grab the [world population data][12] (41MB gzip compressed,
-145MB uncompressed) or just the [US population data][13] (2.2MB gzip
+145MB uncompressed) or only the [US population data][13] (2.2MB gzip
 compressed, 7.2MB uncompressed).
 
 Up until now, we've kept the code limited to Rust's standard library. For a real
@@ -1512,7 +1512,7 @@ and [`rustc-serialize`](https://crates.io/crates/rustc-serialize) crates.
 
 We're not going to spend a lot of time on setting up a project with
 Cargo because it is already covered well in [the Cargo
-chapter](../book/hello-cargo.html) and [Cargo's documentation][14].
+section](../book/hello-cargo.html) and [Cargo's documentation][14].
 
 To get started from scratch, run `cargo new --bin city-pop` and make sure your
 `Cargo.toml` looks something like this:
@@ -1706,7 +1706,7 @@ compiler can no longer reason about its underlying type.
 
 [Previously](#the-limits-of-combinators) we started refactoring our code by
 changing the type of our function from `T` to `Result<T, OurErrorType>`. In
-this case, `OurErrorType` is just `Box<Error>`. But what's `T`? And can we add
+this case, `OurErrorType` is only `Box<Error>`. But what's `T`? And can we add
 a return type to `main`?
 
 The answer to the second question is no, we can't. That means we'll need to
@@ -1795,6 +1795,10 @@ To convert this to proper error handling, we need to do the following:
 Let's try it:
 
 ```rust,ignore
+use std::error::Error;
+
+// The rest of the code before this is unchanged
+
 fn search<P: AsRef<Path>>
          (file_path: P, city: &str)
          -> Result<Vec<PopulationCount>, Box<Error+Send+Sync>> {
@@ -1903,8 +1907,13 @@ let city = if !matches.free.is_empty() {
        return;
 };
 
-for pop in search(&data_file, &city) {
-       println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
+match search(&data_file, &city) {
+    Ok(pops) => {
+        for pop in pops {
+            println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
+        }
+    }
+    Err(err) => println!("{}", err)
 }
 ...
 ```
@@ -1924,9 +1933,13 @@ parser out of
 But how can we use the same code over both types? There's actually a
 couple ways we could go about this. One way is to write `search` such
 that it is generic on some type parameter `R` that satisfies
-`io::Read`. Another way is to just use trait objects:
+`io::Read`. Another way is to use trait objects:
 
 ```rust,ignore
+use std::io;
+
+// The rest of the code before this is unchanged
+
 fn search<P: AsRef<Path>>
          (file_path: &Option<P>, city: &str)
          -> Result<Vec<PopulationCount>, Box<Error+Send+Sync>> {
@@ -2081,7 +2094,7 @@ opts.optflag("q", "quiet", "Silences errors and warnings.");
 ...
 ```
 
-Now we just need to implement our “quiet” functionality. This requires us to
+Now we only need to implement our “quiet” functionality. This requires us to
 tweak the case analysis in `main`:
 
 ```rust,ignore
@@ -2108,13 +2121,13 @@ handling.
 
 # The Short Story
 
-Since this chapter is long, it is useful to have a quick summary for error
+Since this section is long, it is useful to have a quick summary for error
 handling in Rust. These are some good “rules of thumb." They are emphatically
 *not* commandments. There are probably good reasons to break every one of these
 heuristics!
 
 * If you're writing short example code that would be overburdened by error
-  handling, it's probably just fine to use `unwrap` (whether that's
+  handling, it's probably fine to use `unwrap` (whether that's
   [`Result::unwrap`](../std/result/enum.Result.html#method.unwrap),
   [`Option::unwrap`](../std/option/enum.Option.html#method.unwrap)
   or preferably
index c3896e4e9c55737ad35d2b1d24046c34f54bcb61..5c9e55e549e17ed31f8da87f269e7fcbc0fabdec 100644 (file)
@@ -367,7 +367,7 @@ artifact.
 A few examples of how this model can be used are:
 
 * A native build dependency. Sometimes some C/C++ glue is needed when writing
-  some Rust code, but distribution of the C/C++ code in a library format is just
+  some Rust code, but distribution of the C/C++ code in a library format is
   a burden. In this case, the code will be archived into `libfoo.a` and then the
   Rust crate would declare a dependency via `#[link(name = "foo", kind =
   "static")]`.
@@ -490,7 +490,7 @@ interoperating with the target's libraries. For example, on win32 with a x86
 architecture, this means that the abi used would be `stdcall`. On x86_64,
 however, windows uses the `C` calling convention, so `C` would be used. This
 means that in our previous example, we could have used `extern "system" { ... }`
-to define a block for all windows systems, not just x86 ones.
+to define a block for all windows systems, not only x86 ones.
 
 # Interoperability with foreign code
 
index 84cea5dabc3b528edacdcb1be014dbe821e8d235..be905599c64415684110f730bd1e4e3ec0149646 100644 (file)
@@ -124,7 +124,7 @@ statement `x + 1;` doesn’t return a value. There are two kinds of statements i
 Rust: ‘declaration statements’ and ‘expression statements’. Everything else is
 an expression. Let’s talk about declaration statements first.
 
-In some languages, variable bindings can be written as expressions, not just
+In some languages, variable bindings can be written as expressions, not
 statements. Like Ruby:
 
 ```ruby
@@ -145,7 +145,7 @@ Note that assigning to an already-bound variable (e.g. `y = 5`) is still an
 expression, although its value is not particularly useful. Unlike other
 languages where an assignment evaluates to the assigned value (e.g. `5` in the
 previous example), in Rust the value of an assignment is an empty tuple `()`
-because the assigned value can have [just one owner](ownership.html), and any
+because the assigned value can have [only one owner](ownership.html), and any
 other returned value would be too surprising:
 
 ```rust
index 347c1f5757c62e041740557d5535da9e37ead042..9ab601419cd7cc1e08ce130232aed9f923aff89b 100644 (file)
@@ -37,7 +37,7 @@ let x: Option<f64> = Some(5);
 // found `core::option::Option<_>` (expected f64 but found integral variable)
 ```
 
-That doesn’t mean we can’t make `Option<T>`s that hold an `f64`! They just have
+That doesn’t mean we can’t make `Option<T>`s that hold an `f64`! They have
 to match up:
 
 ```rust
@@ -118,7 +118,7 @@ let float_origin = Point { x: 0.0, y: 0.0 };
 Similar to functions, the `<T>` is where we declare the generic parameters,
 and we then use `x: T` in the type declaration, too.
 
-When you want to add an implementation for the generic `struct`, you just
+When you want to add an implementation for the generic `struct`, you
 declare the type parameter after the `impl`:
 
 ```rust
index 17fc5d9233d195cf9be1b94a9ed1ca7598e4eda2..f72737566a493a7dccfec64ca79eda27cffd41d6 100644 (file)
@@ -1,13 +1,13 @@
 % Getting Started
 
-This first section of the book will get us going with Rust and its tooling.
+This first chapter of the book will get us going with Rust and its tooling.
 First, we’ll install Rust. Then, the classic ‘Hello World’ program. Finally,
 we’ll talk about Cargo, Rust’s build system and package manager.
 
 # Installing Rust
 
 The first step to using Rust is to install it. Generally speaking, you’ll need
-an Internet connection to run the commands in this chapter, as we’ll be
+an Internet connection to run the commands in this section, as we’ll be
 downloading Rust from the internet.
 
 We’ll be showing off a number of commands using a terminal, and those lines all
@@ -140,7 +140,7 @@ If you're on Windows, please download the appropriate [installer][install-page].
 
 ## Uninstalling
 
-Uninstalling Rust is as easy as installing it. On Linux or Mac, just run
+Uninstalling Rust is as easy as installing it. On Linux or Mac, run
 the uninstall script:
 
 ```bash
@@ -192,7 +192,7 @@ that tradition.
 
 The nice thing about starting with such a simple program is that you can
 quickly verify that your compiler is installed, and that it's working properly.
-Printing information to the screen is also just a pretty common thing to do, so
+Printing information to the screen is also a pretty common thing to do, so
 practicing it early on is good.
 
 > Note: This book assumes basic familiarity with the command line. Rust itself
@@ -248,7 +248,7 @@ $ ./main
 Hello, world!
 ```
 
-In Windows, just replace `main` with `main.exe`. Regardless of your operating
+In Windows, replace `main` with `main.exe`. Regardless of your operating
 system, you should see the string `Hello, world!` print to the terminal. If you
 did, then congratulations! You've officially written a Rust program. That makes
 you a Rust programmer! Welcome.
@@ -289,7 +289,7 @@ that it’s indented with four spaces, not tabs.
 The second important part is the `println!()` line. This is calling a Rust
 *[macro]*, which is how metaprogramming is done in Rust. If it were calling a
 function instead, it would look like this: `println()` (without the !). We'll
-discuss Rust macros in more detail later, but for now you just need to
+discuss Rust macros in more detail later, but for now you only need to
 know that when you see a `!` that means that you’re calling a macro instead of
 a normal function.
 
@@ -303,10 +303,10 @@ prints the string to the screen. Easy enough!
 
 [statically allocated]: the-stack-and-the-heap.html
 
-The line ends with a semicolon (`;`). Rust is an *[expression oriented]*
-language, which means that most things are expressions, rather than statements.
-The `;` indicates that this expression is over, and the next one is ready to
-begin. Most lines of Rust code end with a `;`.
+The line ends with a semicolon (`;`). Rust is an *[expression-oriented
+language]*, which means that most things are expressions, rather than
+statements. The `;` indicates that this expression is over, and the next one is
+ready to begin. Most lines of Rust code end with a `;`.
 
 [expression-oriented language]: glossary.html#expression-oriented-language
 
@@ -456,7 +456,7 @@ authors = [ "Your name <you@example.com>" ]
 
 The first line, `[package]`, indicates that the following statements are
 configuring a package. As we add more information to this file, we’ll add other
-sections, but for now, we just have the package configuration.
+sections, but for now, we only have the package configuration.
 
 The other three lines set the three bits of configuration that Cargo needs to
 know to compile your program: its name, what version it is, and who wrote it.
@@ -507,7 +507,7 @@ rebuilds your project if they’ve changed since the last time you built it.
 With simple projects, Cargo doesn't bring a whole lot over just using `rustc`,
 but it will become useful in future. With complex projects composed of multiple
 crates, it’s much easier to let Cargo coordinate the build. With Cargo, you can
-just run `cargo build`, and it should work the right way.
+run `cargo build`, and it should work the right way.
 
 ## Building for Release
 
index 323bcbc95033ccd98e984949935bcfedb03a8340..2e315333565c743a375e48eb59bdae8737b22c59 100644 (file)
@@ -7,7 +7,7 @@ prompt us to enter a guess. Upon entering our guess, it will tell us if we’re
 too low or too high. Once we guess correctly, it will congratulate us. Sounds
 good?
 
-Along the way, we’ll learn a little bit about Rust. The next section, ‘Syntax
+Along the way, we’ll learn a little bit about Rust. The next chapter, ‘Syntax
 and Semantics’, will dive deeper into each part.
 
 # Set up
@@ -68,7 +68,7 @@ Hello, world!
 ```
 
 Great! The `run` command comes in handy when you need to rapidly iterate on a
-project. Our game is just such a project, we need to quickly test each
+project. Our game is such a project, we need to quickly test each
 iteration before moving on to the next one.
 
 # Processing a Guess
@@ -294,12 +294,12 @@ src/main.rs:10     io::stdin().read_line(&mut guess);
 Rust warns us that we haven’t used the `Result` value. This warning comes from
 a special annotation that `io::Result` has. Rust is trying to tell you that
 you haven’t handled a possible error. The right way to suppress the error is
-to actually write error handling. Luckily, if we just want to crash if there’s
+to actually write error handling. Luckily, if we want to crash if there’s
 a problem, we can use these two little methods. If we can recover from the
 error somehow, we’d do something else, but we’ll save that for a future
 project.
 
-There’s just one line of this first example left:
+There’s only one line of this first example left:
 
 ```rust,ignore
     println!("You guessed: {}", guess);
@@ -408,7 +408,7 @@ $ cargo build
 That’s right, no output! Cargo knows that our project has been built, and that
 all of its dependencies are built, and so there’s no reason to do all that
 stuff. With nothing to do, it simply exits. If we open up `src/main.rs` again,
-make a trivial change, and then save it again, we’ll just see one line:
+make a trivial change, and then save it again, we’ll only see one line:
 
 ```bash
 $ cargo build
@@ -504,7 +504,7 @@ so we need `1` and `101` to get a number ranging from one to a hundred.
 
 [concurrency]: concurrency.html
 
-The second line just prints out the secret number. This is useful while
+The second line prints out the secret number. This is useful while
 we’re developing our program, so we can easily test it out. But we’ll be
 deleting it for the final version. It’s not much of a game if it prints out
 the answer when you start it up!
@@ -705,7 +705,7 @@ input in it. The `trim()` method on `String`s will eliminate any white space at
 the beginning and end of our string. This is important, as we had to press the
 ‘return’ key to satisfy `read_line()`. This means that if we type `5` and hit
 return, `guess` looks like this: `5\n`. The `\n` represents ‘newline’, the
-enter key. `trim()` gets rid of this, leaving our string with just the `5`. The
+enter key. `trim()` gets rid of this, leaving our string with only the `5`. The
 [`parse()` method on strings][parse] parses a string into some kind of number.
 Since it can parse a variety of numbers, we need to give Rust a hint as to the
 exact type of number we want. Hence, `let guess: u32`. The colon (`:`) after
@@ -853,8 +853,8 @@ fn main() {
 
 By adding the `break` line after the `You win!`, we’ll exit the loop when we
 win. Exiting the loop also means exiting the program, since it’s the last
-thing in `main()`. We have just one more tweak to make: when someone inputs a
-non-number, we don’t want to quit, we just want to ignore it. We can do that
+thing in `main()`. We have only one more tweak to make: when someone inputs a
+non-number, we don’t want to quit, we want to ignore it. We can do that
 like this:
 
 ```rust,ignore
@@ -908,12 +908,12 @@ let guess: u32 = match guess.trim().parse() {
 ```
 
 This is how you generally move from ‘crash on error’ to ‘actually handle the
-returned by `parse()` is an `enum` just like `Ordering`, but in this case, each
+returned by `parse()` is an `enum`  like `Ordering`, but in this case, each
 variant has some data associated with it: `Ok` is a success, and `Err` is a
 failure. Each contains more information: the successfully parsed integer, or an
 error type. In this case, we `match` on `Ok(num)`, which sets the inner value
-of the `Ok` to the name `num`, and then we just return it on the right-hand
-side. In the `Err` case, we don’t care what kind of error it is, so we just
+of the `Ok` to the name `num`, and then we  return it on the right-hand
+side. In the `Err` case, we don’t care what kind of error it is, so we
 use `_` instead of a name. This ignores the error, and `continue` causes us
 to go to the next iteration of the `loop`.
 
index c444f9f2fe53d420e5cbae1bbb63007e2c51d965..5622326d20c31913323f7001e940afaa155c080d 100644 (file)
@@ -37,7 +37,7 @@ which gives us a reference to the next value of the iterator. `next` returns an
 `None`, we `break` out of the loop.
 
 This code sample is basically the same as our `for` loop version. The `for`
-loop is just a handy way to write this `loop`/`match`/`break` construct.
+loop is a handy way to write this `loop`/`match`/`break` construct.
 
 `for` loops aren't the only thing that uses iterators, however. Writing your
 own iterator involves implementing the `Iterator` trait. While doing that is
@@ -94,8 +94,8 @@ Now we're explicitly dereferencing `num`. Why does `&nums` give us
 references?  Firstly, because we explicitly asked it to with
 `&`. Secondly, if it gave us the data itself, we would have to be its
 owner, which would involve making a copy of the data and giving us the
-copy. With references, we're just borrowing a reference to the data,
-and so it's just passing a reference, without needing to do the move.
+copy. With references, we're only borrowing a reference to the data,
+and so it's only passing a reference, without needing to do the move.
 
 So, now that we've established that ranges are often not what you want, let's
 talk about what you do want instead.
@@ -278,7 +278,7 @@ doesn't print any numbers:
 ```
 
 If you are trying to execute a closure on an iterator for its side effects,
-just use `for` instead.
+use `for` instead.
 
 There are tons of interesting iterator adaptors. `take(n)` will return an
 iterator over the next `n` elements of the original iterator. Let's try it out
index 1a02bc95e9d9c84247ff01c674415697457a0b04..7be7fa4f039a710dece1e34f1507f17757bbc286 100644 (file)
@@ -1,6 +1,6 @@
 % Learn Rust
 
-Welcome! This section has a few tutorials that teach you Rust through building
+Welcome! This chapter has a few tutorials that teach you Rust through building
 projects. You’ll get a high-level overview, but we’ll skim over the details.
 
 If you’d prefer a more ‘from the ground up’-style experience, check
index 2d418786e9a1ecbdced56712107249c77c91a714..8bf90b4ea4d8a882a36ef34b8fe603cb79f1f246 100644 (file)
@@ -84,7 +84,7 @@ We previously talked a little about [function syntax][functions], but we didn’
 discuss the `<>`s after a function’s name. A function can have ‘generic
 parameters’ between the `<>`s, of which lifetimes are one kind. We’ll discuss
 other kinds of generics [later in the book][generics], but for now, let’s
-just focus on the lifetimes aspect.
+focus on the lifetimes aspect.
 
 [functions]: functions.html
 [generics]: generics.html
@@ -109,7 +109,7 @@ If we wanted a `&mut` reference, we’d do this:
 ...(x: &'a mut i32)
 ```
 
-If you compare `&mut i32` to `&'a mut i32`, they’re the same, it’s just that
+If you compare `&mut i32` to `&'a mut i32`, they’re the same, it’s that
 the lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut
 i32` as ‘a mutable reference to an `i32`’ and `&'a mut i32` as ‘a mutable
 reference to an `i32` with the lifetime `'a`’.
@@ -175,7 +175,7 @@ fn main() {
 ```
 
 As you can see, we need to declare a lifetime for `Foo` in the `impl` line. We repeat
-`'a` twice, just like on functions: `impl<'a>` defines a lifetime `'a`, and `Foo<'a>`
+`'a` twice, like on functions: `impl<'a>` defines a lifetime `'a`, and `Foo<'a>`
 uses it.
 
 ## Multiple lifetimes
index 41c134b29f3d18109ba3089cd941ce6072c979d9..b2532663339ff26aa1d7d6103b64359ddf25270e 100644 (file)
@@ -49,11 +49,11 @@ and inside it, define a method, `area`.
 Methods take a special first parameter, of which there are three variants:
 `self`, `&self`, and `&mut self`. You can think of this first parameter as
 being the `foo` in `foo.bar()`. The three variants correspond to the three
-kinds of things `foo` could be: `self` if it’s just a value on the stack,
+kinds of things `foo` could be: `self` if it’s a value on the stack,
 `&self` if it’s a reference, and `&mut self` if it’s a mutable reference.
-Because we took the `&self` parameter to `area`, we can use it just like any
+Because we took the `&self` parameter to `area`, we can use it like any
 other parameter. Because we know it’s a `Circle`, we can access the `radius`
-just like we would with any other `struct`.
+like we would with any other `struct`.
 
 We should default to using `&self`, as you should prefer borrowing over taking
 ownership, as well as taking immutable references over mutable ones. Here’s an
@@ -151,7 +151,7 @@ fn grow(&self, increment: f64) -> Circle {
 # Circle } }
 ```
 
-We just say we’re returning a `Circle`. With this method, we can grow a new
+We say we’re returning a `Circle`. With this method, we can grow a new
 `Circle` to any arbitrary size.
 
 # Associated functions
index 0578fbf8bdb09286f768f6b617aeedab63b23480..b3be71038a992f66605f461c14f5888b708a6c5d 100644 (file)
@@ -39,7 +39,7 @@ script:
 $ sudo /usr/local/lib/rustlib/uninstall.sh
 ```
 
-If you used the Windows installer, just re-run the `.msi` and it will give you
+If you used the Windows installer, re-run the `.msi` and it will give you
 an uninstall option.
 
 Some people, and somewhat rightfully so, get very upset when we tell you to
@@ -66,7 +66,7 @@ Finally, a comment about Windows. Rust considers Windows to be a first-class
 platform upon release, but if we're honest, the Windows experience isn't as
 integrated as the Linux/OS X experience is. We're working on it! If anything
 does not work, it is a bug. Please let us know if that happens. Each and every
-commit is tested against Windows just like any other platform.
+commit is tested against Windows like any other platform.
 
 If you've got Rust installed, you can open up a shell, and type this:
 
index da84c6a337416ed2bfbd5f63143efe46101adca9..65beaed2fc7e9a563ab08dd926b45b5efa9e831d 100644 (file)
@@ -1,8 +1,15 @@
 % No stdlib
 
-By default, `std` is linked to every Rust crate. In some contexts,
-this is undesirable, and can be avoided with the `#![no_std]`
-attribute attached to the crate.
+Rust’s standard library provides a lot of useful functionality, but assumes
+support for various features of its host system: threads, networking, heap
+allocation, and others. There are systems that do not have these features,
+however, and Rust can work with those too! To do so, we tell Rust that we
+don’t want to use the standard library via an attribute: `#![no_std]`.
+
+> Note: This feature is technically stable, but there are some caveats. For
+> one, you can build a `#![no_std]` _library_ on stable, but not a _binary_.
+> For details on libraries without the standard library, see [the chapter on
+> `#![no_std]`](using-rust-without-the-standard-library.html)
 
 Obviously there's more to life than just libraries: one can use
 `#[no_std]` with an executable, controlling the entry point is
@@ -77,89 +84,3 @@ personality function (see the
 information), but crates which do not trigger a panic can be assured
 that this function is never called. The second function, `panic_fmt`, is
 also used by the failure mechanisms of the compiler.
-
-## Using libcore
-
-> **Note**: the core library's structure is unstable, and it is recommended to
-> use the standard library instead wherever possible.
-
-With the above techniques, we've got a bare-metal executable running some Rust
-code. There is a good deal of functionality provided by the standard library,
-however, that is necessary to be productive in Rust. If the standard library is
-not sufficient, then [libcore](../core/index.html) is designed to be used
-instead.
-
-The core library has very few dependencies and is much more portable than the
-standard library itself. Additionally, the core library has most of the
-necessary functionality for writing idiomatic and effective Rust code. When
-using `#![no_std]`, Rust will automatically inject the `core` crate, just like
-we do for `std` when we’re using it.
-
-As an example, here is a program that will calculate the dot product of two
-vectors provided from C, using idiomatic Rust practices.
-
-```rust
-# #![feature(libc)]
-#![feature(lang_items)]
-#![feature(start)]
-#![feature(raw)]
-#![no_std]
-
-extern crate libc;
-
-use core::mem;
-
-#[no_mangle]
-pub extern fn dot_product(a: *const u32, a_len: u32,
-                          b: *const u32, b_len: u32) -> u32 {
-    use core::raw::Slice;
-
-    // Convert the provided arrays into Rust slices.
-    // The core::raw module guarantees that the Slice
-    // structure has the same memory layout as a &[T]
-    // slice.
-    //
-    // This is an unsafe operation because the compiler
-    // cannot tell the pointers are valid.
-    let (a_slice, b_slice): (&[u32], &[u32]) = unsafe {
-        mem::transmute((
-            Slice { data: a, len: a_len as usize },
-            Slice { data: b, len: b_len as usize },
-        ))
-    };
-
-    // Iterate over the slices, collecting the result
-    let mut ret = 0;
-    for (i, j) in a_slice.iter().zip(b_slice.iter()) {
-        ret += (*i) * (*j);
-    }
-    return ret;
-}
-
-#[lang = "panic_fmt"]
-extern fn panic_fmt(args: &core::fmt::Arguments,
-                    file: &str,
-                    line: u32) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"] extern fn eh_personality() {}
-# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 }
-# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
-# #[no_mangle] pub extern fn rust_eh_register_frames () {}
-# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
-# fn main() {}
-```
-
-Note that there is one lang item here whose signature differs from the examples
-above, `panic_fmt`. This must be defined by consumers of libcore because the
-core library declares panics, but it does not define it. The `panic_fmt`
-lang item is this crate's definition of panic, and it must be guaranteed to
-never return.
-
-As can be seen in this example, the core library is intended to provide the
-power of Rust in all circumstances, regardless of platform requirements. Further
-libraries, such as liballoc, add functionality to libcore which make other
-platform-specific assumptions, but continue to be more portable than the
-standard library itself.
-
index e53664eeb552662e2b0e4a17aafd17dea37c2adb..fcce831c2d09d23d3ebe8dc0c270bb1f276b5700 100644 (file)
@@ -120,7 +120,7 @@ fn main() {
 }
 ```
 
-For `HasArea` and `Square`, we just declare a type parameter `T` and replace
+For `HasArea` and `Square`, we declare a type parameter `T` and replace
 `f64` with it. The `impl` needs more involved modifications:
 
 ```ignore
index 17b263ef00ab786ea2f72a914724d64bea5b42ca..a62d31d362b14f217c367efbfe76779167dd1ded 100644 (file)
@@ -51,15 +51,24 @@ fn foo() {
 }
 ```
 
-When `v` comes into scope, a new [`Vec<T>`][vect] is created. In this case, the
-vector also allocates space on [the heap][heap], for the three elements. When
-`v` goes out of scope at the end of `foo()`, Rust will clean up everything
-related to the vector, even the heap-allocated memory. This happens
-deterministically, at the end of the scope.
+When `v` comes into scope, a new [vector] is created, and it allocates space on
+[the heap][heap] for each of its elements. When `v` goes out of scope at the
+end of `foo()`, Rust will clean up everything related to the vector, even the
+heap-allocated memory. This happens deterministically, at the end of the scope.
 
-[vect]: ../std/vec/struct.Vec.html
+We'll cover [vectors] in detail later in this chapter; we only use them
+here as an example of a type that allocates space on the heap at runtime. They
+behave like [arrays], except their size may change by `push()`ing more
+elements onto them.
+
+Vectors have a [generic type][generics] `Vec<T>`, so in this example `v` will have type
+`Vec<i32>`. We'll cover generics in detail later in this chapter.
+
+[arrays]: primitive-types.html#arrays
+[vectors]: vectors.html
 [heap]: the-stack-and-the-heap.html
 [bindings]: variable-bindings.html
+[generics]: generics.html
 
 # Move semantics
 
index 43f1bd2529fd2c85e7455f1e7cdfeaa233c56f04..8e9e7246e56f0b3daa935be46250aec061c449bf 100644 (file)
@@ -118,7 +118,7 @@ match origin {
 
 This prints `x is 0`.
 
-You can do this kind of match on any member, not just the first:
+You can do this kind of match on any member, not only the first:
 
 ```rust
 struct Point {
@@ -155,7 +155,7 @@ match some_value {
 ```
 
 In the first arm, we bind the value inside the `Ok` variant to `value`. But
-in the `Err` arm, we use `_` to disregard the specific error, and just print
+in the `Err` arm, we use `_` to disregard the specific error, and print
 a general error message.
 
 `_` is valid in any pattern that creates a binding. This can be useful to
@@ -326,7 +326,7 @@ match x {
 ```
 
 This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to
-just the `5`. In other words, the precedence of `if` behaves like this:
+only the `5`. In other words, the precedence of `if` behaves like this:
 
 ```text
 (4 | 5) if y => ...
index a8c7a7d41573e4fa565a264cf829bc451f2e1b20..cfd5372b90f91f92f19a60c84e5c972d2e349363 100644 (file)
@@ -160,20 +160,23 @@ documentation][array].
 
 A ‘slice’ is a reference to (or “view” into) another data structure. They are
 useful for allowing safe, efficient access to a portion of an array without
-copying. For example, you might want to reference just one line of a file read
+copying. For example, you might want to reference only one line of a file read
 into memory. By nature, a slice is not created directly, but from an existing
 variable binding. Slices have a defined length, can be mutable or immutable.
 
 ## Slicing syntax
 
 You can use a combo of `&` and `[]` to create a slice from various things. The
-`&` indicates that slices are similar to references, and the `[]`s, with a
-range, let you define the length of the slice:
+`&` indicates that slices are similar to [references], which we will cover in
+detail later in this section. The `[]`s, with a range, let you define the
+length of the slice:
+
+[references]: references-and-borrowing.html
 
 ```rust
 let a = [0, 1, 2, 3, 4];
 let complete = &a[..]; // A slice containing all of the elements in a
-let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
+let middle = &a[1..4]; // A slice of a: only the elements 1, 2, and 3
 ```
 
 Slices have type `&[T]`. We’ll talk about that `T` when we cover
@@ -189,11 +192,13 @@ documentation][slice].
 # `str`
 
 Rust’s `str` type is the most primitive string type. As an [unsized type][dst],
-it’s not very useful by itself, but becomes useful when placed behind a reference,
-like [`&str`][strings]. As such, we’ll just leave it at that.
+it’s not very useful by itself, but becomes useful when placed behind a
+reference, like `&str`. We'll elaborate further when we cover
+[Strings][strings] and [references].
 
 [dst]: unsized-types.html
 [strings]: strings.html
+[references]: references-and-borrowing.html
 
 You can find more documentation for `str` [in the standard library
 documentation][str].
@@ -215,11 +220,11 @@ with the type annotated:
 let x: (i32, &str) = (1, "hello");
 ```
 
-As you can see, the type of a tuple looks just like the tuple, but with each
+As you can see, the type of a tuple looks like the tuple, but with each
 position having a type name rather than the value. Careful readers will also
 note that tuples are heterogeneous: we have an `i32` and a `&str` in this tuple.
 In systems programming languages, strings are a bit more complex than in other
-languages. For now, just read `&str` as a *string slice*, and we’ll learn more
+languages. For now, read `&str` as a *string slice*, and we’ll learn more
 soon.
 
 You can assign one tuple into another, if they have the same contained types
@@ -244,7 +249,7 @@ println!("x is {}", x);
 ```
 
 Remember [before][let] when I said the left-hand side of a `let` statement was more
-powerful than just assigning a binding? Here we are. We can put a pattern on
+powerful than assigning a binding? Here we are. We can put a pattern on
 the left-hand side of the `let`, and if it matches up to the right-hand side,
 we can assign multiple bindings at once. In this case, `let` “destructures”
 or “breaks up” the tuple, and assigns the bits to three bindings.
index a172390a02126a6a4ffde7c15b72594b0fdc57fd..e7faf174600a9381b040c6c03d9deba9476f7774 100644 (file)
@@ -84,7 +84,7 @@ it borrows ownership. A binding that borrows something does not deallocate the
 resource when it goes out of scope. This means that after the call to `foo()`,
 we can use our original bindings again.
 
-References are immutable, just like bindings. This means that inside of `foo()`,
+References are immutable, like bindings. This means that inside of `foo()`,
 the vectors can’t be changed at all:
 
 ```rust,ignore
@@ -129,7 +129,7 @@ You'll also notice we added an asterisk (`*`) in front of `y`, making it `*y`,
 this is because `y` is a `&mut` reference. You'll also need to use them for
 accessing the contents of a reference as well.
 
-Otherwise, `&mut` references are just like references. There _is_ a large
+Otherwise, `&mut` references are like references. There _is_ a large
 difference between the two, and how they interact, though. You can tell
 something is fishy in the above example, because we need that extra scope, with
 the `{` and `}`. If we remove them, we get an error:
index 42a0acd21a2a0a0aeb19a8f2969db3b562453017..751619d544a4af57746c31b0acf734bd6dab6adf 100644 (file)
@@ -44,7 +44,7 @@ let s = "foo\
 assert_eq!("foobar", s);
 ```
 
-Rust has more than just `&str`s though. A `String`, is a heap-allocated string.
+Rust has more than only `&str`s though. A `String`, is a heap-allocated string.
 This string is growable, and is also guaranteed to be UTF-8. `String`s are
 commonly created by converting from a string slice using the `to_string`
 method.
index 75d0093b1476aff74063c962b05372672199b907..b2fddf336273fe0d1f3d663e7bd09886579e41fb 100644 (file)
@@ -202,7 +202,7 @@ println!("length is {} inches", integer_length);
 ```
 
 As you can see here, you can extract the inner integer type through a
-destructuring `let`, just as with regular tuples. In this case, the
+destructuring `let`, as with regular tuples. In this case, the
 `let Inches(integer_length)` assigns `10` to `integer_length`.
 
 # Unit-like structs
@@ -223,7 +223,7 @@ This is rarely useful on its own (although sometimes it can serve as a
 marker type), but in combination with other features, it can become
 useful. For instance, a library may ask you to create a structure that
 implements a certain [trait][trait] to handle events. If you don’t have
-any data you need to store in the structure, you can just create a
+any data you need to store in the structure, you can create a
 unit-like `struct`.
 
 [trait]: traits.html
index cce985c9e484c1436179e5773e396b47a35ecad4..e9ec26dccdcdcb4c934bcf112f4ddc73445920ba 100644 (file)
@@ -1,6 +1,6 @@
 % Syntax and Semantics
 
-This section breaks Rust down into small chunks, one for each concept.
+This chapter breaks Rust down into small chunks, one for each concept.
 
 If you’d like to learn Rust from the bottom up, reading this in order is a
 great way to do that.
index 561cc3ab2d11323069894172832acc9f24b6c53b..005184e90a7e96a8e86205d38ffeb132b860420d 100644 (file)
@@ -365,7 +365,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
 It works!
 
 The current convention is to use the `tests` module to hold your "unit-style"
-tests. Anything that just tests one small bit of functionality makes sense to
+tests. Anything that tests one small bit of functionality makes sense to
 go here. But what about "integration-style" tests instead? For that, we have
 the `tests` directory.
 
index bc40eeb8dccfbc4ce2fddaaac07971e2bf91abcd..a7b6faccd8d6e01bac21c0e22c8e6c3a7e9bf36a 100644 (file)
@@ -44,7 +44,7 @@ values ‘go on the stack’. What does that mean?
 Well, when a function gets called, some memory gets allocated for all of its
 local variables and some other information. This is called a ‘stack frame’, and
 for the purpose of this tutorial, we’re going to ignore the extra information
-and just consider the local variables we’re allocating. So in this case, when
+and only consider the local variables we’re allocating. So in this case, when
 `main()` is run, we’ll allocate a single 32-bit integer for our stack frame.
 This is automatically handled for you, as you can see; we didn’t have to write
 any special Rust code or anything.
@@ -177,7 +177,7 @@ And then `bold()` calls `italic()`:
 | 0       | x    | 42    |
 Whew! Our stack is growing tall.
 
-After `italic()` is over, its frame is deallocated, leaving just `bold()` and
+After `italic()` is over, its frame is deallocated, leaving only `bold()` and
 `main()`:
 
 | Address | Name | Value |
@@ -185,9 +185,9 @@ After `italic()` is over, its frame is deallocated, leaving just `bold()` and
 | **3**   | **c**|**1**  |
 | **2**   | **b**|**100**|
 | **1**   | **a**| **5** |
-| 0       | x    | 42    | 
+| 0       | x    | 42    |
 
-And then `bold()` ends, leaving just `main()`:
+And then `bold()` ends, leaving only `main()`:
 
 | Address | Name | Value |
 |---------|------|-------|
@@ -247,7 +247,7 @@ location we’ve asked for.
 We haven’t really talked too much about what it actually means to allocate and
 deallocate memory in these contexts. Getting into very deep detail is out of
 the scope of this tutorial, but what’s important to point out here is that
-the heap isn’t just a stack that grows from the opposite end. We’ll have an
+the heap isn’t a stack that grows from the opposite end. We’ll have an
 example of this later in the book, but because the heap can be allocated and
 freed in any order, it can end up with ‘holes’. Here’s a diagram of the memory
 layout of a program which has been running for a while now:
@@ -332,13 +332,13 @@ What about when we call `foo()`, passing `y` as an argument?
 | 1       | y    | → 0    |
 | 0       | x    | 5      |
 
-Stack frames aren’t just for local bindings, they’re for arguments too. So in
+Stack frames aren’t only for local bindings, they’re for arguments too. So in
 this case, we need to have both `i`, our argument, and `z`, our local variable
 binding. `i` is a copy of the argument, `y`. Since `y`’s value is `0`, so is
 `i`’s.
 
 This is one reason why borrowing a variable doesn’t deallocate any memory: the
-value of a reference is just a pointer to a memory location. If we got rid of
+value of a reference is a pointer to a memory location. If we got rid of
 the underlying memory, things wouldn’t work very well.
 
 # A complex example
@@ -454,7 +454,7 @@ Next, `foo()` calls `bar()` with `x` and `z`:
 | 0                    | h    | 3                      |
 
 We end up allocating another value on the heap, and so we have to subtract one
-from (2<sup>30</sup>) - 1. It’s easier to just write that than `1,073,741,822`. In any
+from (2<sup>30</sup>) - 1. It’s easier to write that than `1,073,741,822`. In any
 case, we set up the variables as usual.
 
 At the end of `bar()`, it calls `baz()`:
@@ -550,12 +550,12 @@ has two big impacts: runtime efficiency and semantic impact.
 
 ## Runtime Efficiency
 
-Managing the memory for the stack is trivial: The machine just
+Managing the memory for the stack is trivial: The machine
 increments or decrements a single value, the so-called “stack pointer”.
 Managing memory for the heap is non-trivial: heap-allocated memory is freed at
 arbitrary points, and each block of heap-allocated memory can be of arbitrary
-size, the memory manager must generally work much harder to identify memory for
-reuse.
+size, so the memory manager must generally work much harder to
+identify memory for reuse.
 
 If you’d like to dive into this topic in greater detail, [this paper][wilson]
 is a great introduction.
@@ -579,4 +579,3 @@ comes at the cost of either significant runtime support (e.g. in the form of a
 garbage collector) or significant programmer effort (in the form of explicit
 memory management calls that require verification not provided by the Rust
 compiler).
-
index 8127b0898c46fe4508d8fcb2cf6f1f0a1f7603d1..1d63435ed5fe71d3d3da89cf7384341082cf3faf 100644 (file)
@@ -272,7 +272,7 @@ made more flexible.
 
 Suppose we’ve got some values that implement `Foo`. The explicit form of
 construction and use of `Foo` trait objects might look a bit like (ignoring the
-type mismatches: they’re all just pointers anyway):
+type mismatches: they’re all pointers anyway):
 
 ```rust,ignore
 let a: String = "foo".to_string();
index f9e3299f9e726c2d4db86c2a6ca1b37fc219ea24..d40689190e7fef4ca038d359983bf11af33ab41c 100644 (file)
@@ -44,8 +44,8 @@ impl HasArea for Circle {
 ```
 
 As you can see, the `trait` block looks very similar to the `impl` block,
-but we don’t define a body, just a type signature. When we `impl` a trait,
-we use `impl Trait for Item`, rather than just `impl Item`.
+but we don’t define a body, only a type signature. When we `impl` a trait,
+we use `impl Trait for Item`, rather than only `impl Item`.
 
 ## Trait bounds on generic functions
 
index 1b223365bd63ac72a15c072fc79da5a5ec3967d9..ecd196a9f0d1fe5b3b79b4f3b54dd7d8df892ed9 100644 (file)
@@ -41,8 +41,8 @@ unsafe impl Scary for i32 {}
 ```
 
 It’s important to be able to explicitly delineate code that may have bugs that
-cause big problems. If a Rust program segfaults, you can be sure it’s somewhere
-in the sections marked `unsafe`.
+cause big problems. If a Rust program segfaults, you can be sure the cause is
+related to something marked `unsafe`.
 
 # What does ‘safe’ mean?
 
@@ -100,7 +100,7 @@ that you normally can not do. Just three. Here they are:
 
 That’s it. It’s important that `unsafe` does not, for example, ‘turn off the
 borrow checker’. Adding `unsafe` to some random Rust code doesn’t change its
-semantics, it won’t just start accepting anything. But it will let you write
+semantics, it won’t start accepting anything. But it will let you write
 things that _do_ break some of the rules.
 
 You will also encounter the `unsafe` keyword when writing bindings to foreign
index b1a2bb5d4172f16ef56e7279ac7ed8dba2d46b3d..73b90355e4f1b0331a89e89f0c10bbdc632d619b 100644 (file)
@@ -11,7 +11,7 @@ Rust understands a few of these types, but they have some restrictions. There
 are three:
 
 1. We can only manipulate an instance of an unsized type via a pointer. An
-   `&[T]` works just fine, but a `[T]` does not.
+   `&[T]` works fine, but a `[T]` does not.
 2. Variables and arguments cannot have dynamically sized types.
 3. Only the last field in a `struct` may have a dynamically sized type; the
    other fields must not. Enum variants must not have dynamically sized types as
diff --git a/src/doc/book/using-rust-without-the-standard-library.md b/src/doc/book/using-rust-without-the-standard-library.md
new file mode 100644 (file)
index 0000000..59182e1
--- /dev/null
@@ -0,0 +1,41 @@
+% Using Rust Without the Standard Library
+
+Rust’s standard library provides a lot of useful functionality, but assumes
+support for various features of its host system: threads, networking, heap
+allocation, and others. There are systems that do not have these features,
+however, and Rust can work with those too! To do so, we tell Rust that we
+don’t want to use the standard library via an attribute: `#![no_std]`.
+
+> Note: This feature is technically stable, but there are some caveats. For
+> one, you can build a `#![no_std]` _library_ on stable, but not a _binary_.
+> For details on binaries without the standard library, see [the nightly
+> chapter on `#![no_std]`](no-stdlib.html)
+
+To use `#![no_std]`, add a it to your crate root:
+
+```rust
+#![no_std]
+
+fn plus_one(x: i32) -> i32 {
+    x + 1
+}
+```
+
+Much of the functionality that’s exposed in the standard library is also
+available via the [`core` crate](../core/). When we’re using the standard
+library, Rust automatically brings `std` into scope, allowing you to use
+its features without an explicit import. By the same token, when using
+`!#[no_std]`, Rust will bring `core` into scope for you, as well as [its
+prelude](../core/prelude/v1/). This means that a lot of code will Just Work:
+
+```rust
+#![no_std]
+
+fn may_fail(failure: bool) -> Result<(), &'static str> {
+    if failure {
+        Err("this didn’t work!")
+    } else {
+        Ok(())
+    }
+}
+```
index f3a5d1dd886c82b86538372b525f35da1c8ebff7..29b59937a63fa6b4bf3d93dc230abe160102c662 100644 (file)
@@ -2,7 +2,7 @@
 
 Virtually every non-'Hello World’ Rust program uses *variable bindings*. They
 bind some value to a name, so it can be used later. `let` is
-used to introduce a binding, just like this:
+used to introduce a binding, like this:
 
 ```rust
 fn main() {
@@ -18,7 +18,7 @@ function, rather than leaving it off. Otherwise, you’ll get an error.
 
 In many languages, a variable binding would be called a *variable*, but Rust’s
 variable bindings have a few tricks up their sleeves. For example the
-left-hand side of a `let` expression is a ‘[pattern][pattern]’, not just a
+left-hand side of a `let` expression is a ‘[pattern][pattern]’, not a
 variable name. This means we can do things like:
 
 ```rust
@@ -27,7 +27,7 @@ let (x, y) = (1, 2);
 
 After this expression is evaluated, `x` will be one, and `y` will be two.
 Patterns are really powerful, and have [their own section][pattern] in the
-book. We don’t need those features for now, so we’ll just keep this in the back
+book. We don’t need those features for now, so we’ll keep this in the back
 of our minds as we go forward.
 
 [pattern]: patterns.html
@@ -169,10 +169,10 @@ in the middle of a string." We add a comma, and then `x`, to indicate that we
 want `x` to be the value we’re interpolating. The comma is used to separate
 arguments we pass to functions and macros, if you’re passing more than one.
 
-When you just use the curly braces, Rust will attempt to display the value in a
+When you use the curly braces, Rust will attempt to display the value in a
 meaningful way by checking out its type. If you want to specify the format in a
 more detailed manner, there are a [wide number of options available][format].
-For now, we'll just stick to the default: integers aren't very complicated to
+For now, we'll stick to the default: integers aren't very complicated to
 print.
 
 [format]: ../std/fmt/index.html
index fef9f1f369cee344999a296f9d7a48ae9e33d4c1..f8a1ec134d9242faa877a156868a53dfc5efa110 100644 (file)
@@ -10,12 +10,28 @@ This is an index of the documentation included with the Rust
 compiler. For more comprehensive documentation see [the
 website](https://www.rust-lang.org).
 
-[**The Rust Programming Language**](book/index.html)
+[**The Rust Programming Language**][book]. Also known as "The Book",
+The Rust Programming Language is the most comprehensive resource for
+all topics related to Rust, and is the primary official document of
+the language.
 
-[**The Rust Reference**](reference.html)
+[**The Rust Reference**][ref]. While Rust does not have a
+specification, the reference tries to describe its working in
+detail. It tends to be out of date.
 
-[**The Standard Library API Reference**](std/index.html)
+[**Standard Library API Reference**][api]. Documentation for the
+standard library.
 
-[**The Rustonomicon**](nomicon/index.html)
+[**The Rustonomicon**][nomicon]. An entire book dedicated to
+explaining how to write unsafe Rust code. It is for advanced Rust
+programmers.
+
+[**Compiler Error Index**][err]. Extended explanations of
+the errors produced by the Rust compiler.
+
+[book]: book/index.html
+[ref]: reference.html
+[api]: std/index.html
+[nomicon]: nomicon/index.html
+[err]: error-index.html
 
-[**The Compiler Error Index**](error-index.html)
index 0a37170c52ca34bf39bef5bd96a80dbec6492f1f..bcecd78a1b75a1227b5dbc2c6aeb53dc13612ae9 100644 (file)
@@ -24,7 +24,7 @@ pub fn insert(&mut self, index: usize, elem: T) {
             // ptr::copy(src, dest, len): "copy from source to dest len elems"
             ptr::copy(self.ptr.offset(index as isize),
                       self.ptr.offset(index as isize + 1),
-                      len - index);
+                      self.len - index);
         }
         ptr::write(self.ptr.offset(index as isize), elem);
         self.len += 1;
@@ -44,7 +44,7 @@ pub fn remove(&mut self, index: usize) -> T {
         let result = ptr::read(self.ptr.offset(index as isize));
         ptr::copy(self.ptr.offset(index as isize + 1),
                   self.ptr.offset(index as isize),
-                  len - index);
+                  self.len - index);
         result
     }
 }
index 5f71ee4437958974f7cd250d1737b9e106df7035..b786b59ec986de641ccd7b88d89d7a6ed1ad69b9 100644 (file)
@@ -2044,7 +2044,7 @@ The following configurations must be defined by the implementation:
   production.  For example, it controls the behavior of the standard library's
   `debug_assert!` macro.
 * `target_arch = "..."` - Target CPU architecture, such as `"x86"`, `"x86_64"`
-  `"mips"`, `"powerpc"`, `"arm"`, or `"aarch64"`.
+  `"mips"`, `"powerpc"`, `"powerpc64"`, `"powerpc64le"`, `"arm"`, or `"aarch64"`.
 * `target_endian = "..."` - Endianness of the target CPU, either `"little"` or
   `"big"`.
 * `target_env = ".."` - An option provided by the compiler by default
@@ -3677,10 +3677,10 @@ sites are:
 
 * `let` statements where an explicit type is given.
 
-   For example, `128` is coerced to have type `i8` in the following:
+   For example, `42` is coerced to have type `i8` in the following:
 
    ```rust
-   let _: i8 = 128;
+   let _: i8 = 42;
    ```
 
 * `static` and `const` statements (similar to `let` statements).
@@ -3690,36 +3690,36 @@ sites are:
   The value being coerced is the actual parameter, and it is coerced to
   the type of the formal parameter.
 
-  For example, `128` is coerced to have type `i8` in the following:
+  For example, `42` is coerced to have type `i8` in the following:
 
   ```rust
   fn bar(_: i8) { }
 
   fn main() {
-      bar(128);
+      bar(42);
   }
   ```
 
 * Instantiations of struct or variant fields
 
-  For example, `128` is coerced to have type `i8` in the following:
+  For example, `42` is coerced to have type `i8` in the following:
 
   ```rust
   struct Foo { x: i8 }
 
   fn main() {
-      Foo { x: 128 };
+      Foo { x: 42 };
   }
   ```
 
 * Function results, either the final line of a block if it is not
   semicolon-terminated or any expression in a `return` statement
 
-  For example, `128` is coerced to have type `i8` in the following:
+  For example, `42` is coerced to have type `i8` in the following:
 
   ```rust
   fn foo() -> i8 {
-      128
+      42
   }
   ```
 
index b0140fb24559dc0eca78542ec0b5c9ee6b8ff652..9fdab1fcfca28a33cd35d67731af7a28b40f0f72 100644 (file)
@@ -25,6 +25,7 @@ even larger, and it's already uncomfortably large (6 KiB).
 """
 from __future__ import print_function
 import sys
+from math import ceil, log
 from fractions import Fraction
 from collections import namedtuple
 
@@ -33,7 +34,6 @@ N = 64  # Size of the significand field in bits
 MIN_SIG = 2 ** (N - 1)
 MAX_SIG = (2 ** N) - 1
 
-
 # Hand-rolled fp representation without arithmetic or any other operations.
 # The significand is normalized and always N bit, but the exponent is
 # unrestricted in range.
@@ -92,7 +92,7 @@ def error(f, e, z):
     ulp_err = abs_err / Fraction(2) ** z.exp
     return float(ulp_err)
 
-LICENSE = """
+HEADER = """
 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
@@ -102,9 +102,23 @@ 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.
+
+//! Tables of approximations of powers of ten.
+//! DO NOT MODIFY: Generated by `src/etc/dec2flt_table.py`
 """
 
+
 def main():
+    print(HEADER.strip())
+    print()
+    print_proper_powers()
+    print()
+    print_short_powers(32, 24)
+    print()
+    print_short_powers(64, 53)
+
+
+def print_proper_powers():
     MIN_E = -305
     MAX_E = 305
     e_range = range(MIN_E, MAX_E+1)
@@ -114,13 +128,10 @@ def main():
         err = error(1, e, z)
         assert err < 0.5
         powers.append(z)
-    typ = "([u64; {0}], [i16; {0}])".format(len(e_range))
-    print(LICENSE.strip())
-    print("// Table of approximations of powers of ten.")
-    print("// DO NOT MODIFY: Generated by a src/etc/dec2flt_table.py")
     print("pub const MIN_E: i16 = {};".format(MIN_E))
     print("pub const MAX_E: i16 = {};".format(MAX_E))
     print()
+    typ = "([u64; {0}], [i16; {0}])".format(len(powers))
     print("pub const POWERS: ", typ, " = ([", sep='')
     for z in powers:
         print("    0x{:x},".format(z.sig))
@@ -130,5 +141,17 @@ def main():
     print("]);")
 
 
+def print_short_powers(num_bits, significand_size):
+    max_sig = 2**significand_size - 1
+    # The fast path bails out for exponents >= ceil(log5(max_sig))
+    max_e = int(ceil(log(max_sig, 5)))
+    e_range = range(max_e)
+    typ = "[f{}; {}]".format(num_bits, len(e_range))
+    print("pub const F", num_bits, "_SHORT_POWERS: ", typ, " = [", sep='')
+    for e in e_range:
+        print("    1e{},".format(e))
+    print("];")
+
+
 if __name__ == '__main__':
     main()
index 3c1659ba2e0c46f160d1ee05920a4b0b9d86fda1..10b864a902dc0a4bebb166b1d8ec0723fa3f4343 100755 (executable)
@@ -271,43 +271,6 @@ def load_properties(f, interestingprops):
 
     return props
 
-# load all widths of want_widths, except those in except_cats
-def load_east_asian_width(want_widths, except_cats):
-    f = "EastAsianWidth.txt"
-    fetch(f)
-    widths = {}
-    re1 = re.compile("^([0-9A-F]+);(\w+) +# (\w+)")
-    re2 = re.compile("^([0-9A-F]+)\.\.([0-9A-F]+);(\w+) +# (\w+)")
-
-    for line in fileinput.input(f):
-        width = None
-        d_lo = 0
-        d_hi = 0
-        cat = None
-        m = re1.match(line)
-        if m:
-            d_lo = m.group(1)
-            d_hi = m.group(1)
-            width = m.group(2)
-            cat = m.group(3)
-        else:
-            m = re2.match(line)
-            if m:
-                d_lo = m.group(1)
-                d_hi = m.group(2)
-                width = m.group(3)
-                cat = m.group(4)
-            else:
-                continue
-        if cat in except_cats or width not in want_widths:
-            continue
-        d_lo = int(d_lo, 16)
-        d_hi = int(d_hi, 16)
-        if width not in widths:
-            widths[width] = []
-        widths[width].append((d_lo, d_hi))
-    return widths
-
 def escape_char(c):
     return "'\\u{%x}'" % c if c != 0 else "'\\0'"
 
@@ -316,12 +279,12 @@ def emit_bsearch_range_table(f):
 fn bsearch_range_table(c: char, r: &'static [(char, char)]) -> bool {
     use core::cmp::Ordering::{Equal, Less, Greater};
     r.binary_search_by(|&(lo, hi)| {
-         if lo <= c && c <= hi {
-             Equal
+         if c < lo {
+             Greater
          } else if hi < c {
              Less
          } else {
-             Greater
+             Equal
          }
      })
      .is_ok()
@@ -356,34 +319,25 @@ def emit_property_module(f, mod, tbl, emit):
 def emit_conversions_module(f, to_upper, to_lower, to_title):
     f.write("pub mod conversions {")
     f.write("""
-    use core::cmp::Ordering::{Equal, Less, Greater};
     use core::option::Option;
     use core::option::Option::{Some, None};
-    use core::result::Result::{Ok, Err};
 
     pub fn to_lower(c: char) -> [char; 3] {
         match bsearch_case_table(c, to_lowercase_table) {
-          None        => [c, '\\0', '\\0'],
-          Some(index) => to_lowercase_table[index].1
+            None        => [c, '\\0', '\\0'],
+            Some(index) => to_lowercase_table[index].1,
         }
     }
 
     pub fn to_upper(c: char) -> [char; 3] {
         match bsearch_case_table(c, to_uppercase_table) {
             None        => [c, '\\0', '\\0'],
-            Some(index) => to_uppercase_table[index].1
+            Some(index) => to_uppercase_table[index].1,
         }
     }
 
     fn bsearch_case_table(c: char, table: &'static [(char, [char; 3])]) -> Option<usize> {
-        match table.binary_search_by(|&(key, _)| {
-            if c == key { Equal }
-            else if key < c { Less }
-            else { Greater }
-        }) {
-            Ok(i) => Some(i),
-            Err(_) => None,
-        }
+        table.binary_search_by(|&(key, _)| key.cmp(&c)).ok()
     }
 
 """)
@@ -398,47 +352,6 @@ def emit_conversions_module(f, to_upper, to_lower, to_title):
         is_pub=False, t_type = t_type, pfun=pfun)
     f.write("}\n\n")
 
-def emit_charwidth_module(f, width_table):
-    f.write("pub mod charwidth {\n")
-    f.write("    use core::option::Option;\n")
-    f.write("    use core::option::Option::{Some, None};\n")
-    f.write("    use core::result::Result::{Ok, Err};\n")
-    f.write("""
-    fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 {
-        use core::cmp::Ordering::{Equal, Less, Greater};
-        match r.binary_search_by(|&(lo, hi, _, _)| {
-            if lo <= c && c <= hi { Equal }
-            else if hi < c { Less }
-            else { Greater }
-        }) {
-            Ok(idx) => {
-                let (_, _, r_ncjk, r_cjk) = r[idx];
-                if is_cjk { r_cjk } else { r_ncjk }
-            }
-            Err(_) => 1
-        }
-    }
-""")
-
-    f.write("""
-    pub fn width(c: char, is_cjk: bool) -> Option<usize> {
-        match c as usize {
-            _c @ 0 => Some(0),          // null is zero width
-            cu if cu < 0x20 => None,    // control sequences have no width
-            cu if cu < 0x7F => Some(1), // ASCII
-            cu if cu < 0xA0 => None,    // more control sequences
-            _ => Some(bsearch_range_value_table(c, is_cjk, charwidth_table) as usize)
-        }
-    }
-
-""")
-
-    f.write("    // character width table. Based on Markus Kuhn's free wcwidth() implementation,\n")
-    f.write("    //     http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c\n")
-    emit_table(f, "charwidth_table", width_table, "&'static [(char, char, u8, u8)]", is_pub=False,
-            pfun=lambda x: "(%s,%s,%s,%s)" % (escape_char(x[0]), escape_char(x[1]), x[2], x[3]))
-    f.write("}\n\n")
-
 def emit_norm_module(f, canon, compat, combine, norm_props):
     canon_keys = canon.keys()
     canon_keys.sort()
@@ -459,43 +372,6 @@ def emit_norm_module(f, canon, compat, combine, norm_props):
     canon_comp_keys = canon_comp.keys()
     canon_comp_keys.sort()
 
-def remove_from_wtable(wtable, val):
-    wtable_out = []
-    while wtable:
-        if wtable[0][1] < val:
-            wtable_out.append(wtable.pop(0))
-        elif wtable[0][0] > val:
-            break
-        else:
-            (wt_lo, wt_hi, width, width_cjk) = wtable.pop(0)
-            if wt_lo == wt_hi == val:
-                continue
-            elif wt_lo == val:
-                wtable_out.append((wt_lo+1, wt_hi, width, width_cjk))
-            elif wt_hi == val:
-                wtable_out.append((wt_lo, wt_hi-1, width, width_cjk))
-            else:
-                wtable_out.append((wt_lo, val-1, width, width_cjk))
-                wtable_out.append((val+1, wt_hi, width, width_cjk))
-    if wtable:
-        wtable_out.extend(wtable)
-    return wtable_out
-
-
-
-def optimize_width_table(wtable):
-    wtable_out = []
-    w_this = wtable.pop(0)
-    while wtable:
-        if w_this[1] == wtable[0][0] - 1 and w_this[2:3] == wtable[0][2:3]:
-            w_tmp = wtable.pop(0)
-            w_this = (w_this[0], w_tmp[1], w_tmp[2], w_tmp[3])
-        else:
-            wtable_out.append(w_this)
-            w_this = wtable.pop(0)
-    wtable_out.append(w_this)
-    return wtable_out
-
 if __name__ == "__main__":
     r = "tables.rs"
     if os.path.exists(r):
index 1afb49d9184b5001567325f9b30525a1eac646a6..be140469eb662b3493e979f8b0a7ddeea8f50b55 100644 (file)
@@ -222,12 +222,12 @@ fn drop(&mut self) {
 }
 
 impl<T> Box<T> {
-    /// Allocates memory on the heap and then moves `x` into it.
+    /// Allocates memory on the heap and then places `x` into it.
     ///
     /// # Examples
     ///
     /// ```
-    /// let x = Box::new(5);
+    /// let five = Box::new(5);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline(always)]
@@ -237,17 +237,17 @@ pub fn new(x: T) -> Box<T> {
 }
 
 impl<T: ?Sized> Box<T> {
-    /// Constructs a box from the raw pointer.
+    /// Constructs a box from a raw pointer.
     ///
-    /// After this function call, pointer is owned by resulting box.
-    /// In particular, it means that `Box` destructor calls destructor
-    /// of `T` and releases memory. Since the way `Box` allocates and
-    /// releases memory is unspecified, the only valid pointer to pass
-    /// to this function is the one taken from another `Box` with
-    /// `Box::into_raw` function.
+    /// After calling this function, the raw pointer is owned by the
+    /// resulting `Box`. Specifically, the `Box` destructor will call
+    /// the destructor of `T` and free the allocated memory. Since the
+    /// way `Box` allocates and releases memory is unspecified, the
+    /// only valid pointer to pass to this function is the one taken
+    /// from another `Box` via the `Box::into_raw` function.
     ///
-    /// Function is unsafe, because improper use of this function may
-    /// lead to memory problems like double-free, for example if the
+    /// This function is unsafe because improper use may lead to
+    /// memory problems. For example, a double-free may occur if the
     /// function is called twice on the same raw pointer.
     #[stable(feature = "box_raw", since = "1.4.0")]
     #[inline]
@@ -257,16 +257,16 @@ pub unsafe fn from_raw(raw: *mut T) -> Self {
 
     /// Consumes the `Box`, returning the wrapped raw pointer.
     ///
-    /// After call to this function, caller is responsible for the memory
-    /// previously managed by `Box`, in particular caller should properly
-    /// destroy `T` and release memory. The proper way to do it is to
-    /// convert pointer back to `Box` with `Box::from_raw` function, because
-    /// `Box` does not specify, how memory is allocated.
+    /// After calling this function, the caller is responsible for the
+    /// memory previously managed by the `Box`. In particular, the
+    /// caller should properly destroy `T` and release the memory. The
+    /// proper way to do so is to convert the raw pointer back into a
+    /// `Box` with the `Box::from_raw` function.
     ///
     /// # Examples
     ///
     /// ```
-    /// let seventeen = Box::new(17u32);
+    /// let seventeen = Box::new(17);
     /// let raw = Box::into_raw(seventeen);
     /// let boxed_again = unsafe { Box::from_raw(raw) };
     /// ```
index 93b84cdedd4cdedab7f36ecc0edde86e9ea8aec6..ffa0ec4917cb3ef02fba42e1cc9171a0124ad576 100644 (file)
 #![feature(unsize)]
 #![feature(drop_in_place)]
 #![feature(fn_traits)]
+#![feature(const_fn)]
 
 #![feature(needs_allocator)]
 
+// Issue# 30592: Systematically use alloc_system during stage0 since jemalloc
+// might be unavailable or disabled
+#![cfg_attr(stage0, feature(alloc_system))]
+
 #![cfg_attr(test, feature(test, rustc_private, box_heap))]
 
+#[cfg(stage0)]
+extern crate alloc_system;
+
 // Allow testing this library
 
 #[cfg(test)]
@@ -127,15 +135,6 @@ mod boxed {
 pub mod arc;
 pub mod rc;
 pub mod raw_vec;
+pub mod oom;
 
-/// Common out-of-memory routine
-#[cold]
-#[inline(never)]
-#[unstable(feature = "oom", reason = "not a scrutinized interface",
-           issue = "27700")]
-pub fn oom() -> ! {
-    // FIXME(#14674): This really needs to do something other than just abort
-    //                here, but any printing done must be *guaranteed* to not
-    //                allocate.
-    unsafe { core::intrinsics::abort() }
-}
+pub use oom::oom;
diff --git a/src/liballoc/oom.rs b/src/liballoc/oom.rs
new file mode 100644 (file)
index 0000000..d355d59
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core::sync::atomic::{AtomicPtr, Ordering};
+use core::mem;
+use core::intrinsics;
+
+static OOM_HANDLER: AtomicPtr<()> = AtomicPtr::new(default_oom_handler as *mut ());
+
+fn default_oom_handler() -> ! {
+    // The default handler can't do much more since we can't assume the presence
+    // of libc or any way of printing an error message.
+    unsafe { intrinsics::abort() }
+}
+
+/// Common out-of-memory routine
+#[cold]
+#[inline(never)]
+#[unstable(feature = "oom", reason = "not a scrutinized interface",
+           issue = "27700")]
+pub fn oom() -> ! {
+    let value = OOM_HANDLER.load(Ordering::SeqCst);
+    let handler: fn() -> ! = unsafe { mem::transmute(value) };
+    handler();
+}
+
+/// Set a custom handler for out-of-memory conditions
+///
+/// To avoid recursive OOM failures, it is critical that the OOM handler does
+/// not allocate any memory itself.
+#[unstable(feature = "oom", reason = "not a scrutinized interface",
+           issue = "27700")]
+pub fn set_oom_handler(handler: fn() -> !) {
+    OOM_HANDLER.store(handler as *mut (), Ordering::SeqCst);
+}
index 92f35c08a7debacc76496f339719508ca7d8c9db..52bd62f7a660a8da2e5b9a4ab857d32ea8f08fff 100644 (file)
@@ -240,6 +240,47 @@ pub fn double(&mut self) {
         }
     }
 
+    /// Attempts to double the size of the type's backing allocation in place. This is common
+    /// enough to want to do that it's easiest to just have a dedicated method. Slightly
+    /// more efficient logic can be provided for this than the general case.
+    ///
+    /// Returns true if the reallocation attempt has succeeded, or false otherwise.
+    ///
+    /// # Panics
+    ///
+    /// * Panics if T is zero-sized on the assumption that you managed to exhaust
+    ///   all `usize::MAX` slots in your imaginary buffer.
+    /// * Panics on 32-bit platforms if the requested capacity exceeds
+    ///   `isize::MAX` bytes.
+    #[inline(never)]
+    #[cold]
+    pub fn double_in_place(&mut self) -> bool {
+        unsafe {
+            let elem_size = mem::size_of::<T>();
+            let align = mem::align_of::<T>();
+
+            // since we set the capacity to usize::MAX when elem_size is
+            // 0, getting to here necessarily means the RawVec is overfull.
+            assert!(elem_size != 0, "capacity overflow");
+
+            // Since we guarantee that we never allocate more than isize::MAX bytes,
+            // `elem_size * self.cap <= isize::MAX` as a precondition, so this can't overflow
+            let new_cap = 2 * self.cap;
+            let new_alloc_size = new_cap * elem_size;
+
+            alloc_guard(new_alloc_size);
+            let size = heap::reallocate_inplace(self.ptr() as *mut _,
+                                                self.cap * elem_size,
+                                                new_alloc_size,
+                                                align);
+            if size >= new_alloc_size {
+                // We can't directly divide `size`.
+                self.cap = new_cap;
+            }
+            size >= new_alloc_size
+        }
+    }
+
     /// Ensures that the buffer contains at least enough space to hold
     /// `used_cap + needed_extra_cap` elements. If it doesn't already,
     /// will reallocate the minimum possible amount of memory necessary.
@@ -300,6 +341,22 @@ pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) {
         }
     }
 
+    /// Calculates the buffer's new size given that it'll hold `used_cap +
+    /// needed_extra_cap` elements. This logic is used in amortized reserve methods.
+    /// Returns `(new_capacity, new_alloc_size)`.
+    fn amortized_new_size(&self, used_cap: usize, needed_extra_cap: usize) -> (usize, usize) {
+        let elem_size = mem::size_of::<T>();
+        // Nothing we can really do about these checks :(
+        let required_cap = used_cap.checked_add(needed_extra_cap)
+                                   .expect("capacity overflow");
+        // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
+        let double_cap = self.cap * 2;
+        // `double_cap` guarantees exponential growth.
+        let new_cap = cmp::max(double_cap, required_cap);
+        let new_alloc_size = new_cap.checked_mul(elem_size).expect("capacity overflow");
+        (new_cap, new_alloc_size)
+    }
+
     /// Ensures that the buffer contains at least enough space to hold
     /// `used_cap + needed_extra_cap` elements. If it doesn't already have
     /// enough capacity, will reallocate enough space plus comfortable slack
@@ -360,17 +417,7 @@ pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) {
                 return;
             }
 
-            // Nothing we can really do about these checks :(
-            let required_cap = used_cap.checked_add(needed_extra_cap)
-                                       .expect("capacity overflow");
-
-            // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
-            let double_cap = self.cap * 2;
-
-            // `double_cap` guarantees exponential growth.
-            let new_cap = cmp::max(double_cap, required_cap);
-
-            let new_alloc_size = new_cap.checked_mul(elem_size).expect("capacity overflow");
+            let (new_cap, new_alloc_size) = self.amortized_new_size(used_cap, needed_extra_cap);
             // FIXME: may crash and burn on over-reserve
             alloc_guard(new_alloc_size);
 
@@ -393,6 +440,55 @@ pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) {
         }
     }
 
+    /// Attempts to ensure that the buffer contains at least enough space to hold
+    /// `used_cap + needed_extra_cap` elements. If it doesn't already have
+    /// enough capacity, will reallocate in place enough space plus comfortable slack
+    /// space to get amortized `O(1)` behaviour. Will limit this behaviour
+    /// if it would needlessly cause itself to panic.
+    ///
+    /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate
+    /// the requested space. This is not really unsafe, but the unsafe
+    /// code *you* write that relies on the behaviour of this function may break.
+    ///
+    /// Returns true if the reallocation attempt has succeeded, or false otherwise.
+    ///
+    /// # Panics
+    ///
+    /// * Panics if the requested capacity exceeds `usize::MAX` bytes.
+    /// * Panics on 32-bit platforms if the requested capacity exceeds
+    ///   `isize::MAX` bytes.
+    pub fn reserve_in_place(&mut self, used_cap: usize, needed_extra_cap: usize) -> bool {
+        unsafe {
+            let elem_size = mem::size_of::<T>();
+            let align = mem::align_of::<T>();
+
+            // NOTE: we don't early branch on ZSTs here because we want this
+            // to actually catch "asking for more than usize::MAX" in that case.
+            // If we make it past the first branch then we are guaranteed to
+            // panic.
+
+            // Don't actually need any more capacity. If the current `cap` is 0, we can't
+            // reallocate in place.
+            // Wrapping in case they give a bad `used_cap`
+            if self.cap().wrapping_sub(used_cap) >= needed_extra_cap || self.cap == 0 {
+                return false;
+            }
+
+            let (_, new_alloc_size) = self.amortized_new_size(used_cap, needed_extra_cap);
+            // FIXME: may crash and burn on over-reserve
+            alloc_guard(new_alloc_size);
+
+            let size = heap::reallocate_inplace(self.ptr() as *mut _,
+                                                self.cap * elem_size,
+                                                new_alloc_size,
+                                                align);
+            if size >= new_alloc_size {
+                self.cap = new_alloc_size / elem_size;
+            }
+            size >= new_alloc_size
+        }
+    }
+
     /// Shrinks the allocation down to the specified amount. If the given amount
     /// is 0, actually completely deallocates.
     ///
index eaaa9391d3115e2667e6f6deab6c977257efcf64..91d229b819df197b84987f7f0b2002cfb8a05c00 100644 (file)
@@ -55,7 +55,9 @@
 const MIN_ALIGN: usize = 8;
 #[cfg(all(any(target_arch = "x86",
               target_arch = "x86_64",
-              target_arch = "aarch64")))]
+              target_arch = "aarch64",
+              target_arch = "powerpc64",
+              target_arch = "powerpc64le")))]
 const MIN_ALIGN: usize = 16;
 
 // MALLOCX_ALIGN(a) macro
index fccc024603ebdb9921d502b2a93ef54ffea23801..ffb6999d6e3fef7ef932832ecbb65f219cdcd8bd 100644 (file)
@@ -29,7 +29,9 @@
               target_arch = "arm",
               target_arch = "mips",
               target_arch = "mipsel",
-              target_arch = "powerpc")))]
+              target_arch = "powerpc",
+              target_arch = "powerpc64",
+              target_arch = "powerpc64le")))]
 const MIN_ALIGN: usize = 8;
 #[cfg(all(any(target_arch = "x86_64",
               target_arch = "aarch64")))]
@@ -75,37 +77,17 @@ mod imp {
     use libc;
     use MIN_ALIGN;
 
-    extern "C" {
-        // Apparently android doesn't have posix_memalign
-        #[cfg(target_os = "android")]
-        fn memalign(align: libc::size_t, size: libc::size_t) -> *mut libc::c_void;
-
-        #[cfg(not(target_os = "android"))]
-        fn posix_memalign(memptr: *mut *mut libc::c_void,
-                          align: libc::size_t,
-                          size: libc::size_t)
-                          -> libc::c_int;
-    }
-
     pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
         if align <= MIN_ALIGN {
             libc::malloc(size as libc::size_t) as *mut u8
         } else {
-            #[cfg(target_os = "android")]
-            unsafe fn more_aligned_malloc(size: usize, align: usize) -> *mut u8 {
-                memalign(align as libc::size_t, size as libc::size_t) as *mut u8
-            }
-            #[cfg(not(target_os = "android"))]
-            unsafe fn more_aligned_malloc(size: usize, align: usize) -> *mut u8 {
-                let mut out = ptr::null_mut();
-                let ret = posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
-                if ret != 0 {
-                    ptr::null_mut()
-                } else {
-                    out as *mut u8
-                }
+            let mut out = ptr::null_mut();
+            let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
+            if ret != 0 {
+                ptr::null_mut()
+            } else {
+                out as *mut u8
             }
-            more_aligned_malloc(size, align)
         }
     }
 
index b5107e411e8510d4b6a30ab1e474edb69344db40..cd2093984e618ef785f7ee748351f5a06f3c5aed 100644 (file)
        test(no_crate_inject, attr(deny(warnings))))]
 
 #![feature(alloc)]
-#![feature(box_syntax)]
 #![feature(core_intrinsics)]
+#![feature(drop_in_place)]
 #![feature(heap_api)]
-#![feature(oom)]
-#![feature(ptr_as_ref)]
 #![feature(raw)]
+#![feature(heap_api)]
 #![feature(staged_api)]
 #![feature(dropck_parametricity)]
 #![cfg_attr(test, feature(test))]
 
+#![allow(deprecated)]
+
 extern crate alloc;
 
 use std::cell::{Cell, RefCell};
 use std::cmp;
 use std::intrinsics;
-use std::marker;
+use std::marker::{PhantomData, Send};
 use std::mem;
 use std::ptr;
-use std::rc::Rc;
+use std::slice;
 
-use alloc::heap::{allocate, deallocate};
+use alloc::heap;
+use alloc::raw_vec::RawVec;
 
-// The way arena uses arrays is really deeply awful. The arrays are
-// allocated, and have capacities reserved, but the fill for the array
-// will always stay at 0.
-#[derive(Clone, PartialEq)]
 struct Chunk {
-    data: Rc<RefCell<Vec<u8>>>,
+    data: RawVec<u8>,
+    /// Index of the first unused byte.
     fill: Cell<usize>,
+    /// Indicates whether objects with destructors are stored in this chunk.
     is_copy: Cell<bool>,
 }
 
 impl Chunk {
+    fn new(size: usize, is_copy: bool) -> Chunk {
+        Chunk {
+            data: RawVec::with_capacity(size),
+            fill: Cell::new(0),
+            is_copy: Cell::new(is_copy),
+        }
+    }
+
     fn capacity(&self) -> usize {
-        self.data.borrow().capacity()
+        self.data.cap()
     }
 
     unsafe fn as_ptr(&self) -> *const u8 {
-        self.data.borrow().as_ptr()
+        self.data.ptr()
+    }
+
+    // Walk down a chunk, running the destructors for any objects stored
+    // in it.
+    unsafe fn destroy(&self) {
+        let mut idx = 0;
+        let buf = self.as_ptr();
+        let fill = self.fill.get();
+
+        while idx < fill {
+            let tydesc_data = buf.offset(idx as isize) as *const usize;
+            let (tydesc, is_done) = un_bitpack_tydesc_ptr(*tydesc_data);
+            let (size, align) = ((*tydesc).size, (*tydesc).align);
+
+            let after_tydesc = idx + mem::size_of::<*const TyDesc>();
+
+            let start = round_up(after_tydesc, align);
+
+            if is_done {
+                ((*tydesc).drop_glue)(buf.offset(start as isize) as *const i8);
+            }
+
+            // Find where the next tydesc lives
+            idx = round_up(start + size, mem::align_of::<*const TyDesc>());
+        }
     }
 }
 
 /// A slower reflection-based arena that can allocate objects of any type.
 ///
-/// This arena uses `Vec<u8>` as a backing store to allocate objects from. For
-/// each allocated object, the arena stores a pointer to the type descriptor
+/// This arena uses `RawVec<u8>` as a backing store to allocate objects from.
+/// For each allocated object, the arena stores a pointer to the type descriptor
 /// followed by the object (potentially with alignment padding after each
 /// element). When the arena is destroyed, it iterates through all of its
 /// chunks, and uses the tydesc information to trace through the objects,
@@ -91,14 +124,17 @@ unsafe fn as_ptr(&self) -> *const u8 {
 /// than objects without destructors. This reduces overhead when initializing
 /// plain-old-data (`Copy` types) and means we don't need to waste time running
 /// their destructors.
+#[unstable(feature = "rustc_private",
+           reason = "Private to rustc", issue = "0")]
+#[rustc_deprecated(since = "1.6.0-dev", reason =
+"The reflection-based arena is superseded by the any-arena crate")]
 pub struct Arena<'longer_than_self> {
-    // The head is separated out from the list as a unbenchmarked
-    // microoptimization, to avoid needing to case on the list to access the
-    // head.
+    // The heads are separated out from the list as a unbenchmarked
+    // microoptimization, to avoid needing to case on the list to access a head.
     head: RefCell<Chunk>,
     copy_head: RefCell<Chunk>,
     chunks: RefCell<Vec<Chunk>>,
-    _marker: marker::PhantomData<*mut &'longer_than_self ()>,
+    _marker: PhantomData<*mut &'longer_than_self ()>,
 }
 
 impl<'a> Arena<'a> {
@@ -110,29 +146,21 @@ pub fn new() -> Arena<'a> {
     /// Allocates a new Arena with `initial_size` bytes preallocated.
     pub fn new_with_size(initial_size: usize) -> Arena<'a> {
         Arena {
-            head: RefCell::new(chunk(initial_size, false)),
-            copy_head: RefCell::new(chunk(initial_size, true)),
+            head: RefCell::new(Chunk::new(initial_size, false)),
+            copy_head: RefCell::new(Chunk::new(initial_size, true)),
             chunks: RefCell::new(Vec::new()),
-            _marker: marker::PhantomData,
+            _marker: PhantomData,
         }
     }
 }
 
-fn chunk(size: usize, is_copy: bool) -> Chunk {
-    Chunk {
-        data: Rc::new(RefCell::new(Vec::with_capacity(size))),
-        fill: Cell::new(0),
-        is_copy: Cell::new(is_copy),
-    }
-}
-
 impl<'longer_than_self> Drop for Arena<'longer_than_self> {
     fn drop(&mut self) {
         unsafe {
-            destroy_chunk(&*self.head.borrow());
+            self.head.borrow().destroy();
             for chunk in self.chunks.borrow().iter() {
                 if !chunk.is_copy.get() {
-                    destroy_chunk(chunk);
+                    chunk.destroy();
                 }
             }
         }
@@ -144,33 +172,6 @@ fn round_up(base: usize, align: usize) -> usize {
     (base.checked_add(align - 1)).unwrap() & !(align - 1)
 }
 
-// Walk down a chunk, running the destructors for any objects stored
-// in it.
-unsafe fn destroy_chunk(chunk: &Chunk) {
-    let mut idx = 0;
-    let buf = chunk.as_ptr();
-    let fill = chunk.fill.get();
-
-    while idx < fill {
-        let tydesc_data = buf.offset(idx as isize) as *const usize;
-        let (tydesc, is_done) = un_bitpack_tydesc_ptr(*tydesc_data);
-        let (size, align) = ((*tydesc).size, (*tydesc).align);
-
-        let after_tydesc = idx + mem::size_of::<*const TyDesc>();
-
-        let start = round_up(after_tydesc, align);
-
-        // debug!("freeing object: idx = {}, size = {}, align = {}, done = {}",
-        //        start, size, align, is_done);
-        if is_done {
-            ((*tydesc).drop_glue)(buf.offset(start as isize) as *const i8);
-        }
-
-        // Find where the next tydesc lives
-        idx = round_up(start + size, mem::align_of::<*const TyDesc>());
-    }
-}
-
 // We encode whether the object a tydesc describes has been
 // initialized in the arena in the low bit of the tydesc pointer. This
 // is necessary in order to properly do cleanup if a panic occurs
@@ -187,6 +188,9 @@ fn un_bitpack_tydesc_ptr(p: usize) -> (*const TyDesc, bool) {
 // HACK(eddyb) TyDesc replacement using a trait object vtable.
 // This could be replaced in the future with a custom DST layout,
 // or `&'static (drop_glue, size, align)` created by a `const fn`.
+// Requirements:
+// * rvalue promotion (issue #1056)
+// * mem::{size_of, align_of} must be const fns
 struct TyDesc {
     drop_glue: fn(*const i8),
     size: usize,
@@ -202,7 +206,7 @@ impl<T: ?Sized> AllTypes for T {}
 unsafe fn get_tydesc<T>() -> *const TyDesc {
     use std::raw::TraitObject;
 
-    let ptr = &*(1 as *const T);
+    let ptr = &*(heap::EMPTY as *const T);
 
     // Can use any trait that is implemented for all types.
     let obj = mem::transmute::<&AllTypes, TraitObject>(ptr);
@@ -210,31 +214,44 @@ unsafe fn get_tydesc<T>() -> *const TyDesc {
 }
 
 impl<'longer_than_self> Arena<'longer_than_self> {
-    fn chunk_size(&self) -> usize {
-        self.copy_head.borrow().capacity()
+    // Grows a given chunk and returns `false`, or replaces it with a bigger
+    // chunk and returns `true`.
+    // This method is shared by both parts of the arena.
+    #[cold]
+    fn alloc_grow(&self, head: &mut Chunk, used_cap: usize, n_bytes: usize) -> bool {
+        if head.data.reserve_in_place(used_cap, n_bytes) {
+            // In-place reallocation succeeded.
+            false
+        } else {
+            // Allocate a new chunk.
+            let new_min_chunk_size = cmp::max(n_bytes, head.capacity());
+            let new_chunk = Chunk::new((new_min_chunk_size + 1).next_power_of_two(), false);
+            let old_chunk = mem::replace(head, new_chunk);
+            if old_chunk.fill.get() != 0 {
+                self.chunks.borrow_mut().push(old_chunk);
+            }
+            true
+        }
     }
 
-    // Functions for the POD part of the arena
-    fn alloc_copy_grow(&self, n_bytes: usize, align: usize) -> *const u8 {
-        // Allocate a new chunk.
-        let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size());
-        self.chunks.borrow_mut().push(self.copy_head.borrow().clone());
-
-        *self.copy_head.borrow_mut() = chunk((new_min_chunk_size + 1).next_power_of_two(), true);
-
-        self.alloc_copy_inner(n_bytes, align)
-    }
+    // Functions for the copyable part of the arena.
 
     #[inline]
     fn alloc_copy_inner(&self, n_bytes: usize, align: usize) -> *const u8 {
-        let start = round_up(self.copy_head.borrow().fill.get(), align);
-
-        let end = start + n_bytes;
-        if end > self.chunk_size() {
-            return self.alloc_copy_grow(n_bytes, align);
+        let mut copy_head = self.copy_head.borrow_mut();
+        let fill = copy_head.fill.get();
+        let mut start = round_up(fill, align);
+        let mut end = start + n_bytes;
+
+        if end > copy_head.capacity() {
+            if self.alloc_grow(&mut *copy_head, fill, end - fill) {
+                // Continuing with a newly allocated chunk
+                start = 0;
+                end = n_bytes;
+                copy_head.is_copy.set(true);
+            }
         }
 
-        let copy_head = self.copy_head.borrow();
         copy_head.fill.set(end);
 
         unsafe { copy_head.as_ptr().offset(start as isize) }
@@ -252,39 +269,28 @@ fn alloc_copy<T, F>(&self, op: F) -> &mut T
         }
     }
 
-    // Functions for the non-POD part of the arena
-    fn alloc_noncopy_grow(&self, n_bytes: usize, align: usize) -> (*const u8, *const u8) {
-        // Allocate a new chunk.
-        let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size());
-        self.chunks.borrow_mut().push(self.head.borrow().clone());
-
-        *self.head.borrow_mut() = chunk((new_min_chunk_size + 1).next_power_of_two(), false);
-
-        self.alloc_noncopy_inner(n_bytes, align)
-    }
+    // Functions for the non-copyable part of the arena.
 
     #[inline]
     fn alloc_noncopy_inner(&self, n_bytes: usize, align: usize) -> (*const u8, *const u8) {
-        // Be careful to not maintain any `head` borrows active, because
-        // `alloc_noncopy_grow` borrows it mutably.
-        let (start, end, tydesc_start, head_capacity) = {
-            let head = self.head.borrow();
-            let fill = head.fill.get();
-
-            let tydesc_start = fill;
-            let after_tydesc = fill + mem::size_of::<*const TyDesc>();
-            let start = round_up(after_tydesc, align);
-            let end = start + n_bytes;
-
-            (start, end, tydesc_start, head.capacity())
-        };
-
-        if end > head_capacity {
-            return self.alloc_noncopy_grow(n_bytes, align);
+        let mut head = self.head.borrow_mut();
+        let fill = head.fill.get();
+
+        let mut tydesc_start = fill;
+        let after_tydesc = fill + mem::size_of::<*const TyDesc>();
+        let mut start = round_up(after_tydesc, align);
+        let mut end = round_up(start + n_bytes, mem::align_of::<*const TyDesc>());
+
+        if end > head.capacity() {
+            if self.alloc_grow(&mut *head, tydesc_start, end - tydesc_start) {
+                // Continuing with a newly allocated chunk
+                tydesc_start = 0;
+                start = round_up(mem::size_of::<*const TyDesc>(), align);
+                end = round_up(start + n_bytes, mem::align_of::<*const TyDesc>());
+            }
         }
 
-        let head = self.head.borrow();
-        head.fill.set(round_up(end, mem::align_of::<*const TyDesc>()));
+        head.fill.set(end);
 
         unsafe {
             let buf = head.as_ptr();
@@ -329,140 +335,111 @@ pub fn alloc<T: 'longer_than_self, F>(&self, op: F) -> &mut T
             }
         }
     }
-}
 
-#[test]
-fn test_arena_destructors() {
-    let arena = Arena::new();
-    for i in 0..10 {
-        // Arena allocate something with drop glue to make sure it
-        // doesn't leak.
-        arena.alloc(|| Rc::new(i));
-        // Allocate something with funny size and alignment, to keep
-        // things interesting.
-        arena.alloc(|| [0u8, 1u8, 2u8]);
+    /// Allocates a slice of bytes of requested length. The bytes are not guaranteed to be zero
+    /// if the arena has previously been cleared.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the requested length is too large and causes overflow.
+    pub fn alloc_bytes(&self, len: usize) -> &mut [u8] {
+        unsafe {
+            // Check for overflow.
+            self.copy_head.borrow().fill.get().checked_add(len).expect("length overflow");
+            let ptr = self.alloc_copy_inner(len, 1);
+            intrinsics::assume(!ptr.is_null());
+            slice::from_raw_parts_mut(ptr as *mut _, len)
+        }
     }
-}
 
-#[test]
-#[should_panic]
-fn test_arena_destructors_fail() {
-    let arena = Arena::new();
-    // Put some stuff in the arena.
-    for i in 0..10 {
-        // Arena allocate something with drop glue to make sure it
-        // doesn't leak.
-        arena.alloc(|| Rc::new(i));
-        // Allocate something with funny size and alignment, to keep
-        // things interesting.
-        arena.alloc(|| [0u8, 1, 2]);
-    }
-    // Now, panic while allocating
-    arena.alloc::<Rc<i32>, _>(|| {
-        panic!();
-    });
+    /// Clears the arena. Deallocates all but the longest chunk which may be reused.
+    pub fn clear(&mut self) {
+        unsafe {
+            self.head.borrow().destroy();
+            self.head.borrow().fill.set(0);
+            self.copy_head.borrow().fill.set(0);
+            for chunk in self.chunks.borrow().iter() {
+                if !chunk.is_copy.get() {
+                    chunk.destroy();
+                }
+            }
+            self.chunks.borrow_mut().clear();
+        }
+    }
 }
 
 /// A faster arena that can hold objects of only one type.
 pub struct TypedArena<T> {
     /// A pointer to the next object to be allocated.
-    ptr: Cell<*const T>,
+    ptr: Cell<*mut T>,
 
     /// A pointer to the end of the allocated area. When this pointer is
     /// reached, a new chunk is allocated.
-    end: Cell<*const T>,
+    end: Cell<*mut T>,
 
-    /// A pointer to the first arena segment.
-    first: RefCell<*mut TypedArenaChunk<T>>,
+    /// A vector arena segments.
+    chunks: RefCell<Vec<TypedArenaChunk<T>>>,
 
     /// Marker indicating that dropping the arena causes its owned
     /// instances of `T` to be dropped.
-    _own: marker::PhantomData<T>,
+    _own: PhantomData<T>,
 }
 
 struct TypedArenaChunk<T> {
-    marker: marker::PhantomData<T>,
-
     /// Pointer to the next arena segment.
-    next: *mut TypedArenaChunk<T>,
-
-    /// The number of elements that this chunk can hold.
-    capacity: usize,
-
-    // Objects follow here, suitably aligned.
-}
-
-fn calculate_size<T>(capacity: usize) -> usize {
-    let mut size = mem::size_of::<TypedArenaChunk<T>>();
-    size = round_up(size, mem::align_of::<T>());
-    let elem_size = mem::size_of::<T>();
-    let elems_size = elem_size.checked_mul(capacity).unwrap();
-    size = size.checked_add(elems_size).unwrap();
-    size
+    storage: RawVec<T>,
 }
 
 impl<T> TypedArenaChunk<T> {
     #[inline]
-    unsafe fn new(next: *mut TypedArenaChunk<T>, capacity: usize) -> *mut TypedArenaChunk<T> {
-        let size = calculate_size::<T>(capacity);
-        let chunk =
-            allocate(size, mem::align_of::<TypedArenaChunk<T>>()) as *mut TypedArenaChunk<T>;
-        if chunk.is_null() {
-            alloc::oom()
-        }
-        (*chunk).next = next;
-        (*chunk).capacity = capacity;
-        chunk
+    unsafe fn new(capacity: usize) -> TypedArenaChunk<T> {
+        TypedArenaChunk { storage: RawVec::with_capacity(capacity) }
     }
 
-    /// Destroys this arena chunk. If the type descriptor is supplied, the
-    /// drop glue is called; otherwise, drop glue is not called.
+    /// Destroys this arena chunk.
     #[inline]
     unsafe fn destroy(&mut self, len: usize) {
-        // Destroy all the allocated objects.
+        // The branch on needs_drop() is an -O1 performance optimization.
+        // Without the branch, dropping TypedArena<u8> takes linear time.
         if intrinsics::needs_drop::<T>() {
             let mut start = self.start();
+            // Destroy all allocated objects.
             for _ in 0..len {
-                ptr::read(start as *const T); // run the destructor on the pointer
-                start = start.offset(mem::size_of::<T>() as isize)
+                ptr::drop_in_place(start);
+                start = start.offset(1);
             }
         }
-
-        // Destroy the next chunk.
-        let next = self.next;
-        let size = calculate_size::<T>(self.capacity);
-        let self_ptr: *mut TypedArenaChunk<T> = self;
-        deallocate(self_ptr as *mut u8,
-                   size,
-                   mem::align_of::<TypedArenaChunk<T>>());
-        if !next.is_null() {
-            let capacity = (*next).capacity;
-            (*next).destroy(capacity);
-        }
     }
 
     // Returns a pointer to the first allocated object.
     #[inline]
-    fn start(&self) -> *const u8 {
-        let this: *const TypedArenaChunk<T> = self;
-        unsafe { round_up(this.offset(1) as usize, mem::align_of::<T>()) as *const u8 }
+    fn start(&self) -> *mut T {
+        self.storage.ptr()
     }
 
     // Returns a pointer to the end of the allocated space.
     #[inline]
-    fn end(&self) -> *const u8 {
+    fn end(&self) -> *mut T {
         unsafe {
-            let size = mem::size_of::<T>().checked_mul(self.capacity).unwrap();
-            self.start().offset(size as isize)
+            if mem::size_of::<T>() == 0 {
+                // A pointer as large as possible for zero-sized elements.
+                !0 as *mut T
+            } else {
+                self.start().offset(self.storage.cap() as isize)
+            }
         }
     }
 }
 
+const PAGE: usize = 4096;
+
 impl<T> TypedArena<T> {
-    /// Creates a new `TypedArena` with preallocated space for eight objects.
+    /// Creates a new `TypedArena` with preallocated space for many objects.
     #[inline]
     pub fn new() -> TypedArena<T> {
-        TypedArena::with_capacity(8)
+        // Reserve at least one page.
+        let elem_size = cmp::max(1, mem::size_of::<T>());
+        TypedArena::with_capacity(PAGE / elem_size)
     }
 
     /// Creates a new `TypedArena` with preallocated space for the given number of
@@ -470,12 +447,12 @@ pub fn new() -> TypedArena<T> {
     #[inline]
     pub fn with_capacity(capacity: usize) -> TypedArena<T> {
         unsafe {
-            let chunk = TypedArenaChunk::<T>::new(ptr::null_mut(), capacity);
+            let chunk = TypedArenaChunk::<T>::new(cmp::max(1, capacity));
             TypedArena {
-                ptr: Cell::new((*chunk).start() as *const T),
-                end: Cell::new((*chunk).end() as *const T),
-                first: RefCell::new(chunk),
-                _own: marker::PhantomData,
+                ptr: Cell::new(chunk.start()),
+                end: Cell::new(chunk.end()),
+                chunks: RefCell::new(vec![chunk]),
+                _own: PhantomData,
             }
         }
     }
@@ -488,24 +465,79 @@ pub fn alloc(&self, object: T) -> &mut T {
         }
 
         unsafe {
-            let ptr: &mut T = &mut *(self.ptr.get() as *mut T);
-            ptr::write(ptr, object);
-            self.ptr.set(self.ptr.get().offset(1));
-            ptr
+            if mem::size_of::<T>() == 0 {
+                self.ptr.set(intrinsics::arith_offset(self.ptr.get() as *mut u8, 1) as *mut T);
+                let ptr = heap::EMPTY as *mut T;
+                // Don't drop the object. This `write` is equivalent to `forget`.
+                ptr::write(ptr, object);
+                &mut *ptr
+            } else {
+                let ptr = self.ptr.get();
+                // Advance the pointer.
+                self.ptr.set(self.ptr.get().offset(1));
+                // Write into uninitialized memory.
+                ptr::write(ptr, object);
+                &mut *ptr
+            }
         }
     }
 
     /// Grows the arena.
     #[inline(never)]
+    #[cold]
     fn grow(&self) {
         unsafe {
-            let chunk = *self.first.borrow_mut();
-            let new_capacity = (*chunk).capacity.checked_mul(2).unwrap();
-            let chunk = TypedArenaChunk::<T>::new(chunk, new_capacity);
-            self.ptr.set((*chunk).start() as *const T);
-            self.end.set((*chunk).end() as *const T);
-            *self.first.borrow_mut() = chunk
+            let mut chunks = self.chunks.borrow_mut();
+            let prev_capacity = chunks.last().unwrap().storage.cap();
+            let new_capacity = prev_capacity.checked_mul(2).unwrap();
+            if chunks.last_mut().unwrap().storage.double_in_place() {
+                self.end.set(chunks.last().unwrap().end());
+            } else {
+                let chunk = TypedArenaChunk::<T>::new(new_capacity);
+                self.ptr.set(chunk.start());
+                self.end.set(chunk.end());
+                chunks.push(chunk);
+            }
+        }
+    }
+    /// Clears the arena. Deallocates all but the longest chunk which may be reused.
+    pub fn clear(&mut self) {
+        unsafe {
+            // Clear the last chunk, which is partially filled.
+            let mut chunks_borrow = self.chunks.borrow_mut();
+            let last_idx = chunks_borrow.len() - 1;
+            self.clear_last_chunk(&mut chunks_borrow[last_idx]);
+            // If `T` is ZST, code below has no effect.
+            for mut chunk in chunks_borrow.drain(..last_idx) {
+                let cap = chunk.storage.cap();
+                chunk.destroy(cap);
+            }
+        }
+    }
+
+    // Drops the contents of the last chunk. The last chunk is partially empty, unlike all other
+    // chunks.
+    fn clear_last_chunk(&self, last_chunk: &mut TypedArenaChunk<T>) {
+        // Determine how much was filled.
+        let start = last_chunk.start() as usize;
+        // We obtain the value of the pointer to the first uninitialized element.
+        let end = self.ptr.get() as usize;
+        // We then calculate the number of elements to be dropped in the last chunk,
+        // which is the filled area's length.
+        let diff = if mem::size_of::<T>() == 0 {
+            // `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get
+            // the number of zero-sized values in the last and only chunk, just out of caution.
+            // Recall that `end` was incremented for each allocated value.
+            end - start
+        } else {
+            (end - start) / mem::size_of::<T>()
+        };
+        // Pass that to the `destroy` method.
+        unsafe {
+            last_chunk.destroy(diff);
         }
+        // Reset the chunk.
+        self.ptr.set(last_chunk.start());
     }
 }
 
@@ -514,23 +546,32 @@ impl<T> Drop for TypedArena<T> {
     fn drop(&mut self) {
         unsafe {
             // Determine how much was filled.
-            let start = self.first.borrow().as_ref().unwrap().start() as usize;
-            let end = self.ptr.get() as usize;
-            let diff = (end - start) / mem::size_of::<T>();
-
-            // Pass that to the `destroy` method.
-            (**self.first.borrow_mut()).destroy(diff)
+            let mut chunks_borrow = self.chunks.borrow_mut();
+            let mut last_chunk = chunks_borrow.pop().unwrap();
+            // Drop the contents of the last chunk.
+            self.clear_last_chunk(&mut last_chunk);
+            // The last chunk will be dropped. Destroy all other chunks.
+            for chunk in chunks_borrow.iter_mut() {
+                let cap = chunk.storage.cap();
+                chunk.destroy(cap);
+            }
+            // RawVec handles deallocation of `last_chunk` and `self.chunks`.
         }
     }
 }
 
+unsafe impl<T: Send> Send for TypedArena<T> {}
+
 #[cfg(test)]
 mod tests {
     extern crate test;
     use self::test::Bencher;
     use super::{Arena, TypedArena};
+    use std::cell::Cell;
+    use std::rc::Rc;
 
     #[allow(dead_code)]
+    #[derive(Debug, Eq, PartialEq)]
     struct Point {
         x: i32,
         y: i32,
@@ -597,7 +638,7 @@ pub fn bench_copy(b: &mut Bencher) {
     #[bench]
     pub fn bench_copy_nonarena(b: &mut Bencher) {
         b.iter(|| {
-            let _: Box<_> = box Point { x: 1, y: 2, z: 3 };
+            let _: Box<_> = Box::new(Point { x: 1, y: 2, z: 3 });
         })
     }
 
@@ -624,6 +665,219 @@ pub fn test_noncopy() {
         }
     }
 
+    #[test]
+    pub fn test_typed_arena_zero_sized() {
+        let arena = TypedArena::new();
+        for _ in 0..100000 {
+            arena.alloc(());
+        }
+    }
+
+    #[test]
+    pub fn test_arena_zero_sized() {
+        let arena = Arena::new();
+        let mut points = vec![];
+        for _ in 0..1000 {
+            for _ in 0..100 {
+                arena.alloc(|| ());
+            }
+            let point = arena.alloc(|| Point { x: 1, y: 2, z: 3 });
+            points.push(point);
+        }
+        for point in &points {
+            assert_eq!(**point, Point { x: 1, y: 2, z: 3 });
+        }
+    }
+
+    #[test]
+    pub fn test_typed_arena_clear() {
+        let mut arena = TypedArena::new();
+        for _ in 0..10 {
+            arena.clear();
+            for _ in 0..10000 {
+                arena.alloc(Point { x: 1, y: 2, z: 3 });
+            }
+        }
+    }
+
+    #[test]
+    pub fn test_arena_clear() {
+        let mut arena = Arena::new();
+        for _ in 0..10 {
+            arena.clear();
+            for _ in 0..10000 {
+                arena.alloc(|| Point { x: 1, y: 2, z: 3 });
+                arena.alloc(|| {
+                    Noncopy {
+                        string: "hello world".to_string(),
+                        array: vec![],
+                    }
+                });
+            }
+        }
+    }
+
+    #[test]
+    pub fn test_arena_alloc_bytes() {
+        let arena = Arena::new();
+        for i in 0..10000 {
+            arena.alloc(|| Point { x: 1, y: 2, z: 3 });
+            for byte in arena.alloc_bytes(i % 42).iter_mut() {
+                *byte = i as u8;
+            }
+        }
+    }
+
+    #[test]
+    fn test_arena_destructors() {
+        let arena = Arena::new();
+        for i in 0..10 {
+            // Arena allocate something with drop glue to make sure it
+            // doesn't leak.
+            arena.alloc(|| Rc::new(i));
+            // Allocate something with funny size and alignment, to keep
+            // things interesting.
+            arena.alloc(|| [0u8, 1u8, 2u8]);
+        }
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_arena_destructors_fail() {
+        let arena = Arena::new();
+        // Put some stuff in the arena.
+        for i in 0..10 {
+            // Arena allocate something with drop glue to make sure it
+            // doesn't leak.
+            arena.alloc(|| Rc::new(i));
+            // Allocate something with funny size and alignment, to keep
+            // things interesting.
+            arena.alloc(|| [0u8, 1, 2]);
+        }
+        // Now, panic while allocating
+        arena.alloc::<Rc<i32>, _>(|| {
+            panic!();
+        });
+    }
+
+    // Drop tests
+
+    struct DropCounter<'a> {
+        count: &'a Cell<u32>,
+    }
+
+    impl<'a> Drop for DropCounter<'a> {
+        fn drop(&mut self) {
+            self.count.set(self.count.get() + 1);
+        }
+    }
+
+    #[test]
+    fn test_arena_drop_count() {
+        let counter = Cell::new(0);
+        {
+            let arena = Arena::new();
+            for _ in 0..100 {
+                // Allocate something with drop glue to make sure it doesn't leak.
+                arena.alloc(|| DropCounter { count: &counter });
+                // Allocate something with funny size and alignment, to keep
+                // things interesting.
+                arena.alloc(|| [0u8, 1u8, 2u8]);
+            }
+            // dropping
+        };
+        assert_eq!(counter.get(), 100);
+    }
+
+    #[test]
+    fn test_arena_drop_on_clear() {
+        let counter = Cell::new(0);
+        for i in 0..10 {
+            let mut arena = Arena::new();
+            for _ in 0..100 {
+                // Allocate something with drop glue to make sure it doesn't leak.
+                arena.alloc(|| DropCounter { count: &counter });
+                // Allocate something with funny size and alignment, to keep
+                // things interesting.
+                arena.alloc(|| [0u8, 1u8, 2u8]);
+            }
+            arena.clear();
+            assert_eq!(counter.get(), i * 100 + 100);
+        }
+    }
+
+    #[test]
+    fn test_typed_arena_drop_count() {
+        let counter = Cell::new(0);
+        {
+            let arena: TypedArena<DropCounter> = TypedArena::new();
+            for _ in 0..100 {
+                // Allocate something with drop glue to make sure it doesn't leak.
+                arena.alloc(DropCounter { count: &counter });
+            }
+        };
+        assert_eq!(counter.get(), 100);
+    }
+
+    #[test]
+    fn test_typed_arena_drop_on_clear() {
+        let counter = Cell::new(0);
+        let mut arena: TypedArena<DropCounter> = TypedArena::new();
+        for i in 0..10 {
+            for _ in 0..100 {
+                // Allocate something with drop glue to make sure it doesn't leak.
+                arena.alloc(DropCounter { count: &counter });
+            }
+            arena.clear();
+            assert_eq!(counter.get(), i * 100 + 100);
+        }
+    }
+
+    thread_local! {
+        static DROP_COUNTER: Cell<u32> = Cell::new(0)
+    }
+
+    struct SmallDroppable;
+
+    impl Drop for SmallDroppable {
+        fn drop(&mut self) {
+            DROP_COUNTER.with(|c| c.set(c.get() + 1));
+        }
+    }
+
+    #[test]
+    fn test_arena_drop_small_count() {
+        DROP_COUNTER.with(|c| c.set(0));
+        {
+            let arena = Arena::new();
+            for _ in 0..10 {
+                for _ in 0..10 {
+                    // Allocate something with drop glue to make sure it doesn't leak.
+                    arena.alloc(|| SmallDroppable);
+                }
+                // Allocate something with funny size and alignment, to keep
+                // things interesting.
+                arena.alloc(|| [0u8, 1u8, 2u8]);
+            }
+            // dropping
+        };
+        assert_eq!(DROP_COUNTER.with(|c| c.get()), 100);
+    }
+
+    #[test]
+    fn test_typed_arena_drop_small_count() {
+        DROP_COUNTER.with(|c| c.set(0));
+        {
+            let arena: TypedArena<SmallDroppable> = TypedArena::new();
+            for _ in 0..100 {
+                // Allocate something with drop glue to make sure it doesn't leak.
+                arena.alloc(SmallDroppable);
+            }
+            // dropping
+        };
+        assert_eq!(DROP_COUNTER.with(|c| c.get()), 100);
+    }
+
     #[bench]
     pub fn bench_noncopy(b: &mut Bencher) {
         let arena = TypedArena::new();
@@ -638,10 +892,10 @@ pub fn bench_noncopy(b: &mut Bencher) {
     #[bench]
     pub fn bench_noncopy_nonarena(b: &mut Bencher) {
         b.iter(|| {
-            let _: Box<_> = box Noncopy {
+            let _: Box<_> = Box::new(Noncopy {
                 string: "hello world".to_string(),
                 array: vec![1, 2, 3, 4, 5],
-            };
+            });
         })
     }
 
index 5ab329c696d77d808f8359baa0074376da9c7f0f..6b60e3b3b07382a48c7ffbaf992876426234bdee 100644 (file)
@@ -6,7 +6,7 @@
 
        * configure.ac: Add --enable-host-shared.
        * configure: Regenerate.
-
+\f
 Copyright (C) 2013-2014 Free Software Foundation, Inc.
 
 Copying and distribution of this file, with or without modification,
index ea78c701632166d9832d89d1448f58fbc24954fa..c5f0dcbcf7a19157326dec3e9e408d4cdafd8e60 100644 (file)
@@ -6,12 +6,12 @@
 # met:
 
 #     (1) Redistributions of source code must retain the above copyright
-#     notice, this list of conditions and the following disclaimer.
+#     notice, this list of conditions and the following disclaimer. 
 
 #     (2) Redistributions in binary form must reproduce the above copyright
 #     notice, this list of conditions and the following disclaimer in
 #     the documentation and/or other materials provided with the
-#     distribution.
+#     distribution.  
 
 #     (3) The name of the author may not be used to
 #     endorse or promote products derived from this software without
index 16b1a72712ffd044dcb36849aa678abe8a7242aa..b434d76edb620e81aa048bdea1019c0fd8213a4a 100644 (file)
 # met:
 
 #     (1) Redistributions of source code must retain the above copyright
-#     notice, this list of conditions and the following disclaimer.
+#     notice, this list of conditions and the following disclaimer. 
 
 #     (2) Redistributions in binary form must reproduce the above copyright
 #     notice, this list of conditions and the following disclaimer in
 #     the documentation and/or other materials provided with the
-#     distribution.
+#     distribution.  
 
 #     (3) The name of the author may not be used to
 #     endorse or promote products derived from this software without
@@ -137,10 +137,10 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
        $(LDFLAGS) -o $@
 SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
        $(btest_SOURCES) $(stest_SOURCES)
-MULTISRCTOP =
-MULTIBUILDTOP =
-MULTIDIRS =
-MULTISUBDIR =
+MULTISRCTOP = 
+MULTIBUILDTOP = 
+MULTIDIRS = 
+MULTISUBDIR = 
 MULTIDO = true
 MULTICLEAN = true
 am__can_run_installinfo = \
@@ -389,7 +389,7 @@ config.h: stamp-h1
 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
        @rm -f stamp-h1
        cd $(top_builddir) && $(SHELL) ./config.status config.h
-$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
        ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
        rm -f stamp-h1
        touch $@
@@ -407,7 +407,7 @@ clean-noinstLTLIBRARIES:
          echo "rm -f \"$${dir}/so_locations\""; \
          rm -f "$${dir}/so_locations"; \
        done
-libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EXTRA_libbacktrace_la_DEPENDENCIES)
+libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EXTRA_libbacktrace_la_DEPENDENCIES) 
        $(LINK)  $(libbacktrace_la_OBJECTS) $(libbacktrace_la_LIBADD) $(LIBS)
 
 clean-checkPROGRAMS:
@@ -418,10 +418,10 @@ clean-checkPROGRAMS:
        list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
        echo " rm -f" $$list; \
        rm -f $$list
-btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES)
+btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES) 
        @rm -f btest$(EXEEXT)
        $(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS)
-stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES)
+stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES) 
        @rm -f stest$(EXEEXT)
        $(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS)
 
index c9d6a1406b7b2e58110593e5ef64fe18e1511204..143ef68ca5148943104b14eb40cc1f3fa8808f7a 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index 40e4ff93cf68ace004289f81ff5e347d8e8f96a0..fdd2490da7c6bdcd50e9e328e5ba495b11557e47 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index 976963e71041ba8dce060e56ce4f5949f7303801..ab051a1689826ba57d4bdf8688beb1a643a97e98 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index 8941375c6cd5575ceecd08b65a1202218eb28568..d352d27a4006d98a755a1a16cbeeb53a4c2d3cf2 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index f16ee36cbce9ad9ab00da24d0e146d017392efd1..50dcd40751b22c7268ef001e8a397cf274d79b7a 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index a950a704f071d7caf2e3fd9fa5f04b9ae8d38e0c..9821e34c0c1ba69c48b98e71b75e46533c8a030e 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
@@ -460,7 +460,7 @@ f23 (int f1line, int f2line)
                       (unsigned int) bdata.index, j + 1);
              bdata.failed = 1;
            }
-       }
+       }      
 
       check ("test3", 0, all, f3line, "f23", &bdata.failed);
       check ("test3", 1, all, f2line, "f22", &bdata.failed);
index 30d890ef14a9fb44c75e189941877f08366f1658..a0e487bb42d71fa88cda59a0b16cbf733716cfaa 100644 (file)
@@ -6,13 +6,13 @@
 # met:
 
 #     (1) Redistributions of source code must retain the above copyright
-#     notice, this list of conditions and the following disclaimer.
+#     notice, this list of conditions and the following disclaimer. 
 
 #     (2) Redistributions in binary form must reproduce the above copyright
 #     notice, this list of conditions and the following disclaimer in
 #     the documentation and/or other materials provided with the
-#     distribution.
-
+#     distribution.  
+    
 #     (3) The name of the author may not be used to
 #     endorse or promote products derived from this software without
 #     specific prior written permission.
index fd3beac01fbafd8f8f9e60f82a3e436f6e4ba917..54e5ace9b4a68cc557fcc96dce7477ea01af4a62 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
@@ -1246,7 +1246,7 @@ add_unit_ranges (struct backtrace_state *state, uintptr_t base_address,
 
 static int
 find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
-                    struct dwarf_buf *unit_buf,
+                    struct dwarf_buf *unit_buf, 
                     const unsigned char *dwarf_str, size_t dwarf_str_size,
                     const unsigned char *dwarf_ranges,
                     size_t dwarf_ranges_size,
@@ -1605,7 +1605,7 @@ read_line_header (struct backtrace_state *state, struct unit *u,
 
   if (!advance (line_buf, hdrlen))
     return 0;
-
+  
   hdr->min_insn_len = read_byte (&hdr_buf);
   if (hdr->version < 4)
     hdr->max_ops_per_insn = 1;
@@ -1614,7 +1614,7 @@ read_line_header (struct backtrace_state *state, struct unit *u,
 
   /* We don't care about default_is_stmt.  */
   read_byte (&hdr_buf);
-
+  
   hdr->line_base = read_sbyte (&hdr_buf);
   hdr->line_range = read_byte (&hdr_buf);
 
index 932ce86435131a1f54aafad359afd6168e45cd50..71a37b30c9f87b429bab08a4a420caa9a6385503 100644 (file)
 
 /* This file declares various DWARF-related constants using a set of
    macros which can be redefined by the including file.
-
+   
    The macros are in sections.  Each section corresponds to a single
    set of DWARF constants and has a corresponding key.  The key is
    used in all the macro names.
-
+   
    The sections are TAG (for DW_TAG_ constants), FORM (DW_FORM_), AT
    (DW_AT_), OP (DW_OP_), ATE (DW_ATE_), and CFA (DW_CFA_).
-
+   
    Using TAG as an example, the following macros may be used for each
    key:
-
+   
    DW_FIRST_TAG(name, value) - Introduce the first DW_TAG constant.
-
+   
    DW_TAG(name, value) - Define a subsequent constant.
-
+   
    DW_TAG_DUP(name, value) - Define a subsequent constant whose value
    is a duplicate of some other constant.  Not all keys use the _DUP
    macro form.  If more than one name shares a value, then the base
    (DW_TAG) form will be the preferred name and DW_TAG_DUP will hold
    any alternate names.
-
+   
    DW_END_TAG - Invoked at the end of the DW_TAG constants.  */
 
 DW_FIRST_TAG (DW_TAG_padding, 0x00)
index c7d49ebb2401b6fb79ce4158e055760fb7d15744..120e2c16b4820f823c75ab8b2aa7c00bab6291fa 100644 (file)
@@ -352,7 +352,7 @@ enum dwarf_macro_record_type
     DW_MACRO_GNU_lo_user = 0xe0,
     DW_MACRO_GNU_hi_user = 0xff
   };
-
+\f
 /* @@@ For use with GNU frame unwind information.  */
 
 #define DW_EH_PE_absptr                0x00
index f0709c9c355dc4f028d95ffb703c0f894727ce41..3f14b11a43c8388f9220122ce8b3e47e1137e0b5 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index c151147213431f29cedda13f78655835dd93e9ac..0acad0603eeb071a4b114cf3a7f544536a1be405 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index f6046ee6057c5c621fe0fedd22c7a289e2522903..30f99ca127f8e8035b18c4b772adf989aa508fbf 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index 610548a8a4e220d9b008b7d23a17ff9a0c9c603f..1ecf131191142879ca808b864eb47810a71c5bbe 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index 45f81a8593d9f72197a0001cb8e93e0b920d3fb2..b5a787e0aa6fd8bd8a50a37167b1d0ef3c9922bc 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index 9952c0bcbfb7bd5b8c452837bd1690612d301d20..f53f906b5a89cb2c617067ed3b43b99acd0cec01 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index f6260a0044eaa0855d6202bd329fa40cf0107569..7fa7cd0d5da6760713ca827d90858105a4d4ab12 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index 271f41c0c59bfeebcb6c9d72d2ac659ca0afcacd..90ecaf89edad0258b80aed7232cba4fe87352500 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index 70dd91ee97c8fd805e59be4c087a4b9b2669817b..299f77ba7c629848f8e22b113f15f2c96747c0ea 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index fc0f4f498012c883b3dea172e5b94423605a8724..39c2e902ff77b17adf036f388fd6bc8b25f36aa4 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index 01b1cb2b8a5553cf397ab3c01ca64088172210d8..bcc765e93aa777e736ed0b685015398c5fb67dc5 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index 373938865c7fff4236ca6fd6a85fd2e5302e478b..a846378e903c2c7876b9a875cde369c5ffa0332e 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index 510715291895ca8065ee95e3180df4d06388210d..ec93e680e89ed8cda9571e03ff92939190d89e5f 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index 953e96e510e593f33369d1f5bf28d68bd347722c..e89cba96f7d91565d1ab307c238cc6b23dbed283 100644 (file)
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
 met:
 
     (1) Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
+    notice, this list of conditions and the following disclaimer. 
 
     (2) Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
-    distribution.
-
+    distribution.  
+    
     (3) The name of the author may not be used to
     endorse or promote products derived from this software without
     specific prior written permission.
index effd4ebb316725f1c42fea3f01741b2336a266e5..bd329949618e5f4376860f8b3af77db4a041be75 100644 (file)
@@ -354,7 +354,7 @@ pub fn pop(&mut self) -> Option<T> {
         self.data.pop().map(|mut item| {
             if !self.is_empty() {
                 swap(&mut item, &mut self.data[0]);
-                self.sift_down(0);
+                self.sift_down_to_bottom(0);
             }
             item
         })
@@ -545,6 +545,31 @@ fn sift_down(&mut self, pos: usize) {
         self.sift_down_range(pos, len);
     }
 
+    /// Take an element at `pos` and move it all the way down the heap,
+    /// then sift it up to its position.
+    ///
+    /// Note: This is faster when the element is known to be large / should
+    /// be closer to the bottom.
+    fn sift_down_to_bottom(&mut self, mut pos: usize) {
+        let end = self.len();
+        let start = pos;
+        unsafe {
+            let mut hole = Hole::new(&mut self.data, pos);
+            let mut child = 2 * pos + 1;
+            while child < end {
+                let right = child + 1;
+                // compare with the greater of the two children
+                if right < end && !(hole.get(child) > hole.get(right)) {
+                    child = right;
+                }
+                hole.move_to(child);
+                child = 2 * hole.pos() + 1;
+            }
+            pos = hole.pos;
+        }
+        self.sift_up(start, pos);
+    }
+
     /// Returns the length of the binary heap.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> usize {
index 370857287d6e6aea59368b200ddd79eca66b0e21..8b876df32af5245b4b40a417e3cde5b8e62e0465 100644 (file)
@@ -10,7 +10,7 @@
 
 //! Collection types.
 //!
-//! See [std::collections](../std/collections) for a detailed discussion of
+//! See [std::collections](../std/collections/index.html) for a detailed discussion of
 //! collections in Rust.
 
 #![crate_name = "collections"]
index c70aa67366b342edd2fca8a398b86a483306ed45..afcd779ddf19f92db8c6b575b2619905675893a3 100644 (file)
@@ -8,8 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![unstable(feature = "collections_range", reason = "was just added",
-            issue = "27711")]
+#![unstable(feature = "collections_range",
+            reason = "waiting for dust to settle on inclusive ranges",
+            issue = "30877")]
 
 //! Range syntax.
 
index 92c23ef2f38b828f8827754f21ddfd123b5c84e0..766867f284ee1f0c0e5148f7a650b08272501669 100644 (file)
@@ -857,9 +857,10 @@ pub fn utf16_units(&self) -> Utf16Units {
         Utf16Units { encoder: Utf16Encoder::new(self[..].chars()) }
     }
 
-    /// Returns `true` if the given `&str` is a sub-slice of this string slice.
+    /// Returns `true` if the given pattern matches a sub-slice of
+    /// this string slice.
     ///
-    /// Returns `false` if it's not.
+    /// Returns `false` if it does not.
     ///
     /// # Examples
     ///
@@ -876,9 +877,10 @@ pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
         core_str::StrExt::contains(self, pat)
     }
 
-    /// Returns `true` if the given `&str` is a prefix of this string slice.
+    /// Returns `true` if the given pattern matches a prefix of this
+    /// string slice.
     ///
-    /// Returns `false` if it's not.
+    /// Returns `false` if it does not.
     ///
     /// # Examples
     ///
@@ -895,9 +897,10 @@ pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
         core_str::StrExt::starts_with(self, pat)
     }
 
-    /// Returns `true` if the given `&str` is a suffix of this string slice.
+    /// Returns `true` if the given pattern matches a suffix of this
+    /// string slice.
     ///
-    /// Returns `false` if not.
+    /// Returns `false` if it does not.
     ///
     /// # Examples
     ///
@@ -1381,7 +1384,7 @@ pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
     ///
     /// For iterating from the front, the [`matches()`] method can be used.
     ///
-    /// [`matches`]: #method.matches
+    /// [`matches()`]: #method.matches
     ///
     /// # Examples
     ///
@@ -1681,11 +1684,11 @@ pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
         core_str::StrExt::parse(self)
     }
 
-    /// Replaces all occurrences of one string with another.
+    /// Replaces all matches of a pattern with another string.
     ///
     /// `replace` creates a new [`String`], and copies the data from this string slice into it.
-    /// While doing so, it attempts to find a sub-`&str`. If it finds it, it replaces it with
-    /// the replacement string slice.
+    /// While doing so, it attempts to find matches of a pattern. If it finds any, it
+    /// replaces them with the replacement string slice.
     ///
     /// [`String`]: string/struct.String.html
     ///
@@ -1699,14 +1702,14 @@ pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
     /// assert_eq!("this is new", s.replace("old", "new"));
     /// ```
     ///
-    /// When a `&str` isn't found:
+    /// When the pattern doesn't match:
     ///
     /// ```
     /// let s = "this is old";
     /// assert_eq!(s, s.replace("cookie monster", "little lamb"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn replace(&self, from: &str, to: &str) -> String {
+    pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String {
         let mut result = String::new();
         let mut last_end = 0;
         for (start, part) in self.match_indices(from) {
index d2cbcad875f347a5249f547829ca463c424bb431..eb9628d6e39dd7e00975dfff28a0f33758ed0d19 100644 (file)
 //!
 //! [`String`]: struct.String.html
 //! [`ToString`]: trait.ToString.html
+//!
+//! # Examples
+//!
+//! There are multiple ways to create a new `String` from a string literal:
+//!
+//! ```rust
+//! let s = "Hello".to_string();
+//!
+//! let s = String::from("world");
+//! let s: String = "also this".into();
+//! ```
+//!
+//! You can create a new `String` from an existing one by concatenating with
+//! `+`:
+//!
+//! ```rust
+//! let s = "Hello".to_string();
+//!
+//! let message = s + " world!";
+//! ```
+//!
+//! If you have a vector of valid UTF-8 bytes, you can make a `String` out of
+//! it. You can do the reverse too.
+//!
+//! ```rust
+//! let sparkle_heart = vec![240, 159, 146, 150];
+//!
+//! // We know these bytes are valid, so we'll use `unwrap()`.
+//! let sparkle_heart = String::from_utf8(sparkle_heart).unwrap();
+//!
+//! assert_eq!("💖", sparkle_heart);
+//!
+//! let bytes = sparkle_heart.into_bytes();
+//!
+//! assert_eq!(bytes, [240, 159, 146, 150]);
+//! ```
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -62,6 +98,7 @@
 /// hello.push_str("orld!");
 /// ```
 ///
+/// [`char`]: ../primitive.char.html
 /// [`push()`]: #method.push
 /// [`push_str()`]: #method.push_str
 ///
 /// ```
 ///
 /// [`as_ptr()`]: #method.as_ptr
-/// [`len()`]: # method.len
-/// [`capacity()`]: # method.capacity
+/// [`len()`]: #method.len
+/// [`capacity()`]: #method.capacity
 ///
 /// If a `String` has enough capacity, adding elements to it will not
 /// re-allocate. For example, consider this program:
@@ -444,7 +481,7 @@ pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
     /// Converts a slice of bytes to a `String`, including invalid characters.
     ///
     /// A string slice ([`&str`]) is made of bytes ([`u8`]), and a slice of
-    /// bytes ([`&[u8]`]) is made of bytes, so this function converts between
+    /// bytes ([`&[u8]`][byteslice]) is made of bytes, so this function converts between
     /// the two. Not all byte slices are valid string slices, however: [`&str`]
     /// requires that it is valid UTF-8. During this conversion,
     /// `from_utf8_lossy()` will replace any invalid UTF-8 sequences with
@@ -452,7 +489,7 @@ pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
     ///
     /// [`&str`]: ../primitive.str.html
     /// [`u8`]: ../primitive.u8.html
-    /// [`&[u8]`]: ../primitive.slice.html
+    /// [byteslice]: ../primitive.slice.html
     ///
     /// If you are sure that the byte slice is valid UTF-8, and you don't want
     /// to incur the overhead of the conversion, there is an unsafe version
@@ -1311,6 +1348,8 @@ pub fn into_bytes(self) -> Vec<u8> {
     ///
     /// [`Utf8Error`]: ../str/struct.Utf8Error.html
     /// [`std::str`]: ../str/index.html
+    /// [`u8`]: ../primitive.u8.html
+    /// [`&str`]: ../primitive.str.html
     ///
     /// # Examples
     ///
index e22ff7ca540610335c22e1b1705d9213c07d1851..4d84855ddf97f3b7bf712b72b5b737ddc70b26cd 100644 (file)
@@ -269,6 +269,15 @@ fn test_replace_2d() {
     assert_eq!(data.replace(d, repl), data);
 }
 
+#[test]
+fn test_replace_pattern() {
+    let data = "abcdαβγδabcdαβγδ";
+    assert_eq!(data.replace("dαβ", "😺😺😺"), "abc😺😺😺γδabc😺😺😺γδ");
+    assert_eq!(data.replace('γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ");
+    assert_eq!(data.replace(&['a', 'γ'] as &[_], "😺😺😺"), "😺😺😺bcdαβ😺😺😺δ😺😺😺bcdαβ😺😺😺δ");
+    assert_eq!(data.replace(|c| c == 'γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ");
+}
+
 #[test]
 fn test_slice() {
     assert_eq!("ab", &"abc"[0..2]);
index 628bf654873c7cfc7e8195fbf9d7146d607ef618..4033fea1f8e5d892bd189b9cd8a8098c297869bd 100644 (file)
@@ -1569,7 +1569,7 @@ fn fmt(&self, f: &mut Formatter) -> Result {
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Debug for PhantomData<T> {
+impl<T: ?Sized> Debug for PhantomData<T> {
     fn fmt(&self, f: &mut Formatter) -> Result {
         f.pad("PhantomData")
     }
index a30e5b1372af98daf081ea88d524c177e1d0b533..e3e783329ec812e003d8d6cd915648eac8c86c86 100644 (file)
@@ -321,7 +321,6 @@ fn _assert_is_object_safe(_: &Iterator<Item=()>) {}
 ///
 /// [module-level documentation]: index.html
 /// [impl]: index.html#implementing-iterator
-#[lang = "iterator"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented = "`{Self}` is not an iterator; maybe try calling \
                             `.iter()` or a similar method"]
@@ -1359,7 +1358,7 @@ fn by_ref(&mut self) -> &mut Self where Self: Sized { self }
     /// One of the keys to `collect()`'s power is that many things you might
     /// not think of as 'collections' actually are. For example, a [`String`]
     /// is a collection of [`char`]s. And a collection of [`Result<T, E>`] can
-    /// be thought of as single [`Result<Collection<T>, E>`]. See the examples
+    /// be thought of as single `Result<Collection<T>, E>`. See the examples
     /// below for more.
     ///
     /// [`String`]: ../string/struct.String.html
index 65ddae51b98f63ab960701eb2f9557fb2c240ce4..621dce3efc86bf8ca7e7c8f13f477e86c5253168 100644 (file)
@@ -295,6 +295,10 @@ fn default() -> $t<T> {
 /// even though it does not. This allows you to inform the compiler about certain safety properties
 /// of your code.
 ///
+/// For a more in-depth explanation of how to use `PhantomData<T>`, please see [the Nomicon].
+///
+/// [the Nomicon]: ../../nomicon/phantom-data.html
+///
 /// # A ghastly note 👻👻👻
 ///
 /// Though they both have scary names, `PhantomData<T>` and 'phantom types' are related, but not
index ee6e708ea327defa7ad3c8e68db99469b1435ed1..fb6dac407983423fa721668cd4a07728f19f933d 100644 (file)
@@ -130,7 +130,7 @@ pub fn size_of<T>() -> usize {
     unsafe { intrinsics::size_of::<T>() }
 }
 
-/// Returns the size of the type that `val` points to in bytes.
+/// Returns the size of the given value in bytes.
 ///
 /// # Examples
 ///
index 1f0f06d746197151f704f818a50de782b6d67b91..82d3389edc478d8fa2fcbed631f483620c2c4ccf 100644 (file)
@@ -60,17 +60,13 @@ pub fn fast_path<T: RawFloat>(integral: &[u8], fractional: &[u8], e: i64) -> Opt
     if f > T::max_sig() {
         return None;
     }
-    let e = e as i16; // Can't overflow because e.abs() <= LOG5_OF_EXP_N
     // The case e < 0 cannot be folded into the other branch. Negative powers result in
     // a repeating fractional part in binary, which are rounded, which causes real
     // (and occasioally quite significant!) errors in the final result.
-    // The case `e == 0`, however, is unnecessary for correctness. It's just measurably faster.
-    if e == 0 {
-        Some(T::from_int(f))
-    } else if e > 0 {
-        Some(T::from_int(f) * fp_to_float(power_of_ten(e)))
+    if e >= 0 {
+        Some(T::from_int(f) * T::short_fast_pow10(e as usize))
     } else {
-        Some(T::from_int(f) / fp_to_float(power_of_ten(-e)))
+        Some(T::from_int(f) / T::short_fast_pow10(e.abs() as usize))
     }
 }
 
index 197589740032ad40e16ea2fb725f9ad871eb4206..2099c6a7baa7649960065f6688d4fae745339368 100644 (file)
@@ -37,6 +37,7 @@
 use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan};
 use num::Float;
 use num::dec2flt::num::{self, Big};
+use num::dec2flt::table;
 
 #[derive(Copy, Clone, Debug)]
 pub struct Unpacked {
@@ -73,6 +74,9 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp
     /// represented, the other code in this module makes sure to never let that happen.
     fn from_int(x: u64) -> Self;
 
+    /// Get the value 10^e from a pre-computed table. Panics for e >= ceil_log5_of_max_sig().
+    fn short_fast_pow10(e: usize) -> Self;
+
     // FIXME Everything that follows should be associated constants, but taking the value of an
     // associated constant from a type parameter does not work (yet?)
     // A possible workaround is having a `FloatInfo` struct for all the constants, but so far
@@ -175,6 +179,10 @@ fn from_int(x: u64) -> f32 {
         x as f32
     }
 
+    fn short_fast_pow10(e: usize) -> Self {
+        table::F32_SHORT_POWERS[e]
+    }
+
     fn max_normal_digits() -> usize {
         35
     }
@@ -222,6 +230,10 @@ fn from_int(x: u64) -> f64 {
         x as f64
     }
 
+    fn short_fast_pow10(e: usize) -> Self {
+        table::F64_SHORT_POWERS[e]
+    }
+
     fn max_normal_digits() -> usize {
         305
     }
index dd985fd155b850417cd3326d7ffcadac407f4b4f..cb8c94313d030cb526a427bdabbf19cd6d8794c0 100644 (file)
@@ -7,8 +7,10 @@
 // <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.
-// Table of approximations of powers of ten.
-// DO NOT MODIFY: Generated by a src/etc/dec2flt_table.py
+
+//! Tables of approximations of powers of ten.
+//! DO NOT MODIFY: Generated by `src/etc/dec2flt_table.py`
+
 pub const MIN_E: i16 = -305;
 pub const MAX_E: i16 = 305;
 
     946,
     950,
 ]);
+
+pub const F32_SHORT_POWERS: [f32; 11] = [
+    1e0,
+    1e1,
+    1e2,
+    1e3,
+    1e4,
+    1e5,
+    1e6,
+    1e7,
+    1e8,
+    1e9,
+    1e10,
+];
+
+pub const F64_SHORT_POWERS: [f64; 23] = [
+    1e0,
+    1e1,
+    1e2,
+    1e3,
+    1e4,
+    1e5,
+    1e6,
+    1e7,
+    1e8,
+    1e9,
+    1e10,
+    1e11,
+    1e12,
+    1e13,
+    1e14,
+    1e15,
+    1e16,
+    1e17,
+    1e18,
+    1e19,
+    1e20,
+    1e21,
+    1e22,
+];
index f180a513b869d8bf4374cc3af6b0fc12c81c9a79..76214366dc6d4d3cc7a9fe78b51e437ba30acdfc 100644 (file)
@@ -124,7 +124,7 @@ macro_rules! checked_op {
 
 // `Int` + `SignedInt` implemented for signed integers
 macro_rules! int_impl {
-    ($ActualT:ty, $UnsignedT:ty, $BITS:expr,
+    ($ActualT:ident, $UnsignedT:ty, $BITS:expr,
      $add_with_overflow:path,
      $sub_with_overflow:path,
      $mul_with_overflow:path) => {
@@ -393,7 +393,8 @@ pub fn to_le(self) -> Self {
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
         pub fn checked_add(self, other: Self) -> Option<Self> {
-            checked_op!($ActualT, $add_with_overflow, self, other)
+            let (a, b) = self.overflowing_add(other);
+            if b {None} else {Some(a)}
         }
 
         /// Checked integer subtraction. Computes `self - other`, returning
@@ -410,7 +411,8 @@ pub fn checked_add(self, other: Self) -> Option<Self> {
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
         pub fn checked_sub(self, other: Self) -> Option<Self> {
-            checked_op!($ActualT, $sub_with_overflow, self, other)
+            let (a, b) = self.overflowing_sub(other);
+            if b {None} else {Some(a)}
         }
 
         /// Checked integer multiplication. Computes `self * other`, returning
@@ -427,7 +429,8 @@ pub fn checked_sub(self, other: Self) -> Option<Self> {
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
         pub fn checked_mul(self, other: Self) -> Option<Self> {
-            checked_op!($ActualT, $mul_with_overflow, self, other)
+            let (a, b) = self.overflowing_mul(other);
+            if b {None} else {Some(a)}
         }
 
         /// Checked integer division. Computes `self / other`, returning `None`
@@ -445,14 +448,103 @@ pub fn checked_mul(self, other: Self) -> Option<Self> {
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
         pub fn checked_div(self, other: Self) -> Option<Self> {
-            match other {
-                0    => None,
-               -1 if self == Self::min_value()
-                     => None,
-               other => Some(self / other),
+            if other == 0 {
+                None
+            } else {
+                let (a, b) = self.overflowing_div(other);
+                if b {None} else {Some(a)}
             }
         }
 
+        /// Checked integer remainder. Computes `self % other`, returning `None`
+        /// if `other == 0` or the operation results in underflow or overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// use std::i32;
+        ///
+        /// assert_eq!(5i32.checked_rem(2), Some(1));
+        /// assert_eq!(5i32.checked_rem(0), None);
+        /// assert_eq!(i32::MIN.checked_rem(-1), None);
+        /// ```
+        #[unstable(feature = "wrapping", issue = "27755")]
+        #[inline]
+        pub fn checked_rem(self, other: Self) -> Option<Self> {
+            if other == 0 {
+                None
+            } else {
+                let (a, b) = self.overflowing_rem(other);
+                if b {None} else {Some(a)}
+            }
+        }
+
+        /// Checked negation. Computes `!self`, returning `None` if `self ==
+        /// MIN`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// use std::i32;
+        ///
+        /// assert_eq!(5i32.checked_neg(), Some(-5));
+        /// assert_eq!(i32::MIN.checked_neg(), None);
+        /// ```
+        #[unstable(feature = "wrapping", issue = "27755")]
+        #[inline]
+        pub fn checked_neg(self) -> Option<Self> {
+            let (a, b) = self.overflowing_neg();
+            if b {None} else {Some(a)}
+        }
+
+        /// Checked shift left. Computes `self << rhs`, returning `None`
+        /// if `rhs` is larger than or equal to the number of bits in `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(0x10i32.checked_shl(4), Some(0x100));
+        /// assert_eq!(0x10i32.checked_shl(33), None);
+        /// ```
+        #[unstable(feature = "wrapping", issue = "27755")]
+        #[inline]
+        pub fn checked_shl(self, rhs: u32) -> Option<Self> {
+            let (a, b) = self.overflowing_shl(rhs);
+            if b {None} else {Some(a)}
+        }
+
+        /// Checked shift right. Computes `self >> rhs`, returning `None`
+        /// if `rhs` is larger than or equal to the number of bits in `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(0x10i32.checked_shr(4), Some(0x1));
+        /// assert_eq!(0x10i32.checked_shr(33), None);
+        /// ```
+        #[unstable(feature = "wrapping", issue = "27755")]
+        #[inline]
+        pub fn checked_shr(self, rhs: u32) -> Option<Self> {
+            let (a, b) = self.overflowing_shr(rhs);
+            if b {None} else {Some(a)}
+        }
+
         /// Saturating integer addition. Computes `self + other`, saturating at
         /// the numeric bounds instead of overflowing.
         ///
@@ -468,7 +560,7 @@ pub fn checked_div(self, other: Self) -> Option<Self> {
         #[inline]
         pub fn saturating_add(self, other: Self) -> Self {
             match self.checked_add(other) {
-                Some(x)                       => x,
+                Some(x) => x,
                 None if other >= Self::zero() => Self::max_value(),
                 None => Self::min_value(),
             }
@@ -489,12 +581,40 @@ pub fn saturating_add(self, other: Self) -> Self {
         #[inline]
         pub fn saturating_sub(self, other: Self) -> Self {
             match self.checked_sub(other) {
-                Some(x)                      => x,
+                Some(x) => x,
                 None if other >= Self::zero() => Self::min_value(),
                 None => Self::max_value(),
             }
         }
 
+        /// Saturating integer multiplication. Computes `self * other`,
+        /// saturating at the numeric bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// use std::i32;
+        ///
+        /// assert_eq!(100i32.saturating_mul(127), 12700);
+        /// assert_eq!((1i32 << 23).saturating_mul(1 << 23), i32::MAX);
+        /// assert_eq!((-1i32 << 23).saturating_mul(1 << 23), i32::MIN);
+        /// ```
+        #[unstable(feature = "wrapping", issue = "27755")]
+        #[inline]
+        pub fn saturating_mul(self, other: Self) -> Self {
+            self.checked_mul(other).unwrap_or_else(|| {
+                if (self < 0 && other < 0) || (self > 0 && other > 0) {
+                    Self::max_value()
+                } else {
+                    Self::min_value()
+                }
+            })
+        }
+
         /// Wrapping (modular) addition. Computes `self + other`,
         /// wrapping around at the boundary of the type.
         ///
@@ -562,6 +682,10 @@ pub fn wrapping_mul(self, rhs: Self) -> Self {
         /// in the type. In such a case, this function returns `MIN`
         /// itself.
         ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
         /// # Examples
         ///
         /// Basic usage:
@@ -584,6 +708,10 @@ pub fn wrapping_div(self, rhs: Self) -> Self {
         /// -1` on a signed type (where `MIN` is the negative
         /// minimal value). In such a case, this function returns `0`.
         ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
         /// # Examples
         ///
         /// Basic usage:
@@ -657,6 +785,230 @@ pub fn wrapping_shr(self, rhs: u32) -> Self {
             self.overflowing_shr(rhs).0
         }
 
+        /// Calculates `self` + `rhs`
+        ///
+        /// Returns a tuple of the addition along with a boolean indicating
+        /// whether an arithmetic overflow would occur. If an overflow would
+        /// have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// use std::i32;
+        ///
+        /// assert_eq!(5i32.overflowing_add(2), (7, false));
+        /// assert_eq!(i32::MAX.overflowing_add(1), (i32::MIN, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+            unsafe {
+                let (a, b) = $add_with_overflow(self as $ActualT,
+                                                rhs as $ActualT);
+                (a as Self, b)
+            }
+        }
+
+        /// Calculates `self` - `rhs`
+        ///
+        /// Returns a tuple of the subtraction along with a boolean indicating
+        /// whether an arithmetic overflow would occur. If an overflow would
+        /// have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// use std::i32;
+        ///
+        /// assert_eq!(5i32.overflowing_sub(2), (3, false));
+        /// assert_eq!(i32::MIN.overflowing_sub(1), (i32::MAX, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+            unsafe {
+                let (a, b) = $sub_with_overflow(self as $ActualT,
+                                                rhs as $ActualT);
+                (a as Self, b)
+            }
+        }
+
+        /// Calculates the multiplication of `self` and `rhs`.
+        ///
+        /// Returns a tuple of the multiplication along with a boolean
+        /// indicating whether an arithmetic overflow would occur. If an
+        /// overflow would have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(5i32.overflowing_mul(2), (10, false));
+        /// assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
+            unsafe {
+                let (a, b) = $mul_with_overflow(self as $ActualT,
+                                                rhs as $ActualT);
+                (a as Self, b)
+            }
+        }
+
+        /// Calculates the divisor when `self` is divided by `rhs`.
+        ///
+        /// Returns a tuple of the divisor along with a boolean indicating
+        /// whether an arithmetic overflow would occur. If an overflow would
+        /// occur then self is returned.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// use std::i32;
+        ///
+        /// assert_eq!(5i32.overflowing_div(2), (2, false));
+        /// assert_eq!(i32::MIN.overflowing_div(-1), (i32::MIN, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_div(self, rhs: Self) -> (Self, bool) {
+            if self == Self::min_value() && rhs == -1 {
+                (self, true)
+            } else {
+                (self / rhs, false)
+            }
+        }
+
+        /// Calculates the remainder when `self` is divided by `rhs`.
+        ///
+        /// Returns a tuple of the remainder after dividing along with a boolean
+        /// indicating whether an arithmetic overflow would occur. If an
+        /// overflow would occur then 0 is returned.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// use std::i32;
+        ///
+        /// assert_eq!(5i32.overflowing_rem(2), (1, false));
+        /// assert_eq!(i32::MIN.overflowing_rem(-1), (0, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
+            if self == Self::min_value() && rhs == -1 {
+                (0, true)
+            } else {
+                (self % rhs, false)
+            }
+        }
+
+        /// Negates self, overflowing if this is equal to the minimum value.
+        ///
+        /// Returns a tuple of the negated version of self along with a boolean
+        /// indicating whether an overflow happened. If `self` is the minimum
+        /// value (e.g. `i32::MIN` for values of type `i32`), then the minimum
+        /// value will be returned again and `true` will be returned for an
+        /// overflow happening.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// use std::i32;
+        ///
+        /// assert_eq!(2i32.overflowing_neg(), (-2, false));
+        /// assert_eq!(i32::MIN.overflowing_neg(), (i32::MIN, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_neg(self) -> (Self, bool) {
+            if self == Self::min_value() {
+                (Self::min_value(), true)
+            } else {
+                (-self, false)
+            }
+        }
+
+        /// Shifts self left by `rhs` bits.
+        ///
+        /// Returns a tuple of the shifted version of self along with a boolean
+        /// indicating whether the shift value was larger than or equal to the
+        /// number of bits. If the shift value is too large, then value is
+        /// masked (N-1) where N is the number of bits, and this value is then
+        /// used to perform the shift.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(0x10i32.overflowing_shl(4), (0x100, false));
+        /// assert_eq!(0x10i32.overflowing_shl(36), (0x100, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+            (self << (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
+        }
+
+        /// Shifts self right by `rhs` bits.
+        ///
+        /// Returns a tuple of the shifted version of self along with a boolean
+        /// indicating whether the shift value was larger than or equal to the
+        /// number of bits. If the shift value is too large, then value is
+        /// masked (N-1) where N is the number of bits, and this value is then
+        /// used to perform the shift.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(0x10i32.overflowing_shr(4), (0x1, false));
+        /// assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+            (self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
+        }
+
         /// Raises self to the power of `exp`, using exponentiation by squaring.
         ///
         /// # Examples
@@ -1121,7 +1473,8 @@ pub fn to_le(self) -> Self {
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
         pub fn checked_add(self, other: Self) -> Option<Self> {
-            checked_op!($ActualT, $add_with_overflow, self, other)
+            let (a, b) = self.overflowing_add(other);
+            if b {None} else {Some(a)}
         }
 
         /// Checked integer subtraction. Computes `self - other`, returning
@@ -1138,7 +1491,8 @@ pub fn checked_add(self, other: Self) -> Option<Self> {
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
         pub fn checked_sub(self, other: Self) -> Option<Self> {
-            checked_op!($ActualT, $sub_with_overflow, self, other)
+            let (a, b) = self.overflowing_sub(other);
+            if b {None} else {Some(a)}
         }
 
         /// Checked integer multiplication. Computes `self * other`, returning
@@ -1155,7 +1509,8 @@ pub fn checked_sub(self, other: Self) -> Option<Self> {
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline]
         pub fn checked_mul(self, other: Self) -> Option<Self> {
-            checked_op!($ActualT, $mul_with_overflow, self, other)
+            let (a, b) = self.overflowing_mul(other);
+            if b {None} else {Some(a)}
         }
 
         /// Checked integer division. Computes `self / other`, returning `None`
@@ -1179,6 +1534,69 @@ pub fn checked_div(self, other: Self) -> Option<Self> {
             }
         }
 
+        /// Checked integer remainder. Computes `self % other`, returning `None`
+        /// if `other == 0` or the operation results in underflow or overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(5u32.checked_rem(2), Some(1));
+        /// assert_eq!(5u32.checked_rem(0), None);
+        /// ```
+        #[unstable(feature = "wrapping", issue = "27755")]
+        #[inline]
+        pub fn checked_rem(self, other: Self) -> Option<Self> {
+            if other == 0 {
+                None
+            } else {
+                Some(self % other)
+            }
+        }
+
+        /// Checked shift left. Computes `self << rhs`, returning `None`
+        /// if `rhs` is larger than or equal to the number of bits in `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(0x10u32.checked_shl(4), Some(0x100));
+        /// assert_eq!(0x10u32.checked_shl(33), None);
+        /// ```
+        #[unstable(feature = "wrapping", issue = "27755")]
+        #[inline]
+        pub fn checked_shl(self, rhs: u32) -> Option<Self> {
+            let (a, b) = self.overflowing_shl(rhs);
+            if b {None} else {Some(a)}
+        }
+
+        /// Checked shift right. Computes `self >> rhs`, returning `None`
+        /// if `rhs` is larger than or equal to the number of bits in `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(0x10u32.checked_shr(4), Some(0x1));
+        /// assert_eq!(0x10u32.checked_shr(33), None);
+        /// ```
+        #[unstable(feature = "wrapping", issue = "27755")]
+        #[inline]
+        pub fn checked_shr(self, rhs: u32) -> Option<Self> {
+            let (a, b) = self.overflowing_shr(rhs);
+            if b {None} else {Some(a)}
+        }
+
         /// Saturating integer addition. Computes `self + other`, saturating at
         /// the numeric bounds instead of overflowing.
         ///
@@ -1221,6 +1639,27 @@ pub fn saturating_sub(self, other: Self) -> Self {
             }
         }
 
+        /// Saturating integer multiplication. Computes `self * other`,
+        /// saturating at the numeric bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// use std::u32;
+        ///
+        /// assert_eq!(100u32.saturating_mul(127), 12700);
+        /// assert_eq!((1u32 << 23).saturating_mul(1 << 23), u32::MAX);
+        /// ```
+        #[unstable(feature = "wrapping", issue = "27755")]
+        #[inline]
+        pub fn saturating_mul(self, other: Self) -> Self {
+            self.checked_mul(other).unwrap_or(Self::max_value())
+        }
+
         /// Wrapping (modular) addition. Computes `self + other`,
         /// wrapping around at the boundary of the type.
         ///
@@ -1383,6 +1822,211 @@ pub fn wrapping_shr(self, rhs: u32) -> Self {
             self.overflowing_shr(rhs).0
         }
 
+        /// Calculates `self` + `rhs`
+        ///
+        /// Returns a tuple of the addition along with a boolean indicating
+        /// whether an arithmetic overflow would occur. If an overflow would
+        /// have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// use std::u32;
+        ///
+        /// assert_eq!(5u32.overflowing_add(2), (7, false));
+        /// assert_eq!(u32::MAX.overflowing_add(1), (0, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+            unsafe {
+                let (a, b) = $add_with_overflow(self as $ActualT,
+                                                rhs as $ActualT);
+                (a as Self, b)
+            }
+        }
+
+        /// Calculates `self` - `rhs`
+        ///
+        /// Returns a tuple of the subtraction along with a boolean indicating
+        /// whether an arithmetic overflow would occur. If an overflow would
+        /// have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// use std::u32;
+        ///
+        /// assert_eq!(5u32.overflowing_sub(2), (3, false));
+        /// assert_eq!(0u32.overflowing_sub(1), (u32::MAX, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+            unsafe {
+                let (a, b) = $sub_with_overflow(self as $ActualT,
+                                                rhs as $ActualT);
+                (a as Self, b)
+            }
+        }
+
+        /// Calculates the multiplication of `self` and `rhs`.
+        ///
+        /// Returns a tuple of the multiplication along with a boolean
+        /// indicating whether an arithmetic overflow would occur. If an
+        /// overflow would have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(5u32.overflowing_mul(2), (10, false));
+        /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
+            unsafe {
+                let (a, b) = $mul_with_overflow(self as $ActualT,
+                                                rhs as $ActualT);
+                (a as Self, b)
+            }
+        }
+
+        /// Calculates the divisor when `self` is divided by `rhs`.
+        ///
+        /// Returns a tuple of the divisor along with a boolean indicating
+        /// whether an arithmetic overflow would occur. Note that for unsigned
+        /// integers overflow never occurs, so the second value is always
+        /// `false`.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(5u32.overflowing_div(2), (2, false));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_div(self, rhs: Self) -> (Self, bool) {
+            (self / rhs, false)
+        }
+
+        /// Calculates the remainder when `self` is divided by `rhs`.
+        ///
+        /// Returns a tuple of the remainder after dividing along with a boolean
+        /// indicating whether an arithmetic overflow would occur. Note that for
+        /// unsigned integers overflow never occurs, so the second value is
+        /// always `false`.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(5u32.overflowing_rem(2), (1, false));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
+            (self % rhs, false)
+        }
+
+        /// Negates self in an overflowing fashion.
+        ///
+        /// Returns `!self + 1` using wrapping operations to return the value
+        /// that represents the negation of this unsigned value. Note that for
+        /// positive unsigned values overflow always occurs, but negating 0 does
+        /// not overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(0u32.overflowing_neg(), (0, false));
+        /// assert_eq!(2u32.overflowing_neg(), (-2i32 as u32, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_neg(self) -> (Self, bool) {
+            ((!self).wrapping_add(1), self != 0)
+        }
+
+        /// Shifts self left by `rhs` bits.
+        ///
+        /// Returns a tuple of the shifted version of self along with a boolean
+        /// indicating whether the shift value was larger than or equal to the
+        /// number of bits. If the shift value is too large, then value is
+        /// masked (N-1) where N is the number of bits, and this value is then
+        /// used to perform the shift.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(0x10u32.overflowing_shl(4), (0x100, false));
+        /// assert_eq!(0x10u32.overflowing_shl(36), (0x100, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+            (self << (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
+        }
+
+        /// Shifts self right by `rhs` bits.
+        ///
+        /// Returns a tuple of the shifted version of self along with a boolean
+        /// indicating whether the shift value was larger than or equal to the
+        /// number of bits. If the shift value is too large, then value is
+        /// masked (N-1) where N is the number of bits, and this value is then
+        /// used to perform the shift.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(wrapping)]
+        ///
+        /// assert_eq!(0x10u32.overflowing_shr(4), (0x1, false));
+        /// assert_eq!(0x10u32.overflowing_shr(36), (0x1, true));
+        /// ```
+        #[inline]
+        #[unstable(feature = "wrapping", issue = "27755")]
+        pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+            (self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
+        }
+
         /// Raises self to the power of `exp`, using exponentiation by squaring.
         ///
         /// # Examples
index e0c0bf439add63a6a25a25ba47e4aec9547bf9af..95d6a00134f284e6b889d98f4c2cb4b285950327 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e0c0bf439add63a6a25a25ba47e4aec9547bf9af
+Subproject commit 95d6a00134f284e6b889d98f4c2cb4b285950327
index 178d8a872141805332a20665eb74f17a9efde2fe..3aabe4b4931307d10bf6e12b3967a6066ae56d5a 100644 (file)
@@ -1822,6 +1822,30 @@ fn main() {
 //      |
 //    type `i32` assigned to variable `x`
 ```
+
+Another situation in which this occurs is when you attempt to use the `try!`
+macro inside a function that does not return a `Result<T, E>`:
+
+```
+use std::fs::File;
+
+fn main() {
+    let mut f = try!(File::create("foo.txt"));
+}
+```
+
+This code gives an error like this:
+
+```text
+<std macros>:5:8: 6:42 error: mismatched types:
+ expected `()`,
+     found `core::result::Result<_, _>`
+ (expected (),
+     found enum `core::result::Result`) [E0308]
+```
+
+`try!` returns a `Result<T, E>`, and so the function must. But `main()` has
+`()` as its return type, hence the error.
 "##,
 
 E0309: r##"
index aff925d108272cb40f96dad30552e4911013300a..93a46090b90eb018427a3f455b7322a0518ab7c8 100644 (file)
     "type parameter default erroneously allowed in invalid location"
 }
 
+declare_lint! {
+    pub MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
+    Warn,
+    "unit struct or enum variant erroneously allowed to match via path::ident(..)"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -159,6 +165,7 @@ fn get_lints(&self) -> LintArray {
             TRIVIAL_NUMERIC_CASTS,
             PRIVATE_IN_PUBLIC,
             INVALID_TYPE_PARAM_DEFAULT,
+            MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
             CONST_ERR
         )
     }
index 08fba2dc56feefdbc5009d1234a9e95d7fa68265..d7eacbfff90db6032a350216a64ac37c2f6b84fa 100644 (file)
@@ -28,7 +28,7 @@
 use dep_graph::DepNode;
 use middle::privacy::AccessLevels;
 use middle::ty;
-use session::{early_error, Session};
+use session::{config, early_error, Session};
 use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
 use lint::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject};
 use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
 
 use std::cell::RefCell;
 use std::cmp;
+use std::default::Default as StdDefault;
 use std::mem;
 use syntax::ast_util::{self, IdVisitingOperation};
 use syntax::attr::{self, AttrMetaMethods};
 use syntax::codemap::Span;
-use syntax::errors::{self, DiagnosticBuilder};
+use syntax::errors::DiagnosticBuilder;
 use syntax::parse::token::InternedString;
 use syntax::ast;
 use syntax::attr::ThinAttributesExt;
@@ -168,7 +169,7 @@ fn push_pass<P: LintPass + ?Sized + 'static>(&mut self,
                 match (sess, from_plugin) {
                     // We load builtin lints first, so a duplicate is a compiler bug.
                     // Use early_error when handling -W help with no crate.
-                    (None, _) => early_error(errors::ColorConfig::Auto, &msg[..]),
+                    (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
                     (Some(sess), false) => sess.bug(&msg[..]),
 
                     // A duplicate name from a plugin is a user error.
@@ -192,7 +193,7 @@ pub fn register_group(&mut self, sess: Option<&Session>,
             match (sess, from_plugin) {
                 // We load builtin lints first, so a duplicate is a compiler bug.
                 // Use early_error when handling -W help with no crate.
-                (None, _) => early_error(errors::ColorConfig::Auto, &msg[..]),
+                (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
                 (Some(sess), false) => sess.bug(&msg[..]),
 
                 // A duplicate name from a plugin is a user error.
index 972f9e2c64d0e195aa8b33d4ee2eb15cf8cf53c5..a33142433463adb5b0760b50b4a49abc57b10a3e 100644 (file)
@@ -19,9 +19,8 @@
 use middle::const_eval::EvalHint::ExprTypeChecked;
 use middle::def::*;
 use middle::def_id::{DefId};
-use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Init};
-use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode};
-use middle::expr_use_visitor::WriteAndRead;
+use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
+use middle::expr_use_visitor::{LoanCause, MutateMode};
 use middle::expr_use_visitor as euv;
 use middle::infer;
 use middle::mem_categorization::{cmt};
@@ -1161,10 +1160,10 @@ fn borrow(&mut self,
     fn decl_without_init(&mut self, _: NodeId, _: Span) {}
     fn mutate(&mut self, _: NodeId, span: Span, _: cmt, mode: MutateMode) {
         match mode {
-            JustWrite | WriteAndRead => {
+            MutateMode::JustWrite | MutateMode::WriteAndRead => {
                 span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
             }
-            Init => {}
+            MutateMode::Init => {}
         }
     }
 }
index 23d1617e5c658e39ee93d285a5b2bdcde6b94efb..e746f3ac57914a712f61b39e935902a1219e72fe 100644 (file)
@@ -12,7 +12,6 @@
 //! normal visitor, which just walks the entire body in one shot, the
 //! `ExprUseVisitor` determines how expressions are being used.
 
-pub use self::MutateMode::*;
 pub use self::LoanCause::*;
 pub use self::ConsumeMode::*;
 pub use self::MoveReason::*;
@@ -465,7 +464,11 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
                         self.consume_expr(&*output.expr);
                     } else {
                         self.mutate_expr(expr, &*output.expr,
-                                         if output.is_rw { WriteAndRead } else { JustWrite });
+                                         if output.is_rw {
+                                             MutateMode::WriteAndRead
+                                         } else {
+                                             MutateMode::JustWrite
+                                         });
                     }
                 }
             }
@@ -519,7 +522,7 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
             }
 
             hir::ExprAssign(ref lhs, ref rhs) => {
-                self.mutate_expr(expr, &**lhs, JustWrite);
+                self.mutate_expr(expr, &**lhs, MutateMode::JustWrite);
                 self.consume_expr(&**rhs);
             }
 
@@ -532,7 +535,7 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
                 assert!(::rustc_front::util::is_by_value_binop(op.node));
 
                 if !self.walk_overloaded_operator(expr, lhs, vec![rhs], PassArgs::ByValue) {
-                    self.mutate_expr(expr, &**lhs, WriteAndRead);
+                    self.mutate_expr(expr, &**lhs, MutateMode::WriteAndRead);
                     self.consume_expr(&**rhs);
                 }
             }
@@ -991,7 +994,7 @@ fn walk_pat(&mut self,
                 let def = def_map.borrow().get(&pat.id).unwrap().full_def();
                 match mc.cat_def(pat.id, pat.span, pat_ty, def) {
                     Ok(binding_cmt) => {
-                        delegate.mutate(pat.id, pat.span, binding_cmt, Init);
+                        delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
                     }
                     Err(_) => { }
                 }
index cb166fbff05859a00e6a9bdaaddb475c81f17401..0f95aa74b6fd731f5f93720b23e09067219ffff5 100644 (file)
@@ -63,9 +63,9 @@ fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>,
                                                                 b_def_id,
                                                                 util::fresh_type_vars_for_impl);
 
-    debug!("overlap: a_trait_ref={:?}", a_trait_ref);
+    debug!("overlap: a_trait_ref={:?} a_obligations={:?}", a_trait_ref, a_obligations);
 
-    debug!("overlap: b_trait_ref={:?}", b_trait_ref);
+    debug!("overlap: b_trait_ref={:?} b_obligations={:?}", b_trait_ref, b_obligations);
 
     // Do `a` and `b` unify? If not, no overlap.
     if let Err(_) = infer::mk_eq_trait_refs(selcx.infcx(),
@@ -330,8 +330,11 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>,
             tt.principal_def_id().is_local()
         }
 
-        ty::TyClosure(..) |
         ty::TyError => {
+            true
+        }
+
+        ty::TyClosure(..) => {
             tcx.sess.bug(
                 &format!("ty_is_local invoked on unexpected type: {:?}",
                         ty))
index ad3524661d326a4b8abb0023c97dae8292510073..e9d7b330d07acc17f15bbc29f093e63dd3812872 100644 (file)
@@ -426,11 +426,25 @@ fn opt_normalize_projection_type<'a,'b,'tcx>(
     }
 }
 
-/// in various error cases, we just set TyError and return an obligation
-/// that, when fulfilled, will lead to an error.
+/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
+/// hold. In various error cases, we cannot generate a valid
+/// normalized projection. Therefore, we create an inference variable
+/// return an associated obligation that, when fulfilled, will lead to
+/// an error.
 ///
-/// FIXME: the TyError created here can enter the obligation we create,
-/// leading to error messages involving TyError.
+/// Note that we used to return `TyError` here, but that was quite
+/// dubious -- the premise was that an error would *eventually* be
+/// reported, when the obligation was processed. But in general once
+/// you see a `TyError` you are supposed to be able to assume that an
+/// error *has been* reported, so that you can take whatever heuristic
+/// paths you want to take. To make things worse, it was possible for
+/// cycles to arise, where you basically had a setup like `<MyType<$0>
+/// as Trait>::Foo == $0`. Here, normalizing `<MyType<$0> as
+/// Trait>::Foo> to `[type error]` would lead to an obligation of
+/// `<MyType<[type error]> as Trait>::Foo`.  We are supposed to report
+/// an error for this obligation, but we legitimately should not,
+/// because it contains `[type error]`. Yuck! (See issue #29857 for
+/// one case where this arose.)
 fn normalize_to_error<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
                                projection_ty: ty::ProjectionTy<'tcx>,
                                cause: ObligationCause<'tcx>,
@@ -441,8 +455,9 @@ fn normalize_to_error<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
     let trait_obligation = Obligation { cause: cause,
                                         recursion_depth: depth,
                                         predicate: trait_ref.to_predicate() };
+    let new_value = selcx.infcx().next_ty_var();
     Normalized {
-        value: selcx.tcx().types.err,
+        value: new_value,
         obligations: vec!(trait_obligation)
     }
 }
index f544f8ce362341f1c4ef71f3e5f088a1b0b8348f..f6d0da904a40f0bd15b197c854a0777da08aeaff 100644 (file)
@@ -210,8 +210,6 @@ enum SelectionCandidate<'tcx> {
     BuiltinObjectCandidate,
 
     BuiltinUnsizeCandidate,
-
-    ErrorCandidate,
 }
 
 struct SelectionCandidateSet<'tcx> {
@@ -753,8 +751,15 @@ fn candidate_from_obligation_no_cache<'o>(&mut self,
                                               stack: &TraitObligationStack<'o, 'tcx>)
                                               -> SelectionResult<'tcx, SelectionCandidate<'tcx>>
     {
-        if stack.obligation.predicate.0.self_ty().references_error() {
-            return Ok(Some(ErrorCandidate));
+        if stack.obligation.predicate.references_error() {
+            // If we encounter a `TyError`, we generally prefer the
+            // most "optimistic" result in response -- that is, the
+            // one least likely to report downstream errors. But
+            // because this routine is shared by coherence and by
+            // trait selection, there isn't an obvious "right" choice
+            // here in that respect, so we opt to just return
+            // ambiguity and let the upstream clients sort it out.
+            return Ok(None);
         }
 
         if !self.is_knowable(stack) {
@@ -1587,7 +1592,6 @@ fn candidate_should_be_dropped_in_favor_of<'o>(&mut self,
                     true
                 },
                 &ParamCandidate(..) => false,
-                &ErrorCandidate => false // propagate errors
             },
             _ => false
         }
@@ -1998,10 +2002,6 @@ fn confirm_candidate(&mut self,
                     try!(self.confirm_builtin_candidate(obligation, builtin_bound))))
             }
 
-            ErrorCandidate => {
-                Ok(VtableBuiltin(VtableBuiltinData { nested: vec![] }))
-            }
-
             ParamCandidate(param) => {
                 let obligations = self.confirm_param_candidate(obligation, param);
                 Ok(VtableParam(obligations))
index 6ca39d3ba7a8758f7481adee2297fc9b7c3c3db6..1b0dfc73229613a56babad1cd099123edd233fe2 100644 (file)
@@ -314,10 +314,19 @@ pub fn successors_mut(&mut self) -> &mut [BasicBlock] {
         }
     }
 
-    pub fn destination(&self) -> Option<Lvalue<'tcx>> {
+    pub fn destination(&self) -> Option<&Lvalue<'tcx>> {
         match *self {
             CallKind::Converging { ref destination, .. } |
-            CallKind::ConvergingCleanup { ref destination, .. } => Some(destination.clone()),
+            CallKind::ConvergingCleanup { ref destination, .. } => Some(destination),
+            CallKind::Diverging |
+            CallKind::DivergingCleanup(_) => None
+        }
+    }
+
+    pub fn destination_mut(&mut self) -> Option<&mut Lvalue<'tcx>> {
+        match *self {
+            CallKind::Converging { ref mut destination, .. } |
+            CallKind::ConvergingCleanup { ref mut destination, .. } => Some(destination),
             CallKind::Diverging |
             CallKind::DivergingCleanup(_) => None
         }
index 0134bcdf1757b2913f6dbcb70b4b13b5157687e3..1a99aba591a8cb29e78c650b6da87d9fdce3775a 100644 (file)
@@ -14,7 +14,6 @@
 pub use self::EntryFnType::*;
 pub use self::CrateType::*;
 pub use self::Passes::*;
-pub use self::OptLevel::*;
 pub use self::DebugInfoLevel::*;
 
 use session::{early_error, early_warn, Session};
@@ -71,6 +70,18 @@ pub enum OutputType {
     DepInfo,
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum ErrorOutputType {
+    HumanReadable(ColorConfig),
+    Json,
+}
+
+impl Default for ErrorOutputType {
+    fn default() -> ErrorOutputType {
+        ErrorOutputType::HumanReadable(ColorConfig::Auto)
+    }
+}
+
 impl OutputType {
     fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
         match *self {
@@ -124,6 +135,7 @@ pub struct Options {
     pub test: bool,
     pub parse_only: bool,
     pub no_trans: bool,
+    pub error_format: ErrorOutputType,
     pub treat_err_as_bug: bool,
     pub incremental_compilation: bool,
     pub dump_dep_graph: bool,
@@ -131,8 +143,6 @@ pub struct Options {
     pub debugging_opts: DebuggingOptions,
     pub prints: Vec<PrintRequest>,
     pub cg: CodegenOptions,
-    pub color: ColorConfig,
-    pub show_span: Option<String>,
     pub externs: HashMap<String, Vec<String>>,
     pub crate_name: Option<String>,
     /// An optional name to use as the crate for std during std injection,
@@ -222,7 +232,7 @@ pub fn basic_options() -> Options {
     Options {
         crate_types: Vec::new(),
         gc: false,
-        optimize: No,
+        optimize: OptLevel::No,
         debuginfo: NoDebugInfo,
         lint_opts: Vec::new(),
         lint_cap: None,
@@ -242,8 +252,7 @@ pub fn basic_options() -> Options {
         debugging_opts: basic_debugging_options(),
         prints: Vec::new(),
         cg: basic_codegen_options(),
-        color: ColorConfig::Auto,
-        show_span: None,
+        error_format: ErrorOutputType::default(),
         externs: HashMap::new(),
         crate_name: None,
         alt_std_name: None,
@@ -310,7 +319,7 @@ pub fn $defaultfn() -> $struct_name {
         $struct_name { $($opt: $init),* }
     }
 
-    pub fn $buildfn(matches: &getopts::Matches, color: ColorConfig) -> $struct_name
+    pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
     {
         let mut op = $defaultfn();
         for option in matches.opt_strs($prefix) {
@@ -324,20 +333,20 @@ pub fn $buildfn(matches: &getopts::Matches, color: ColorConfig) -> $struct_name
                 if !setter(&mut op, value) {
                     match (value, opt_type_desc) {
                         (Some(..), None) => {
-                            early_error(color, &format!("{} option `{}` takes no \
-                                                         value", $outputname, key))
+                            early_error(error_format, &format!("{} option `{}` takes no \
+                                                              value", $outputname, key))
                         }
                         (None, Some(type_desc)) => {
-                            early_error(color, &format!("{0} option `{1}` requires \
-                                                         {2} ({3} {1}=<value>)",
-                                                        $outputname, key,
-                                                        type_desc, $prefix))
+                            early_error(error_format, &format!("{0} option `{1}` requires \
+                                                              {2} ({3} {1}=<value>)",
+                                                             $outputname, key,
+                                                             type_desc, $prefix))
                         }
                         (Some(value), Some(type_desc)) => {
-                            early_error(color, &format!("incorrect value `{}` for {} \
-                                                         option `{}` - {} was expected",
-                                                        value, $outputname,
-                                                        key, type_desc))
+                            early_error(error_format, &format!("incorrect value `{}` for {} \
+                                                              option `{}` - {} was expected",
+                                                             value, $outputname,
+                                                             key, type_desc))
                         }
                         (None, None) => unreachable!()
                     }
@@ -346,8 +355,8 @@ pub fn $buildfn(matches: &getopts::Matches, color: ColorConfig) -> $struct_name
                 break;
             }
             if !found {
-                early_error(color, &format!("unknown {} option: `{}`",
-                                            $outputname, key));
+                early_error(error_format, &format!("unknown {} option: `{}`",
+                                                 $outputname, key));
             }
         }
         return op;
@@ -543,8 +552,6 @@ fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
         "explicitly enable the cfg(debug_assertions) directive"),
     inline_threshold: Option<usize> = (None, parse_opt_uint,
         "set the inlining threshold for"),
-    disable_gold: bool = (false, parse_bool,
-        "disable use of the ld.gold linker"),
 }
 
 
@@ -634,6 +641,8 @@ fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
           "don't clear the resolution tables after analysis"),
     keep_ast: bool = (false, parse_bool,
           "keep the AST after lowering it to HIR"),
+    show_span: Option<String> = (None, parse_opt_string,
+          "show spans for compiler debugging (expr|pat|ty)"),
 }
 
 pub fn default_lib_output() -> CrateType {
@@ -863,6 +872,7 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
                  "NAME=PATH"),
         opt::opt("", "sysroot", "Override the system root", "PATH"),
         opt::multi("Z", "", "Set internal debugging options", "FLAG"),
+        opt::opt_u("", "error-format", "How errors and other messages are produced", "human|json"),
         opt::opt("", "color", "Configure coloring of output:
             auto   = colorize, if output goes to a tty (default);
             always = always colorize output;
@@ -882,7 +892,6 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
                       `hir` (the HIR), `hir,identified`, or
                       `hir,typed` (HIR with types for each node).",
                      "TYPE"),
-        opt::opt_u("", "show-span", "Show spans for compiler debugging", "expr|pat|ty"),
     ]);
     opts
 }
@@ -906,15 +915,37 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         None => ColorConfig::Auto,
 
         Some(arg) => {
-            early_error(ColorConfig::Auto, &format!("argument for --color must be auto, always \
-                                                     or never (instead was `{}`)",
-                                                    arg))
+            early_error(ErrorOutputType::default(), &format!("argument for --color must be auto, \
+                                                              always or never (instead was `{}`)",
+                                                            arg))
         }
     };
 
+    // We need the opts_present check because the driver will send us Matches
+    // with only stable options if no unstable options are used. Since error-format
+    // is unstable, it will not be present. We have to use opts_present not
+    // opt_present because the latter will panic.
+    let error_format = if matches.opts_present(&["error-format".to_owned()]) {
+        match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
+            Some("human")   => ErrorOutputType::HumanReadable(color),
+            Some("json") => ErrorOutputType::Json,
+
+            None => ErrorOutputType::default(),
+
+            Some(arg) => {
+                early_error(ErrorOutputType::default(), &format!("argument for --error-format must \
+                                                                  be human or json (instead was \
+                                                                  `{}`)",
+                                                                 arg))
+            }
+        }
+    } else {
+        ErrorOutputType::default()
+    };
+
     let unparsed_crate_types = matches.opt_strs("crate-type");
     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
-        .unwrap_or_else(|e| early_error(color, &e[..]));
+        .unwrap_or_else(|e| early_error(error_format, &e[..]));
 
     let mut lint_opts = vec!();
     let mut describe_lints = false;
@@ -931,11 +962,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     let lint_cap = matches.opt_str("cap-lints").map(|cap| {
         lint::Level::from_str(&cap).unwrap_or_else(|| {
-            early_error(color, &format!("unknown lint level: `{}`", cap))
+            early_error(error_format, &format!("unknown lint level: `{}`", cap))
         })
     });
 
-    let debugging_opts = build_debugging_options(matches, color);
+    let debugging_opts = build_debugging_options(matches, error_format);
 
     let parse_only = debugging_opts.parse_only;
     let no_trans = debugging_opts.no_trans;
@@ -961,7 +992,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
                     "link" => OutputType::Exe,
                     "dep-info" => OutputType::DepInfo,
                     part => {
-                        early_error(color, &format!("unknown emission type: `{}`",
+                        early_error(error_format, &format!("unknown emission type: `{}`",
                                                     part))
                     }
                 };
@@ -974,7 +1005,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         output_types.insert(OutputType::Exe, None);
     }
 
-    let mut cg = build_codegen_options(matches, color);
+    let mut cg = build_codegen_options(matches, error_format);
 
     // Issue #30063: if user requests llvm-related output to one
     // particular path, disable codegen-units.
@@ -986,11 +1017,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
             }).collect();
         if !incompatible.is_empty() {
             for ot in &incompatible {
-                early_warn(color, &format!("--emit={} with -o incompatible with \
-                                            -C codegen-units=N for N > 1",
-                                           ot.shorthand()));
+                early_warn(error_format, &format!("--emit={} with -o incompatible with \
+                                                 -C codegen-units=N for N > 1",
+                                                ot.shorthand()));
             }
-            early_warn(color, "resetting to default -C codegen-units=1");
+            early_warn(error_format, "resetting to default -C codegen-units=1");
             cg.codegen_units = 1;
         }
     }
@@ -1003,29 +1034,29 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     let opt_level = {
         if matches.opt_present("O") {
             if cg.opt_level.is_some() {
-                early_error(color, "-O and -C opt-level both provided");
+                early_error(error_format, "-O and -C opt-level both provided");
             }
-            Default
+            OptLevel::Default
         } else {
             match cg.opt_level {
-                None => No,
-                Some(0) => No,
-                Some(1) => Less,
-                Some(2) => Default,
-                Some(3) => Aggressive,
+                None => OptLevel::No,
+                Some(0) => OptLevel::No,
+                Some(1) => OptLevel::Less,
+                Some(2) => OptLevel::Default,
+                Some(3) => OptLevel::Aggressive,
                 Some(arg) => {
-                    early_error(color, &format!("optimization level needs to be \
-                                                 between 0-3 (instead was `{}`)",
-                                                arg));
+                    early_error(error_format, &format!("optimization level needs to be \
+                                                      between 0-3 (instead was `{}`)",
+                                                     arg));
                 }
             }
         }
     };
-    let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == No);
+    let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
     let gc = debugging_opts.gc;
     let debuginfo = if matches.opt_present("g") {
         if cg.debuginfo.is_some() {
-            early_error(color, "-g and -C debuginfo both provided");
+            early_error(error_format, "-g and -C debuginfo both provided");
         }
         FullDebugInfo
     } else {
@@ -1034,16 +1065,16 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
             Some(1) => LimitedDebugInfo,
             Some(2) => FullDebugInfo,
             Some(arg) => {
-                early_error(color, &format!("debug info level needs to be between \
-                                             0-2 (instead was `{}`)",
-                                            arg));
+                early_error(error_format, &format!("debug info level needs to be between \
+                                                  0-2 (instead was `{}`)",
+                                                 arg));
             }
         }
     };
 
     let mut search_paths = SearchPaths::new();
     for s in &matches.opt_strs("L") {
-        search_paths.add_path(&s[..], color);
+        search_paths.add_path(&s[..], error_format);
     }
 
     let libs = matches.opt_strs("l").into_iter().map(|s| {
@@ -1055,9 +1086,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
             (Some(name), "framework") => (name, cstore::NativeFramework),
             (Some(name), "static") => (name, cstore::NativeStatic),
             (_, s) => {
-                early_error(color, &format!("unknown library kind `{}`, expected \
-                                             one of dylib, framework, or static",
-                                            s));
+                early_error(error_format, &format!("unknown library kind `{}`, expected \
+                                                  one of dylib, framework, or static",
+                                                 s));
             }
         };
         (name.to_string(), kind)
@@ -1072,14 +1103,14 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
             "file-names" => PrintRequest::FileNames,
             "sysroot" => PrintRequest::Sysroot,
             req => {
-                early_error(color, &format!("unknown print request `{}`", req))
+                early_error(error_format, &format!("unknown print request `{}`", req))
             }
         }
     }).collect::<Vec<_>>();
 
     if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
-        early_warn(color, "-C remark will not show source locations without \
-                           --debuginfo");
+        early_warn(error_format, "-C remark will not show source locations without \
+                                --debuginfo");
     }
 
     let mut externs = HashMap::new();
@@ -1087,11 +1118,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         let mut parts = arg.splitn(2, '=');
         let name = match parts.next() {
             Some(s) => s,
-            None => early_error(color, "--extern value must not be empty"),
+            None => early_error(error_format, "--extern value must not be empty"),
         };
         let location = match parts.next() {
             Some(s) => s,
-            None => early_error(color, "--extern value must be of the format `foo=bar`"),
+            None => early_error(error_format, "--extern value must be of the format `foo=bar`"),
         };
 
         externs.entry(name.to_string()).or_insert(vec![]).push(location.to_string());
@@ -1122,8 +1153,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         debugging_opts: debugging_opts,
         prints: prints,
         cg: cg,
-        color: color,
-        show_span: None,
+        error_format: error_format,
         externs: externs,
         crate_name: crate_name,
         alt_std_name: None,
index 80b4c1916a81626d9c28cc3b8b5271f29acf5328..2f3af1c0d09b5c4b14ab2cfd501d1660f4d9d838 100644 (file)
@@ -17,7 +17,8 @@
 use syntax::ast::{NodeId, NodeIdAssigner, Name};
 use syntax::codemap::Span;
 use syntax::errors::{self, DiagnosticBuilder};
-use syntax::errors::emitter::{Emitter, BasicEmitter};
+use syntax::errors::emitter::{Emitter, BasicEmitter, EmitterWriter};
+use syntax::errors::json::JsonEmitter;
 use syntax::diagnostics;
 use syntax::feature_gate;
 use syntax::parse;
@@ -405,12 +406,19 @@ pub fn build_session(sopts: config::Options,
     let treat_err_as_bug = sopts.treat_err_as_bug;
 
     let codemap = Rc::new(codemap::CodeMap::new());
+    let emitter: Box<Emitter> = match sopts.error_format {
+        config::ErrorOutputType::HumanReadable(color_config) => {
+            Box::new(EmitterWriter::stderr(color_config, Some(registry), codemap.clone()))
+        }
+        config::ErrorOutputType::Json => {
+            Box::new(JsonEmitter::stderr(Some(registry), codemap.clone()))
+        }
+    };
+
     let diagnostic_handler =
-        errors::Handler::new(sopts.color,
-                             Some(registry),
-                             can_print_warnings,
-                             treat_err_as_bug,
-                             codemap.clone());
+        errors::Handler::with_emitter(can_print_warnings,
+                                      treat_err_as_bug,
+                                      emitter);
 
     build_session_(sopts, local_crate_source_file, diagnostic_handler, codemap, cstore)
 }
@@ -473,13 +481,23 @@ pub fn build_session_(sopts: config::Options,
     sess
 }
 
-pub fn early_error(color: errors::ColorConfig, msg: &str) -> ! {
-    let mut emitter = BasicEmitter::stderr(color);
+pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
+    let mut emitter: Box<Emitter> = match output {
+        config::ErrorOutputType::HumanReadable(color_config) => {
+            Box::new(BasicEmitter::stderr(color_config))
+        }
+        config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
+    };
     emitter.emit(None, msg, None, errors::Level::Fatal);
     panic!(errors::FatalError);
 }
 
-pub fn early_warn(color: errors::ColorConfig, msg: &str) {
-    let mut emitter = BasicEmitter::stderr(color);
+pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
+    let mut emitter: Box<Emitter> = match output {
+        config::ErrorOutputType::HumanReadable(color_config) => {
+            Box::new(BasicEmitter::stderr(color_config))
+        }
+        config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
+    };
     emitter.emit(None, msg, None, errors::Level::Warning);
 }
index 6a787139d77aa88c3d96dfa981da7f41c9fbdfde..3c6cd26bef6ce87bfc853f040abae95d848a14a2 100644 (file)
@@ -10,8 +10,7 @@
 
 use std::slice;
 use std::path::{Path, PathBuf};
-use session::early_error;
-use syntax::errors;
+use session::{early_error, config};
 
 #[derive(Clone, Debug)]
 pub struct SearchPaths {
@@ -38,7 +37,7 @@ pub fn new() -> SearchPaths {
         SearchPaths { paths: Vec::new() }
     }
 
-    pub fn add_path(&mut self, path: &str, color: errors::ColorConfig) {
+    pub fn add_path(&mut self, path: &str, output: config::ErrorOutputType) {
         let (kind, path) = if path.starts_with("native=") {
             (PathKind::Native, &path["native=".len()..])
         } else if path.starts_with("crate=") {
@@ -53,7 +52,7 @@ pub fn add_path(&mut self, path: &str, color: errors::ColorConfig) {
             (PathKind::All, path)
         };
         if path.is_empty() {
-            early_error(color, "empty search path given via `-L`");
+            early_error(output, "empty search path given via `-L`");
         }
         self.paths.push((kind, PathBuf::from(path)));
     }
index 21bfd87e412dd5d899ed8ad226d5b0b852d3fa2c..51abab6609a86c52997e73b576723a21a4204833 100644 (file)
@@ -11,8 +11,7 @@
 use target::Target;
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
-    base.has_elf_tls = false;
+    let base = super::linux_base::opts();
     Target {
         llvm_target: "aarch64-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
index 2883ffd6e9f2244ccd24b24dea153eeac6422792..9791520e9339bbd8ad6908b74e70256abbf83673 100644 (file)
@@ -17,5 +17,6 @@ pub fn opts() -> TargetOptions {
     base.pre_link_args.push("-Wl,--allow-multiple-definition".to_string());
     base.is_like_android = true;
     base.position_independent_executables = true;
+    base.has_elf_tls = false;
     base
 }
index 7776aaacd00b1b8f2f2506265a79674658be9917..732f1a353a8bd719c1f363e5fec3c02c9837765d 100644 (file)
@@ -13,7 +13,6 @@
 pub fn target() -> Target {
     let mut base = super::android_base::opts();
     base.features = "+v7".to_string();
-    base.has_elf_tls = false;
 
     Target {
         llvm_target: "arm-linux-androideabi".to_string(),
index 666903b4eed42a881dc1422cce04075b16d85f64..51149101e0c2dd441586d35a197cb59cd191fa86 100644 (file)
@@ -80,7 +80,7 @@ pub struct Target {
     /// Vendor name to use for conditional compilation.
     pub target_vendor: String,
     /// Architecture to use for ABI considerations. Valid options: "x86", "x86_64", "arm",
-    /// "aarch64", "mips", and "powerpc". "mips" includes "mipsel".
+    /// "aarch64", "mips", "powerpc", "powerpc64" and "powerpc64le". "mips" includes "mipsel".
     pub arch: String,
     /// Optional settings with defaults.
     pub options: TargetOptions,
@@ -413,6 +413,8 @@ macro_rules! load_specific {
             mips_unknown_linux_gnu,
             mipsel_unknown_linux_gnu,
             powerpc_unknown_linux_gnu,
+            powerpc64_unknown_linux_gnu,
+            powerpc64le_unknown_linux_gnu,
             arm_unknown_linux_gnueabi,
             arm_unknown_linux_gnueabihf,
             aarch64_unknown_linux_gnu,
diff --git a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs
new file mode 100644 (file)
index 0000000..83970e7
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2012-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 target::Target;
+
+pub fn target() -> Target {
+    let mut base = super::linux_base::opts();
+    base.pre_link_args.push("-m64".to_string());
+
+    Target {
+        llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "64".to_string(),
+        arch: "powerpc64".to_string(),
+        target_os: "linux".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        options: base,
+    }
+}
diff --git a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs
new file mode 100644 (file)
index 0000000..0f5252f
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2012-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 target::Target;
+
+pub fn target() -> Target {
+    let mut base = super::linux_base::opts();
+    base.pre_link_args.push("-m64".to_string());
+
+    Target {
+        llvm_target: "powerpc64le-unknown-linux-gnu".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "64".to_string(),
+        arch: "powerpc64le".to_string(),
+        target_os: "linux".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        options: base,
+    }
+}
index df181aec4ea4c536b13aba9959f6c17f1257d73e..2d30b827750acda7b2bbba833b7689d829066dff 100644 (file)
@@ -21,6 +21,7 @@
 use borrowck::*;
 use borrowck::InteriorKind::{InteriorElement, InteriorField};
 use rustc::middle::expr_use_visitor as euv;
+use rustc::middle::expr_use_visitor::MutateMode;
 use rustc::middle::infer;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
@@ -161,7 +162,7 @@ fn mutate(&mut self,
         match opt_loan_path(&assignee_cmt) {
             Some(lp) => {
                 match mode {
-                    euv::Init | euv::JustWrite => {
+                    MutateMode::Init | MutateMode::JustWrite => {
                         // In a case like `path = 1`, then path does not
                         // have to be *FULLY* initialized, but we still
                         // must be careful lest it contains derefs of
@@ -171,7 +172,7 @@ fn mutate(&mut self,
                                                              MovedInUse,
                                                              &lp);
                     }
-                    euv::WriteAndRead => {
+                    MutateMode::WriteAndRead => {
                         // In a case like `path += 1`, then path must be
                         // fully initialized, since we will read it before
                         // we write it.
index 62404a73ad3be5184bc1a66ed6d0542edbdd7752..735e618cc732b1f0da607b438e7e58c57de0369c 100644 (file)
@@ -20,6 +20,7 @@
 use rustc::middle::dataflow::DataFlowOperator;
 use rustc::middle::dataflow::KillFrom;
 use rustc::middle::expr_use_visitor as euv;
+use rustc::middle::expr_use_visitor::MutateMode;
 use rustc::middle::ty;
 use rustc::util::nodemap::{FnvHashMap, NodeSet};
 
@@ -406,10 +407,10 @@ pub fn add_assignment(&self,
         self.fragments.borrow_mut().add_assignment(path_index);
 
         match mode {
-            euv::Init | euv::JustWrite => {
+            MutateMode::Init | MutateMode::JustWrite => {
                 self.assignee_ids.borrow_mut().insert(assignee_id);
             }
-            euv::WriteAndRead => { }
+            MutateMode::WriteAndRead => { }
         }
 
         let assignment = Assignment {
index d172bfb441358e6ca180ff91b04443c541aec4fb..840260da33086956d30499da09b76782da9453b2 100644 (file)
@@ -428,7 +428,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
         println!("Pre-expansion node count:  {}", count_nodes(&krate));
     }
 
-    if let Some(ref s) = sess.opts.show_span {
+    if let Some(ref s) = sess.opts.debugging_opts.show_span {
         syntax::show_span::run(sess.diagnostic(), s, &krate);
     }
 
index 7b8970876f6e3adc7711e9211920ae81971df266..62bea61216888aec22d1962de40984aea9497419 100644 (file)
@@ -62,7 +62,7 @@
 use rustc_trans::back::link;
 use rustc_trans::save;
 use rustc::session::{config, Session, build_session};
-use rustc::session::config::{Input, PrintRequest, OutputType};
+use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
 use rustc::middle::cstore::CrateStore;
 use rustc::lint::Lint;
 use rustc::lint;
@@ -72,6 +72,7 @@
 
 use std::cmp::max;
 use std::cmp::Ordering::Equal;
+use std::default::Default;
 use std::env;
 use std::io::{self, Read, Write};
 use std::iter::repeat;
@@ -126,7 +127,7 @@ macro_rules! do_or_return {($expr: expr) => {
 
     let descriptions = diagnostics_registry();
 
-    do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.color));
+    do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.error_format));
 
     let (odir, ofile) = make_output(&matches);
     let (input, input_file_path) = match make_input(&matches.free) {
@@ -138,12 +139,9 @@ macro_rules! do_or_return {($expr: expr) => {
     };
 
     let cstore = Rc::new(CStore::new(token::get_ident_interner()));
-    let mut sess = build_session(sopts, input_file_path, descriptions,
+    let sess = build_session(sopts, input_file_path, descriptions,
                                  cstore.clone());
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-    if sess.unstable_options() {
-        sess.opts.show_span = matches.opt_str("show-span");
-    }
     let mut cfg = config::build_configuration(&sess);
     target_features::add_configuration(&mut cfg, &sess);
 
@@ -217,7 +215,7 @@ pub trait CompilerCalls<'a> {
     fn early_callback(&mut self,
                       _: &getopts::Matches,
                       _: &diagnostics::registry::Registry,
-                      _: errors::ColorConfig)
+                      _: ErrorOutputType)
                       -> Compilation {
         Compilation::Continue
     }
@@ -293,7 +291,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
     fn early_callback(&mut self,
                       matches: &getopts::Matches,
                       descriptions: &diagnostics::registry::Registry,
-                      color: errors::ColorConfig)
+                      output: ErrorOutputType)
                       -> Compilation {
         match matches.opt_str("explain") {
             Some(ref code) => {
@@ -308,7 +306,7 @@ fn early_callback(&mut self,
                         print!("{}", &description[1..]);
                     }
                     None => {
-                        early_error(color, &format!("no extended information for {}", code));
+                        early_error(output, &format!("no extended information for {}", code));
                     }
                 }
                 return Compilation::Stop;
@@ -342,10 +340,10 @@ fn no_input(&mut self,
                 if should_stop == Compilation::Stop {
                     return None;
                 }
-                early_error(sopts.color, "no input filename given");
+                early_error(sopts.error_format, "no input filename given");
             }
             1 => panic!("make_input should have provided valid inputs"),
-            _ => early_error(sopts.color, "multiple input filenames provided"),
+            _ => early_error(sopts.error_format, "multiple input filenames provided"),
         }
 
         None
@@ -387,7 +385,7 @@ fn late_callback(&mut self,
     fn build_controller(&mut self, sess: &Session) -> CompileController<'a> {
         let mut control = CompileController::basic();
 
-        if sess.opts.parse_only || sess.opts.show_span.is_some() ||
+        if sess.opts.parse_only || sess.opts.debugging_opts.show_span.is_some() ||
            sess.opts.debugging_opts.ast_json_noexpand {
             control.after_parse.stop = Compilation::Stop;
         }
@@ -435,7 +433,7 @@ pub fn list_metadata(sess: &Session, matches: &getopts::Matches, input: &Input)
                     println!("{}", String::from_utf8(v).unwrap());
                 }
                 &Input::Str(_) => {
-                    early_error(sess.opts.color, "cannot list metadata for stdin");
+                    early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
                 }
             }
             return Compilation::Stop;
@@ -462,7 +460,7 @@ fn print_crate_info(sess: &Session,
                 PrintRequest::CrateName => {
                     let input = match input {
                         Some(input) => input,
-                        None => early_error(sess.opts.color, "no input file provided"),
+                        None => early_error(ErrorOutputType::default(), "no input file provided"),
                     };
                     let attrs = attrs.as_ref().unwrap();
                     let t_outputs = driver::build_output_filenames(input, odir, ofile, attrs, sess);
@@ -755,7 +753,7 @@ fn parse_all_options(args: &Vec<String>) -> getopts::Matches {
                             &opt.opt_group.short_name
                         };
                         if m.opt_present(opt_name) {
-                            early_error(errors::ColorConfig::Auto,
+                            early_error(ErrorOutputType::default(),
                                         &format!("use of unstable option '{}' requires -Z \
                                                   unstable-options",
                                                  opt_name));
@@ -764,7 +762,7 @@ fn parse_all_options(args: &Vec<String>) -> getopts::Matches {
                 }
                 m
             }
-            Err(f) => early_error(errors::ColorConfig::Auto, &f.to_string()),
+            Err(f) => early_error(ErrorOutputType::default(), &f.to_string()),
         }
     }
 
index f2e75960406f188e5e10309212f7c85b3a82053a..825dee9f659f5cad64306b9f2221e00de18e7ff4 100644 (file)
@@ -38,6 +38,7 @@
 #![feature(staged_api)]
 #![feature(str_char)]
 
+#[macro_use]
 extern crate syntax;
 #[macro_use]
 extern crate rustc;
@@ -144,7 +145,8 @@ macro_rules! add_lint_group {
                     UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES);
 
     add_lint_group!(sess, FUTURE_INCOMPATIBLE,
-                    PRIVATE_IN_PUBLIC, INVALID_TYPE_PARAM_DEFAULT);
+                    PRIVATE_IN_PUBLIC, INVALID_TYPE_PARAM_DEFAULT,
+                    MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT);
 
     // We have one lint pass defined specially
     store.register_late_pass(sess, false, box lint::GatherNodeLevels);
@@ -153,4 +155,5 @@ macro_rules! add_lint_group {
     store.register_renamed("unknown_features", "unused_features");
 
     store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
+    store.register_removed("negate_unsigned", "cast a signed value instead");
 }
index a1d029025b2fa8c09680dc4ca93f8e7c7462ff77..891c1aebcdf30704afa57221a73bfaf68c4fb7cb 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![allow(non_snake_case)]
+
 use middle::{infer};
 use middle::def_id::DefId;
 use middle::subst::Substs;
 use syntax::{abi, ast};
 use syntax::attr::{self, AttrMetaMethods};
 use syntax::codemap::{self, Span};
-use syntax::feature_gate::{emit_feature_err, GateIssue};
 use syntax::ast::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64};
 
 use rustc_front::hir;
 use rustc_front::intravisit::{self, Visitor};
 use rustc_front::util::is_shift_binop;
 
+register_long_diagnostics! {
+E0519: r##"
+It is not allowed to negate an unsigned integer.
+You can negate a signed integer and cast it to an
+unsigned integer or use the `!` operator.
+
+```
+let x: usize = -1isize as usize;
+let y: usize = !0;
+assert_eq!(x, y);
+```
+
+Alternatively you can use the `Wrapping` newtype
+or the `wrapping_neg` operation that all
+integral types support:
+
+```
+use std::num::Wrapping;
+let x: Wrapping<usize> = -Wrapping(1);
+let Wrapping(x) = x;
+let y: usize = 1.wrapping_neg();
+assert_eq!(x, y);
+```
+
+"##
+}
+
 declare_lint! {
     UNUSED_COMPARISONS,
     Warn,
@@ -73,30 +101,24 @@ impl LateLintPass for TypeLimits {
     fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
         match e.node {
             hir::ExprUnary(hir::UnNeg, ref expr) => {
-                match expr.node  {
-                    hir::ExprLit(ref lit) => {
-                        match lit.node {
-                            ast::LitInt(_, ast::UnsignedIntLit(_)) => {
-                                check_unsigned_negation_feature(cx, e.span);
-                            },
-                            ast::LitInt(_, ast::UnsuffixedIntLit(_)) => {
-                                if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty {
-                                    check_unsigned_negation_feature(cx, e.span);
-                                }
-                            },
-                            _ => ()
-                        }
-                    },
-                    _ => {
-                        let t = cx.tcx.node_id_to_type(expr.id);
-                        match t.sty {
-                            ty::TyUint(_) => {
-                                check_unsigned_negation_feature(cx, e.span);
-                            },
-                            _ => ()
-                        }
+                if let hir::ExprLit(ref lit) = expr.node {
+                    match lit.node {
+                        ast::LitInt(_, ast::UnsignedIntLit(_)) => {
+                            forbid_unsigned_negation(cx, e.span);
+                        },
+                        ast::LitInt(_, ast::UnsuffixedIntLit(_)) => {
+                            if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty {
+                                forbid_unsigned_negation(cx, e.span);
+                            }
+                        },
+                        _ => ()
                     }
-                };
+                } else {
+                    let t = cx.tcx.node_id_to_type(expr.id);
+                    if let ty::TyUint(_) = t.sty {
+                        forbid_unsigned_negation(cx, e.span);
+                    }
+                }
                 // propagate negation, if the negation itself isn't negated
                 if self.negated_expr_id != e.id {
                     self.negated_expr_id = expr.id;
@@ -322,15 +344,11 @@ fn is_comparison(binop: hir::BinOp) -> bool {
             }
         }
 
-        fn check_unsigned_negation_feature(cx: &LateContext, span: Span) {
-            if !cx.sess().features.borrow().negate_unsigned {
-                emit_feature_err(
-                    &cx.sess().parse_sess.span_diagnostic,
-                    "negate_unsigned",
-                    span,
-                    GateIssue::Language,
-                    "unary negation of unsigned integers may be removed in the future");
-            }
+        fn forbid_unsigned_negation(cx: &LateContext, span: Span) {
+            cx.sess()
+              .struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
+              .span_help(span, "use a cast or the `!` operator")
+              .emit();
         }
     }
 }
index 26f32e207647fd0d4c948e285fb32fedbea49357..22da853dfedb5325902a4b0d629f56a3940fc7d1 100644 (file)
@@ -806,18 +806,18 @@ fn encode_inlined_item(ecx: &EncodeContext,
     let eii: &mut EncodeInlinedItem = &mut *eii;
     eii(ecx, rbml_w, ii);
 
-    encode_mir(ecx, rbml_w, ii);
-}
-
-fn encode_mir(ecx: &EncodeContext, rbml_w: &mut Encoder, ii: InlinedItemRef) {
-    let id = match ii {
+    let node_id = match ii {
         InlinedItemRef::Item(item) => item.id,
         InlinedItemRef::TraitItem(_, trait_item) => trait_item.id,
         InlinedItemRef::ImplItem(_, impl_item) => impl_item.id,
         InlinedItemRef::Foreign(foreign_item) => foreign_item.id
     };
 
-    if let Some(mir) = ecx.mir_map.get(&id) {
+    encode_mir(ecx, rbml_w, node_id);
+}
+
+fn encode_mir(ecx: &EncodeContext, rbml_w: &mut Encoder, node_id: NodeId) {
+    if let Some(mir) = ecx.mir_map.get(&node_id) {
         rbml_w.start_tag(tag_mir as usize);
         rbml_w.emit_opaque(|opaque_encoder| {
             tls::enter_encoding_context(ecx, opaque_encoder, |_, opaque_encoder| {
@@ -1436,6 +1436,9 @@ fn my_visit_expr(expr: &hir::Expr,
 
             ecx.tcx.map.with_path(expr.id, |path| encode_path(rbml_w, path));
 
+            assert!(ecx.mir_map.contains_key(&expr.id));
+            encode_mir(ecx, rbml_w, expr.id);
+
             rbml_w.end_tag();
         }
         _ => { }
index 5f7f87cb86234ecbe7eb73c5dda309b693d716ec..12b9130b48c612c9081914e2af66f6597a819951 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use build::{BlockAnd, Builder};
+use build::{BlockAnd, BlockAndExtension, Builder};
 use hair::*;
 use rustc::mir::repr::*;
 use rustc_front::hir;
@@ -19,11 +19,16 @@ pub fn ast_block(&mut self,
                      mut block: BasicBlock,
                      ast_block: &'tcx hir::Block)
                      -> BlockAnd<()> {
-        let this = self;
-        let Block { extent, span: _, stmts, expr } = this.hir.mirror(ast_block);
-        this.in_scope(extent, block, |this| {
+        let Block { extent, span, stmts, expr } = self.hir.mirror(ast_block);
+        self.in_scope(extent, block, move |this| {
             unpack!(block = this.stmts(block, stmts));
-            this.into(destination, block, expr)
+            match expr {
+                Some(expr) => this.into(destination, block, expr),
+                None => {
+                    this.cfg.push_assign_unit(block, span, destination);
+                    block.unit()
+                }
+            }
         })
     }
 }
index 2e70e6bb5ae0499e1a56eada967ae9258114459f..523ac85cdc5090414e3d93f812ec1669380d6fd3 100644 (file)
@@ -37,14 +37,6 @@ pub fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
         self.block_data_mut(block).statements.push(statement);
     }
 
-    pub fn push_assign_constant(&mut self,
-                                block: BasicBlock,
-                                span: Span,
-                                temp: &Lvalue<'tcx>,
-                                constant: Constant<'tcx>) {
-        self.push_assign(block, span, temp, Rvalue::Use(Operand::Constant(constant)));
-    }
-
     pub fn push_drop(&mut self, block: BasicBlock, span: Span,
                      kind: DropKind, lvalue: &Lvalue<'tcx>) {
         self.push(block, Statement {
@@ -64,6 +56,23 @@ pub fn push_assign(&mut self,
         });
     }
 
+    pub fn push_assign_constant(&mut self,
+                                block: BasicBlock,
+                                span: Span,
+                                temp: &Lvalue<'tcx>,
+                                constant: Constant<'tcx>) {
+        self.push_assign(block, span, temp, Rvalue::Use(Operand::Constant(constant)));
+    }
+
+    pub fn push_assign_unit(&mut self,
+                            block: BasicBlock,
+                            span: Span,
+                            lvalue: &Lvalue<'tcx>) {
+        self.push_assign(block, span, lvalue, Rvalue::Aggregate(
+            AggregateKind::Tuple, vec![]
+        ));
+    }
+
     pub fn terminate(&mut self,
                      block: BasicBlock,
                      terminator: Terminator<'tcx>) {
index 44d1d52a06a3466a6dec9a0596f92899af8a9c05..63eb760720479a750d90779fa96a21c135332975 100644 (file)
@@ -58,7 +58,14 @@ pub fn into_expr(&mut self,
                 });
 
                 unpack!(then_block = this.into(destination, then_block, then_expr));
-                unpack!(else_block = this.into(destination, else_block, else_expr));
+                else_block = if let Some(else_expr) = else_expr {
+                    unpack!(this.into(destination, else_block, else_expr))
+                } else {
+                    // Body of the `if` expression without an `else` clause must return `()`, thus
+                    // we implicitly generate a `else {}` if it is not specified.
+                    this.cfg.push_assign_unit(else_block, expr_span, &Lvalue::ReturnPointer);
+                    else_block
+                };
 
                 let join_block = this.cfg.start_new_block();
                 this.cfg.terminate(then_block, Terminator::Goto { target: join_block });
@@ -157,11 +164,18 @@ pub fn into_expr(&mut self,
                     }
 
                     // execute the body, branching back to the test
-                    let unit_temp = this.unit_temp.clone();
-                    let body_block_end = unpack!(this.into(&unit_temp, body_block, body));
+                    // We write body’s “return value” into the destination of loop. This is fine,
+                    // because:
+                    //
+                    // * In Rust both loop expression and its body are required to have `()`
+                    //   as the “return value”;
+                    // * The destination will be considered uninitialised (given it was
+                    //   uninitialised before the loop) during the first iteration, thus
+                    //   disallowing its use inside the body. Alternatively, if it was already
+                    //   initialised, the `destination` can only possibly have a value of `()`,
+                    //   therefore, “mutating” the destination during iteration is fine.
+                    let body_block_end = unpack!(this.into(destination, body_block, body));
                     this.cfg.terminate(body_block_end, Terminator::Goto { target: loop_block });
-
-                    // final point is exit_block
                     exit_block.unit()
                 })
             }
@@ -206,7 +220,13 @@ pub fn into_expr(&mut self,
                 this.break_or_continue(expr_span, label, block, |loop_scope| loop_scope.break_block)
             }
             ExprKind::Return { value } => {
-                unpack!(block = this.into(&Lvalue::ReturnPointer, block, value));
+                block = match value {
+                    Some(value) => unpack!(this.into(&Lvalue::ReturnPointer, block, value)),
+                    None => {
+                        this.cfg.push_assign_unit(block, expr_span, &Lvalue::ReturnPointer);
+                        block
+                    }
+                };
                 let extent = this.extent_of_outermost_scope();
                 this.exit_scope(expr_span, extent, block, END_BLOCK);
                 this.cfg.start_new_block().unit()
index 66d6c49ef12aaf3b49b0eb5d49ae9a1152fb029b..77d9d926328fc5535bf26967ad79797c2d7a07b9 100644 (file)
@@ -14,7 +14,7 @@
 //! wrapped up as expressions (e.g. blocks). To make this ergonomic, we use this
 //! latter `EvalInto` trait.
 
-use build::{BlockAnd, BlockAndExtension, Builder};
+use build::{BlockAnd, Builder};
 use hair::*;
 use rustc::mir::repr::*;
 
@@ -58,16 +58,3 @@ fn eval_into<'a>(self,
         builder.into_expr(destination, block, self)
     }
 }
-
-impl<'tcx> EvalInto<'tcx> for Option<ExprRef<'tcx>> {
-    fn eval_into<'a>(self,
-                     builder: &mut Builder<'a, 'tcx>,
-                     destination: &Lvalue<'tcx>,
-                     block: BasicBlock)
-                     -> BlockAnd<()> {
-        match self {
-            Some(expr) => builder.into(destination, block, expr),
-            None => block.unit(),
-        }
-    }
-}
index e6e5b8380b24121a05d062ad3625ab4df0c2d02e..d217eb066479364de370bdc536bb7d96c3d091f0 100644 (file)
@@ -23,7 +23,6 @@ pub struct Builder<'a, 'tcx: 'a> {
     cfg: CFG<'tcx>,
     scopes: Vec<scope::Scope<'tcx>>,
     loop_scopes: Vec<scope::LoopScope>,
-    unit_temp: Lvalue<'tcx>,
     var_decls: Vec<VarDecl<'tcx>>,
     var_indices: FnvHashMap<ast::NodeId, u32>,
     temp_decls: Vec<TempDecl<'tcx>>,
@@ -79,7 +78,7 @@ macro_rules! unpack {
 ///////////////////////////////////////////////////////////////////////////
 // construct() -- the main entry point for building MIR for a function
 
-pub fn construct<'a,'tcx>(mut hir: Cx<'a,'tcx>,
+pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
                           _span: Span,
                           implicit_arguments: Vec<Ty<'tcx>>,
                           explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
@@ -89,20 +88,14 @@ pub fn construct<'a,'tcx>(mut hir: Cx<'a,'tcx>,
                           -> Mir<'tcx> {
     let cfg = CFG { basic_blocks: vec![] };
 
-    // it's handy to have a temporary of type `()` sometimes, so make
-    // one from the start and keep it available
-    let temp_decls = vec![TempDecl::<'tcx> { ty: hir.unit_ty() }];
-    let unit_temp = Lvalue::Temp(0);
-
     let mut builder = Builder {
         hir: hir,
         cfg: cfg,
         scopes: vec![],
         loop_scopes: vec![],
-        temp_decls: temp_decls,
+        temp_decls: vec![],
         var_decls: vec![],
         var_indices: FnvHashMap(),
-        unit_temp: unit_temp,
     };
 
     assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
index e912e933bd81f2869ee29cae3350e527c87b4322..90d6a90682f6eb1680cd467d1730a56fa6e0ed47 100644 (file)
@@ -34,7 +34,7 @@
 matches, it sometimes happen that certain code (namely guards) gets
 executed multiple times. This means that the scope lexical scope may
 in fact correspond to multiple, disjoint SEME regions. So in fact our
-mapping os from one scope to a vector of SEME regions.
+mapping is from one scope to a vector of SEME regions.
 
 ### Drops
 
index f9dd40defdf70aa44eb1b95a419cb34fd0c8e337..b49dc6d89624265d68b6f82c396acbc75065efbc 100644 (file)
@@ -46,10 +46,6 @@ pub fn mirror<M: Mirror<'tcx>>(&mut self, ast: M) -> M::Output {
         ast.make_mirror(self)
     }
 
-    pub fn unit_ty(&mut self) -> Ty<'tcx> {
-        self.tcx.mk_nil()
-    }
-
     pub fn usize_ty(&mut self) -> Ty<'tcx> {
         self.tcx.types.usize
     }
index 163559f279281ac2caa67b07b366552ecc1b5c85..ea4036a4d375f6ec68435bf707ca8322fd5d68f7 100644 (file)
@@ -39,7 +39,7 @@ fn write_basic_block<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::R
     }
 
     // Terminator at the bottom.
-    try!(writeln!(w, "{0}{0}{1:?};", INDENT, data.terminator));
+    try!(writeln!(w, "{0}{0}{1:?};", INDENT, data.terminator()));
 
     writeln!(w, "{}}}", INDENT)
 }
index 20a14cf415404feab75ba62affa757bd34727e40..9679654d958e9a24e202443a272f5a52e762a9f8 100644 (file)
@@ -94,7 +94,7 @@ fn erase_regions_terminator(&mut self,
                 *switch_ty = self.tcx.erase_regions(switch_ty);
             },
             Terminator::Call { ref mut func, ref mut args, ref mut kind } => {
-                if let Some(ref mut destination) = kind.destination() {
+                if let Some(destination) = kind.destination_mut() {
                     self.erase_regions_lvalue(destination);
                 }
                 self.erase_regions_operand(func);
index 1d3f2b79844ea0094120458537cc139239d58055..2e713a2f50e0fcdb0d5dfe08db3c54f2107f20ab 100644 (file)
@@ -21,7 +21,7 @@
 use Namespace::{TypeNS, ValueNS};
 use NameBindings;
 use {names_to_string, module_to_string};
-use ParentLink::{self, ModuleParentLink, BlockParentLink};
+use ParentLink::{ModuleParentLink, BlockParentLink};
 use Resolver;
 use resolve_imports::Shadowable;
 use {resolve_error, resolve_struct_error, ResolutionError};
@@ -52,7 +52,6 @@
 
 use std::mem::replace;
 use std::ops::{Deref, DerefMut};
-use std::rc::Rc;
 
 // Specifies how duplicates should be handled when adding a child item if
 // another item exists with the same name in some namespace.
@@ -86,7 +85,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
     /// Constructs the reduced graph for the entire crate.
     fn build_reduced_graph(self, krate: &hir::Crate) {
         let mut visitor = BuildReducedGraphVisitor {
-            parent: self.graph_root.clone(),
+            parent: self.graph_root,
             builder: self,
         };
         intravisit::walk_crate(&mut visitor, krate);
@@ -97,12 +96,12 @@ fn build_reduced_graph(self, krate: &hir::Crate) {
     /// Returns the child's corresponding name bindings.
     fn add_child(&self,
                  name: Name,
-                 parent: &Rc<Module>,
+                 parent: Module<'b>,
                  duplicate_checking_mode: DuplicateCheckingMode,
                  // For printing errors
                  sp: Span)
-                 -> NameBindings {
-        self.check_for_conflicts_between_external_crates_and_items(&**parent, name, sp);
+                 -> NameBindings<'b> {
+        self.check_for_conflicts_between_external_crates_and_items(parent, name, sp);
 
         // Add or reuse the child.
         let child = parent.children.borrow().get(&name).cloned();
@@ -178,12 +177,8 @@ fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
         return false;
     }
 
-    fn get_parent_link(&mut self, parent: &Rc<Module>, name: Name) -> ParentLink {
-        ModuleParentLink(Rc::downgrade(parent), name)
-    }
-
     /// Constructs the reduced graph for one item.
-    fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) -> Rc<Module> {
+    fn build_reduced_graph_for_item(&mut self, item: &Item, parent: Module<'b>) -> Module<'b> {
         let name = item.name;
         let sp = item.span;
         let is_public = item.vis == hir::Public;
@@ -238,7 +233,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
                         }
 
                         let subclass = SingleImport(binding, source_name);
-                        self.build_import_directive(&**parent,
+                        self.build_import_directive(parent,
                                                     module_path,
                                                     subclass,
                                                     view_path.span,
@@ -288,7 +283,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
                                     (module_path.to_vec(), name, rename)
                                 }
                             };
-                            self.build_import_directive(&**parent,
+                            self.build_import_directive(parent,
                                                         module_path,
                                                         SingleImport(rename, name),
                                                         source_item.span,
@@ -298,7 +293,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
                         }
                     }
                     ViewPathGlob(_) => {
-                        self.build_import_directive(&**parent,
+                        self.build_import_directive(parent,
                                                     module_path,
                                                     GlobImport,
                                                     view_path.span,
@@ -307,7 +302,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
                                                     shadowable);
                     }
                 }
-                parent.clone()
+                parent
             }
 
             ItemExternCrate(_) => {
@@ -319,32 +314,32 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
                         index: CRATE_DEF_INDEX,
                     };
                     self.external_exports.insert(def_id);
-                    let parent_link = ModuleParentLink(Rc::downgrade(parent), name);
+                    let parent_link = ModuleParentLink(parent, name);
                     let def = DefMod(def_id);
-                    let external_module = Module::new(parent_link, Some(def), false, true);
+                    let external_module = self.new_module(parent_link, Some(def), false, true);
 
                     debug!("(build reduced graph for item) found extern `{}`",
                            module_to_string(&*external_module));
-                    self.check_for_conflicts_between_external_crates(&**parent, name, sp);
+                    self.check_for_conflicts_for_external_crate(parent, name, sp);
                     parent.external_module_children
                           .borrow_mut()
-                          .insert(name, external_module.clone());
+                          .insert(name, external_module);
                     self.build_reduced_graph_for_external_crate(&external_module);
                 }
-                parent.clone()
+                parent
             }
 
             ItemMod(..) => {
                 let name_bindings = self.add_child(name, parent, ForbidDuplicateTypes, sp);
 
-                let parent_link = self.get_parent_link(parent, name);
+                let parent_link = ModuleParentLink(parent, name);
                 let def = DefMod(self.ast_map.local_def_id(item.id));
-                let module = Module::new(parent_link, Some(def), false, is_public);
+                let module = self.new_module(parent_link, Some(def), false, is_public);
                 name_bindings.define_module(module.clone(), sp);
                 module
             }
 
-            ItemForeignMod(..) => parent.clone(),
+            ItemForeignMod(..) => parent,
 
             // These items live in the value namespace.
             ItemStatic(_, m, _) => {
@@ -354,19 +349,19 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
                 name_bindings.define_value(DefStatic(self.ast_map.local_def_id(item.id), mutbl),
                                            sp,
                                            modifiers);
-                parent.clone()
+                parent
             }
             ItemConst(_, _) => {
                 self.add_child(name, parent, ForbidDuplicateValues, sp)
                     .define_value(DefConst(self.ast_map.local_def_id(item.id)), sp, modifiers);
-                parent.clone()
+                parent
             }
             ItemFn(_, _, _, _, _, _) => {
                 let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp);
 
                 let def = DefFn(self.ast_map.local_def_id(item.id), false);
                 name_bindings.define_value(def, sp, modifiers);
-                parent.clone()
+                parent
             }
 
             // These items live in the type namespace.
@@ -376,11 +371,11 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
                                                    ForbidDuplicateTypes,
                                                    sp);
 
-                let parent_link = self.get_parent_link(parent, name);
+                let parent_link = ModuleParentLink(parent, name);
                 let def = DefTy(self.ast_map.local_def_id(item.id), false);
-                let module = Module::new(parent_link, Some(def), false, is_public);
+                let module = self.new_module(parent_link, Some(def), false, is_public);
                 name_bindings.define_module(module, sp);
-                parent.clone()
+                parent
             }
 
             ItemEnum(ref enum_definition, _) => {
@@ -389,9 +384,9 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
                                                    ForbidDuplicateTypes,
                                                    sp);
 
-                let parent_link = self.get_parent_link(parent, name);
+                let parent_link = ModuleParentLink(parent, name);
                 let def = DefTy(self.ast_map.local_def_id(item.id), true);
-                let module = Module::new(parent_link, Some(def), false, is_public);
+                let module = self.new_module(parent_link, Some(def), false, is_public);
                 name_bindings.define_module(module.clone(), sp);
 
                 let variant_modifiers = if is_public {
@@ -404,7 +399,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
                     self.build_reduced_graph_for_variant(variant, item_def_id,
                                                          &module, variant_modifiers);
                 }
-                parent.clone()
+                parent
             }
 
             // These items live in both the type and value namespaces.
@@ -444,11 +439,11 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
                 let item_def_id = self.ast_map.local_def_id(item.id);
                 self.structs.insert(item_def_id, named_fields);
 
-                parent.clone()
+                parent
             }
 
             ItemDefaultImpl(_, _) |
-            ItemImpl(..) => parent.clone(),
+            ItemImpl(..) => parent,
 
             ItemTrait(_, _, _, ref items) => {
                 let name_bindings = self.add_child(name,
@@ -459,9 +454,9 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
                 let def_id = self.ast_map.local_def_id(item.id);
 
                 // Add all the items within to a new module.
-                let parent_link = self.get_parent_link(parent, name);
+                let parent_link = ModuleParentLink(parent, name);
                 let def = DefTrait(def_id);
-                let module_parent = Module::new(parent_link, Some(def), false, is_public);
+                let module_parent = self.new_module(parent_link, Some(def), false, is_public);
                 name_bindings.define_module(module_parent.clone(), sp);
 
                 // Add the names of all the items to the trait info.
@@ -494,7 +489,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
                     self.trait_item_map.insert((trait_item.name, def_id), trait_item_def_id);
                 }
 
-                parent.clone()
+                parent
             }
         }
     }
@@ -504,7 +499,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
     fn build_reduced_graph_for_variant(&mut self,
                                        variant: &Variant,
                                        item_id: DefId,
-                                       parent: &Rc<Module>,
+                                       parent: Module<'b>,
                                        variant_modifiers: DefModifiers) {
         let name = variant.node.name;
         let is_exported = if variant.node.data.is_struct() {
@@ -534,7 +529,7 @@ fn build_reduced_graph_for_variant(&mut self,
     /// Constructs the reduced graph for one foreign item.
     fn build_reduced_graph_for_foreign_item(&mut self,
                                             foreign_item: &ForeignItem,
-                                            parent: &Rc<Module>) {
+                                            parent: Module<'b>) {
         let name = foreign_item.name;
         let is_public = foreign_item.vis == hir::Public;
         let modifiers = if is_public {
@@ -555,7 +550,7 @@ fn build_reduced_graph_for_foreign_item(&mut self,
         name_bindings.define_value(def, foreign_item.span, modifiers);
     }
 
-    fn build_reduced_graph_for_block(&mut self, block: &Block, parent: &Rc<Module>) -> Rc<Module> {
+    fn build_reduced_graph_for_block(&mut self, block: &Block, parent: Module<'b>) -> Module<'b> {
         if self.block_needs_anonymous_module(block) {
             let block_id = block.id;
 
@@ -563,22 +558,22 @@ fn build_reduced_graph_for_block(&mut self, block: &Block, parent: &Rc<Module>)
                     {}",
                    block_id);
 
-            let parent_link = BlockParentLink(Rc::downgrade(parent), block_id);
-            let new_module = Module::new(parent_link, None, false, false);
-            parent.anonymous_children.borrow_mut().insert(block_id, new_module.clone());
+            let parent_link = BlockParentLink(parent, block_id);
+            let new_module = self.new_module(parent_link, None, false, false);
+            parent.anonymous_children.borrow_mut().insert(block_id, new_module);
             new_module
         } else {
-            parent.clone()
+            parent
         }
     }
 
     fn handle_external_def(&mut self,
                            def: Def,
                            vis: Visibility,
-                           child_name_bindings: &NameBindings,
+                           child_name_bindings: &NameBindings<'b>,
                            final_ident: &str,
                            name: Name,
-                           new_parent: &Rc<Module>) {
+                           new_parent: Module<'b>) {
         debug!("(building reduced graph for external crate) building external def {}, priv {:?}",
                final_ident,
                vis);
@@ -609,8 +604,8 @@ fn handle_external_def(&mut self,
                     debug!("(building reduced graph for external crate) building module {} {}",
                            final_ident,
                            is_public);
-                    let parent_link = self.get_parent_link(new_parent, name);
-                    let module = Module::new(parent_link, Some(def), true, is_public);
+                    let parent_link = ModuleParentLink(new_parent, name);
+                    let module = self.new_module(parent_link, Some(def), true, is_public);
                     child_name_bindings.define_module(module, DUMMY_SP);
                 }
             }
@@ -681,8 +676,8 @@ fn handle_external_def(&mut self,
                 }
 
                 // Define a module if necessary.
-                let parent_link = self.get_parent_link(new_parent, name);
-                let module = Module::new(parent_link, Some(def), true, is_public);
+                let parent_link = ModuleParentLink(new_parent, name);
+                let module = self.new_module(parent_link, Some(def), true, is_public);
                 child_name_bindings.define_module(module, DUMMY_SP);
             }
             DefTy(..) | DefAssociatedTy(..) => {
@@ -728,7 +723,7 @@ fn handle_external_def(&mut self,
 
     /// Builds the reduced graph for a single item in an external crate.
     fn build_reduced_graph_for_external_crate_def(&mut self,
-                                                  root: &Rc<Module>,
+                                                  root: Module<'b>,
                                                   xcdef: ChildItem) {
         match xcdef.def {
             DlDef(def) => {
@@ -766,9 +761,9 @@ fn build_reduced_graph_for_external_crate_def(&mut self,
     }
 
     /// Builds the reduced graph rooted at the given external module.
-    fn populate_external_module(&mut self, module: &Rc<Module>) {
+    fn populate_external_module(&mut self, module: Module<'b>) {
         debug!("(populating external module) attempting to populate {}",
-               module_to_string(&**module));
+               module_to_string(module));
 
         let def_id = match module.def_id() {
             None => {
@@ -788,7 +783,7 @@ fn populate_external_module(&mut self, module: &Rc<Module>) {
 
     /// Ensures that the reduced graph rooted at the given external module
     /// is built, building it if it is not.
-    fn populate_module_if_necessary(&mut self, module: &Rc<Module>) {
+    fn populate_module_if_necessary(&mut self, module: Module<'b>) {
         if !module.populated.get() {
             self.populate_external_module(module)
         }
@@ -797,7 +792,7 @@ fn populate_module_if_necessary(&mut self, module: &Rc<Module>) {
 
     /// Builds the reduced graph rooted at the 'use' directive for an external
     /// crate.
-    fn build_reduced_graph_for_external_crate(&mut self, root: &Rc<Module>) {
+    fn build_reduced_graph_for_external_crate(&mut self, root: Module<'b>) {
         let root_cnum = root.def_id().unwrap().krate;
         for child in self.session.cstore.crate_top_level_items(root_cnum) {
             self.build_reduced_graph_for_external_crate_def(root, child);
@@ -806,7 +801,7 @@ fn build_reduced_graph_for_external_crate(&mut self, root: &Rc<Module>) {
 
     /// Creates and adds an import directive to the given module.
     fn build_import_directive(&mut self,
-                              module_: &Module,
+                              module_: Module<'b>,
                               module_path: Vec<Name>,
                               subclass: ImportDirectiveSubclass,
                               span: Span,
@@ -866,7 +861,7 @@ fn build_import_directive(&mut self,
 
 struct BuildReducedGraphVisitor<'a, 'b: 'a, 'tcx: 'b> {
     builder: GraphBuilder<'a, 'b, 'tcx>,
-    parent: Rc<Module>,
+    parent: Module<'b>,
 }
 
 impl<'a, 'b, 'v, 'tcx> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
@@ -897,6 +892,7 @@ pub fn build_reduced_graph(resolver: &mut Resolver, krate: &hir::Crate) {
     GraphBuilder { resolver: resolver }.build_reduced_graph(krate);
 }
 
-pub fn populate_module_if_necessary(resolver: &mut Resolver, module: &Rc<Module>) {
+pub fn populate_module_if_necessary<'a, 'tcx>(resolver: &mut Resolver<'a, 'tcx>,
+                                              module: Module<'a>) {
     GraphBuilder { resolver: resolver }.populate_module_if_necessary(module);
 }
index 5a17f2528c85b1aec723b921324e8c195a8ba41d..9857e83bd621a7ddc47dcee3c60c5950f6fe0458 100644 (file)
@@ -26,6 +26,7 @@
 extern crate log;
 #[macro_use]
 extern crate syntax;
+extern crate arena;
 #[macro_use]
 #[no_link]
 extern crate rustc_bitflags;
@@ -72,7 +73,7 @@
 use rustc_front::hir;
 use rustc_front::hir::{Arm, BindByRef, BindByValue, BindingMode, Block};
 use rustc_front::hir::Crate;
-use rustc_front::hir::{Expr, ExprAgain, ExprBreak, ExprField};
+use rustc_front::hir::{Expr, ExprAgain, ExprBreak, ExprCall, ExprField};
 use rustc_front::hir::{ExprLoop, ExprWhile, ExprMethodCall};
 use rustc_front::hir::{ExprPath, ExprStruct, FnDecl};
 use rustc_front::hir::{ForeignItemFn, ForeignItemStatic, Generics};
@@ -90,7 +91,7 @@
 use std::cell::{Cell, RefCell};
 use std::fmt;
 use std::mem::replace;
-use std::rc::{Rc, Weak};
+use std::rc::Rc;
 
 use resolve_imports::{Target, ImportDirective, ImportResolutionPerNamespace};
 use resolve_imports::Shadowable;
@@ -122,6 +123,8 @@ enum SuggestionType {
 }
 
 pub enum ResolutionError<'a> {
+    /// error E0260: name conflicts with an extern crate
+    NameConflictsWithExternCrate(Name),
     /// error E0401: can't use type parameters from outer function
     TypeParametersFromOuterFunction,
     /// error E0402: cannot use an outer type parameter in this context
@@ -228,6 +231,14 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
     }
 
     match resolution_error {
+        ResolutionError::NameConflictsWithExternCrate(name) => {
+            struct_span_err!(resolver.session,
+                             span,
+                             E0260,
+                             "the name `{}` conflicts with an external crate \
+                             that has been imported into this module",
+                             name)
+        }
         ResolutionError::TypeParametersFromOuterFunction => {
             struct_span_err!(resolver.session,
                              span,
@@ -433,7 +444,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
                                            msg);
 
             match context {
-                UnresolvedNameContext::Other => {} // no help available
+                UnresolvedNameContext::Other => { } // no help available
                 UnresolvedNameContext::PathIsMod(id) => {
                     let mut help_msg = String::new();
                     let parent_id = resolver.ast_map.get_parent_node(id);
@@ -446,7 +457,6 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
                                                    module = &*path,
                                                    ident = ident.node);
                             }
-
                             ExprMethodCall(ident, _, _) => {
                                 help_msg = format!("To call a function from the \
                                                     `{module}` module, use \
@@ -454,9 +464,15 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
                                                    module = &*path,
                                                    ident = ident.node);
                             }
-
-                            _ => {} // no help available
+                            ExprCall(_, _) => {
+                                help_msg = format!("No function corresponds to `{module}(..)`",
+                                                   module = &*path);
+                            }
+                            _ => { } // no help available
                         }
+                    } else {
+                        help_msg = format!("Module `{module}` cannot be the value of an expression",
+                                           module = &*path);
                     }
 
                     if !help_msg.is_empty() {
@@ -561,7 +577,7 @@ pub enum Namespace {
 /// a particular namespace. The result is either definitely-resolved,
 /// definitely- unresolved, or unknown.
 #[derive(Clone)]
-enum NamespaceResult {
+enum NamespaceResult<'a> {
     /// Means that resolve hasn't gathered enough information yet to determine
     /// whether the name is bound in this namespace. (That is, it hasn't
     /// resolved all `use` directives yet.)
@@ -571,10 +587,10 @@ enum NamespaceResult {
     UnboundResult,
     /// Means that resolve has determined that the name is bound in the Module
     /// argument, and specified by the NameBinding argument.
-    BoundResult(Rc<Module>, NameBinding),
+    BoundResult(Module<'a>, NameBinding<'a>),
 }
 
-impl NamespaceResult {
+impl<'a> NamespaceResult<'a> {
     fn is_unknown(&self) -> bool {
         match *self {
             UnknownResult => true,
@@ -751,9 +767,9 @@ enum UseLexicalScopeFlag {
     UseLexicalScope,
 }
 
-enum ModulePrefixResult {
+enum ModulePrefixResult<'a> {
     NoPrefixFound,
-    PrefixFound(Rc<Module>, usize),
+    PrefixFound(Module<'a>, usize),
 }
 
 #[derive(Copy, Clone)]
@@ -815,24 +831,24 @@ fn from_def(def: Def) -> Self {
 
 /// The link from a module up to its nearest parent node.
 #[derive(Clone,Debug)]
-enum ParentLink {
+enum ParentLink<'a> {
     NoParentLink,
-    ModuleParentLink(Weak<Module>, Name),
-    BlockParentLink(Weak<Module>, NodeId),
+    ModuleParentLink(Module<'a>, Name),
+    BlockParentLink(Module<'a>, NodeId),
 }
 
 /// One node in the tree of modules.
-pub struct Module {
-    parent_link: ParentLink,
+pub struct ModuleS<'a> {
+    parent_link: ParentLink<'a>,
     def: Cell<Option<Def>>,
     is_public: bool,
 
-    children: RefCell<HashMap<Name, NameBindings>>,
+    children: RefCell<HashMap<Name, NameBindings<'a>>>,
     imports: RefCell<Vec<ImportDirective>>,
 
     // The external module children of this node that were declared with
     // `extern crate`.
-    external_module_children: RefCell<HashMap<Name, Rc<Module>>>,
+    external_module_children: RefCell<HashMap<Name, Module<'a>>>,
 
     // The anonymous children of this node. Anonymous children are pseudo-
     // modules that are implicitly created around items contained within
@@ -848,10 +864,10 @@ pub struct Module {
     //
     // There will be an anonymous module created around `g` with the ID of the
     // entry block for `f`.
-    anonymous_children: RefCell<NodeMap<Rc<Module>>>,
+    anonymous_children: RefCell<NodeMap<Module<'a>>>,
 
     // The status of resolving each import in this module.
-    import_resolutions: RefCell<HashMap<Name, ImportResolutionPerNamespace>>,
+    import_resolutions: RefCell<HashMap<Name, ImportResolutionPerNamespace<'a>>>,
 
     // The number of unresolved globs that this module exports.
     glob_count: Cell<usize>,
@@ -871,13 +887,11 @@ pub struct Module {
     populated: Cell<bool>,
 }
 
-impl Module {
-    fn new(parent_link: ParentLink,
-           def: Option<Def>,
-           external: bool,
-           is_public: bool)
-           -> Rc<Module> {
-        Rc::new(Module {
+pub type Module<'a> = &'a ModuleS<'a>;
+
+impl<'a> ModuleS<'a> {
+    fn new(parent_link: ParentLink<'a>, def: Option<Def>, external: bool, is_public: bool) -> Self {
+        ModuleS {
             parent_link: parent_link,
             def: Cell::new(def),
             is_public: is_public,
@@ -891,7 +905,7 @@ fn new(parent_link: ParentLink,
             pub_glob_count: Cell::new(0),
             resolved_import_count: Cell::new(0),
             populated: Cell::new(!external),
-        })
+        }
     }
 
     fn def_id(&self) -> Option<DefId> {
@@ -920,9 +934,7 @@ fn all_imports_resolved(&self) -> bool {
             self.imports.borrow().len() == self.resolved_import_count.get()
         }
     }
-}
 
-impl Module {
     pub fn inc_glob_count(&self) {
         self.glob_count.set(self.glob_count.get() + 1);
     }
@@ -946,7 +958,7 @@ pub fn dec_pub_glob_count(&self) {
     }
 }
 
-impl fmt::Debug for Module {
+impl<'a> fmt::Debug for ModuleS<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f,
                "{:?}, {}",
@@ -974,20 +986,20 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 // Records a possibly-private value, type, or module definition.
 #[derive(Debug)]
-struct NsDef {
+struct NsDef<'a> {
     modifiers: DefModifiers, // see note in ImportResolutionPerNamespace about how to use this
-    def_or_module: DefOrModule,
+    def_or_module: DefOrModule<'a>,
     span: Option<Span>,
 }
 
 #[derive(Debug)]
-enum DefOrModule {
+enum DefOrModule<'a> {
     Def(Def),
-    Module(Rc<Module>),
+    Module(Module<'a>),
 }
 
-impl NsDef {
-    fn create_from_module(module: Rc<Module>, span: Option<Span>) -> Self {
+impl<'a> NsDef<'a> {
+    fn create_from_module(module: Module<'a>, span: Option<Span>) -> Self {
         let modifiers = if module.is_public {
             DefModifiers::PUBLIC
         } else {
@@ -1001,9 +1013,9 @@ fn create_from_def(def: Def, modifiers: DefModifiers, span: Option<Span>) -> Sel
         NsDef { modifiers: modifiers, def_or_module: DefOrModule::Def(def), span: span }
     }
 
-    fn module(&self) -> Option<Rc<Module>> {
+    fn module(&self) -> Option<Module<'a>> {
         match self.def_or_module {
-            DefOrModule::Module(ref module) => Some(module.clone()),
+            DefOrModule::Module(ref module) => Some(module),
             DefOrModule::Def(_) => None,
         }
     }
@@ -1018,18 +1030,18 @@ fn def(&self) -> Option<Def> {
 
 // Records at most one definition that a name in a namespace is bound to
 #[derive(Clone,Debug)]
-pub struct NameBinding(Rc<RefCell<Option<NsDef>>>);
+pub struct NameBinding<'a>(Rc<RefCell<Option<NsDef<'a>>>>);
 
-impl NameBinding {
+impl<'a> NameBinding<'a> {
     fn new() -> Self {
         NameBinding(Rc::new(RefCell::new(None)))
     }
 
-    fn create_from_module(module: Rc<Module>) -> Self {
+    fn create_from_module(module: Module<'a>) -> Self {
         NameBinding(Rc::new(RefCell::new(Some(NsDef::create_from_module(module, None)))))
     }
 
-    fn set(&self, ns_def: NsDef) {
+    fn set(&self, ns_def: NsDef<'a>) {
         *self.0.borrow_mut() = Some(ns_def);
     }
 
@@ -1039,7 +1051,7 @@ fn set_modifiers(&self, modifiers: DefModifiers) {
         }
     }
 
-    fn borrow(&self) -> ::std::cell::Ref<Option<NsDef>> {
+    fn borrow(&self) -> ::std::cell::Ref<Option<NsDef<'a>>> {
         self.0.borrow()
     }
 
@@ -1047,7 +1059,7 @@ fn borrow(&self) -> ::std::cell::Ref<Option<NsDef>> {
     fn def(&self) -> Option<Def> {
         self.borrow().as_ref().and_then(NsDef::def)
     }
-    fn module(&self) -> Option<Rc<Module>> {
+    fn module(&self) -> Option<Module<'a>> {
         self.borrow().as_ref().and_then(NsDef::module)
     }
     fn span(&self) -> Option<Span> {
@@ -1078,20 +1090,20 @@ fn def_and_lp(&self) -> (Def, LastPrivate) {
 // Records the definitions (at most one for each namespace) that a name is
 // bound to.
 #[derive(Clone,Debug)]
-pub struct NameBindings {
-    type_ns: NameBinding, // < Meaning in type namespace.
-    value_ns: NameBinding, // < Meaning in value namespace.
+pub struct NameBindings<'a> {
+    type_ns: NameBinding<'a>, // < Meaning in type namespace.
+    value_ns: NameBinding<'a>, // < Meaning in value namespace.
 }
 
-impl ::std::ops::Index<Namespace> for NameBindings {
-    type Output = NameBinding;
-    fn index(&self, namespace: Namespace) -> &NameBinding {
+impl<'a> ::std::ops::Index<Namespace> for NameBindings<'a> {
+    type Output = NameBinding<'a>;
+    fn index(&self, namespace: Namespace) -> &NameBinding<'a> {
         match namespace { TypeNS => &self.type_ns, ValueNS => &self.value_ns }
     }
 }
 
-impl NameBindings {
-    fn new() -> NameBindings {
+impl<'a> NameBindings<'a> {
+    fn new() -> Self {
         NameBindings {
             type_ns: NameBinding::new(),
             value_ns: NameBinding::new(),
@@ -1099,7 +1111,7 @@ fn new() -> NameBindings {
     }
 
     /// Creates a new module in this set of name bindings.
-    fn define_module(&self, module: Rc<Module>, sp: Span) {
+    fn define_module(&self, module: Module<'a>, sp: Span) {
         self.type_ns.set(NsDef::create_from_module(module, Some(sp)));
     }
 
@@ -1155,7 +1167,7 @@ pub struct Resolver<'a, 'tcx: 'a> {
 
     ast_map: &'a hir_map::Map<'tcx>,
 
-    graph_root: Rc<Module>,
+    graph_root: Module<'a>,
 
     trait_item_map: FnvHashMap<(Name, DefId), DefId>,
 
@@ -1165,7 +1177,7 @@ pub struct Resolver<'a, 'tcx: 'a> {
     unresolved_imports: usize,
 
     // The module that represents the current item scope.
-    current_module: Rc<Module>,
+    current_module: Module<'a>,
 
     // The current set of local scopes, for values.
     // FIXME #4948: Reuse ribs to avoid allocation.
@@ -1211,6 +1223,12 @@ pub struct Resolver<'a, 'tcx: 'a> {
     // The intention is that the callback modifies this flag.
     // Once set, the resolver falls out of the walk, preserving the ribs.
     resolved: bool,
+
+    arenas: &'a ResolverArenas<'a>,
+}
+
+pub struct ResolverArenas<'a> {
+    modules: arena::TypedArena<ModuleS<'a>>,
 }
 
 #[derive(PartialEq)]
@@ -1222,10 +1240,12 @@ enum FallbackChecks {
 impl<'a, 'tcx> Resolver<'a, 'tcx> {
     fn new(session: &'a Session,
            ast_map: &'a hir_map::Map<'tcx>,
-           make_glob_map: MakeGlobMap)
+           make_glob_map: MakeGlobMap,
+           arenas: &'a ResolverArenas<'a>)
            -> Resolver<'a, 'tcx> {
         let root_def_id = ast_map.local_def_id(CRATE_NODE_ID);
-        let graph_root = Module::new(NoParentLink, Some(DefMod(root_def_id)), false, true);
+        let graph_root = ModuleS::new(NoParentLink, Some(DefMod(root_def_id)), false, true);
+        let graph_root = arenas.modules.alloc(graph_root);
 
         Resolver {
             session: session,
@@ -1234,7 +1254,7 @@ fn new(session: &'a Session,
 
             // The outermost module has def ID 0; this is not reflected in the
             // AST.
-            graph_root: graph_root.clone(),
+            graph_root: graph_root,
 
             trait_item_map: FnvHashMap(),
             structs: FnvHashMap(),
@@ -1266,9 +1286,25 @@ fn new(session: &'a Session,
 
             callback: None,
             resolved: false,
+
+            arenas: arenas,
         }
     }
 
+    fn arenas() -> ResolverArenas<'a> {
+        ResolverArenas {
+            modules: arena::TypedArena::new(),
+        }
+    }
+
+    fn new_module(&self,
+                  parent_link: ParentLink<'a>,
+                  def: Option<Def>,
+                  external: bool,
+                  is_public: bool) -> Module<'a> {
+        self.arenas.modules.alloc(ModuleS::new(parent_link, def, external, is_public))
+    }
+
     #[inline]
     fn record_import_use(&mut self, import_id: NodeId, name: Name) {
         if !self.make_glob_map {
@@ -1292,12 +1328,8 @@ fn get_trait_name(&self, did: DefId) -> Name {
         }
     }
 
-    /// Checks that the names of external crates don't collide with other
-    /// external crates.
-    fn check_for_conflicts_between_external_crates(&self,
-                                                   module: &Module,
-                                                   name: Name,
-                                                   span: Span) {
+    /// Check that an external crate doesn't collide with items or other external crates.
+    fn check_for_conflicts_for_external_crate(&self, module: Module<'a>, name: Name, span: Span) {
         if module.external_module_children.borrow().contains_key(&name) {
             span_err!(self.session,
                       span,
@@ -1305,38 +1337,42 @@ fn check_for_conflicts_between_external_crates(&self,
                       "an external crate named `{}` has already been imported into this module",
                       name);
         }
+        match module.children.borrow().get(&name) {
+            Some(name_bindings) if name_bindings.type_ns.defined() => {
+                resolve_error(self,
+                              name_bindings.type_ns.span().unwrap_or(codemap::DUMMY_SP),
+                              ResolutionError::NameConflictsWithExternCrate(name));
+            }
+            _ => {},
+        }
     }
 
     /// Checks that the names of items don't collide with external crates.
     fn check_for_conflicts_between_external_crates_and_items(&self,
-                                                             module: &Module,
+                                                             module: Module<'a>,
                                                              name: Name,
                                                              span: Span) {
         if module.external_module_children.borrow().contains_key(&name) {
-            span_err!(self.session,
-                      span,
-                      E0260,
-                      "the name `{}` conflicts with an external crate that has been imported \
-                       into this module",
-                      name);
+            resolve_error(self, span, ResolutionError::NameConflictsWithExternCrate(name));
         }
     }
 
     /// Resolves the given module path from the given root `module_`.
     fn resolve_module_path_from_root(&mut self,
-                                     module_: Rc<Module>,
+                                     module_: Module<'a>,
                                      module_path: &[Name],
                                      index: usize,
                                      span: Span,
                                      name_search_type: NameSearchType,
                                      lp: LastPrivate)
-                                     -> ResolveResult<(Rc<Module>, LastPrivate)> {
-        fn search_parent_externals(needle: Name, module: &Rc<Module>) -> Option<Rc<Module>> {
+                                     -> ResolveResult<(Module<'a>, LastPrivate)> {
+        fn search_parent_externals<'a>(needle: Name, module: Module<'a>)
+                                       -> Option<Module<'a>> {
             match module.external_module_children.borrow().get(&needle) {
-                Some(_) => Some(module.clone()),
+                Some(_) => Some(module),
                 None => match module.parent_link {
                     ModuleParentLink(ref parent, _) => {
-                        search_parent_externals(needle, &parent.upgrade().unwrap())
+                        search_parent_externals(needle, parent)
                     }
                     _ => None,
                 },
@@ -1353,14 +1389,14 @@ fn search_parent_externals(needle: Name, module: &Rc<Module>) -> Option<Rc<Modul
         // modules as we go.
         while index < module_path_len {
             let name = module_path[index];
-            match self.resolve_name_in_module(search_module.clone(),
+            match self.resolve_name_in_module(search_module,
                                               name,
                                               TypeNS,
                                               name_search_type,
                                               false) {
                 Failed(None) => {
                     let segment_name = name.as_str();
-                    let module_name = module_to_string(&*search_module);
+                    let module_name = module_to_string(search_module);
                     let mut span = span;
                     let msg = if "???" == &module_name[..] {
                         span.hi = span.lo + Pos::from_usize(segment_name.len());
@@ -1431,12 +1467,12 @@ fn search_parent_externals(needle: Name, module: &Rc<Module>) -> Option<Rc<Modul
     /// On success, returns the resolved module, and the closest *private*
     /// module found to the destination when resolving this path.
     fn resolve_module_path(&mut self,
-                           module_: Rc<Module>,
+                           module_: Module<'a>,
                            module_path: &[Name],
                            use_lexical_scope: UseLexicalScopeFlag,
                            span: Span,
                            name_search_type: NameSearchType)
-                           -> ResolveResult<(Rc<Module>, LastPrivate)> {
+                           -> ResolveResult<(Module<'a>, LastPrivate)> {
         let module_path_len = module_path.len();
         assert!(module_path_len > 0);
 
@@ -1445,7 +1481,7 @@ fn resolve_module_path(&mut self,
                module_to_string(&*module_));
 
         // Resolve the module prefix, if any.
-        let module_prefix_result = self.resolve_module_prefix(module_.clone(), module_path);
+        let module_prefix_result = self.resolve_module_prefix(module_, module_path);
 
         let search_module;
         let start_index;
@@ -1481,7 +1517,7 @@ fn resolve_module_path(&mut self,
                     DontUseLexicalScope => {
                         // This is a crate-relative path. We will start the
                         // resolution process at index zero.
-                        search_module = self.graph_root.clone();
+                        search_module = self.graph_root;
                         start_index = 0;
                         last_private = LastMod(AllPublic);
                     }
@@ -1505,7 +1541,7 @@ fn resolve_module_path(&mut self,
                 }
             }
             Success(PrefixFound(ref containing_module, index)) => {
-                search_module = containing_module.clone();
+                search_module = containing_module;
                 start_index = index;
                 last_private = LastMod(DependsOn(containing_module.def_id()
                                                                   .unwrap()));
@@ -1523,11 +1559,11 @@ fn resolve_module_path(&mut self,
     /// Invariant: This must only be called during main resolution, not during
     /// import resolution.
     fn resolve_item_in_lexical_scope(&mut self,
-                                     module_: Rc<Module>,
+                                     module_: Module<'a>,
                                      name: Name,
                                      namespace: Namespace,
                                      record_used: bool)
-                                     -> ResolveResult<(Target, bool)> {
+                                     -> ResolveResult<(Target<'a>, bool)> {
         debug!("(resolving item in lexical scope) resolving `{}` in namespace {:?} in `{}`",
                name,
                namespace,
@@ -1540,7 +1576,7 @@ fn resolve_item_in_lexical_scope(&mut self,
         match module_.children.borrow().get(&name) {
             Some(name_bindings) if name_bindings[namespace].defined() => {
                 debug!("top name bindings succeeded");
-                return Success((Target::new(module_.clone(),
+                return Success((Target::new(module_,
                                             name_bindings[namespace].clone(),
                                             Shadowable::Never),
                                 false));
@@ -1580,9 +1616,8 @@ fn resolve_item_in_lexical_scope(&mut self,
 
         // Search for external modules.
         if namespace == TypeNS {
-            // FIXME (21114): In principle unclear `child` *has* to be lifted.
-            let child = module_.external_module_children.borrow().get(&name).cloned();
-            if let Some(module) = child {
+            let children = module_.external_module_children.borrow();
+            if let Some(module) = children.get(&name) {
                 let name_binding = NameBinding::create_from_module(module);
                 debug!("lower name bindings succeeded");
                 return Success((Target::new(module_, name_binding, Shadowable::Never),
@@ -1594,7 +1629,7 @@ fn resolve_item_in_lexical_scope(&mut self,
         let mut search_module = module_;
         loop {
             // Go to the next parent.
-            match search_module.parent_link.clone() {
+            match search_module.parent_link {
                 NoParentLink => {
                     // No more parents. This module was unresolved.
                     debug!("(resolving item in lexical scope) unresolved module");
@@ -1607,16 +1642,16 @@ fn resolve_item_in_lexical_scope(&mut self,
                                 searching through module parents");
                             return Failed(None);
                     } else {
-                        search_module = parent_module_node.upgrade().unwrap();
+                        search_module = parent_module_node;
                     }
                 }
-                BlockParentLink(ref parent_module_node, _) => {
-                    search_module = parent_module_node.upgrade().unwrap();
+                BlockParentLink(parent_module_node, _) => {
+                    search_module = parent_module_node;
                 }
             }
 
             // Resolve the name in the parent module.
-            match self.resolve_name_in_module(search_module.clone(),
+            match self.resolve_name_in_module(search_module,
                                               name,
                                               namespace,
                                               PathSearch,
@@ -1643,9 +1678,9 @@ fn resolve_item_in_lexical_scope(&mut self,
 
     /// Resolves a module name in the current lexical scope.
     fn resolve_module_in_lexical_scope(&mut self,
-                                       module_: Rc<Module>,
+                                       module_: Module<'a>,
                                        name: Name)
-                                       -> ResolveResult<Rc<Module>> {
+                                       -> ResolveResult<Module<'a>> {
         // If this module is an anonymous module, resolve the item in the
         // lexical scope. Otherwise, resolve the item from the crate root.
         let resolve_result = self.resolve_item_in_lexical_scope(module_, name, TypeNS, true);
@@ -1671,14 +1706,14 @@ fn resolve_module_in_lexical_scope(&mut self,
     }
 
     /// Returns the nearest normal module parent of the given module.
-    fn get_nearest_normal_module_parent(&mut self, module_: Rc<Module>) -> Option<Rc<Module>> {
+    fn get_nearest_normal_module_parent(&mut self, module_: Module<'a>) -> Option<Module<'a>> {
         let mut module_ = module_;
         loop {
-            match module_.parent_link.clone() {
+            match module_.parent_link {
                 NoParentLink => return None,
                 ModuleParentLink(new_module, _) |
                 BlockParentLink(new_module, _) => {
-                    let new_module = new_module.upgrade().unwrap();
+                    let new_module = new_module;
                     if new_module.is_normal() {
                         return Some(new_module);
                     }
@@ -1690,11 +1725,11 @@ fn get_nearest_normal_module_parent(&mut self, module_: Rc<Module>) -> Option<Rc
 
     /// Returns the nearest normal module parent of the given module, or the
     /// module itself if it is a normal module.
-    fn get_nearest_normal_module_parent_or_self(&mut self, module_: Rc<Module>) -> Rc<Module> {
+    fn get_nearest_normal_module_parent_or_self(&mut self, module_: Module<'a>) -> Module<'a> {
         if module_.is_normal() {
             return module_;
         }
-        match self.get_nearest_normal_module_parent(module_.clone()) {
+        match self.get_nearest_normal_module_parent(module_) {
             None => module_,
             Some(new_module) => new_module,
         }
@@ -1704,9 +1739,9 @@ fn get_nearest_normal_module_parent_or_self(&mut self, module_: Rc<Module>) -> R
     /// (b) some chain of `super::`.
     /// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) *
     fn resolve_module_prefix(&mut self,
-                             module_: Rc<Module>,
+                             module_: Module<'a>,
                              module_path: &[Name])
-                             -> ResolveResult<ModulePrefixResult> {
+                             -> ResolveResult<ModulePrefixResult<'a>> {
         // Start at the current module if we see `self` or `super`, or at the
         // top of the crate otherwise.
         let mut i = match &*module_path[0].as_str() {
@@ -1742,12 +1777,12 @@ fn resolve_module_prefix(&mut self,
     /// The boolean returned on success is an indicator of whether this lookup
     /// passed through a public re-export proxy.
     fn resolve_name_in_module(&mut self,
-                              module_: Rc<Module>,
+                              module_: Module<'a>,
                               name: Name,
                               namespace: Namespace,
                               name_search_type: NameSearchType,
                               allow_private_imports: bool)
-                              -> ResolveResult<(Target, bool)> {
+                              -> ResolveResult<(Target<'a>, bool)> {
         debug!("(resolving name in module) resolving `{}` in `{}`",
                name,
                module_to_string(&*module_));
@@ -1755,10 +1790,11 @@ fn resolve_name_in_module(&mut self,
         // First, check the direct children of the module.
         build_reduced_graph::populate_module_if_necessary(self, &module_);
 
-        match module_.children.borrow().get(&name) {
+        let children = module_.children.borrow();
+        match children.get(&name) {
             Some(name_bindings) if name_bindings[namespace].defined() => {
                 debug!("(resolving name in module) found node as child");
-                return Success((Target::new(module_.clone(),
+                return Success((Target::new(module_,
                                             name_bindings[namespace].clone(),
                                             Shadowable::Never),
                                 false));
@@ -1777,7 +1813,8 @@ fn resolve_name_in_module(&mut self,
         }
 
         // Check the list of resolved imports.
-        match module_.import_resolutions.borrow().get(&name) {
+        let children = module_.import_resolutions.borrow();
+        match children.get(&name) {
             Some(import_resolution) if allow_private_imports ||
                                        import_resolution[namespace].is_public => {
 
@@ -1809,9 +1846,8 @@ fn resolve_name_in_module(&mut self,
 
         // Finally, search through external children.
         if namespace == TypeNS {
-            // FIXME (21114): In principle unclear `child` *has* to be lifted.
-            let child = module_.external_module_children.borrow().get(&name).cloned();
-            if let Some(module) = child {
+            let children = module_.external_module_children.borrow();
+            if let Some(module) = children.get(&name) {
                 let name_binding = NameBinding::create_from_module(module);
                 return Success((Target::new(module_, name_binding, Shadowable::Never),
                                 false));
@@ -1823,7 +1859,7 @@ fn resolve_name_in_module(&mut self,
         return Failed(None);
     }
 
-    fn report_unresolved_imports(&mut self, module_: Rc<Module>) {
+    fn report_unresolved_imports(&mut self, module_: Module<'a>) {
         let index = module_.resolved_import_count.get();
         let imports = module_.imports.borrow();
         let import_count = imports.len();
@@ -1848,7 +1884,7 @@ fn report_unresolved_imports(&mut self, module_: Rc<Module>) {
         }
 
         for (_, module_) in module_.anonymous_children.borrow().iter() {
-            self.report_unresolved_imports(module_.clone());
+            self.report_unresolved_imports(module_);
         }
     }
 
@@ -1873,7 +1909,7 @@ fn report_unresolved_imports(&mut self, module_: Rc<Module>) {
     fn with_scope<F>(&mut self, name: Option<Name>, f: F)
         where F: FnOnce(&mut Resolver)
     {
-        let orig_module = self.current_module.clone();
+        let orig_module = self.current_module;
 
         // Move down in the graph.
         match name {
@@ -2461,14 +2497,14 @@ fn resolve_block(&mut self, block: &Block) {
         self.value_ribs.push(Rib::new(NormalRibKind));
 
         // Move down in the graph, if there's an anonymous module rooted here.
-        let orig_module = self.current_module.clone();
+        let orig_module = self.current_module;
         match orig_module.anonymous_children.borrow().get(&block.id) {
             None => {
                 // Nothing to do.
             }
             Some(anonymous_module) => {
                 debug!("(resolving block) found anonymous module, moving down");
-                self.current_module = anonymous_module.clone();
+                self.current_module = anonymous_module;
             }
         }
 
@@ -2857,7 +2893,7 @@ fn resolve_bare_identifier_pattern(&mut self,
                                        name: Name,
                                        span: Span)
                                        -> BareIdentifierPatternResolution {
-        let module = self.current_module.clone();
+        let module = self.current_module;
         match self.resolve_item_in_lexical_scope(module, name, ValueNS, true) {
             Success((target, _)) => {
                 debug!("(resolve bare identifier pattern) succeeded in finding {} at {:?}",
@@ -3121,7 +3157,7 @@ fn resolve_module_relative_path(&mut self,
 
         let containing_module;
         let last_private;
-        let current_module = self.current_module.clone();
+        let current_module = self.current_module;
         match self.resolve_module_path(current_module,
                                        &module_path[..],
                                        UseLexicalScope,
@@ -3148,7 +3184,7 @@ fn resolve_module_relative_path(&mut self,
         }
 
         let name = segments.last().unwrap().identifier.name;
-        let def = match self.resolve_name_in_module(containing_module.clone(),
+        let def = match self.resolve_name_in_module(containing_module,
                                                     name,
                                                     namespace,
                                                     NameSearchType::PathSearch,
@@ -3179,7 +3215,7 @@ fn resolve_crate_relative_path(&mut self,
                                   .map(|ps| ps.identifier.name)
                                   .collect::<Vec<_>>();
 
-        let root_module = self.graph_root.clone();
+        let root_module = self.graph_root;
 
         let containing_module;
         let last_private;
@@ -3269,7 +3305,7 @@ fn resolve_item_by_name_in_lexical_scope(&mut self,
                                              record_used: bool)
                                              -> Option<Def> {
         // Check the items.
-        let module = self.current_module.clone();
+        let module = self.current_module;
         match self.resolve_item_in_lexical_scope(module, name, namespace, record_used) {
             Success((target, _)) => {
                 match target.binding.def() {
@@ -3331,11 +3367,11 @@ fn extract_path_and_node_id(t: &Ty,
             }
         }
 
-        fn get_module(this: &mut Resolver,
-                      span: Span,
-                      name_path: &[ast::Name])
-                      -> Option<Rc<Module>> {
-            let root = this.current_module.clone();
+        fn get_module<'a, 'tcx>(this: &mut Resolver<'a, 'tcx>,
+                                span: Span,
+                                name_path: &[ast::Name])
+                                -> Option<Module<'a>> {
+            let root = this.current_module;
             let last_name = name_path.last().unwrap();
 
             if name_path.len() == 1 {
@@ -3589,7 +3625,7 @@ fn resolve_expr(&mut self, expr: &Expr) {
                                     let name_path = path.segments.iter()
                                                         .map(|seg| seg.identifier.name)
                                                         .collect::<Vec<_>>();
-                                    let current_module = self.current_module.clone();
+                                    let current_module = self.current_module;
 
                                     match self.resolve_module_path(current_module,
                                                    &name_path[..],
@@ -3711,7 +3747,7 @@ fn add_trait_info(found_traits: &mut Vec<DefId>, trait_def_id: DefId, name: Name
         }
 
         let mut found_traits = Vec::new();
-        let mut search_module = self.current_module.clone();
+        let mut search_module = self.current_module;
         loop {
             // Look for the current trait.
             match self.current_trait_ref {
@@ -3764,10 +3800,10 @@ fn add_trait_info(found_traits: &mut Vec<DefId>, trait_def_id: DefId, name: Name
                 }
             }
 
-            match search_module.parent_link.clone() {
+            match search_module.parent_link {
                 NoParentLink | ModuleParentLink(..) => break,
                 BlockParentLink(parent_module, _) => {
-                    search_module = parent_module.upgrade().unwrap();
+                    search_module = parent_module;
                 }
             }
         }
@@ -3814,7 +3850,7 @@ fn enforce_default_binding_mode(&mut self,
     //
 
     #[allow(dead_code)]   // useful for debugging
-    fn dump_module(&mut self, module_: Rc<Module>) {
+    fn dump_module(&mut self, module_: Module<'a>) {
         debug!("Dump of module `{}`:", module_to_string(&*module_));
 
         debug!("Children:");
@@ -3877,20 +3913,20 @@ fn path_names_to_string(path: &Path, depth: usize) -> String {
 }
 
 /// A somewhat inefficient routine to obtain the name of a module.
-fn module_to_string(module: &Module) -> String {
+fn module_to_string<'a>(module: Module<'a>) -> String {
     let mut names = Vec::new();
 
-    fn collect_mod(names: &mut Vec<ast::Name>, module: &Module) {
+    fn collect_mod<'a>(names: &mut Vec<ast::Name>, module: Module<'a>) {
         match module.parent_link {
             NoParentLink => {}
             ModuleParentLink(ref module, name) => {
                 names.push(name);
-                collect_mod(names, &*module.upgrade().unwrap());
+                collect_mod(names, module);
             }
             BlockParentLink(ref module, _) => {
                 // danger, shouldn't be ident?
                 names.push(special_idents::opaque.name);
-                collect_mod(names, &*module.upgrade().unwrap());
+                collect_mod(names, module);
             }
         }
     }
@@ -3932,7 +3968,8 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
                                make_glob_map: MakeGlobMap)
                                -> CrateMap {
     let krate = ast_map.krate();
-    let mut resolver = create_resolver(session, ast_map, krate, make_glob_map, None);
+    let arenas = Resolver::arenas();
+    let mut resolver = create_resolver(session, ast_map, krate, make_glob_map, &arenas, None);
 
     resolver.resolve_crate(krate);
 
@@ -3964,9 +4001,10 @@ pub fn create_resolver<'a, 'tcx>(session: &'a Session,
                                  ast_map: &'a hir_map::Map<'tcx>,
                                  krate: &'a Crate,
                                  make_glob_map: MakeGlobMap,
+                                 arenas: &'a ResolverArenas<'a>,
                                  callback: Option<Box<Fn(hir_map::Node, &mut bool) -> bool>>)
                                  -> Resolver<'a, 'tcx> {
-    let mut resolver = Resolver::new(session, ast_map, make_glob_map);
+    let mut resolver = Resolver::new(session, ast_map, make_glob_map, arenas);
 
     resolver.callback = callback;
 
index 59cf83e91d2da68bc13f4997fa58af3b160abeb2..13f4348f79522052aa2b735df00d24be3f055798 100644 (file)
@@ -28,7 +28,6 @@
 use syntax::ast;
 
 use std::ops::{Deref, DerefMut};
-use std::rc::Rc;
 
 struct ExportRecorder<'a, 'b: 'a, 'tcx: 'b> {
     resolver: &'a mut Resolver<'b, 'tcx>,
@@ -50,7 +49,7 @@ fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b, 'tcx> {
 }
 
 impl<'a, 'b, 'tcx> ExportRecorder<'a, 'b, 'tcx> {
-    fn record_exports_for_module_subtree(&mut self, module_: Rc<Module>) {
+    fn record_exports_for_module_subtree(&mut self, module_: Module<'b>) {
         // If this isn't a local krate, then bail out. We don't need to record
         // exports for nonlocal crates.
 
@@ -59,23 +58,23 @@ fn record_exports_for_module_subtree(&mut self, module_: Rc<Module>) {
                 // OK. Continue.
                 debug!("(recording exports for module subtree) recording exports for local \
                         module `{}`",
-                       module_to_string(&*module_));
+                       module_to_string(module_));
             }
             None => {
                 // Record exports for the root module.
                 debug!("(recording exports for module subtree) recording exports for root module \
                         `{}`",
-                       module_to_string(&*module_));
+                       module_to_string(module_));
             }
             Some(_) => {
                 // Bail out.
                 debug!("(recording exports for module subtree) not recording exports for `{}`",
-                       module_to_string(&*module_));
+                       module_to_string(module_));
                 return;
             }
         }
 
-        self.record_exports_for_module(&*module_);
+        self.record_exports_for_module(module_);
         build_reduced_graph::populate_module_if_necessary(self.resolver, &module_);
 
         for (_, child_name_bindings) in module_.children.borrow().iter() {
@@ -90,11 +89,11 @@ fn record_exports_for_module_subtree(&mut self, module_: Rc<Module>) {
         }
 
         for (_, child_module) in module_.anonymous_children.borrow().iter() {
-            self.record_exports_for_module_subtree(child_module.clone());
+            self.record_exports_for_module_subtree(child_module);
         }
     }
 
-    fn record_exports_for_module(&mut self, module_: &Module) {
+    fn record_exports_for_module(&mut self, module_: Module<'b>) {
         let mut exports = Vec::new();
 
         self.add_exports_for_module(&mut exports, module_);
@@ -128,7 +127,7 @@ fn add_export_of_namebinding(&mut self,
         }
     }
 
-    fn add_exports_for_module(&mut self, exports: &mut Vec<Export>, module_: &Module) {
+    fn add_exports_for_module(&mut self, exports: &mut Vec<Export>, module_: Module<'b>) {
         for (name, import_resolution) in module_.import_resolutions.borrow().iter() {
             let xs = [TypeNS, ValueNS];
             for &ns in &xs {
@@ -150,6 +149,6 @@ fn add_exports_for_module(&mut self, exports: &mut Vec<Export>, module_: &Module
 
 pub fn record(resolver: &mut Resolver) {
     let mut recorder = ExportRecorder { resolver: resolver };
-    let root_module = recorder.graph_root.clone();
+    let root_module = recorder.graph_root;
     recorder.record_exports_for_module_subtree(root_module);
 }
index 40bf55efde645eb31e8d45c8fe733015a46d066a..53d1b888d8e87a5b0f8c3bfa837efafe01141178 100644 (file)
@@ -36,7 +36,6 @@
 use syntax::util::lev_distance::find_best_match_for_name;
 
 use std::mem::replace;
-use std::rc::Rc;
 
 /// Contains data for specific types of import directives.
 #[derive(Copy, Clone,Debug)]
@@ -84,17 +83,15 @@ pub fn new(module_path: Vec<Name>,
 
 /// The item that an import resolves to.
 #[derive(Clone,Debug)]
-pub struct Target {
-    pub target_module: Rc<Module>,
-    pub binding: NameBinding,
+pub struct Target<'a> {
+    pub target_module: Module<'a>,
+    pub binding: NameBinding<'a>,
     pub shadowable: Shadowable,
 }
 
-impl Target {
-    pub fn new(target_module: Rc<Module>,
-               binding: NameBinding,
-               shadowable: Shadowable)
-               -> Target {
+impl<'a> Target<'a> {
+    pub fn new(target_module: Module<'a>, binding: NameBinding<'a>, shadowable: Shadowable)
+               -> Self {
         Target {
             target_module: target_module,
             binding: binding,
@@ -109,44 +106,44 @@ pub fn new(target_module: Rc<Module>,
 /// and for each namespace, it records the `use` directive importing the name in the namespace
 /// and the `Target` to which the name in the namespace resolves (if applicable).
 /// Different `use` directives may import the same name in different namespaces.
-pub struct ImportResolutionPerNamespace {
+pub struct ImportResolutionPerNamespace<'a> {
     // When outstanding_references reaches zero, outside modules can count on the targets being
     // correct. Before then, all bets are off; future `use` directives could override the name.
     // Since shadowing is forbidden, the only way outstanding_references > 1 in a legal program
     // is if the name is imported by exactly two `use` directives, one of which resolves to a
     // value and the other of which resolves to a type.
     pub outstanding_references: usize,
-    pub type_ns: ImportResolution,
-    pub value_ns: ImportResolution,
+    pub type_ns: ImportResolution<'a>,
+    pub value_ns: ImportResolution<'a>,
 }
 
 /// Records what we know about an imported name in a namespace (see `ImportResolutionPerNamespace`).
 #[derive(Clone,Debug)]
-pub struct ImportResolution {
+pub struct ImportResolution<'a> {
     /// Whether the name in the namespace was imported with a `use` or a `pub use`.
     pub is_public: bool,
 
     /// Resolution of the name in the namespace
-    pub target: Option<Target>,
+    pub target: Option<Target<'a>>,
 
     /// The source node of the `use` directive
     pub id: NodeId,
 }
 
-impl ::std::ops::Index<Namespace> for ImportResolutionPerNamespace {
-    type Output = ImportResolution;
-    fn index(&self, ns: Namespace) -> &ImportResolution {
+impl<'a> ::std::ops::Index<Namespace> for ImportResolutionPerNamespace<'a> {
+    type Output = ImportResolution<'a>;
+    fn index(&self, ns: Namespace) -> &ImportResolution<'a> {
         match ns { TypeNS => &self.type_ns, ValueNS => &self.value_ns }
     }
 }
 
-impl ::std::ops::IndexMut<Namespace> for ImportResolutionPerNamespace {
-    fn index_mut(&mut self, ns: Namespace) -> &mut ImportResolution {
+impl<'a> ::std::ops::IndexMut<Namespace> for ImportResolutionPerNamespace<'a> {
+    fn index_mut(&mut self, ns: Namespace) -> &mut ImportResolution<'a> {
         match ns { TypeNS => &mut self.type_ns, ValueNS => &mut self.value_ns }
     }
 }
 
-impl ImportResolutionPerNamespace {
+impl<'a> ImportResolutionPerNamespace<'a> {
     pub fn new(id: NodeId, is_public: bool) -> Self {
         let resolution = ImportResolution { id: id, is_public: is_public, target: None };
         ImportResolutionPerNamespace {
@@ -191,8 +188,8 @@ fn resolve_imports(&mut self) {
                    i,
                    self.resolver.unresolved_imports);
 
-            let module_root = self.resolver.graph_root.clone();
-            let errors = self.resolve_imports_for_module_subtree(module_root.clone());
+            let module_root = self.resolver.graph_root;
+            let errors = self.resolve_imports_for_module_subtree(module_root);
 
             if self.resolver.unresolved_imports == 0 {
                 debug!("(resolving imports) success");
@@ -225,13 +222,13 @@ fn resolve_imports(&mut self) {
     /// Attempts to resolve imports for the given module and all of its
     /// submodules.
     fn resolve_imports_for_module_subtree(&mut self,
-                                          module_: Rc<Module>)
+                                          module_: Module<'b>)
                                           -> Vec<ImportResolvingError> {
         let mut errors = Vec::new();
         debug!("(resolving imports for module subtree) resolving {}",
                module_to_string(&*module_));
-        let orig_module = replace(&mut self.resolver.current_module, module_.clone());
-        errors.extend(self.resolve_imports_for_module(module_.clone()));
+        let orig_module = replace(&mut self.resolver.current_module, module_);
+        errors.extend(self.resolve_imports_for_module(module_));
         self.resolver.current_module = orig_module;
 
         build_reduced_graph::populate_module_if_necessary(self.resolver, &module_);
@@ -247,14 +244,14 @@ fn resolve_imports_for_module_subtree(&mut self,
         }
 
         for (_, child_module) in module_.anonymous_children.borrow().iter() {
-            errors.extend(self.resolve_imports_for_module_subtree(child_module.clone()));
+            errors.extend(self.resolve_imports_for_module_subtree(child_module));
         }
 
         errors
     }
 
     /// Attempts to resolve imports for the given module only.
-    fn resolve_imports_for_module(&mut self, module: Rc<Module>) -> Vec<ImportResolvingError> {
+    fn resolve_imports_for_module(&mut self, module: Module<'b>) -> Vec<ImportResolvingError> {
         let mut errors = Vec::new();
 
         if module.all_imports_resolved() {
@@ -268,7 +265,7 @@ fn resolve_imports_for_module(&mut self, module: Rc<Module>) -> Vec<ImportResolv
         let mut indeterminate_imports = Vec::new();
         while module.resolved_import_count.get() + indeterminate_imports.len() < import_count {
             let import_index = module.resolved_import_count.get();
-            match self.resolve_import_for_module(module.clone(), &imports[import_index]) {
+            match self.resolve_import_for_module(module, &imports[import_index]) {
                 ResolveResult::Failed(err) => {
                     let import_directive = &imports[import_index];
                     let (span, help) = match err {
@@ -306,7 +303,7 @@ fn resolve_imports_for_module(&mut self, module: Rc<Module>) -> Vec<ImportResolv
     /// currently-unresolved imports, or success if we know the name exists.
     /// If successful, the resolved bindings are written into the module.
     fn resolve_import_for_module(&mut self,
-                                 module_: Rc<Module>,
+                                 module_: Module<'b>,
                                  import_directive: &ImportDirective)
                                  -> ResolveResult<()> {
         let mut resolution_result = ResolveResult::Failed(None);
@@ -319,9 +316,9 @@ fn resolve_import_for_module(&mut self,
         // First, resolve the module path for the directive, if necessary.
         let container = if module_path.is_empty() {
             // Use the crate root.
-            Some((self.resolver.graph_root.clone(), LastMod(AllPublic)))
+            Some((self.resolver.graph_root, LastMod(AllPublic)))
         } else {
-            match self.resolver.resolve_module_path(module_.clone(),
+            match self.resolver.resolve_module_path(module_,
                                                     &module_path[..],
                                                     UseLexicalScopeFlag::DontUseLexicalScope,
                                                     import_directive.span,
@@ -399,8 +396,8 @@ fn resolve_import_for_module(&mut self,
     }
 
     fn resolve_single_import(&mut self,
-                             module_: &Module,
-                             target_module: Rc<Module>,
+                             module_: Module<'b>,
+                             target_module: Module<'b>,
                              target: Name,
                              source: Name,
                              directive: &ImportDirective,
@@ -447,7 +444,7 @@ fn resolve_single_import(&mut self,
                 let mut pub_err = false;
                 if child_name_bindings.value_ns.defined() {
                     debug!("(resolving single import) found value binding");
-                    value_result = BoundResult(target_module.clone(),
+                    value_result = BoundResult(target_module,
                                                child_name_bindings.value_ns.clone());
                     if directive.is_public && !child_name_bindings.value_ns.is_public() {
                         let msg = format!("`{}` is private, and cannot be reexported", source);
@@ -473,7 +470,7 @@ fn resolve_single_import(&mut self,
                 }
                 if child_name_bindings.type_ns.defined() {
                     debug!("(resolving single import) found type binding");
-                    type_result = BoundResult(target_module.clone(),
+                    type_result = BoundResult(target_module,
                                               child_name_bindings.type_ns.clone());
                     if !pub_err && directive.is_public &&
                        !child_name_bindings.type_ns.is_public() {
@@ -543,11 +540,11 @@ fn resolve_single_import(&mut self,
                     }
                     Some(import_resolution) if import_resolution.outstanding_references == 0 => {
 
-                        fn get_binding(this: &mut Resolver,
-                                       import_resolution: &ImportResolutionPerNamespace,
-                                       namespace: Namespace,
-                                       source: Name)
-                                       -> NamespaceResult {
+                        fn get_binding<'a>(this: &mut Resolver,
+                                           import_resolution: &ImportResolutionPerNamespace<'a>,
+                                           namespace: Namespace,
+                                           source: Name)
+                                           -> NamespaceResult<'a> {
 
                             // Import resolutions must be declared with "pub"
                             // in order to be exported.
@@ -640,7 +637,7 @@ fn get_binding(this: &mut Resolver,
         match type_result {
             BoundResult(..) => {}
             _ => {
-                match target_module.external_module_children.borrow_mut().get(&source).cloned() {
+                match target_module.external_module_children.borrow_mut().get(&source) {
                     None => {} // Continue.
                     Some(module) => {
                         debug!("(resolving single import) found external module");
@@ -652,7 +649,7 @@ fn get_binding(this: &mut Resolver,
                             _ => {}
                         }
                         let name_binding = NameBinding::create_from_module(module);
-                        type_result = BoundResult(target_module.clone(), name_binding);
+                        type_result = BoundResult(target_module, name_binding);
                         type_used_public = true;
                     }
                 }
@@ -685,7 +682,7 @@ fn get_binding(this: &mut Resolver,
                                                              target);
 
                         import_resolution[namespace] = ImportResolution {
-                            target: Some(Target::new(target_module.clone(),
+                            target: Some(Target::new(target_module,
                                                      name_binding.clone(),
                                                      directive.shadowable)),
                             id: directive.id,
@@ -777,8 +774,8 @@ fn get_binding(this: &mut Resolver,
     // that exports nothing is valid). target_module is the module we are
     // actually importing, i.e., `foo` in `use foo::*`.
     fn resolve_glob_import(&mut self,
-                           module_: &Module,
-                           target_module: Rc<Module>,
+                           module_: Module<'b>,
+                           target_module: Module<'b>,
                            import_directive: &ImportDirective,
                            lp: LastPrivate)
                            -> ResolveResult<()> {
@@ -841,7 +838,7 @@ fn resolve_glob_import(&mut self,
 
         for (&name, name_bindings) in target_module.children.borrow().iter() {
             self.merge_import_resolution(module_,
-                                         target_module.clone(),
+                                         target_module,
                                          import_directive,
                                          name,
                                          name_bindings.clone());
@@ -863,11 +860,11 @@ fn resolve_glob_import(&mut self,
     }
 
     fn merge_import_resolution(&mut self,
-                               module_: &Module,
-                               containing_module: Rc<Module>,
+                               module_: Module<'b>,
+                               containing_module: Module<'b>,
                                import_directive: &ImportDirective,
                                name: Name,
-                               name_bindings: NameBindings) {
+                               name_bindings: NameBindings<'b>) {
         let id = import_directive.id;
         let is_public = import_directive.is_public;
 
@@ -916,7 +913,7 @@ fn merge_import_resolution(&mut self,
                                   msg);
                     } else {
                         dest_import_resolution[namespace] = ImportResolution {
-                            target: Some(Target::new(containing_module.clone(),
+                            target: Some(Target::new(containing_module,
                                                      name_bindings[namespace].clone(),
                                                      import_directive.shadowable)),
                             id: id,
@@ -993,8 +990,8 @@ fn check_that_import_is_importable(&mut self,
 
     /// Checks that imported names and items don't have the same name.
     fn check_for_conflicts_between_imports_and_items(&mut self,
-                                                     module: &Module,
-                                                     import: &ImportResolutionPerNamespace,
+                                                     module: Module<'b>,
+                                                     import: &ImportResolutionPerNamespace<'b>,
                                                      import_span: Span,
                                                      name: Name) {
         // First, check for conflicts between imports and `extern crate`s.
@@ -1013,8 +1010,7 @@ fn check_for_conflicts_between_imports_and_items(&mut self,
         }
 
         // Check for item conflicts.
-        let children = module.children.borrow();
-        let name_bindings = match children.get(&name) {
+        let name_bindings = match module.children.borrow().get(&name) {
             None => {
                 // There can't be any conflicts.
                 return;
index e1edbf4a1276dc963d13858c4510c03d45c0c1bf..ec1383f1f7b2b19ac8b40dc4db49d3e801096b13 100644 (file)
@@ -1063,10 +1063,6 @@ fn link_args(cmd: &mut Linker,
         cmd.args(&rpath::get_rpath_flags(&mut rpath_config));
     }
 
-    // Use the gold linker if possible instead of ld. It is much
-    // faster.
-    cmd.try_gold_linker();
-
     // Finally add all the linker arguments provided on the command line along
     // with any #[link_args] attributes found inside the crate
     if let Some(ref args) = sess.opts.cg.link_args {
index 90ebf364367a0c66388a8423e70b74fef16e3198..f585c65228a825116d0e402eeb7b42f97f74d0c5 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::env;
 use std::ffi::OsString;
 use std::fs::{self, File};
 use std::io::{self, BufWriter};
@@ -57,7 +56,6 @@ pub trait Linker {
     fn no_whole_archives(&mut self);
     fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation,
                       tmpdir: &Path);
-    fn try_gold_linker(&mut self);
 }
 
 pub struct GnuLinker<'a> {
@@ -149,8 +147,8 @@ fn optimize(&mut self) {
 
         // GNU-style linkers support optimization with -O. GNU ld doesn't
         // need a numeric argument, but other linkers do.
-        if self.sess.opts.optimize == config::Default ||
-           self.sess.opts.optimize == config::Aggressive {
+        if self.sess.opts.optimize == config::OptLevel::Default ||
+           self.sess.opts.optimize == config::OptLevel::Aggressive {
             self.cmd.arg("-Wl,-O1");
         }
     }
@@ -201,53 +199,6 @@ fn hint_dynamic(&mut self) {
     fn export_symbols(&mut self, _: &Session, _: &CrateTranslation, _: &Path) {
         // noop, visibility in object files takes care of this
     }
-
-    fn try_gold_linker(&mut self) {
-        // Only use gold under specific conditions that we know work
-
-        let gold_exists = match env::var_os("PATH") {
-            Some(ref env_path) => {
-                env::split_paths(env_path).any(|mut p| {
-                    p.push("ld.gold");
-                    p.exists()
-                })
-            }
-            None => false
-        };
-        let host_is_linux = cfg!(target_os = "linux");
-        // Defensively prevent trying to use gold for bogus cross-targets.
-        let target_is_host_compatible = {
-            let host_os_is_target_os = self.sess.target.target.target_os == env::consts::OS;
-            let host_arch_is_target_arch = self.sess.target.target.arch == env::consts::ARCH;
-            // Support x86_64->i686 and reverse
-            let host_and_target_are_x86ish =
-                (self.sess.target.target.arch == "x86" ||
-                 self.sess.target.target.arch == "x86_64") &&
-                (env::consts::ARCH == "x86" ||
-                 env::consts::ARCH == "x86_64");
-            host_os_is_target_os && (host_arch_is_target_arch || host_and_target_are_x86ish)
-        };
-        // We have strong confidence that x86 works, but not much
-        // visibility into other architectures.
-        let target_works_with_gold =
-            self.sess.target.target.arch == "x86" ||
-            self.sess.target.target.arch == "x86_64";
-        let opt_out = self.sess.opts.cg.disable_gold;
-
-        let can_use_gold =
-            gold_exists &&
-            host_is_linux &&
-            target_is_host_compatible &&
-            target_works_with_gold &&
-            !opt_out;
-
-        if can_use_gold {
-            info!("linking with ld.gold");
-            self.cmd.arg("-fuse-ld=gold");
-        } else {
-            info!("linking with ld");
-        }
-    }
 }
 
 pub struct MsvcLinker<'a> {
@@ -407,6 +358,4 @@ fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation,
         arg.push(path);
         self.cmd.arg(&arg);
     }
-
-    fn try_gold_linker(&mut self) {}
 }
index 9d0a83fe3635046e7828db0f438209356d3c74b3..544df1798eaf93e48dc1a288c75ce74b087661a4 100644 (file)
@@ -144,10 +144,10 @@ fn target_feature(sess: &Session) -> String {
 
 fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel {
     match optimize {
-      config::No => llvm::CodeGenLevelNone,
-      config::Less => llvm::CodeGenLevelLess,
-      config::Default => llvm::CodeGenLevelDefault,
-      config::Aggressive => llvm::CodeGenLevelAggressive,
+      config::OptLevel::No => llvm::CodeGenLevelNone,
+      config::OptLevel::Less => llvm::CodeGenLevelLess,
+      config::OptLevel::Default => llvm::CodeGenLevelDefault,
+      config::OptLevel::Aggressive => llvm::CodeGenLevelAggressive,
     }
 }
 
@@ -303,13 +303,13 @@ fn set_flags(&mut self, sess: &Session, trans: &CrateTranslation) {
         // slp vectorization at O3. Otherwise configure other optimization aspects
         // of this pass manager builder.
         self.vectorize_loop = !sess.opts.cg.no_vectorize_loops &&
-                             (sess.opts.optimize == config::Default ||
-                              sess.opts.optimize == config::Aggressive);
+                             (sess.opts.optimize == config::OptLevel::Default ||
+                              sess.opts.optimize == config::OptLevel::Aggressive);
         self.vectorize_slp = !sess.opts.cg.no_vectorize_slp &&
-                            sess.opts.optimize == config::Aggressive;
+                            sess.opts.optimize == config::OptLevel::Aggressive;
 
-        self.merge_functions = sess.opts.optimize == config::Default ||
-                               sess.opts.optimize == config::Aggressive;
+        self.merge_functions = sess.opts.optimize == config::OptLevel::Default ||
+                               sess.opts.optimize == config::OptLevel::Aggressive;
     }
 }
 
index 0ad780fb0e4d33add43667cb0648c4b333736e4e..f46a7ea67b5f23aa7aadb72d978806d1163a9ce3 100644 (file)
@@ -1760,6 +1760,9 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
     let lvalue = Lvalue::new_with_hint(caller_name, bcx, p_id, HintKind::DontZeroJustUse);
     let datum = Datum::new(llval, var_ty, lvalue);
 
+    debug!("mk_binding_alloca cleanup_scope={:?} llval={} var_ty={:?}",
+           cleanup_scope, bcx.ccx().tn().val_to_string(llval), var_ty);
+
     // Subtle: be sure that we *populate* the memory *before*
     // we schedule the cleanup.
     call_lifetime_start(bcx, llval);
index c744ef321278d0b6d6b6eb10ce7308a74b124708..d22d619b9622754002c18d29f3b14a9c8eb92bee 100644 (file)
@@ -55,6 +55,7 @@
 use syntax::attr;
 use syntax::attr::IntType;
 use trans::_match;
+use trans::base::InitAlloca;
 use trans::build::*;
 use trans::cleanup;
 use trans::cleanup::CleanupMethods;
@@ -1279,7 +1280,12 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
             let scratch = unpack_datum!(bcx, datum::lvalue_scratch_datum(
                 bcx, tcx.dtor_type(), "drop_flag",
-                cleanup::CustomScope(custom_cleanup_scope), (), |_, bcx, _| bcx
+                InitAlloca::Uninit("drop flag itself has no dtor"),
+                cleanup::CustomScope(custom_cleanup_scope), (), |_, bcx, _| {
+                    debug!("no-op populate call for trans_drop_flag_ptr on dtor_type={:?}",
+                           tcx.dtor_type());
+                    bcx
+                }
             ));
             bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {
                 let ptr = struct_field_ptr(variant_cx, st, MaybeSizedValue::sized(value),
index d694374acc927898e8effc4e517ccfb7678f34cc..ea4259f8262a7b484c38314b0b12e0b5aa2a9934 100644 (file)
@@ -1147,48 +1147,63 @@ pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) ->
     next_cx
 }
 
-pub fn call_lifetime_start(cx: Block, ptr: ValueRef) {
-    if cx.sess().opts.optimize == config::No {
+enum Lifetime { Start, End }
+
+// If LLVM lifetime intrinsic support is enabled (i.e. optimizations
+// on), and `ptr` is nonzero-sized, then extracts the size of `ptr`
+// and the intrinsic for `lt` and passes them to `emit`, which is in
+// charge of generating code to call the passed intrinsic on whatever
+// block of generated code is targetted for the intrinsic.
+//
+// If LLVM lifetime intrinsic support is disabled (i.e.  optimizations
+// off) or `ptr` is zero-sized, then no-op (does not call `emit`).
+fn core_lifetime_emit<'blk, 'tcx, F>(ccx: &'blk CrateContext<'blk, 'tcx>,
+                                     ptr: ValueRef,
+                                     lt: Lifetime,
+                                     emit: F)
+    where F: FnOnce(&'blk CrateContext<'blk, 'tcx>, machine::llsize, ValueRef)
+{
+    if ccx.sess().opts.optimize == config::OptLevel::No {
         return;
     }
 
-    let _icx = push_ctxt("lifetime_start");
-    let ccx = cx.ccx();
+    let _icx = push_ctxt(match lt {
+        Lifetime::Start => "lifetime_start",
+        Lifetime::End => "lifetime_end"
+    });
 
     let size = machine::llsize_of_alloc(ccx, val_ty(ptr).element_type());
     if size == 0 {
         return;
     }
 
-    let ptr = PointerCast(cx, ptr, Type::i8p(ccx));
-    let lifetime_start = ccx.get_intrinsic(&"llvm.lifetime.start");
-    Call(cx,
-         lifetime_start,
-         &[C_u64(ccx, size), ptr],
-         None,
-         DebugLoc::None);
+    let lifetime_intrinsic = ccx.get_intrinsic(match lt {
+        Lifetime::Start => "llvm.lifetime.start",
+        Lifetime::End => "llvm.lifetime.end"
+    });
+    emit(ccx, size, lifetime_intrinsic)
 }
 
-pub fn call_lifetime_end(cx: Block, ptr: ValueRef) {
-    if cx.sess().opts.optimize == config::No {
-        return;
-    }
-
-    let _icx = push_ctxt("lifetime_end");
-    let ccx = cx.ccx();
-
-    let size = machine::llsize_of_alloc(ccx, val_ty(ptr).element_type());
-    if size == 0 {
-        return;
-    }
+pub fn call_lifetime_start(cx: Block, ptr: ValueRef) {
+    core_lifetime_emit(cx.ccx(), ptr, Lifetime::Start, |ccx, size, lifetime_start| {
+        let ptr = PointerCast(cx, ptr, Type::i8p(ccx));
+        Call(cx,
+             lifetime_start,
+             &[C_u64(ccx, size), ptr],
+             None,
+             DebugLoc::None);
+    })
+}
 
-    let ptr = PointerCast(cx, ptr, Type::i8p(ccx));
-    let lifetime_end = ccx.get_intrinsic(&"llvm.lifetime.end");
-    Call(cx,
-         lifetime_end,
-         &[C_u64(ccx, size), ptr],
-         None,
-         DebugLoc::None);
+pub fn call_lifetime_end(cx: Block, ptr: ValueRef) {
+    core_lifetime_emit(cx.ccx(), ptr, Lifetime::End, |ccx, size, lifetime_end| {
+        let ptr = PointerCast(cx, ptr, Type::i8p(ccx));
+        Call(cx,
+             lifetime_end,
+             &[C_u64(ccx, size), ptr],
+             None,
+             DebugLoc::None);
+    })
 }
 
 // Generates code for resumption of unwind at the end of a landing pad.
@@ -1285,12 +1300,81 @@ fn memfill<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>, byte:
            None);
 }
 
-pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, name: &str) -> ValueRef {
+/// In general, when we create an scratch value in an alloca, the
+/// creator may not know if the block (that initializes the scratch
+/// with the desired value) actually dominates the cleanup associated
+/// with the scratch value.
+///
+/// To deal with this, when we do an alloca (at the *start* of whole
+/// function body), we optionally can also set the associated
+/// dropped-flag state of the alloca to "dropped."
+#[derive(Copy, Clone, Debug)]
+pub enum InitAlloca {
+    /// Indicates that the state should have its associated drop flag
+    /// set to "dropped" at the point of allocation.
+    Dropped,
+    /// Indicates the value of the associated drop flag is irrelevant.
+    /// The embedded string literal is a programmer provided argument
+    /// for why. This is a safeguard forcing compiler devs to
+    /// document; it might be a good idea to also emit this as a
+    /// comment with the alloca itself when emitting LLVM output.ll.
+    Uninit(&'static str),
+}
+
+
+pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                            t: Ty<'tcx>,
+                            name: &str) -> ValueRef {
+    // pnkfelix: I do not know why alloc_ty meets the assumptions for
+    // passing Uninit, but it was never needed (even back when we had
+    // the original boolean `zero` flag on `lvalue_scratch_datum`).
+    alloc_ty_init(bcx, t, InitAlloca::Uninit("all alloc_ty are uninit"), name)
+}
+
+/// This variant of `fn alloc_ty` does not necessarily assume that the
+/// alloca should be created with no initial value. Instead the caller
+/// controls that assumption via the `init` flag.
+///
+/// Note that if the alloca *is* initialized via `init`, then we will
+/// also inject an `llvm.lifetime.start` before that initialization
+/// occurs, and thus callers should not call_lifetime_start
+/// themselves.  But if `init` says "uninitialized", then callers are
+/// in charge of choosing where to call_lifetime_start and
+/// subsequently populate the alloca.
+///
+/// (See related discussion on PR #30823.)
+pub fn alloc_ty_init<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                             t: Ty<'tcx>,
+                             init: InitAlloca,
+                             name: &str) -> ValueRef {
     let _icx = push_ctxt("alloc_ty");
     let ccx = bcx.ccx();
     let ty = type_of::type_of(ccx, t);
     assert!(!t.has_param_types());
-    alloca(bcx, ty, name)
+    match init {
+        InitAlloca::Dropped => alloca_dropped(bcx, t, name),
+        InitAlloca::Uninit(_) => alloca(bcx, ty, name),
+    }
+}
+
+pub fn alloca_dropped<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ty: Ty<'tcx>, name: &str) -> ValueRef {
+    let _icx = push_ctxt("alloca_dropped");
+    let llty = type_of::type_of(cx.ccx(), ty);
+    if cx.unreachable.get() {
+        unsafe { return llvm::LLVMGetUndef(llty.ptr_to().to_ref()); }
+    }
+    let p = alloca(cx, llty, name);
+    let b = cx.fcx.ccx.builder();
+    b.position_before(cx.fcx.alloca_insert_pt.get().unwrap());
+
+    // This is just like `call_lifetime_start` (but latter expects a
+    // Block, which we do not have for `alloca_insert_pt`).
+    core_lifetime_emit(cx.ccx(), p, Lifetime::Start, |ccx, size, lifetime_start| {
+        let ptr = b.pointercast(p, Type::i8p(ccx));
+        b.call(lifetime_start, &[C_u64(ccx, size), ptr], None);
+    });
+    memfill(&b, p, ty, adt::DTOR_DONE);
+    p
 }
 
 pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef {
@@ -1565,6 +1649,7 @@ pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>,
     // Create the drop-flag hints for every unfragmented path in the function.
     let tcx = fcx.ccx.tcx();
     let fn_did = tcx.map.local_def_id(fcx.id);
+    let tables = tcx.tables.borrow();
     let mut hints = fcx.lldropflag_hints.borrow_mut();
     let fragment_infos = tcx.fragment_infos.borrow();
 
@@ -1588,12 +1673,22 @@ pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>,
             let (var, datum) = match info {
                 ty::FragmentInfo::Moved { var, .. } |
                 ty::FragmentInfo::Assigned { var, .. } => {
-                    let datum = seen.get(&var).cloned().unwrap_or_else(|| {
-                        let datum = make_datum(var);
-                        seen.insert(var, datum.clone());
-                        datum
+                    let opt_datum = seen.get(&var).cloned().unwrap_or_else(|| {
+                        let ty = tables.node_types[&var];
+                        if fcx.type_needs_drop(ty) {
+                            let datum = make_datum(var);
+                            seen.insert(var, Some(datum.clone()));
+                            Some(datum)
+                        } else {
+                            // No drop call needed, so we don't need a dropflag hint
+                            None
+                        }
                     });
-                    (var, datum)
+                    if let Some(datum) = opt_datum {
+                        (var, datum)
+                    } else {
+                        continue
+                    }
                 }
             };
             match info {
@@ -1639,6 +1734,8 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
     let fcx = bcx.fcx;
     let arg_scope_id = cleanup::CustomScope(arg_scope);
 
+    debug!("create_datums_for_fn_args");
+
     // Return an array wrapping the ValueRefs that we get from `get_param` for
     // each argument into datums.
     //
@@ -1650,6 +1747,7 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
     // This alloca should be optimized away by LLVM's mem-to-reg pass in
     // the event it's not truly needed.
     let mut idx = fcx.arg_offset() as c_uint;
+    let uninit_reason = InitAlloca::Uninit("fn_arg populate dominates dtor");
     for (i, &arg_ty) in arg_tys.iter().enumerate() {
         let arg_datum = if !has_tupled_arg || i < arg_tys.len() - 1 {
             if type_of::arg_is_indirect(bcx.ccx(), arg_ty) &&
@@ -1669,9 +1767,12 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
                 let data = get_param(fcx.llfn, idx);
                 let extra = get_param(fcx.llfn, idx + 1);
                 idx += 2;
-                unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "",
+                unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "", uninit_reason,
                                                         arg_scope_id, (data, extra),
                                                         |(data, extra), bcx, dst| {
+                    debug!("populate call for create_datum_for_fn_args \
+                            early fat arg, on arg[{}] ty={:?}", i, arg_ty);
+
                     Store(bcx, data, expr::get_dataptr(bcx, dst));
                     Store(bcx, extra, expr::get_meta(bcx, dst));
                     bcx
@@ -1684,9 +1785,16 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
                               datum::lvalue_scratch_datum(bcx,
                                                           arg_ty,
                                                           "",
+                                                          uninit_reason,
                                                           arg_scope_id,
                                                           tmp,
-                                                          |tmp, bcx, dst| tmp.store_to(bcx, dst)))
+                                                          |tmp, bcx, dst| {
+
+                        debug!("populate call for create_datum_for_fn_args \
+                                early thin arg, on arg[{}] ty={:?}", i, arg_ty);
+
+                                                              tmp.store_to(bcx, dst)
+                                                          }))
             }
         } else {
             // FIXME(pcwalton): Reduce the amount of code bloat this is responsible for.
@@ -1696,11 +1804,14 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
                                   datum::lvalue_scratch_datum(bcx,
                                                               arg_ty,
                                                               "tupled_args",
+                                                              uninit_reason,
                                                               arg_scope_id,
                                                               (),
                                                               |(),
                                                                mut bcx,
-                                                               llval| {
+                                                              llval| {
+                        debug!("populate call for create_datum_for_fn_args \
+                                tupled_args, on arg[{}] ty={:?}", i, arg_ty);
                         for (j, &tupled_arg_ty) in
                                     tupled_arg_tys.iter().enumerate() {
                             let lldest = StructGEP(bcx, llval, j);
index 0ff5264c00f0f8346ebd9d3180affdf7787c9216..4bfbb8b69f0acee7fd17163e36b9c3c7baddd6ad 100644 (file)
@@ -19,6 +19,7 @@
 use trans::cabi_arm;
 use trans::cabi_aarch64;
 use trans::cabi_powerpc;
+use trans::cabi_powerpc64;
 use trans::cabi_mips;
 use trans::type_::Type;
 
@@ -127,6 +128,7 @@ pub fn compute_abi_info(ccx: &CrateContext,
         },
         "mips" => cabi_mips::compute_abi_info(ccx, atys, rty, ret_def),
         "powerpc" => cabi_powerpc::compute_abi_info(ccx, atys, rty, ret_def),
+        "powerpc64" | "powerpc64le" => cabi_powerpc64::compute_abi_info(ccx, atys, rty, ret_def),
         a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)
                               ),
     }
diff --git a/src/librustc_trans/trans/cabi_powerpc64.rs b/src/librustc_trans/trans/cabi_powerpc64.rs
new file mode 100644 (file)
index 0000000..cba7300
--- /dev/null
@@ -0,0 +1,259 @@
+// Copyright 2014-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.
+
+// FIXME: The PowerPC64 ABI needs to zero or sign extend function
+// call parameters, but compute_abi_info() is passed LLVM types
+// which have no sign information.
+//
+// Alignment of 128 bit types is not currently handled, this will
+// need to be fixed when PowerPC vector support is added.
+
+use llvm::{Integer, Pointer, Float, Double, Struct, Array, Attribute};
+use trans::cabi::{FnType, ArgType};
+use trans::context::CrateContext;
+use trans::type_::Type;
+
+use std::cmp;
+
+fn align_up_to(off: usize, a: usize) -> usize {
+    return (off + a - 1) / a * a;
+}
+
+fn align(off: usize, ty: Type) -> usize {
+    let a = ty_align(ty);
+    return align_up_to(off, a);
+}
+
+fn ty_align(ty: Type) -> usize {
+    match ty.kind() {
+        Integer => ((ty.int_width() as usize) + 7) / 8,
+        Pointer => 8,
+        Float => 4,
+        Double => 8,
+        Struct => {
+            if ty.is_packed() {
+                1
+            } else {
+                let str_tys = ty.field_types();
+                str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
+            }
+        }
+        Array => {
+            let elt = ty.element_type();
+            ty_align(elt)
+        }
+        _ => panic!("ty_align: unhandled type")
+    }
+}
+
+fn ty_size(ty: Type) -> usize {
+    match ty.kind() {
+        Integer => ((ty.int_width() as usize) + 7) / 8,
+        Pointer => 8,
+        Float => 4,
+        Double => 8,
+        Struct => {
+            if ty.is_packed() {
+                let str_tys = ty.field_types();
+                str_tys.iter().fold(0, |s, t| s + ty_size(*t))
+            } else {
+                let str_tys = ty.field_types();
+                let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
+                align(size, ty)
+            }
+        }
+        Array => {
+            let len = ty.array_length();
+            let elt = ty.element_type();
+            let eltsz = ty_size(elt);
+            len * eltsz
+        }
+        _ => panic!("ty_size: unhandled type")
+    }
+}
+
+fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
+    fn check_array(ty: Type) -> Option<(Type, u64)> {
+        let len = ty.array_length() as u64;
+        if len == 0 {
+            return None
+        }
+        let elt = ty.element_type();
+
+        // if our element is an HFA/HVA, so are we; multiply members by our len
+        is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members))
+    }
+
+    fn check_struct(ty: Type) -> Option<(Type, u64)> {
+        let str_tys = ty.field_types();
+        if str_tys.len() == 0 {
+            return None
+        }
+
+        let mut prev_base_ty = None;
+        let mut members = 0;
+        for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) {
+            match (prev_base_ty, opt_homog_agg) {
+                // field isn't itself an HFA, so we aren't either
+                (_, None) => return None,
+
+                // first field - store its type and number of members
+                (None, Some((field_ty, field_members))) => {
+                    prev_base_ty = Some(field_ty);
+                    members = field_members;
+                },
+
+                // 2nd or later field - give up if it's a different type; otherwise incr. members
+                (Some(prev_ty), Some((field_ty, field_members))) => {
+                    if prev_ty != field_ty {
+                        return None;
+                    }
+                    members += field_members;
+                }
+            }
+        }
+
+        // Because of previous checks, we know prev_base_ty is Some(...) because
+        //   1. str_tys has at least one element; and
+        //   2. prev_base_ty was filled in (or we would've returned early)
+        let (base_ty, members) = (prev_base_ty.unwrap(), members);
+
+        // Ensure there is no padding.
+        if ty_size(ty) == ty_size(base_ty) * (members as usize) {
+            Some((base_ty, members))
+        } else {
+            None
+        }
+    }
+
+    let homog_agg = match ty.kind() {
+        Float  => Some((ty, 1)),
+        Double => Some((ty, 1)),
+        Array  => check_array(ty),
+        Struct => check_struct(ty),
+        _ => None
+    };
+
+    // Ensure we have at most eight uniquely addressable members
+    homog_agg.and_then(|(base_ty, members)| {
+        if members > 0 && members <= 8 {
+            Some((base_ty, members))
+        } else {
+            None
+        }
+    })
+}
+
+fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
+    if is_reg_ty(ty) {
+        let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExt) } else { None };
+        return ArgType::direct(ty, None, None, attr);
+    }
+
+    // The PowerPC64 big endian ABI doesn't return aggregates in registers
+    if ccx.sess().target.target.arch == "powerpc64" {
+        return ArgType::indirect(ty, Some(Attribute::StructRet))
+    }
+
+    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) {
+        let llty = Type::array(&base_ty, members);
+        return ArgType::direct(ty, Some(llty), None, None);
+    }
+    let size = ty_size(ty);
+    if size <= 16 {
+        let llty = if size <= 1 {
+            Type::i8(ccx)
+        } else if size <= 2 {
+            Type::i16(ccx)
+        } else if size <= 4 {
+            Type::i32(ccx)
+        } else if size <= 8 {
+            Type::i64(ccx)
+        } else {
+            Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
+        };
+        return ArgType::direct(ty, Some(llty), None, None);
+    }
+
+    ArgType::indirect(ty, Some(Attribute::StructRet))
+}
+
+fn classify_arg_ty(ccx: &CrateContext, ty: Type) -> ArgType {
+    if is_reg_ty(ty) {
+        let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExt) } else { None };
+        return ArgType::direct(ty, None, None, attr);
+    }
+    if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) {
+        let llty = Type::array(&base_ty, members);
+        return ArgType::direct(ty, Some(llty), None, None);
+    }
+
+    ArgType::direct(
+        ty,
+        Some(struct_ty(ccx, ty)),
+        None,
+        None
+    )
+}
+
+fn is_reg_ty(ty: Type) -> bool {
+    match ty.kind() {
+        Integer
+        | Pointer
+        | Float
+        | Double => true,
+        _ => false
+    }
+}
+
+fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec<Type> {
+    let long_ty = Type::i64(ccx);
+    let mut args = Vec::new();
+
+    let mut n = size / 64;
+    while n > 0 {
+        args.push(long_ty);
+        n -= 1;
+    }
+
+    let r = size % 64;
+    if r > 0 {
+        args.push(Type::ix(ccx, r as u64));
+    }
+
+    args
+}
+
+fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
+    let size = ty_size(ty) * 8;
+    Type::struct_(ccx, &coerce_to_long(ccx, size), false)
+}
+
+pub fn compute_abi_info(ccx: &CrateContext,
+                        atys: &[Type],
+                        rty: Type,
+                        ret_def: bool) -> FnType {
+    let ret_ty = if ret_def {
+        classify_ret_ty(ccx, rty)
+    } else {
+        ArgType::direct(Type::void(ccx), None, None, None)
+    };
+
+    let mut arg_tys = Vec::new();
+    for &aty in atys {
+        let ty = classify_arg_ty(ccx, aty);
+        arg_tys.push(ty);
+    };
+
+    return FnType {
+        arg_tys: arg_tys,
+        ret_ty: ret_ty,
+    };
+}
index 418ff4c8337e7f27dd48da0a72d0ef98c34400fd..32f263746d31e04158742f0abcf12395ad1d44c4 100644 (file)
@@ -288,20 +288,31 @@ pub fn immediate_rvalue_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     return DatumBlock::new(bcx, immediate_rvalue(val, ty))
 }
 
-
 /// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to
 /// it. The memory will be dropped upon exit from `scope`. The callback `populate` should
 /// initialize the memory.
+///
+/// The flag `zero` indicates how the temporary space itself should be
+/// initialized at the outset of the function; the only time that
+/// `InitAlloca::Uninit` is a valid value for `zero` is when the
+/// caller can prove that either (1.) the code injected by `populate`
+/// onto `bcx` always dominates the end of `scope`, or (2.) the data
+/// being allocated has no associated destructor.
 pub fn lvalue_scratch_datum<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
                                               ty: Ty<'tcx>,
                                               name: &str,
+                                              zero: InitAlloca,
                                               scope: cleanup::ScopeId,
                                               arg: A,
                                               populate: F)
                                               -> DatumBlock<'blk, 'tcx, Lvalue> where
     F: FnOnce(A, Block<'blk, 'tcx>, ValueRef) -> Block<'blk, 'tcx>,
 {
-    let scratch = alloc_ty(bcx, ty, name);
+    // Very subtle: potentially initialize the scratch memory at point where it is alloca'ed.
+    // (See discussion at Issue 30530.)
+    let scratch = alloc_ty_init(bcx, ty, zero, name);
+    debug!("lvalue_scratch_datum scope={:?} scratch={} ty={:?}",
+           scope, bcx.ccx().tn().val_to_string(scratch), ty);
 
     // Subtle. Populate the scratch memory *before* scheduling cleanup.
     let bcx = populate(arg, bcx, scratch);
@@ -340,6 +351,8 @@ fn add_rvalue_clean<'a, 'tcx>(mode: RvalueMode,
                               scope: cleanup::ScopeId,
                               val: ValueRef,
                               ty: Ty<'tcx>) {
+    debug!("add_rvalue_clean scope={:?} val={} ty={:?}",
+           scope, fcx.ccx.tn().val_to_string(val), ty);
     match mode {
         ByValue => { fcx.schedule_drop_immediate(scope, val, ty); }
         ByRef => {
@@ -496,9 +509,13 @@ pub fn to_lvalue_datum_in_scope<'blk>(self,
 
             ByValue => {
                 lvalue_scratch_datum(
-                    bcx, self.ty, name, scope, self,
+                    bcx, self.ty, name, InitAlloca::Dropped, scope, self,
                     |this, bcx, llval| {
-                        call_lifetime_start(bcx, llval);
+                        debug!("populate call for Datum::to_lvalue_datum_in_scope \
+                                self.ty={:?}", this.ty);
+                        // do not call_lifetime_start here; the
+                        // `InitAlloc::Dropped` will start scratch
+                        // value's lifetime at open of function body.
                         let bcx = this.store_to(bcx, llval);
                         bcx.fcx.schedule_lifetime_end(scope, llval);
                         bcx
index 5284971f2c21929e52867780fce2004ef0afdd45..d90acd78147c974d7428e721449be9881a582a29 100644 (file)
@@ -1020,7 +1020,7 @@ pub fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor {
             compile_unit_name,
             work_dir.as_ptr(),
             producer.as_ptr(),
-            cx.sess().opts.optimize != config::No,
+            cx.sess().opts.optimize != config::OptLevel::No,
             flags.as_ptr() as *const _,
             0,
             split_name.as_ptr() as *const _)
index ee1d834fc8a89efb638a271e2475184e65e21388..5e11a50be22735f00e2195c43a4df658e10493e5 100644 (file)
@@ -383,7 +383,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             true,
             scope_line as c_uint,
             FlagPrototyped as c_uint,
-            cx.sess().opts.optimize != config::No,
+            cx.sess().opts.optimize != config::OptLevel::No,
             llfn,
             template_parameters,
             ptr::null_mut())
@@ -596,7 +596,7 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                     file_metadata,
                     loc.line as c_uint,
                     type_metadata,
-                    cx.sess().opts.optimize != config::No,
+                    cx.sess().opts.optimize != config::OptLevel::No,
                     0,
                     address_operations.as_ptr(),
                     address_operations.len() as c_uint,
index fb6f2190207ee3c8e33efe303b558371152800ba..57afd0b580f177d40906cf3022e3d2e62b955638 100644 (file)
@@ -1487,6 +1487,8 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         }
     };
 
+    debug!("trans_adt");
+
     // This scope holds intermediates that must be cleaned should
     // panic occur before the ADT as a whole is ready.
     let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
index aa0b3a25ebb0cabc8f3603255922c8c2bdd484f1..18a9aad0e915d1a885ea49c439ae64183f4b4e94 100644 (file)
@@ -100,7 +100,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                 let mut llargs = Vec::with_capacity(args.len() + 1);
 
                 // Prepare the return value destination
-                let (ret_dest_ty, must_copy_dest) = if let Some(ref d) = kind.destination() {
+                let (ret_dest_ty, must_copy_dest) = if let Some(d) = kind.destination() {
                     let dest = self.trans_lvalue(bcx, d);
                     let ret_ty = dest.ty.to_ty(bcx.tcx());
                     if type_of::return_uses_outptr(bcx.ccx(), ret_ty) {
index e461a1c05bcf39323b44687915094870bd57e8fa..84cc87e9b13850000069d9a0dd769a0579188a1e 100644 (file)
 use rustc::middle::const_eval::ConstVal;
 use rustc::mir::repr as mir;
 use trans::common::{self, Block, C_bool, C_bytes, C_floating_f64, C_integral, C_str_slice};
-use trans::consts::{self, TrueConst};
-use trans::{type_of, expr};
-
+use trans::consts;
+use trans::expr;
+use trans::type_of;
 
 use super::operand::{OperandRef, OperandValue};
 use super::MirContext;
 
+
 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     pub fn trans_constval(&mut self,
                           bcx: Block<'bcx, 'tcx>,
@@ -66,13 +67,7 @@ fn trans_constval_inner(&mut self,
             ConstVal::Uint(v) => C_integral(llty, v, false),
             ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
             ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
-            ConstVal::Struct(id) | ConstVal::Tuple(id) => {
-                let expr = bcx.tcx().map.expect_expr(id);
-                match consts::const_expr(ccx, expr, param_substs, None, TrueConst::Yes) {
-                    Ok((val, _)) => val,
-                    Err(e) => panic!("const eval failure: {}", e.description()),
-                }
-            },
+            ConstVal::Struct(id) | ConstVal::Tuple(id) |
             ConstVal::Array(id, _) | ConstVal::Repeat(id, _) => {
                 let expr = bcx.tcx().map.expect_expr(id);
                 expr::trans(bcx, expr).datum.val
index 6240473b78ec3ecd4875414961ebb4b2c36e6946..114e78b05bddd0b72d55611b49dbde390676694f 100644 (file)
@@ -169,6 +169,11 @@ pub fn store_operand(&mut self,
                          operand: OperandRef<'tcx>)
     {
         debug!("store_operand: operand={}", operand.repr(bcx));
+        // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
+        // value is through `undef`, and store itself is useless.
+        if common::type_is_zero_size(bcx.ccx(), operand.ty) {
+            return;
+        }
         match operand.val {
             OperandValue::Ref(r) => base::memcpy_ty(bcx, lldest, r, operand.ty),
             OperandValue::Immediate(s) => base::store_ty(bcx, s, lldest, operand.ty),
index b57d3b107fb45c058f5a8a83beb682185c956333..f0842554277cc7e50fcfcaa1bf824665bb25d325 100644 (file)
@@ -108,11 +108,15 @@ pub fn trans_rvalue(&mut self,
                     },
                     _ => {
                         for (i, operand) in operands.iter().enumerate() {
-                            // Note: perhaps this should be StructGep, but
-                            // note that in some cases the values here will
-                            // not be structs but arrays.
-                            let lldest_i = build::GEPi(bcx, dest.llval, &[0, i]);
-                            self.trans_operand_into(bcx, lldest_i, operand);
+                            let op = self.trans_operand(bcx, operand);
+                            // Do not generate stores and GEPis for zero-sized fields.
+                            if !common::type_is_zero_size(bcx.ccx(), op.ty) {
+                                // Note: perhaps this should be StructGep, but
+                                // note that in some cases the values here will
+                                // not be structs but arrays.
+                                let dest = build::GEPi(bcx, dest.llval, &[0, i]);
+                                self.store_operand(bcx, dest, op);
+                            }
                         }
                     }
                 }
index 1fbc0d5c0152930a29acf337990a4ddf7d51ecb3..f474e288efe86b8363269df53ad6a3bee601b5c0 100644 (file)
@@ -31,6 +31,7 @@
 mod cabi_arm;
 mod cabi_mips;
 mod cabi_powerpc;
+mod cabi_powerpc64;
 mod cabi_x86;
 mod cabi_x86_64;
 mod cabi_x86_win64;
index c7e1af5853d11a48ca3b34eef95bb3cb75d3b3a6..3a1568a70c9922d8d8804c8daa75b0c6b402a090 100644 (file)
@@ -111,8 +111,15 @@ pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     // Always create an alloca even if zero-sized, to preserve
     // the non-null invariant of the inner slice ptr
-    let llfixed = base::alloc_ty(bcx, fixed_ty, "");
-    call_lifetime_start(bcx, llfixed);
+    let llfixed;
+    // Issue 30018: ensure state is initialized as dropped if necessary.
+    if fcx.type_needs_drop(vt.unit_ty) {
+        llfixed = base::alloc_ty_init(bcx, fixed_ty, InitAlloca::Dropped, "");
+    } else {
+        let uninit = InitAlloca::Uninit("fcx says vt.unit_ty is non-drop");
+        llfixed = base::alloc_ty_init(bcx, fixed_ty, uninit, "");
+        call_lifetime_start(bcx, llfixed);
+    };
 
     if count > 0 {
         // Arrange for the backing array to be cleaned up.
@@ -212,8 +219,8 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                         bcx = expr::trans_into(bcx, &**element,
                                                SaveIn(lleltptr));
                         let scope = cleanup::CustomScope(temp_scope);
-                        fcx.schedule_lifetime_end(scope, lleltptr);
-                        fcx.schedule_drop_mem(scope, lleltptr, vt.unit_ty, None);
+                        // Issue #30822: mark memory as dropped after running destructor
+                        fcx.schedule_drop_and_fill_mem(scope, lleltptr, vt.unit_ty, None);
                     }
                     fcx.pop_custom_cleanup_scope(temp_scope);
                 }
index 926d7fd6e25eb10ccffb4ff385b755651dfc17da..93ceaf8b11f12e47e9cf41388e320437bed89941 100644 (file)
@@ -19,6 +19,7 @@
 use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
 use check::{check_expr_with_lvalue_pref};
 use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type};
+use lint;
 use require_same_types;
 use util::nodemap::FnvHashMap;
 use session::Session;
@@ -138,7 +139,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                 if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => {
             if let hir::PatEnum(ref path, ref subpats) = pat.node {
                 if !(subpats.is_some() && subpats.as_ref().unwrap().is_empty()) {
-                    bad_struct_kind_err(tcx.sess, pat.span, path, false);
+                    bad_struct_kind_err(tcx.sess, pat, path, false);
                     return;
                 }
             }
@@ -590,10 +591,21 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx hir::Pat,
 }
 
 // This function exists due to the warning "diagnostic code E0164 already used"
-fn bad_struct_kind_err(sess: &Session, span: Span, path: &hir::Path, is_warning: bool) {
+fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: bool) {
     let name = pprust::path_to_string(path);
-    span_err_or_warn!(is_warning, sess, span, E0164,
-        "`{}` does not name a tuple variant or a tuple struct", name);
+    let msg = format!("`{}` does not name a tuple variant or a tuple struct", name);
+    if lint {
+        let expanded_msg =
+            format!("{}; RFC 218 disallowed matching of unit variants or unit structs via {}(..)",
+                    msg,
+                    name);
+        sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
+                      pat.id,
+                      pat.span,
+                      expanded_msg);
+    } else {
+        span_err!(sess, pat.span, E0164, "{}", msg);
+    }
 }
 
 pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
@@ -657,11 +669,8 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                      opt_ty, def, pat.span, pat.id);
 
     let report_bad_struct_kind = |is_warning| {
-        bad_struct_kind_err(tcx.sess, pat.span, path, is_warning);
-        if is_warning {
-            return;
-        }
-
+        bad_struct_kind_err(tcx.sess, pat, path, is_warning);
+        if is_warning { return; }
         fcx.write_error(pat.id);
         if let Some(subpats) = subpats {
             for pat in subpats {
@@ -699,12 +708,6 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                 report_bad_struct_kind(is_special_case);
                 if !is_special_case {
                     return
-                } else {
-                    // Boo! Too painful to attach this to the actual warning,
-                    // it should go away at some point though.
-                    tcx.sess.span_note_without_error(pat.span,
-                        "this warning will become a HARD ERROR in a future release. \
-                        See RFC 218 for details.");
                 }
             }
             (variant.fields
@@ -718,7 +721,10 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
         ty::TyStruct(struct_def, expected_substs) => {
             let variant = struct_def.struct_variant();
             if is_tuple_struct_pat && variant.kind() != ty::VariantKind::Tuple {
-                report_bad_struct_kind(false);
+                // Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
+                // is allowed for backward compatibility.
+                let is_special_case = variant.kind() == ty::VariantKind::Unit;
+                report_bad_struct_kind(is_special_case);
                 return;
             }
             (variant.fields
index 85f0aa3bbd3c3c7fcad4020eadc89c38ed54aef6..8f64e85de4b0f4708d6b481d9b53c0b48139431f 100644 (file)
@@ -69,6 +69,7 @@
 use middle::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
 use middle::ty::adjustment::{AdjustUnsafeFnPointer};
 use middle::ty::{self, LvaluePreference, TypeAndMut, Ty};
+use middle::ty::fold::TypeFoldable;
 use middle::ty::error::TypeError;
 use middle::ty::relate::RelateResult;
 use util::common::indent;
@@ -110,10 +111,15 @@ fn coerce(&self,
                a,
                b);
 
+        let a = self.fcx.infcx().shallow_resolve(a);
+
+        // Just ignore error types.
+        if a.references_error() || b.references_error() {
+            return Ok(None);
+        }
+
         // Consider coercing the subtype to a DST
-        let unsize = self.unpack_actual_value(a, |a| {
-            self.coerce_unsized(a, b)
-        });
+        let unsize = self.coerce_unsized(a, b);
         if unsize.is_ok() {
             return unsize;
         }
@@ -124,39 +130,33 @@ fn coerce(&self,
         // See above for details.
         match b.sty {
             ty::TyRawPtr(mt_b) => {
-                return self.unpack_actual_value(a, |a| {
-                    self.coerce_unsafe_ptr(a, b, mt_b.mutbl)
-                });
+                return self.coerce_unsafe_ptr(a, b, mt_b.mutbl);
             }
 
             ty::TyRef(_, mt_b) => {
-                return self.unpack_actual_value(a, |a| {
-                    self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl)
-                });
+                return self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl);
             }
 
             _ => {}
         }
 
-        self.unpack_actual_value(a, |a| {
-            match a.sty {
-                ty::TyBareFn(Some(_), a_f) => {
-                    // Function items are coercible to any closure
-                    // type; function pointers are not (that would
-                    // require double indirection).
-                    self.coerce_from_fn_item(a, a_f, b)
-                }
-                ty::TyBareFn(None, a_f) => {
-                    // We permit coercion of fn pointers to drop the
-                    // unsafe qualifier.
-                    self.coerce_from_fn_pointer(a, a_f, b)
-                }
-                _ => {
-                    // Otherwise, just use subtyping rules.
-                    self.subtype(a, b)
-                }
+        match a.sty {
+            ty::TyBareFn(Some(_), a_f) => {
+                // Function items are coercible to any closure
+                // type; function pointers are not (that would
+                // require double indirection).
+                self.coerce_from_fn_item(a, a_f, b)
             }
-        })
+            ty::TyBareFn(None, a_f) => {
+                // We permit coercion of fn pointers to drop the
+                // unsafe qualifier.
+                self.coerce_from_fn_pointer(a, a_f, b)
+            }
+            _ => {
+                // Otherwise, just use subtyping rules.
+                self.subtype(a, b)
+            }
+        }
     }
 
     /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
index 3cf75483fea0f28bb17c466556fb79e2b9549dbb..e644178ddd62f26bec6680ae47689213f15f95a1 100644 (file)
@@ -1038,6 +1038,9 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                          t_cast: Ty<'tcx>,
                                          t_expr: Ty<'tcx>,
                                          id: ast::NodeId) {
+    if t_cast.references_error() || t_expr.references_error() {
+        return;
+    }
     let tstr = fcx.infcx().ty_to_string(t_cast);
     let mut err = fcx.type_error_struct(span, |actual| {
         format!("cast to unsized type: `{}` as `{}`", actual, tstr)
@@ -3511,9 +3514,10 @@ fn check_expr_struct<'a, 'tcx>(fcx: &FnCtxt<'a,'tcx>,
         let t_cast = structurally_resolved_type(fcx, expr.span, t_cast);
         check_expr_with_expectation(fcx, e, ExpectCastableToType(t_cast));
         let t_expr = fcx.expr_ty(e);
+        let t_cast = fcx.infcx().resolve_type_vars_if_possible(&t_cast);
 
         // Eagerly check for some obvious errors.
-        if t_expr.references_error() {
+        if t_expr.references_error() || t_cast.references_error() {
             fcx.write_error(id);
         } else if !fcx.type_is_known_to_be_sized(t_cast, expr.span) {
             report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_cast, t_expr, id);
index 2c8fedb46a7b7b52e770f9194875b1c8854a2be9..7465ff526b6de1398b569cbd55f74ef67e78e663 100644 (file)
@@ -149,11 +149,23 @@ fn check_implementation(&self, item: &Item) {
                    trait_ref,
                    item.name);
 
+            // Skip impls where one of the self type is an error type.
+            // This occurs with e.g. resolve failures (#30589).
+            if trait_ref.references_error() {
+                return;
+            }
+
             enforce_trait_manually_implementable(self.crate_context.tcx,
                                                  item.span,
                                                  trait_ref.def_id);
             self.add_trait_impl(trait_ref, impl_did);
         } else {
+            // Skip inherent impls where the self type is an error
+            // type. This occurs with e.g. resolve failures (#30589).
+            if self_type.ty.references_error() {
+                return;
+            }
+
             // Add the implementation to the mapping from implementation to base
             // type def ID, if there is a base type for this implementation and
             // the implementation does not have any associated traits.
index 66f8068eae6571658645754015d5f8fd70bd9ce0..46ecd3a80b5d12e8bc77f855773a888bc16caf36 100644 (file)
@@ -46,8 +46,8 @@
 /// This `struct` is created by the [`to_lowercase()`] method on [`char`]. See
 /// its documentation for more.
 ///
-/// [`to_lowercase()`]: primitive.char.html#method.escape_to_lowercase
-/// [`char`]: primitive.char.html
+/// [`to_lowercase()`]: ../primitive.char.html#method.to_lowercase
+/// [`char`]: ../primitive.char.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct ToLowercase(CaseMappingIter);
 
@@ -64,8 +64,8 @@ fn next(&mut self) -> Option<char> {
 /// This `struct` is created by the [`to_uppercase()`] method on [`char`]. See
 /// its documentation for more.
 ///
-/// [`to_uppercase()`]: primitive.char.html#method.escape_to_uppercase
-/// [`char`]: primitive.char.html
+/// [`to_uppercase()`]: ../primitive.char.html#method.to_uppercase
+/// [`char`]: ../primitive.char.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct ToUppercase(CaseMappingIter);
 
index cf75cf525771408a7d9d64e5fc74ae3feeab2674..a147bea791c47f4ff1f95f3399cca7046f2af2d4 100644 (file)
 /// that the unicode parts of `CharExt` and `UnicodeStrPrelude` traits are based on.
 pub const UNICODE_VERSION: (u64, u64, u64) = (8, 0, 0);
 
-fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
+fn bsearch_range_table(c: char, r: &'static [(char, char)]) -> bool {
     use core::cmp::Ordering::{Equal, Less, Greater};
-    r.binary_search_by(|&(lo,hi)| {
-        if lo <= c && c <= hi { Equal }
-        else if hi < c { Less }
-        else { Greater }
-    }).is_ok()
+    r.binary_search_by(|&(lo, hi)| {
+         if c < lo {
+             Greater
+         } else if hi < c {
+             Less
+         } else {
+             Equal
+         }
+     })
+     .is_ok()
 }
 
 pub mod general_category {
@@ -1188,34 +1193,25 @@ pub fn White_Space(c: char) -> bool {
 }
 
 pub mod conversions {
-    use core::cmp::Ordering::{Equal, Less, Greater};
     use core::option::Option;
     use core::option::Option::{Some, None};
-    use core::result::Result::{Ok, Err};
 
     pub fn to_lower(c: char) -> [char; 3] {
         match bsearch_case_table(c, to_lowercase_table) {
-          None        => [c, '\0', '\0'],
-          Some(index) => to_lowercase_table[index].1
+            None        => [c, '\0', '\0'],
+            Some(index) => to_lowercase_table[index].1,
         }
     }
 
     pub fn to_upper(c: char) -> [char; 3] {
         match bsearch_case_table(c, to_uppercase_table) {
             None        => [c, '\0', '\0'],
-            Some(index) => to_uppercase_table[index].1
+            Some(index) => to_uppercase_table[index].1,
         }
     }
 
     fn bsearch_case_table(c: char, table: &'static [(char, [char; 3])]) -> Option<usize> {
-        match table.binary_search_by(|&(key, _)| {
-            if c == key { Equal }
-            else if key < c { Less }
-            else { Greater }
-        }) {
-            Ok(i) => Some(i),
-            Err(_) => None,
-        }
+        table.binary_search_by(|&(key, _)| key.cmp(&c)).ok()
     }
 
     const to_lowercase_table: &'static [(char, [char; 3])] = &[
index c0f62cddb98bfe2e9c05c270cb1b30aa83649b1e..9bbbcc66ca6c04b0cb1125221d1fccf8c7d50801 100644 (file)
@@ -459,7 +459,7 @@ fn fill_in(cx: &DocContext, tcx: &ty::ctxt, did: DefId,
                     fill_in(cx, tcx, did, items);
                 }
                 cstore::DlDef(def) if item.vis == hir::Public => {
-                    if !visited.insert(def) { return }
+                    if !visited.insert(def) { continue }
                     match try_inline_def(cx, tcx, def) {
                         Some(i) => items.extend(i),
                         None => {}
index d57d1bcd92da505454cb45ad23818b0550cbb6ff..a7fd170b91c37778196b1a080c66acd5c605aeee 100644 (file)
@@ -118,11 +118,11 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
     };
 
     let codemap = Rc::new(codemap::CodeMap::new());
-    let diagnostic_handler = errors::Handler::new(ColorConfig::Auto,
-                                                  None,
-                                                  true,
-                                                  false,
-                                                  codemap.clone());
+    let diagnostic_handler = errors::Handler::with_tty_emitter(ColorConfig::Auto,
+                                                               None,
+                                                               true,
+                                                               false,
+                                                               codemap.clone());
 
     let cstore = Rc::new(CStore::new(token::get_ident_interner()));
     let sess = session::build_session_(sessopts, cpath, diagnostic_handler,
index b9ebe977b7bd753eccfcc0a3f6b08486baa15427..8bc1c184d20387daa6939e4534a086637a444deb 100644 (file)
@@ -1819,10 +1819,10 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Optio
         } else if stab.level == stability::Unstable {
             let unstable_extra = if show_reason {
                 match (!stab.feature.is_empty(), &cx.issue_tracker_base_url, stab.issue) {
-                    (true, &Some(ref tracker_url), Some(issue_no)) =>
+                    (true, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
                         format!(" (<code>{}</code> <a href=\"{}{}\">#{}</a>)",
                                 Escape(&stab.feature), tracker_url, issue_no, issue_no),
-                    (false, &Some(ref tracker_url), Some(issue_no)) =>
+                    (false, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
                         format!(" (<a href=\"{}{}\">#{}</a>)", Escape(&tracker_url), issue_no,
                                 issue_no),
                     (true, _, _) =>
index ffda261c24f3d819ed05f32fa8ba981be261a580..dce537fe9d292a0a5923dba022b0c0ac3c14bcab 100644 (file)
@@ -50,6 +50,7 @@
 
 use std::cell::RefCell;
 use std::collections::HashMap;
+use std::default::Default;
 use std::env;
 use std::fs::File;
 use std::io::{self, Read, Write};
@@ -62,7 +63,7 @@
 use serialize::Decodable;
 use serialize::json::{self, Json};
 use rustc::session::search_paths::SearchPaths;
-use syntax::errors::emitter::ColorConfig;
+use rustc::session::config::ErrorOutputType;
 
 // reexported from `clean` so it can be easily updated with the mod itself
 pub use clean::SCHEMA_VERSION;
@@ -225,7 +226,7 @@ pub fn main_args(args: &[String]) -> isize {
 
     let mut libs = SearchPaths::new();
     for s in &matches.opt_strs("L") {
-        libs.add_path(s, ColorConfig::Auto);
+        libs.add_path(s, ErrorOutputType::default());
     }
     let externs = match parse_externs(&matches) {
         Ok(ex) => ex,
@@ -360,7 +361,7 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche
     // First, parse the crate and extract all relevant information.
     let mut paths = SearchPaths::new();
     for s in &matches.opt_strs("L") {
-        paths.add_path(s, ColorConfig::Auto);
+        paths.add_path(s, ErrorOutputType::default());
     }
     let cfgs = matches.opt_strs("cfg");
     let triple = matches.opt_str("target");
index 7aa97d3652f5ab3d03db2fddae1dec8bdc09d9c7..d7d30f065bf0e9c857fe5aa83cfb4db23431a854 100644 (file)
@@ -73,11 +73,11 @@ pub fn run(input: &str,
     };
 
     let codemap = Rc::new(CodeMap::new());
-    let diagnostic_handler = errors::Handler::new(ColorConfig::Auto,
-                                                  None,
-                                                  true,
-                                                  false,
-                                                  codemap.clone());
+    let diagnostic_handler = errors::Handler::with_tty_emitter(ColorConfig::Auto,
+                                                               None,
+                                                               true,
+                                                               false,
+                                                               codemap.clone());
 
     let cstore = Rc::new(CStore::new(token::get_ident_interner()));
     let sess = session::build_session_(sessopts,
index 760733872ea190c8d2498e9f1f9f2641ac2ca6ac..6726f5222475550266d5930d4ac57f3875f6b449 100644 (file)
@@ -615,6 +615,8 @@ pub mod consts {
     /// - mips
     /// - mipsel
     /// - powerpc
+    /// - powerpc64
+    /// - powerpc64le
     #[stable(feature = "env", since = "1.0.0")]
     pub const ARCH: &'static str = super::arch::ARCH;
 
@@ -867,6 +869,16 @@ mod arch {
     pub const ARCH: &'static str = "powerpc";
 }
 
+#[cfg(target_arch = "powerpc64")]
+mod arch {
+    pub const ARCH: &'static str = "powerpc64";
+}
+
+#[cfg(target_arch = "powerpc64le")]
+mod arch {
+    pub const ARCH: &'static str = "powerpc64le";
+}
+
 #[cfg(target_arch = "le32")]
 mod arch {
     pub const ARCH: &'static str = "le32";
index 46d03169b2da36b4312705811a67a6f3ec644c76..c44a4bfe0f16157a6698ffbb5e8e14a89a49037a 100644 (file)
@@ -119,6 +119,15 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
+#[stable(feature = "string_box_error", since = "1.7.0")]
+impl From<String> for Box<Error> {
+    fn from(str_err: String) -> Box<Error> {
+        let err1: Box<Error + Send + Sync> = From::from(str_err);
+        let err2: Box<Error> = err1;
+        err2
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a> {
     fn from(err: &'b str) -> Box<Error + Send + Sync + 'a> {
@@ -126,6 +135,13 @@ fn from(err: &'b str) -> Box<Error + Send + Sync + 'a> {
     }
 }
 
+#[stable(feature = "string_box_error", since = "1.7.0")]
+impl<'a> From<&'a str> for Box<Error> {
+    fn from(err: &'a str) -> Box<Error> {
+        From::from(String::from(err))
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Error for str::ParseBoolError {
     fn description(&self) -> &str { "failed to parse bool" }
index 90b108e67707269638963d7ecc397245a7a15daa..eb5ddecbd054d090700585fc3c9ef971efeaf893 100644 (file)
@@ -8,27 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! A type that can represent all platform-native strings, but is cheaply
-//! interconvertable with Rust strings.
-//!
-//! The need for this type arises from the fact that:
-//!
-//! * On Unix systems, strings are often arbitrary sequences of non-zero
-//!   bytes, in many cases interpreted as UTF-8.
-//!
-//! * On Windows, strings are often arbitrary sequences of non-zero 16-bit
-//!   values, interpreted as UTF-16 when it is valid to do so.
-//!
-//! * In Rust, strings are always valid UTF-8, but may contain zeros.
-//!
-//! The types in this module bridge this gap by simultaneously representing Rust
-//! and platform-native string values, and in particular allowing a Rust string
-//! to be converted into an "OS" string with no cost.
-//!
-//! **Note**: At the moment, these types are extremely bare-bones, usable only
-//! for conversion to/from various other string types. Eventually these types
-//! will offer a full-fledged string API.
-
 use borrow::{Borrow, Cow, ToOwned};
 use ffi::CString;
 use fmt::{self, Debug};
 use sys::os_str::{Buf, Slice};
 use sys_common::{AsInner, IntoInner, FromInner};
 
-/// Owned, mutable OS strings.
+/// A type that can represent owned, mutable platform-native strings, but is
+/// cheaply interconvertable with Rust strings.
+///
+/// The need for this type arises from the fact that:
+///
+/// * On Unix systems, strings are often arbitrary sequences of non-zero
+///   bytes, in many cases interpreted as UTF-8.
+///
+/// * On Windows, strings are often arbitrary sequences of non-zero 16-bit
+///   values, interpreted as UTF-16 when it is valid to do so.
+///
+/// * In Rust, strings are always valid UTF-8, but may contain zeros.
+///
+/// `OsString` and `OsStr` bridge this gap by simultaneously representing Rust
+/// and platform-native string values, and in particular allowing a Rust string
+/// to be converted into an "OS" string with no cost.
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OsString {
     inner: Buf
 }
 
-/// Slices into OS strings.
+/// Slices into OS strings (see `OsString`).
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OsStr {
     inner: Slice
index 16ce05ef2dcaf72497b171796eda90357dc1b624..a9a79fe2c7733f3afc9332c2f99f8f62b4724791 100644 (file)
@@ -772,21 +772,6 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-struct InternalBufWriter<W: Write>(BufWriter<W>);
-
-impl<W: Read + Write> InternalBufWriter<W> {
-    fn get_mut(&mut self) -> &mut BufWriter<W> {
-        let InternalBufWriter(ref mut w) = *self;
-        return w;
-    }
-}
-
-impl<W: Read + Write> Read for InternalBufWriter<W> {
-    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        self.get_mut().inner.as_mut().unwrap().read(buf)
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use prelude::v1::*;
index b5ba6ff54c0e3b7d32b5fcb9ed1b450aae48562d..40533117f06c2353d3a6fe888677c9c32b6ddb96 100644 (file)
 //! ```
 //!
 //! `BufWriter` doesn't add any new ways of writing; it just buffers every call
-//! to [`write()`][write]:
+//! to [`write()`][write()]:
 //!
 //! ```
 //! use std::io;
 //! # }
 //! ```
 //!
-//! [write]: trait.Write.html#tymethod.write
+//! [write()]: trait.Write.html#tymethod.write
 //!
 //! ## Standard input and output
 //!
@@ -399,7 +399,7 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize>
 ///
 /// [`File`][file]s implement `Read`:
 ///
-/// [file]: ../std/fs/struct.File.html
+/// [file]: ../fs/struct.File.html
 ///
 /// ```
 /// use std::io;
@@ -459,7 +459,7 @@ pub trait Read {
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../std/fs/struct.File.html
+    /// [file]: ../fs/struct.File.html
     ///
     /// ```
     /// use std::io;
@@ -501,7 +501,7 @@ pub trait Read {
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../std/fs/struct.File.html
+    /// [file]: ../fs/struct.File.html
     ///
     /// ```
     /// use std::io;
@@ -540,7 +540,7 @@ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../std/fs/struct.File.html
+    /// [file]: ../fs/struct.File.html
     ///
     /// ```
     /// use std::io;
@@ -600,7 +600,7 @@ fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../std/fs/struct.File.html
+    /// [file]: ../fs/struct.File.html
     ///
     /// ```
     /// use std::io;
@@ -643,7 +643,7 @@ fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> {
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../std/fs/struct.File.html
+    /// [file]: ../fs/struct.File.html
     ///
     /// ```
     /// use std::io;
@@ -682,7 +682,7 @@ fn by_ref(&mut self) -> &mut Self where Self: Sized { self }
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../std/fs/struct.File.html
+    /// [file]: ../fs/struct.File.html
     ///
     /// ```
     /// use std::io;
@@ -718,7 +718,7 @@ fn bytes(self) -> Bytes<Self> where Self: Sized {
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../std/fs/struct.File.html
+    /// [file]: ../fs/struct.File.html
     ///
     /// ```
     /// #![feature(io)]
@@ -753,7 +753,7 @@ fn chars(self) -> Chars<Self> where Self: Sized {
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../std/fs/struct.File.html
+    /// [file]: ../fs/struct.File.html
     ///
     /// ```
     /// use std::io;
@@ -789,7 +789,7 @@ fn chain<R: Read>(self, next: R) -> Chain<Self, R> where Self: Sized {
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../std/fs/struct.File.html
+    /// [file]: ../fs/struct.File.html
     ///
     /// ```
     /// use std::io;
@@ -823,7 +823,7 @@ fn take(self, limit: u64) -> Take<Self> where Self: Sized {
     ///
     /// [`File`][file]s implement `Read`:
     ///
-    /// [file]: ../std/fs/struct.File.html
+    /// [file]: ../fs/struct.File.html
     ///
     /// ```
     /// #![feature(io)]
index 9c20a48d42518149261b1680d1bb06a414b59140..824acda522f3c7c6599588ede7d4c9cc3b8dcf8e 100644 (file)
 #![feature(slice_concat_ext)]
 #![feature(slice_patterns)]
 #![feature(staged_api)]
+#![feature(stmt_expr_attributes)]
 #![feature(str_char)]
 #![feature(str_internals)]
 #![feature(str_utf16)]
index ce8ce097f54cb6ba59143db93021db4d73d81ca0..7f57d6dc650bab145670458d28143328787cf85e 100644 (file)
@@ -62,7 +62,7 @@ mod cmath {
         pub fn hypotf(x: c_float, y: c_float) -> c_float;
     }
 
-    // See the comments in `core::float::Float::floor` for why MSVC is special
+    // See the comments in the `floor` function for why MSVC is special
     // here.
     #[cfg(not(target_env = "msvc"))]
     extern {
@@ -84,44 +84,54 @@ mod cmath {
     mod shims {
         use libc::{c_float, c_int};
 
+        #[inline]
         pub unsafe fn acosf(n: c_float) -> c_float {
             f64::acos(n as f64) as c_float
         }
 
+        #[inline]
         pub unsafe fn asinf(n: c_float) -> c_float {
             f64::asin(n as f64) as c_float
         }
 
+        #[inline]
         pub unsafe fn atan2f(n: c_float, b: c_float) -> c_float {
             f64::atan2(n as f64, b as f64) as c_float
         }
 
+        #[inline]
         pub unsafe fn atanf(n: c_float) -> c_float {
             f64::atan(n as f64) as c_float
         }
 
+        #[inline]
         pub unsafe fn coshf(n: c_float) -> c_float {
             f64::cosh(n as f64) as c_float
         }
 
+        #[inline]
         pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float {
             let (a, b) = f64::frexp(x as f64);
             *value = b as c_int;
             a as c_float
         }
 
+        #[inline]
         pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float {
             f64::ldexp(x as f64, n as isize) as c_float
         }
 
+        #[inline]
         pub unsafe fn sinhf(n: c_float) -> c_float {
             f64::sinh(n as f64) as c_float
         }
 
+        #[inline]
         pub unsafe fn tanf(n: c_float) -> c_float {
             f64::tan(n as f64) as c_float
         }
 
+        #[inline]
         pub unsafe fn tanhf(n: c_float) -> c_float {
             f64::tanh(n as f64) as c_float
         }
@@ -272,8 +282,6 @@ pub fn integer_decode(self) -> (u64, i16, i8) {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn floor(self) -> f32 {
-        return floorf(self);
-
         // On MSVC LLVM will lower many math intrinsics to a call to the
         // corresponding function. On MSVC, however, many of these functions
         // aren't actually available as symbols to call, but rather they are all
@@ -288,9 +296,9 @@ pub fn floor(self) -> f32 {
         // redirect to this comment, so `floorf` is just one case of a missing
         // function on MSVC, but there are many others elsewhere.
         #[cfg(target_env = "msvc")]
-        fn floorf(f: f32) -> f32 { (f as f64).floor() as f32 }
+        return (self as f64).floor() as f32;
         #[cfg(not(target_env = "msvc"))]
-        fn floorf(f: f32) -> f32 { unsafe { intrinsics::floorf32(f) } }
+        return unsafe { intrinsics::floorf32(self) };
     }
 
     /// Returns the smallest integer greater than or equal to a number.
@@ -305,13 +313,11 @@ fn floorf(f: f32) -> f32 { unsafe { intrinsics::floorf32(f) } }
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn ceil(self) -> f32 {
-        return ceilf(self);
-
         // see notes above in `floor`
         #[cfg(target_env = "msvc")]
-        fn ceilf(f: f32) -> f32 { (f as f64).ceil() as f32 }
+        return (self as f64).ceil() as f32;
         #[cfg(not(target_env = "msvc"))]
-        fn ceilf(f: f32) -> f32 { unsafe { intrinsics::ceilf32(f) } }
+        return unsafe { intrinsics::ceilf32(self) };
     }
 
     /// Returns the nearest integer to a number. Round half-way cases away from
@@ -506,13 +512,11 @@ pub fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) }
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn powf(self, n: f32) -> f32 {
-        return powf(self, n);
-
         // see notes above in `floor`
         #[cfg(target_env = "msvc")]
-        fn powf(f: f32, n: f32) -> f32 { (f as f64).powf(n as f64) as f32 }
+        return (self as f64).powf(n as f64) as f32;
         #[cfg(not(target_env = "msvc"))]
-        fn powf(f: f32, n: f32) -> f32 { unsafe { intrinsics::powf32(f, n) } }
+        return unsafe { intrinsics::powf32(self, n) };
     }
 
     /// Takes the square root of a number.
@@ -557,13 +561,11 @@ pub fn sqrt(self) -> f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn exp(self) -> f32 {
-        return expf(self);
-
         // see notes above in `floor`
         #[cfg(target_env = "msvc")]
-        fn expf(f: f32) -> f32 { (f as f64).exp() as f32 }
+        return (self as f64).exp() as f32;
         #[cfg(not(target_env = "msvc"))]
-        fn expf(f: f32) -> f32 { unsafe { intrinsics::expf32(f) } }
+        return unsafe { intrinsics::expf32(self) };
     }
 
     /// Returns `2^(self)`.
@@ -601,13 +603,11 @@ pub fn exp2(self) -> f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn ln(self) -> f32 {
-        return logf(self);
-
         // see notes above in `floor`
         #[cfg(target_env = "msvc")]
-        fn logf(f: f32) -> f32 { (f as f64).ln() as f32 }
+        return (self as f64).ln() as f32;
         #[cfg(not(target_env = "msvc"))]
-        fn logf(f: f32) -> f32 { unsafe { intrinsics::logf32(f) } }
+        return unsafe { intrinsics::logf32(self) };
     }
 
     /// Returns the logarithm of the number with respect to an arbitrary base.
@@ -664,13 +664,11 @@ pub fn log2(self) -> f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn log10(self) -> f32 {
-        return log10f(self);
-
         // see notes above in `floor`
         #[cfg(target_env = "msvc")]
-        fn log10f(f: f32) -> f32 { (f as f64).log10() as f32 }
+        return (self as f64).log10() as f32;
         #[cfg(not(target_env = "msvc"))]
-        fn log10f(f: f32) -> f32 { unsafe { intrinsics::log10f32(f) } }
+        return unsafe { intrinsics::log10f32(self) };
     }
 
     /// Converts radians to degrees.
@@ -884,13 +882,11 @@ pub fn hypot(self, other: f32) -> f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sin(self) -> f32 {
-        return sinf(self);
-
         // see notes in `core::f32::Float::floor`
         #[cfg(target_env = "msvc")]
-        fn sinf(f: f32) -> f32 { (f as f64).sin() as f32 }
+        return (self as f64).sin() as f32;
         #[cfg(not(target_env = "msvc"))]
-        fn sinf(f: f32) -> f32 { unsafe { intrinsics::sinf32(f) } }
+        return unsafe { intrinsics::sinf32(self) };
     }
 
     /// Computes the cosine of a number (in radians).
@@ -907,13 +903,11 @@ fn sinf(f: f32) -> f32 { unsafe { intrinsics::sinf32(f) } }
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn cos(self) -> f32 {
-        return cosf(self);
-
         // see notes in `core::f32::Float::floor`
         #[cfg(target_env = "msvc")]
-        fn cosf(f: f32) -> f32 { (f as f64).cos() as f32 }
+        return (self as f64).cos() as f32;
         #[cfg(not(target_env = "msvc"))]
-        fn cosf(f: f32) -> f32 { unsafe { intrinsics::cosf32(f) } }
+        return unsafe { intrinsics::cosf32(self) };
     }
 
     /// Computes the tangent of a number (in radians).
index f44199f311bfa7298a5e86eb57c8e12365270360..953d0917141d10337b9b262009577691d889d31f 100644 (file)
@@ -205,7 +205,8 @@ pub struct stat {
     }
 }
 
-#[cfg(target_arch = "x86_64")]
+#[cfg(any(target_arch = "x86_64", target_arch = "powerpc64",
+          target_arch = "powerpc64le"))]
 mod arch {
     use super::{dev_t, mode_t};
     use os::raw::{c_long, c_int};
index 3bc063f4269206eef6cf7e3a4217f5b6e46d9e3c..62080fee48ec1178e62e0acecd44199ca47918b3 100644 (file)
 
 #[cfg(any(target_os = "android",
           all(target_os = "linux", any(target_arch = "aarch64",
-                                       target_arch = "arm"))))]
+                                       target_arch = "arm",
+                                       target_arch = "powerpc",
+                                       target_arch = "powerpc64",
+                                       target_arch = "powerpc64le"))))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
 #[cfg(not(any(target_os = "android",
               all(target_os = "linux", any(target_arch = "aarch64",
-                                           target_arch = "arm")))))]
+                                           target_arch = "arm",
+                                           target_arch = "powerpc",
+                                           target_arch = "powerpc64",
+                                           target_arch = "powerpc64le")))))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8;
index 3f9a1c30ef4936c6d4767fcc27c1d767aa91af0d..8561ecd9c4cb92d9e21952fe65167c03b9ad9ab5 100644 (file)
@@ -206,7 +206,7 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
     // debugger provides a useable stacktrace.
     if panics >= 3 {
         util::dumb_print(format_args!("thread panicked while processing \
-                                       panic. aborting."));
+                                       panic. aborting.\n"));
         unsafe { intrinsics::abort() }
     }
 
@@ -232,7 +232,7 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
         // just abort. In the future we may consider resuming
         // unwinding or otherwise exiting the thread cleanly.
         util::dumb_print(format_args!("thread panicked while panicking. \
-                                       aborting."));
+                                       aborting.\n"));
         unsafe { intrinsics::abort() }
     }
 }
index 0ba0e01ce29102d03968deb06915a4ac07b2a5cb..619f100f1a137ad9092498d19a68306915742c04 100644 (file)
@@ -30,14 +30,19 @@ mod imp {
                   target_arch = "x86",
                   target_arch = "arm",
                   target_arch = "aarch64",
-                  target_arch = "powerpc")))]
+                  target_arch = "powerpc",
+                  target_arch = "powerpc64",
+                  target_arch = "powerpc64le")))]
     fn getrandom(buf: &mut [u8]) -> libc::c_long {
         #[cfg(target_arch = "x86_64")]
         const NR_GETRANDOM: libc::c_long = 318;
         #[cfg(target_arch = "x86")]
         const NR_GETRANDOM: libc::c_long = 355;
-        #[cfg(any(target_arch = "arm", target_arch = "powerpc"))]
+        #[cfg(target_arch = "arm")]
         const NR_GETRANDOM: libc::c_long = 384;
+        #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64",
+                  target_arch = "powerpc64le"))]
+        const NR_GETRANDOM: libc::c_long = 359;
         #[cfg(target_arch = "aarch64")]
         const NR_GETRANDOM: libc::c_long = 278;
 
@@ -51,7 +56,9 @@ fn getrandom(buf: &mut [u8]) -> libc::c_long {
                       target_arch = "x86",
                       target_arch = "arm",
                       target_arch = "aarch64",
-                      target_arch = "powerpc"))))]
+                      target_arch = "powerpc",
+                      target_arch = "powerpc64",
+                      target_arch = "powerpc64le"))))]
     fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }
 
     fn getrandom_fill_bytes(v: &mut [u8]) {
@@ -88,7 +95,9 @@ fn getrandom_next_u64() -> u64 {
                   target_arch = "x86",
                   target_arch = "arm",
                   target_arch = "aarch64",
-                  target_arch = "powerpc")))]
+                  target_arch = "powerpc",
+                  target_arch = "powerpc64",
+                  target_arch = "powerpc64le")))]
     fn is_getrandom_available() -> bool {
         use sync::atomic::{AtomicBool, Ordering};
         use sync::Once;
@@ -116,7 +125,9 @@ fn is_getrandom_available() -> bool {
                       target_arch = "x86",
                       target_arch = "arm",
                       target_arch = "aarch64",
-                      target_arch = "powerpc"))))]
+                      target_arch = "powerpc",
+                      target_arch = "powerpc64",
+                      target_arch = "powerpc64le"))))]
     fn is_getrandom_available() -> bool { false }
 
     /// A random number generator that retrieves randomness straight from
@@ -222,7 +233,7 @@ fn fill_bytes(&mut self, v: &mut [u8]) {
             // getentropy(2) permits a maximum buffer size of 256 bytes
             for s in v.chunks_mut(256) {
                 let ret = unsafe {
-                    libc::syscall(libc::NR_GETENTROPY, s.as_mut_ptr(), s.len())
+                    libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
                 };
                 if ret == -1 {
                     panic!("unexpected getentropy error: {}", errno());
index feb05c7b56008e7881947f4fc0889607bd3d0fe2..77d1eed96231df0626e517e679c4657e59ab03c6 100644 (file)
@@ -83,7 +83,8 @@ pub enum _Unwind_Reason_Code {
 #[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
 pub const unwinder_private_data_size: usize = 2;
 
-#[cfg(target_arch = "powerpc")]
+#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64",
+          target_arch = "powerpc64le"))]
 pub const unwinder_private_data_size: usize = 2;
 
 #[repr(C)]
index 979f1f486698358f25a6e902877e097c56f874f2..b7a6b7650d54079de57495659ba7684dc697264a 100644 (file)
@@ -35,12 +35,12 @@ pub fn dumb_print(args: fmt::Arguments) {
 }
 
 pub fn abort(args: fmt::Arguments) -> ! {
-    dumb_print(format_args!("fatal runtime error: {}", args));
+    dumb_print(format_args!("fatal runtime error: {}\n", args));
     unsafe { intrinsics::abort(); }
 }
 
 #[allow(dead_code)] // stack overflow detection not enabled on all platforms
 pub unsafe fn report_overflow() {
-    dumb_print(format_args!("\nthread '{}' has overflowed its stack",
+    dumb_print(format_args!("\nthread '{}' has overflowed its stack\n",
                             thread::current().name().unwrap_or("<unknown>")));
 }
index e8575a6c21cf13c0eb159766123a3c415df28c05..10fda3fcd7fa5165ce82e70ea0fab45d8517559e 100644 (file)
@@ -204,7 +204,8 @@ pub fn ino(&self) -> raw::ino_t {
 
     #[cfg(any(target_os = "macos",
               target_os = "ios",
-              target_os = "netbsd"))]
+              target_os = "netbsd",
+              target_os = "openbsd"))]
     fn name_bytes(&self) -> &[u8] {
         unsafe {
             ::slice::from_raw_parts(self.entry.d_name.as_ptr() as *const u8,
@@ -213,8 +214,7 @@ fn name_bytes(&self) -> &[u8] {
     }
     #[cfg(any(target_os = "freebsd",
               target_os = "dragonfly",
-              target_os = "bitrig",
-              target_os = "openbsd"))]
+              target_os = "bitrig"))]
     fn name_bytes(&self) -> &[u8] {
         unsafe {
             ::slice::from_raw_parts(self.entry.d_name.as_ptr() as *const u8,
index 929fd2fb0c38b8a0c3dc146d634c1fb63e5b396f..9771b057d8d21f5bfac77a38cbb71b5130e5c899 100644 (file)
@@ -15,6 +15,7 @@
 use libc;
 use num::One;
 use ops::Neg;
+use alloc::oom;
 
 #[cfg(target_os = "android")]   pub use os::android as platform;
 #[cfg(target_os = "bitrig")]    pub use os::bitrig as platform;
 pub mod time;
 pub mod stdio;
 
+// A nicer handler for out-of-memory situations than the default one. This one
+// prints a message to stderr before aborting. It is critical that this code
+// does not allocate any memory since we are in an OOM situation. Any errors are
+// ignored while printing since there's nothing we can do about them and we are
+// about to exit anyways.
+fn oom_handler() -> ! {
+    use intrinsics;
+    let msg = "fatal runtime error: out of memory\n";
+    unsafe {
+        libc::write(libc::STDERR_FILENO,
+                    msg.as_ptr() as *const libc::c_void,
+                    msg.len() as libc::size_t);
+        intrinsics::abort();
+    }
+}
+
 #[cfg(not(any(target_os = "nacl", test)))]
 pub fn init() {
     use libc::signal;
@@ -58,10 +75,14 @@ pub fn init() {
     unsafe {
         assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
     }
+
+    oom::set_oom_handler(oom_handler);
 }
 
 #[cfg(all(target_os = "nacl", not(test)))]
-pub fn init() { }
+pub fn init() {
+    oom::set_oom_handler(oom_handler);
+}
 
 pub fn decode_error_kind(errno: i32) -> ErrorKind {
     match errno as libc::c_int {
index 495f45f5c7e224346f26e0ac06ead4b70738aad1..bb9d37f93ab8b26b0217574a1cc40902703d4751 100644 (file)
@@ -288,6 +288,32 @@ fn fail(output: &mut AnonPipe) -> ! {
             unsafe { libc::_exit(1) }
         }
 
+        // Make sure that the source descriptors are not an stdio descriptor,
+        // otherwise the order which we set the child's descriptors may blow
+        // away a descriptor which we are hoping to save. For example,
+        // suppose we want the child's stderr to be the parent's stdout, and
+        // the child's stdout to be the parent's stderr. No matter which we
+        // dup first, the second will get overwritten prematurely.
+        let maybe_migrate = |src: Stdio, output: &mut AnonPipe| {
+            match src {
+                Stdio::Raw(fd @ libc::STDIN_FILENO) |
+                Stdio::Raw(fd @ libc::STDOUT_FILENO) |
+                Stdio::Raw(fd @ libc::STDERR_FILENO) => {
+                    let fd = match cvt_r(|| libc::dup(fd)) {
+                        Ok(fd) => fd,
+                        Err(_) => fail(output),
+                    };
+                    let fd = FileDesc::new(fd);
+                    fd.set_cloexec();
+                    Stdio::Raw(fd.into_raw())
+                },
+
+                s @ Stdio::None |
+                s @ Stdio::Inherit |
+                s @ Stdio::Raw(_) => s,
+            }
+        };
+
         let setup = |src: Stdio, dst: c_int| {
             match src {
                 Stdio::Inherit => true,
@@ -313,6 +339,12 @@ fn fail(output: &mut AnonPipe) -> ! {
             }
         };
 
+        // Make sure we migrate all source descriptors before
+        // we start overwriting them
+        let in_fd = maybe_migrate(in_fd, &mut output);
+        let out_fd = maybe_migrate(out_fd, &mut output);
+        let err_fd = maybe_migrate(err_fd, &mut output);
+
         if !setup(in_fd, libc::STDIN_FILENO) { fail(&mut output) }
         if !setup(out_fd, libc::STDOUT_FILENO) { fail(&mut output) }
         if !setup(err_fd, libc::STDERR_FILENO) { fail(&mut output) }
index 776acd20b069bbc0598eb417c4f10dd78d1d6ca6..fc49f4257be2ace4908917a38edd0278ce04b774 100644 (file)
@@ -59,19 +59,19 @@ mod imp {
     static mut PAGE_SIZE: usize = 0;
 
     #[cfg(any(target_os = "linux", target_os = "android"))]
-    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> *mut libc::c_void {
+    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
         #[repr(C)]
         struct siginfo_t {
             a: [libc::c_int; 3], // si_signo, si_code, si_errno,
             si_addr: *mut libc::c_void,
         }
 
-        (*(info as *const siginfo_t)).si_addr
+        (*(info as *const siginfo_t)).si_addr as usize
     }
 
     #[cfg(not(any(target_os = "linux", target_os = "android")))]
-    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> *mut libc::c_void {
-        (*info).si_addr
+    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
+        (*info).si_addr as usize
     }
 
     // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
@@ -98,7 +98,7 @@ unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> *mut libc::c_void {
         use sys_common::util::report_overflow;
 
         let guard = thread_info::stack_guard().unwrap_or(0);
-        let addr = siginfo_si_addr(info) as usize;
+        let addr = siginfo_si_addr(info);
 
         // If the faulting address is within the guard page, then we print a
         // message saying so.
index 7e5342a3fd4733d2308a60a7205d24e3fc0a5f18..16c4ae8257c132d7018e018fcab09c682f8f8db6 100644 (file)
@@ -20,6 +20,7 @@
 use os::windows::ffi::{OsStrExt, OsStringExt};
 use path::PathBuf;
 use time::Duration;
+use alloc::oom;
 
 #[macro_use] pub mod compat;
 
 pub mod time;
 pub mod stdio;
 
-pub fn init() {}
+// See comment in sys/unix/mod.rs
+fn oom_handler() -> ! {
+    use intrinsics;
+    use ptr;
+    let msg = "fatal runtime error: out of memory\n";
+    unsafe {
+        // WriteFile silently fails if it is passed an invalid handle, so there
+        // is no need to check the result of GetStdHandle.
+        c::WriteFile(c::GetStdHandle(c::STD_ERROR_HANDLE),
+                     msg.as_ptr() as c::LPVOID,
+                     msg.len() as c::DWORD,
+                     ptr::null_mut(),
+                     ptr::null_mut());
+        intrinsics::abort();
+    }
+}
+
+pub fn init() {
+    oom::set_oom_handler(oom_handler);
+}
 
 pub fn decode_error_kind(errno: i32) -> ErrorKind {
     match errno as c::DWORD {
index 2c92bc504c896bb5854139f1902a4098896b3c17..dc0bc6dfe024559ed6586ac04001950e4b732035 100644 (file)
@@ -87,32 +87,9 @@ macro_rules! scoped_thread_local {
            issue = "0")]
 #[macro_export]
 #[allow_internal_unstable]
-#[cfg(no_elf_tls)]
 macro_rules! __scoped_thread_local_inner {
     ($t:ty) => {{
-        static _KEY: $crate::thread::__ScopedKeyInner<$t> =
-            $crate::thread::__ScopedKeyInner::new();
-        fn _getit() -> &'static $crate::thread::__ScopedKeyInner<$t> { &_KEY }
-        $crate::thread::ScopedKey::new(_getit)
-    }}
-}
-
-#[doc(hidden)]
-#[unstable(feature = "thread_local_internals",
-           reason = "should not be necessary",
-           issue = "0")]
-#[macro_export]
-#[allow_internal_unstable]
-#[cfg(not(no_elf_tls))]
-macro_rules! __scoped_thread_local_inner {
-    ($t:ty) => {{
-        #[cfg_attr(not(any(windows,
-                           target_os = "android",
-                           target_os = "ios",
-                           target_os = "netbsd",
-                           target_os = "openbsd",
-                           target_arch = "aarch64")),
-                   thread_local)]
+        #[cfg_attr(target_thread_local, thread_local)]
         static _KEY: $crate::thread::__ScopedKeyInner<$t> =
             $crate::thread::__ScopedKeyInner::new();
         fn _getit() -> &'static $crate::thread::__ScopedKeyInner<$t> { &_KEY }
@@ -221,13 +198,7 @@ pub fn is_set(&'static self) -> bool {
     }
 }
 
-#[cfg(not(any(windows,
-              target_os = "android",
-              target_os = "ios",
-              target_os = "netbsd",
-              target_os = "openbsd",
-              target_arch = "aarch64",
-              no_elf_tls)))]
+#[cfg(target_thread_local)]
 #[doc(hidden)]
 mod imp {
     use cell::Cell;
@@ -246,13 +217,7 @@ pub unsafe fn get(&self) -> *mut T { self.inner.get() }
     }
 }
 
-#[cfg(any(windows,
-          target_os = "android",
-          target_os = "ios",
-          target_os = "netbsd",
-          target_os = "openbsd",
-          target_arch = "aarch64",
-          no_elf_tls))]
+#[cfg(not(target_thread_local))]
 #[doc(hidden)]
 mod imp {
     use cell::Cell;
index ad1be82d6d8422a9a28b1b14481c0961a8847056..7ecb3920cc86c9ede483e4a79cf264de587ec15a 100644 (file)
@@ -40,7 +40,7 @@
 /// let ten_millis = Duration::from_millis(10);
 /// ```
 #[stable(feature = "duration", since = "1.3.0")]
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 pub struct Duration {
     secs: u64,
     nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
index e3ce8e0de4b12793a6e12c01a39e7fd7c5647d0c..f885733c2d18ff9c1b556a65162dbf9f3c086249 100644 (file)
@@ -23,6 +23,7 @@
 mod duration;
 
 /// A measurement of a monotonically increasing clock.
+///  Opaque and useful only with `Duration`.
 ///
 /// Instants are always guaranteed to be greater than any previously measured
 /// instant when created, and are often useful for tasks such as measuring
@@ -42,8 +43,8 @@
 #[unstable(feature = "time2", reason = "recently added", issue = "29866")]
 pub struct Instant(time::Instant);
 
-/// A measurement of the system clock appropriate for timestamps such as those
-/// on files on the filesystem.
+/// A measurement of the system clock, useful for talking to
+/// external entities like the file system or other processes.
 ///
 /// Distinct from the `Instant` type, this time measurement **is not
 /// monotonic**. This means that you can save a file to the file system, then
index a7bfdedf71813d0fd70ef99033069f1927598008..c21bf1e6a1fa04abaf1033296f2209de5de9138f 100644 (file)
@@ -43,7 +43,7 @@ fn emit_struct(&mut self, db: &DiagnosticBuilder) {
 /// maximum number of lines we will print for each error; arbitrary.
 const MAX_LINES: usize = 6;
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum ColorConfig {
     Auto,
     Always,
diff --git a/src/libsyntax/errors/json.rs b/src/libsyntax/errors/json.rs
new file mode 100644 (file)
index 0000000..713190e
--- /dev/null
@@ -0,0 +1,233 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A JSON emitter for errors.
+//!
+//! This works by converting errors to a simplified structural format (see the
+//! structs at the start of the file) and then serialising them. These should
+//! contain as much information about the error as possible.
+//!
+//! The format of the JSON output should be considered *unstable*. For now the
+//! structs at the end of this file (Diagnostic*) specify the error format.
+
+// FIXME spec the JSON output properly.
+
+
+use codemap::{Span, CodeMap};
+use diagnostics::registry::Registry;
+use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan};
+use errors::emitter::Emitter;
+
+use std::rc::Rc;
+use std::io::{self, Write};
+
+use rustc_serialize::json::as_json;
+
+pub struct JsonEmitter {
+    dst: Box<Write + Send>,
+    registry: Option<Registry>,
+    cm: Rc<CodeMap>,
+}
+
+impl JsonEmitter {
+    pub fn basic() -> JsonEmitter {
+        JsonEmitter::stderr(None, Rc::new(CodeMap::new()))
+    }
+
+    pub fn stderr(registry: Option<Registry>,
+                  code_map: Rc<CodeMap>) -> JsonEmitter {
+        JsonEmitter {
+            dst: Box::new(io::stderr()),
+            registry: registry,
+            cm: code_map,
+        }
+    }
+}
+
+impl Emitter for JsonEmitter {
+    fn emit(&mut self, span: Option<Span>, msg: &str, code: Option<&str>, level: Level) {
+        let data = Diagnostic::new(span, msg, code, level, self);
+        if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
+            panic!("failed to print diagnostics: {:?}", e);
+        }
+    }
+
+    fn custom_emit(&mut self, sp: RenderSpan, msg: &str, level: Level) {
+        let data = Diagnostic::from_render_span(&sp, msg, level, self);
+        if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
+            panic!("failed to print diagnostics: {:?}", e);
+        }
+    }
+
+    fn emit_struct(&mut self, db: &DiagnosticBuilder) {
+        let data = Diagnostic::from_diagnostic_builder(db, self);
+        if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
+            panic!("failed to print diagnostics: {:?}", e);
+        }
+    }
+}
+
+// The following data types are provided just for serialisation.
+
+#[derive(RustcEncodable)]
+struct Diagnostic<'a> {
+    /// The primary error message.
+    message: &'a str,
+    code: Option<DiagnosticCode>,
+    /// "error: internal compiler error", "error", "warning", "note", "help".
+    level: &'static str,
+    span: Option<DiagnosticSpan>,
+    /// Assocaited diagnostic messages.
+    children: Vec<Diagnostic<'a>>,
+}
+
+#[derive(RustcEncodable)]
+struct DiagnosticSpan {
+    file_name: String,
+    byte_start: u32,
+    byte_end: u32,
+    /// 1-based.
+    line_start: usize,
+    line_end: usize,
+    /// 1-based, character offset.
+    column_start: usize,
+    column_end: usize,
+}
+
+#[derive(RustcEncodable)]
+struct DiagnosticCode {
+    /// The code itself.
+    code: String,
+    /// An explanation for the code.
+    explanation: Option<&'static str>,
+}
+
+impl<'a> Diagnostic<'a> {
+    fn new(span: Option<Span>,
+           msg: &'a str,
+           code: Option<&str>,
+           level: Level,
+           je: &JsonEmitter)
+           -> Diagnostic<'a> {
+        Diagnostic {
+            message: msg,
+            code: DiagnosticCode::map_opt_string(code.map(|c| c.to_owned()), je),
+            level: level.to_str(),
+            span: span.map(|sp| DiagnosticSpan::from_span(sp, je)),
+            children: vec![],
+        }
+    }
+
+    fn from_render_span(span: &RenderSpan,
+                        msg: &'a str,
+                        level: Level,
+                        je: &JsonEmitter)
+                        -> Diagnostic<'a> {
+        Diagnostic {
+            message: msg,
+            code: None,
+            level: level.to_str(),
+            span: Some(DiagnosticSpan::from_render_span(span, je)),
+            children: vec![],
+        }
+    }
+
+    fn from_diagnostic_builder<'c>(db: &'c DiagnosticBuilder,
+                                   je: &JsonEmitter)
+                                   -> Diagnostic<'c> {
+        Diagnostic {
+            message: &db.message,
+            code: DiagnosticCode::map_opt_string(db.code.clone(), je),
+            level: db.level.to_str(),
+            span: db.span.map(|sp| DiagnosticSpan::from_span(sp, je)),
+            children: db.children.iter().map(|c| {
+                Diagnostic::from_sub_diagnostic(c, je)
+            }).collect(),
+        }
+    }
+
+    fn from_sub_diagnostic<'c>(db: &'c SubDiagnostic, je: &JsonEmitter) -> Diagnostic<'c> {
+        Diagnostic {
+            message: &db.message,
+            code: None,
+            level: db.level.to_str(),
+            span: db.render_span.as_ref()
+                    .map(|sp| DiagnosticSpan::from_render_span(sp, je))
+                    .or_else(|| db.span.map(|sp| DiagnosticSpan::from_span(sp, je))),
+            children: vec![],
+        }
+    }
+}
+
+impl DiagnosticSpan {
+    fn from_span(span: Span, je: &JsonEmitter) -> DiagnosticSpan {
+        let start = je.cm.lookup_char_pos(span.lo);
+        let end = je.cm.lookup_char_pos(span.hi);
+        DiagnosticSpan {
+            file_name: start.file.name.clone(),
+            byte_start: span.lo.0,
+            byte_end: span.hi.0,
+            line_start: start.line,
+            line_end: end.line,
+            column_start: start.col.0 + 1,
+            column_end: end.col.0 + 1,
+        }
+    }
+
+    fn from_render_span(span: &RenderSpan, je: &JsonEmitter) -> DiagnosticSpan {
+        match *span {
+            // FIXME(#30701) handle Suggestion properly
+            RenderSpan::FullSpan(sp) | RenderSpan::Suggestion(sp, _) => {
+                DiagnosticSpan::from_span(sp, je)
+            }
+            RenderSpan::EndSpan(span) => {
+                let end = je.cm.lookup_char_pos(span.hi);
+                DiagnosticSpan {
+                    file_name: end.file.name.clone(),
+                    byte_start: span.lo.0,
+                    byte_end: span.hi.0,
+                    line_start: 0,
+                    line_end: end.line,
+                    column_start: 0,
+                    column_end: end.col.0 + 1,
+                }
+            }
+            RenderSpan::FileLine(span) => {
+                let start = je.cm.lookup_char_pos(span.lo);
+                let end = je.cm.lookup_char_pos(span.hi);
+                DiagnosticSpan {
+                    file_name: start.file.name.clone(),
+                    byte_start: span.lo.0,
+                    byte_end: span.hi.0,
+                    line_start: start.line,
+                    line_end: end.line,
+                    column_start: 0,
+                    column_end: 0,
+                }
+            }
+        }
+    }
+}
+
+impl DiagnosticCode {
+    fn map_opt_string(s: Option<String>, je: &JsonEmitter) -> Option<DiagnosticCode> {
+        s.map(|s| {
+
+            let explanation = je.registry
+                                .as_ref()
+                                .and_then(|registry| registry.find_description(&s));
+
+            DiagnosticCode {
+                code: s,
+                explanation: explanation,
+            }
+        })
+    }
+}
index a2fae975148f953e913d96b878babf75fcd01ae8..f269dee31d9ead90579cee0144ac3513179cce61 100644 (file)
@@ -24,6 +24,7 @@
 use term;
 
 pub mod emitter;
+pub mod json;
 
 #[derive(Clone)]
 pub enum RenderSpan {
@@ -275,12 +276,12 @@ pub struct Handler {
 }
 
 impl Handler {
-    pub fn new(color_config: ColorConfig,
-               registry: Option<diagnostics::registry::Registry>,
-               can_emit_warnings: bool,
-               treat_err_as_bug: bool,
-               cm: Rc<codemap::CodeMap>)
-               -> Handler {
+    pub fn with_tty_emitter(color_config: ColorConfig,
+                            registry: Option<diagnostics::registry::Registry>,
+                            can_emit_warnings: bool,
+                            treat_err_as_bug: bool,
+                            cm: Rc<codemap::CodeMap>)
+                            -> Handler {
         let emitter = Box::new(EmitterWriter::stderr(color_config, registry, cm));
         Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter)
     }
@@ -547,14 +548,7 @@ impl fmt::Display for Level {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         use std::fmt::Display;
 
-        match *self {
-            Bug => "error: internal compiler error".fmt(f),
-            Fatal | Error => "error".fmt(f),
-            Warning => "warning".fmt(f),
-            Note => "note".fmt(f),
-            Help => "help".fmt(f),
-            Cancelled => unreachable!(),
-        }
+        self.to_str().fmt(f)
     }
 }
 
@@ -568,6 +562,17 @@ fn color(self) -> term::color::Color {
             Cancelled => unreachable!(),
         }
     }
+
+    fn to_str(self) -> &'static str {
+        match self {
+            Bug => "error: internal compiler error",
+            Fatal | Error => "error",
+            Warning => "warning",
+            Note => "note",
+            Help => "help",
+            Cancelled => panic!("Shouldn't call on cancelled error"),
+        }
+    }
 }
 
 pub fn expect<T, M>(diag: &Handler, opt: Option<T>, msg: M) -> T where
index c61b91df092496b452720280baae0c55f313b97b..9f069cb17ed9033b6174d720e148d563331de281 100644 (file)
@@ -25,8 +25,9 @@
 use util::small_vector::SmallVector;
 
 use std::cell::RefCell;
+use std::collections::{HashMap};
+use std::collections::hash_map::{Entry};
 use std::rc::Rc;
-use std::iter::once;
 
 struct ParserAnyMacro<'a> {
     parser: RefCell<Parser<'a>>,
@@ -320,15 +321,18 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
     NormalTT(exp, Some(def.span), def.allow_internal_unstable)
 }
 
+// why is this here? because of https://github.com/rust-lang/rust/issues/27774
+fn ref_slice<A>(s: &A) -> &[A] { use std::slice::from_raw_parts; unsafe { from_raw_parts(s, 1) } }
+
 fn check_lhs_nt_follows(cx: &mut ExtCtxt, lhs: &TokenTree, sp: Span) {
     // lhs is going to be like TokenTree::Delimited(...), where the
     // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
     match lhs {
         &TokenTree::Delimited(_, ref tts) => {
-            check_matcher(cx, tts.tts.iter(), &Eof);
+            check_matcher(cx, &tts.tts);
         },
         tt @ &TokenTree::Sequence(..) => {
-            check_matcher(cx, Some(tt).into_iter(), &Eof);
+            check_matcher(cx, ref_slice(tt));
         },
         _ => cx.span_err(sp, "invalid macro matcher; matchers must be contained \
                               in balanced delimiters or a repetition indicator")
@@ -345,10 +349,59 @@ fn check_rhs(cx: &mut ExtCtxt, rhs: &TokenTree) -> bool {
     false
 }
 
-// returns the last token that was checked, for TokenTree::Sequence. this gets used later on.
-fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token)
+// Issue 30450: when we are through a warning cycle, we can just error
+// on all failure conditions and remove this struct and enum.
+
+#[derive(Debug)]
+struct OnFail {
+    saw_failure: bool,
+    action: OnFailAction,
+}
+
+#[derive(Copy, Clone, Debug)]
+enum OnFailAction { Warn, Error, DoNothing }
+
+impl OnFail {
+    fn warn() -> OnFail { OnFail { saw_failure: false, action: OnFailAction::Warn } }
+    fn error() -> OnFail { OnFail { saw_failure: false, action: OnFailAction::Error } }
+    fn do_nothing() -> OnFail { OnFail { saw_failure: false, action: OnFailAction::DoNothing } }
+    fn react(&mut self, cx: &mut ExtCtxt, sp: Span, msg: &str) {
+        match self.action {
+            OnFailAction::DoNothing => {}
+            OnFailAction::Error => cx.span_err(sp, msg),
+            OnFailAction::Warn => {
+                cx.struct_span_warn(sp, msg)
+                    .span_note(sp, "The above warning will be a hard error in the next release.")
+                    .emit();
+            }
+        };
+        self.saw_failure = true;
+    }
+}
+
+fn check_matcher(cx: &mut ExtCtxt, matcher: &[TokenTree]) {
+    // Issue 30450: when we are through a warning cycle, we can just
+    // error on all failure conditions (and remove check_matcher_old).
+
+    // First run the old-pass, but *only* to find out if it would have failed.
+    let mut on_fail = OnFail::do_nothing();
+    check_matcher_old(cx, matcher.iter(), &Eof, &mut on_fail);
+    // Then run the new pass, but merely warn if the old pass accepts and new pass rejects.
+    // (Note this silently accepts code if new pass accepts.)
+    let mut on_fail = if on_fail.saw_failure {
+        OnFail::error()
+    } else {
+        OnFail::warn()
+    };
+    check_matcher_new(cx, matcher, &mut on_fail);
+}
+
+// returns the last token that was checked, for TokenTree::Sequence.
+// return value is used by recursive calls.
+fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fail: &mut OnFail)
 -> Option<(Span, Token)> where I: Iterator<Item=&'a TokenTree> {
     use print::pprust::token_to_string;
+    use std::iter::once;
 
     let mut last = None;
 
@@ -375,7 +428,7 @@ fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token)
                             // look at the token that follows the
                             // sequence, which may itself be a sequence,
                             // and so on).
-                            cx.span_err(sp,
+                            on_fail.react(cx, sp,
                                         &format!("`${0}:{1}` is followed by a \
                                                   sequence repetition, which is not \
                                                   allowed for `{1}` fragments",
@@ -398,13 +451,13 @@ fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token)
                     // If T' is in the set FOLLOW(NT), continue. Else, reject.
                     match (&next_token, is_in_follow(cx, &next_token, &frag_spec.name.as_str())) {
                         (_, Err(msg)) => {
-                            cx.span_err(sp, &msg);
+                            on_fail.react(cx, sp, &msg);
                             continue
                         }
                         (&Eof, _) => return Some((sp, tok.clone())),
                         (_, Ok(true)) => continue,
                         (next, Ok(false)) => {
-                            cx.span_err(sp, &format!("`${0}:{1}` is followed by `{2}`, which \
+                            on_fail.react(cx, sp, &format!("`${0}:{1}` is followed by `{2}`, which \
                                                       is not allowed for `{1}` fragments",
                                                      name, frag_spec,
                                                      token_to_string(next)));
@@ -420,7 +473,7 @@ fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token)
                     // run the algorithm on the contents with F set to U. If it
                     // accepts, continue, else, reject.
                     Some(ref u) => {
-                        let last = check_matcher(cx, seq.tts.iter(), u);
+                        let last = check_matcher_old(cx, seq.tts.iter(), u, on_fail);
                         match last {
                             // Since the delimiter isn't required after the last
                             // repetition, make sure that the *next* token is
@@ -434,14 +487,14 @@ fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token)
                                     Some(&&TokenTree::Delimited(_, ref delim)) =>
                                         delim.close_token(),
                                     Some(_) => {
-                                        cx.span_err(sp, "sequence repetition followed by \
+                                        on_fail.react(cx, sp, "sequence repetition followed by \
                                                 another sequence repetition, which is not allowed");
                                         Eof
                                     },
                                     None => Eof
                                 };
-                                check_matcher(cx, once(&TokenTree::Token(span, tok.clone())),
-                                              &fol)
+                                check_matcher_old(cx, once(&TokenTree::Token(span, tok.clone())),
+                                                  &fol, on_fail)
                             },
                             None => last,
                         }
@@ -454,13 +507,13 @@ fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token)
                             Some(&&TokenTree::Token(_, ref tok)) => tok.clone(),
                             Some(&&TokenTree::Delimited(_, ref delim)) => delim.close_token(),
                             Some(_) => {
-                                cx.span_err(sp, "sequence repetition followed by another \
+                                on_fail.react(cx, sp, "sequence repetition followed by another \
                                              sequence repetition, which is not allowed");
                                 Eof
                             },
                             None => Eof
                         };
-                        check_matcher(cx, seq.tts.iter(), &fol)
+                        check_matcher_old(cx, seq.tts.iter(), &fol, on_fail)
                     }
                 }
             },
@@ -471,13 +524,425 @@ fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token)
             TokenTree::Delimited(_, ref tts) => {
                 // if we don't pass in that close delimiter, we'll incorrectly consider the matcher
                 // `{ $foo:ty }` as having a follow that isn't `RBrace`
-                check_matcher(cx, tts.tts.iter(), &tts.close_token())
+                check_matcher_old(cx, tts.tts.iter(), &tts.close_token(), on_fail)
             }
         }
     }
     last
 }
 
+fn check_matcher_new(cx: &mut ExtCtxt, matcher: &[TokenTree], on_fail: &mut OnFail) {
+    let first_sets = FirstSets::new(matcher);
+    let empty_suffix = TokenSet::empty();
+    check_matcher_core(cx, &first_sets, matcher, &empty_suffix, on_fail);
+}
+
+// The FirstSets for a matcher is a mapping from subsequences in the
+// matcher to the FIRST set for that subsequence.
+//
+// This mapping is partially precomputed via a backwards scan over the
+// token trees of the matcher, which provides a mapping from each
+// repetition sequence to its FIRST set.
+//
+// (Hypothetically sequences should be uniquely identifiable via their
+// spans, though perhaps that is false e.g. for macro-generated macros
+// that do not try to inject artificial span information. My plan is
+// to try to catch such cases ahead of time and not include them in
+// the precomputed mapping.)
+struct FirstSets {
+    // this maps each TokenTree::Sequence `$(tt ...) SEP OP` that is uniquely identified by its
+    // span in the original matcher to the First set for the inner sequence `tt ...`.
+    //
+    // If two sequences have the same span in a matcher, then map that
+    // span to None (invalidating the mapping here and forcing the code to
+    // use a slow path).
+    first: HashMap<Span, Option<TokenSet>>,
+}
+
+impl FirstSets {
+    fn new(tts: &[TokenTree]) -> FirstSets {
+        let mut sets = FirstSets { first: HashMap::new() };
+        build_recur(&mut sets, tts);
+        return sets;
+
+        // walks backward over `tts`, returning the FIRST for `tts`
+        // and updating `sets` at the same time for all sequence
+        // substructure we find within `tts`.
+        fn build_recur(sets: &mut FirstSets, tts: &[TokenTree]) -> TokenSet {
+            let mut first = TokenSet::empty();
+            for tt in tts.iter().rev() {
+                match *tt {
+                    TokenTree::Token(sp, ref tok) => {
+                        first.replace_with((sp, tok.clone()));
+                    }
+                    TokenTree::Delimited(_, ref delimited) => {
+                        build_recur(sets, &delimited.tts[..]);
+                        first.replace_with((delimited.open_span,
+                                            Token::OpenDelim(delimited.delim)));
+                    }
+                    TokenTree::Sequence(sp, ref seq_rep) => {
+                        let subfirst = build_recur(sets, &seq_rep.tts[..]);
+
+                        match sets.first.entry(sp) {
+                            Entry::Vacant(vac) => {
+                                vac.insert(Some(subfirst.clone()));
+                            }
+                            Entry::Occupied(mut occ) => {
+                                // if there is already an entry, then a span must have collided.
+                                // This should not happen with typical macro_rules macros,
+                                // but syntax extensions need not maintain distinct spans,
+                                // so distinct syntax trees can be assigned the same span.
+                                // In such a case, the map cannot be trusted; so mark this
+                                // entry as unusable.
+                                occ.insert(None);
+                            }
+                        }
+
+                        // If the sequence contents can be empty, then the first
+                        // token could be the separator token itself.
+
+                        if let (Some(ref sep), true) = (seq_rep.separator.clone(),
+                                                        subfirst.maybe_empty) {
+                            first.add_one_maybe((sp, sep.clone()));
+                        }
+
+                        // Reverse scan: Sequence comes before `first`.
+                        if subfirst.maybe_empty || seq_rep.op == ast::KleeneOp::ZeroOrMore {
+                            // If sequence is potentially empty, then
+                            // union them (preserving first emptiness).
+                            first.add_all(&TokenSet { maybe_empty: true, ..subfirst });
+                        } else {
+                            // Otherwise, sequence guaranteed
+                            // non-empty; replace first.
+                            first = subfirst;
+                        }
+                    }
+                }
+            }
+
+            return first;
+        }
+    }
+
+    // walks forward over `tts` until all potential FIRST tokens are
+    // identified.
+    fn first(&self, tts: &[TokenTree]) -> TokenSet {
+        let mut first = TokenSet::empty();
+        for tt in tts.iter() {
+            assert!(first.maybe_empty);
+            match *tt {
+                TokenTree::Token(sp, ref tok) => {
+                    first.add_one((sp, tok.clone()));
+                    return first;
+                }
+                TokenTree::Delimited(_, ref delimited) => {
+                    first.add_one((delimited.open_span,
+                                   Token::OpenDelim(delimited.delim)));
+                    return first;
+                }
+                TokenTree::Sequence(sp, ref seq_rep) => {
+                    match self.first.get(&sp) {
+                        Some(&Some(ref subfirst)) => {
+
+                            // If the sequence contents can be empty, then the first
+                            // token could be the separator token itself.
+
+                            if let (Some(ref sep), true) = (seq_rep.separator.clone(),
+                                                            subfirst.maybe_empty) {
+                                first.add_one_maybe((sp, sep.clone()));
+                            }
+
+                            assert!(first.maybe_empty);
+                            first.add_all(subfirst);
+                            if subfirst.maybe_empty || seq_rep.op == ast::KleeneOp::ZeroOrMore {
+                                // continue scanning for more first
+                                // tokens, but also make sure we
+                                // restore empty-tracking state
+                                first.maybe_empty = true;
+                                continue;
+                            } else {
+                                return first;
+                            }
+                        }
+
+                        Some(&None) => {
+                            panic!("assume all sequences have (unique) spans for now");
+                        }
+
+                        None => {
+                            panic!("We missed a sequence during FirstSets construction");
+                        }
+                    }
+                }
+            }
+        }
+
+        // we only exit the loop if `tts` was empty or if every
+        // element of `tts` matches the empty sequence.
+        assert!(first.maybe_empty);
+        return first;
+    }
+}
+
+// A set of Tokens, which may include MatchNt tokens (for
+// macro-by-example syntactic variables). It also carries the
+// `maybe_empty` flag; that is true if and only if the matcher can
+// match an empty token sequence.
+//
+// The First set is computed on submatchers like `$($a:expr b),* $(c)* d`,
+// which has corresponding FIRST = {$a:expr, c, d}.
+// Likewise, `$($a:expr b),* $(c)+ d` has FIRST = {$a:expr, c}.
+//
+// (Notably, we must allow for *-op to occur zero times.)
+#[derive(Clone, Debug)]
+struct TokenSet {
+    tokens: Vec<(Span, Token)>,
+    maybe_empty: bool,
+}
+
+impl TokenSet {
+    // Returns a set for the empty sequence.
+    fn empty() -> Self { TokenSet { tokens: Vec::new(), maybe_empty: true } }
+
+    // Returns the set `{ tok }` for the single-token (and thus
+    // non-empty) sequence [tok].
+    fn singleton(tok: (Span, Token)) -> Self {
+        TokenSet { tokens: vec![tok], maybe_empty: false }
+    }
+
+    // Changes self to be the set `{ tok }`.
+    // Since `tok` is always present, marks self as non-empty.
+    fn replace_with(&mut self, tok: (Span, Token)) {
+        self.tokens.clear();
+        self.tokens.push(tok);
+        self.maybe_empty = false;
+    }
+
+    // Changes self to be the empty set `{}`; meant for use when
+    // the particular token does not matter, but we want to
+    // record that it occurs.
+    fn replace_with_irrelevant(&mut self) {
+        self.tokens.clear();
+        self.maybe_empty = false;
+    }
+
+    // Adds `tok` to the set for `self`, marking sequence as non-empy.
+    fn add_one(&mut self, tok: (Span, Token)) {
+        if !self.tokens.contains(&tok) {
+            self.tokens.push(tok);
+        }
+        self.maybe_empty = false;
+    }
+
+    // Adds `tok` to the set for `self`. (Leaves `maybe_empty` flag alone.)
+    fn add_one_maybe(&mut self, tok: (Span, Token)) {
+        if !self.tokens.contains(&tok) {
+            self.tokens.push(tok);
+        }
+    }
+
+    // Adds all elements of `other` to this.
+    //
+    // (Since this is a set, we filter out duplicates.)
+    //
+    // If `other` is potentially empty, then preserves the previous
+    // setting of the empty flag of `self`. If `other` is guaranteed
+    // non-empty, then `self` is marked non-empty.
+    fn add_all(&mut self, other: &Self) {
+        for tok in &other.tokens {
+            if !self.tokens.contains(tok) {
+                self.tokens.push(tok.clone());
+            }
+        }
+        if !other.maybe_empty {
+            self.maybe_empty = false;
+        }
+    }
+}
+
+// Checks that `matcher` is internally consistent and that it
+// can legally by followed by a token N, for all N in `follow`.
+// (If `follow` is empty, then it imposes no constraint on
+// the `matcher`.)
+//
+// Returns the set of NT tokens that could possibly come last in
+// `matcher`. (If `matcher` matches the empty sequence, then
+// `maybe_empty` will be set to true.)
+//
+// Requires that `first_sets` is pre-computed for `matcher`;
+// see `FirstSets::new`.
+fn check_matcher_core(cx: &mut ExtCtxt,
+                      first_sets: &FirstSets,
+                      matcher: &[TokenTree],
+                      follow: &TokenSet,
+                      on_fail: &mut OnFail) -> TokenSet {
+    use print::pprust::token_to_string;
+
+    let mut last = TokenSet::empty();
+
+    // 2. For each token and suffix  [T, SUFFIX] in M:
+    // ensure that T can be followed by SUFFIX, and if SUFFIX may be empty,
+    // then ensure T can also be followed by any element of FOLLOW.
+    'each_token: for i in 0..matcher.len() {
+        let token = &matcher[i];
+        let suffix = &matcher[i+1..];
+
+        let build_suffix_first = || {
+            let mut s = first_sets.first(suffix);
+            if s.maybe_empty { s.add_all(follow); }
+            return s;
+        };
+
+        // (we build `suffix_first` on demand below; you can tell
+        // which cases are supposed to fall through by looking for the
+        // initialization of this variable.)
+        let suffix_first;
+
+        // First, update `last` so that it corresponds to the set
+        // of NT tokens that might end the sequence `... token`.
+        match *token {
+            TokenTree::Token(sp, ref tok) => {
+                let can_be_followed_by_any;
+                if let Err(bad_frag) = has_legal_fragment_specifier(tok) {
+                    on_fail.react(cx, sp, &format!("invalid fragment specifier `{}`", bad_frag));
+                    // (This eliminates false positives and duplicates
+                    // from error messages.)
+                    can_be_followed_by_any = true;
+                } else {
+                    can_be_followed_by_any = token_can_be_followed_by_any(tok);
+                }
+
+                if can_be_followed_by_any {
+                    // don't need to track tokens that work with any,
+                    last.replace_with_irrelevant();
+                    // ... and don't need to check tokens that can be
+                    // followed by anything against SUFFIX.
+                    continue 'each_token;
+                } else {
+                    last.replace_with((sp, tok.clone()));
+                    suffix_first = build_suffix_first();
+                }
+            }
+            TokenTree::Delimited(_, ref d) => {
+                let my_suffix = TokenSet::singleton((d.close_span, Token::CloseDelim(d.delim)));
+                check_matcher_core(cx, first_sets, &d.tts, &my_suffix, on_fail);
+                // don't track non NT tokens
+                last.replace_with_irrelevant();
+
+                // also, we don't need to check delimited sequences
+                // against SUFFIX
+                continue 'each_token;
+            }
+            TokenTree::Sequence(sp, ref seq_rep) => {
+                suffix_first = build_suffix_first();
+                // The trick here: when we check the interior, we want
+                // to include the separator (if any) as a potential
+                // (but not guaranteed) element of FOLLOW. So in that
+                // case, we make a temp copy of suffix and stuff
+                // delimiter in there.
+                //
+                // FIXME: Should I first scan suffix_first to see if
+                // delimiter is already in it before I go through the
+                // work of cloning it? But then again, this way I may
+                // get a "tighter" span?
+                let mut new;
+                let my_suffix = if let Some(ref u) = seq_rep.separator {
+                    new = suffix_first.clone();
+                    new.add_one_maybe((sp, u.clone()));
+                    &new
+                } else {
+                    &suffix_first
+                };
+
+                // At this point, `suffix_first` is built, and
+                // `my_suffix` is some TokenSet that we can use
+                // for checking the interior of `seq_rep`.
+                let next = check_matcher_core(cx, first_sets, &seq_rep.tts, my_suffix, on_fail);
+                if next.maybe_empty {
+                    last.add_all(&next);
+                } else {
+                    last = next;
+                }
+
+                // the recursive call to check_matcher_core already ran the 'each_last
+                // check below, so we can just keep going forward here.
+                continue 'each_token;
+            }
+        }
+
+        // (`suffix_first` guaranteed initialized once reaching here.)
+
+        // Now `last` holds the complete set of NT tokens that could
+        // end the sequence before SUFFIX. Check that every one works with `suffix`.
+        'each_last: for &(_sp, ref t) in &last.tokens {
+            if let MatchNt(ref name, ref frag_spec, _, _) = *t {
+                for &(sp, ref next_token) in &suffix_first.tokens {
+                    match is_in_follow(cx, next_token, &frag_spec.name.as_str()) {
+                        Err(msg) => {
+                            on_fail.react(cx, sp, &msg);
+                            // don't bother reporting every source of
+                            // conflict for a particular element of `last`.
+                            continue 'each_last;
+                        }
+                        Ok(true) => {}
+                        Ok(false) => {
+                            let may_be = if last.tokens.len() == 1 &&
+                                suffix_first.tokens.len() == 1
+                            {
+                                "is"
+                            } else {
+                                "may be"
+                            };
+
+                            on_fail.react(
+                                cx, sp,
+                                &format!("`${name}:{frag}` {may_be} followed by `{next}`, which \
+                                          is not allowed for `{frag}` fragments",
+                                         name=name,
+                                         frag=frag_spec,
+                                         next=token_to_string(next_token),
+                                         may_be=may_be));
+                        }
+                    }
+                }
+            }
+        }
+    }
+    last
+}
+
+
+fn token_can_be_followed_by_any(tok: &Token) -> bool {
+    if let &MatchNt(_, ref frag_spec, _, _) = tok {
+        frag_can_be_followed_by_any(&frag_spec.name.as_str())
+    } else {
+        // (Non NT's can always be followed by anthing in matchers.)
+        true
+    }
+}
+
+/// True if a fragment of type `frag` can be followed by any sort of
+/// token.  We use this (among other things) as a useful approximation
+/// for when `frag` can be followed by a repetition like `$(...)*` or
+/// `$(...)+`. In general, these can be a bit tricky to reason about,
+/// so we adopt a conservative position that says that any fragment
+/// specifier which consumes at most one token tree can be followed by
+/// a fragment specifier (indeed, these fragments can be followed by
+/// ANYTHING without fear of future compatibility hazards).
+fn frag_can_be_followed_by_any(frag: &str) -> bool {
+    match frag {
+        "item" |  // always terminated by `}` or `;`
+        "block" | // exactly one token tree
+        "ident" | // exactly one token tree
+        "meta" |  // exactly one token tree
+        "tt" =>    // exactly one token tree
+            true,
+
+        _ =>
+            false,
+    }
+}
+
 /// True if a fragment of type `frag` can be followed by any sort of
 /// token.  We use this (among other things) as a useful approximation
 /// for when `frag` can be followed by a repetition like `$(...)*` or
@@ -501,7 +966,7 @@ fn can_be_followed_by_any(frag: &str) -> bool {
 }
 
 /// True if `frag` can legally be followed by the token `tok`. For
-/// fragments that can consume an unbounded numbe of tokens, `tok`
+/// fragments that can consume an unbounded number of tokens, `tok`
 /// must be within a well-defined follow set. This is intended to
 /// guarantee future compatibility: for example, without this rule, if
 /// we expanded `expr` to include a new binary operator, we might
@@ -532,15 +997,18 @@ fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result<bool, String> {
             },
             "pat" => {
                 match *tok {
-                    FatArrow | Comma | Eq => Ok(true),
-                    Ident(i, _) if i.name.as_str() == "if" || i.name.as_str() == "in" => Ok(true),
+                    FatArrow | Comma | Eq | BinOp(token::Or) => Ok(true),
+                    Ident(i, _) if (i.name.as_str() == "if" ||
+                                    i.name.as_str() == "in") => Ok(true),
                     _ => Ok(false)
                 }
             },
             "path" | "ty" => {
                 match *tok {
-                    Comma | FatArrow | Colon | Eq | Gt | Semi => Ok(true),
-                    Ident(i, _) if i.name.as_str() == "as" => Ok(true),
+                    OpenDelim(token::DelimToken::Brace) |
+                    Comma | FatArrow | Colon | Eq | Gt | Semi | BinOp(token::Or) => Ok(true),
+                    Ident(i, _) if (i.name.as_str() == "as" ||
+                                    i.name.as_str() == "where") => Ok(true),
                     _ => Ok(false)
                 }
             },
@@ -557,3 +1025,22 @@ fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result<bool, String> {
         }
     }
 }
+
+fn has_legal_fragment_specifier(tok: &Token) -> Result<(), String> {
+    debug!("has_legal_fragment_specifier({:?})", tok);
+    if let &MatchNt(_, ref frag_spec, _, _) = tok {
+        let s = &frag_spec.name.as_str();
+        if !is_legal_fragment_specifier(s) {
+            return Err(s.to_string());
+        }
+    }
+    Ok(())
+}
+
+fn is_legal_fragment_specifier(frag: &str) -> bool {
+    match frag {
+        "item" | "block" | "stmt" | "expr" | "pat" |
+        "path" | "ty" | "ident" | "meta" | "tt" => true,
+        _ => false,
+    }
+}
index c281571305b8bc7de8f4df9c4af3af69a4b368f0..3054c307f36d95cfed856979318c8539571d5883 100644 (file)
     ("slice_patterns", "1.0.0", Some(23121), Active),
 
     // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
-    ("negate_unsigned", "1.0.0", Some(29645), Active),
+    ("negate_unsigned", "1.0.0", Some(29645), Removed),
 
     // Allows the definition of associated constants in `trait` or `impl`
     // blocks.
@@ -548,7 +548,6 @@ pub struct Features {
     pub allow_pushpop_unsafe: bool,
     pub simd_ffi: bool,
     pub unmarked_api: bool,
-    pub negate_unsigned: bool,
     /// spans of #![feature] attrs for stable language features. for error reporting
     pub declared_stable_lang_features: Vec<Span>,
     /// #![feature] attrs for non-language (library) features
@@ -585,7 +584,6 @@ pub fn new() -> Features {
             allow_pushpop_unsafe: false,
             simd_ffi: false,
             unmarked_api: false,
-            negate_unsigned: false,
             declared_stable_lang_features: Vec::new(),
             declared_lib_features: Vec::new(),
             const_fn: false,
@@ -1174,7 +1172,6 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
         allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"),
         simd_ffi: cx.has_feature("simd_ffi"),
         unmarked_api: cx.has_feature("unmarked_api"),
-        negate_unsigned: cx.has_feature("negate_unsigned"),
         declared_stable_lang_features: accepted_features,
         declared_lib_features: unknown_features,
         const_fn: cx.has_feature("const_fn"),
index d2156d7cb68d25ae45b0420eb608b359ebe71ba7..e336c98f03ca0c7d2795f2407776c12cca94c8b1 100644 (file)
@@ -43,10 +43,8 @@ pub struct Comment {
 }
 
 pub fn is_doc_comment(s: &str) -> bool {
-    (s.starts_with("///") && super::is_doc_comment(s)) ||
-    s.starts_with("//!") ||
-    (s.starts_with("/**") && is_block_doc_comment(s)) ||
-    s.starts_with("/*!")
+    (s.starts_with("///") && super::is_doc_comment(s)) || s.starts_with("//!") ||
+    (s.starts_with("/**") && is_block_doc_comment(s)) || s.starts_with("/*!")
 }
 
 pub fn doc_comment_style(comment: &str) -> ast::AttrStyle {
@@ -64,18 +62,18 @@ fn vertical_trim(lines: Vec<String>) -> Vec<String> {
         let mut i = 0;
         let mut j = lines.len();
         // first line of all-stars should be omitted
-        if !lines.is_empty() &&
-                lines[0].chars().all(|c| c == '*') {
+        if !lines.is_empty() && lines[0].chars().all(|c| c == '*') {
             i += 1;
         }
         while i < j && lines[i].trim().is_empty() {
             i += 1;
         }
         // like the first, a last line of all stars should be omitted
-        if j > i && lines[j - 1]
-                         .chars()
-                         .skip(1)
-                         .all(|c| c == '*') {
+        if j > i &&
+           lines[j - 1]
+               .chars()
+               .skip(1)
+               .all(|c| c == '*') {
             j -= 1;
         }
         while j > i && lines[j - 1].trim().is_empty() {
@@ -85,7 +83,7 @@ fn vertical_trim(lines: Vec<String>) -> Vec<String> {
     }
 
     /// remove a "[ \t]*\*" block from each line, if possible
-    fn horizontal_trim(lines: Vec<String> ) -> Vec<String> {
+    fn horizontal_trim(lines: Vec<String>) -> Vec<String> {
         let mut i = usize::MAX;
         let mut can_trim = true;
         let mut first = true;
@@ -114,9 +112,9 @@ fn horizontal_trim(lines: Vec<String> ) -> Vec<String> {
         }
 
         if can_trim {
-            lines.iter().map(|line| {
-                (&line[i + 1..line.len()]).to_string()
-            }).collect()
+            lines.iter()
+                 .map(|line| (&line[i + 1..line.len()]).to_string())
+                 .collect()
         } else {
             lines
         }
@@ -132,9 +130,9 @@ fn horizontal_trim(lines: Vec<String> ) -> Vec<String> {
 
     if comment.starts_with("/*") {
         let lines = comment[3..comment.len() - 2]
-            .lines()
-            .map(|s| s.to_string())
-            .collect::<Vec<String> >();
+                        .lines()
+                        .map(|s| s.to_string())
+                        .collect::<Vec<String>>();
 
         let lines = vertical_trim(lines);
         let lines = horizontal_trim(lines);
@@ -154,8 +152,7 @@ fn push_blank_line_comment(rdr: &StringReader, comments: &mut Vec<Comment>) {
     });
 }
 
-fn consume_whitespace_counting_blank_lines(rdr: &mut StringReader,
-                                           comments: &mut Vec<Comment>) {
+fn consume_whitespace_counting_blank_lines(rdr: &mut StringReader, comments: &mut Vec<Comment>) {
     while is_whitespace(rdr.curr) && !rdr.is_eof() {
         if rdr.col == CharPos(0) && rdr.curr_is('\n') {
             push_blank_line_comment(rdr, &mut *comments);
@@ -165,19 +162,21 @@ fn consume_whitespace_counting_blank_lines(rdr: &mut StringReader,
 }
 
 
-fn read_shebang_comment(rdr: &mut StringReader, code_to_the_left: bool,
+fn read_shebang_comment(rdr: &mut StringReader,
+                        code_to_the_left: bool,
                         comments: &mut Vec<Comment>) {
     debug!(">>> shebang comment");
     let p = rdr.last_pos;
     debug!("<<< shebang comment");
     comments.push(Comment {
         style: if code_to_the_left { Trailing } else { Isolated },
-        lines: vec!(rdr.read_one_line_comment()),
-        pos: p
+        lines: vec![rdr.read_one_line_comment()],
+        pos: p,
     });
 }
 
-fn read_line_comments(rdr: &mut StringReader, code_to_the_left: bool,
+fn read_line_comments(rdr: &mut StringReader,
+                      code_to_the_left: bool,
                       comments: &mut Vec<Comment>) {
     debug!(">>> line comments");
     let p = rdr.last_pos;
@@ -197,7 +196,7 @@ fn read_line_comments(rdr: &mut StringReader, code_to_the_left: bool,
         comments.push(Comment {
             style: if code_to_the_left { Trailing } else { Isolated },
             lines: lines,
-            pos: p
+            pos: p,
         });
     }
 }
@@ -220,8 +219,7 @@ fn all_whitespace(s: &str, col: CharPos) -> Option<usize> {
     return Some(cursor);
 }
 
-fn trim_whitespace_prefix_and_push_line(lines: &mut Vec<String> ,
-                                        s: String, col: CharPos) {
+fn trim_whitespace_prefix_and_push_line(lines: &mut Vec<String>, s: String, col: CharPos) {
     let len = s.len();
     let s1 = match all_whitespace(&s[..], col) {
         Some(col) => {
@@ -239,7 +237,7 @@ fn trim_whitespace_prefix_and_push_line(lines: &mut Vec<String> ,
 
 fn read_block_comment(rdr: &mut StringReader,
                       code_to_the_left: bool,
-                      comments: &mut Vec<Comment> ) {
+                      comments: &mut Vec<Comment>) {
     debug!(">>> block comment");
     let p = rdr.last_pos;
     let mut lines: Vec<String> = Vec::new();
@@ -261,7 +259,7 @@ fn read_block_comment(rdr: &mut StringReader,
             rdr.bump();
         }
         if is_block_doc_comment(&curr_line[..]) {
-            return
+            return;
         }
         assert!(!curr_line.contains('\n'));
         lines.push(curr_line);
@@ -273,9 +271,7 @@ fn read_block_comment(rdr: &mut StringReader,
                 panic!(rdr.fatal("unterminated block comment"));
             }
             if rdr.curr_is('\n') {
-                trim_whitespace_prefix_and_push_line(&mut lines,
-                                                     curr_line,
-                                                     col);
+                trim_whitespace_prefix_and_push_line(&mut lines, curr_line, col);
                 curr_line = String::new();
                 rdr.bump();
             } else {
@@ -291,30 +287,36 @@ fn read_block_comment(rdr: &mut StringReader,
                         rdr.bump();
                         curr_line.push('/');
                         level -= 1;
-                    } else { rdr.bump(); }
+                    } else {
+                        rdr.bump();
+                    }
                 }
             }
         }
         if !curr_line.is_empty() {
-            trim_whitespace_prefix_and_push_line(&mut lines,
-                                                 curr_line,
-                                                 col);
+            trim_whitespace_prefix_and_push_line(&mut lines, curr_line, col);
         }
     }
 
-    let mut style = if code_to_the_left { Trailing } else { Isolated };
+    let mut style = if code_to_the_left {
+        Trailing
+    } else {
+        Isolated
+    };
     rdr.consume_non_eol_whitespace();
     if !rdr.is_eof() && !rdr.curr_is('\n') && lines.len() == 1 {
         style = Mixed;
     }
     debug!("<<< block comment");
-    comments.push(Comment {style: style, lines: lines, pos: p});
+    comments.push(Comment {
+        style: style,
+        lines: lines,
+        pos: p,
+    });
 }
 
 
-fn consume_comment(rdr: &mut StringReader,
-                   code_to_the_left: bool,
-                   comments: &mut Vec<Comment> ) {
+fn consume_comment(rdr: &mut StringReader, code_to_the_left: bool, comments: &mut Vec<Comment>) {
     debug!(">>> consume comment");
     if rdr.curr_is('/') && rdr.nextch_is('/') {
         read_line_comments(rdr, code_to_the_left, comments);
@@ -322,7 +324,9 @@ fn consume_comment(rdr: &mut StringReader,
         read_block_comment(rdr, code_to_the_left, comments);
     } else if rdr.curr_is('#') && rdr.nextch_is('!') {
         read_shebang_comment(rdr, code_to_the_left, comments);
-    } else { panic!(); }
+    } else {
+        panic!();
+    }
     debug!("<<< consume comment");
 }
 
@@ -337,7 +341,7 @@ pub struct Literal {
 pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler,
                                     path: String,
                                     srdr: &mut Read)
-                                 -> (Vec<Comment>, Vec<Literal>) {
+                                    -> (Vec<Comment>, Vec<Literal>) {
     let mut src = Vec::new();
     srdr.read_to_end(&mut src).unwrap();
     let src = String::from_utf8(src).unwrap();
@@ -366,12 +370,15 @@ pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler,
 
         let bstart = rdr.last_pos;
         rdr.next_token();
-        //discard, and look ahead; we're working with internal state
+        // discard, and look ahead; we're working with internal state
         let TokenAndSpan { tok, sp } = rdr.peek();
         if tok.is_lit() {
             rdr.with_str_from(bstart, |s| {
                 debug!("tok lit: {}", s);
-                literals.push(Literal {lit: s.to_string(), pos: sp.lo});
+                literals.push(Literal {
+                    lit: s.to_string(),
+                    pos: sp.lo,
+                });
             })
         } else {
             debug!("tok: {}", pprust::token_to_string(&tok));
@@ -386,31 +393,36 @@ pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler,
 mod tests {
     use super::*;
 
-    #[test] fn test_block_doc_comment_1() {
+    #[test]
+    fn test_block_doc_comment_1() {
         let comment = "/**\n * Test \n **  Test\n *   Test\n*/";
         let stripped = strip_doc_comment_decoration(comment);
         assert_eq!(stripped, " Test \n*  Test\n   Test");
     }
 
-    #[test] fn test_block_doc_comment_2() {
+    #[test]
+    fn test_block_doc_comment_2() {
         let comment = "/**\n * Test\n *  Test\n*/";
         let stripped = strip_doc_comment_decoration(comment);
         assert_eq!(stripped, " Test\n  Test");
     }
 
-    #[test] fn test_block_doc_comment_3() {
+    #[test]
+    fn test_block_doc_comment_3() {
         let comment = "/**\n let a: *i32;\n *a = 5;\n*/";
         let stripped = strip_doc_comment_decoration(comment);
         assert_eq!(stripped, " let a: *i32;\n *a = 5;");
     }
 
-    #[test] fn test_block_doc_comment_4() {
+    #[test]
+    fn test_block_doc_comment_4() {
         let comment = "/*******************\n test\n *********************/";
         let stripped = strip_doc_comment_decoration(comment);
         assert_eq!(stripped, " test");
     }
 
-    #[test] fn test_line_doc_comment() {
+    #[test]
+    fn test_line_doc_comment() {
         let stripped = strip_doc_comment_decoration("/// test");
         assert_eq!(stripped, " test");
         let stripped = strip_doc_comment_decoration("///! test");
index 3d8f3bcd5268fa174c9df7084c8faf8aff340305..3183dfbd954f57dff4642fe8dceffb231e7c39f9 100644 (file)
@@ -42,8 +42,8 @@ fn real_token(&mut self) -> TokenAndSpan {
             match t.tok {
                 token::Whitespace | token::Comment | token::Shebang(_) => {
                     t = self.next_token();
-                },
-                _ => break
+                }
+                _ => break,
             }
         }
         t
@@ -67,17 +67,19 @@ pub struct StringReader<'a> {
     /// The last character to be read
     pub curr: Option<char>,
     pub filemap: Rc<codemap::FileMap>,
-    /* cached: */
+    // cached:
     pub peek_tok: token::Token,
     pub peek_span: Span,
 
     // cache a direct reference to the source text, so that we don't have to
     // retrieve it via `self.filemap.src.as_ref().unwrap()` all the time.
-    source_text: Rc<String>
+    source_text: Rc<String>,
 }
 
 impl<'a> Reader for StringReader<'a> {
-    fn is_eof(&self) -> bool { self.curr.is_none() }
+    fn is_eof(&self) -> bool {
+        self.curr.is_none()
+    }
     /// Return the next token. EFFECT: advances the string_reader.
     fn next_token(&mut self) -> TokenAndSpan {
         let ret_val = TokenAndSpan {
@@ -128,10 +130,12 @@ fn peek(&self) -> TokenAndSpan {
 impl<'a> StringReader<'a> {
     /// For comments.rs, which hackily pokes into pos and curr
     pub fn new_raw<'b>(span_diagnostic: &'b Handler,
-                       filemap: Rc<codemap::FileMap>) -> StringReader<'b> {
+                       filemap: Rc<codemap::FileMap>)
+                       -> StringReader<'b> {
         if filemap.src.is_none() {
-            span_diagnostic.bug(&format!("Cannot lex filemap without source: {}",
-                                                 filemap.name)[..]);
+            span_diagnostic.bug(&format!("Cannot lex filemap \
+                                          without source: {}",
+                                         filemap.name)[..]);
         }
 
         let source_text = (*filemap.src.as_ref().unwrap()).clone();
@@ -143,17 +147,18 @@ pub fn new_raw<'b>(span_diagnostic: &'b Handler,
             col: CharPos(0),
             curr: Some('\n'),
             filemap: filemap,
-            /* dummy values; not read */
+            // dummy values; not read
             peek_tok: token::Eof,
             peek_span: codemap::DUMMY_SP,
-            source_text: source_text
+            source_text: source_text,
         };
         sr.bump();
         sr
     }
 
     pub fn new<'b>(span_diagnostic: &'b Handler,
-                   filemap: Rc<codemap::FileMap>) -> StringReader<'b> {
+                   filemap: Rc<codemap::FileMap>)
+                   -> StringReader<'b> {
         let mut sr = StringReader::new_raw(span_diagnostic, filemap);
         sr.advance_token();
         sr
@@ -189,7 +194,9 @@ fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) {
     fn fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) -> FatalError {
         let mut m = m.to_string();
         m.push_str(": ");
-        for c in c.escape_default() { m.push(c) }
+        for c in c.escape_default() {
+            m.push(c)
+        }
         self.fatal_span_(from_pos, to_pos, &m[..])
     }
     fn struct_fatal_span_char(&self,
@@ -197,10 +204,12 @@ fn struct_fatal_span_char(&self,
                               to_pos: BytePos,
                               m: &str,
                               c: char)
-                              -> DiagnosticBuilder<'a>  {
+                              -> DiagnosticBuilder<'a> {
         let mut m = m.to_string();
         m.push_str(": ");
-        for c in c.escape_default() { m.push(c) }
+        for c in c.escape_default() {
+            m.push(c)
+        }
         self.span_diagnostic.struct_span_fatal(codemap::mk_sp(from_pos, to_pos), &m[..])
     }
 
@@ -209,7 +218,9 @@ fn struct_fatal_span_char(&self,
     fn err_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) {
         let mut m = m.to_string();
         m.push_str(": ");
-        for c in c.escape_default() { m.push(c) }
+        for c in c.escape_default() {
+            m.push(c)
+        }
         self.err_span_(from_pos, to_pos, &m[..]);
     }
     fn struct_err_span_char(&self,
@@ -217,10 +228,12 @@ fn struct_err_span_char(&self,
                             to_pos: BytePos,
                             m: &str,
                             c: char)
-                            -> DiagnosticBuilder<'a>  {
+                            -> DiagnosticBuilder<'a> {
         let mut m = m.to_string();
         m.push_str(": ");
-        for c in c.escape_default() { m.push(c) }
+        for c in c.escape_default() {
+            m.push(c)
+        }
         self.span_diagnostic.struct_span_err(codemap::mk_sp(from_pos, to_pos), &m[..])
     }
 
@@ -241,7 +254,7 @@ fn advance_token(&mut self) {
             Some(comment) => {
                 self.peek_span = comment.sp;
                 self.peek_tok = comment.tok;
-            },
+            }
             None => {
                 if self.is_eof() {
                     self.peek_tok = token::Eof;
@@ -249,8 +262,7 @@ fn advance_token(&mut self) {
                 } else {
                     let start_bytepos = self.last_pos;
                     self.peek_tok = self.next_token_inner();
-                    self.peek_span = codemap::mk_sp(start_bytepos,
-                                                    self.last_pos);
+                    self.peek_span = codemap::mk_sp(start_bytepos, self.last_pos);
                 };
             }
         }
@@ -263,8 +275,8 @@ fn byte_offset(&self, pos: BytePos) -> BytePos {
     /// Calls `f` with a string slice of the source text spanning from `start`
     /// up to but excluding `self.last_pos`, meaning the slice does not include
     /// the character `self.curr`.
-    pub fn with_str_from<T, F>(&self, start: BytePos, f: F) -> T where
-        F: FnOnce(&str) -> T,
+    pub fn with_str_from<T, F>(&self, start: BytePos, f: F) -> T
+        where F: FnOnce(&str) -> T
     {
         self.with_str_from_to(start, self.last_pos, f)
     }
@@ -285,16 +297,14 @@ pub fn name_from_to(&self, start: BytePos, end: BytePos) -> ast::Name {
 
     /// Calls `f` with a string slice of the source text spanning from `start`
     /// up to but excluding `end`.
-    fn with_str_from_to<T, F>(&self, start: BytePos, end: BytePos, f: F) -> T where
-        F: FnOnce(&str) -> T,
+    fn with_str_from_to<T, F>(&self, start: BytePos, end: BytePos, f: F) -> T
+        where F: FnOnce(&str) -> T
     {
-        f(&self.source_text[self.byte_offset(start).to_usize()..
-                            self.byte_offset(end).to_usize()])
+        f(&self.source_text[self.byte_offset(start).to_usize()..self.byte_offset(end).to_usize()])
     }
 
     /// Converts CRLF to LF in the given string, raising an error on bare CR.
-    fn translate_crlf<'b>(&self, start: BytePos,
-                          s: &'b str, errmsg: &'b str) -> Cow<'b, str> {
+    fn translate_crlf<'b>(&self, start: BytePos, s: &'b str, errmsg: &'b str) -> Cow<'b, str> {
         let mut i = 0;
         while i < s.len() {
             let ch = char_at(s, i);
@@ -311,15 +321,21 @@ fn translate_crlf<'b>(&self, start: BytePos,
         }
         return s.into();
 
-        fn translate_crlf_(rdr: &StringReader, start: BytePos,
-                        s: &str, errmsg: &str, mut i: usize) -> String {
+        fn translate_crlf_(rdr: &StringReader,
+                           start: BytePos,
+                           s: &str,
+                           errmsg: &str,
+                           mut i: usize)
+                           -> String {
             let mut buf = String::with_capacity(s.len());
             let mut j = 0;
             while i < s.len() {
                 let ch = char_at(s, i);
                 let next = i + ch.len_utf8();
                 if ch == '\r' {
-                    if j < i { buf.push_str(&s[j..i]); }
+                    if j < i {
+                        buf.push_str(&s[j..i]);
+                    }
                     j = next;
                     if next >= s.len() || char_at(s, next) != '\n' {
                         let pos = start + BytePos(i as u32);
@@ -329,7 +345,9 @@ fn translate_crlf_(rdr: &StringReader, start: BytePos,
                 }
                 i = next;
             }
-            if j < s.len() { buf.push_str(&s[j..]); }
+            if j < s.len() {
+                buf.push_str(&s[j..]);
+            }
             buf
         }
     }
@@ -378,7 +396,9 @@ pub fn nextch_is(&self, c: char) -> bool {
     pub fn nextnextch(&self) -> Option<char> {
         let offset = self.byte_offset(self.pos).to_usize();
         let s = &self.source_text[..];
-        if offset >= s.len() { return None }
+        if offset >= s.len() {
+            return None;
+        }
         let next = offset + char_at(s, offset).len_utf8();
         if next < s.len() {
             Some(char_at(s, next))
@@ -394,7 +414,7 @@ pub fn nextnextch_is(&self, c: char) -> bool {
     /// Eats <XID_start><XID_continue>*, if possible.
     fn scan_optional_raw_name(&mut self) -> Option<ast::Name> {
         if !ident_start(self.curr) {
-            return None
+            return None;
         }
         let start = self.last_pos;
         while ident_continue(self.curr) {
@@ -417,10 +437,11 @@ fn scan_comment(&mut self) -> Option<TokenAndSpan> {
             Some(c) => {
                 if c.is_whitespace() {
                     self.span_diagnostic.span_err(codemap::mk_sp(self.last_pos, self.last_pos),
-                                    "called consume_any_line_comment, but there was whitespace");
+                                                  "called consume_any_line_comment, but there \
+                                                   was whitespace");
                 }
-            },
-            None => { }
+            }
+            None => {}
         }
 
         if self.curr_is('/') {
@@ -443,13 +464,14 @@ fn scan_comment(&mut self) -> Option<TokenAndSpan> {
                             '\r' => {
                                 if self.nextch_is('\n') {
                                     // CRLF
-                                    break
+                                    break;
                                 } else if doc_comment {
-                                    self.err_span_(self.last_pos, self.pos,
+                                    self.err_span_(self.last_pos,
+                                                   self.pos,
                                                    "bare CR not allowed in doc-comment");
                                 }
                             }
-                            _ => ()
+                            _ => (),
                         }
                         self.bump();
                     }
@@ -465,21 +487,22 @@ fn scan_comment(&mut self) -> Option<TokenAndSpan> {
 
                             Some(TokenAndSpan {
                                 tok: tok,
-                                sp: codemap::mk_sp(start_bpos, self.last_pos)
+                                sp: codemap::mk_sp(start_bpos, self.last_pos),
                             })
                         })
                     } else {
                         Some(TokenAndSpan {
                             tok: token::Comment,
-                            sp: codemap::mk_sp(start_bpos, self.last_pos)
+                            sp: codemap::mk_sp(start_bpos, self.last_pos),
                         })
-                    }
+                    };
                 }
                 Some('*') => {
-                    self.bump(); self.bump();
+                    self.bump();
+                    self.bump();
                     self.scan_block_comment()
                 }
-                _ => None
+                _ => None,
             }
         } else if self.curr_is('#') {
             if self.nextch_is('!') {
@@ -498,10 +521,12 @@ fn scan_comment(&mut self) -> Option<TokenAndSpan> {
                 if loc.line == 1 && loc.col == CharPos(0) {
                     // FIXME: Add shebang "token", return it
                     let start = self.last_pos;
-                    while !self.curr_is('\n') && !self.is_eof() { self.bump(); }
+                    while !self.curr_is('\n') && !self.is_eof() {
+                        self.bump();
+                    }
                     return Some(TokenAndSpan {
                         tok: token::Shebang(self.name_from(start)),
-                        sp: codemap::mk_sp(start, self.last_pos)
+                        sp: codemap::mk_sp(start, self.last_pos),
                     });
                 }
             }
@@ -521,18 +546,20 @@ fn scan_whitespace_or_comment(&mut self) -> Option<TokenAndSpan> {
                 let c = self.scan_comment();
                 debug!("scanning a comment {:?}", c);
                 c
-            },
+            }
             c if is_whitespace(Some(c)) => {
                 let start_bpos = self.last_pos;
-                while is_whitespace(self.curr) { self.bump(); }
+                while is_whitespace(self.curr) {
+                    self.bump();
+                }
                 let c = Some(TokenAndSpan {
                     tok: token::Whitespace,
-                    sp: codemap::mk_sp(start_bpos, self.last_pos)
+                    sp: codemap::mk_sp(start_bpos, self.last_pos),
                 });
                 debug!("scanning whitespace: {:?}", c);
                 c
-            },
-            _ => None
+            }
+            _ => None,
         }
     }
 
@@ -567,7 +594,7 @@ fn scan_block_comment(&mut self) -> Option<TokenAndSpan> {
                 '\r' => {
                     has_cr = true;
                 }
-                _ => ()
+                _ => (),
             }
             self.bump();
         }
@@ -576,17 +603,20 @@ fn scan_block_comment(&mut self) -> Option<TokenAndSpan> {
             // but comments with only "*"s between two "/"s are not
             let tok = if is_block_doc_comment(string) {
                 let string = if has_cr {
-                    self.translate_crlf(start_bpos, string,
+                    self.translate_crlf(start_bpos,
+                                        string,
                                         "bare CR not allowed in block doc-comment")
-                } else { string.into() };
+                } else {
+                    string.into()
+                };
                 token::DocComment(token::intern(&string[..]))
             } else {
                 token::Comment
             };
 
-            Some(TokenAndSpan{
+            Some(TokenAndSpan {
                 tok: tok,
-                sp: codemap::mk_sp(start_bpos, self.last_pos)
+                sp: codemap::mk_sp(start_bpos, self.last_pos),
             })
         })
     }
@@ -602,23 +632,27 @@ fn scan_digits(&mut self, real_radix: u32, scan_radix: u32) -> usize {
         let mut len = 0;
         loop {
             let c = self.curr;
-            if c == Some('_') { debug!("skipping a _"); self.bump(); continue; }
+            if c == Some('_') {
+                debug!("skipping a _");
+                self.bump();
+                continue;
+            }
             match c.and_then(|cc| cc.to_digit(scan_radix)) {
                 Some(_) => {
                     debug!("{:?} in scan_digits", c);
                     // check that the hypothetical digit is actually
                     // in range for the true radix
                     if c.unwrap().to_digit(real_radix).is_none() {
-                        self.err_span_(self.last_pos, self.pos,
-                                       &format!("invalid digit for a base {} literal",
-                                                real_radix));
+                        self.err_span_(self.last_pos,
+                                       self.pos,
+                                       &format!("invalid digit for a base {} literal", real_radix));
                     }
                     len += 1;
                     self.bump();
                 }
-                _ => return len
+                _ => return len,
             }
-        };
+        }
     }
 
     /// Lex a LIT_INTEGER or a LIT_FLOAT
@@ -631,9 +665,21 @@ fn scan_number(&mut self, c: char) -> token::Lit {
 
         if c == '0' {
             match self.curr.unwrap_or('\0') {
-                'b' => { self.bump(); base = 2; num_digits = self.scan_digits(2, 10); }
-                'o' => { self.bump(); base = 8; num_digits = self.scan_digits(8, 10); }
-                'x' => { self.bump(); base = 16; num_digits = self.scan_digits(16, 16); }
+                'b' => {
+                    self.bump();
+                    base = 2;
+                    num_digits = self.scan_digits(2, 10);
+                }
+                'o' => {
+                    self.bump();
+                    base = 8;
+                    num_digits = self.scan_digits(8, 10);
+                }
+                'x' => {
+                    self.bump();
+                    base = 16;
+                    num_digits = self.scan_digits(16, 16);
+                }
                 '0'...'9' | '_' | '.' => {
                     num_digits = self.scan_digits(10, 10) + 1;
                 }
@@ -649,15 +695,19 @@ fn scan_number(&mut self, c: char) -> token::Lit {
         }
 
         if num_digits == 0 {
-            self.err_span_(start_bpos, self.last_pos, "no valid digits found for number");
+            self.err_span_(start_bpos,
+                           self.last_pos,
+                           "no valid digits found for number");
             return token::Integer(token::intern("0"));
         }
 
         // might be a float, but don't be greedy if this is actually an
         // integer literal followed by field/method access or a range pattern
         // (`0..2` and `12.foo()`)
-        if self.curr_is('.') && !self.nextch_is('.') && !self.nextch().unwrap_or('\0')
-                                                             .is_xid_start() {
+        if self.curr_is('.') && !self.nextch_is('.') &&
+           !self.nextch()
+                .unwrap_or('\0')
+                .is_xid_start() {
             // might have stuff after the ., and if it does, it needs to start
             // with a number
             self.bump();
@@ -683,11 +733,7 @@ fn scan_number(&mut self, c: char) -> token::Lit {
 
     /// Scan over `n_digits` hex digits, stopping at `delim`, reporting an
     /// error if too many or too few digits are encountered.
-    fn scan_hex_digits(&mut self,
-                       n_digits: usize,
-                       delim: char,
-                       below_0x7f_only: bool)
-                       -> bool {
+    fn scan_hex_digits(&mut self, n_digits: usize, delim: char, below_0x7f_only: bool) -> bool {
         debug!("scanning {} digits until {:?}", n_digits, delim);
         let start_bpos = self.last_pos;
         let mut accum_int = 0;
@@ -702,15 +748,19 @@ fn scan_hex_digits(&mut self,
             }
             if self.curr_is(delim) {
                 let last_bpos = self.last_pos;
-                self.err_span_(start_bpos, last_bpos, "numeric character escape is too short");
+                self.err_span_(start_bpos,
+                               last_bpos,
+                               "numeric character escape is too short");
                 valid = false;
                 break;
             }
             let c = self.curr.unwrap_or('\x00');
             accum_int *= 16;
             accum_int += c.to_digit(16).unwrap_or_else(|| {
-                self.err_span_char(self.last_pos, self.pos,
-                              "invalid character in numeric character escape", c);
+                self.err_span_char(self.last_pos,
+                                   self.pos,
+                                   "invalid character in numeric character escape",
+                                   c);
 
                 valid = false;
                 0
@@ -721,8 +771,8 @@ fn scan_hex_digits(&mut self,
         if below_0x7f_only && accum_int >= 0x80 {
             self.err_span_(start_bpos,
                            self.last_pos,
-                           "this form of character escape may only be used \
-                            with characters in the range [\\x00-\\x7f]");
+                           "this form of character escape may only be used with characters in \
+                            the range [\\x00-\\x7f]");
             valid = false;
         }
 
@@ -741,8 +791,12 @@ fn scan_hex_digits(&mut self,
     /// `start` is the position of `first_source_char`, which is already consumed.
     ///
     /// Returns true if there was a valid char/byte, false otherwise.
-    fn scan_char_or_byte(&mut self, start: BytePos, first_source_char: char,
-                         ascii_only: bool, delim: char) -> bool {
+    fn scan_char_or_byte(&mut self,
+                         start: BytePos,
+                         first_source_char: char,
+                         ascii_only: bool,
+                         delim: char)
+                         -> bool {
         match first_source_char {
             '\\' => {
                 // '\X' for some X must be a character constant:
@@ -750,7 +804,7 @@ fn scan_char_or_byte(&mut self, start: BytePos, first_source_char: char,
                 let escaped_pos = self.last_pos;
                 self.bump();
                 match escaped {
-                    None => {},  // EOF here is an error that will be checked later.
+                    None => {}  // EOF here is an error that will be checked later.
                     Some(e) => {
                         return match e {
                             'n' | 'r' | 't' | '\\' | '\'' | '"' | '0' => true,
@@ -760,18 +814,19 @@ fn scan_char_or_byte(&mut self, start: BytePos, first_source_char: char,
                                     self.scan_unicode_escape(delim) && !ascii_only
                                 } else {
                                     let span = codemap::mk_sp(start, self.last_pos);
-                                    self.span_diagnostic.struct_span_err(span,
-                                        "incorrect unicode escape sequence")
+                                    self.span_diagnostic
+                                        .struct_span_err(span, "incorrect unicode escape sequence")
                                         .span_help(span,
-                                        "format of unicode escape sequences is `\\u{…}`")
+                                                   "format of unicode escape sequences is \
+                                                    `\\u{…}`")
                                         .emit();
                                     false
                                 };
                                 if ascii_only {
-                                    self.err_span_(start, self.last_pos,
-                                        "unicode escape sequences cannot be used as a byte or in \
-                                        a byte string"
-                                    );
+                                    self.err_span_(start,
+                                                   self.last_pos,
+                                                   "unicode escape sequences cannot be used as a \
+                                                    byte or in a byte string");
                                 }
                                 valid
 
@@ -779,27 +834,32 @@ fn scan_char_or_byte(&mut self, start: BytePos, first_source_char: char,
                             '\n' if delim == '"' => {
                                 self.consume_whitespace();
                                 true
-                            },
+                            }
                             '\r' if delim == '"' && self.curr_is('\n') => {
                                 self.consume_whitespace();
                                 true
                             }
                             c => {
                                 let last_pos = self.last_pos;
-                                let mut err = self.struct_err_span_char(
-                                    escaped_pos, last_pos,
-                                    if ascii_only { "unknown byte escape" }
-                                    else { "unknown character escape" },
-                                    c);
+                                let mut err = self.struct_err_span_char(escaped_pos,
+                                                                        last_pos,
+                                                                        if ascii_only {
+                                                                            "unknown byte escape"
+                                                                        } else {
+                                                                            "unknown character \
+                                                                             escape"
+                                                                        },
+                                                                        c);
                                 if e == '\r' {
                                     err.span_help(codemap::mk_sp(escaped_pos, last_pos),
-                                        "this is an isolated carriage return; consider checking \
-                                         your editor and version control settings");
+                                                  "this is an isolated carriage return; consider \
+                                                   checking your editor and version control \
+                                                   settings");
                                 }
                                 if (e == '{' || e == '}') && !ascii_only {
                                     err.span_help(codemap::mk_sp(escaped_pos, last_pos),
-                                        "if used in a formatting string, \
-                                        curly braces are escaped with `{{` and `}}`");
+                                                  "if used in a formatting string, curly braces \
+                                                   are escaped with `{{` and `}}`");
                                 }
                                 err.emit();
                                 false
@@ -810,11 +870,14 @@ fn scan_char_or_byte(&mut self, start: BytePos, first_source_char: char,
             }
             '\t' | '\n' | '\r' | '\'' if delim == '\'' => {
                 let last_pos = self.last_pos;
-                self.err_span_char(
-                    start, last_pos,
-                    if ascii_only { "byte constant must be escaped" }
-                    else { "character constant must be escaped" },
-                    first_source_char);
+                self.err_span_char(start,
+                                   last_pos,
+                                   if ascii_only {
+                                       "byte constant must be escaped"
+                                   } else {
+                                       "character constant must be escaped"
+                                   },
+                                   first_source_char);
                 return false;
             }
             '\r' => {
@@ -822,18 +885,22 @@ fn scan_char_or_byte(&mut self, start: BytePos, first_source_char: char,
                     self.bump();
                     return true;
                 } else {
-                    self.err_span_(start, self.last_pos,
+                    self.err_span_(start,
+                                   self.last_pos,
                                    "bare CR not allowed in string, use \\r instead");
                     return false;
                 }
             }
-            _ => if ascii_only && first_source_char > '\x7F' {
-                let last_pos = self.last_pos;
-                self.err_span_char(
-                    start, last_pos,
-                    "byte constant must be ASCII. \
-                     Use a \\xHH escape for a non-ASCII byte", first_source_char);
-                return false;
+            _ => {
+                if ascii_only && first_source_char > '\x7F' {
+                    let last_pos = self.last_pos;
+                    self.err_span_char(start,
+                                       last_pos,
+                                       "byte constant must be ASCII. Use a \\xHH escape for a \
+                                        non-ASCII byte",
+                                       first_source_char);
+                    return false;
+                }
             }
         }
         true
@@ -854,18 +921,22 @@ fn scan_unicode_escape(&mut self, delim: char) -> bool {
             let c = match self.curr {
                 Some(c) => c,
                 None => {
-                    panic!(self.fatal_span_(start_bpos, self.last_pos,
+                    panic!(self.fatal_span_(start_bpos,
+                                            self.last_pos,
                                             "unterminated unicode escape (found EOF)"));
                 }
             };
             accum_int *= 16;
             accum_int += c.to_digit(16).unwrap_or_else(|| {
                 if c == delim {
-                    panic!(self.fatal_span_(self.last_pos, self.pos,
+                    panic!(self.fatal_span_(self.last_pos,
+                                            self.pos,
                                             "unterminated unicode escape (needed a `}`)"));
                 } else {
-                    self.err_span_char(self.last_pos, self.pos,
-                                   "invalid character in unicode escape", c);
+                    self.err_span_char(self.last_pos,
+                                       self.pos,
+                                       "invalid character in unicode escape",
+                                       c);
                 }
                 valid = false;
                 0
@@ -875,13 +946,16 @@ fn scan_unicode_escape(&mut self, delim: char) -> bool {
         }
 
         if count > 6 {
-            self.err_span_(start_bpos, self.last_pos,
-                          "overlong unicode escape (can have at most 6 hex digits)");
+            self.err_span_(start_bpos,
+                           self.last_pos,
+                           "overlong unicode escape (can have at most 6 hex digits)");
             valid = false;
         }
 
         if valid && (char::from_u32(accum_int).is_none() || count == 0) {
-            self.err_span_(start_bpos, self.last_pos, "invalid unicode character escape");
+            self.err_span_(start_bpos,
+                           self.last_pos,
+                           "invalid unicode character escape");
             valid = false;
         }
 
@@ -897,7 +971,9 @@ fn scan_float_exponent(&mut self) {
                 self.bump();
             }
             if self.scan_digits(10, 10) == 0 {
-                self.err_span_(self.last_pos, self.pos, "expected at least one digit in exponent")
+                self.err_span_(self.last_pos,
+                               self.pos,
+                               "expected at least one digit in exponent")
             }
         }
     }
@@ -906,11 +982,22 @@ fn scan_float_exponent(&mut self) {
     /// error if it isn't.
     fn check_float_base(&mut self, start_bpos: BytePos, last_bpos: BytePos, base: usize) {
         match base {
-            16 => self.err_span_(start_bpos, last_bpos, "hexadecimal float literal is not \
-                                   supported"),
-            8 => self.err_span_(start_bpos, last_bpos, "octal float literal is not supported"),
-            2 => self.err_span_(start_bpos, last_bpos, "binary float literal is not supported"),
-            _   => ()
+            16 => {
+                self.err_span_(start_bpos,
+                               last_bpos,
+                               "hexadecimal float literal is not supported")
+            }
+            8 => {
+                self.err_span_(start_bpos,
+                               last_bpos,
+                               "octal float literal is not supported")
+            }
+            2 => {
+                self.err_span_(start_bpos,
+                               last_bpos,
+                               "binary float literal is not supported")
+            }
+            _ => (),
         }
     }
 
@@ -928,14 +1015,18 @@ fn binop(&mut self, op: token::BinOpToken) -> token::Token {
     /// token, and updates the interner
     fn next_token_inner(&mut self) -> token::Token {
         let c = self.curr;
-        if ident_start(c) && match (c.unwrap(), self.nextch(), self.nextnextch()) {
+        if ident_start(c) &&
+           match (c.unwrap(), self.nextch(), self.nextnextch()) {
             // Note: r as in r" or r#" is part of a raw string literal,
             // b as in b' is part of a byte literal.
             // They are not identifiers, and are handled further down.
-           ('r', Some('"'), _) | ('r', Some('#'), _) |
-           ('b', Some('"'), _) | ('b', Some('\''), _) |
-           ('b', Some('r'), Some('"')) | ('b', Some('r'), Some('#')) => false,
-           _ => true
+            ('r', Some('"'), _) |
+            ('r', Some('#'), _) |
+            ('b', Some('"'), _) |
+            ('b', Some('\''), _) |
+            ('b', Some('r'), Some('"')) |
+            ('b', Some('r'), Some('#')) => false,
+            _ => true,
         } {
             let start = self.last_pos;
             while ident_continue(self.curr) {
@@ -960,299 +1051,398 @@ fn next_token_inner(&mut self) -> token::Token {
             let num = self.scan_number(c.unwrap());
             let suffix = self.scan_optional_raw_name();
             debug!("next_token_inner: scanned number {:?}, {:?}", num, suffix);
-            return token::Literal(num, suffix)
+            return token::Literal(num, suffix);
         }
 
         match c.expect("next_token_inner called at EOF") {
-          // One-byte tokens.
-          ';' => { self.bump(); return token::Semi; }
-          ',' => { self.bump(); return token::Comma; }
-          '.' => {
-              self.bump();
-              return if self.curr_is('.') {
-                  self.bump();
-                  if self.curr_is('.') {
-                      self.bump();
-                      token::DotDotDot
-                  } else {
-                      token::DotDot
-                  }
-              } else {
-                  token::Dot
-              };
-          }
-          '(' => { self.bump(); return token::OpenDelim(token::Paren); }
-          ')' => { self.bump(); return token::CloseDelim(token::Paren); }
-          '{' => { self.bump(); return token::OpenDelim(token::Brace); }
-          '}' => { self.bump(); return token::CloseDelim(token::Brace); }
-          '[' => { self.bump(); return token::OpenDelim(token::Bracket); }
-          ']' => { self.bump(); return token::CloseDelim(token::Bracket); }
-          '@' => { self.bump(); return token::At; }
-          '#' => { self.bump(); return token::Pound; }
-          '~' => { self.bump(); return token::Tilde; }
-          '?' => { self.bump(); return token::Question; }
-          ':' => {
-            self.bump();
-            if self.curr_is(':') {
+            // One-byte tokens.
+            ';' => {
                 self.bump();
-                return token::ModSep;
-            } else {
-                return token::Colon;
+                return token::Semi;
+            }
+            ',' => {
+                self.bump();
+                return token::Comma;
+            }
+            '.' => {
+                self.bump();
+                return if self.curr_is('.') {
+                    self.bump();
+                    if self.curr_is('.') {
+                        self.bump();
+                        token::DotDotDot
+                    } else {
+                        token::DotDot
+                    }
+                } else {
+                    token::Dot
+                };
+            }
+            '(' => {
+                self.bump();
+                return token::OpenDelim(token::Paren);
+            }
+            ')' => {
+                self.bump();
+                return token::CloseDelim(token::Paren);
+            }
+            '{' => {
+                self.bump();
+                return token::OpenDelim(token::Brace);
+            }
+            '}' => {
+                self.bump();
+                return token::CloseDelim(token::Brace);
+            }
+            '[' => {
+                self.bump();
+                return token::OpenDelim(token::Bracket);
+            }
+            ']' => {
+                self.bump();
+                return token::CloseDelim(token::Bracket);
+            }
+            '@' => {
+                self.bump();
+                return token::At;
+            }
+            '#' => {
+                self.bump();
+                return token::Pound;
+            }
+            '~' => {
+                self.bump();
+                return token::Tilde;
+            }
+            '?' => {
+                self.bump();
+                return token::Question;
+            }
+            ':' => {
+                self.bump();
+                if self.curr_is(':') {
+                    self.bump();
+                    return token::ModSep;
+                } else {
+                    return token::Colon;
+                }
             }
-          }
 
-          '$' => { self.bump(); return token::Dollar; }
+            '$' => {
+                self.bump();
+                return token::Dollar;
+            }
 
-          // Multi-byte tokens.
-          '=' => {
-            self.bump();
-            if self.curr_is('=') {
+            // Multi-byte tokens.
+            '=' => {
                 self.bump();
-                return token::EqEq;
-            } else if self.curr_is('>') {
+                if self.curr_is('=') {
+                    self.bump();
+                    return token::EqEq;
+                } else if self.curr_is('>') {
+                    self.bump();
+                    return token::FatArrow;
+                } else {
+                    return token::Eq;
+                }
+            }
+            '!' => {
                 self.bump();
-                return token::FatArrow;
-            } else {
-                return token::Eq;
+                if self.curr_is('=') {
+                    self.bump();
+                    return token::Ne;
+                } else {
+                    return token::Not;
+                }
             }
-          }
-          '!' => {
-            self.bump();
-            if self.curr_is('=') {
+            '<' => {
                 self.bump();
-                return token::Ne;
-            } else { return token::Not; }
-          }
-          '<' => {
-            self.bump();
-            match self.curr.unwrap_or('\x00') {
-              '=' => { self.bump(); return token::Le; }
-              '<' => { return self.binop(token::Shl); }
-              '-' => {
+                match self.curr.unwrap_or('\x00') {
+                    '=' => {
+                        self.bump();
+                        return token::Le;
+                    }
+                    '<' => {
+                        return self.binop(token::Shl);
+                    }
+                    '-' => {
+                        self.bump();
+                        match self.curr.unwrap_or('\x00') {
+                            _ => {
+                                return token::LArrow;
+                            }
+                        }
+                    }
+                    _ => {
+                        return token::Lt;
+                    }
+                }
+            }
+            '>' => {
                 self.bump();
                 match self.curr.unwrap_or('\x00') {
-                  _ => { return token::LArrow; }
+                    '=' => {
+                        self.bump();
+                        return token::Ge;
+                    }
+                    '>' => {
+                        return self.binop(token::Shr);
+                    }
+                    _ => {
+                        return token::Gt;
+                    }
                 }
-              }
-              _ => { return token::Lt; }
             }
-          }
-          '>' => {
-            self.bump();
-            match self.curr.unwrap_or('\x00') {
-              '=' => { self.bump(); return token::Ge; }
-              '>' => { return self.binop(token::Shr); }
-              _ => { return token::Gt; }
-            }
-          }
-          '\'' => {
-            // Either a character constant 'a' OR a lifetime name 'abc
-            self.bump();
-            let start = self.last_pos;
+            '\'' => {
+                // Either a character constant 'a' OR a lifetime name 'abc
+                let start_with_quote = self.last_pos;
+                self.bump();
+                let start = self.last_pos;
 
-            // the eof will be picked up by the final `'` check below
-            let c2 = self.curr.unwrap_or('\x00');
-            self.bump();
+                // the eof will be picked up by the final `'` check below
+                let c2 = self.curr.unwrap_or('\x00');
+                self.bump();
 
-            // If the character is an ident start not followed by another single
-            // quote, then this is a lifetime name:
-            if ident_start(Some(c2)) && !self.curr_is('\'') {
-                while ident_continue(self.curr) {
-                    self.bump();
-                }
+                // If the character is an ident start not followed by another single
+                // quote, then this is a lifetime name:
+                if ident_start(Some(c2)) && !self.curr_is('\'') {
+                    while ident_continue(self.curr) {
+                        self.bump();
+                    }
+                    // lifetimes shouldn't end with a single quote
+                    // if we find one, then this is an invalid character literal
+                    if self.curr_is('\'') {
+                        panic!(self.fatal_span_verbose(
+                               start_with_quote, self.pos,
+                               String::from("character literal may only contain one codepoint")));
 
-                // Include the leading `'` in the real identifier, for macro
-                // expansion purposes. See #12512 for the gory details of why
-                // this is necessary.
-                let ident = self.with_str_from(start, |lifetime_name| {
-                    str_to_ident(&format!("'{}", lifetime_name))
-                });
+                    }
 
-                // Conjure up a "keyword checking ident" to make sure that
-                // the lifetime name is not a keyword.
-                let keyword_checking_ident =
-                    self.with_str_from(start, |lifetime_name| {
+                    // Include the leading `'` in the real identifier, for macro
+                    // expansion purposes. See #12512 for the gory details of why
+                    // this is necessary.
+                    let ident = self.with_str_from(start, |lifetime_name| {
+                        str_to_ident(&format!("'{}", lifetime_name))
+                    });
+
+                    // Conjure up a "keyword checking ident" to make sure that
+                    // the lifetime name is not a keyword.
+                    let keyword_checking_ident = self.with_str_from(start, |lifetime_name| {
                         str_to_ident(lifetime_name)
                     });
-                let keyword_checking_token =
-                    &token::Ident(keyword_checking_ident, token::Plain);
-                let last_bpos = self.last_pos;
-                if keyword_checking_token.is_keyword(token::keywords::SelfValue) {
-                    self.err_span_(start,
-                                   last_bpos,
-                                   "invalid lifetime name: 'self \
-                                    is no longer a special lifetime");
-                } else if keyword_checking_token.is_any_keyword() &&
-                    !keyword_checking_token.is_keyword(token::keywords::Static)
-                {
-                    self.err_span_(start,
-                                   last_bpos,
-                                   "invalid lifetime name");
+                    let keyword_checking_token = &token::Ident(keyword_checking_ident,
+                                                               token::Plain);
+                    let last_bpos = self.last_pos;
+                    if keyword_checking_token.is_keyword(token::keywords::SelfValue) {
+                        self.err_span_(start,
+                                       last_bpos,
+                                       "invalid lifetime name: 'self is no longer a special \
+                                        lifetime");
+                    } else if keyword_checking_token.is_any_keyword() &&
+                       !keyword_checking_token.is_keyword(token::keywords::Static) {
+                        self.err_span_(start, last_bpos, "invalid lifetime name");
+                    }
+
+                    return token::Lifetime(ident);
                 }
-                return token::Lifetime(ident);
-            }
 
-            // Otherwise it is a character constant:
-            let valid = self.scan_char_or_byte(start, c2, /* ascii_only = */ false, '\'');
-            if !self.curr_is('\'') {
-                let last_bpos = self.last_pos;
-                panic!(self.fatal_span_verbose(
-                        // Byte offsetting here is okay because the
-                        // character before position `start` is an
-                        // ascii single quote.
-                        start - BytePos(1), last_bpos,
+                let valid = self.scan_char_or_byte(start,
+                                                   c2,
+                                                   // ascii_only =
+                                                   false,
+                                                   '\'');
 
-                        String::from("character literal may only contain one codepoint")));
-            }
-            let id = if valid { self.name_from(start) } else { token::intern("0") };
-            self.bump(); // advance curr past token
-            let suffix = self.scan_optional_raw_name();
-            return token::Literal(token::Char(id), suffix);
-          }
-          'b' => {
-            self.bump();
-            let lit = match self.curr {
-                Some('\'') => self.scan_byte(),
-                Some('"') => self.scan_byte_string(),
-                Some('r') => self.scan_raw_byte_string(),
-                _ => unreachable!()  // Should have been a token::Ident above.
-            };
-            let suffix = self.scan_optional_raw_name();
-            return token::Literal(lit, suffix);
-          }
-          '"' => {
-            let start_bpos = self.last_pos;
-            let mut valid = true;
-            self.bump();
-            while !self.curr_is('"') {
-                if self.is_eof() {
-                    let last_bpos = self.last_pos;
-                    panic!(self.fatal_span_(start_bpos,
-                                            last_bpos,
-                                            "unterminated double quote string"));
+                if !self.curr_is('\'') {
+                    panic!(self.fatal_span_verbose(
+                           start_with_quote, self.last_pos,
+                           String::from("character literal may only contain one codepoint")));
                 }
 
-                let ch_start = self.last_pos;
-                let ch = self.curr.unwrap();
-                self.bump();
-                valid &= self.scan_char_or_byte(ch_start, ch, /* ascii_only = */ false, '"');
+                let id = if valid {
+                    self.name_from(start)
+                } else {
+                    token::intern("0")
+                };
+                self.bump(); // advance curr past token
+                let suffix = self.scan_optional_raw_name();
+                return token::Literal(token::Char(id), suffix);
             }
-            // adjust for the ASCII " at the start of the literal
-            let id = if valid { self.name_from(start_bpos + BytePos(1)) }
-                     else { token::intern("??") };
-            self.bump();
-            let suffix = self.scan_optional_raw_name();
-            return token::Literal(token::Str_(id), suffix);
-          }
-          'r' => {
-            let start_bpos = self.last_pos;
-            self.bump();
-            let mut hash_count = 0;
-            while self.curr_is('#') {
+            'b' => {
                 self.bump();
-                hash_count += 1;
+                let lit = match self.curr {
+                    Some('\'') => self.scan_byte(),
+                    Some('"') => self.scan_byte_string(),
+                    Some('r') => self.scan_raw_byte_string(),
+                    _ => unreachable!(),  // Should have been a token::Ident above.
+                };
+                let suffix = self.scan_optional_raw_name();
+                return token::Literal(lit, suffix);
             }
+            '"' => {
+                let start_bpos = self.last_pos;
+                let mut valid = true;
+                self.bump();
+                while !self.curr_is('"') {
+                    if self.is_eof() {
+                        let last_bpos = self.last_pos;
+                        panic!(self.fatal_span_(start_bpos,
+                                                last_bpos,
+                                                "unterminated double quote string"));
+                    }
 
-            if self.is_eof() {
-                let last_bpos = self.last_pos;
-                panic!(self.fatal_span_(start_bpos, last_bpos, "unterminated raw string"));
-            } else if !self.curr_is('"') {
-                let last_bpos = self.last_pos;
-                let curr_char = self.curr.unwrap();
-                panic!(self.fatal_span_char(start_bpos, last_bpos,
-                                "found invalid character; \
-                                 only `#` is allowed in raw string delimitation",
-                                curr_char));
+                    let ch_start = self.last_pos;
+                    let ch = self.curr.unwrap();
+                    self.bump();
+                    valid &= self.scan_char_or_byte(ch_start,
+                                                    ch,
+                                                    // ascii_only =
+                                                    false,
+                                                    '"');
+                }
+                // adjust for the ASCII " at the start of the literal
+                let id = if valid {
+                    self.name_from(start_bpos + BytePos(1))
+                } else {
+                    token::intern("??")
+                };
+                self.bump();
+                let suffix = self.scan_optional_raw_name();
+                return token::Literal(token::Str_(id), suffix);
             }
-            self.bump();
-            let content_start_bpos = self.last_pos;
-            let mut content_end_bpos;
-            let mut valid = true;
-            'outer: loop {
+            'r' => {
+                let start_bpos = self.last_pos;
+                self.bump();
+                let mut hash_count = 0;
+                while self.curr_is('#') {
+                    self.bump();
+                    hash_count += 1;
+                }
+
                 if self.is_eof() {
                     let last_bpos = self.last_pos;
                     panic!(self.fatal_span_(start_bpos, last_bpos, "unterminated raw string"));
+                } else if !self.curr_is('"') {
+                    let last_bpos = self.last_pos;
+                    let curr_char = self.curr.unwrap();
+                    panic!(self.fatal_span_char(start_bpos,
+                                                last_bpos,
+                                                "found invalid character; only `#` is allowed \
+                                                 in raw string delimitation",
+                                                curr_char));
                 }
-                //if self.curr_is('"') {
-                    //content_end_bpos = self.last_pos;
-                    //for _ in 0..hash_count {
-                        //self.bump();
-                        //if !self.curr_is('#') {
-                            //continue 'outer;
-                let c = self.curr.unwrap();
-                match c {
-                    '"' => {
-                        content_end_bpos = self.last_pos;
-                        for _ in 0..hash_count {
-                            self.bump();
-                            if !self.curr_is('#') {
-                                continue 'outer;
+                self.bump();
+                let content_start_bpos = self.last_pos;
+                let mut content_end_bpos;
+                let mut valid = true;
+                'outer: loop {
+                    if self.is_eof() {
+                        let last_bpos = self.last_pos;
+                        panic!(self.fatal_span_(start_bpos, last_bpos, "unterminated raw string"));
+                    }
+                    // if self.curr_is('"') {
+                    // content_end_bpos = self.last_pos;
+                    // for _ in 0..hash_count {
+                    // self.bump();
+                    // if !self.curr_is('#') {
+                    // continue 'outer;
+                    let c = self.curr.unwrap();
+                    match c {
+                        '"' => {
+                            content_end_bpos = self.last_pos;
+                            for _ in 0..hash_count {
+                                self.bump();
+                                if !self.curr_is('#') {
+                                    continue 'outer;
+                                }
                             }
+                            break;
                         }
-                        break;
-                    },
-                    '\r' => {
-                        if !self.nextch_is('\n') {
-                            let last_bpos = self.last_pos;
-                            self.err_span_(start_bpos, last_bpos, "bare CR not allowed in raw \
-                                           string, use \\r instead");
-                            valid = false;
+                        '\r' => {
+                            if !self.nextch_is('\n') {
+                                let last_bpos = self.last_pos;
+                                self.err_span_(start_bpos,
+                                               last_bpos,
+                                               "bare CR not allowed in raw string, use \\r \
+                                                instead");
+                                valid = false;
+                            }
                         }
+                        _ => (),
                     }
-                    _ => ()
+                    self.bump();
                 }
                 self.bump();
+                let id = if valid {
+                    self.name_from_to(content_start_bpos, content_end_bpos)
+                } else {
+                    token::intern("??")
+                };
+                let suffix = self.scan_optional_raw_name();
+                return token::Literal(token::StrRaw(id, hash_count), suffix);
+            }
+            '-' => {
+                if self.nextch_is('>') {
+                    self.bump();
+                    self.bump();
+                    return token::RArrow;
+                } else {
+                    return self.binop(token::Minus);
+                }
+            }
+            '&' => {
+                if self.nextch_is('&') {
+                    self.bump();
+                    self.bump();
+                    return token::AndAnd;
+                } else {
+                    return self.binop(token::And);
+                }
+            }
+            '|' => {
+                match self.nextch() {
+                    Some('|') => {
+                        self.bump();
+                        self.bump();
+                        return token::OrOr;
+                    }
+                    _ => {
+                        return self.binop(token::Or);
+                    }
+                }
+            }
+            '+' => {
+                return self.binop(token::Plus);
+            }
+            '*' => {
+                return self.binop(token::Star);
+            }
+            '/' => {
+                return self.binop(token::Slash);
+            }
+            '^' => {
+                return self.binop(token::Caret);
+            }
+            '%' => {
+                return self.binop(token::Percent);
+            }
+            c => {
+                let last_bpos = self.last_pos;
+                let bpos = self.pos;
+                let mut err = self.struct_fatal_span_char(last_bpos,
+                                                          bpos,
+                                                          "unknown start of token",
+                                                          c);
+                unicode_chars::check_for_substitution(&self, c, &mut err);
+                err.emit();
+                panic!(FatalError);
             }
-            self.bump();
-            let id = if valid {
-                self.name_from_to(content_start_bpos, content_end_bpos)
-            } else {
-                token::intern("??")
-            };
-            let suffix = self.scan_optional_raw_name();
-            return token::Literal(token::StrRaw(id, hash_count), suffix);
-          }
-          '-' => {
-            if self.nextch_is('>') {
-                self.bump();
-                self.bump();
-                return token::RArrow;
-            } else { return self.binop(token::Minus); }
-          }
-          '&' => {
-            if self.nextch_is('&') {
-                self.bump();
-                self.bump();
-                return token::AndAnd;
-            } else { return self.binop(token::And); }
-          }
-          '|' => {
-            match self.nextch() {
-              Some('|') => { self.bump(); self.bump(); return token::OrOr; }
-              _ => { return self.binop(token::Or); }
-            }
-          }
-          '+' => { return self.binop(token::Plus); }
-          '*' => { return self.binop(token::Star); }
-          '/' => { return self.binop(token::Slash); }
-          '^' => { return self.binop(token::Caret); }
-          '%' => { return self.binop(token::Percent); }
-          c => {
-              let last_bpos = self.last_pos;
-              let bpos = self.pos;
-              let mut err = self.struct_fatal_span_char(last_bpos,
-                                                        bpos,
-                                                        "unknown start of token",
-                                                        c);
-              unicode_chars::check_for_substitution(&self, c, &mut err);
-              err.emit();
-              panic!(FatalError);
-          }
         }
     }
 
     fn consume_whitespace(&mut self) {
-        while is_whitespace(self.curr) && !self.is_eof() { self.bump(); }
+        while is_whitespace(self.curr) && !self.is_eof() {
+            self.bump();
+        }
     }
 
     fn read_to_eol(&mut self) -> String {
@@ -1261,14 +1451,16 @@ fn read_to_eol(&mut self) -> String {
             val.push(self.curr.unwrap());
             self.bump();
         }
-        if self.curr_is('\n') { self.bump(); }
-        return val
+        if self.curr_is('\n') {
+            self.bump();
+        }
+        return val;
     }
 
     fn read_one_line_comment(&mut self) -> String {
         let val = self.read_to_eol();
-        assert!((val.as_bytes()[0] == b'/' && val.as_bytes()[1] == b'/')
-             || (val.as_bytes()[0] == b'#' && val.as_bytes()[1] == b'!'));
+        assert!((val.as_bytes()[0] == b'/' && val.as_bytes()[1] == b'/') ||
+                (val.as_bytes()[0] == b'#' && val.as_bytes()[1] == b'!'));
         return val;
     }
 
@@ -1279,10 +1471,9 @@ fn consume_non_eol_whitespace(&mut self) {
     }
 
     fn peeking_at_comment(&self) -> bool {
-        (self.curr_is('/') && self.nextch_is('/'))
-     || (self.curr_is('/') && self.nextch_is('*'))
-     // consider shebangs comments, but not inner attributes
-     || (self.curr_is('#') && self.nextch_is('!') && !self.nextnextch_is('['))
+        (self.curr_is('/') && self.nextch_is('/')) || (self.curr_is('/') && self.nextch_is('*')) ||
+        // consider shebangs comments, but not inner attributes
+        (self.curr_is('#') && self.nextch_is('!') && !self.nextnextch_is('['))
     }
 
     fn scan_byte(&mut self) -> token::Lit {
@@ -1293,18 +1484,26 @@ fn scan_byte(&mut self) -> token::Lit {
         let c2 = self.curr.unwrap_or('\x00');
         self.bump();
 
-        let valid = self.scan_char_or_byte(start, c2, /* ascii_only = */ true, '\'');
+        let valid = self.scan_char_or_byte(start,
+                                           c2,
+                                           // ascii_only =
+                                           true,
+                                           '\'');
         if !self.curr_is('\'') {
             // Byte offsetting here is okay because the
             // character before position `start` are an
             // ascii single quote and ascii 'b'.
             let last_pos = self.last_pos;
-            panic!(self.fatal_span_verbose(
-                start - BytePos(2), last_pos,
-                "unterminated byte constant".to_string()));
+            panic!(self.fatal_span_verbose(start - BytePos(2),
+                                           last_pos,
+                                           "unterminated byte constant".to_string()));
         }
 
-        let id = if valid { self.name_from(start) } else { token::intern("?") };
+        let id = if valid {
+            self.name_from(start)
+        } else {
+            token::intern("?")
+        };
         self.bump(); // advance curr past token
         return token::Byte(id);
     }
@@ -1327,9 +1526,17 @@ fn scan_byte_string(&mut self) -> token::Lit {
             let ch_start = self.last_pos;
             let ch = self.curr.unwrap();
             self.bump();
-            valid &= self.scan_char_or_byte(ch_start, ch, /* ascii_only = */ true, '"');
+            valid &= self.scan_char_or_byte(ch_start,
+                                            ch,
+                                            // ascii_only =
+                                            true,
+                                            '"');
         }
-        let id = if valid { self.name_from(start) } else { token::intern("??") };
+        let id = if valid {
+            self.name_from(start)
+        } else {
+            token::intern("??")
+        };
         self.bump();
         return token::ByteStr(id);
     }
@@ -1349,10 +1556,11 @@ fn scan_raw_byte_string(&mut self) -> token::Lit {
         } else if !self.curr_is('"') {
             let last_pos = self.last_pos;
             let ch = self.curr.unwrap();
-            panic!(self.fatal_span_char(start_bpos, last_pos,
-                            "found invalid character; \
-                             only `#` is allowed in raw string delimitation",
-                            ch));
+            panic!(self.fatal_span_char(start_bpos,
+                                        last_pos,
+                                        "found invalid character; only `#` is allowed in raw \
+                                         string delimitation",
+                                        ch));
         }
         self.bump();
         let content_start_bpos = self.last_pos;
@@ -1362,7 +1570,7 @@ fn scan_raw_byte_string(&mut self) -> token::Lit {
                 None => {
                     let last_pos = self.last_pos;
                     panic!(self.fatal_span_(start_bpos, last_pos, "unterminated raw string"))
-                },
+                }
                 Some('"') => {
                     content_end_bpos = self.last_pos;
                     for _ in 0..hash_count {
@@ -1372,70 +1580,72 @@ fn scan_raw_byte_string(&mut self) -> token::Lit {
                         }
                     }
                     break;
-                },
-                Some(c) => if c > '\x7F' {
-                    let last_pos = self.last_pos;
-                    self.err_span_char(
-                        last_pos, last_pos, "raw byte string must be ASCII", c);
+                }
+                Some(c) => {
+                    if c > '\x7F' {
+                        let last_pos = self.last_pos;
+                        self.err_span_char(last_pos, last_pos, "raw byte string must be ASCII", c);
+                    }
                 }
             }
             self.bump();
         }
         self.bump();
-        return token::ByteStrRaw(self.name_from_to(content_start_bpos,
-                                                  content_end_bpos),
-                                hash_count);
+        return token::ByteStrRaw(self.name_from_to(content_start_bpos, content_end_bpos),
+                                 hash_count);
     }
 }
 
 pub fn is_whitespace(c: Option<char>) -> bool {
     match c.unwrap_or('\x00') { // None can be null for now... it's not whitespace
         ' ' | '\n' | '\t' | '\r' => true,
-        _ => false
+        _ => false,
     }
 }
 
 fn in_range(c: Option<char>, lo: char, hi: char) -> bool {
     match c {
         Some(c) => lo <= c && c <= hi,
-        _ => false
+        _ => false,
     }
 }
 
-fn is_dec_digit(c: Option<char>) -> bool { return in_range(c, '0', '9'); }
+fn is_dec_digit(c: Option<char>) -> bool {
+    return in_range(c, '0', '9');
+}
 
 pub fn is_doc_comment(s: &str) -> bool {
-    let res = (s.starts_with("///") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'/')
-              || s.starts_with("//!");
+    let res = (s.starts_with("///") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'/') ||
+              s.starts_with("//!");
     debug!("is {:?} a doc comment? {}", s, res);
     res
 }
 
 pub fn is_block_doc_comment(s: &str) -> bool {
-    let res = ((s.starts_with("/**") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'*')
-               || s.starts_with("/*!"))
-              && s.len() >= 5; // Prevent `/**/` from being parsed as a doc comment
+    // Prevent `/**/` from being parsed as a doc comment
+    let res = ((s.starts_with("/**") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'*') ||
+               s.starts_with("/*!")) && s.len() >= 5;
     debug!("is {:?} a doc comment? {}", s, res);
     res
 }
 
 fn ident_start(c: Option<char>) -> bool {
-    let c = match c { Some(c) => c, None => return false };
+    let c = match c {
+        Some(c) => c,
+        None => return false,
+    };
 
-    (c >= 'a' && c <= 'z')
-        || (c >= 'A' && c <= 'Z')
-        || c == '_'
-        || (c > '\x7f' && c.is_xid_start())
+    (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c > '\x7f' && c.is_xid_start())
 }
 
 fn ident_continue(c: Option<char>) -> bool {
-    let c = match c { Some(c) => c, None => return false };
+    let c = match c {
+        Some(c) => c,
+        None => return false,
+    };
 
-    (c >= 'a' && c <= 'z')
-        || (c >= 'A' && c <= 'Z')
-        || (c >= '0' && c <= '9')
-        || c == '_'
-        || (c > '\x7f' && c.is_xid_continue())
+    (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' ||
+    (c > '\x7f' && c.is_xid_continue())
 }
 
 #[cfg(test)]
@@ -1445,7 +1655,7 @@ mod tests {
     use codemap::{BytePos, CodeMap, Span, NO_EXPANSION};
     use errors;
     use parse::token;
-    use parse::token::{str_to_ident};
+    use parse::token::str_to_ident;
     use std::io;
     use std::rc::Rc;
 
@@ -1458,41 +1668,54 @@ fn mk_sh(cm: Rc<CodeMap>) -> errors::Handler {
     // open a string reader for the given string
     fn setup<'a>(cm: &CodeMap,
                  span_handler: &'a errors::Handler,
-                 teststr: String) -> StringReader<'a> {
+                 teststr: String)
+                 -> StringReader<'a> {
         let fm = cm.new_filemap("zebra.rs".to_string(), teststr);
         StringReader::new(span_handler, fm)
     }
 
-    #[test] fn t1 () {
+    #[test]
+    fn t1() {
         let cm = Rc::new(CodeMap::new());
         let sh = mk_sh(cm.clone());
-        let mut string_reader = setup(&cm, &sh,
-            "/* my source file */ \
-             fn main() { println!(\"zebra\"); }\n".to_string());
+        let mut string_reader = setup(&cm,
+                                      &sh,
+                                      "/* my source file */ fn main() { println!(\"zebra\"); }\n"
+                                          .to_string());
         let id = str_to_ident("fn");
         assert_eq!(string_reader.next_token().tok, token::Comment);
         assert_eq!(string_reader.next_token().tok, token::Whitespace);
         let tok1 = string_reader.next_token();
-        let tok2 = TokenAndSpan{
-            tok:token::Ident(id, token::Plain),
-            sp:Span {lo:BytePos(21),hi:BytePos(23),expn_id: NO_EXPANSION}};
-        assert_eq!(tok1,tok2);
+        let tok2 = TokenAndSpan {
+            tok: token::Ident(id, token::Plain),
+            sp: Span {
+                lo: BytePos(21),
+                hi: BytePos(23),
+                expn_id: NO_EXPANSION,
+            },
+        };
+        assert_eq!(tok1, tok2);
         assert_eq!(string_reader.next_token().tok, token::Whitespace);
         // the 'main' id is already read:
         assert_eq!(string_reader.last_pos.clone(), BytePos(28));
         // read another token:
         let tok3 = string_reader.next_token();
-        let tok4 = TokenAndSpan{
-            tok:token::Ident(str_to_ident("main"), token::Plain),
-            sp:Span {lo:BytePos(24),hi:BytePos(28),expn_id: NO_EXPANSION}};
-        assert_eq!(tok3,tok4);
+        let tok4 = TokenAndSpan {
+            tok: token::Ident(str_to_ident("main"), token::Plain),
+            sp: Span {
+                lo: BytePos(24),
+                hi: BytePos(28),
+                expn_id: NO_EXPANSION,
+            },
+        };
+        assert_eq!(tok3, tok4);
         // the lparen is already read:
         assert_eq!(string_reader.last_pos.clone(), BytePos(29))
     }
 
     // check that the given reader produces the desired stream
     // of tokens (stop checking after exhausting the expected vec)
-    fn check_tokenization (mut string_reader: StringReader, expected: Vec<token::Token> ) {
+    fn check_tokenization(mut string_reader: StringReader, expected: Vec<token::Token>) {
         for expected_tok in &expected {
             assert_eq!(&string_reader.next_token().tok, expected_tok);
         }
@@ -1503,7 +1726,8 @@ fn mk_ident(id: &str, style: token::IdentStyle) -> token::Token {
         token::Ident(str_to_ident(id), style)
     }
 
-    #[test] fn doublecolonparsing () {
+    #[test]
+    fn doublecolonparsing() {
         let cm = Rc::new(CodeMap::new());
         let sh = mk_sh(cm.clone());
         check_tokenization(setup(&cm, &sh, "a b".to_string()),
@@ -1512,16 +1736,18 @@ fn mk_ident(id: &str, style: token::IdentStyle) -> token::Token {
                                 mk_ident("b", token::Plain)]);
     }
 
-    #[test] fn dcparsing_2 () {
+    #[test]
+    fn dcparsing_2() {
         let cm = Rc::new(CodeMap::new());
         let sh = mk_sh(cm.clone());
         check_tokenization(setup(&cm, &sh, "a::b".to_string()),
-                           vec![mk_ident("a",token::ModName),
+                           vec![mk_ident("a", token::ModName),
                                 token::ModSep,
                                 mk_ident("b", token::Plain)]);
     }
 
-    #[test] fn dcparsing_3 () {
+    #[test]
+    fn dcparsing_3() {
         let cm = Rc::new(CodeMap::new());
         let sh = mk_sh(cm.clone());
         check_tokenization(setup(&cm, &sh, "a ::b".to_string()),
@@ -1531,54 +1757,61 @@ fn mk_ident(id: &str, style: token::IdentStyle) -> token::Token {
                                 mk_ident("b", token::Plain)]);
     }
 
-    #[test] fn dcparsing_4 () {
+    #[test]
+    fn dcparsing_4() {
         let cm = Rc::new(CodeMap::new());
         let sh = mk_sh(cm.clone());
         check_tokenization(setup(&cm, &sh, "a:: b".to_string()),
-                           vec![mk_ident("a",token::ModName),
+                           vec![mk_ident("a", token::ModName),
                                 token::ModSep,
                                 token::Whitespace,
                                 mk_ident("b", token::Plain)]);
     }
 
-    #[test] fn character_a() {
+    #[test]
+    fn character_a() {
         let cm = Rc::new(CodeMap::new());
         let sh = mk_sh(cm.clone());
         assert_eq!(setup(&cm, &sh, "'a'".to_string()).next_token().tok,
                    token::Literal(token::Char(token::intern("a")), None));
     }
 
-    #[test] fn character_space() {
+    #[test]
+    fn character_space() {
         let cm = Rc::new(CodeMap::new());
         let sh = mk_sh(cm.clone());
         assert_eq!(setup(&cm, &sh, "' '".to_string()).next_token().tok,
                    token::Literal(token::Char(token::intern(" ")), None));
     }
 
-    #[test] fn character_escaped() {
+    #[test]
+    fn character_escaped() {
         let cm = Rc::new(CodeMap::new());
         let sh = mk_sh(cm.clone());
         assert_eq!(setup(&cm, &sh, "'\\n'".to_string()).next_token().tok,
                    token::Literal(token::Char(token::intern("\\n")), None));
     }
 
-    #[test] fn lifetime_name() {
+    #[test]
+    fn lifetime_name() {
         let cm = Rc::new(CodeMap::new());
         let sh = mk_sh(cm.clone());
         assert_eq!(setup(&cm, &sh, "'abc".to_string()).next_token().tok,
                    token::Lifetime(token::str_to_ident("'abc")));
     }
 
-    #[test] fn raw_string() {
+    #[test]
+    fn raw_string() {
         let cm = Rc::new(CodeMap::new());
         let sh = mk_sh(cm.clone());
-        assert_eq!(setup(&cm, &sh,
-                         "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token()
-                                                                 .tok,
+        assert_eq!(setup(&cm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string())
+                       .next_token()
+                       .tok,
                    token::Literal(token::StrRaw(token::intern("\"#a\\b\x00c\""), 3), None));
     }
 
-    #[test] fn literal_suffixes() {
+    #[test]
+    fn literal_suffixes() {
         let cm = Rc::new(CodeMap::new());
         let sh = mk_sh(cm.clone());
         macro_rules! test {
@@ -1614,24 +1847,28 @@ macro_rules! test {
                                   Some(token::intern("suffix"))));
     }
 
-    #[test] fn line_doc_comments() {
+    #[test]
+    fn line_doc_comments() {
         assert!(is_doc_comment("///"));
         assert!(is_doc_comment("/// blah"));
         assert!(!is_doc_comment("////"));
     }
 
-    #[test] fn nested_block_comments() {
+    #[test]
+    fn nested_block_comments() {
         let cm = Rc::new(CodeMap::new());
         let sh = mk_sh(cm.clone());
         let mut lexer = setup(&cm, &sh, "/* /* */ */'a'".to_string());
         match lexer.next_token().tok {
-            token::Comment => { },
-            _ => panic!("expected a comment!")
+            token::Comment => {}
+            _ => panic!("expected a comment!"),
         }
-        assert_eq!(lexer.next_token().tok, token::Literal(token::Char(token::intern("a")), None));
+        assert_eq!(lexer.next_token().tok,
+                   token::Literal(token::Char(token::intern("a")), None));
     }
 
-    #[test] fn crlf_comments() {
+    #[test]
+    fn crlf_comments() {
         let cm = Rc::new(CodeMap::new());
         let sh = mk_sh(cm.clone());
         let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string());
@@ -1639,6 +1876,7 @@ macro_rules! test {
         assert_eq!(comment.tok, token::Comment);
         assert_eq!(comment.sp, ::codemap::mk_sp(BytePos(0), BytePos(7)));
         assert_eq!(lexer.next_token().tok, token::Whitespace);
-        assert_eq!(lexer.next_token().tok, token::DocComment(token::intern("/// test")));
+        assert_eq!(lexer.next_token().tok,
+                   token::DocComment(token::intern("/// test")));
     }
 }
index a122456550116c3135c13b5f35a900eee837fd7c..090b070433f46dc9fef15255b90dd99044df2c3b 100644 (file)
@@ -49,7 +49,7 @@ pub struct ParseSess {
 impl ParseSess {
     pub fn new() -> ParseSess {
         let cm = Rc::new(CodeMap::new());
-        let handler = Handler::new(ColorConfig::Auto, None, true, false, cm.clone());
+        let handler = Handler::with_tty_emitter(ColorConfig::Auto, None, true, false, cm.clone());
         ParseSess::with_span_handler(handler, cm)
     }
 
index e089e630e5760224fb84f63686bf29b8fd8f277f..bfa42e761294b7f9f69c3edcf5d9b3470450a49b 100644 (file)
@@ -4046,10 +4046,12 @@ fn parse_generic_values_after_lt(&mut self) -> PResult<'a, (Vec<ast::Lifetime>,
             let mut err = self.diagnostic().struct_span_err(self.span, &msg);
 
             let span_hi = self.span.hi;
-            let span_hi = if self.parse_ty().is_ok() {
-                self.span.hi
-            } else {
-                span_hi
+            let span_hi = match self.parse_ty() {
+                Ok(..) => self.span.hi,
+                Err(ref mut err) => {
+                    err.cancel();
+                    span_hi
+                }
             };
 
             let msg = format!("did you mean a single argument type &'a Type, \
index 2945d20ceb1b8c641f3dbe8af5fbc8c64505a580..dcc344c4ffd2140f6d6b9965aba5c936bbd12924 100644 (file)
@@ -919,7 +919,6 @@ fn num_cpus() -> usize {
     #[cfg(any(target_os = "freebsd",
               target_os = "dragonfly",
               target_os = "bitrig",
-              target_os = "openbsd",
               target_os = "netbsd"))]
     fn num_cpus() -> usize {
         let mut cpus: libc::c_uint = 0;
@@ -946,6 +945,24 @@ fn num_cpus() -> usize {
         }
         cpus as usize
     }
+
+    #[cfg(target_os = "openbsd")]
+    fn num_cpus() -> usize {
+        let mut cpus: libc::c_uint = 0;
+        let mut cpus_size = std::mem::size_of_val(&cpus);
+        let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+
+        unsafe {
+            libc::sysctl(mib.as_mut_ptr(), 2,
+                         &mut cpus as *mut _ as *mut _,
+                         &mut cpus_size as *mut _ as *mut _,
+                         0 as *mut _, 0);
+        }
+        if cpus < 1 {
+            cpus = 1;
+        }
+        cpus as usize
+    }
 }
 
 pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
index 22cbc415eb4cef9849a1366e017b5cf9236122a4..55a4226c6632da8685dd5c58fd556c6469e79834 100644 (file)
@@ -24,7 +24,7 @@ pub extern "win64" fn foo(a: isize, b: isize, c: isize, d: isize) {
 }
 
 #[inline(never)]
-#[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "aarch64"))]
+#[cfg(not(target_arch = "x86_64"))]
 pub extern fn foo(a: isize, b: isize, c: isize, d: isize) {
     assert_eq!(a, 1);
     assert_eq!(b, 2);
diff --git a/src/test/codegen/mir_zst_stores.rs b/src/test/codegen/mir_zst_stores.rs
new file mode 100644 (file)
index 0000000..c1acdaf
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+#![feature(rustc_attrs)]
+#![crate_type = "lib"]
+use std::marker::PhantomData;
+
+
+struct Zst { phantom: PhantomData<Zst> }
+
+// CHECK-LABEL: @mir
+#[no_mangle]
+#[rustc_mir]
+fn mir(){
+    // CHECK-NOT: getelementptr
+    // CHECK-NOT: store{{.*}}undef
+    let x = Zst { phantom: PhantomData };
+}
diff --git a/src/test/compile-fail/coherence-projection-conflict-orphan.rs b/src/test/compile-fail/coherence-projection-conflict-orphan.rs
new file mode 100644 (file)
index 0000000..3de7945
--- /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)]
+
+// Here we expect a coherence conflict because, even though `i32` does
+// not implement `Iterator`, we cannot rely on that negative reasoning
+// due to the orphan rules. Therefore, `A::Item` may yet turn out to
+// be `i32`.
+
+pub trait Foo<P> {}
+
+pub trait Bar {
+    type Output: 'static;
+}
+
+impl Foo<i32> for i32 { } //~ ERROR E0119
+
+impl<A:Iterator> Foo<A::Item> for A { }
+
+fn main() {}
diff --git a/src/test/compile-fail/coherence-projection-conflict-ty-param.rs b/src/test/compile-fail/coherence-projection-conflict-ty-param.rs
new file mode 100644 (file)
index 0000000..6880f3e
--- /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.
+
+// Coherence error results because we do not know whether `T: Foo<P>` or not
+// for the second impl.
+
+use std::marker::PhantomData;
+
+pub trait Foo<P> {}
+
+impl <P, T: Foo<P>> Foo<P> for Option<T> {} //~ ERROR E0119
+
+impl<T, U> Foo<T> for Option<U> { }
+
+fn main() {}
diff --git a/src/test/compile-fail/coherence-projection-conflict.rs b/src/test/compile-fail/coherence-projection-conflict.rs
new file mode 100644 (file)
index 0000000..2236e71
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::marker::PhantomData;
+
+pub trait Foo<P> {}
+
+pub trait Bar {
+    type Output: 'static;
+}
+
+impl Foo<i32> for i32 { } //~ ERROR E0119
+
+impl<A:Bar> Foo<A::Output> for A { }
+
+impl Bar for i32 {
+    type Output = i32;
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/coherence-projection-ok-orphan.rs b/src/test/compile-fail/coherence-projection-ok-orphan.rs
new file mode 100644 (file)
index 0000000..a52af08
--- /dev/null
@@ -0,0 +1,29 @@
+// 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(dead_code)]
+
+// Here we do not get a coherence conflict because `Baz: Iterator`
+// does not hold and (due to the orphan rules), we can rely on that.
+
+pub trait Foo<P> {}
+
+pub trait Bar {
+    type Output: 'static;
+}
+
+struct Baz;
+impl Foo<i32> for Baz { }
+
+impl<A:Iterator> Foo<A::Item> for A { }
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
diff --git a/src/test/compile-fail/coherence-projection-ok.rs b/src/test/compile-fail/coherence-projection-ok.rs
new file mode 100644 (file)
index 0000000..af88f37
--- /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)]
+
+pub trait Foo<P> {}
+
+pub trait Bar {
+    type Output: 'static;
+}
+
+impl Foo<i32> for i32 { }
+
+impl<A:Bar> Foo<A::Output> for A { }
+
+impl Bar for i32 {
+    type Output = u32;
+}
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
index a8f47ab92e52950040606ebc5174b7e47d8373c0..253285d3919c21937c4c5ebb4ee90fdfc7eb6a44 100644 (file)
@@ -22,7 +22,7 @@
 const A_I8_T
     : [u32; (i8::MAX as i8 + 1u8) as usize]
     //~^ ERROR mismatched types
-    //~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
+    //~| ERROR the trait `core::ops::Add<u8>` is not implemented for the type `i8`
     = [0; (i8::MAX as usize) + 1];
 
 fn main() {
index daa60955ad88decd4d037bc1fe3299d4d24ec018..2a2fc2ef080dbf30cacd440ff6d482e0c7eda65d 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 #![allow(unused_imports)]
-#![feature(negate_unsigned)]
 
 // Note: the relevant lint pass here runs before some of the constant
 // evaluation below (e.g. that performed by trans and llvm), so if you
@@ -65,7 +64,7 @@
      );
 
 const VALS_U8: (u8, u8, u8, u8) =
-    (-u8::MIN,
+    (-(u8::MIN as i8) as u8,
      u8::MIN - 1,
      //~^ ERROR attempted to sub with overflow
      u8::MAX + 1,
@@ -75,7 +74,7 @@
      );
 
 const VALS_U16: (u16, u16, u16, u16) =
-    (-u16::MIN,
+    (-(u16::MIN as i16) as u16,
      u16::MIN - 1,
      //~^ ERROR attempted to sub with overflow
      u16::MAX + 1,
@@ -85,7 +84,7 @@
      );
 
 const VALS_U32: (u32, u32, u32, u32) =
-    (-u32::MIN,
+    (-(u32::MIN as i32) as u32,
      u32::MIN - 1,
      //~^ ERROR attempted to sub with overflow
      u32::MAX + 1,
@@ -95,7 +94,7 @@
      );
 
 const VALS_U64: (u64, u64, u64, u64) =
-    (-u64::MIN,
+    (-(u64::MIN as i64) as u64,
      u64::MIN - 1,
      //~^ ERROR attempted to sub with overflow
      u64::MAX + 1,
diff --git a/src/test/compile-fail/const-eval-overflow0.rs b/src/test/compile-fail/const-eval-overflow0.rs
new file mode 100644 (file)
index 0000000..7db7de9
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(unused_imports)]
+
+// Note: the relevant lint pass here runs before some of the constant
+// evaluation below (e.g. that performed by trans and llvm), so if you
+// change this warn to a deny, then the compiler will exit before
+// those errors are detected.
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const VALS_I8: (i8, i8, i8, i8) =
+    (-i8::MIN,
+     i8::MIN - 1,
+     i8::MAX + 1,
+     i8::MIN * 2,
+     );
+
+const VALS_I16: (i16, i16, i16, i16) =
+    (-i16::MIN,
+     i16::MIN - 1,
+     i16::MAX + 1,
+     i16::MIN * 2,
+     );
+
+const VALS_I32: (i32, i32, i32, i32) =
+    (-i32::MIN,
+     i32::MIN - 1,
+     i32::MAX + 1,
+     i32::MIN * 2,
+     );
+
+const VALS_I64: (i64, i64, i64, i64) =
+    (-i64::MIN,
+     i64::MIN - 1,
+     i64::MAX + 1,
+     i64::MAX * 2,
+     );
+
+const VALS_U8: (u8, u8, u8, u8) =
+    (-u8::MIN,
+     //~^ ERROR unary negation of unsigned integer
+     //~| HELP use a cast or the `!` operator
+     u8::MIN - 1,
+     u8::MAX + 1,
+     u8::MAX * 2,
+     );
+
+const VALS_U16: (u16, u16, u16, u16) =
+    (-u16::MIN,
+     //~^ ERROR unary negation of unsigned integer
+     //~| HELP use a cast or the `!` operator
+     u16::MIN - 1,
+     u16::MAX + 1,
+     u16::MAX * 2,
+     );
+
+const VALS_U32: (u32, u32, u32, u32) =
+    (-u32::MIN,
+     //~^ ERROR unary negation of unsigned integer
+     //~| HELP use a cast or the `!` operator
+     u32::MIN - 1,
+     u32::MAX + 1,
+     u32::MAX * 2,
+     );
+
+const VALS_U64: (u64, u64, u64, u64) =
+    (-u64::MIN,
+     //~^ ERROR unary negation of unsigned integer
+     //~| HELP use a cast or the `!` operator
+     u64::MIN - 1,
+     u64::MAX + 1,
+     u64::MAX * 2,
+     );
+
+fn main() {
+    foo(VALS_I8);
+    foo(VALS_I16);
+    foo(VALS_I32);
+    foo(VALS_I64);
+
+    foo(VALS_U8);
+    foo(VALS_U16);
+    foo(VALS_U32);
+    foo(VALS_U64);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+    println!("{:?}", x);
+}
index 6cb9a3f007f0c5e628e6fd8983e6e548255fad23..7e13f539bb0438c37640980e6cea60f34d4fbb30 100644 (file)
@@ -10,6 +10,8 @@
 
 // Can't use unit struct as enum pattern
 
+#![feature(rustc_attrs)]
+// remove prior feature after warning cycle and promoting warnings to errors
 #![feature(braced_empty_structs)]
 
 struct Empty1;
@@ -18,7 +20,9 @@ enum E {
     Empty2
 }
 
-fn main() {
+// remove attribute after warning cycle and promoting warnings to errors
+#[rustc_error]
+fn main() { //~ ERROR: compilation successful
     let e1 = Empty1;
     let e2 = E::Empty2;
 
@@ -27,7 +31,7 @@ fn main() {
     //     Empty1() => () // ERROR `Empty1` does not name a tuple variant or a tuple struct
     // }
     match e1 {
-        Empty1(..) => () //~ ERROR `Empty1` does not name a tuple variant or a tuple struct
+        Empty1(..) => () //~ WARN `Empty1` does not name a tuple variant or a tuple struct
     }
     // Rejected by parser as yet
     // match e2 {
index cdf7d026d5eebd4b26039d7b9508496c51b8aad4..84a27a382006988820be6dac882733a5b7b3c9f0 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(negate_unsigned)]
 
 #[repr(u8)] //~ NOTE discriminant type specified here
 enum Eu8 {
index b1c73fab4ffa61f2623ad2128c12c3272c47bef1..15cc17b19db33bfc9bb1b2695d95fa6bdfb3df20 100644 (file)
@@ -8,8 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Test that negating unsigned integers is gated by `negate_unsigned` feature
-// gate
+// Test that negating unsigned integers doesn't compile
 
 struct S;
 impl std::ops::Neg for S {
@@ -18,21 +17,26 @@ fn neg(self) -> u32 { 0 }
 }
 
 const _MAX: usize = -1;
-//~^ ERROR unary negation of unsigned integers may be removed in the future
+//~^ ERROR unary negation of unsigned integer
+//~| HELP use a cast or the `!` operator
 
 fn main() {
     let a = -1;
-    //~^ ERROR unary negation of unsigned integers may be removed in the future
+    //~^ ERROR unary negation of unsigned integer
+    //~| HELP use a cast or the `!` operator
     let _b : u8 = a; // for infering variable a to u8.
 
     -a;
-    //~^ ERROR unary negation of unsigned integers may be removed in the future
+    //~^ ERROR unary negation of unsigned integer
+    //~| HELP use a cast or the `!` operator
 
     let _d = -1u8;
-    //~^ ERROR unary negation of unsigned integers may be removed in the future
+    //~^ ERROR unary negation of unsigned integer
+    //~| HELP use a cast or the `!` operator
 
     for _ in -10..10u8 {}
-    //~^ ERROR unary negation of unsigned integers may be removed in the future
+    //~^ ERROR unary negation of unsigned integer
+    //~| HELP use a cast or the `!` operator
 
     -S; // should not trigger the gate; issue 26840
 }
index 88ae0f835d0d724b69676800bd8199ca607618de..53ad2416878942e4e6d6a8261f14cab53c5117a3 100644 (file)
@@ -12,7 +12,7 @@
 
 fn akemi(homura: Homura) {
     let Some(ref madoka) = Some(homura.kaname()); //~ ERROR no method named `kaname` found
-    madoka.clone(); //~ ERROR the type of this value must be known in this context
+    madoka.clone(); //~ ERROR the type of this value must be known
 }
 
 fn main() { }
index 900ad5ce812e3dfb96018862da620d4a9a985c8f..ef6ce5c995bf3f91803e2c7362498f00138d9750 100644 (file)
@@ -16,5 +16,5 @@ fn main() {
     let x = &10 as
             &Add;
             //~^ ERROR the type parameter `RHS` must be explicitly specified in an object type because its default value `Self` references the type `Self`
-            //~^^ ERROR the value of the associated type `Output` (from the trait `core::ops::Add`) must be specified
+            //~| ERROR the value of the associated type `Output` (from the trait `core::ops::Add`) must be specified
 }
index d7f909e4ebcf628bb7fa55009d7b9205be7303fe..7f9c7a292f2be0c7de7921b9ecbfcc483c35dabb 100644 (file)
@@ -9,5 +9,7 @@
 // except according to those terms.
 
 fn main() {
-    "".chars().fold(|_, _| (), ()); //~ ERROR is not implemented for the type `()`
+    "".chars().fold(|_, _| (), ());
+    //~^ ERROR E0277
+    //~| ERROR E0277
 }
index 9936f67b3af3c8e0908bfff2d03376c0d7725c77..4b0773140566c06fb1bf9923da9ac4b8715ef4ed 100644 (file)
@@ -10,5 +10,5 @@
 
 fn main() {
     1.0f64 - 1.0;
-    1.0f64 - 1 //~ ERROR: is not implemented
+    1.0f64 - 1 //~ ERROR E0277
 }
diff --git a/src/test/compile-fail/issue-29857.rs b/src/test/compile-fail/issue-29857.rs
new file mode 100644 (file)
index 0000000..661579f
--- /dev/null
@@ -0,0 +1,31 @@
+// 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)]
+
+use std::marker::PhantomData;
+
+pub trait Foo<P> {}
+
+impl <P, T: Foo<P>> Foo<P> for Option<T> {}
+
+pub struct Qux<T> (PhantomData<*mut T>);
+
+impl<T> Foo<*mut T> for Option<Qux<T>> {}
+
+pub trait Bar {
+    type Output: 'static;
+}
+
+impl<T: 'static, W: Bar<Output = T>> Foo<*mut T> for W {}
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
diff --git a/src/test/compile-fail/issue-30589.rs b/src/test/compile-fail/issue-30589.rs
new file mode 100644 (file)
index 0000000..32765d5
--- /dev/null
@@ -0,0 +1,19 @@
+// 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 std::fmt;
+
+impl fmt::Display for DecoderError { //~ ERROR E0412
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "Missing data: {}", self.0)
+    }
+}
+fn main() {
+}
index 16761905cb983bc518b53752eae0dc594f36e47b..7ad43954010b9b4333e422e3cdab9c47a16ceaad 100644 (file)
 
 macro_rules! parallel {
     (
-        for $id:ident in $iter:expr {
+        // If future has `pred`/`moelarry` fragments (where "pred" is
+        // "like expr, but with `{` in its FOLLOW set"), then could
+        // use `pred` instead of future-proof erroring here. See also:
+        //
+        // https://github.com/rust-lang/rfcs/pull/1384#issuecomment-160165525
+        for $id:ident in $iter:expr { //~ WARN `$iter:expr` is followed by `{`
             $( $inner:expr; )*
         }
     ) => {};
index 1fda423e9ee8d37ab30f2bafef90a2312ededdcd..54eb2a908295568ce1d49356b954d4cd959f02b2 100644 (file)
@@ -31,6 +31,5 @@ fn to_string(&self) -> String {
 fn main() {
     let p = Point::new(0.0, 0.0);
     //~^ ERROR no associated item named `new` found for type `Point` in the current scope
-    println!("{}", p.to_string());
-    //~^ ERROR the type of this value must be known in this context
+    println!("{}", p.to_string()); //~ ERROR type of this value must be known
 }
index 839d50ae63f90359901ecb01dda7ad1489ecf6a4..0b414ad73db6f9109bd33fc5106102bae088e7e5 100644 (file)
@@ -8,9 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(negate_unsigned)]
 #![allow(dead_code)]
-#![feature(negate_unsigned)]
 
 // compile-flags: -D unused-comparisons
 fn main() { }
index 15f6d88fd8998da324e6d34fd415ec4d6bdedc3b..fe758a4a6310fbfe925eeb75d0a1e9c234d0209c 100644 (file)
@@ -18,13 +18,14 @@ macro_rules! errors_everywhere {
     ($bl:block < ) => ();
     ($pa:pat >) => (); //~ ERROR `$pa:pat` is followed by `>`, which is not allowed for `pat`
     ($pa:pat , ) => ();
-    ($pa:pat | ) => (); //~ ERROR `$pa:pat` is followed by `|`
     ($pa:pat $pb:pat $ty:ty ,) => ();
     //~^ ERROR `$pa:pat` is followed by `$pb:pat`, which is not allowed
     //~^^ ERROR `$pb:pat` is followed by `$ty:ty`, which is not allowed
     ($($ty:ty)* -) => (); //~ ERROR `$ty:ty` is followed by `-`
     ($($a:ty, $b:ty)* -) => (); //~ ERROR `$b:ty` is followed by `-`
     ($($ty:ty)-+) => (); //~ ERROR `$ty:ty` is followed by `-`, which is not allowed for `ty`
+    ( $($a:expr)* $($b:tt)* ) => { };
+    //~^ ERROR `$a:expr` is followed by `$b:tt`, which is not allowed for `expr` fragments
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/macro-seq-followed-by-seq.rs b/src/test/compile-fail/macro-seq-followed-by-seq.rs
deleted file mode 100644 (file)
index b4f7134..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Check that we cannot have two sequence repetitions in a row.
-
-macro_rules! foo {
-  ( $($a:expr)* $($b:tt)* ) => { }; //~ ERROR sequence repetition followed by another sequence
-  ( $($a:tt)* $($b:tt)* ) => { }; //~ ERROR sequence repetition followed by another sequence
-}
-
-fn main() { }
index 17debdabb61f08fe1982e77ae63037a6f7bc21a9..e63ddf6c7fd9b6ff210acf15b07cfecfcf459221 100644 (file)
@@ -21,7 +21,6 @@ fn foo(c: color) {
           color::cmyk(_, _, _, _) => { }
           color::no_color(_) => { }
           //~^ ERROR this pattern has 1 field, but the corresponding variant has no fields
-          //~^^ WARN `color::no_color` does not name a tuple variant or a tuple struct
         }
     }
 }
index 1721d1f0ae11c6697426314235917d7aaf963a27..aa7202574abfc3d15c0230790723e81f0d97b56c 100644 (file)
@@ -26,7 +26,6 @@ fn main() {
     match A::B(1, 2) {
         A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but
         A::D(_) => (),       //~ ERROR this pattern has 1 field, but
-        //~^ WARN `A::D` does not name a tuple variant or a tuple struct
         _ => ()
     }
     match 'c' {
index ecf17fa84d7e32bfe2399d40aa7c96e843c1c6dc..1d04679fd11e799dd9ebb620163e378d939b02e6 100644 (file)
@@ -58,3 +58,15 @@ fn h6() -> i32 {
         //~^ ERROR E0425
         //~| HELP To call a function from the `a::b` module, use `a::b::f(..)`
 }
+
+fn h7() {
+    a::b
+        //~^ ERROR E0425
+        //~| HELP Module `a::b` cannot be the value of an expression
+}
+
+fn h8() -> i32 {
+    a::b()
+        //~^ ERROR E0425
+        //~| HELP No function corresponds to `a::b(..)`
+}
diff --git a/src/test/parse-fail/lex-bad-char-literals-1.rs b/src/test/parse-fail/lex-bad-char-literals-1.rs
new file mode 100644 (file)
index 0000000..7e22a11
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z parse-only
+static c3: char =
+    '\x1' //~ ERROR: numeric character escape is too short
+;
+
+static s: &'static str =
+    "\x1" //~ ERROR: numeric character escape is too short
+;
+
+static c: char =
+    '\●' //~ ERROR: unknown character escape
+;
+
+static s: &'static str =
+    "\●" //~ ERROR: unknown character escape
+;
+
diff --git a/src/test/parse-fail/lex-bad-char-literals-2.rs b/src/test/parse-fail/lex-bad-char-literals-2.rs
new file mode 100644 (file)
index 0000000..8bd6808
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z parse-only
+
+// This test needs to the last one appearing in this file as it kills the parser
+static c: char =
+    'nope' //~ ERROR: character literal may only contain one codepoint: 'nope'
+;
+
diff --git a/src/test/parse-fail/lex-bad-char-literals-3.rs b/src/test/parse-fail/lex-bad-char-literals-3.rs
new file mode 100644 (file)
index 0000000..92432dc
--- /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.
+
+// compile-flags: -Z parse-only
+
+// This test needs to the last one appearing in this file as it kills the parser
+static c: char =
+    '●●' //~ ERROR: character literal may only contain one codepoint: '●
+;
diff --git a/src/test/parse-fail/lex-bad-char-literals-4.rs b/src/test/parse-fail/lex-bad-char-literals-4.rs
new file mode 100644 (file)
index 0000000..b230e62
--- /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.
+
+// compile-flags: -Z parse-only
+//
+// This test needs to the last one appearing in this file as it kills the parser
+static c: char =
+    '●  //~ ERROR: character literal may only contain one codepoint: '●
+;
diff --git a/src/test/parse-fail/lex-bad-char-literals-5.rs b/src/test/parse-fail/lex-bad-char-literals-5.rs
new file mode 100644 (file)
index 0000000..5259175
--- /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.
+
+// compile-flags: -Z parse-only
+//
+// This test needs to the last one appearing in this file as it kills the parser
+static c: char =
+    '\x10\x10'  //~ ERROR: character literal may only contain one codepoint: '\x10
+;
diff --git a/src/test/parse-fail/lex-bad-char-literals.rs b/src/test/parse-fail/lex-bad-char-literals.rs
deleted file mode 100644 (file)
index 6335632..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-static c3: char =
-    '\x1' //~ ERROR: numeric character escape is too short
-;
-
-static s: &'static str =
-    "\x1" //~ ERROR: numeric character escape is too short
-;
-
-static c: char =
-    '\●' //~ ERROR: unknown character escape
-;
-
-static s: &'static str =
-    "\●" //~ ERROR: unknown character escape
-;
-
-// THIS MUST BE LAST, since it kills the lexer
-
-static c: char =
-    '●  //~ ERROR: character literal may only contain one codepoint
-;
diff --git a/src/test/parse-fail/lifetime-semicolon.rs b/src/test/parse-fail/lifetime-semicolon.rs
new file mode 100644 (file)
index 0000000..7010d0e
--- /dev/null
@@ -0,0 +1,19 @@
+// 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.
+
+// compile-flags: -Z parse-only
+
+struct Foo<'a, 'b> {
+    a: &'a &'b i32
+}
+
+fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {}
+//~^ ERROR expected `,` or `>` after lifetime name, found `;`
+//~^^ NOTE did you mean a single argument type &'a Type, or did you mean the comma-separated
index 928f2f996a028820aac3931bf75ea61832f612d2..dc409f393a86a971fa82fb3005fc0ef78eb286dc 100644 (file)
@@ -195,7 +195,7 @@ fn build_exec_options(sysroot: PathBuf) -> Options {
     opts.maybe_sysroot = Some(sysroot);
 
     // Prefer faster build time
-    opts.optimize = config::No;
+    opts.optimize = config::OptLevel::No;
 
     // Don't require a `main` function
     opts.crate_types = vec![config::CrateTypeDylib];
diff --git a/src/test/run-make/json-errors/Makefile b/src/test/run-make/json-errors/Makefile
new file mode 100644 (file)
index 0000000..2467e08
--- /dev/null
@@ -0,0 +1,8 @@
+-include ../tools.mk
+
+all:
+       cp foo.rs $(TMPDIR)
+       cd $(TMPDIR)
+       -$(RUSTC) -Z unstable-options --error-format=json foo.rs 2>foo.log
+       grep -q '{"message":"unresolved name `y`","code":{"code":"E0425","explanation":"\\nAn unresolved name was used. Example of erroneous codes.*"},"level":"error","span":{"file_name":"foo.rs","byte_start":496,"byte_end":497,"line_start":12,"line_end":12,"column_start":18,"column_end":19},"children":\[\]}' foo.log
+       grep -q '{"message":".*","code":{"code":"E0277","explanation":"\\nYou tried.*"},"level":"error","span":{.*},"children":\[{"message":"the .*","code":null,"level":"help","span":{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":0,"column_end":0},"children":\[\]},{"message":"  <u8 as core::ops::Add>","code":null,"level":"help",' foo.log
diff --git a/src/test/run-make/json-errors/foo.rs b/src/test/run-make/json-errors/foo.rs
new file mode 100644 (file)
index 0000000..4db3394
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    let x = 42 + y;
+
+    42u8 + 42i32;
+}
index e3eeeb863568800949e95c08d3bbe57d9910d2ef..56481dc646a9c5e35a694a4daac24cc24e532094 100644 (file)
@@ -35,7 +35,7 @@ impl<'a> CompilerCalls<'a> for TestCalls {
     fn early_callback(&mut self,
                       _: &getopts::Matches,
                       _: &diagnostics::registry::Registry,
-                      _: errors::emitter::ColorConfig)
+                      _: config::ErrorOutputType)
                       -> Compilation {
         self.count *= 2;
         Compilation::Continue
index a9f19c12b0278e09b1d0f122028ae1f162671f7d..bb4b9cfecf7b62b609742d245f0a3d16d66dd854 100644 (file)
@@ -8,16 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(negate_unsigned)]
-
-#[cfg(any(target_arch = "x86", target_arch = "arm"))]
+#[cfg(any(target_pointer_width = "32"))]
 fn target() {
-    assert_eq!(-1000 as usize >> 3_usize, 536870787_usize);
+    assert_eq!(-1000isize as usize >> 3_usize, 536870787_usize);
 }
 
-#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
+#[cfg(any(target_pointer_width = "64"))]
 fn target() {
-    assert_eq!(-1000 as usize >> 3_usize, 2305843009213693827_usize);
+    assert_eq!(-1000isize as usize >> 3_usize, 2305843009213693827_usize);
 }
 
 fn general() {
index e51270fdc8d21f50a31a1a4db1c6f23536bd0dfc..4e4c98e50bca167c89217ec9697e82329a7a8220 100644 (file)
@@ -21,3 +21,9 @@ pub fn main() { }
 
 #[cfg(target_arch = "aarch64")]
 pub fn main() { }
+
+#[cfg(target_arch = "powerpc64")]
+pub fn main() { }
+
+#[cfg(target_arch = "powerpc64le")]
+pub fn main() { }
index ef69946d7aa2ad27c943bd0db86744bab4088819..a4720d48213ce43f527d0a369631d4d0b11d217a 100644 (file)
@@ -35,7 +35,7 @@ pub fn main() {
     }
 
     #[main]
-    #[cfg(any(target_arch = "x86_64", target_arch = "arm", target_arch = "aarch64"))]
+    #[cfg(not(target_arch = "x86"))]
     pub fn main() {
         unsafe {
             assert_eq!(::rusti::pref_align_of::<u64>(), 8);
index 170a6c95aa8a8f0dd204c1d34dd7968449751b80..759dc515456de1784a2421661821f348a7b4a16d 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
-#![feature(negate_unsigned)]
 #![feature(intrinsics)]
 
 mod rusti {
@@ -45,10 +43,10 @@ pub fn main() {
         assert_eq!(ctpop(100u32), 3); assert_eq!(ctpop(100i32), 3);
         assert_eq!(ctpop(100u64), 3); assert_eq!(ctpop(100i64), 3);
 
-        assert_eq!(ctpop(-1u8), 8); assert_eq!(ctpop(-1i8), 8);
-        assert_eq!(ctpop(-1u16), 16); assert_eq!(ctpop(-1i16), 16);
-        assert_eq!(ctpop(-1u32), 32); assert_eq!(ctpop(-1i32), 32);
-        assert_eq!(ctpop(-1u64), 64); assert_eq!(ctpop(-1i64), 64);
+        assert_eq!(ctpop(-1i8 as u8), 8); assert_eq!(ctpop(-1i8), 8);
+        assert_eq!(ctpop(-1i16 as u16), 16); assert_eq!(ctpop(-1i16), 16);
+        assert_eq!(ctpop(-1i32 as u32), 32); assert_eq!(ctpop(-1i32), 32);
+        assert_eq!(ctpop(-1i64 as u64), 64); assert_eq!(ctpop(-1i64), 64);
 
         assert_eq!(ctlz(0u8), 8); assert_eq!(ctlz(0i8), 8);
         assert_eq!(ctlz(0u16), 16); assert_eq!(ctlz(0i16), 16);
@@ -70,10 +68,10 @@ pub fn main() {
         assert_eq!(ctlz(100u32), 25); assert_eq!(ctlz(100i32), 25);
         assert_eq!(ctlz(100u64), 57); assert_eq!(ctlz(100i64), 57);
 
-        assert_eq!(cttz(-1u8), 0); assert_eq!(cttz(-1i8), 0);
-        assert_eq!(cttz(-1u16), 0); assert_eq!(cttz(-1i16), 0);
-        assert_eq!(cttz(-1u32), 0); assert_eq!(cttz(-1i32), 0);
-        assert_eq!(cttz(-1u64), 0); assert_eq!(cttz(-1i64), 0);
+        assert_eq!(cttz(-1i8 as u8), 0); assert_eq!(cttz(-1i8), 0);
+        assert_eq!(cttz(-1i16 as u16), 0); assert_eq!(cttz(-1i16), 0);
+        assert_eq!(cttz(-1i32 as u32), 0); assert_eq!(cttz(-1i32), 0);
+        assert_eq!(cttz(-1i64 as u64), 0); assert_eq!(cttz(-1i64), 0);
 
         assert_eq!(cttz(0u8), 8); assert_eq!(cttz(0i8), 8);
         assert_eq!(cttz(0u16), 16); assert_eq!(cttz(0i16), 16);
index 93d9300edf634c599b4d569b12b256c56e242daf..5587f68bd18544465c2aa5c8fb8dd7929ed233f4 100644 (file)
@@ -23,13 +23,13 @@ impl Drop for Kitty {
     fn drop(&mut self) {}
 }
 
-#[cfg(any(target_arch = "x86_64", target_arch="aarch64"))]
+#[cfg(target_pointer_width = "64")]
 pub fn main() {
     assert_eq!(mem::size_of::<Cat>(), 8 as usize);
     assert_eq!(mem::size_of::<Kitty>(), 16 as usize);
 }
 
-#[cfg(any(target_arch = "x86", target_arch = "arm"))]
+#[cfg(target_pointer_width = "32")]
 pub fn main() {
     assert_eq!(mem::size_of::<Cat>(), 4 as usize);
     assert_eq!(mem::size_of::<Kitty>(), 8 as usize);
diff --git a/src/test/run-pass/issue-29092.rs b/src/test/run-pass/issue-29092.rs
new file mode 100644 (file)
index 0000000..c55cc91
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2012-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.
+
+// Regression test for Issue #29092.
+//
+// (Possibly redundant with regression test run-pass/issue-30530.rs)
+
+use self::Term::*;
+
+#[derive(Clone)]
+pub enum Term {
+    Dummy,
+    A(Box<Term>),
+    B(Box<Term>),
+}
+
+// a small-step evaluator
+pub fn small_eval(v: Term) -> Term {
+    match v {
+        A(t) => *t.clone(),
+        B(t) => *t.clone(),
+        _ => Dummy,
+    }
+}
+
+fn main() {
+    small_eval(Dummy);
+}
diff --git a/src/test/run-pass/issue-30018-nopanic.rs b/src/test/run-pass/issue-30018-nopanic.rs
new file mode 100644 (file)
index 0000000..25eff9d
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright 2012-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.
+
+// More thorough regression test for Issues #30018 and #30822. This
+// attempts to explore different ways that array element construction
+// (for both scratch arrays and non-scratch ones) interacts with
+// breaks in the control-flow, in terms of the order of evaluation of
+// the destructors (which may change; see RFC Issue 744) and the
+// number of times that the destructor evaluates for each value (which
+// should never exceed 1; this latter case is what #30822 is about).
+
+use std::cell::RefCell;
+
+struct D<'a>(&'a RefCell<Vec<i32>>, i32);
+
+impl<'a> Drop for D<'a> {
+    fn drop(&mut self) {
+        println!("Dropping D({})", self.1);
+        (self.0).borrow_mut().push(self.1);
+    }
+}
+
+fn main() {
+    println!("Start");
+    break_during_elem();
+    break_after_whole();
+    println!("Finis");
+}
+
+fn break_during_elem() {
+    let log = &RefCell::new(Vec::new());
+
+    // CASE 1: Fixed-size array itself is stored in _r slot.
+    loop {
+        let _r = [D(log, 10),
+                  D(log, 11),
+                  { D(log, 12); break; },
+                  D(log, 13)];
+    }
+    assert_eq!(&log.borrow()[..], &[12, 11, 10]);
+    log.borrow_mut().clear();
+
+    // CASE 2: Slice (borrow of array) is stored in _r slot.
+    // This is the case that is actually being reported in #30018.
+    loop {
+        let _r = &[D(log, 20),
+                   D(log, 21),
+                   { D(log, 22); break; },
+                   D(log, 23)];
+    }
+    assert_eq!(&log.borrow()[..], &[22, 21, 20]);
+    log.borrow_mut().clear();
+
+    // CASE 3: (Borrow of) slice-index of array is stored in _r slot.
+    loop {
+        let _r = &[D(log, 30),
+                  D(log, 31),
+                  { D(log, 32); break; },
+                  D(log, 33)][..];
+    }
+    assert_eq!(&log.borrow()[..], &[32, 31, 30]);
+    log.borrow_mut().clear();
+}
+
+// The purpose of these functions is to test what happens when we
+// panic after an array has been constructed in its entirety.
+//
+// It is meant to act as proof that we still need to continue
+// scheduling the destruction of an array even after we've scheduling
+// drop for its elements during construction; the latter is tested by
+// `fn break_during_elem()`.
+fn break_after_whole() {
+    let log = &RefCell::new(Vec::new());
+
+    // CASE 1: Fixed-size array itself is stored in _r slot.
+    loop {
+        let _r = [D(log, 10),
+                  D(log, 11),
+                  D(log, 12)];
+        break;
+    }
+    assert_eq!(&log.borrow()[..], &[10, 11, 12]);
+    log.borrow_mut().clear();
+
+    // CASE 2: Slice (borrow of array) is stored in _r slot.
+    loop {
+        let _r = &[D(log, 20),
+                   D(log, 21),
+                   D(log, 22)];
+        break;
+    }
+    assert_eq!(&log.borrow()[..], &[20, 21, 22]);
+    log.borrow_mut().clear();
+
+    // CASE 3: (Borrow of) slice-index of array is stored in _r slot.
+    loop {
+        let _r = &[D(log, 30),
+                   D(log, 31),
+                   D(log, 32)][..];
+        break;
+    }
+    assert_eq!(&log.borrow()[..], &[30, 31, 32]);
+    log.borrow_mut().clear();
+}
diff --git a/src/test/run-pass/issue-30018-panic.rs b/src/test/run-pass/issue-30018-panic.rs
new file mode 100644 (file)
index 0000000..da4d5f1
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2012-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.
+
+// Regression test for Issue #30018. This is very similar to the
+// original reported test, except that the panic is wrapped in a
+// spawned thread to isolate the expected error result from the
+// SIGTRAP injected by the drop-flag consistency checking.
+
+struct Foo;
+
+impl Drop for Foo {
+    fn drop(&mut self) {}
+}
+
+fn foo() -> Foo {
+    panic!();
+}
+
+fn main() {
+    use std::thread;
+    let handle = thread::spawn(|| {
+        let _ = &[foo()];
+    });
+    let _ = handle.join();
+}
diff --git a/src/test/run-pass/issue-30490.rs b/src/test/run-pass/issue-30490.rs
new file mode 100644 (file)
index 0000000..ea603fc
--- /dev/null
@@ -0,0 +1,107 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Previously libstd would set stdio descriptors of a child process
+// by `dup`ing the requested descriptors to inherit directly into the
+// stdio descriptors. This, however, would incorrectly handle cases
+// where the descriptors to inherit were already stdio descriptors.
+// This test checks to avoid that regression.
+
+#![cfg_attr(unix, feature(libc))]
+#![cfg_attr(windows, allow(unused_imports))]
+
+#[cfg(unix)]
+extern crate libc;
+
+use std::fs::File;
+use std::io::{Read, Write};
+use std::io::{stdout, stderr};
+use std::process::{Command, Stdio};
+
+#[cfg(unix)]
+use std::os::unix::io::FromRawFd;
+
+#[cfg(not(unix))]
+fn main() {
+    // Bug not present in Windows
+}
+
+#[cfg(unix)]
+fn main() {
+    let mut args = std::env::args();
+    let name = args.next().unwrap();
+    let args: Vec<String> = args.collect();
+    if let Some("--child") = args.get(0).map(|s| &**s) {
+        return child();
+    } else if !args.is_empty() {
+        panic!("unknown options");
+    }
+
+    let stdout_backup = unsafe { libc::dup(libc::STDOUT_FILENO) };
+    let stderr_backup = unsafe { libc::dup(libc::STDERR_FILENO) };
+    assert!(stdout_backup > -1);
+    assert!(stderr_backup > -1);
+
+    let (stdout_reader, stdout_writer) = pipe();
+    let (stderr_reader, stderr_writer) = pipe();
+    assert!(unsafe { libc::dup2(stdout_writer, libc::STDOUT_FILENO) } > -1);
+    assert!(unsafe { libc::dup2(stderr_writer, libc::STDERR_FILENO) } > -1);
+
+    // Make sure we close any duplicates of the writer end of the pipe,
+    // otherwise we can get stuck reading from the pipe which has open
+    // writers but no one supplying any input
+    assert_eq!(unsafe { libc::close(stdout_writer) }, 0);
+    assert_eq!(unsafe { libc::close(stderr_writer) }, 0);
+
+    stdout().write_all("parent stdout\n".as_bytes()).expect("failed to write to stdout");
+    stderr().write_all("parent stderr\n".as_bytes()).expect("failed to write to stderr");
+
+    let child = {
+        Command::new(name)
+            .arg("--child")
+            .stdin(Stdio::inherit())
+            .stdout(unsafe { FromRawFd::from_raw_fd(libc::STDERR_FILENO) })
+            .stderr(unsafe { FromRawFd::from_raw_fd(libc::STDOUT_FILENO) })
+            .spawn()
+    };
+
+    // The Stdio passed into the Command took over (and closed) std{out, err}
+    // so we should restore them as they were.
+    assert!(unsafe { libc::dup2(stdout_backup, libc::STDOUT_FILENO) } > -1);
+    assert!(unsafe { libc::dup2(stderr_backup, libc::STDERR_FILENO) } > -1);
+
+    // Using File as a shim around the descriptor
+    let mut read = String::new();
+    let mut f: File = unsafe { FromRawFd::from_raw_fd(stdout_reader) };
+    f.read_to_string(&mut read).expect("failed to read from stdout file");
+    assert_eq!(read, "parent stdout\nchild stderr\n");
+
+    // Using File as a shim around the descriptor
+    read.clear();
+    let mut f: File = unsafe { FromRawFd::from_raw_fd(stderr_reader) };
+    f.read_to_string(&mut read).expect("failed to read from stderr file");
+    assert_eq!(read, "parent stderr\nchild stdout\n");
+
+    assert!(child.expect("failed to execute child process").wait().unwrap().success());
+}
+
+#[cfg(unix)]
+fn child() {
+    stdout().write_all("child stdout\n".as_bytes()).expect("child failed to write to stdout");
+    stderr().write_all("child stderr\n".as_bytes()).expect("child failed to write to stderr");
+}
+
+#[cfg(unix)]
+/// Returns a pipe (reader, writer combo)
+fn pipe() -> (i32, i32) {
+     let mut fds = [0; 2];
+     assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
+     (fds[0], fds[1])
+}
diff --git a/src/test/run-pass/issue-30530.rs b/src/test/run-pass/issue-30530.rs
new file mode 100644 (file)
index 0000000..d5139c9
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2012-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.
+
+// Regression test for Issue #30530: alloca's created for storing
+// intermediate scratch values during brace-less match arms need to be
+// initialized with their drop-flag set to "dropped" (or else we end
+// up running the destructors on garbage data at the end of the
+// function).
+
+pub enum Handler {
+    Default,
+    #[allow(dead_code)]
+    Custom(*mut Box<Fn()>),
+}
+
+fn main() {
+    take(Handler::Default, Box::new(main));
+}
+
+#[inline(never)]
+pub fn take(h: Handler, f: Box<Fn()>) -> Box<Fn()> {
+    unsafe {
+        match h {
+            Handler::Custom(ptr) => *Box::from_raw(ptr),
+            Handler::Default => f,
+        }
+    }
+}
index 77c6ed4447f116a174c0ada89133f1cf1a7a0d58..c1abebd5f9040caa068c2813bbe2cafdbad9470c 100644 (file)
@@ -24,7 +24,17 @@ macro_rules! pat_if {
     }}
 }
 
+macro_rules! pat_bar {
+    ($p:pat | $p2:pat) => {{
+        match Some(1u8) {
+            $p | $p2 => {},
+            _ => {}
+        }
+    }}
+}
+
 fn main() {
     pat_in!(Some(_) in 0..10);
     pat_if!(Some(x) if x > 0);
+    pat_bar!(Some(1u8) | None);
 }
diff --git a/src/test/run-pass/macro-seq-followed-by-seq.rs b/src/test/run-pass/macro-seq-followed-by-seq.rs
new file mode 100644 (file)
index 0000000..23c7d25
--- /dev/null
@@ -0,0 +1,26 @@
+// 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.
+
+// Test of allowing two sequences repetitions in a row,
+// functionality added as byproduct of RFC amendment #1384
+//   https://github.com/rust-lang/rfcs/pull/1384
+
+// Old version of Rust would reject this macro definition, even though
+// there are no local ambiguities (the initial `banana` and `orange`
+// tokens are enough for the expander to distinguish which case is
+// intended).
+macro_rules! foo {
+    ( $(banana $a:ident)* $(orange $b:tt)* ) => { };
+}
+
+fn main() {
+    foo!( banana id1 banana id2
+          orange hi  orange (hello world) );
+}
diff --git a/src/test/run-pass/mir_constval_adts.rs b/src/test/run-pass/mir_constval_adts.rs
new file mode 100644 (file)
index 0000000..8a1f68d
--- /dev/null
@@ -0,0 +1,32 @@
+// 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)]
+
+#[derive(PartialEq, Debug)]
+struct Point {
+    _x: i32,
+    _y: i32,
+}
+const STRUCT: Point = Point { _x: 42, _y: 42 };
+const TUPLE1: (i32, i32) = (42, 42);
+const TUPLE2: (&'static str, &'static str) = ("hello","world");
+
+#[rustc_mir]
+fn mir() -> (Point, (i32, i32), (&'static str, &'static str)){
+    let struct1 = STRUCT;
+    let tuple1 = TUPLE1;
+    let tuple2 = TUPLE2;
+    (struct1, tuple1, tuple2)
+}
+
+fn main(){
+    assert_eq!(mir(), (STRUCT, TUPLE1, TUPLE2));
+}
+
index bd236e95d1c0a9db2d877ad2b7df2a0a3a2742bf..bca72330c85ad99aa8419e21b58fa3acd452be68 100644 (file)
@@ -58,16 +58,11 @@ fn test5(x: &Bar, a: isize) -> isize {
     x.extension_method(a)
 }
 
-// FIXME #30661: Although this function has the #[rustc_mir] attribute it never
-//               was translated via the MIR implementation because attributes
-//               where not passed along to trans::base::trans_fn() for generic
-//               functions.
-//               Uncomment this test once the thing it tests is fixed.
-// #[rustc_mir]
-// fn test6<T: Bar>(x: &T, a: isize) -> isize {
-//     // Test calling extension method on generic callee
-//     x.extension_method(a)
-// }
+#[rustc_mir]
+fn test6<T: Bar>(x: &T, a: isize) -> isize {
+    // Test calling extension method on generic callee
+    x.extension_method(a)
+}
 
 trait One<T = Self> {
     fn one() -> T;
@@ -119,8 +114,7 @@ fn main() {
     assert_eq!(test3(&Foo, 42), 42);
     assert_eq!(test4(&Foo, 970), 970);
     assert_eq!(test5(&Foo, 8576), 8576);
-    // see definition of test6() above
-    // assert_eq!(test6(&Foo, 12367), 12367);
+    assert_eq!(test6(&Foo, 12367), 12367);
     assert_eq!(test7(), 1);
     assert_eq!(test8(), 2);
 
index e5d76c3e67abd5f6c76dfde5afc00b35f04f6863..4a115c737da3a5752e82873a5c473475551dc274 100644 (file)
@@ -35,14 +35,6 @@ struct Outer {
     t: Inner
 }
 
-
-#[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "aarch64"))]
-mod m {
-    pub fn align() -> usize { 4 }
-    pub fn size() -> usize { 8 }
-}
-
-#[cfg(target_arch = "x86_64")]
 mod m {
     pub fn align() -> usize { 4 }
     pub fn size() -> usize { 8 }
index fc032aa3ff0cdfd45fa9642c7727d8e8e8b40b09..25cd77845ea03bf9ef8389ce4265614b549ecad6 100644 (file)
@@ -49,7 +49,7 @@ pub fn align() -> usize { 4 }
         pub fn size() -> usize { 12 }
     }
 
-    #[cfg(any(target_arch = "x86_64", target_arch = "arm", target_arch = "aarch64"))]
+    #[cfg(not(target_arch = "x86"))]
     pub mod m {
         pub fn align() -> usize { 8 }
         pub fn size() -> usize { 16 }
diff --git a/src/test/run-pass/string-box-error.rs b/src/test/run-pass/string-box-error.rs
new file mode 100644 (file)
index 0000000..a80d9a0
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Ensure that both `Box<Error + Send + Sync>` and `Box<Error>` can be obtained from `String`.
+
+use std::error::Error;
+
+fn main() {
+    let _err1: Box<Error + Send + Sync> = From::from("test".to_string());
+    let _err2: Box<Error> = From::from("test".to_string());
+    let _err3: Box<Error + Send + Sync + 'static> = From::from("test");
+    let _err4: Box<Error> = From::from("test");
+}
index 109287a83b16a88e93ced69fd83047aac5ad4188..6f23263790cb777ff0c0f8e4c56122f85598a467 100644 (file)
@@ -43,7 +43,7 @@ fn test1() {
     }
 }
 
-#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
+#[cfg(target_pointer_width = "64")]
 fn test2() {
     unsafe {
         let f = Floats { a: 1.234567890e-15_f64,
@@ -59,7 +59,7 @@ fn test2() {
     }
 }
 
-#[cfg(any(target_arch = "x86", target_arch = "arm"))]
+#[cfg(target_pointer_width = "32")]
 fn test2() {
 }
 
index fdb70fe248eff1bc456ebbf60557582488d985b0..cff260c3ba63e01f9cafd8dbeffb53d5fe6122f8 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(negate_unsigned)]
-
 pub fn main() {
     let a = 1;
     let a_neg: i8 = -a;
@@ -30,26 +28,4 @@ pub fn main() {
     let e = 1;
     let e_neg: isize = -e;
     println!("{}", e_neg);
-
-    // intentional overflows
-
-    let f = 1;
-    let f_neg: u8 = -f;
-    println!("{}", f_neg);
-
-    let g = 1;
-    let g_neg: u16 = -g;
-    println!("{}", g_neg);
-
-    let h = 1;
-    let h_neg: u32 = -h;
-    println!("{}", h_neg);
-
-    let i = 1;
-    let i_neg: u64 = -i;
-    println!("{}", i_neg);
-
-    let j = 1;
-    let j_neg: usize = -j;
-    println!("{}", j_neg);
 }