]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #36766 - nnethercote:hash-span-capacity, r=bluss
authorbors <bors@rust-lang.org>
Mon, 3 Oct 2016 11:25:58 +0000 (04:25 -0700)
committerGitHub <noreply@github.com>
Mon, 3 Oct 2016 11:25:58 +0000 (04:25 -0700)
Clarify HashMap's capacity handling.

HashMap has two notions of "capacity":

- "Usable capacity": the number of elements a hash map can hold without
  resizing. This is the meaning of "capacity" used in HashMap's API,
  e.g. the `with_capacity()` function.

- "Internal capacity": the number of allocated slots. Except for the
  zero case, it is always larger than the usable capacity (because some
  slots must be left empty) and is always a power of two.

HashMap's code is confusing because it does a poor job of
distinguishing these two meanings. I propose using two different terms
for these two concepts. Because "capacity" is already used in HashMap's
API to mean "usable capacity", I will use a different word for "internal
capacity". I propose "span", though I'm happy to consider other names.

419 files changed:
RELEASES.md
configure
mk/cfg/i686-unknown-haiku.mk [new file with mode: 0644]
mk/cfg/wasm32-unknown-emscripten.mk [new file with mode: 0644]
mk/cfg/x86_64-unknown-haiku.mk [new file with mode: 0644]
mk/main.mk
src/bootstrap/Cargo.lock
src/bootstrap/bin/rustc.rs
src/bootstrap/check.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/sanity.rs
src/bootstrap/step.rs
src/compiler-rt
src/doc/book/getting-started.md
src/doc/book/references-and-borrowing.md
src/doc/book/syntax-index.md
src/doc/book/variable-bindings.md
src/doc/grammar.md
src/doc/reference.md
src/etc/local_stage0.sh
src/liballoc/arc.rs
src/liballoc/boxed.rs
src/liballoc/lib.rs
src/liballoc/raw_vec.rs
src/liballoc/rc.rs
src/liballoc_jemalloc/build.rs
src/liballoc_jemalloc/lib.rs
src/liballoc_system/lib.rs
src/libcollections/borrow.rs
src/libcollections/lib.rs
src/libcollections/linked_list.rs
src/libcollections/macros.rs
src/libcollections/slice.rs
src/libcollections/str.rs
src/libcollections/string.rs
src/libcollections/vec.rs
src/libcollectionstest/cow_str.rs [new file with mode: 0644]
src/libcollectionstest/slice.rs
src/libcollectionstest/str.rs
src/libcompiler_builtins/build.rs
src/libcompiler_builtins/lib.rs
src/libcore/char.rs
src/libcore/clone.rs
src/libcore/cmp.rs
src/libcore/fmt/mod.rs
src/libcore/intrinsics.rs
src/libcore/iter/range.rs
src/libcore/mem.rs
src/libcore/ops.rs
src/libcoretest/char.rs
src/libcoretest/num/flt2dec/estimator.rs
src/liblibc
src/libpanic_unwind/Cargo.lock
src/libpanic_unwind/emcc.rs [new file with mode: 0644]
src/libpanic_unwind/lib.rs
src/librustc/cfg/construct.rs
src/librustc/hir/intravisit.rs
src/librustc/hir/lowering.rs
src/librustc/hir/map/def_collector.rs
src/librustc/hir/map/definitions.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/mod.rs
src/librustc/hir/pat_util.rs
src/librustc/hir/print.rs
src/librustc/infer/error_reporting.rs
src/librustc/middle/cstore.rs
src/librustc/middle/dependency_format.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/intrinsicck.rs
src/librustc/middle/liveness.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/region.rs
src/librustc/middle/stability.rs
src/librustc/middle/weak_lang_items.rs
src/librustc/mir/repr.rs
src/librustc/mir/tcx.rs
src/librustc/mir/visit.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc/ty/context.rs
src/librustc/ty/error.rs
src/librustc/ty/fast_reject.rs
src/librustc/ty/layout.rs
src/librustc/ty/mod.rs
src/librustc/ty/structural_impls.rs
src/librustc/ty/util.rs
src/librustc_back/lib.rs
src/librustc_back/target/asmjs_unknown_emscripten.rs
src/librustc_back/target/haiku_base.rs [new file with mode: 0644]
src/librustc_back/target/i686_unknown_haiku.rs [new file with mode: 0644]
src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs
src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs
src/librustc_back/target/mod.rs
src/librustc_back/target/wasm32_unknown_emscripten.rs [new file with mode: 0644]
src/librustc_back/target/x86_64_unknown_haiku.rs [new file with mode: 0644]
src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs
src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
src/librustc_borrowck/borrowck/mir/gather_moves.rs
src/librustc_borrowck/borrowck/mir/mod.rs
src/librustc_borrowck/borrowck/mir/patch.rs
src/librustc_const_eval/check_match.rs
src/librustc_const_eval/eval.rs
src/librustc_data_structures/flock.rs
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_errors/emitter.rs
src/librustc_incremental/calculate_svh/svh_visitor.rs
src/librustc_incremental/persist/directory.rs
src/librustc_incremental/persist/file_format.rs [new file with mode: 0644]
src/librustc_incremental/persist/fs.rs
src/librustc_incremental/persist/hash.rs
src/librustc_incremental/persist/load.rs
src/librustc_incremental/persist/mod.rs
src/librustc_incremental/persist/save.rs
src/librustc_lint/types.rs
src/librustc_llvm/build.rs
src/librustc_llvm/lib.rs
src/librustc_macro/lib.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/csearch.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/diagnostics.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/loader.rs
src/librustc_metadata/macro_import.rs
src/librustc_metadata/schema.rs
src/librustc_mir/build/expr/as_lvalue.rs
src/librustc_mir/build/expr/as_rvalue.rs
src/librustc_mir/build/expr/stmt.rs
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/build/misc.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/def_use.rs
src/librustc_mir/graphviz.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/cx/pattern.rs
src/librustc_mir/mir_map.rs
src/librustc_mir/pretty.rs
src/librustc_mir/transform/copy_prop.rs
src/librustc_mir/transform/instcombine.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/type_check.rs
src/librustc_passes/ast_validation.rs
src/librustc_passes/consts.rs
src/librustc_passes/static_recursion.rs
src/librustc_privacy/lib.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_resolve/resolve_imports.rs
src/librustc_trans/abi.rs
src/librustc_trans/adt.rs
src/librustc_trans/back/link.rs
src/librustc_trans/back/symbol_names.rs
src/librustc_trans/cabi_aarch64.rs
src/librustc_trans/cabi_arm.rs
src/librustc_trans/cabi_mips.rs
src/librustc_trans/cabi_mips64.rs
src/librustc_trans/cabi_powerpc.rs
src/librustc_trans/cabi_powerpc64.rs
src/librustc_trans/cabi_s390x.rs
src/librustc_trans/cabi_x86_64.rs
src/librustc_trans/common.rs
src/librustc_trans/debuginfo/create_scope_map.rs
src/librustc_trans/glue.rs
src/librustc_trans/mir/analyze.rs
src/librustc_trans/mir/block.rs
src/librustc_trans/mir/constant.rs
src/librustc_trans/mir/lvalue.rs
src/librustc_trans/mir/mod.rs
src/librustc_trans/mir/operand.rs
src/librustc_trans/mir/statement.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/compare_method.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/coherence/mod.rs
src/librustc_typeck/coherence/orphan.rs
src/librustc_typeck/coherence/overlap.rs
src/librustc_typeck/coherence/unsafety.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/diagnostics.rs
src/librustc_unicode/char.rs
src/librustc_unicode/u_str.rs
src/librustdoc/clean/mod.rs
src/librustdoc/core.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/rustdoc.css
src/librustdoc/lib.rs
src/librustdoc/passes.rs [deleted file]
src/librustdoc/passes/collapse_docs.rs [new file with mode: 0644]
src/librustdoc/passes/mod.rs [new file with mode: 0644]
src/librustdoc/passes/strip_hidden.rs [new file with mode: 0644]
src/librustdoc/passes/strip_priv_imports.rs [new file with mode: 0644]
src/librustdoc/passes/strip_private.rs [new file with mode: 0644]
src/librustdoc/passes/unindent_comments.rs [new file with mode: 0644]
src/librustdoc/test.rs
src/libserialize/json.rs
src/libstd/collections/hash/map.rs
src/libstd/collections/hash/set.rs
src/libstd/collections/hash/table.rs
src/libstd/env.rs
src/libstd/ffi/c_str.rs
src/libstd/ffi/os_str.rs
src/libstd/fs.rs
src/libstd/io/buffered.rs
src/libstd/io/mod.rs
src/libstd/io/stdio.rs
src/libstd/lib.rs
src/libstd/macros.rs
src/libstd/memchr.rs
src/libstd/net/addr.rs
src/libstd/net/ip.rs
src/libstd/net/mod.rs
src/libstd/net/tcp.rs
src/libstd/net/test.rs
src/libstd/net/udp.rs
src/libstd/os/haiku/fs.rs [new file with mode: 0644]
src/libstd/os/haiku/mod.rs [new file with mode: 0644]
src/libstd/os/haiku/raw.rs [new file with mode: 0644]
src/libstd/os/linux/raw.rs
src/libstd/os/mod.rs
src/libstd/path.rs
src/libstd/process.rs
src/libstd/rand/mod.rs
src/libstd/rt.rs
src/libstd/rtdeps.rs
src/libstd/sync/barrier.rs
src/libstd/sync/condvar.rs
src/libstd/sync/mpsc/mod.rs
src/libstd/sync/mpsc/mpsc_queue.rs
src/libstd/sync/mpsc/select.rs
src/libstd/sync/mpsc/spsc_queue.rs
src/libstd/sync/mutex.rs
src/libstd/sync/once.rs
src/libstd/sync/rwlock.rs
src/libstd/sys/common/args.rs [deleted file]
src/libstd/sys/common/io.rs
src/libstd/sys/common/memchr.rs [new file with mode: 0644]
src/libstd/sys/common/mod.rs
src/libstd/sys/common/net.rs
src/libstd/sys/common/remutex.rs
src/libstd/sys/common/wtf8.rs
src/libstd/sys/unix/args.rs [new file with mode: 0644]
src/libstd/sys/unix/env.rs [new file with mode: 0644]
src/libstd/sys/unix/ext/net.rs
src/libstd/sys/unix/fd.rs
src/libstd/sys/unix/fs.rs
src/libstd/sys/unix/memchr.rs [new file with mode: 0644]
src/libstd/sys/unix/mod.rs
src/libstd/sys/unix/net.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/unix/path.rs [new file with mode: 0644]
src/libstd/sys/unix/process.rs
src/libstd/sys/unix/stdio.rs
src/libstd/sys/unix/thread.rs
src/libstd/sys/windows/args.rs [new file with mode: 0644]
src/libstd/sys/windows/env.rs [new file with mode: 0644]
src/libstd/sys/windows/memchr.rs [new file with mode: 0644]
src/libstd/sys/windows/mod.rs
src/libstd/sys/windows/os.rs
src/libstd/sys/windows/path.rs [new file with mode: 0644]
src/libstd/sys/windows/stdio.rs
src/libstd/thread/local.rs
src/libstd/thread/mod.rs
src/libstd/time/mod.rs
src/libsyntax/abi.rs
src/libsyntax/ast.rs
src/libsyntax/config.rs
src/libsyntax/diagnostics/plugin.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/build.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/hygiene.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/json.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/test.rs
src/libsyntax/visit.rs
src/libsyntax_ext/asm.rs
src/libsyntax_ext/concat_idents.rs
src/libsyntax_ext/deriving/generic/mod.rs
src/libsyntax_ext/deriving/generic/ty.rs
src/libsyntax_ext/deriving/mod.rs
src/libsyntax_ext/format.rs
src/libsyntax_ext/lib.rs
src/libsyntax_ext/log_syntax.rs
src/libsyntax_ext/trace_macros.rs
src/libterm/terminfo/searcher.rs
src/libtest/lib.rs
src/libunwind/libunwind.rs
src/llvm
src/rustllvm/ArchiveWrapper.cpp
src/rustllvm/PassWrapper.cpp
src/rustllvm/RustWrapper.cpp
src/rustllvm/llvm-auto-clean-trigger
src/rustllvm/rustllvm.h
src/stage0.txt
src/test/codegen-units/item-collection/overloaded-operators.rs
src/test/codegen/lifetime_start_end.rs
src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs
src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs [deleted file]
src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs [deleted file]
src/test/compile-fail/E0025.rs
src/test/compile-fail/E0033.rs
src/test/compile-fail/E0035.rs
src/test/compile-fail/E0036.rs
src/test/compile-fail/E0050.rs
src/test/compile-fail/E0220.rs
src/test/compile-fail/E0446.rs
src/test/compile-fail/E0449.rs
src/test/compile-fail/E0512.rs
src/test/compile-fail/E0513.rs [new file with mode: 0644]
src/test/compile-fail/allocator-dylib-is-system.rs
src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs
src/test/compile-fail/attr-on-generic-formals-are-visited.rs [new file with mode: 0644]
src/test/compile-fail/attr-on-generic-formals-wo-feature-gate.rs [new file with mode: 0644]
src/test/compile-fail/attrs-with-no-formal-in-generics-1.rs [new file with mode: 0644]
src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs [new file with mode: 0644]
src/test/compile-fail/attrs-with-no-formal-in-generics-3.rs [new file with mode: 0644]
src/test/compile-fail/bad-expr-path.rs
src/test/compile-fail/bad-expr-path2.rs
src/test/compile-fail/discrim-overflow-2.rs
src/test/compile-fail/discrim-overflow.rs
src/test/compile-fail/gated-non-ascii-idents.rs
src/test/compile-fail/issue-14254.rs
src/test/compile-fail/issue-15260.rs
src/test/compile-fail/issue-21146.rs
src/test/compile-fail/issue-2356.rs
src/test/compile-fail/issue-32922.rs
src/test/compile-fail/issue-36881.rs [new file with mode: 0644]
src/test/compile-fail/issue-5067.rs [new file with mode: 0644]
src/test/compile-fail/macro-context.rs
src/test/compile-fail/macro-shadowing.rs [new file with mode: 0644]
src/test/compile-fail/paths-in-macro-invocations.rs [new file with mode: 0644]
src/test/compile-fail/platform-intrinsic-params.rs [new file with mode: 0644]
src/test/compile-fail/resolve-hint-macro.rs
src/test/compile-fail/self_type_keyword.rs
src/test/compile-fail/token-error-correct-2.rs
src/test/compile-fail/token-error-correct-3.rs
src/test/compile-fail/token-error-correct.rs
src/test/compile-fail/typo-suggestion.rs [deleted file]
src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs
src/test/incremental/cache_file_headers.rs [new file with mode: 0644]
src/test/incremental/change_crate_order/auxiliary/a.rs [new file with mode: 0644]
src/test/incremental/change_crate_order/auxiliary/b.rs [new file with mode: 0644]
src/test/incremental/change_crate_order/main.rs [new file with mode: 0644]
src/test/incremental/hashes/enum_defs.rs [new file with mode: 0644]
src/test/mir-opt/deaggregator_test.rs
src/test/mir-opt/deaggregator_test_enum.rs
src/test/mir-opt/simplify_if.rs
src/test/mir-opt/storage_ranges.rs
src/test/parse-fail/extern-no-fn.rs
src/test/parse-fail/issue-21153.rs
src/test/run-fail/panic-task-name-none.rs
src/test/run-fail/panic-task-name-owned.rs
src/test/run-fail/task-spawn-barefn.rs
src/test/run-fail/test-panic.rs
src/test/run-fail/test-should-fail-bad-message.rs
src/test/run-fail/test-tasks-invalid-value.rs
src/test/run-make/link-arg/Makefile [new file with mode: 0644]
src/test/run-make/link-arg/empty.rs [new file with mode: 0644]
src/test/run-make/llvm-phase/test.rs
src/test/run-make/rustc-macro-dep-files/Makefile [new file with mode: 0644]
src/test/run-make/rustc-macro-dep-files/bar.rs [new file with mode: 0644]
src/test/run-make/rustc-macro-dep-files/foo.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/compiler-calls.rs
src/test/run-pass-fulldeps/rustc-macro/append-impl.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/rustc-macro/auxiliary/append-impl.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs
src/test/run-pass/allocator-override.rs
src/test/run-pass/attr-on-generic-formals.rs [new file with mode: 0644]
src/test/run-pass/cstring-drop.rs [deleted file]
src/test/run-pass/deriving-show.rs
src/test/run-pass/discriminant_value-wrapper.rs [new file with mode: 0644]
src/test/run-pass/extern-pass-empty.rs
src/test/run-pass/fds-are-cloexec.rs
src/test/run-pass/format-no-std.rs
src/test/run-pass/hygiene.rs
src/test/run-pass/issue-18088.rs [new file with mode: 0644]
src/test/run-pass/issue-36768.rs [new file with mode: 0644]
src/test/run-pass/issue-36786-resolve-call.rs [new file with mode: 0644]
src/test/run-pass/issue-36816.rs [new file with mode: 0644]
src/test/run-pass/mod_dir_path.rs
src/test/run-pass/packed-struct-layout.rs
src/test/run-pass/packed-tuple-struct-layout.rs
src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs
src/test/run-pass/panic-runtime/abort.rs
src/test/run-pass/panic-runtime/lto-abort.rs
src/test/run-pass/panic-runtime/lto-unwind.rs
src/test/run-pass/process-status-inherits-stdin.rs
src/test/run-pass/range_inclusive.rs
src/test/run-pass/simd-intrinsic-generic-cast.rs
src/test/run-pass/task-stderr.rs
src/test/ui/codemap_tests/tab.stderr
src/test/ui/macros/macro-backtrace-nested.stderr
src/test/ui/span/type-binding.stderr
src/test/ui/span/typo-suggestion.rs [new file with mode: 0644]
src/test/ui/span/typo-suggestion.stderr [new file with mode: 0644]
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/compiletest/src/util.rs
src/tools/tidy/src/main.rs
src/tools/tidy/src/pal.rs [new file with mode: 0644]

index 8817d7f88a73801e64c16b5f127f6404ebfc9a1f..e6f18f9f7ba557726f9078ac320e0577a92318ae 100644 (file)
@@ -1,3 +1,259 @@
+Version 1.12.0 (2016-09-29)
+===========================
+
+Highlights
+----------
+
+* [`rustc` translates code to LLVM IR via its own "middle" IR (MIR)]
+  (https://github.com/rust-lang/rust/pull/34096).
+  This translation pass is far simpler than the previous AST->LLVM pass, and
+  creates opportunities to perform new optimizations directly on the MIR. It
+  was previously described [on the Rust blog]
+  (https://blog.rust-lang.org/2016/04/19/MIR.html).
+* [`rustc` presents a new, more readable error format, along with
+  machine-readable JSON error output for use by IDEs]
+  (https://github.com/rust-lang/rust/pull/35401).
+  Most common editors supporting Rust have been updated to work with it. It was
+  previously described [on the Rust blog]
+  (https://blog.rust-lang.org/2016/08/10/Shape-of-errors-to-come.html).
+
+Compiler
+--------
+
+* [`rustc` translates code to LLVM IR via its own "middle" IR (MIR)]
+  (https://github.com/rust-lang/rust/pull/34096).
+  This translation pass is far simpler than the previous AST->LLVM pass, and
+  creates opportunities to perform new optimizations directly on the MIR. It
+  was previously described [on the Rust blog]
+  (https://blog.rust-lang.org/2016/04/19/MIR.html).
+* [Print the Rust target name, not the LLVM target name, with
+  `--print target-list`]
+  (https://github.com/rust-lang/rust/pull/35489)
+* [The computation of `TypeId` is correct in some cases where it was previously
+  producing inconsistent results]
+  (https://github.com/rust-lang/rust/pull/35267)
+* [The `mips-unknown-linux-gnu` target uses hardware floating point by default]
+  (https://github.com/rust-lang/rust/pull/34910)
+* [The `rustc` arguments, `--print target-cpus`, `--print target-features`,
+  `--print relocation-models`, and `--print code-models` print the available
+  options to the `-C target-cpu`, `-C target-feature`, `-C relocation-model` and
+  `-C code-model` code generation arguments]
+  (https://github.com/rust-lang/rust/pull/34845)
+* [`rustc` supports three new MUSL targets on ARM: `arm-unknown-linux-musleabi`,
+  `arm-unknown-linux-musleabihf`, and `armv7-unknown-linux-musleabihf`]
+  (https://github.com/rust-lang/rust/pull/35060).
+  These targets produce statically-linked binaries. There are no binary release
+  builds yet though.
+
+Diagnostics
+-----------
+
+* [`rustc` presents a new, more readable error format, along with
+  machine-readable JSON error output for use by IDEs]
+  (https://github.com/rust-lang/rust/pull/35401).
+  Most common editors supporting Rust have been updated to work with it. It was
+  previously described [on the Rust blog]
+  (https://blog.rust-lang.org/2016/08/10/Shape-of-errors-to-come.html).
+* [In error descriptions, references are now described in plain English,
+  instead of as "&-ptr"]
+  (https://github.com/rust-lang/rust/pull/35611)
+* [In error type descriptions, unknown numeric types are named `{integer}` or
+  `{float}` instead of `_`]
+  (https://github.com/rust-lang/rust/pull/35080)
+* [`rustc` emits a clearer error when inner attributes follow a doc comment]
+  (https://github.com/rust-lang/rust/pull/34676)
+
+Language
+--------
+
+* [`macro_rules!` invocations can be made within `macro_rules!` invocations]
+  (https://github.com/rust-lang/rust/pull/34925)
+* [`macro_rules!` meta-variables are hygienic]
+  (https://github.com/rust-lang/rust/pull/35453)
+* [`macro_rules!` `tt` matchers can be reparsed correctly, making them much more
+  useful]
+  (https://github.com/rust-lang/rust/pull/34908)
+* [`macro_rules!` `stmt` matchers correctly consume the entire contents when
+  inside non-braces invocations]
+  (https://github.com/rust-lang/rust/pull/34886)
+* [Semicolons are properly required as statement delimeters inside
+  `macro_rules!` invocations]
+  (https://github.com/rust-lang/rust/pull/34660)
+* [`cfg_attr` works on `path` attributes]
+  (https://github.com/rust-lang/rust/pull/34546)
+
+Stabilized APIs
+---------------
+
+* [`Cell::as_ptr`]
+  (https://doc.rust-lang.org/std/cell/struct.Cell.html#method.as_ptr)
+* [`RefCell::as_ptr`]
+  (https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.as_ptr)
+* [`IpAddr::is_unspecified`]
+  (https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_unspecified)
+* [`IpAddr::is_loopback`]
+  (https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_loopback)
+* [`IpAddr::is_multicast`]
+  (https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_multicast)
+* [`Ipv4Addr::is_unspecified`]
+  (https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html#method.is_unspecified)
+* [`Ipv6Addr::octets`]
+  (https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html#method.octets)
+* [`LinkedList::contains`]
+  (https://doc.rust-lang.org/std/collections/linked_list/struct.LinkedList.html#method.contains)
+* [`VecDeque::contains`]
+  (https://doc.rust-lang.org/std/collections/vec_deque/struct.VecDeque.html#method.contains)
+* [`ExitStatusExt::from_raw`]
+  (https://doc.rust-lang.org/std/os/unix/process/trait.ExitStatusExt.html#tymethod.from_raw).
+  Both on Unix and Windows.
+* [`Receiver::recv_timeout`]
+  (https://doc.rust-lang.org/std/sync/mpsc/struct.Receiver.html#method.recv_timeout)
+* [`RecvTimeoutError`]
+  (https://doc.rust-lang.org/std/sync/mpsc/enum.RecvTimeoutError.html)
+* [`BinaryHeap::peek_mut`]
+  (https://doc.rust-lang.org/std/collections/binary_heap/struct.BinaryHeap.html#method.peek_mut)
+* [`PeekMut`]
+  (https://doc.rust-lang.org/std/collections/binary_heap/struct.PeekMut.html)
+* [`iter::Product`]
+  (https://doc.rust-lang.org/std/iter/trait.Product.html)
+* [`iter::Sum`]
+  (https://doc.rust-lang.org/std/iter/trait.Sum.html)
+* [`OccupiedEntry::remove_entry`]
+  (https://doc.rust-lang.org/std/collections/btree_map/struct.OccupiedEntry.html#method.remove_entry)
+* [`VacantEntry::into_key`]
+  (https://doc.rust-lang.org/std/collections/btree_map/struct.VacantEntry.html#method.into_key)
+
+Libraries
+---------
+
+* [The `format!` macro and friends now allow a single argument to be formatted
+  in multiple styles]
+  (https://github.com/rust-lang/rust/pull/33642)
+* [The lifetime bounds on `[T]::binary_search_by` and
+  `[T]::binary_search_by_key` have been adjusted to be more flexible]
+  (https://github.com/rust-lang/rust/pull/34762)
+* [`Option` implements `From` for its contained type]
+  (https://github.com/rust-lang/rust/pull/34828)
+* [`Cell`, `RefCell` and `UnsafeCell` implement `From` for their contained type]
+  (https://github.com/rust-lang/rust/pull/35392)
+* [`RwLock` panics if the reader count overflows]
+  (https://github.com/rust-lang/rust/pull/35378)
+* [`vec_deque::Drain`, `hash_map::Drain` and `hash_set::Drain` are covariant]
+  (https://github.com/rust-lang/rust/pull/35354)
+* [`vec::Drain` and `binary_heap::Drain` are covariant]
+  (https://github.com/rust-lang/rust/pull/34951)
+* [`Cow<str>` implements `FromIterator` for `char`, `&str` and `String`]
+  (https://github.com/rust-lang/rust/pull/35064)
+* [Sockets on Linux are correctly closed in subprocesses via `SOCK_CLOEXEC`]
+  (https://github.com/rust-lang/rust/pull/34946)
+* [`hash_map::Entry`, `hash_map::VacantEntry` and `hash_map::OccupiedEntry`
+  implement `Debug`]
+  (https://github.com/rust-lang/rust/pull/34937)
+* [`btree_map::Entry`, `btree_map::VacantEntry` and `btree_map::OccupiedEntry`
+  implement `Debug`]
+  (https://github.com/rust-lang/rust/pull/34885)
+* [`String` implements `AddAssign`]
+  (https://github.com/rust-lang/rust/pull/34890)
+* [Variadic `extern fn` pointers implement the `Clone`, `PartialEq`, `Eq`,
+  `PartialOrd`, `Ord`, `Hash`, `fmt::Pointer`, and `fmt::Debug` traits]
+  (https://github.com/rust-lang/rust/pull/34879)
+* [`FileType` implements `Debug`]
+  (https://github.com/rust-lang/rust/pull/34757)
+* [References to `Mutex` and `RwLock` are unwind-safe]
+  (https://github.com/rust-lang/rust/pull/34756)
+* [`mpsc::sync_channel` `Receiver`s return any available message before
+  reporting a disconnect]
+  (https://github.com/rust-lang/rust/pull/34731)
+* [Unicode definitions have been updated to 9.0]
+  (https://github.com/rust-lang/rust/pull/34599)
+* [`env` iterators implement `DoubleEndedIterator`]
+  (https://github.com/rust-lang/rust/pull/33312)
+
+Cargo
+-----
+
+* [Support local mirrors of registries]
+  (https://github.com/rust-lang/cargo/pull/2857)
+* [Add support for command aliases]
+  (https://github.com/rust-lang/cargo/pull/2679)
+* [Allow `opt-level="s"` / `opt-level="z"` in profile overrides]
+  (https://github.com/rust-lang/cargo/pull/3007)
+* [Make `cargo doc --open --target` work as expected]
+  (https://github.com/rust-lang/cargo/pull/2988)
+* [Speed up noop registry updates]
+  (https://github.com/rust-lang/cargo/pull/2974)
+* [Update OpenSSL]
+  (https://github.com/rust-lang/cargo/pull/2971)
+* [Fix `--panic=abort` with plugins]
+  (https://github.com/rust-lang/cargo/pull/2954)
+* [Always pass `-C metadata` to the compiler]
+  (https://github.com/rust-lang/cargo/pull/2946)
+* [Fix depending on git repos with workspaces]
+  (https://github.com/rust-lang/cargo/pull/2938)
+* [Add a `--lib` flag to `cargo new`]
+  (https://github.com/rust-lang/cargo/pull/2921)
+* [Add `http.cainfo` for custom certs]
+  (https://github.com/rust-lang/cargo/pull/2917)
+* [Indicate the compilation profile after compiling]
+  (https://github.com/rust-lang/cargo/pull/2909)
+* [Allow enabling features for dependencies with `--features`]
+  (https://github.com/rust-lang/cargo/pull/2876)
+* [Add `--jobs` flag to `cargo package`]
+  (https://github.com/rust-lang/cargo/pull/2867)
+* [Add `--dry-run` to `cargo publish`]
+  (https://github.com/rust-lang/cargo/pull/2849)
+* [Add support for `RUSTDOCFLAGS`]
+  (https://github.com/rust-lang/cargo/pull/2794)
+
+Performance
+-----------
+
+* [`panic::catch_unwind` is more optimized]
+  (https://github.com/rust-lang/rust/pull/35444)
+* [`panic::catch_unwind` no longer accesses thread-local storage on entry]
+  (https://github.com/rust-lang/rust/pull/34866)
+
+Tooling
+-------
+
+* [Test binaries now support a `--test-threads` argument to specify the number
+  of threads used to run tests, and which acts the same as the
+  `RUST_TEST_THREADS` environment variable]
+  (https://github.com/rust-lang/rust/pull/35414)  
+* [The test runner now emits a warning when tests run over 60 seconds]
+  (https://github.com/rust-lang/rust/pull/35405)
+* [rustdoc: Fix methods in search results]
+  (https://github.com/rust-lang/rust/pull/34752)
+* [`rust-lldb` warns about unsupported versions of LLDB]
+  (https://github.com/rust-lang/rust/pull/34646)
+* [Rust releases now come with source packages that can be installed by rustup
+  via `rustup component add rust-src`]
+  (https://github.com/rust-lang/rust/pull/34366).
+  The resulting source code can be used by tools and IDES, located in the
+  sysroot under `lib/rustlib/src`.
+
+Misc
+----
+
+* [The compiler can now be built against LLVM 3.9]
+  (https://github.com/rust-lang/rust/pull/35594)
+* Many minor improvements to the documentation.
+* [The Rust exception handling "personality" routine is now written in Rust]
+  (https://github.com/rust-lang/rust/pull/34832)
+
+Compatibility Notes
+-------------------
+
+* [When printing Windows `OsStr`s, unpaired surrogate codepoints are escaped
+  with the lowercase format instead of the uppercase]
+  (https://github.com/rust-lang/rust/pull/35084)
+* [When formatting strings, if "precision" is specified, the "fill",
+  "align" and "width" specifiers are no longer ignored]
+  (https://github.com/rust-lang/rust/pull/34544)
+* [The `Debug` impl for strings no longer escapes all non-ASCII characters]
+  (https://github.com/rust-lang/rust/pull/34485)
+
+
 Version 1.11.0 (2016-08-18)
 ===========================
 
@@ -629,7 +885,7 @@ Cargo
 Performance
 -----------
 
-* [The time complexity of comparing variables for equivalence during type 
+* [The time complexity of comparing variables for equivalence during type
   unification is reduced from _O_(_n_!) to _O_(_n_)][1.9tu]. This leads
   to major compilation time improvement in some scenarios.
 * [`ToString` is specialized for `str`, giving it the same performance
index 586b29646c59ea7ac0945c3c72ab7afc0d94ec2a..59a3c1c828d4edfddc9b1fdd736d281bcf4b11f0 100755 (executable)
--- a/configure
+++ b/configure
@@ -437,6 +437,10 @@ case $CFG_OSTYPE in
         CFG_CPUTYPE=$(isainfo -n)
         ;;
 
+    Haiku)
+        CFG_OSTYPE=unknown-haiku
+        ;;
+
     MINGW*)
         # msys' `uname` does not print gcc configuration, but prints msys
         # configuration. so we cannot believe `uname -m`:
@@ -532,6 +536,10 @@ case $CFG_CPUTYPE in
         CFG_CPUTYPE=x86_64
         ;;
 
+    BePC)
+        CFG_CPUTYPE=i686
+        ;;
+
     *)
         err "unknown CPU type: $CFG_CPUTYPE"
 esac
@@ -637,7 +645,6 @@ valopt datadir "${CFG_PREFIX}/share" "install data"
 valopt infodir "${CFG_PREFIX}/share/info" "install additional info"
 valopt llvm-root "" "set LLVM root"
 valopt python "" "set path to python"
-valopt nodejs "" "set path to nodejs"
 valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
 valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
 valopt android-cross-path "" "Android NDK standalone path (deprecated)"
@@ -754,9 +761,6 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then
     err "Found $python_version, but Python 2.7 is required"
 fi
 
-# Checking for node, but not required
-probe CFG_NODEJS nodejs node
-
 # If we have no git directory then we are probably a tarball distribution
 # and shouldn't attempt to load submodules
 if [ ! -e ${CFG_SRC_DIR}.git ]
diff --git a/mk/cfg/i686-unknown-haiku.mk b/mk/cfg/i686-unknown-haiku.mk
new file mode 100644 (file)
index 0000000..cbacbff
--- /dev/null
@@ -0,0 +1,27 @@
+# i686-unknown-haiku configuration
+CROSS_PREFIX_i686-unknown-haiku=i586-pc-haiku-
+CC_i686-unknown-haiku=$(CC)
+CXX_i686-unknown-haiku=$(CXX)
+CPP_i686-unknown-haiku=$(CPP)
+AR_i686-unknown-haiku=$(AR)
+CFG_LIB_NAME_i686-unknown-haiku=lib$(1).so
+CFG_STATIC_LIB_NAME_i686-unknown-haiku=lib$(1).a
+CFG_LIB_GLOB_i686-unknown-haiku=lib$(1)-*.so
+CFG_LIB_DSYM_GLOB_i686-unknown-haiku=lib$(1)-*.dylib.dSYM
+CFG_CFLAGS_i686-unknown-haiku := -m32 $(CFLAGS)
+CFG_GCCISH_CFLAGS_i686-unknown-haiku := -Wall -Werror -g -fPIC -m32 $(CFLAGS)
+CFG_GCCISH_CXXFLAGS_i686-unknown-haiku := -fno-rtti $(CXXFLAGS)
+CFG_GCCISH_LINK_FLAGS_i686-unknown-haiku := -shared -fPIC -ldl -pthread  -lrt -g -m32
+CFG_GCCISH_PRE_LIB_FLAGS_i686-unknown-haiku := -Wl,-whole-archive
+CFG_GCCISH_POST_LIB_FLAGS_i686-unknown-haiku := -Wl,-no-whole-archive
+CFG_DEF_SUFFIX_i686-unknown-haiku := .linux.def
+CFG_LLC_FLAGS_i686-unknown-haiku :=
+CFG_INSTALL_NAME_i686-unknown-haiku =
+CFG_EXE_SUFFIX_i686-unknown-haiku =
+CFG_WINDOWSY_i686-unknown-haiku :=
+CFG_UNIXY_i686-unknown-haiku := 1
+CFG_PATH_MUNGE_i686-unknown-haiku := true
+CFG_LDPATH_i686-unknown-haiku :=
+CFG_RUN_i686-unknown-haiku=$(2)
+CFG_RUN_TARG_i686-unknown-haiku=$(call CFG_RUN_i686-unknown-haiku,,$(2))
+CFG_GNU_TRIPLE_i686-unknown-haiku := i686-unknown-haiku
diff --git a/mk/cfg/wasm32-unknown-emscripten.mk b/mk/cfg/wasm32-unknown-emscripten.mk
new file mode 100644 (file)
index 0000000..997bdfb
--- /dev/null
@@ -0,0 +1,24 @@
+# wasm32-unknown-emscripten configuration
+CC_wasm32-unknown-emscripten=emcc
+CXX_wasm32-unknown-emscripten=em++
+CPP_wasm32-unknown-emscripten=$(CPP)
+AR_wasm32-unknown-emscripten=emar
+CFG_LIB_NAME_wasm32-unknown-emscripten=lib$(1).so
+CFG_STATIC_LIB_NAME_wasm32-unknown-emscripten=lib$(1).a
+CFG_LIB_GLOB_wasm32-unknown-emscripten=lib$(1)-*.so
+CFG_LIB_DSYM_GLOB_wasm32-unknown-emscripten=lib$(1)-*.dylib.dSYM
+CFG_JEMALLOC_CFLAGS_wasm32-unknown-emscripten := -m32 $(CFLAGS)
+CFG_GCCISH_CFLAGS_wasm32-unknown-emscripten :=  -g -fPIC -m32 -s BINARYEN=1 $(CFLAGS)
+CFG_GCCISH_CXXFLAGS_wasm32-unknown-emscripten := -fno-rtti -s BINARYEN=1 $(CXXFLAGS)
+CFG_GCCISH_LINK_FLAGS_wasm32-unknown-emscripten := -shared -fPIC -ldl -pthread  -lrt -g -m32 -s BINARYEN=1
+CFG_GCCISH_DEF_FLAG_wasm32-unknown-emscripten := -Wl,--export-dynamic,--dynamic-list=
+CFG_LLC_FLAGS_wasm32-unknown-emscripten :=
+CFG_INSTALL_NAME_wasm32-unknown-emscripten =
+CFG_EXE_SUFFIX_wasm32-unknown-emscripten =
+CFG_WINDOWSY_wasm32-unknown-emscripten :=
+CFG_UNIXY_wasm32-unknown-emscripten := 1
+CFG_LDPATH_wasm32-unknown-emscripten :=
+CFG_RUN_wasm32-unknown-emscripten=$(2)
+CFG_RUN_TARG_wasm32-unknown-emscripten=$(call CFG_RUN_wasm32-unknown-emscripten,,$(2))
+CFG_GNU_TRIPLE_wasm32-unknown-emscripten := wasm32-unknown-emscripten
+CFG_DISABLE_JEMALLOC_wasm32-unknown-emscripten := 1
diff --git a/mk/cfg/x86_64-unknown-haiku.mk b/mk/cfg/x86_64-unknown-haiku.mk
new file mode 100644 (file)
index 0000000..4c2d888
--- /dev/null
@@ -0,0 +1,27 @@
+# x86_64-unknown-haiku configuration
+CROSS_PREFIX_x86_64-unknown-haiku=x86_64-unknown-haiku-
+CC_x86_64-unknown-haiku=$(CC)
+CXX_x86_64-unknown-haiku=$(CXX)
+CPP_x86_64-unknown-haiku=$(CPP)
+AR_x86_64-unknown-haiku=$(AR)
+CFG_LIB_NAME_x86_64-unknown-haiku=lib$(1).so
+CFG_STATIC_LIB_NAME_x86_64-unknown-haiku=lib$(1).a
+CFG_LIB_GLOB_x86_64-unknown-haiku=lib$(1)-*.so
+CFG_LIB_DSYM_GLOB_x86_64-unknown-haiku=lib$(1)-*.dylib.dSYM
+CFG_CFLAGS_x86_64-unknown-haiku := -m64 $(CFLAGS)
+CFG_GCCISH_CFLAGS_x86_64-unknown-haiku := -Wall -Werror -g -fPIC -m64 $(CFLAGS)
+CFG_GCCISH_CXXFLAGS_x86_64-unknown-haiku := -fno-rtti $(CXXFLAGS)
+CFG_GCCISH_LINK_FLAGS_x86_64-unknown-haiku := -shared -fPIC -ldl -pthread -lrt -g -m64
+CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-haiku := -Wl,-whole-archive
+CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-haiku := -Wl,-no-whole-archive
+CFG_DEF_SUFFIX_x86_64-unknown-haiku := .linux.def
+CFG_LLC_FLAGS_x86_64-unknown-haiku :=
+CFG_INSTALL_NAME_x86_64-unknown-haiku =
+CFG_EXE_SUFFIX_x86_64-unknown-haiku =
+CFG_WINDOWSY_x86_64-unknown-haiku :=
+CFG_UNIXY_x86_64-unknown-haiku := 1
+CFG_PATH_MUNGE_x86_64-unknown-haiku := true
+CFG_LDPATH_x86_64-unknown-haiku :=
+CFG_RUN_x86_64-unknown-haiku=$(2)
+CFG_RUN_TARG_x86_64-unknown-haiku=$(call CFG_RUN_x86_64-unknown-haiku,,$(2))
+CFG_GNU_TRIPLE_x86_64-unknown-haiku := x86_64-unknown-haiku
index 7dcf3a7f3acd4bd28fa2efd18f24cb5322773523..e68a8f3005561d56309527c7ac1de40c82e0ae93 100644 (file)
@@ -13,7 +13,7 @@
 ######################################################################
 
 # The version number
-CFG_RELEASE_NUM=1.13.0
+CFG_RELEASE_NUM=1.14.0
 
 # An optional number to put after the label, e.g. '.2' -> '-beta.2'
 # NB Make sure it starts with a dot to conform to semver pre-release
@@ -300,7 +300,7 @@ endif
 # LLVM macros
 ######################################################################
 
-LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz
+LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend
 LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \
                 interpreter instrumentation
 
@@ -512,10 +512,14 @@ ifeq ($$(OSTYPE_$(3)),apple-darwin)
 else
 ifeq ($$(CFG_WINDOWSY_$(3)),1)
   LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := PATH
+else
+ifeq ($$(OSTYPE_$(3)),unknown-haiku)
+  LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := LIBRARY_PATH
 else
   LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := LD_LIBRARY_PATH
 endif
 endif
+endif
 
 LD_LIBRARY_PATH_ENV_HOSTDIR$(1)_T_$(2)_H_$(3) := \
     $$(CURDIR)/$$(HLIB$(1)_H_$(3)):$$(CFG_LLVM_INST_DIR_$(3))/lib
index 36b94e4ebea32d4136abc26919eb7f89f4fe0d8d..babbb6a16bae0002e1b4506e13394f6e60986e15 100644 (file)
@@ -5,16 +5,16 @@ dependencies = [
  "build_helper 0.1.0",
  "cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)",
+ "gcc 0.3.35 (git+https://github.com/alexcrichton/gcc-rs)",
  "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -34,7 +34,7 @@ name = "cmake"
 version = "0.1.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -42,17 +42,17 @@ name = "filetime"
 version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gcc"
-version = "0.3.31"
-source = "git+https://github.com/alexcrichton/gcc-rs#b8e2400883f1a2749b323354dad372cdd1c838c7"
+version = "0.3.35"
+source = "git+https://github.com/alexcrichton/gcc-rs#8ff5360b6e0dc4f3c9d3f71036f1ff403c68469d"
 
 [[package]]
 name = "gcc"
-version = "0.3.31"
+version = "0.3.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -65,13 +65,13 @@ name = "kernel32-sys"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "libc"
-version = "0.2.10"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -84,15 +84,15 @@ name = "memchr"
 version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "num_cpus"
-version = "0.2.11"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -123,7 +123,7 @@ version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -136,7 +136,7 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.1.28"
+version = "0.1.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -149,7 +149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "winapi"
-version = "0.2.6"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -161,20 +161,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9"
 "checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978"
 "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
-"checksum gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)" = "<none>"
-"checksum gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)" = "cfe877476e53690ebb0ce7325d0bf43e198d9500291b54b3c65e518de5039b07"
+"checksum gcc 0.3.35 (git+https://github.com/alexcrichton/gcc-rs)" = "<none>"
+"checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312"
 "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-"checksum libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "55f3730be7e803cf350d32061958171731c2395831fbd67a61083782808183e0"
+"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2"
 "checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db"
 "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
-"checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09"
+"checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3"
 "checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2"
 "checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199"
 "checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
 "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
 "checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d"
-"checksum toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "fcd27a04ca509aff336ba5eb2abc58d456f52c4ff64d9724d88acb85ead560b6"
+"checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796"
 "checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
-"checksum winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfaaa8fbdaa618fa6914b59b2769d690dd7521920a18d84b42d254678dd5fd4"
+"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
 "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
index a70a15b383ccc47cc724487314093429fc76ebfb..cdbbc229bc84e091e22a7c35f2261af9d262848c 100644 (file)
@@ -104,8 +104,7 @@ fn main() {
         let is_panic_abort = args.windows(2).any(|a| {
             &*a[0] == "--crate-name" && &*a[1] == "panic_abort"
         });
-        // FIXME(stage0): remove this `stage != "0"` condition
-        if is_panic_abort && stage != "0" {
+        if is_panic_abort {
             cmd.arg("-C").arg("panic=abort");
         }
 
index 2b9d717cbd48dbaa3365257cb80916b32a10c393..b8417218a2231e285e3adbefc3b99ba1c01fc77d 100644 (file)
@@ -108,6 +108,10 @@ pub fn compiletest(build: &Build,
     cmd.arg("--host").arg(compiler.host);
     cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build));
 
+    if let Some(nodejs) = build.config.nodejs.as_ref() {
+        cmd.arg("--nodejs").arg(nodejs);
+    }
+
     let mut flags = vec!["-Crpath".to_string()];
     if build.config.rust_optimize_tests {
         flags.push("-O".to_string());
@@ -323,6 +327,9 @@ pub fn krate(build: &Build,
     if target.contains("android") {
         build.run(cargo.arg("--no-run"));
         krate_android(build, compiler, target, mode);
+    } else if target.contains("emscripten") {
+        build.run(cargo.arg("--no-run"));
+        krate_emscripten(build, compiler, target, mode);
     } else {
         cargo.args(&build.flags.args);
         build.run(&mut cargo);
@@ -371,6 +378,35 @@ fn krate_android(build: &Build,
     }
 }
 
+fn krate_emscripten(build: &Build,
+                    compiler: &Compiler,
+                    target: &str,
+                    mode: Mode) {
+     let mut tests = Vec::new();
+     let out_dir = build.cargo_out(compiler, mode, target);
+     find_tests(&out_dir, target, &mut tests);
+     find_tests(&out_dir.join("deps"), target, &mut tests);
+
+     for test in tests {
+         let test_file_name = test.to_string_lossy().into_owned();
+         println!("running {}", test_file_name);
+         let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured");
+         let status = Command::new(nodejs)
+             .arg(&test_file_name)
+             .stderr(::std::process::Stdio::inherit())
+             .status();
+         match status {
+             Ok(status) => {
+                 if !status.success() {
+                     panic!("some tests failed");
+                 }
+             }
+             Err(e) => panic!(format!("failed to execute command: {}", e)),
+         };
+     }
+ }
+
+
 fn find_tests(dir: &Path,
               target: &str,
               dst: &mut Vec<PathBuf>) {
@@ -381,7 +417,8 @@ fn find_tests(dir: &Path,
         }
         let filename = e.file_name().into_string().unwrap();
         if (target.contains("windows") && filename.ends_with(".exe")) ||
-           (!target.contains("windows") && !filename.contains(".")) {
+           (!target.contains("windows") && !filename.contains(".")) ||
+           (target.contains("emscripten") && filename.contains(".js")){
             dst.push(e.path());
         }
     }
index 9de438cfa7d504756e1211fdcf2c8733c9ce57d2..16dbcae99fa1df2da3b816d8af5590496f37f9ba 100644 (file)
@@ -25,7 +25,7 @@
 use build_helper::output;
 use filetime::FileTime;
 
-use util::{exe, staticlib, libdir, mtime, is_dylib, copy};
+use util::{exe, libdir, mtime, is_dylib, copy};
 use {Build, Compiler, Mode};
 
 /// Build the standard library.
@@ -40,20 +40,6 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
     let libdir = build.sysroot_libdir(compiler, target);
     let _ = fs::remove_dir_all(&libdir);
     t!(fs::create_dir_all(&libdir));
-    // FIXME(stage0) remove this `if` after the next snapshot
-    // The stage0 compiler still passes the `-lcompiler-rt` flag to the linker but now `bootstrap`
-    // never builds a `libcopmiler-rt.a`! We'll fill the hole by simply copying stage0's
-    // `libcompiler-rt.a` to where the stage1's one is expected (though we could as well just use
-    // an empty `.a` archive). Note that the symbols of that stage0 `libcompiler-rt.a` won't make
-    // it to the final binary because now `libcore.rlib` also contains the symbols that
-    // `libcompiler-rt.a` provides. Since that rlib appears first in the linker arguments, its
-    // symbols are used instead of `libcompiler-rt.a`'s.
-    if compiler.stage == 0 {
-        let rtlib = &staticlib("compiler-rt", target);
-        let src = build.rustc.parent().unwrap().parent().unwrap().join("lib").join("rustlib")
-            .join(target).join("lib").join(rtlib);
-        copy(&src, &libdir.join(rtlib));
-    }
 
     // Some platforms have startup objects that may be required to produce the
     // libstd dynamic library, for example.
index 0f69bcfbb649da101c12e05e574e7f5a371a2732..a8434c3efb3589d256639129fe0d605a2796fab9 100644 (file)
@@ -396,9 +396,6 @@ macro_rules! check {
                     self.rustc = Some(PathBuf::from(value).join("bin/rustc"));
                     self.cargo = Some(PathBuf::from(value).join("bin/cargo"));
                 }
-                "CFG_NODEJS" if value.len() > 0 => {
-                    self.nodejs = Some(PathBuf::from(value));
-                }
                 _ => {}
             }
         }
index a5146c846ce28fbb6830d95b1fcbfb6805b4e07c..b4f61605d472db1f72596f99da37483513097ded 100644 (file)
@@ -243,7 +243,14 @@ pub fn build(&mut self) {
         // Almost all of these are simple one-liners that shell out to the
         // corresponding functionality in the extra modules, where more
         // documentation can be found.
-        for target in step::all(self) {
+        let steps = step::all(self);
+
+        self.verbose("bootstrap build plan:");
+        for step in &steps {
+            self.verbose(&format!("{:?}", step));
+        }
+
+        for target in steps {
             let doc_out = self.out.join(&target.target).join("doc");
             match target.src {
                 Llvm { _dummy } => {
@@ -550,12 +557,23 @@ enum State {
                 continue
             }
 
+            // `submodule.path` is the relative path to a submodule (from the repository root)
+            // `submodule_path` is the path to a submodule from the cwd
+
+            // use `submodule.path` when e.g. executing a submodule specific command from the
+            // repository root
+            // use `submodule_path` when e.g. executing a normal git command for the submodule
+            // (set via `current_dir`)
+            let submodule_path = self.src.join(submodule.path);
+
             match submodule.state {
                 State::MaybeDirty => {
                     // drop staged changes
-                    self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"]));
+                    self.run(git().current_dir(&submodule_path)
+                                  .args(&["reset", "--hard"]));
                     // drops unstaged changes
-                    self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"]));
+                    self.run(git().current_dir(&submodule_path)
+                                  .args(&["clean", "-fdx"]));
                 },
                 State::NotInitialized => {
                     self.run(git_submodule().arg("init").arg(submodule.path));
@@ -564,8 +582,10 @@ enum State {
                 State::OutOfSync => {
                     // drops submodule commits that weren't reported to the (outer) git repository
                     self.run(git_submodule().arg("update").arg(submodule.path));
-                    self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"]));
-                    self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"]));
+                    self.run(git().current_dir(&submodule_path)
+                                  .args(&["reset", "--hard"]));
+                    self.run(git().current_dir(&submodule_path)
+                                  .args(&["clean", "-fdx"]));
                 },
             }
         }
@@ -652,12 +672,6 @@ fn cargo(&self,
                  .env(format!("CFLAGS_{}", target), self.cflags(target).join(" "));
         }
 
-        // If we're building for OSX, inform the compiler and the linker that
-        // we want to build a compiler runnable on 10.7
-        if target.contains("apple-darwin") {
-            cargo.env("MACOSX_DEPLOYMENT_TARGET", "10.7");
-        }
-
         // Environment variables *required* needed throughout the build
         //
         // FIXME: should update code to not require this env var
@@ -926,7 +940,6 @@ fn cflags(&self, target: &str) -> Vec<String> {
         // LLVM/jemalloc/etc are all properly compiled.
         if target.contains("apple-darwin") {
             base.push("-stdlib=libc++".into());
-            base.push("-mmacosx-version-min=10.7".into());
         }
         // This is a hack, because newer binutils broke things on some vms/distros
         // (i.e., linking against unknown relocs disabled by the following flag)
@@ -967,7 +980,8 @@ fn rustc_flags(&self, target: &str) -> Vec<String> {
         // than an entry here.
 
         let mut base = Vec::new();
-        if target != self.config.build && !target.contains("msvc") {
+        if target != self.config.build && !target.contains("msvc") &&
+            !target.contains("emscripten") {
             base.push(format!("-Clinker={}", self.cc(target).display()));
         }
         return base
index df6408e5fe1c8ac2010abcfdd3222a6b61b976d5..63fc59e43286e24d987de924f87b57afbf85ee01 100644 (file)
@@ -65,7 +65,7 @@ pub fn llvm(build: &Build, target: &str) {
        .out_dir(&dst)
        .profile(if build.config.llvm_optimize {"Release"} else {"Debug"})
        .define("LLVM_ENABLE_ASSERTIONS", assertions)
-       .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ")
+       .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend")
        .define("LLVM_INCLUDE_EXAMPLES", "OFF")
        .define("LLVM_INCLUDE_TESTS", "OFF")
        .define("LLVM_INCLUDE_DOCS", "OFF")
index 05c35543e3e5b0584407531eb546b20a14c325b7..c4e6399c2c36d270fc65fed47663379bf92bacff 100644 (file)
@@ -40,17 +40,23 @@ pub fn check(build: &mut Build) {
             panic!("PATH contains invalid character '\"'");
         }
     }
-    let mut need_cmd = |cmd: &OsStr| {
-        if !checked.insert(cmd.to_owned()) {
-            return
-        }
+    let have_cmd = |cmd: &OsStr| {
         for path in env::split_paths(&path).map(|p| p.join(cmd)) {
             if fs::metadata(&path).is_ok() ||
                fs::metadata(path.with_extension("exe")).is_ok() {
-                return
+                return Some(path);
             }
         }
-        panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
+        return None;
+    };
+
+    let mut need_cmd = |cmd: &OsStr| {
+        if !checked.insert(cmd.to_owned()) {
+            return
+        }
+        if have_cmd(cmd).is_none() {
+            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
+        }
     };
 
     // If we've got a git directory we're gona need git to update
@@ -75,8 +81,13 @@ pub fn check(build: &mut Build) {
 
     need_cmd("python".as_ref());
 
-    // If a manual nodejs was added to the config,
-    // of if a nodejs install is detected through config, use it.
+    // Look for the nodejs command, needed for emscripten testing
+    if let Some(node) = have_cmd("node".as_ref()) {
+        build.config.nodejs = Some(node);
+    } else if let Some(node) = have_cmd("nodejs".as_ref()) {
+        build.config.nodejs = Some(node);
+    }
+
     if let Some(ref s) = build.config.nodejs {
         need_cmd(s.as_ref());
     }
@@ -84,6 +95,13 @@ pub fn check(build: &mut Build) {
     // We're gonna build some custom C code here and there, host triples
     // also build some C++ shims for LLVM so we need a C++ compiler.
     for target in build.config.target.iter() {
+        // On emscripten we don't actually need the C compiler to just
+        // build the target artifacts, only for testing. For the sake
+        // of easier bot configuration, just skip detection.
+        if target.contains("emscripten") {
+            continue;
+        }
+
         need_cmd(build.cc(target).as_ref());
         if let Some(ar) = build.ar(target) {
             need_cmd(ar.as_ref());
@@ -93,6 +111,14 @@ pub fn check(build: &mut Build) {
         need_cmd(build.cxx(host).as_ref());
     }
 
+    // The msvc hosts don't use jemalloc, turn it off globally to
+    // avoid packaging the dummy liballoc_jemalloc on that platform.
+    for host in build.config.host.iter() {
+        if host.contains("msvc") {
+            build.config.use_jemalloc = false;
+        }
+    }
+
     // Externally configured LLVM requires FileCheck to exist
     let filecheck = build.llvm_filecheck(&build.config.build);
     if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
@@ -100,15 +126,6 @@ pub fn check(build: &mut Build) {
     }
 
     for target in build.config.target.iter() {
-        // Either can't build or don't want to run jemalloc on these targets
-        if target.contains("rumprun") ||
-           target.contains("bitrig") ||
-           target.contains("openbsd") ||
-           target.contains("msvc") ||
-           target.contains("emscripten") {
-            build.config.use_jemalloc = false;
-        }
-
         // Can't compile for iOS unless we're on OSX
         if target.contains("apple-ios") &&
            !build.config.build.contains("apple-darwin") {
index 5f391b70fbe88b76ef958360ad0487785ef50e91..8a96cd1b4d23939f5e08e516beaa4a984e5c96fc 100644 (file)
@@ -171,6 +171,8 @@ pub enum Source<'a> {
 /// into a topologically sorted list which when executed left-to-right will
 /// correctly sequence the entire build.
 pub fn all(build: &Build) -> Vec<Step> {
+    build.verbose("inferred build steps:");
+
     let mut ret = Vec::new();
     let mut all = HashSet::new();
     for target in top_level(build) {
@@ -184,6 +186,7 @@ fn fill<'a>(build: &'a Build,
                 set: &mut HashSet<Step<'a>>) {
         if set.insert(target.clone()) {
             for dep in target.deps(build) {
+                build.verbose(&format!("{:?}\n  -> {:?}", target, dep));
                 fill(build, &dep, ret, set);
             }
             ret.push(target.clone());
@@ -415,7 +418,6 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
                     self.check_crate_std(compiler),
                     self.check_crate_test(compiler),
                     self.check_debuginfo(compiler),
-                    self.dist(stage),
                 ];
 
                 // If we're testing the build triple, then we know we can
@@ -460,6 +462,9 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
                         // misc
                         self.check_linkcheck(stage),
                         self.check_tidy(stage),
+
+                        // can we make the distributables?
+                        self.dist(stage),
                     ]);
                 }
                 return base
index 8598065bd965d9713bfafb6c1e766d63a7b17b89..f03ba5a4e8bf16dcf42dd742a4ce255c36321356 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8598065bd965d9713bfafb6c1e766d63a7b17b89
+Subproject commit f03ba5a4e8bf16dcf42dd742a4ce255c36321356
index 700ab2be589326f5b30521f66cbc94705ae5c341..22db70e605bf49304bffe76e05ae4ec9a4f714da 100644 (file)
@@ -166,12 +166,22 @@ you can find the Rust executables in a directory like
 `"C:\Program Files\Rust stable GNU 1.x\bin"`.
 
 Rust does not do its own linking, and so you’ll need to have a linker
-installed. Doing so will depend on your specific system, consult its
-documentation for more details.
-
-If not, there are a number of places where we can get help. The easiest is
-[the #rust-beginners IRC channel on irc.mozilla.org][irc-beginners] and for
-general discussion [the #rust IRC channel on irc.mozilla.org][irc], which we
+installed. Doing so will depend on your specific system. For
+Linux-based systems, Rust will attempt to call `cc` for linking. On
+`windows-msvc` (Rust built on Windows with Microsoft Visual Studio),
+this depends on having [Microsoft Visual C++ Build Tools][msvbt]
+installed. These do not need to be in `%PATH%` as `rustc` will find
+them automatically. In general, if you have your linker in a
+non-traditional location you can call `rustc 
+linker=/path/to/cc`, where `/path/to/cc` should point to your linker path.
+
+[msvbt]: http://landinghub.visualstudio.com/visual-cpp-build-tools
+
+If you are still stuck, there are a number of places where we can get
+help. The easiest is
+[the #rust-beginners IRC channel on irc.mozilla.org][irc-beginners] 
+and for general discussion
+[the #rust IRC channel on irc.mozilla.org][irc], which we 
 can access through [Mibbit][mibbit]. Then we'll be chatting with other
 Rustaceans (a silly nickname we call ourselves) who can help us out. Other great
 resources include [the user’s forum][users] and [Stack Overflow][stackoverflow].
@@ -230,12 +240,13 @@ $ cd hello_world
 
 ## Writing and Running a Rust Program
 
-Next, make a new source file and call it *main.rs*. Rust files always end
-in a *.rs* extension. If you’re using more than one word in your filename, use
-an underscore to separate them; for example, you'd use *hello_world.rs* rather
-than *helloworld.rs*.
+We need to create a source file for our Rust program. Rust files always end
+in a *.rs* extension. If you are using more than one word in your filename,
+use an underscore to separate them; for example, you would use
+*my_program.rs* rather than *myprogram.rs*.
 
-Now open the *main.rs* file you just created, and type the following code:
+Now, make a new file and call it *main.rs*. Open the file and type
+the following code:
 
 ```rust
 fn main() {
index 2ec3a00c0df516ab73db23926639712697c0cd50..d845ad6feb0013deb3856982f1e11a5c1d894201 100644 (file)
@@ -86,7 +86,7 @@ fn main() {
         return v.iter().fold(0, |a, &b| a + b);
     }
     // Borrow two vectors and sum them.
-    // This kind of borrowing does not allow mutation to the borrowed.
+    // This kind of borrowing does not allow mutation through the borrowed reference.
     fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
         // do stuff with v1 and v2
         let s1 = sum_vec(v1);
index 0259db221b6bc0dbaa0a47c94e7386eec91d22a3..1e05b01d30d46531843a8b1a3cd45767f0013772 100644 (file)
@@ -61,7 +61,6 @@
 * `-` (`- expr`): arithmetic negation.  Overloadable (`Neg`).
 * `-=` (`var -= expr`): arithmetic subtraction & assignment. Overloadable (`SubAssign`).
 * `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type.  See [Functions], [Closures].
-* `-> !` (`fn(…) -> !`, `|…| -> !`): diverging function or closure. See [Diverging Functions].
 * `.` (`expr.ident`): member access.  See [Structs], [Method Syntax].
 * `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal.
 * `..` (`..expr`): struct literal update syntax.  See [Structs (Update syntax)].
 * `/*!…*/`: inner block doc comment.  See [Comments].
 * `/**…*/`: outer block doc comment.  See [Comments].
 
+<!-- Special types -->
+
+* `!`: always empty Never type.  See [Diverging Functions].
+
 <!-- Various things involving parens and tuples -->
 
 * `()`: empty tuple (*a.k.a.* unit), both literal and type.
index 30e922d7f4dc0714f8ddd12eeabcdb2c2bbaf438..03f17371de68d8aea04f76fe43fdd632e7b9bb07 100644 (file)
@@ -161,7 +161,7 @@ Could not compile `hello_world`.
 
 Rust will not let us use a value that has not been initialized.
 
-Let take a minute to talk about this stuff we've added to `println!`.
+Let us take a minute to talk about this stuff we've added to `println!`.
 
 If you include two curly braces (`{}`, some call them moustaches...) in your
 string to print, Rust will interpret this as a request to interpolate some sort
index be64379b516e797a69272868254692b940586f66..690d44cc2cb7bc1585624121a5f99724df337957 100644 (file)
@@ -764,6 +764,13 @@ bound-list := bound | bound '+' bound-list
 bound := path | lifetime
 ```
 
+### Never type
+An empty type
+
+```antlr
+never_type : "!" ;
+```
+
 ### Object types
 
 **FIXME:** grammar?
index b72c3743a69ce1f34d447d7976f94b83ba62a66e..20970ab7a351254322cedef0f6efb4198e95dc75 100644 (file)
@@ -3959,6 +3959,16 @@ the top-level type for the implementation of the called method. If no such metho
 found, `.deref()` is called and the compiler continues to search for the method
 implementation in the returned type `U`.
 
+## The `Send` trait
+
+The `Send` trait indicates that a value of this type is safe to send from one 
+thread to another.
+
+## The 'Sync' trait
+
+The 'Sync' trait indicates that a value of this type is safe to share between
+multiple threads.
+
 # Memory model
 
 A Rust program's memory consists of a static set of *items* and a *heap*.
index f5f39d264a6b0a2f1cb7704aacabbbfc721522d9..645a80ab8b5813c438d60042ae1b2b674a072ceb 100755 (executable)
@@ -18,7 +18,7 @@ LIB_PREFIX=lib
 
 OS=`uname -s`
 case $OS in
-    ("Linux"|"FreeBSD"|"DragonFly"|"Bitrig"|"OpenBSD"|"SunOS")
+    ("Linux"|"FreeBSD"|"DragonFly"|"Bitrig"|"OpenBSD"|"SunOS"|"Haiku")
     BIN_SUF=
     LIB_SUF=.so
     ;;
index 5f9ccd1820ca6181dcf1011b684e873026f15de9..29e18781ce2a597884333e84f57f5d1938a27948 100644 (file)
 /// }
 /// ```
 
-#[cfg_attr(stage0, unsafe_no_drop_flag)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Arc<T: ?Sized> {
     ptr: Shared<ArcInner<T>>,
@@ -153,7 +152,6 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
 /// nodes behind strong `Arc<T>` pointers, and then storing the parent pointers
 /// as `Weak<T>` pointers.
 
-#[cfg_attr(stage0, unsafe_no_drop_flag)]
 #[stable(feature = "arc_weak", since = "1.4.0")]
 pub struct Weak<T: ?Sized> {
     ptr: Shared<ArcInner<T>>,
@@ -1002,6 +1000,7 @@ fn drop(&mut self) {
     }
 
     #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn manually_share_arc() {
         let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
         let arc_v = Arc::new(v);
index bc9b6e805efc91ee5107229de22de8d01ec78148..28f4dda1408830264612d571a35d7f651868f988 100644 (file)
@@ -244,12 +244,14 @@ impl<T: ?Sized> Box<T> {
     /// 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.
+    /// from another `Box` via the [`Box::into_raw`] function.
     ///
     /// 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.
     ///
+    /// [`Box::into_raw`]: struct.Box.html#method.into_raw
+    ///
     /// # Examples
     ///
     /// ```
@@ -269,12 +271,14 @@ pub unsafe fn from_raw(raw: *mut T) -> Self {
     /// 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.
+    /// `Box` with the [`Box::from_raw`] function.
     ///
     /// Note: this is an associated function, which means that you have
     /// to call it as `Box::into_raw(b)` instead of `b.into_raw()`. This
     /// is so that there is no conflict with a method on the inner type.
     ///
+    /// [`Box::from_raw`]: struct.Box.html#method.from_raw
+    ///
     /// # Examples
     ///
     /// ```
index c6453da3f4697d5f660634cf59a088a4197059ea..31491106d97ee1b22a88d9f1184adc6322c56926 100644 (file)
@@ -88,7 +88,6 @@
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
 #![feature(unique)]
-#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
 #![feature(unsize)]
 
 #![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol))]
index 23542215fa890a7f4ddffb236a6cc714bc4a7ca2..e153507956b9f9907452d56170a223260e26ee4a 100644 (file)
@@ -44,7 +44,6 @@
 /// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity
 /// field. This allows zero-sized types to not be special-cased by consumers of
 /// this type.
-#[cfg_attr(stage0, unsafe_no_drop_flag)]
 pub struct RawVec<T> {
     ptr: Unique<T>,
     cap: usize,
index e0f635f195bcd770bbb147440b3f20090320746f..4a4de419f2ede5bf9ce5dc8e4e8b04f46f8348d5 100644 (file)
@@ -252,7 +252,6 @@ struct RcBox<T: ?Sized> {
 /// that you have to call them as e.g. `Rc::get_mut(&value)` instead of
 /// `value.get_mut()`.  This avoids conflicts with methods of the inner
 /// type `T`.
-#[cfg_attr(stage0, unsafe_no_drop_flag)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Rc<T: ?Sized> {
     ptr: Shared<RcBox<T>>,
@@ -873,7 +872,6 @@ fn from(t: T) -> Self {
 ///
 /// [rc]: struct.Rc.html
 /// [downgrade]: struct.Rc.html#method.downgrade
-#[cfg_attr(stage0, unsafe_no_drop_flag)]
 #[stable(feature = "rc_weak", since = "1.4.0")]
 pub struct Weak<T: ?Sized> {
     ptr: Shared<RcBox<T>>,
index 8b31c5a557747765fbdc09967cc9c28ad4cec700..028d742cc832ea7c0a466562075f25c787f629e3 100644 (file)
@@ -27,6 +27,24 @@ fn main() {
     let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
     let src_dir = env::current_dir().unwrap();
 
+    // FIXME: This is a hack to support building targets that don't
+    // support jemalloc alongside hosts that do. The jemalloc build is
+    // controlled by a feature of the std crate, and if that feature
+    // changes between targets, it invalidates the fingerprint of
+    // std's build script (this is a cargo bug); so we must ensure
+    // that the feature set used by std is the same across all
+    // targets, which means we have to build the alloc_jemalloc crate
+    // for targets like emscripten, even if we don't use it.
+    if target.contains("rumprun") ||
+        target.contains("bitrig") ||
+        target.contains("openbsd") ||
+        target.contains("msvc") ||
+        target.contains("emscripten")
+    {
+        println!("cargo:rustc-cfg=dummy_jemalloc");
+        return;
+    }
+
     if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") {
         let jemalloc = PathBuf::from(jemalloc);
         println!("cargo:rustc-link-search=native={}",
index 5bbf1c35e0dd41f0b60e6f46d0ec3f0003b050df..21e45f9c4b20c81598c7629da18deeedc31941b4 100644 (file)
 
 extern crate libc;
 
-use libc::{c_int, c_void, size_t};
+pub use imp::*;
 
-// Linkage directives to pull in jemalloc and its dependencies.
-//
-// On some platforms we need to be sure to link in `pthread` which jemalloc
-// depends on, and specifically on android we need to also link to libgcc.
-// Currently jemalloc is compiled with gcc which will generate calls to
-// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
-// libcompiler-rt), so link that in to get that support.
-#[link(name = "jemalloc", kind = "static")]
-#[cfg_attr(target_os = "android", link(name = "gcc"))]
-#[cfg_attr(all(not(windows),
-               not(target_os = "android"),
-               not(target_env = "musl")),
-           link(name = "pthread"))]
-#[cfg(not(cargobuild))]
-extern "C" {}
-
-// Note that the symbols here are prefixed by default on OSX and Windows (we
-// don't explicitly request it), and on Android and DragonFly we explicitly
-// request it as unprefixing cause segfaults (mismatches in allocators).
-extern "C" {
-    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
-                   target_os = "dragonfly", target_os = "windows"),
-               link_name = "je_mallocx")]
-    fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
-    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
-                   target_os = "dragonfly", target_os = "windows"),
-               link_name = "je_rallocx")]
-    fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
-    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
-                   target_os = "dragonfly", target_os = "windows"),
-               link_name = "je_xallocx")]
-    fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
-    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
-                   target_os = "dragonfly", target_os = "windows"),
-               link_name = "je_sdallocx")]
-    fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
-    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
-                   target_os = "dragonfly", target_os = "windows"),
-               link_name = "je_nallocx")]
-    fn nallocx(size: size_t, flags: c_int) -> size_t;
-}
+// See comments in build.rs for why we sometimes build a crate that does nothing
+#[cfg(not(dummy_jemalloc))]
+mod imp {
+    use libc::{c_int, c_void, size_t};
 
-// The minimum alignment guaranteed by the architecture. This value is used to
-// add fast paths for low alignment values. In practice, the alignment is a
-// constant at the call site and the branch will be optimized out.
-#[cfg(all(any(target_arch = "arm",
-              target_arch = "mips",
-              target_arch = "powerpc")))]
-const MIN_ALIGN: usize = 8;
-#[cfg(all(any(target_arch = "x86",
-              target_arch = "x86_64",
-              target_arch = "aarch64",
-              target_arch = "powerpc64",
-              target_arch = "mips64",
-              target_arch = "s390x")))]
-const MIN_ALIGN: usize = 16;
-
-// MALLOCX_ALIGN(a) macro
-fn mallocx_align(a: usize) -> c_int {
-    a.trailing_zeros() as c_int
-}
+    // Linkage directives to pull in jemalloc and its dependencies.
+    //
+    // On some platforms we need to be sure to link in `pthread` which jemalloc
+    // depends on, and specifically on android we need to also link to libgcc.
+    // Currently jemalloc is compiled with gcc which will generate calls to
+    // intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
+    // libcompiler-rt), so link that in to get that support.
+    #[link(name = "jemalloc", kind = "static")]
+    #[cfg_attr(target_os = "android", link(name = "gcc"))]
+    #[cfg_attr(all(not(windows),
+                   not(target_os = "android"),
+                   not(target_env = "musl")),
+               link(name = "pthread"))]
+    #[cfg(not(cargobuild))]
+    extern "C" {}
+
+    // Note that the symbols here are prefixed by default on OSX and Windows (we
+    // don't explicitly request it), and on Android and DragonFly we explicitly
+    // request it as unprefixing cause segfaults (mismatches in allocators).
+    extern "C" {
+        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+                       target_os = "dragonfly", target_os = "windows"),
+                   link_name = "je_mallocx")]
+        fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
+        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+                       target_os = "dragonfly", target_os = "windows"),
+                   link_name = "je_rallocx")]
+        fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
+        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+                       target_os = "dragonfly", target_os = "windows"),
+                   link_name = "je_xallocx")]
+        fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
+        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+                       target_os = "dragonfly", target_os = "windows"),
+                   link_name = "je_sdallocx")]
+        fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
+        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+                       target_os = "dragonfly", target_os = "windows"),
+                   link_name = "je_nallocx")]
+        fn nallocx(size: size_t, flags: c_int) -> size_t;
+    }
+
+    // The minimum alignment guaranteed by the architecture. This value is used to
+    // add fast paths for low alignment values. In practice, the alignment is a
+    // constant at the call site and the branch will be optimized out.
+    #[cfg(all(any(target_arch = "arm",
+                  target_arch = "mips",
+                  target_arch = "powerpc")))]
+    const MIN_ALIGN: usize = 8;
+    #[cfg(all(any(target_arch = "x86",
+                  target_arch = "x86_64",
+                  target_arch = "aarch64",
+                  target_arch = "powerpc64",
+                  target_arch = "mips64",
+                  target_arch = "s390x")))]
+    const MIN_ALIGN: usize = 16;
+
+    // MALLOCX_ALIGN(a) macro
+    fn mallocx_align(a: usize) -> c_int {
+        a.trailing_zeros() as c_int
+    }
+
+    fn align_to_flags(align: usize) -> c_int {
+        if align <= MIN_ALIGN {
+            0
+        } else {
+            mallocx_align(align)
+        }
+    }
+
+    #[no_mangle]
+    pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
+        let flags = align_to_flags(align);
+        unsafe { mallocx(size as size_t, flags) as *mut u8 }
+    }
+
+    #[no_mangle]
+    pub extern "C" fn __rust_reallocate(ptr: *mut u8,
+                                        _old_size: usize,
+                                        size: usize,
+                                        align: usize)
+                                        -> *mut u8 {
+        let flags = align_to_flags(align);
+        unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
+    }
+
+    #[no_mangle]
+    pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
+                                                _old_size: usize,
+                                                size: usize,
+                                                align: usize)
+                                                -> usize {
+        let flags = align_to_flags(align);
+        unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
+    }
 
-fn align_to_flags(align: usize) -> c_int {
-    if align <= MIN_ALIGN {
+    #[no_mangle]
+    pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
+        let flags = align_to_flags(align);
+        unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
+    }
+
+    #[no_mangle]
+    pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
+        let flags = align_to_flags(align);
+        unsafe { nallocx(size as size_t, flags) as usize }
+    }
+
+    // These symbols are used by jemalloc on android but the really old android
+    // we're building on doesn't have them defined, so just make sure the symbols
+    // are available.
+    #[no_mangle]
+    #[cfg(target_os = "android")]
+    pub extern "C" fn pthread_atfork(_prefork: *mut u8,
+                                     _postfork_parent: *mut u8,
+                                     _postfork_child: *mut u8)
+                                     -> i32 {
         0
-    } else {
-        mallocx_align(align)
     }
 }
 
-#[no_mangle]
-pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
-    let flags = align_to_flags(align);
-    unsafe { mallocx(size as size_t, flags) as *mut u8 }
-}
+#[cfg(dummy_jemalloc)]
+mod imp {
+    fn bogus() -> ! {
+        panic!("jemalloc is not implemented for this platform");
+    }
 
-#[no_mangle]
-pub extern "C" fn __rust_reallocate(ptr: *mut u8,
-                                    _old_size: usize,
-                                    size: usize,
-                                    align: usize)
-                                    -> *mut u8 {
-    let flags = align_to_flags(align);
-    unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
-}
+    #[no_mangle]
+    pub extern "C" fn __rust_allocate(_size: usize, _align: usize) -> *mut u8 {
+        bogus()
+    }
 
-#[no_mangle]
-pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
-                                            _old_size: usize,
-                                            size: usize,
-                                            align: usize)
-                                            -> usize {
-    let flags = align_to_flags(align);
-    unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
-}
+    #[no_mangle]
+    pub extern "C" fn __rust_reallocate(_ptr: *mut u8,
+                                        _old_size: usize,
+                                        _size: usize,
+                                        _align: usize)
+                                        -> *mut u8 {
+        bogus()
+    }
 
-#[no_mangle]
-pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
-    let flags = align_to_flags(align);
-    unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
-}
+    #[no_mangle]
+    pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8,
+                                                _old_size: usize,
+                                                _size: usize,
+                                                _align: usize)
+                                                -> usize {
+        bogus()
+    }
 
-#[no_mangle]
-pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
-    let flags = align_to_flags(align);
-    unsafe { nallocx(size as size_t, flags) as usize }
-}
+    #[no_mangle]
+    pub extern "C" fn __rust_deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) {
+        bogus()
+    }
 
-// These symbols are used by jemalloc on android but the really old android
-// we're building on doesn't have them defined, so just make sure the symbols
-// are available.
-#[no_mangle]
-#[cfg(target_os = "android")]
-pub extern "C" fn pthread_atfork(_prefork: *mut u8,
-                                 _postfork_parent: *mut u8,
-                                 _postfork_child: *mut u8)
-                                 -> i32 {
-    0
+    #[no_mangle]
+    pub extern "C" fn __rust_usable_size(_size: usize, _align: usize) -> usize {
+        bogus()
+    }
 }
index 01407d1acd2ecda82db51af61f7f50925cc91a22..dacafe771edc2c500264e0d028fcbe6ddfbc5fbd 100644 (file)
@@ -29,7 +29,8 @@
               target_arch = "mips",
               target_arch = "powerpc",
               target_arch = "powerpc64",
-              target_arch = "asmjs")))]
+              target_arch = "asmjs",
+              target_arch = "wasm32")))]
 const MIN_ALIGN: usize = 8;
 #[cfg(all(any(target_arch = "x86_64",
               target_arch = "aarch64",
index 700f88dc0f267688bb91e057616256fc84c00e1c..6b45c25eb21399dff7de1062213a72dcd29f55b9 100644 (file)
@@ -14,7 +14,7 @@
 
 use core::cmp::Ordering;
 use core::hash::{Hash, Hasher};
-use core::ops::Deref;
+use core::ops::{Add, AddAssign, Deref};
 
 use fmt;
 
@@ -270,3 +270,49 @@ fn as_ref(&self) -> &T {
         self
     }
 }
+
+#[stable(feature = "cow_add", since = "1.13.0")]
+impl<'a> Add<&'a str> for Cow<'a, str> {
+    type Output = Cow<'a, str>;
+
+    fn add(self, rhs: &'a str) -> Self {
+        if self == "" {
+            Cow::Borrowed(rhs)
+        } else if rhs == "" {
+            self
+        } else {
+            Cow::Owned(self.into_owned() + rhs)
+        }
+    }
+}
+
+#[stable(feature = "cow_add", since = "1.13.0")]
+impl<'a> Add<Cow<'a, str>> for Cow<'a, str> {
+    type Output = Cow<'a, str>;
+
+    fn add(self, rhs: Cow<'a, str>) -> Self {
+        if self == "" {
+            rhs
+        } else if rhs == "" {
+            self
+        } else {
+            Cow::Owned(self.into_owned() + rhs.borrow())
+        }
+    }
+}
+
+#[stable(feature = "cow_add", since = "1.13.0")]
+impl<'a> AddAssign<&'a str> for Cow<'a, str> {
+    fn add_assign(&mut self, rhs: &'a str) {
+        if rhs == "" { return; }
+        self.to_mut().push_str(rhs);
+    }
+}
+
+#[stable(feature = "cow_add", since = "1.13.0")]
+impl<'a> AddAssign<Cow<'a, str>> for Cow<'a, str> {
+    fn add_assign(&mut self, rhs: Cow<'a, str>) {
+        if rhs == "" { return; }
+        self.to_mut().push_str(rhs.borrow());
+    }
+}
index c5a921693475a60e7ec1abfef9f78274ef742c11..990de541b6783db047df209c0c013f7c5502bca7 100644 (file)
@@ -52,7 +52,6 @@
 #![feature(step_by)]
 #![feature(unicode)]
 #![feature(unique)]
-#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
 #![cfg_attr(test, feature(rand, test))]
 
 #![no_std]
index 690c4f4af35896df5b24cb5be112bfbf279b34e4..67f3708a62b91dbf50e83d6bf98fcb5842f967b0 100644 (file)
@@ -1294,6 +1294,7 @@ fn test_insert_prev() {
     }
 
     #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn test_send() {
         let n = list_from(&[1, 2, 3]);
         thread::spawn(move || {
index d6a8362d58182597527fe1b14449f46c9ef8e86a..3115be00a4d720094fe846219a7d8d91470d924f 100644 (file)
@@ -68,7 +68,9 @@ macro_rules! vec {
 }
 
 /// Use the syntax described in `std::fmt` to create a value of type `String`.
-/// See `std::fmt` for more information.
+/// See [`std::fmt`][fmt] for more information.
+///
+/// [fmt]: ../std/fmt/index.html
 ///
 /// # Examples
 ///
index 54dc7ec06da16b9661bf7f9547ad6eaaf9ba49b9..6b705ca039fd881b4f1d261c764f0b78c9eb1b60 100644 (file)
@@ -168,7 +168,7 @@ pub fn len(&self) -> usize {
         core_slice::SliceExt::len(self)
     }
 
-    /// Returns true if the slice has a length of 0
+    /// Returns true if the slice has a length of 0.
     ///
     /// # Example
     ///
@@ -402,7 +402,7 @@ pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
         core_slice::SliceExt::get_unchecked_mut(self, index)
     }
 
-    /// Returns an raw pointer to the slice's buffer
+    /// Returns an raw pointer to the slice's buffer.
     ///
     /// The caller must ensure that the slice outlives the pointer this
     /// function returns, or else it will end up pointing to garbage.
@@ -468,7 +468,7 @@ pub fn as_mut_ptr(&mut self) -> *mut T {
     ///
     /// # Examples
     ///
-    /// ```rust
+    /// ```
     /// let mut v = ["a", "b", "c", "d"];
     /// v.swap(1, 3);
     /// assert!(v == ["a", "d", "c", "b"]);
@@ -483,7 +483,7 @@ pub fn swap(&mut self, a: usize, b: usize) {
     ///
     /// # Example
     ///
-    /// ```rust
+    /// ```
     /// let mut v = [1, 2, 3];
     /// v.reverse();
     /// assert!(v == [3, 2, 1]);
@@ -567,9 +567,9 @@ pub fn windows(&self, size: usize) -> Windows<T> {
     }
 
     /// Returns an iterator over `size` elements of the slice at a
-    /// time. The chunks are slices and do not overlap. If `size` does not divide the
-    /// length of the slice, then the last chunk will not have length
-    /// `size`.
+    /// time. The chunks are slices and do not overlap. If `size` does
+    /// not divide the length of the slice, then the last chunk will
+    /// not have length `size`.
     ///
     /// # Panics
     ///
@@ -656,7 +656,7 @@ pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
     ///
     /// # Examples
     ///
-    /// ```rust
+    /// ```
     /// let mut v = [1, 2, 3, 4, 5, 6];
     ///
     /// // scoped to restrict the lifetime of the borrows
@@ -754,7 +754,7 @@ pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F>
     }
 
     /// Returns an iterator over subslices separated by elements that match
-    /// `pred`, limited to returning at most `n` items.  The matched element is
+    /// `pred`, limited to returning at most `n` items. The matched element is
     /// not contained in the subslices.
     ///
     /// The last element returned, if any, will contain the remainder of the
@@ -781,7 +781,7 @@ pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<T, F>
     }
 
     /// Returns an iterator over subslices separated by elements that match
-    /// `pred`, limited to returning at most `n` items.  The matched element is
+    /// `pred`, limited to returning at most `n` items. The matched element is
     /// not contained in the subslices.
     ///
     /// The last element returned, if any, will contain the remainder of the
@@ -835,7 +835,7 @@ pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<T, F>
 
     /// Returns an iterator over subslices separated by elements that match
     /// `pred` limited to returning at most `n` items. This starts at the end of
-    /// the slice and works backwards.  The matched element is not contained in
+    /// the slice and works backwards. The matched element is not contained in
     /// the subslices.
     ///
     /// The last element returned, if any, will contain the remainder of the
@@ -922,9 +922,9 @@ pub fn ends_with(&self, needle: &[T]) -> bool
     ///
     /// Looks up a series of four elements. The first is found, with a
     /// uniquely determined position; the second and third are not
-    /// found; the fourth could match any position in `[1,4]`.
+    /// found; the fourth could match any position in `[1, 4]`.
     ///
-    /// ```rust
+    /// ```
     /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
     ///
     /// assert_eq!(s.binary_search(&13),  Ok(9));
@@ -956,9 +956,9 @@ pub fn binary_search(&self, x: &T) -> Result<usize, usize>
     ///
     /// Looks up a series of four elements. The first is found, with a
     /// uniquely determined position; the second and third are not
-    /// found; the fourth could match any position in `[1,4]`.
+    /// found; the fourth could match any position in `[1, 4]`.
     ///
-    /// ```rust
+    /// ```
     /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
     ///
     /// let seek = 13;
@@ -982,21 +982,23 @@ pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
     /// Binary search a sorted slice with a key extraction function.
     ///
     /// Assumes that the slice is sorted by the key, for instance with
-    /// `sort_by_key` using the same key extraction function.
+    /// [`sort_by_key`] using the same key extraction function.
     ///
     /// If a matching value is found then returns `Ok`, containing the
     /// index for the matched element; if no match is found then `Err`
     /// is returned, containing the index where a matching element could
     /// be inserted while maintaining sorted order.
     ///
+    /// [`sort_by_key`]: #method.sort_by_key
+    ///
     /// # Examples
     ///
     /// Looks up a series of four elements in a slice of pairs sorted by
     /// their second elements. The first is found, with a uniquely
     /// determined position; the second and third are not found; the
-    /// fourth could match any position in `[1,4]`.
+    /// fourth could match any position in `[1, 4]`.
     ///
-    /// ```rust
+    /// ```
     /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
     ///          (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
     ///          (1, 21), (2, 34), (4, 55)];
@@ -1023,7 +1025,7 @@ pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, us
     ///
     /// # Examples
     ///
-    /// ```rust
+    /// ```
     /// let mut v = [-5, 4, 1, -3, 2];
     ///
     /// v.sort();
@@ -1045,7 +1047,7 @@ pub fn sort(&mut self)
     ///
     /// # Examples
     ///
-    /// ```rust
+    /// ```
     /// let mut v = [-5i32, 4, 1, -3, 2];
     ///
     /// v.sort_by_key(|k| k.abs());
@@ -1067,7 +1069,7 @@ pub fn sort_by_key<B, F>(&mut self, mut f: F)
     ///
     /// # Examples
     ///
-    /// ```rust
+    /// ```
     /// let mut v = [5, 4, 1, 3, 2];
     /// v.sort_by(|a, b| a.cmp(b));
     /// assert!(v == [1, 2, 3, 4, 5]);
@@ -1094,7 +1096,7 @@ pub fn sort_by<F>(&mut self, compare: F)
     ///
     /// # Example
     ///
-    /// ```rust
+    /// ```
     /// let mut dst = [0, 0, 0];
     /// let src = [1, 2, 3];
     ///
@@ -1116,7 +1118,7 @@ pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
     ///
     /// # Example
     ///
-    /// ```rust
+    /// ```
     /// let mut dst = [0, 0, 0];
     /// let src = [1, 2, 3];
     ///
index 6a6b450e518632ff0b0666e594290d239bf077f7..96efe1a03e351095898bbead31653ec78ae5f13f 100644 (file)
@@ -697,7 +697,7 @@ pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
     ///
     /// Basic usage:
     ///
-    /// ```rust
+    /// ```
     /// let bananas = "bananas";
     ///
     /// assert!(bananas.ends_with("anas"));
@@ -900,7 +900,7 @@ pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
     ///
     /// It does _not_ give you:
     ///
-    /// ```rust,ignore
+    /// ```,ignore
     /// assert_eq!(d, &["a", "b", "c"]);
     /// ```
     ///
index cff0308d4af8416176a06a87b4e6d63cd65342ff..119828ea43c61c31ce419b1c173ae0fd795f542b 100644 (file)
@@ -21,7 +21,7 @@
 //!
 //! There are multiple ways to create a new `String` from a string literal:
 //!
-//! ```rust
+//! ```
 //! let s = "Hello".to_string();
 //!
 //! let s = String::from("world");
@@ -31,7 +31,7 @@
 //! You can create a new `String` from an existing one by concatenating with
 //! `+`:
 //!
-//! ```rust
+//! ```
 //! let s = "Hello".to_string();
 //!
 //! let message = s + " world!";
@@ -40,7 +40,7 @@
 //! 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()`.
@@ -975,7 +975,7 @@ pub fn shrink_to_fit(&mut self) {
     pub fn push(&mut self, ch: char) {
         match ch.len_utf8() {
             1 => self.vec.push(ch as u8),
-            _ => self.vec.extend_from_slice(ch.encode_utf8().as_slice()),
+            _ => self.vec.extend_from_slice(ch.encode_utf8(&mut [0;4]).as_bytes()),
         }
     }
 
@@ -1131,10 +1131,11 @@ pub fn insert(&mut self, idx: usize, ch: char) {
         let len = self.len();
         assert!(idx <= len);
         assert!(self.is_char_boundary(idx));
-        let bits = ch.encode_utf8();
+        let mut bits = [0; 4];
+        let bits = ch.encode_utf8(&mut bits).as_bytes();
 
         unsafe {
-            self.insert_bytes(idx, bits.as_slice());
+            self.insert_bytes(idx, bits);
         }
     }
 
index f8b4a92df2c5dca5dc25317e7fc6ac23d8a9fb8e..ed6eb62c9677ebdc5bafd47aba8dc359724f2728 100644 (file)
 /// Vec does not currently guarantee the order in which elements are dropped
 /// (the order has changed in the past, and may change again).
 ///
-#[cfg_attr(stage0, unsafe_no_drop_flag)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Vec<T> {
     buf: RawVec<T>,
@@ -1770,7 +1769,7 @@ impl<T> IntoIter<T> {
     ///
     /// # Examples
     ///
-    /// ```rust
+    /// ```
     /// # #![feature(vec_into_iter_as_slice)]
     /// let vec = vec!['a', 'b', 'c'];
     /// let mut into_iter = vec.into_iter();
@@ -1789,7 +1788,7 @@ pub fn as_slice(&self) -> &[T] {
     ///
     /// # Examples
     ///
-    /// ```rust
+    /// ```
     /// # #![feature(vec_into_iter_as_slice)]
     /// let vec = vec!['a', 'b', 'c'];
     /// let mut into_iter = vec.into_iter();
diff --git a/src/libcollectionstest/cow_str.rs b/src/libcollectionstest/cow_str.rs
new file mode 100644 (file)
index 0000000..82533ba
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright 2012-2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::borrow::Cow;
+
+// check that Cow<'a, str> implements addition
+#[test]
+fn check_cow_add() {
+    borrowed1 = Cow::Borrowed("Hello, ");
+    borrowed2 = Cow::Borrowed("World!");
+    borrow_empty = Cow::Borrowed("");
+
+    owned1 = Cow::Owned("Hi, ".into());
+    owned2 = Cow::Owned("Rustaceans!".into());
+    owned_empty = Cow::Owned("".into());
+
+    assert_eq!("Hello, World!", borrowed1 + borrowed2);
+    assert_eq!("Hello, Rustaceans!", borrowed1 + owned2);
+
+    assert_eq!("Hello, World!", owned1 + borrowed2);
+    assert_eq!("Hello, Rustaceans!", owned1 + owned2);
+
+    if let Cow::Owned(_) = borrowed1 + borrow_empty {
+        panic!("Adding empty strings to a borrow should note allocate");
+    }
+    if let Cow::Owned(_) = borrow_empty + borrowed1 {
+        panic!("Adding empty strings to a borrow should note allocate");
+    }
+    if let Cow::Owned(_) = borrowed1 + owned_empty {
+        panic!("Adding empty strings to a borrow should note allocate");
+    }
+    if let Cow::Owned(_) = owned_empty + borrowed1 {
+        panic!("Adding empty strings to a borrow should note allocate");
+    }
+}
+
+fn check_cow_add_assign() {
+    borrowed1 = Cow::Borrowed("Hello, ");
+    borrowed2 = Cow::Borrowed("World!");
+    borrow_empty = Cow::Borrowed("");
+
+    owned1 = Cow::Owned("Hi, ".into());
+    owned2 = Cow::Owned("Rustaceans!".into());
+    owned_empty = Cow::Owned("".into());
+
+    let borrowed1clone = borrowed1.clone();
+    borrowed1clone += borrow_empty;
+    assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr());
+
+    borrowed1clone += owned_empty;
+    assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr());
+
+    owned1 += borrowed2;
+    borrowed1 += owned2;
+
+    assert_eq!("Hello, World!", owned1);
+    assert_eq!("Hello, Rustaceans!", borrowed1);
+}
index 5b341ab62d097dd3de59d4ed5150a93e93df8e2b..9580714075ad78260e8c68e50354d8af085319ea 100644 (file)
@@ -1116,6 +1116,7 @@ fn test_box_slice_clone() {
 }
 
 #[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
 fn test_box_slice_clone_panics() {
     use std::sync::Arc;
     use std::sync::atomic::{AtomicUsize, Ordering};
index 62e164a569aa642005e5daa53b38e78eeb006cda..560895f721bbf7aefc8f103bfa2639e532fcf2bd 100644 (file)
@@ -786,9 +786,9 @@ fn test_rev_iterator() {
 
 #[test]
 fn test_chars_decoding() {
+    let mut bytes = [0; 4];
     for c in (0..0x110000).filter_map(::std::char::from_u32) {
-        let bytes = c.encode_utf8();
-        let s = ::std::str::from_utf8(bytes.as_slice()).unwrap();
+        let s = c.encode_utf8(&mut bytes);
         if Some(c) != s.chars().next() {
             panic!("character {:x}={} does not decode correctly", c as u32, c);
         }
@@ -797,9 +797,9 @@ fn test_chars_decoding() {
 
 #[test]
 fn test_chars_rev_decoding() {
+    let mut bytes = [0; 4];
     for c in (0..0x110000).filter_map(::std::char::from_u32) {
-        let bytes = c.encode_utf8();
-        let s = ::std::str::from_utf8(bytes.as_slice()).unwrap();
+        let s = c.encode_utf8(&mut bytes);
         if Some(c) != s.chars().rev().next() {
             panic!("character {:x}={} does not decode correctly", c as u32, c);
         }
index 66c683333b9854812767fc92e16b790c296f391d..acbd39bb1630c483c3a25064c8780eb95c118728 100644 (file)
@@ -73,6 +73,12 @@ fn extend(&mut self, sources: &[&'static str]) {
 
 fn main() {
     let target = env::var("TARGET").expect("TARGET was not set");
+
+    // Emscripten's runtime includes all the builtins
+    if target.contains("emscripten") {
+        return;
+    }
+
     let cfg = &mut gcc::Config::new();
 
     if target.contains("msvc") {
index fbcf5204d2537df68196083b55dd94bc5ec83241..4a703b3da68f64c1b34e48f16075ac4ef2a213dd 100644 (file)
@@ -8,9 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![cfg_attr(not(stage0), feature(compiler_builtins))]
+#![feature(compiler_builtins)]
 #![no_std]
-#![cfg_attr(not(stage0), compiler_builtins)]
+#![compiler_builtins]
 #![unstable(feature = "compiler_builtins_lib",
             reason = "internal implementation detail of rustc right now",
             issue = "0")]
index a21d1229d358be89a4c57be74bdc03c48caf5bc2..26d28049a474d3f6d4076a3a52c8092a977963d9 100644 (file)
@@ -18,6 +18,7 @@
 use char_private::is_printable;
 use convert::TryFrom;
 use fmt;
+use slice;
 use iter::FusedIterator;
 use mem::transmute;
 
@@ -327,9 +328,9 @@ pub trait CharExt {
     #[stable(feature = "core", since = "1.6.0")]
     fn len_utf16(self) -> usize;
     #[unstable(feature = "unicode", issue = "27784")]
-    fn encode_utf8(self) -> EncodeUtf8;
+    fn encode_utf8(self, dst: &mut [u8]) -> &mut str;
     #[unstable(feature = "unicode", issue = "27784")]
-    fn encode_utf16(self) -> EncodeUtf16;
+    fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16];
 }
 
 #[stable(feature = "core", since = "1.6.0")]
@@ -419,47 +420,59 @@ fn len_utf16(self) -> usize {
     }
 
     #[inline]
-    fn encode_utf8(self) -> EncodeUtf8 {
+    fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
         let code = self as u32;
-        let mut buf = [0; 4];
-        let pos = if code < MAX_ONE_B {
-            buf[3] = code as u8;
-            3
-        } else if code < MAX_TWO_B {
-            buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
-            buf[3] = (code & 0x3F) as u8 | TAG_CONT;
-            2
-        } else if code < MAX_THREE_B {
-            buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
-            buf[2] = (code >>  6 & 0x3F) as u8 | TAG_CONT;
-            buf[3] = (code & 0x3F) as u8 | TAG_CONT;
-            1
-        } else {
-            buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
-            buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
-            buf[2] = (code >>  6 & 0x3F) as u8 | TAG_CONT;
-            buf[3] = (code & 0x3F) as u8 | TAG_CONT;
-            0
-        };
-        EncodeUtf8 { buf: buf, pos: pos }
+        unsafe {
+            let len =
+            if code < MAX_ONE_B && !dst.is_empty() {
+                *dst.get_unchecked_mut(0) = code as u8;
+                1
+            } else if code < MAX_TWO_B && dst.len() >= 2 {
+                *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
+                *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT;
+                2
+            } else if code < MAX_THREE_B && dst.len() >= 3  {
+                *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
+                *dst.get_unchecked_mut(1) = (code >>  6 & 0x3F) as u8 | TAG_CONT;
+                *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT;
+                3
+            } else if dst.len() >= 4 {
+                *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
+                *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT;
+                *dst.get_unchecked_mut(2) = (code >>  6 & 0x3F) as u8 | TAG_CONT;
+                *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT;
+                4
+            } else {
+                panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}",
+                    from_u32_unchecked(code).len_utf8(),
+                    code,
+                    dst.len())
+            };
+            transmute(slice::from_raw_parts_mut(dst.as_mut_ptr(), len))
+        }
     }
 
     #[inline]
-    fn encode_utf16(self) -> EncodeUtf16 {
-        let mut buf = [0; 2];
+    fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] {
         let mut code = self as u32;
-        let pos = if (code & 0xFFFF) == code {
-            // The BMP falls through (assuming non-surrogate, as it should)
-            buf[1] = code as u16;
-            1
-        } else {
-            // Supplementary planes break into surrogates.
-            code -= 0x1_0000;
-            buf[0] = 0xD800 | ((code >> 10) as u16);
-            buf[1] = 0xDC00 | ((code as u16) & 0x3FF);
-            0
-        };
-        EncodeUtf16 { buf: buf, pos: pos }
+        unsafe {
+            if (code & 0xFFFF) == code && !dst.is_empty() {
+                // The BMP falls through (assuming non-surrogate, as it should)
+                *dst.get_unchecked_mut(0) = code as u16;
+                slice::from_raw_parts_mut(dst.as_mut_ptr(), 1)
+            } else if dst.len() >= 2 {
+                // Supplementary planes break into surrogates.
+                code -= 0x1_0000;
+                *dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16);
+                *dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF);
+                slice::from_raw_parts_mut(dst.as_mut_ptr(), 2)
+            } else {
+                panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}",
+                    from_u32_unchecked(code).len_utf16(),
+                    code,
+                    dst.len())
+            }
+        }
     }
 }
 
@@ -702,88 +715,7 @@ impl ExactSizeIterator for EscapeDebug { }
 #[unstable(feature = "fused", issue = "35602")]
 impl FusedIterator for EscapeDebug {}
 
-/// An iterator over `u8` entries represending the UTF-8 encoding of a `char`
-/// value.
-///
-/// Constructed via the `.encode_utf8()` method on `char`.
-#[unstable(feature = "unicode", issue = "27784")]
-#[derive(Debug)]
-pub struct EncodeUtf8 {
-    buf: [u8; 4],
-    pos: usize,
-}
-
-impl EncodeUtf8 {
-    /// Returns the remaining bytes of this iterator as a slice.
-    #[unstable(feature = "unicode", issue = "27784")]
-    pub fn as_slice(&self) -> &[u8] {
-        &self.buf[self.pos..]
-    }
-}
-
-#[unstable(feature = "unicode", issue = "27784")]
-impl Iterator for EncodeUtf8 {
-    type Item = u8;
-
-    fn next(&mut self) -> Option<u8> {
-        if self.pos == self.buf.len() {
-            None
-        } else {
-            let ret = Some(self.buf[self.pos]);
-            self.pos += 1;
-            ret
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.as_slice().iter().size_hint()
-    }
-}
-
-#[unstable(feature = "fused", issue = "35602")]
-impl FusedIterator for EncodeUtf8 {}
-
-/// An iterator over `u16` entries represending the UTF-16 encoding of a `char`
-/// value.
-///
-/// Constructed via the `.encode_utf16()` method on `char`.
-#[unstable(feature = "unicode", issue = "27784")]
-#[derive(Debug)]
-pub struct EncodeUtf16 {
-    buf: [u16; 2],
-    pos: usize,
-}
-
-impl EncodeUtf16 {
-    /// Returns the remaining bytes of this iterator as a slice.
-    #[unstable(feature = "unicode", issue = "27784")]
-    pub fn as_slice(&self) -> &[u16] {
-        &self.buf[self.pos..]
-    }
-}
-
-
-#[unstable(feature = "unicode", issue = "27784")]
-impl Iterator for EncodeUtf16 {
-    type Item = u16;
-
-    fn next(&mut self) -> Option<u16> {
-        if self.pos == self.buf.len() {
-            None
-        } else {
-            let ret = Some(self.buf[self.pos]);
-            self.pos += 1;
-            ret
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.as_slice().iter().size_hint()
-    }
-}
 
-#[unstable(feature = "fused", issue = "35602")]
-impl FusedIterator for EncodeUtf16 {}
 
 /// An iterator over an iterator of bytes of the characters the bytes represent
 /// as UTF-8
index 0b800cacfc19adbd41909051c8c233b1ef5f83f1..d72b18ae345ce144018d56722403516f99727bdd 100644 (file)
@@ -129,13 +129,6 @@ pub struct AssertParamIsClone<T: Clone + ?Sized> { _field: ::marker::PhantomData
            reason = "deriving hack, should not be public",
            issue = "0")]
 pub struct AssertParamIsCopy<T: Copy + ?Sized> { _field: ::marker::PhantomData<T> }
-#[cfg(stage0)]
-#[doc(hidden)]
-#[inline(always)]
-#[unstable(feature = "derive_clone_copy",
-           reason = "deriving hack, should not be public",
-           issue = "0")]
-pub fn assert_receiver_is_clone<T: Clone + ?Sized>(_: &T) {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T: ?Sized> Clone for &'a T {
index f990a27e52b3190b8a00fd6840b7ad75ee546f62..036633fe89dc67d514c7e27dd84fbe68610149c0 100644 (file)
 
 //! Functionality for ordering and comparison.
 //!
-//! This module defines both `PartialOrd` and `PartialEq` traits which are used
+//! This module defines both [`PartialOrd`] and [`PartialEq`] traits which are used
 //! by the compiler to implement comparison operators. Rust programs may
-//! implement `PartialOrd` to overload the `<`, `<=`, `>`, and `>=` operators,
-//! and may implement `PartialEq` to overload the `==` and `!=` operators.
+//! implement [`PartialOrd`] to overload the `<`, `<=`, `>`, and `>=` operators,
+//! and may implement [`PartialEq`] to overload the `==` and `!=` operators.
+//!
+//! [`PartialOrd`]: trait.PartialOrd.html
+//! [`PartialEq`]: trait.PartialEq.html
 //!
 //! # Examples
 //!
index 8342d663cdc7cf7275df75e4d5affffc54bcb6c0..9aba6703386a2ec2c04e6c245a13d04c4fbbe6df 100644 (file)
@@ -97,9 +97,7 @@ pub trait Write {
     /// This function will return an instance of `Error` on error.
     #[stable(feature = "fmt_write_char", since = "1.1.0")]
     fn write_char(&mut self, c: char) -> Result {
-        self.write_str(unsafe {
-            str::from_utf8_unchecked(c.encode_utf8().as_slice())
-        })
+        self.write_str(c.encode_utf8(&mut [0; 4]))
     }
 
     /// Glue for usage of the `write!` macro with implementors of this trait.
@@ -796,7 +794,7 @@ pub trait UpperExp {
 /// assert_eq!(output, "Hello world!");
 /// ```
 ///
-/// Please note that using [`write!`][write_macro] might be preferrable. Example:
+/// Please note that using [`write!`] might be preferrable. Example:
 ///
 /// ```
 /// use std::fmt::Write;
@@ -807,7 +805,7 @@ pub trait UpperExp {
 /// assert_eq!(output, "Hello world!");
 /// ```
 ///
-/// [write_macro]: ../../std/macro.write!.html
+/// [`write!`]: ../../std/macro.write.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn write(output: &mut Write, args: Arguments) -> Result {
     let mut formatter = Formatter {
@@ -924,9 +922,7 @@ pub fn pad_integral(&mut self,
         // Writes the sign if it exists, and then the prefix if it was requested
         let write_prefix = |f: &mut Formatter| {
             if let Some(c) = sign {
-                f.buf.write_str(unsafe {
-                    str::from_utf8_unchecked(c.encode_utf8().as_slice())
-                })?;
+                f.buf.write_str(c.encode_utf8(&mut [0; 4]))?;
             }
             if prefixed { f.buf.write_str(prefix) }
             else { Ok(()) }
@@ -1032,10 +1028,8 @@ fn with_padding<F>(&mut self, padding: usize, default: rt::v1::Alignment,
             rt::v1::Alignment::Center => (padding / 2, (padding + 1) / 2),
         };
 
-        let fill = self.fill.encode_utf8();
-        let fill = unsafe {
-            str::from_utf8_unchecked(fill.as_slice())
-        };
+        let mut fill = [0; 4];
+        let fill = self.fill.encode_utf8(&mut fill);
 
         for _ in 0..pre_pad {
             self.buf.write_str(fill)?;
@@ -1435,9 +1429,7 @@ fn fmt(&self, f: &mut Formatter) -> Result {
         if f.width.is_none() && f.precision.is_none() {
             f.write_char(*self)
         } else {
-            f.pad(unsafe {
-                str::from_utf8_unchecked(self.encode_utf8().as_slice())
-            })
+            f.pad(self.encode_utf8(&mut [0; 4]))
         }
     }
 }
@@ -1574,11 +1566,11 @@ fn fmt(&self, fmt: &mut Formatter) -> Result {
 // Implementation of Display/Debug for various core types
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Debug for *const T {
+impl<T: ?Sized> Debug for *const T {
     fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Debug for *mut T {
+impl<T: ?Sized> Debug for *mut T {
     fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) }
 }
 
index 22abe7a99b1870890bbfad80068066594147ab02..e844a158484af488b2adea942de2127bc12644cc 100644 (file)
     /// own, or if it does not enable any significant optimizations.
     pub fn assume(b: bool);
 
-    #[cfg(not(stage0))]
     /// Hints to the compiler that branch condition is likely to be true.
     /// Returns the value passed to it.
     ///
     /// Any use other than with `if` statements will probably not have an effect.
     pub fn likely(b: bool) -> bool;
 
-    #[cfg(not(stage0))]
     /// Hints to the compiler that branch condition is likely to be false.
     /// Returns the value passed to it.
     ///
 
     /// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
     /// bytes of memory starting at `dst` to `val`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ptr;
+    ///
+    /// let mut vec = vec![0; 4];
+    /// unsafe {
+    ///     let vec_ptr = vec.as_mut_ptr();
+    ///     ptr::write_bytes(vec_ptr, b'a', 2);
+    /// }
+    /// assert_eq!(vec, [b'a', b'a', 0, 0]);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
 
index 66d05d81d80cd7e92157bfd865eb5d353713791f..38afcb6a65e82f4029c328de62531cb3b769c7a0 100644 (file)
@@ -466,7 +466,11 @@ macro_rules! range_exact_iter_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
         impl ExactSizeIterator for ops::Range<$t> { }
+    )*)
+}
 
+macro_rules! range_incl_exact_iter_impl {
+    ($($t:ty)*) => ($(
         #[unstable(feature = "inclusive_range",
                    reason = "recently added, follows RFC",
                    issue = "28237")]
@@ -500,9 +504,12 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
-// Ranges of u64 and i64 are excluded because they cannot guarantee having
-// a length <= usize::MAX, which is required by ExactSizeIterator.
+// These macros generate `ExactSizeIterator` impls for various range types.
+// Range<{u,i}64> and RangeInclusive<{u,i}{32,64,size}> are excluded
+// because they cannot guarantee having a length <= usize::MAX, which is
+// required by ExactSizeIterator.
 range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32);
+range_incl_exact_iter_impl!(u8 u16 i8 i16);
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A: Step + Clone> DoubleEndedIterator for ops::Range<A> where
index d3b8a60b79776c3f00a304e3430f006b1a4abc59..e0aa25724c1f93924ce901139295d840355328af 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+use clone;
+use cmp;
+use fmt;
+use hash;
 use intrinsics;
+use marker::{Copy, PhantomData, Sized};
 use ptr;
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -647,3 +652,80 @@ pub fn drop<T>(_x: T) { }
 pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
     ptr::read(src as *const T as *const U)
 }
+
+/// Opaque type representing the discriminant of an enum.
+///
+/// See the `discriminant` function in this module for more information.
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+pub struct Discriminant<T>(u64, PhantomData<*const T>);
+
+// N.B. These trait implementations cannot be derived because we don't want any bounds on T.
+
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+impl<T> Copy for Discriminant<T> {}
+
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+impl<T> clone::Clone for Discriminant<T> {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+impl<T> cmp::PartialEq for Discriminant<T> {
+    fn eq(&self, rhs: &Self) -> bool {
+        self.0 == rhs.0
+    }
+}
+
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+impl<T> cmp::Eq for Discriminant<T> {}
+
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+impl<T> hash::Hash for Discriminant<T> {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        self.0.hash(state);
+    }
+}
+
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+impl<T> fmt::Debug for Discriminant<T> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt.debug_tuple("Discriminant")
+           .field(&self.0)
+           .finish()
+    }
+}
+
+/// Returns a value uniquely identifying the enum variant in `v`.
+///
+/// If `T` is not an enum, calling this function will not result in undefined behavior, but the
+/// return value is unspecified.
+///
+/// # Stability
+///
+/// The discriminant of an enum variant may change if the enum definition changes. A discriminant
+/// of some variant will not change between compilations with the same compiler.
+///
+/// # Examples
+///
+/// This can be used to compare enums that carry data, while disregarding
+/// the actual data:
+///
+/// ```
+/// #![feature(discriminant_value)]
+/// use std::mem;
+///
+/// enum Foo { A(&'static str), B(i32), C(i32) }
+///
+/// assert!(mem::discriminant(&Foo::A("bar")) == mem::discriminant(&Foo::A("baz")));
+/// assert!(mem::discriminant(&Foo::B(1))     == mem::discriminant(&Foo::B(2)));
+/// assert!(mem::discriminant(&Foo::B(3))     != mem::discriminant(&Foo::C(3)));
+/// ```
+#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
+pub fn discriminant<T>(v: &T) -> Discriminant<T> {
+    unsafe {
+        Discriminant(intrinsics::discriminant_value(v), PhantomData)
+    }
+}
+
index 85a52da332db53a8842a803ee14b83dd70fbf2d8..72e951a7c347c1f2c73f76c06d78e880c84472c2 100644 (file)
@@ -14,7 +14,7 @@
 //!
 //! Some of these traits are imported by the prelude, so they are available in
 //! every Rust program. Only operators backed by traits can be overloaded. For
-//! example, the addition operator (`+`) can be overloaded through the `Add`
+//! example, the addition operator (`+`) can be overloaded through the [`Add`]
 //! trait, but since the assignment operator (`=`) has no backing trait, there
 //! is no way of overloading its semantics. Additionally, this module does not
 //! provide any mechanism to create new operators. If traitless overloading or
 //! contexts involving built-in types, this is usually not a problem.
 //! However, using these operators in generic code, requires some
 //! attention if values have to be reused as opposed to letting the operators
-//! consume them. One option is to occasionally use `clone()`.
+//! consume them. One option is to occasionally use [`clone()`].
 //! Another option is to rely on the types involved providing additional
 //! operator implementations for references. For example, for a user-defined
 //! type `T` which is supposed to support addition, it is probably a good
-//! idea to have both `T` and `&T` implement the traits `Add<T>` and `Add<&T>`
-//! so that generic code can be written without unnecessary cloning.
+//! idea to have both `T` and `&T` implement the traits [`Add<T>`][`Add`] and
+//! [`Add<&T>`][`Add`] so that generic code can be written without unnecessary
+//! cloning.
 //!
 //! # Examples
 //!
-//! This example creates a `Point` struct that implements `Add` and `Sub`, and
-//! then demonstrates adding and subtracting two `Point`s.
+//! This example creates a `Point` struct that implements [`Add`] and [`Sub`],
+//! and then demonstrates adding and subtracting two `Point`s.
 //!
 //! ```rust
 //! use std::ops::{Add, Sub};
 //! See the documentation for each trait for an example implementation.
 //!
 //! The [`Fn`], [`FnMut`], and [`FnOnce`] traits are implemented by types that can be
-//! invoked like functions. Note that `Fn` takes `&self`, `FnMut` takes `&mut
-//! self` and `FnOnce` takes `self`. These correspond to the three kinds of
+//! invoked like functions. Note that [`Fn`] takes `&self`, [`FnMut`] takes `&mut
+//! self` and [`FnOnce`] takes `self`. These correspond to the three kinds of
 //! methods that can be invoked on an instance: call-by-reference,
 //! call-by-mutable-reference, and call-by-value. The most common use of these
 //! traits is to act as bounds to higher-level functions that take functions or
 //! closures as arguments.
 //!
-//! [`Fn`]: trait.Fn.html
-//! [`FnMut`]: trait.FnMut.html
-//! [`FnOnce`]: trait.FnOnce.html
-//!
-//! Taking a `Fn` as a parameter:
+//! Taking a [`Fn`] as a parameter:
 //!
 //! ```rust
 //! fn call_with_one<F>(func: F) -> usize
@@ -99,7 +96,7 @@
 //! assert_eq!(call_with_one(double), 2);
 //! ```
 //!
-//! Taking a `FnMut` as a parameter:
+//! Taking a [`FnMut`] as a parameter:
 //!
 //! ```rust
 //! fn do_twice<F>(mut func: F)
 //! assert_eq!(x, 5);
 //! ```
 //!
-//! Taking a `FnOnce` as a parameter:
+//! Taking a [`FnOnce`] as a parameter:
 //!
 //! ```rust
 //! fn consume_with_relish<F>(func: F)
 //!
 //! // `consume_and_return_x` can no longer be invoked at this point
 //! ```
+//!
+//! [`Fn`]: trait.Fn.html
+//! [`FnMut`]: trait.FnMut.html
+//! [`FnOnce`]: trait.FnOnce.html
+//! [`Add`]: trait.Add.html
+//! [`Sub`]: trait.Sub.html
+//! [`clone()`]: ../clone/trait.Clone.html#tymethod.clone
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -1873,7 +1877,7 @@ macro_rules! shr_assign_impl_all {
 shr_assign_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
 
 /// The `Index` trait is used to specify the functionality of indexing operations
-/// like `arr[idx]` when used in an immutable context.
+/// like `container[index]` when used in an immutable context.
 ///
 /// # Examples
 ///
@@ -1924,50 +1928,50 @@ pub trait Index<Idx: ?Sized> {
     #[stable(feature = "rust1", since = "1.0.0")]
     type Output: ?Sized;
 
-    /// The method for the indexing (`Foo[Bar]`) operation
+    /// The method for the indexing (`container[index]`) operation
     #[stable(feature = "rust1", since = "1.0.0")]
     fn index(&self, index: Idx) -> &Self::Output;
 }
 
 /// The `IndexMut` trait is used to specify the functionality of indexing
-/// operations like `arr[idx]`, when used in a mutable context.
+/// operations like `container[index]`, when used in a mutable context.
 ///
 /// # Examples
 ///
-/// A trivial implementation of `IndexMut`. When `Foo[Bar]` happens, it ends up
-/// calling `index_mut`, and therefore, `main` prints `Indexing!`.
+/// A trivial implementation of `IndexMut` for a type `Foo`. When `&mut Foo[2]`
+/// happens, it ends up calling `index_mut`, and therefore, `main` prints
+/// `Mutable indexing with 2!`.
 ///
 /// ```
 /// use std::ops::{Index, IndexMut};
 ///
 /// #[derive(Copy, Clone)]
 /// struct Foo;
-/// struct Bar;
 ///
-/// impl Index<Bar> for Foo {
+/// impl Index<usize> for Foo {
 ///     type Output = Foo;
 ///
-///     fn index<'a>(&'a self, _index: Bar) -> &'a Foo {
+///     fn index(&self, _index: usize) -> &Foo {
 ///         self
 ///     }
 /// }
 ///
-/// impl IndexMut<Bar> for Foo {
-///     fn index_mut<'a>(&'a mut self, _index: Bar) -> &'a mut Foo {
-///         println!("Indexing!");
+/// impl IndexMut<usize> for Foo {
+///     fn index_mut(&mut self, index: usize) -> &mut Foo {
+///         println!("Mutable indexing with {}!", index);
 ///         self
 ///     }
 /// }
 ///
 /// fn main() {
-///     &mut Foo[Bar];
+///     &mut Foo[2];
 /// }
 /// ```
 #[lang = "index_mut"]
 #[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
-    /// The method for the indexing (`Foo[Bar]`) operation
+    /// The method for the mutable indexing (`container[index]`) operation
     #[stable(feature = "rust1", since = "1.0.0")]
     fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
 }
index 199437a431eeea6c298947f6640b00c3921d71a1..7da0b6902f2717f5f6a584cd77d2c15eba74ed96 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::char;
+use std::{char,str};
 use std::convert::TryFrom;
 
 #[test]
@@ -248,10 +248,12 @@ fn string(c: char) -> String { c.escape_unicode().collect() }
 #[test]
 fn test_encode_utf8() {
     fn check(input: char, expect: &[u8]) {
-        assert_eq!(input.encode_utf8().as_slice(), expect);
-        for (a, b) in input.encode_utf8().zip(expect) {
-            assert_eq!(a, *b);
-        }
+        let mut buf = [0; 4];
+        let ptr = buf.as_ptr();
+        let s = input.encode_utf8(&mut buf);
+        assert_eq!(s.as_ptr() as usize, ptr as usize);
+        assert!(str::from_utf8(s.as_bytes()).is_ok());
+        assert_eq!(s.as_bytes(), expect);
     }
 
     check('x', &[0x78]);
@@ -263,10 +265,11 @@ fn check(input: char, expect: &[u8]) {
 #[test]
 fn test_encode_utf16() {
     fn check(input: char, expect: &[u16]) {
-        assert_eq!(input.encode_utf16().as_slice(), expect);
-        for (a, b) in input.encode_utf16().zip(expect) {
-            assert_eq!(a, *b);
-        }
+        let mut buf = [0; 2];
+        let ptr = buf.as_mut_ptr();
+        let b = input.encode_utf16(&mut buf);
+        assert_eq!(b.as_mut_ptr() as usize, ptr as usize);
+        assert_eq!(b, expect);
     }
 
     check('x', &[0x0078]);
index 857aae72c8a5bd5d92a0088a36bbe3c37fc58b37..0bca616ea9abcc99e5fc604ee4d91f2472b2985d 100644 (file)
@@ -8,6 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// FIXME https://github.com/kripken/emscripten/issues/4563
+// NB we have to actually not compile this test to avoid
+// an undefined symbol error
+#![cfg(not(target_os = "emscripten"))]
+
 use core::num::flt2dec::estimator::*;
 
 #[test]
index d4f6a19c55a03e3f9f6fb7377911b37ed807eb6c..b474785561d58efbd27add9d22339dcabad742ad 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d4f6a19c55a03e3f9f6fb7377911b37ed807eb6c
+Subproject commit b474785561d58efbd27add9d22339dcabad742ad
index 20d826d4a470ee7c7c14d85b6760caade6f26eef..0cf75c941508b7b378ceeb86cb3105e0c593df5b 100644 (file)
@@ -5,6 +5,7 @@ dependencies = [
  "alloc 0.0.0",
  "core 0.0.0",
  "libc 0.0.0",
+ "unwind 0.0.0",
 ]
 
 [[package]]
@@ -25,3 +26,11 @@ dependencies = [
  "core 0.0.0",
 ]
 
+[[package]]
+name = "unwind"
+version = "0.0.0"
+dependencies = [
+ "core 0.0.0",
+ "libc 0.0.0",
+]
+
diff --git a/src/libpanic_unwind/emcc.rs b/src/libpanic_unwind/emcc.rs
new file mode 100644 (file)
index 0000000..b3ab111
--- /dev/null
@@ -0,0 +1,78 @@
+// 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.
+
+//! Unwinding for emscripten
+//!
+//! Whereas Rust's usual unwinding implementation for Unix platforms
+//! calls into the libunwind APIs directly, on emscripten we instead
+//! call into the C++ unwinding APIs. This is just an expedience since
+//! emscripten's runtime always implements those APIs and does not
+//! implement libunwind.
+
+#![allow(private_no_mangle_fns)]
+
+use core::any::Any;
+use core::ptr;
+use alloc::boxed::Box;
+use libc::{self, c_int};
+use unwind as uw;
+use core::mem;
+
+pub fn payload() -> *mut u8 {
+    ptr::null_mut()
+}
+
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
+    assert!(!ptr.is_null());
+    let ex = ptr::read(ptr as *mut _);
+    __cxa_free_exception(ptr as *mut _);
+    ex
+}
+
+pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
+    let sz = mem::size_of_val(&data);
+    let exception = __cxa_allocate_exception(sz);
+    if exception == ptr::null_mut() {
+        return uw::_URC_FATAL_PHASE1_ERROR as u32;
+    }
+    let exception = exception as *mut Box<Any + Send>;
+    ptr::write(exception, data);
+    __cxa_throw(exception as *mut _, ptr::null_mut(), ptr::null_mut());
+
+    unreachable!()
+}
+
+#[lang = "eh_personality"]
+#[no_mangle]
+unsafe extern "C" fn rust_eh_personality(version: c_int,
+                                         actions: uw::_Unwind_Action,
+                                         exception_class: uw::_Unwind_Exception_Class,
+                                         exception_object: *mut uw::_Unwind_Exception,
+                                         context: *mut uw::_Unwind_Context)
+                                         -> uw::_Unwind_Reason_Code {
+    __gxx_personality_v0(version, actions,
+                         exception_class,
+                         exception_object,
+                         context)
+}
+
+extern {
+    fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void;
+    fn __cxa_free_exception(thrown_exception: *mut libc::c_void);
+    fn __cxa_throw(thrown_exception: *mut libc::c_void,
+                   tinfo: *mut libc::c_void,
+                   dest: *mut libc::c_void);
+    fn __gxx_personality_v0(version: c_int,
+                            actions: uw::_Unwind_Action,
+                            exception_class: uw::_Unwind_Exception_Class,
+                            exception_object: *mut uw::_Unwind_Exception,
+                            context: *mut uw::_Unwind_Context)
+                            -> uw::_Unwind_Reason_Code;
+}
index 11dd9befe0a82e940da630f68317591ef960187b..ff483fa823e0cc0c86d7b224474b0ad5ae7266d7 100644 (file)
 mod imp;
 
 // i686-pc-windows-gnu and all others
-#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))]
+#[cfg(any(all(unix, not(target_os = "emscripten")),
+          all(windows, target_arch = "x86", target_env = "gnu")))]
 #[path = "gcc.rs"]
 mod imp;
 
+// emscripten
+#[cfg(target_os = "emscripten")]
+#[path = "emcc.rs"]
+mod imp;
+
 mod dwarf;
 mod windows;
 
index 25a73226473b7556e3179a7ca77108cf98db7b15..50d4cbc982e97b2be8633d71090024b430f76ddb 100644 (file)
@@ -126,7 +126,7 @@ fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {
                 self.add_ast_node(pat.id, &[pats_exit])
             }
 
-            PatKind::Vec(ref pre, ref vec, ref post) => {
+            PatKind::Slice(ref pre, ref vec, ref post) => {
                 let pre_exit = self.pats_all(pre.iter(), pred);
                 let vec_exit = self.pats_all(vec.iter(), pre_exit);
                 let post_exit = self.pats_all(post.iter(), vec_exit);
@@ -298,7 +298,7 @@ fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
                 self.add_unreachable_node()
             }
 
-            hir::ExprVec(ref elems) => {
+            hir::ExprArray(ref elems) => {
                 self.straightline(expr, pred, elems.iter().map(|e| &**e))
             }
 
index 726e4e53e231c1fc5c592ac4e80b9be80f7c3524..b1771f52da2c6fef8b4fa31ade542c9ea393c380 100644 (file)
@@ -394,7 +394,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
     visitor.visit_id(typ.id);
 
     match typ.node {
-        TyVec(ref ty) => {
+        TySlice(ref ty) => {
             visitor.visit_ty(ty)
         }
         TyPtr(ref mutable_type) => {
@@ -422,7 +422,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_ty_param_bound, bounds);
         }
-        TyFixedLengthVec(ref ty, ref expression) => {
+        TyArray(ref ty, ref expression) => {
             visitor.visit_ty(ty);
             visitor.visit_expr(expression)
         }
@@ -520,7 +520,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
             visitor.visit_expr(upper_bound)
         }
         PatKind::Wild => (),
-        PatKind::Vec(ref prepatterns, ref slice_pattern, ref postpatterns) => {
+        PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => {
             walk_list!(visitor, visit_pat, prepatterns);
             walk_list!(visitor, visit_pat, slice_pattern);
             walk_list!(visitor, visit_pat, postpatterns);
@@ -749,7 +749,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
         ExprBox(ref subexpression) => {
             visitor.visit_expr(subexpression)
         }
-        ExprVec(ref subexpressions) => {
+        ExprArray(ref subexpressions) => {
             walk_list!(visitor, visit_expr, subexpressions);
         }
         ExprRepeat(ref element, ref count) => {
index 29dedeeeb03e646414b730635837fac25bd2414c..dace486b277db7e5360287fe876610486994a6a8 100644 (file)
@@ -222,17 +222,16 @@ fn lower_ty_binding(&mut self, b: &TypeBinding) -> hir::TypeBinding {
     }
 
     fn lower_ty(&mut self, t: &Ty) -> P<hir::Ty> {
-        use syntax::ast::TyKind::*;
         P(hir::Ty {
             id: t.id,
             node: match t.node {
-                Infer | ImplicitSelf => hir::TyInfer,
-                Vec(ref ty) => hir::TyVec(self.lower_ty(ty)),
-                Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
-                Rptr(ref region, ref mt) => {
+                TyKind::Infer | TyKind::ImplicitSelf => hir::TyInfer,
+                TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
+                TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
+                TyKind::Rptr(ref region, ref mt) => {
                     hir::TyRptr(self.lower_opt_lifetime(region), self.lower_mt(mt))
                 }
-                BareFn(ref f) => {
+                TyKind::BareFn(ref f) => {
                     hir::TyBareFn(P(hir::BareFnTy {
                         lifetimes: self.lower_lifetime_defs(&f.lifetimes),
                         unsafety: self.lower_unsafety(f.unsafety),
@@ -240,12 +239,14 @@ fn lower_ty(&mut self, t: &Ty) -> P<hir::Ty> {
                         decl: self.lower_fn_decl(&f.decl),
                     }))
                 }
-                Never => hir::TyNever,
-                Tup(ref tys) => hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect()),
-                Paren(ref ty) => {
+                TyKind::Never => hir::TyNever,
+                TyKind::Tup(ref tys) => {
+                    hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect())
+                }
+                TyKind::Paren(ref ty) => {
                     return self.lower_ty(ty);
                 }
-                Path(ref qself, ref path) => {
+                TyKind::Path(ref qself, ref path) => {
                     let qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
                         hir::QSelf {
                             ty: self.lower_ty(ty),
@@ -254,22 +255,22 @@ fn lower_ty(&mut self, t: &Ty) -> P<hir::Ty> {
                     });
                     hir::TyPath(qself, self.lower_path(path))
                 }
-                ObjectSum(ref ty, ref bounds) => {
+                TyKind::ObjectSum(ref ty, ref bounds) => {
                     hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds))
                 }
-                FixedLengthVec(ref ty, ref e) => {
-                    hir::TyFixedLengthVec(self.lower_ty(ty), self.lower_expr(e))
+                TyKind::Array(ref ty, ref e) => {
+                    hir::TyArray(self.lower_ty(ty), self.lower_expr(e))
                 }
-                Typeof(ref expr) => {
+                TyKind::Typeof(ref expr) => {
                     hir::TyTypeof(self.lower_expr(expr))
                 }
-                PolyTraitRef(ref bounds) => {
+                TyKind::PolyTraitRef(ref bounds) => {
                     hir::TyPolyTraitRef(self.lower_bounds(bounds))
                 }
-                ImplTrait(ref bounds) => {
+                TyKind::ImplTrait(ref bounds) => {
                     hir::TyImplTrait(self.lower_bounds(bounds))
                 }
-                Mac(_) => panic!("TyMac should have been expanded by now."),
+                TyKind::Mac(_) => panic!("TyMac should have been expanded by now."),
             },
             span: t.span,
         })
@@ -891,8 +892,8 @@ fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
                 PatKind::Range(ref e1, ref e2) => {
                     hir::PatKind::Range(self.lower_expr(e1), self.lower_expr(e2))
                 }
-                PatKind::Vec(ref before, ref slice, ref after) => {
-                    hir::PatKind::Vec(before.iter().map(|x| self.lower_pat(x)).collect(),
+                PatKind::Slice(ref before, ref slice, ref after) => {
+                    hir::PatKind::Slice(before.iter().map(|x| self.lower_pat(x)).collect(),
                                 slice.as_ref().map(|x| self.lower_pat(x)),
                                 after.iter().map(|x| self.lower_pat(x)).collect())
                 }
@@ -1031,7 +1032,7 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
                 }
 
                 ExprKind::Vec(ref exprs) => {
-                    hir::ExprVec(exprs.iter().map(|x| self.lower_expr(x)).collect())
+                    hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect())
                 }
                 ExprKind::Repeat(ref expr, ref count) => {
                     let expr = self.lower_expr(expr);
index b0a717e18f98d79796d0a19297e04e3f106e457f..421843a7f11d8752af6ac3bfa71126a14d68d097 100644 (file)
 use middle::cstore::InlinedItem;
 
 use syntax::ast::*;
+use syntax::ext::hygiene::Mark;
 use syntax::visit;
-use syntax::parse::token;
+use syntax::parse::token::{self, keywords};
 
 /// Creates def ids for nodes in the HIR.
-pub struct DefCollector<'ast> {
+pub struct DefCollector<'a> {
     // If we are walking HIR (c.f., AST), we need to keep a reference to the
     // crate.
-    hir_crate: Option<&'ast hir::Crate>,
-    definitions: &'ast mut Definitions,
+    hir_crate: Option<&'a hir::Crate>,
+    definitions: &'a mut Definitions,
     parent_def: Option<DefIndex>,
+    pub visit_macro_invoc: Option<&'a mut FnMut(MacroInvocationData)>,
 }
 
-impl<'ast> DefCollector<'ast> {
-    pub fn new(definitions: &'ast mut Definitions) -> DefCollector<'ast> {
+pub struct MacroInvocationData {
+    pub mark: Mark,
+    pub def_index: DefIndex,
+    pub const_integer: bool,
+}
+
+impl<'a> DefCollector<'a> {
+    pub fn new(definitions: &'a mut Definitions) -> Self {
         DefCollector {
             hir_crate: None,
             definitions: definitions,
             parent_def: None,
+            visit_macro_invoc: None,
         }
     }
 
     pub fn extend(parent_node: NodeId,
                   parent_def_path: DefPath,
                   parent_def_id: DefId,
-                  definitions: &'ast mut Definitions)
-                  -> DefCollector<'ast> {
+                  definitions: &'a mut Definitions)
+                  -> Self {
         let mut collector = DefCollector::new(definitions);
 
         assert_eq!(parent_def_path.krate, parent_def_id.krate);
@@ -65,7 +74,7 @@ pub fn collect_root(&mut self) {
         self.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc);
     }
 
-    pub fn walk_item(&mut self, ii: &'ast InlinedItem, krate: &'ast hir::Crate) {
+    pub fn walk_item(&mut self, ii: &'a InlinedItem, krate: &'a hir::Crate) {
         self.hir_crate = Some(krate);
         ii.visit(self);
     }
@@ -84,29 +93,28 @@ fn create_def_with_parent(&mut self,
         self.definitions.create_def_with_parent(parent, node_id, data)
     }
 
-    fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
+    pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
         let parent = self.parent_def;
         self.parent_def = Some(parent_def);
         f(self);
         self.parent_def = parent;
     }
 
-    fn visit_ast_const_integer(&mut self, expr: &Expr) {
-        // Find the node which will be used after lowering.
-        if let ExprKind::Paren(ref inner) = expr.node {
-            return self.visit_ast_const_integer(inner);
-        }
-
-        // FIXME(eddyb) Closures should have separate
-        // function definition IDs and expression IDs.
-        if let ExprKind::Closure(..) = expr.node {
-            return;
+    pub fn visit_ast_const_integer(&mut self, expr: &Expr) {
+        match expr.node {
+            // Find the node which will be used after lowering.
+            ExprKind::Paren(ref inner) => return self.visit_ast_const_integer(inner),
+            ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, true),
+            // FIXME(eddyb) Closures should have separate
+            // function definition IDs and expression IDs.
+            ExprKind::Closure(..) => return,
+            _ => {}
         }
 
         self.create_def(expr.id, DefPathData::Initializer);
     }
 
-    fn visit_hir_const_integer(&mut self, expr: &'ast hir::Expr) {
+    fn visit_hir_const_integer(&mut self, expr: &hir::Expr) {
         // FIXME(eddyb) Closures should have separate
         // function definition IDs and expression IDs.
         if let hir::ExprClosure(..) = expr.node {
@@ -115,9 +123,19 @@ fn visit_hir_const_integer(&mut self, expr: &'ast hir::Expr) {
 
         self.create_def(expr.id, DefPathData::Initializer);
     }
+
+    fn visit_macro_invoc(&mut self, id: NodeId, const_integer: bool) {
+        if let Some(ref mut visit) = self.visit_macro_invoc {
+            visit(MacroInvocationData {
+                mark: Mark::from_placeholder_id(id),
+                const_integer: const_integer,
+                def_index: self.parent_def.unwrap(),
+            })
+        }
+    }
 }
 
-impl<'ast> visit::Visitor for DefCollector<'ast> {
+impl<'a> visit::Visitor for DefCollector<'a> {
     fn visit_item(&mut self, i: &Item) {
         debug!("visit_item: {:?}", i);
 
@@ -129,10 +147,14 @@ fn visit_item(&mut self, i: &Item) {
             ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) |
             ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
                 DefPathData::TypeNs(i.ident.name.as_str()),
+            ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
+                return visit::walk_item(self, i);
+            }
             ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
             ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
                 DefPathData::ValueNs(i.ident.name.as_str()),
-            ItemKind::Mac(..) => DefPathData::MacroDef(i.ident.name.as_str()),
+            ItemKind::Mac(..) if i.id == DUMMY_NODE_ID => return, // Scope placeholder
+            ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false),
             ItemKind::Use(..) => DefPathData::Misc,
         };
         let def = self.create_def(i.id, def_data);
@@ -198,7 +220,7 @@ fn visit_trait_item(&mut self, ti: &TraitItem) {
             TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
                 DefPathData::ValueNs(ti.ident.name.as_str()),
             TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name.as_str()),
-            TraitItemKind::Macro(..) => DefPathData::MacroDef(ti.ident.name.as_str()),
+            TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false),
         };
 
         let def = self.create_def(ti.id, def_data);
@@ -216,7 +238,7 @@ fn visit_impl_item(&mut self, ii: &ImplItem) {
             ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
                 DefPathData::ValueNs(ii.ident.name.as_str()),
             ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name.as_str()),
-            ImplItemKind::Macro(..) => DefPathData::MacroDef(ii.ident.name.as_str()),
+            ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false),
         };
 
         let def = self.create_def(ii.id, def_data);
@@ -232,9 +254,13 @@ fn visit_impl_item(&mut self, ii: &ImplItem) {
     fn visit_pat(&mut self, pat: &Pat) {
         let parent_def = self.parent_def;
 
-        if let PatKind::Ident(_, id, _) = pat.node {
-            let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str()));
-            self.parent_def = Some(def);
+        match pat.node {
+            PatKind::Mac(..) => return self.visit_macro_invoc(pat.id, false),
+            PatKind::Ident(_, id, _) => {
+                let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str()));
+                self.parent_def = Some(def);
+            }
+            _ => {}
         }
 
         visit::walk_pat(self, pat);
@@ -244,13 +270,14 @@ fn visit_pat(&mut self, pat: &Pat) {
     fn visit_expr(&mut self, expr: &Expr) {
         let parent_def = self.parent_def;
 
-        if let ExprKind::Repeat(_, ref count) = expr.node {
-            self.visit_ast_const_integer(count);
-        }
-
-        if let ExprKind::Closure(..) = expr.node {
-            let def = self.create_def(expr.id, DefPathData::ClosureExpr);
-            self.parent_def = Some(def);
+        match expr.node {
+            ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, false),
+            ExprKind::Repeat(_, ref count) => self.visit_ast_const_integer(count),
+            ExprKind::Closure(..) => {
+                let def = self.create_def(expr.id, DefPathData::ClosureExpr);
+                self.parent_def = Some(def);
+            }
+            _ => {}
         }
 
         visit::walk_expr(self, expr);
@@ -258,11 +285,13 @@ fn visit_expr(&mut self, expr: &Expr) {
     }
 
     fn visit_ty(&mut self, ty: &Ty) {
-        if let TyKind::FixedLengthVec(_, ref length) = ty.node {
-            self.visit_ast_const_integer(length);
-        }
-        if let TyKind::ImplTrait(..) = ty.node {
-            self.create_def(ty.id, DefPathData::ImplTrait);
+        match ty.node {
+            TyKind::Mac(..) => return self.visit_macro_invoc(ty.id, false),
+            TyKind::Array(_, ref length) => self.visit_ast_const_integer(length),
+            TyKind::ImplTrait(..) => {
+                self.create_def(ty.id, DefPathData::ImplTrait);
+            }
+            _ => {}
         }
         visit::walk_ty(self, ty);
     }
@@ -274,6 +303,13 @@ fn visit_lifetime_def(&mut self, def: &LifetimeDef) {
     fn visit_macro_def(&mut self, macro_def: &MacroDef) {
         self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str()));
     }
+
+    fn visit_stmt(&mut self, stmt: &Stmt) {
+        match stmt.node {
+            StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false),
+            _ => visit::walk_stmt(self, stmt),
+        }
+    }
 }
 
 // We walk the HIR rather than the AST when reading items from metadata.
@@ -413,7 +449,7 @@ fn visit_expr(&mut self, expr: &'ast hir::Expr) {
     }
 
     fn visit_ty(&mut self, ty: &'ast hir::Ty) {
-        if let hir::TyFixedLengthVec(_, ref length) = ty.node {
+        if let hir::TyArray(_, ref length) = ty.node {
             self.visit_hir_const_integer(length);
         }
         if let hir::TyImplTrait(..) = ty.node {
index 5cfb71f4fc877f81b5011eb2538296cb24bc4bb0..f87844652cc199e8e6ab0e0e9cd36644ccf7bf9d 100644 (file)
@@ -9,11 +9,10 @@
 // except according to those terms.
 
 use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
-use hir::map::def_collector::DefCollector;
 use rustc_data_structures::fnv::FnvHashMap;
 use std::fmt::Write;
 use std::hash::{Hash, Hasher, SipHasher};
-use syntax::{ast, visit};
+use syntax::ast;
 use syntax::parse::token::{self, InternedString};
 use ty::TyCtxt;
 use util::nodemap::NodeMap;
@@ -224,12 +223,6 @@ pub fn new() -> Definitions {
         }
     }
 
-    pub fn collect(&mut self, krate: &ast::Crate) {
-        let mut def_collector = DefCollector::new(self);
-        def_collector.collect_root();
-        visit::walk_crate(&mut def_collector, krate);
-    }
-
     /// Get the number of definitions.
     pub fn len(&self) -> usize {
         self.data.len()
index b351bd427acbc26de10d8a477d7b10473b09ac9a..39114ec4238e72a9682c6a7b99f87e6ed7fe48f1 100644 (file)
@@ -11,7 +11,7 @@
 pub use self::Node::*;
 use self::MapEntry::*;
 use self::collector::NodeCollector;
-use self::def_collector::DefCollector;
+pub use self::def_collector::{DefCollector, MacroInvocationData};
 pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
                             DisambiguatedDefPathData, InlinedRootPath};
 
@@ -260,7 +260,7 @@ fn dep_node(&self, id0: NodeId) -> DepNode<DefId> {
                     EntryVariant(p, _) |
                     EntryExpr(p, _) |
                     EntryStmt(p, _) |
-                EntryTy(p, _) |
+                    EntryTy(p, _) |
                     EntryLocal(p, _) |
                     EntryPat(p, _) |
                     EntryBlock(p, _) |
index 0cfdbae1a50b0a53d7bd1f9e1392620dc45eb391..f64b0e9c7342cf994cfc8624b8261ea66443b500 100644 (file)
@@ -478,7 +478,7 @@ fn walk_<G>(&self, it: &mut G) -> bool
             PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
                 s.walk_(it)
             }
-            PatKind::Vec(ref before, ref slice, ref after) => {
+            PatKind::Slice(ref before, ref slice, ref after) => {
                 before.iter().all(|p| p.walk_(it)) &&
                 slice.iter().all(|p| p.walk_(it)) &&
                 after.iter().all(|p| p.walk_(it))
@@ -554,8 +554,8 @@ pub enum PatKind {
     /// A range pattern, e.g. `1...2`
     Range(P<Expr>, P<Expr>),
     /// `[a, b, ..i, y, z]` is represented as:
-    ///     `PatKind::Vec(box [a, b], Some(i), box [y, z])`
-    Vec(HirVec<P<Pat>>, Option<P<Pat>>, HirVec<P<Pat>>),
+    ///     `PatKind::Slice(box [a, b], Some(i), box [y, z])`
+    Slice(HirVec<P<Pat>>, Option<P<Pat>>, HirVec<P<Pat>>),
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
@@ -826,7 +826,7 @@ pub enum Expr_ {
     /// A `box x` expression.
     ExprBox(P<Expr>),
     /// An array (`[a, b, c, d]`)
-    ExprVec(HirVec<P<Expr>>),
+    ExprArray(HirVec<P<Expr>>),
     /// A function call
     ///
     /// The first field resolves to the function itself (usually an `ExprPath`),
@@ -1080,10 +1080,10 @@ pub struct BareFnTy {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 /// The different kinds of types recognized by the compiler
 pub enum Ty_ {
-    /// A variable length array (`[T]`)
-    TyVec(P<Ty>),
+    /// A variable length slice (`[T]`)
+    TySlice(P<Ty>),
     /// A fixed length array (`[T; n]`)
-    TyFixedLengthVec(P<Ty>, P<Expr>),
+    TyArray(P<Ty>, P<Expr>),
     /// A raw pointer (`*const T` or `*mut T`)
     TyPtr(MutTy),
     /// A reference (`&'a T` or `&'a mut T`)
index dec41fdfc3b50c35a4693339c61948d6488a3407..505d126db7f4fb9f6b848d58ec2d468c5de1ebfd 100644 (file)
@@ -62,7 +62,7 @@ pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
                 _ => false
             }
         }
-        PatKind::Vec(..) => true,
+        PatKind::Slice(..) => true,
         _ => false
     }
 }
index eebc8fa9e5d5dfd6aadc0cd48cca061f0e427418..90b92beb7a7fbf0eb17e332c6bed942b181e1ab8 100644 (file)
@@ -486,7 +486,7 @@ pub fn print_type(&mut self, ty: &hir::Ty) -> io::Result<()> {
         self.maybe_print_comment(ty.span.lo)?;
         self.ibox(0)?;
         match ty.node {
-            hir::TyVec(ref ty) => {
+            hir::TySlice(ref ty) => {
                 word(&mut self.s, "[")?;
                 self.print_type(&ty)?;
                 word(&mut self.s, "]")?;
@@ -543,7 +543,7 @@ pub fn print_type(&mut self, ty: &hir::Ty) -> io::Result<()> {
             hir::TyImplTrait(ref bounds) => {
                 self.print_bounds("impl ", &bounds[..])?;
             }
-            hir::TyFixedLengthVec(ref ty, ref v) => {
+            hir::TyArray(ref ty, ref v) => {
                 word(&mut self.s, "[")?;
                 self.print_type(&ty)?;
                 word(&mut self.s, "; ")?;
@@ -1319,7 +1319,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
                 self.word_space("box")?;
                 self.print_expr(expr)?;
             }
-            hir::ExprVec(ref exprs) => {
+            hir::ExprArray(ref exprs) => {
                 self.print_expr_vec(&exprs[..])?;
             }
             hir::ExprRepeat(ref element, ref count) => {
@@ -1829,7 +1829,7 @@ pub fn print_pat(&mut self, pat: &hir::Pat) -> io::Result<()> {
                 word(&mut self.s, "...")?;
                 self.print_expr(&end)?;
             }
-            PatKind::Vec(ref before, ref slice, ref after) => {
+            PatKind::Slice(ref before, ref slice, ref after) => {
                 word(&mut self.s, "[")?;
                 self.commasep(Inconsistent, &before[..], |s, p| s.print_pat(&p))?;
                 if let Some(ref p) = *slice {
index 2792968d427aa95d39b99bf2e6e2202bd6800153..3f216d6916851a15867247edc15111a336d78c51 100644 (file)
@@ -1433,8 +1433,8 @@ fn rebuild_arg_ty_or_output(&self,
                 hir::TyPtr(ref mut_ty) => {
                     ty_queue.push(&mut_ty.ty);
                 }
-                hir::TyVec(ref ty) |
-                hir::TyFixedLengthVec(ref ty, _) => {
+                hir::TySlice(ref ty) |
+                hir::TyArray(ref ty, _) => {
                     ty_queue.push(&ty);
                 }
                 hir::TyTup(ref tys) => ty_queue.extend(tys.iter().map(|ty| &**ty)),
@@ -1469,9 +1469,9 @@ fn build_to(from: P<hir::Ty>,
                             ty: build_to(mut_ty.ty, to),
                         })
                     }
-                    hir::TyVec(ty) => hir::TyVec(build_to(ty, to)),
-                    hir::TyFixedLengthVec(ty, e) => {
-                        hir::TyFixedLengthVec(build_to(ty, to), e)
+                    hir::TySlice(ty) => hir::TySlice(build_to(ty, to)),
+                    hir::TyArray(ty, e) => {
+                        hir::TyArray(build_to(ty, to), e)
                     }
                     hir::TyTup(tys) => {
                         hir::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect())
index 107cf9b6cae6bd46c32dddd87b319f27953165c9..be91b86dbcc95738b5479d5339371dc535819870 100644 (file)
@@ -32,7 +32,6 @@
 use mir::repr::Mir;
 use mir::mir_map::MirMap;
 use session::Session;
-use session::config::PanicStrategy;
 use session::search_paths::PathKind;
 use util::nodemap::{NodeSet, DefIdMap};
 use std::path::PathBuf;
@@ -46,6 +45,7 @@
 use rustc_back::target::Target;
 use hir;
 use hir::intravisit::Visitor;
+use rustc_back::PanicStrategy;
 
 pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown};
 
@@ -423,7 +423,12 @@ fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
     fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") }
 }
 
-pub enum LoadedMacro {
+pub struct LoadedMacro {
+    pub import_site: Span,
+    pub kind: LoadedMacroKind,
+}
+
+pub enum LoadedMacroKind {
     Def(ast::MacroDef),
     CustomDerive(String, Rc<MultiItemModifier>),
 }
index c6908e11ed20950902468383b5437c203ff89769..159b7256c7a27a92f369419f1df37f71dcc04c7d 100644 (file)
 use hir::def_id::CrateNum;
 
 use session;
-use session::config::{self, PanicStrategy};
+use session::config;
 use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic};
 use util::nodemap::FnvHashMap;
+use rustc_back::PanicStrategy;
 
 /// A list of dependencies for a certain crate type.
 ///
@@ -357,7 +358,7 @@ fn verify_ok(sess: &session::Session, list: &[Linkage]) {
     // only one, but we perform validation here that all the panic strategy
     // compilation modes for the whole DAG are valid.
     if let Some((cnum, found_strategy)) = panic_runtime {
-        let desired_strategy = sess.opts.cg.panic.clone();
+        let desired_strategy = sess.panic_strategy();
 
         // First up, validate that our selected panic runtime is indeed exactly
         // our same strategy.
index 5b5c3da8f05b2eae0334c60879f5a8d7e0f2933d..d7392338d5ed9539af80d2c660f5e75af5c870f7 100644 (file)
@@ -442,7 +442,7 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
                 }
             }
 
-            hir::ExprVec(ref exprs) => {
+            hir::ExprArray(ref exprs) => {
                 self.consume_exprs(exprs);
             }
 
index 61bcc05bbb4f4d25c6549cb285f17b42c26edc3f..1acd0fb0f79c05d4c0c29fb3d0abd7e2e1f50dd1 100644 (file)
@@ -103,11 +103,16 @@ fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>, id: ast::Nod
             }
         };
 
-        span_err!(self.infcx.tcx.sess, span, E0512,
+        struct_span_err!(self.infcx.tcx.sess, span, E0512,
                   "transmute called with differently sized types: \
                    {} ({}) to {} ({})",
                   from, skeleton_string(from, sk_from),
-                  to, skeleton_string(to, sk_to));
+                  to, skeleton_string(to, sk_to))
+            .span_label(span,
+                &format!("transmuting between {} and {}",
+                    skeleton_string(from, sk_from),
+                    skeleton_string(to, sk_to)))
+            .emit();
     }
 }
 
index db9dd82d492d3193650fd464a0248bd63991511a..79396b9ca4dab155cda150de99f7af64395c3a90 100644 (file)
@@ -490,7 +490,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
 
       // otherwise, live nodes are not required:
       hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprTupField(..) |
-      hir::ExprVec(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) |
+      hir::ExprArray(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) |
       hir::ExprTup(..) | hir::ExprBinary(..) | hir::ExprAddrOf(..) |
       hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprBreak(_) |
       hir::ExprAgain(_) | hir::ExprLit(_) | hir::ExprRet(..) |
@@ -1095,7 +1095,7 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
 
           // Uninteresting cases: just propagate in rev exec order
 
-          hir::ExprVec(ref exprs) => {
+          hir::ExprArray(ref exprs) => {
             self.propagate_through_exprs(&exprs[..], succ)
           }
 
@@ -1436,7 +1436,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       hir::ExprCall(..) | hir::ExprMethodCall(..) | hir::ExprIf(..) |
       hir::ExprMatch(..) | hir::ExprWhile(..) | hir::ExprLoop(..) |
       hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprTupField(..) |
-      hir::ExprVec(..) | hir::ExprTup(..) | hir::ExprBinary(..) |
+      hir::ExprArray(..) | hir::ExprTup(..) | hir::ExprBinary(..) |
       hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprRet(..) |
       hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(_) |
       hir::ExprBlock(..) | hir::ExprAddrOf(..) |
index 340a5ac8f87b73a03f6a06adb8360006ece44cfd..c50e668a417946c59d12bc377ab43dce9c2bb88d 100644 (file)
@@ -503,7 +503,7 @@ pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
           hir::ExprClosure(..) | hir::ExprRet(..) |
           hir::ExprUnary(..) |
           hir::ExprMethodCall(..) | hir::ExprCast(..) |
-          hir::ExprVec(..) | hir::ExprTup(..) | hir::ExprIf(..) |
+          hir::ExprArray(..) | hir::ExprTup(..) | hir::ExprIf(..) |
           hir::ExprBinary(..) | hir::ExprWhile(..) |
           hir::ExprBlock(..) | hir::ExprLoop(..) | hir::ExprMatch(..) |
           hir::ExprLit(..) | hir::ExprBreak(..) |
@@ -1155,7 +1155,7 @@ fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResul
             self.cat_pattern_(subcmt, &subpat, op)?;
           }
 
-          PatKind::Vec(ref before, ref slice, ref after) => {
+          PatKind::Slice(ref before, ref slice, ref after) => {
             let context = InteriorOffsetKind::Pattern;
             let elt_cmt = self.cat_index(pat, cmt, context)?;
             for before_pat in before {
index 33110c61e8f8b1f0cf95c30f319c600f599a545d..90b6cbad3d9aea54849a66893debd7e0279bcae0 100644 (file)
@@ -961,7 +961,7 @@ fn is_binding_pat(pat: &hir::Pat) -> bool {
                 field_pats.iter().any(|fp| is_binding_pat(&fp.node.pat))
             }
 
-            PatKind::Vec(ref pats1, ref pats2, ref pats3) => {
+            PatKind::Slice(ref pats1, ref pats2, ref pats3) => {
                 pats1.iter().any(|p| is_binding_pat(&p)) ||
                 pats2.iter().any(|p| is_binding_pat(&p)) ||
                 pats3.iter().any(|p| is_binding_pat(&p))
@@ -1012,7 +1012,7 @@ fn record_rvalue_scope_if_borrow_expr(visitor: &mut RegionResolutionVisitor,
                         visitor, &field.expr, blk_id);
                 }
             }
-            hir::ExprVec(ref subexprs) |
+            hir::ExprArray(ref subexprs) |
             hir::ExprTup(ref subexprs) => {
                 for subexpr in subexprs {
                     record_rvalue_scope_if_borrow_expr(
index 2c768db47f11a94661c000b9c99ae6167443fc3b..ccab4279232b5f4e8b9b56412c77bea0175087da 100644 (file)
@@ -411,8 +411,8 @@ fn check(&mut self, id: DefId, span: Span,
                                                &feature, &r),
                         None => format!("use of unstable library feature '{}'", &feature)
                     };
-                    emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic,
-                                      &feature, span, GateIssue::Library(Some(issue)), &msg);
+                    emit_feature_err(&self.tcx.sess.parse_sess, &feature, span,
+                                     GateIssue::Library(Some(issue)), &msg);
                 }
             }
             Some(&Stability { ref level, ref feature, .. }) => {
index c2f275e6deaf82671a27c49f4aad8e88b1bf43ad..aa75c7a572bc5ba322f9d3d6219cfc438879f0d8 100644 (file)
 
 //! Validity checking for weak lang items
 
-use session::config::{self, PanicStrategy};
+use session::config;
 use session::Session;
 use middle::lang_items;
 
+use rustc_back::PanicStrategy;
 use syntax::ast;
 use syntax::parse::token::InternedString;
 use syntax_pos::Span;
@@ -92,7 +93,7 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) {
     // symbols. Other panic runtimes ensure that the relevant symbols are
     // available to link things together, but they're never exercised.
     let mut whitelisted = HashSet::new();
-    if sess.opts.cg.panic != PanicStrategy::Unwind {
+    if sess.panic_strategy() != PanicStrategy::Unwind {
         whitelisted.insert(lang_items::EhPersonalityLangItem);
         whitelisted.insert(lang_items::EhUnwindResumeLangItem);
     }
index 70b0b810c6c4805801c5b41095a3ae045ae4de9b..f11dc3740da666a2bd53b6474d0fc12a2134eed5 100644 (file)
@@ -70,29 +70,37 @@ pub struct Mir<'tcx> {
 
     /// Rvalues promoted from this function, such as borrows of constants.
     /// Each of them is the Mir of a constant with the fn's type parameters
-    /// in scope, but no vars or args and a separate set of temps.
+    /// in scope, but a separate set of locals.
     pub promoted: IndexVec<Promoted, Mir<'tcx>>,
 
     /// Return type of the function.
     pub return_ty: Ty<'tcx>,
 
-    /// Variables: these are stack slots corresponding to user variables. They may be
-    /// assigned many times.
-    pub var_decls: IndexVec<Var, VarDecl<'tcx>>,
-
-    /// Args: these are stack slots corresponding to the input arguments.
-    pub arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
+    /// Declarations of locals.
+    ///
+    /// The first local is the return value pointer, followed by `arg_count`
+    /// locals for the function arguments, followed by any user-declared
+    /// variables and temporaries.
+    pub local_decls: IndexVec<Local, LocalDecl<'tcx>>,
 
-    /// Temp declarations: stack slots that for temporaries created by
-    /// the compiler. These are assigned once, but they are not SSA
-    /// values in that it is possible to borrow them and mutate them
-    /// through the resulting reference.
-    pub temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
+    /// Number of arguments this function takes.
+    ///
+    /// Starting at local 1, `arg_count` locals will be provided by the caller
+    /// and can be assumed to be initialized.
+    ///
+    /// If this MIR was built for a constant, this will be 0.
+    pub arg_count: usize,
 
     /// Names and capture modes of all the closure upvars, assuming
     /// the first argument is either the closure or a reference to it.
     pub upvar_decls: Vec<UpvarDecl>,
 
+    /// Mark an argument local (which must be a tuple) as getting passed as
+    /// its individual components at the LLVM level.
+    ///
+    /// This is used for the "rust-call" ABI.
+    pub spread_arg: Option<Local>,
+
     /// A span representing this MIR, for error reporting
     pub span: Span,
 
@@ -108,21 +116,25 @@ pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
                visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
                promoted: IndexVec<Promoted, Mir<'tcx>>,
                return_ty: Ty<'tcx>,
-               var_decls: IndexVec<Var, VarDecl<'tcx>>,
-               arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
-               temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
+               local_decls: IndexVec<Local, LocalDecl<'tcx>>,
+               arg_count: usize,
                upvar_decls: Vec<UpvarDecl>,
                span: Span) -> Self
     {
+        // We need `arg_count` locals, and one for the return pointer
+        assert!(local_decls.len() >= arg_count + 1,
+            "expected at least {} locals, got {}", arg_count + 1, local_decls.len());
+        assert_eq!(local_decls[RETURN_POINTER].ty, return_ty);
+
         Mir {
             basic_blocks: basic_blocks,
             visibility_scopes: visibility_scopes,
             promoted: promoted,
             return_ty: return_ty,
-            var_decls: var_decls,
-            arg_decls: arg_decls,
-            temp_decls: temp_decls,
+            local_decls: local_decls,
+            arg_count: arg_count,
             upvar_decls: upvar_decls,
+            spread_arg: None,
             span: span,
             cache: Cache::new()
         }
@@ -154,56 +166,66 @@ pub fn dominators(&self) -> Dominators<BasicBlock> {
         dominators(self)
     }
 
-    /// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order)
-    /// to their index in the whole list of locals. This is useful if you
-    /// want to treat all locals the same instead of repeating yourself.
-    pub fn local_index(&self, lvalue: &Lvalue<'tcx>) -> Option<Local> {
-        let idx = match *lvalue {
-            Lvalue::Arg(arg) => arg.index(),
-            Lvalue::Var(var) => {
-                self.arg_decls.len() +
-                var.index()
-            }
-            Lvalue::Temp(temp) => {
-                self.arg_decls.len() +
-                self.var_decls.len() +
-                temp.index()
+    #[inline]
+    pub fn local_kind(&self, local: Local) -> LocalKind {
+        let index = local.0 as usize;
+        if index == 0 {
+            debug_assert!(self.local_decls[local].mutability == Mutability::Mut,
+                          "return pointer should be mutable");
+
+            LocalKind::ReturnPointer
+        } else if index < self.arg_count + 1 {
+            LocalKind::Arg
+        } else if self.local_decls[local].name.is_some() {
+            LocalKind::Var
+        } else {
+            debug_assert!(self.local_decls[local].mutability == Mutability::Mut,
+                          "temp should be mutable");
+
+            LocalKind::Temp
+        }
+    }
+
+    /// Returns an iterator over all temporaries.
+    #[inline]
+    pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
+        (self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
+            let local = Local::new(index);
+            if self.local_decls[local].source_info.is_none() {
+                Some(local)
+            } else {
+                None
             }
-            Lvalue::ReturnPointer => {
-                self.arg_decls.len() +
-                self.var_decls.len() +
-                self.temp_decls.len()
+        })
+    }
+
+    /// Returns an iterator over all user-declared locals.
+    #[inline]
+    pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
+        (self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
+            let local = Local::new(index);
+            if self.local_decls[local].source_info.is_none() {
+                None
+            } else {
+                Some(local)
             }
-            Lvalue::Static(_) |
-            Lvalue::Projection(_) => return None
-        };
-        Some(Local::new(idx))
+        })
     }
 
-    /// Counts the number of locals, such that local_index
-    /// will always return an index smaller than this count.
-    pub fn count_locals(&self) -> usize {
-        self.arg_decls.len() +
-        self.var_decls.len() +
-        self.temp_decls.len() + 1
+    /// Returns an iterator over all function arguments.
+    #[inline]
+    pub fn args_iter(&self) -> impl Iterator<Item=Local> {
+        let arg_count = self.arg_count;
+        (1..arg_count+1).map(Local::new)
     }
 
-    pub fn format_local(&self, local: Local) -> String {
-        let mut index = local.index();
-        index = match index.checked_sub(self.arg_decls.len()) {
-            None => return format!("{:?}", Arg::new(index)),
-            Some(index) => index,
-        };
-        index = match index.checked_sub(self.var_decls.len()) {
-            None => return format!("{:?}", Var::new(index)),
-            Some(index) => index,
-        };
-        index = match index.checked_sub(self.temp_decls.len()) {
-            None => return format!("{:?}", Temp::new(index)),
-            Some(index) => index,
-        };
-        debug_assert!(index == 0);
-        return "ReturnPointer".to_string()
+    /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
+    /// locals that are neither arguments nor the return pointer).
+    #[inline]
+    pub fn vars_and_temps_iter(&self) -> impl Iterator<Item=Local> {
+        let arg_count = self.arg_count;
+        let local_count = self.local_decls.len();
+        (arg_count+1..local_count).map(Local::new)
     }
 
     /// Changes a statement to a nop. This is both faster than deleting instructions and avoids
@@ -301,53 +323,76 @@ pub enum BorrowKind {
 ///////////////////////////////////////////////////////////////////////////
 // Variables and temps
 
-/// A "variable" is a binding declared by the user as part of the fn
-/// decl, a let, etc.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
-pub struct VarDecl<'tcx> {
-    /// `let mut x` vs `let x`
-    pub mutability: Mutability,
-
-    /// name that user gave the variable; not that, internally,
-    /// mir references variables by index
-    pub name: Name,
+newtype_index!(Local, "_");
 
-    /// type inferred for this variable (`let x: ty = ...`)
-    pub ty: Ty<'tcx>,
+pub const RETURN_POINTER: Local = Local(0);
 
-    /// source information (span, scope, etc.) for the declaration
-    pub source_info: SourceInfo,
-}
-
-/// A "temp" is a temporary that we place on the stack. They are
-/// anonymous, always mutable, and have only a type.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
-pub struct TempDecl<'tcx> {
-    pub ty: Ty<'tcx>,
+/// Classifies locals into categories. See `Mir::local_kind`.
+#[derive(PartialEq, Eq, Debug)]
+pub enum LocalKind {
+    /// User-declared variable binding
+    Var,
+    /// Compiler-introduced temporary
+    Temp,
+    /// Function argument
+    Arg,
+    /// Location of function's return value
+    ReturnPointer,
 }
 
-/// A "arg" is one of the function's formal arguments. These are
-/// anonymous and distinct from the bindings that the user declares.
-///
-/// For example, in this function:
-///
-/// ```
-/// fn foo((x, y): (i32, u32)) { ... }
-/// ```
+/// A MIR local.
 ///
-/// there is only one argument, of type `(i32, u32)`, but two bindings
-/// (`x` and `y`).
+/// This can be a binding declared by the user, a temporary inserted by the compiler, a function
+/// argument, or the return pointer.
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
-pub struct ArgDecl<'tcx> {
+pub struct LocalDecl<'tcx> {
+    /// `let mut x` vs `let x`.
+    ///
+    /// Temporaries and the return pointer are always mutable.
+    pub mutability: Mutability,
+
+    /// Type of this local.
     pub ty: Ty<'tcx>,
 
-    /// If true, this argument is a tuple after monomorphization,
-    /// and has to be collected from multiple actual arguments.
-    pub spread: bool,
+    /// Name of the local, used in debuginfo and pretty-printing.
+    ///
+    /// Note that function arguments can also have this set to `Some(_)`
+    /// to generate better debuginfo.
+    pub name: Option<Name>,
+
+    /// For user-declared variables, stores their source information.
+    ///
+    /// For temporaries, this is `None`.
+    ///
+    /// This is the primary way to differentiate between user-declared
+    /// variables and compiler-generated temporaries.
+    pub source_info: Option<SourceInfo>,
+}
+
+impl<'tcx> LocalDecl<'tcx> {
+    /// Create a new `LocalDecl` for a temporary.
+    #[inline]
+    pub fn new_temp(ty: Ty<'tcx>) -> Self {
+        LocalDecl {
+            mutability: Mutability::Mut,
+            ty: ty,
+            name: None,
+            source_info: None,
+        }
+    }
 
-    /// Either keywords::Invalid or the name of a single-binding
-    /// pattern associated with this argument. Useful for debuginfo.
-    pub debug_name: Name
+    /// Builds a `LocalDecl` for the return pointer.
+    ///
+    /// This must be inserted into the `local_decls` list as the first local.
+    #[inline]
+    pub fn new_return_pointer(return_ty: Ty) -> LocalDecl {
+        LocalDecl {
+            mutability: Mutability::Mut,
+            ty: return_ty,
+            source_info: None,
+            name: None,     // FIXME maybe we do want some name here?
+        }
+    }
 }
 
 /// A closure capture, with its name and mode.
@@ -439,7 +484,7 @@ pub enum TerminatorKind<'tcx> {
     /// continue. Emitted by build::scope::diverge_cleanup.
     Resume,
 
-    /// Indicates a normal return. The ReturnPointer lvalue should
+    /// Indicates a normal return. The return pointer lvalue should
     /// have been filled in by now. This should occur at most once.
     Return,
 
@@ -756,31 +801,16 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
 ///////////////////////////////////////////////////////////////////////////
 // Lvalues
 
-newtype_index!(Var, "var");
-newtype_index!(Temp, "tmp");
-newtype_index!(Arg, "arg");
-newtype_index!(Local, "local");
-
 /// A path to a value; something that can be evaluated without
 /// changing or disturbing program state.
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum Lvalue<'tcx> {
-    /// local variable declared by the user
-    Var(Var),
-
-    /// temporary introduced during lowering into MIR
-    Temp(Temp),
-
-    /// formal parameter of the function; note that these are NOT the
-    /// bindings that the user declares, which are vars
-    Arg(Arg),
+    /// local variable
+    Local(Local),
 
     /// static or static mut variable
     Static(DefId),
 
-    /// the return pointer of the fn
-    ReturnPointer,
-
     /// projection out of an lvalue (access a field, deref a pointer, etc)
     Projection(Box<LvalueProjection<'tcx>>),
 }
@@ -862,24 +892,6 @@ pub fn elem(self, elem: LvalueElem<'tcx>) -> Lvalue<'tcx> {
             elem: elem,
         }))
     }
-
-    pub fn from_local(mir: &Mir<'tcx>, local: Local) -> Lvalue<'tcx> {
-        let mut index = local.index();
-        index = match index.checked_sub(mir.arg_decls.len()) {
-            None => return Lvalue::Arg(Arg(index as u32)),
-            Some(index) => index,
-        };
-        index = match index.checked_sub(mir.var_decls.len()) {
-            None => return Lvalue::Var(Var(index as u32)),
-            Some(index) => index,
-        };
-        index = match index.checked_sub(mir.temp_decls.len()) {
-            None => return Lvalue::Temp(Temp(index as u32)),
-            Some(index) => index,
-        };
-        debug_assert!(index == 0);
-        Lvalue::ReturnPointer
-    }
 }
 
 impl<'tcx> Debug for Lvalue<'tcx> {
@@ -887,13 +899,9 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
         use self::Lvalue::*;
 
         match *self {
-            Var(id) => write!(fmt, "{:?}", id),
-            Arg(id) => write!(fmt, "{:?}", id),
-            Temp(id) => write!(fmt, "{:?}", id),
+            Local(id) => write!(fmt, "{:?}", id),
             Static(def_id) =>
                 write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))),
-            ReturnPointer =>
-                write!(fmt, "return"),
             Projection(ref data) =>
                 match data.elem {
                     ProjectionElem::Downcast(ref adt_def, index) =>
@@ -1016,7 +1024,7 @@ pub enum CastKind {
 
 #[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum AggregateKind<'tcx> {
-    Vec,
+    Array,
     Tuple,
     /// The second field is variant number (discriminant), it's equal to 0
     /// for struct and union expressions. The fourth field is active field
@@ -1107,8 +1115,6 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
             }
 
             Aggregate(ref kind, ref lvs) => {
-                use self::AggregateKind::*;
-
                 fn fmt_tuple(fmt: &mut Formatter, lvs: &[Operand]) -> fmt::Result {
                     let mut tuple_fmt = fmt.debug_tuple("");
                     for lv in lvs {
@@ -1118,9 +1124,9 @@ fn fmt_tuple(fmt: &mut Formatter, lvs: &[Operand]) -> fmt::Result {
                 }
 
                 match *kind {
-                    Vec => write!(fmt, "{:?}", lvs),
+                    AggregateKind::Array => write!(fmt, "{:?}", lvs),
 
-                    Tuple => {
+                    AggregateKind::Tuple => {
                         match lvs.len() {
                             0 => write!(fmt, "()"),
                             1 => write!(fmt, "({:?},)", lvs[0]),
@@ -1128,7 +1134,7 @@ fn fmt_tuple(fmt: &mut Formatter, lvs: &[Operand]) -> fmt::Result {
                         }
                     }
 
-                    Adt(adt_def, variant, substs, _) => {
+                    AggregateKind::Adt(adt_def, variant, substs, _) => {
                         let variant_def = &adt_def.variants[variant];
 
                         ppaux::parameterized(fmt, substs, variant_def.did,
@@ -1147,7 +1153,7 @@ fn fmt_tuple(fmt: &mut Formatter, lvs: &[Operand]) -> fmt::Result {
                         }
                     }
 
-                    Closure(def_id, _) => ty::tls::with(|tcx| {
+                    AggregateKind::Closure(def_id, _) => ty::tls::with(|tcx| {
                         if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
                             let name = format!("[closure@{:?}]", tcx.map.span(node_id));
                             let mut struct_fmt = fmt.debug_struct(&name);
index 74ad6c602f6cdf47f3bd59bb96d07d29dab6a579..960d61adba72c3b7c8b4878505f6f73a0b0cea04 100644 (file)
@@ -49,12 +49,17 @@ pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                          -> LvalueTy<'tcx>
     {
         match *elem {
-            ProjectionElem::Deref =>
+            ProjectionElem::Deref => {
+                let ty = self.to_ty(tcx)
+                             .builtin_deref(true, ty::LvaluePreference::NoPreference)
+                             .unwrap_or_else(|| {
+                                 bug!("deref projection of non-dereferencable ty {:?}", self)
+                             })
+                             .ty;
                 LvalueTy::Ty {
-                    ty: self.to_ty(tcx).builtin_deref(true, ty::LvaluePreference::NoPreference)
-                                          .unwrap()
-                                          .ty
-                },
+                    ty: ty,
+                }
+            }
             ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
                 LvalueTy::Ty {
                     ty: self.to_ty(tcx).builtin_index().unwrap()
@@ -116,18 +121,12 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
 
 impl<'tcx> Lvalue<'tcx> {
     pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> LvalueTy<'tcx> {
-        match self {
-            &Lvalue::Var(index) =>
-                LvalueTy::Ty { ty: mir.var_decls[index].ty },
-            &Lvalue::Temp(index) =>
-                LvalueTy::Ty { ty: mir.temp_decls[index].ty },
-            &Lvalue::Arg(index) =>
-                LvalueTy::Ty { ty: mir.arg_decls[index].ty },
-            &Lvalue::Static(def_id) =>
+        match *self {
+            Lvalue::Local(index) =>
+                LvalueTy::Ty { ty: mir.local_decls[index].ty },
+            Lvalue::Static(def_id) =>
                 LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty },
-            &Lvalue::ReturnPointer =>
-                LvalueTy::Ty { ty: mir.return_ty },
-            &Lvalue::Projection(ref proj) =>
+            Lvalue::Projection(ref proj) =>
                 proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem),
         }
     }
@@ -175,7 +174,7 @@ pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Opti
             }
             &Rvalue::Aggregate(ref ak, ref ops) => {
                 match *ak {
-                    AggregateKind::Vec => {
+                    AggregateKind::Array => {
                         if let Some(operand) = ops.get(0) {
                             let ty = operand.ty(mir, tcx);
                             Some(tcx.mk_array(ty, ops.len()))
index 2c58d35973e73a2c6b7880875cf0824e10016ff4..cb8d3f97f7b2963fc8541c8f73d274d82bb45e8c 100644 (file)
@@ -236,19 +236,9 @@ fn visit_typed_const_val(&mut self,
                 self.super_typed_const_val(val, location);
             }
 
-            fn visit_var_decl(&mut self,
-                              var_decl: & $($mutability)* VarDecl<'tcx>) {
-                self.super_var_decl(var_decl);
-            }
-
-            fn visit_temp_decl(&mut self,
-                               temp_decl: & $($mutability)* TempDecl<'tcx>) {
-                self.super_temp_decl(temp_decl);
-            }
-
-            fn visit_arg_decl(&mut self,
-                              arg_decl: & $($mutability)* ArgDecl<'tcx>) {
-                self.super_arg_decl(arg_decl);
+            fn visit_local_decl(&mut self,
+                                local_decl: & $($mutability)* LocalDecl<'tcx>) {
+                self.super_local_decl(local_decl);
             }
 
             fn visit_visibility_scope(&mut self,
@@ -272,16 +262,8 @@ fn super_mir(&mut self,
 
                 self.visit_ty(&$($mutability)* mir.return_ty);
 
-                for var_decl in &$($mutability)* mir.var_decls {
-                    self.visit_var_decl(var_decl);
-                }
-
-                for arg_decl in &$($mutability)* mir.arg_decls {
-                    self.visit_arg_decl(arg_decl);
-                }
-
-                for temp_decl in &$($mutability)* mir.temp_decls {
-                    self.visit_temp_decl(temp_decl);
+                for local_decl in &$($mutability)* mir.local_decls {
+                    self.visit_local_decl(local_decl);
                 }
 
                 self.visit_span(&$($mutability)* mir.span);
@@ -531,7 +513,7 @@ fn super_rvalue(&mut self,
                     Rvalue::Aggregate(ref $($mutability)* kind,
                                       ref $($mutability)* operands) => {
                         match *kind {
-                            AggregateKind::Vec => {
+                            AggregateKind::Array => {
                             }
                             AggregateKind::Tuple => {
                             }
@@ -584,10 +566,7 @@ fn super_lvalue(&mut self,
                             context: LvalueContext<'tcx>,
                             location: Location) {
                 match *lvalue {
-                    Lvalue::Var(_) |
-                    Lvalue::Temp(_) |
-                    Lvalue::Arg(_) |
-                    Lvalue::ReturnPointer => {
+                    Lvalue::Local(_) => {
                     }
                     Lvalue::Static(ref $($mutability)* def_id) => {
                         self.visit_def_id(def_id, location);
@@ -639,37 +618,19 @@ fn super_projection_elem(&mut self,
                 }
             }
 
-            fn super_var_decl(&mut self,
-                              var_decl: & $($mutability)* VarDecl<'tcx>) {
-                let VarDecl {
+            fn super_local_decl(&mut self,
+                                local_decl: & $($mutability)* LocalDecl<'tcx>) {
+                let LocalDecl {
                     mutability: _,
-                    name: _,
                     ref $($mutability)* ty,
+                    name: _,
                     ref $($mutability)* source_info,
-                } = *var_decl;
-
-                self.visit_ty(ty);
-                self.visit_source_info(source_info);
-            }
-
-            fn super_temp_decl(&mut self,
-                               temp_decl: & $($mutability)* TempDecl<'tcx>) {
-                let TempDecl {
-                    ref $($mutability)* ty,
-                } = *temp_decl;
-
-                self.visit_ty(ty);
-            }
-
-            fn super_arg_decl(&mut self,
-                              arg_decl: & $($mutability)* ArgDecl<'tcx>) {
-                let ArgDecl {
-                    ref $($mutability)* ty,
-                    spread: _,
-                    debug_name: _
-                } = *arg_decl;
+                } = *local_decl;
 
                 self.visit_ty(ty);
+                if let Some(ref $($mutability)* info) = *source_info {
+                    self.visit_source_info(info);
+                }
             }
 
             fn super_visibility_scope(&mut self,
index 2e01ec9b0a7250114a438b9619b6d97989fcf97d..f8b06bf2e97626c6951323634c8037fe5e1af692 100644 (file)
@@ -19,6 +19,7 @@
 use session::{early_error, early_warn, Session};
 use session::search_paths::SearchPaths;
 
+use rustc_back::PanicStrategy;
 use rustc_back::target::Target;
 use lint;
 use middle::cstore;
@@ -37,7 +38,6 @@
 use std::collections::btree_map::Keys as BTreeMapKeysIter;
 use std::collections::btree_map::Values as BTreeMapValuesIter;
 
-use std::env;
 use std::fmt;
 use std::hash::{Hasher, SipHasher};
 use std::iter::FromIterator;
@@ -493,21 +493,6 @@ pub fn is_empty(&self) -> bool {
     }
 }
 
-#[derive(Clone, PartialEq, Hash, RustcEncodable, RustcDecodable)]
-pub enum PanicStrategy {
-    Unwind,
-    Abort,
-}
-
-impl PanicStrategy {
-    pub fn desc(&self) -> &str {
-        match *self {
-            PanicStrategy::Unwind => "unwind",
-            PanicStrategy::Abort => "abort",
-        }
-    }
-}
-
 /// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all
 /// at once. The goal of this macro is to define an interface that can be
 /// programmatically used by the option parser in order to initialize the struct
@@ -606,6 +591,7 @@ mod $mod_desc {
         pub const parse_opt_bool: Option<&'static str> =
             Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
         pub const parse_string: Option<&'static str> = Some("a string");
+        pub const parse_string_push: Option<&'static str> = Some("a string");
         pub const parse_opt_string: Option<&'static str> = Some("a string");
         pub const parse_list: Option<&'static str> = Some("a space-separated list of strings");
         pub const parse_opt_list: Option<&'static str> = Some("a space-separated list of strings");
@@ -620,7 +606,8 @@ mod $mod_desc {
 
     #[allow(dead_code)]
     mod $mod_set {
-        use super::{$struct_name, Passes, SomePasses, AllPasses, PanicStrategy};
+        use super::{$struct_name, Passes, SomePasses, AllPasses};
+        use rustc_back::PanicStrategy;
 
         $(
             pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
@@ -668,6 +655,13 @@ fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
             }
         }
 
+        fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
+            match v {
+                Some(s) => { slot.push(s.to_string()); true },
+                None => false,
+            }
+        }
+
         fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
                       -> bool {
             match v {
@@ -725,10 +719,10 @@ fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
             }
         }
 
-        fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
+        fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
             match v {
-                Some("unwind") => *slot = PanicStrategy::Unwind,
-                Some("abort") => *slot = PanicStrategy::Abort,
+                Some("unwind") => *slot = Some(PanicStrategy::Unwind),
+                Some("abort") => *slot = Some(PanicStrategy::Abort),
                 _ => return false
             }
             true
@@ -743,6 +737,8 @@ fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
         "tool to assemble archives with"),
     linker: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "system linker to link outputs with"),
+    link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
+        "a single extra argument to pass to the linker (can be used several times)"),
     link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
         "extra arguments to pass to the linker (space separated)"),
     link_dead_code: bool = (false, parse_bool, [UNTRACKED],
@@ -800,7 +796,7 @@ fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
         "explicitly enable the cfg(debug_assertions) directive"),
     inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
         "set the inlining threshold for"),
-    panic: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy,
+    panic: Option<PanicStrategy> = (None, parse_panic_strategy,
         [TRACKED], "panic strategy to compile crate with"),
 }
 
@@ -1525,27 +1521,12 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
         crate_name: crate_name,
         alt_std_name: None,
         libs: libs,
-        unstable_features: get_unstable_features_setting(),
+        unstable_features: UnstableFeatures::from_environment(),
         debug_assertions: debug_assertions,
     },
     cfg)
 }
 
-pub fn get_unstable_features_setting() -> UnstableFeatures {
-    // Whether this is a feature-staged build, i.e. on the beta or stable channel
-    let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
-    // The secret key needed to get through the rustc build itself by
-    // subverting the unstable features lints
-    let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY");
-    // The matching key to the above, only known by the build system
-    let bootstrap_provided_key = env::var("RUSTC_BOOTSTRAP_KEY").ok();
-    match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) {
-        (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat,
-        (true, ..) => UnstableFeatures::Disallow,
-        (false, ..) => UnstableFeatures::Allow
-    }
-}
-
 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
     let mut crate_types: Vec<CrateType> = Vec::new();
     for unparsed_crate_type in &list_list {
@@ -1575,7 +1556,7 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
 pub mod nightly_options {
     use getopts;
     use syntax::feature_gate::UnstableFeatures;
-    use super::{ErrorOutputType, OptionStability, RustcOptGroup, get_unstable_features_setting};
+    use super::{ErrorOutputType, OptionStability, RustcOptGroup};
     use session::{early_error, early_warn};
 
     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
@@ -1583,18 +1564,13 @@ pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
     }
 
     pub fn is_nightly_build() -> bool {
-        match get_unstable_features_setting() {
-            UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
-            _ => false,
-        }
+        UnstableFeatures::from_environment().is_nightly_build()
     }
 
     pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
         let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
-        let really_allows_unstable_options = match get_unstable_features_setting() {
-            UnstableFeatures::Disallow => false,
-            _ => true,
-        };
+        let really_allows_unstable_options = UnstableFeatures::from_environment()
+            .is_nightly_build();
 
         for opt in flags.iter() {
             if opt.stability == OptionStability::Stable {
@@ -1676,9 +1652,10 @@ mod dep_tracking {
     use std::collections::BTreeMap;
     use std::hash::{Hash, SipHasher};
     use std::path::PathBuf;
-    use super::{Passes, PanicStrategy, CrateType, OptLevel, DebugInfoLevel,
+    use super::{Passes, CrateType, OptLevel, DebugInfoLevel,
                 OutputTypes, Externs, ErrorOutputType};
     use syntax::feature_gate::UnstableFeatures;
+    use rustc_back::PanicStrategy;
 
     pub trait DepTrackingHash {
         fn hash(&self, &mut SipHasher, ErrorOutputType);
@@ -1717,6 +1694,7 @@ fn hash(&self, hasher: &mut SipHasher, error_format: ErrorOutputType) {
     impl_dep_tracking_hash_via_hash!(Option<bool>);
     impl_dep_tracking_hash_via_hash!(Option<usize>);
     impl_dep_tracking_hash_via_hash!(Option<String>);
+    impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
     impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
     impl_dep_tracking_hash_via_hash!(CrateType);
@@ -1783,7 +1761,8 @@ mod tests {
     use std::iter::FromIterator;
     use std::path::PathBuf;
     use std::rc::Rc;
-    use super::{OutputType, OutputTypes, Externs, PanicStrategy};
+    use super::{OutputType, OutputTypes, Externs};
+    use rustc_back::PanicStrategy;
     use syntax::{ast, attr};
     use syntax::parse::token::InternedString;
     use syntax::codemap::dummy_spanned;
@@ -2329,7 +2308,7 @@ fn test_codegen_options_tracking_hash() {
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
 
         opts = reference.clone();
-        opts.cg.panic = PanicStrategy::Abort;
+        opts.cg.panic = Some(PanicStrategy::Abort);
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
     }
 
index 268dbd70bb5bb2f8cd1bdde4a9c4e8bbd4efbbd2..f706bab32c80a0a74d6583a463de7c8b3415537c 100644 (file)
@@ -15,7 +15,7 @@
 use middle::cstore::CrateStore;
 use middle::dependency_format;
 use session::search_paths::PathKind;
-use session::config::{DebugInfoLevel, PanicStrategy};
+use session::config::DebugInfoLevel;
 use ty::tls;
 use util::nodemap::{NodeMap, FnvHashMap};
 use util::common::duration_to_secs_str;
@@ -33,6 +33,7 @@
 use syntax::feature_gate::AttributeType;
 use syntax_pos::{Span, MultiSpan};
 
+use rustc_back::PanicStrategy;
 use rustc_back::target::Target;
 use rustc_data_structures::flock;
 use llvm;
@@ -42,6 +43,7 @@
 use std::collections::HashMap;
 use std::env;
 use std::ffi::CString;
+use std::io::Write;
 use std::rc::Rc;
 use std::fmt;
 use std::time::Duration;
@@ -306,9 +308,13 @@ pub fn print_llvm_passes(&self) -> bool {
     pub fn lto(&self) -> bool {
         self.opts.cg.lto
     }
+    /// Returns the panic strategy for this compile session. If the user explicitly selected one
+    /// using '-C panic', use that, otherwise use the panic strategy defined by the target.
+    pub fn panic_strategy(&self) -> PanicStrategy {
+        self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy)
+    }
     pub fn no_landing_pads(&self) -> bool {
-        self.opts.debugging_opts.no_landing_pads ||
-            self.opts.cg.panic == PanicStrategy::Abort
+        self.opts.debugging_opts.no_landing_pads || self.panic_strategy() == PanicStrategy::Abort
     }
     pub fn unstable_options(&self) -> bool {
         self.opts.debugging_opts.unstable_options
@@ -449,7 +455,8 @@ pub fn build_session(sopts: config::Options,
                                local_crate_source_file,
                                registry,
                                cstore,
-                               Rc::new(codemap::CodeMap::new()))
+                               Rc::new(codemap::CodeMap::new()),
+                               None)
 }
 
 pub fn build_session_with_codemap(sopts: config::Options,
@@ -457,7 +464,8 @@ pub fn build_session_with_codemap(sopts: config::Options,
                                   local_crate_source_file: Option<PathBuf>,
                                   registry: errors::registry::Registry,
                                   cstore: Rc<for<'a> CrateStore<'a>>,
-                                  codemap: Rc<codemap::CodeMap>)
+                                  codemap: Rc<codemap::CodeMap>,
+                                  emitter_dest: Option<Box<Write + Send>>)
                                   -> Session {
     // FIXME: This is not general enough to make the warning lint completely override
     // normal diagnostic warnings, since the warning lint can also be denied and changed
@@ -470,14 +478,21 @@ pub fn build_session_with_codemap(sopts: config::Options,
         .unwrap_or(true);
     let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug;
 
-    let emitter: Box<Emitter> = match sopts.error_format {
-        config::ErrorOutputType::HumanReadable(color_config) => {
+    let emitter: Box<Emitter> = match (sopts.error_format, emitter_dest) {
+        (config::ErrorOutputType::HumanReadable(color_config), None) => {
             Box::new(EmitterWriter::stderr(color_config,
                                            Some(codemap.clone())))
         }
-        config::ErrorOutputType::Json => {
+        (config::ErrorOutputType::HumanReadable(_), Some(dst)) => {
+            Box::new(EmitterWriter::new(dst,
+                                        Some(codemap.clone())))
+        }
+        (config::ErrorOutputType::Json, None) => {
             Box::new(JsonEmitter::stderr(Some(registry), codemap.clone()))
         }
+        (config::ErrorOutputType::Json, Some(dst)) => {
+            Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone()))
+        }
     };
 
     let diagnostic_handler =
index 0c7c387b67ea3c33aeb4791dda6a9ffd7da14351..b1f80455dd98b979d8a6ad46c2cf5166eb6a9f01 100644 (file)
@@ -17,7 +17,7 @@
 use hir::def::DefMap;
 use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
 use hir::map as ast_map;
-use hir::map::{DefKey, DefPath, DefPathData, DisambiguatedDefPathData};
+use hir::map::{DefKey, DefPathData, DisambiguatedDefPathData};
 use middle::free_region::FreeRegionMap;
 use middle::region::RegionMaps;
 use middle::resolve_lifetime;
@@ -546,8 +546,11 @@ pub fn def_index_for_def_key(self, krate: CrateNum, key: DefKey)
         }
     }
 
-    pub fn retrace_path(self, path: &DefPath) -> Option<DefId> {
-        debug!("retrace_path(path={:?}, krate={:?})", path, self.crate_name(path.krate));
+    pub fn retrace_path(self,
+                        krate: CrateNum,
+                        path_data: &[DisambiguatedDefPathData])
+                        -> Option<DefId> {
+        debug!("retrace_path(path={:?}, krate={:?})", path_data, self.crate_name(krate));
 
         let root_key = DefKey {
             parent: None,
@@ -557,22 +560,22 @@ pub fn retrace_path(self, path: &DefPath) -> Option<DefId> {
             },
         };
 
-        let root_index = self.def_index_for_def_key(path.krate, root_key)
+        let root_index = self.def_index_for_def_key(krate, root_key)
                              .expect("no root key?");
 
         debug!("retrace_path: root_index={:?}", root_index);
 
         let mut index = root_index;
-        for data in &path.data {
+        for data in path_data {
             let key = DefKey { parent: Some(index), disambiguated_data: data.clone() };
             debug!("retrace_path: key={:?}", key);
-            match self.def_index_for_def_key(path.krate, key) {
+            match self.def_index_for_def_key(krate, key) {
                 Some(i) => index = i,
                 None => return None,
             }
         }
 
-        Some(DefId { krate: path.krate, index: index })
+        Some(DefId { krate: krate, index: index })
     }
 
     pub fn type_parameter_def(self,
index 001f47af68c3bf67b0727f6425a2040eb5c0ef32..9b345c2d02329b5f1f6ca1e7a3a7da130cdb01b8 100644 (file)
@@ -33,13 +33,8 @@ pub enum TypeError<'tcx> {
     UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
     AbiMismatch(ExpectedFound<abi::Abi>),
     Mutability,
-    BoxMutability,
-    PtrMutability,
-    RefMutability,
-    VecMutability,
     TupleSize(ExpectedFound<usize>),
     FixedArraySize(ExpectedFound<usize>),
-    TyParamSize(ExpectedFound<usize>),
     ArgCount,
     RegionsDoesNotOutlive(&'tcx Region, &'tcx Region),
     RegionsNotSame(&'tcx Region, &'tcx Region),
@@ -47,14 +42,12 @@ pub enum TypeError<'tcx> {
     RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region),
     RegionsOverlyPolymorphic(BoundRegion, &'tcx Region),
     Sorts(ExpectedFound<Ty<'tcx>>),
-    IntegerAsChar,
     IntMismatch(ExpectedFound<ty::IntVarValue>),
     FloatMismatch(ExpectedFound<ast::FloatTy>),
     Traits(ExpectedFound<DefId>),
     BuiltinBoundsMismatch(ExpectedFound<ty::BuiltinBounds>),
     VariadicMismatch(ExpectedFound<bool>),
     CyclicTy,
-    ConvergenceMismatch(ExpectedFound<bool>),
     ProjectionNameMismatched(ExpectedFound<Name>),
     ProjectionBoundsLength(ExpectedFound<usize>),
     TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>)
@@ -99,18 +92,6 @@ fn report_maybe_different(f: &mut fmt::Formatter,
                        values.found)
             }
             Mutability => write!(f, "types differ in mutability"),
-            BoxMutability => {
-                write!(f, "boxed types differ in mutability")
-            }
-            VecMutability => write!(f, "vectors differ in mutability"),
-            PtrMutability => write!(f, "pointers differ in mutability"),
-            RefMutability => write!(f, "references differ in mutability"),
-            TyParamSize(values) => {
-                write!(f, "expected a type with {} type params, \
-                           found one with {} type params",
-                       values.expected,
-                       values.found)
-            }
             FixedArraySize(values) => {
                 write!(f, "expected an array with a fixed size of {} elements, \
                            found one with {} elements",
@@ -167,9 +148,6 @@ fn report_maybe_different(f: &mut fmt::Formatter,
                            values.found)
                 }
             }
-            IntegerAsChar => {
-                write!(f, "expected an integral type, found `char`")
-            }
             IntMismatch(ref values) => {
                 write!(f, "expected `{:?}`, found `{:?}`",
                        values.expected,
@@ -185,11 +163,6 @@ fn report_maybe_different(f: &mut fmt::Formatter,
                        if values.expected { "variadic" } else { "non-variadic" },
                        if values.found { "variadic" } else { "non-variadic" })
             }
-            ConvergenceMismatch(ref values) => {
-                write!(f, "expected {} fn, found {} function",
-                       if values.expected { "converging" } else { "diverging" },
-                       if values.found { "converging" } else { "diverging" })
-            }
             ProjectionNameMismatched(ref values) => {
                 write!(f, "expected {}, found {}",
                        values.expected,
index ee1544d2d996d3df5905d29c6838ec2b4439e6e5..befc9533c387b338747e386c4e876ab0ff19ec44 100644 (file)
@@ -24,7 +24,7 @@ pub enum SimplifiedType {
     FloatSimplifiedType(ast::FloatTy),
     AdtSimplifiedType(DefId),
     StrSimplifiedType,
-    VecSimplifiedType,
+    ArraySimplifiedType,
     PtrSimplifiedType,
     NeverSimplifiedType,
     TupleSimplifiedType(usize),
@@ -57,7 +57,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         ty::TyFloat(float_type) => Some(FloatSimplifiedType(float_type)),
         ty::TyAdt(def, _) => Some(AdtSimplifiedType(def.did)),
         ty::TyStr => Some(StrSimplifiedType),
-        ty::TyArray(..) | ty::TySlice(_) => Some(VecSimplifiedType),
+        ty::TyArray(..) | ty::TySlice(_) => Some(ArraySimplifiedType),
         ty::TyRawPtr(_) => Some(PtrSimplifiedType),
         ty::TyTrait(ref trait_info) => {
             Some(TraitSimplifiedType(trait_info.principal.def_id()))
index ed945534e1e5f4014187bb4831ac33a6a97ba621..ec6843eb75d1f7f4ac8d7fbb390bd5a0030e90da 100644 (file)
@@ -511,11 +511,11 @@ pub struct Struct {
     /// If true, the size is exact, otherwise it's only a lower bound.
     pub sized: bool,
 
-    /// Offsets for the first byte after each field.
-    /// That is, field_offset(i) = offset_after_field[i - 1] and the
-    /// whole structure's size is the last offset, excluding padding.
-    // FIXME(eddyb) use small vector optimization for the common case.
-    pub offset_after_field: Vec<Size>
+    /// Offsets for the first byte of each field.
+    /// FIXME(eddyb) use small vector optimization for the common case.
+    pub offsets: Vec<Size>,
+
+    pub min_size: Size,
 }
 
 impl<'a, 'gcx, 'tcx> Struct {
@@ -524,7 +524,8 @@ pub fn new(dl: &TargetDataLayout, packed: bool) -> Struct {
             align: if packed { dl.i8_align } else { dl.aggregate_align },
             packed: packed,
             sized: true,
-            offset_after_field: vec![]
+            offsets: vec![],
+            min_size: Size::from_bytes(0),
         }
     }
 
@@ -534,12 +535,14 @@ pub fn extend<I>(&mut self, dl: &TargetDataLayout,
                      scapegoat: Ty<'gcx>)
                      -> Result<(), LayoutError<'gcx>>
     where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
-        self.offset_after_field.reserve(fields.size_hint().0);
+        self.offsets.reserve(fields.size_hint().0);
+
+        let mut offset = self.min_size;
 
         for field in fields {
             if !self.sized {
                 bug!("Struct::extend: field #{} of `{}` comes after unsized field",
-                     self.offset_after_field.len(), scapegoat);
+                     self.offsets.len(), scapegoat);
             }
 
             let field = field?;
@@ -548,34 +551,29 @@ pub fn extend<I>(&mut self, dl: &TargetDataLayout,
             }
 
             // Invariant: offset < dl.obj_size_bound() <= 1<<61
-            let mut offset = if !self.packed {
+            if !self.packed {
                 let align = field.align(dl);
                 self.align = self.align.max(align);
-                self.offset_after_field.last_mut().map_or(Size::from_bytes(0), |last| {
-                    *last = last.abi_align(align);
-                    *last
-                })
-            } else {
-                self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last)
-            };
+                offset = offset.abi_align(align);
+            }
+
+            self.offsets.push(offset);
+
 
             offset = offset.checked_add(field.size(dl), dl)
                            .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?;
-
-            self.offset_after_field.push(offset);
         }
 
+        self.min_size = offset;
+
         Ok(())
     }
 
     /// Get the size without trailing alignment padding.
-    pub fn min_size(&self) -> Size {
-        self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last)
-    }
 
     /// Get the size with trailing aligment padding.
     pub fn stride(&self) -> Size {
-        self.min_size().abi_align(self.align)
+        self.min_size.abi_align(self.align)
     }
 
     /// Determine whether a structure would be zero-sized, given its fields.
@@ -671,15 +669,6 @@ pub fn non_zero_field_path<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
         }
         Ok(None)
     }
-
-    pub fn offset_of_field(&self, index: usize) -> Size {
-        assert!(index < self.offset_after_field.len());
-        if index == 0 {
-            Size::from_bytes(0)
-        } else {
-            self.offset_after_field[index-1]
-        }
-    }
 }
 
 /// An untagged union.
@@ -1138,7 +1127,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                     });
                     let mut st = Struct::new(dl, false);
                     st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?;
-                    size = cmp::max(size, st.min_size());
+                    size = cmp::max(size, st.min_size);
                     align = align.max(st.align);
                     Ok(st)
                 }).collect::<Result<Vec<_>, _>>()?;
@@ -1171,12 +1160,16 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                     let old_ity_size = Int(min_ity).size(dl);
                     let new_ity_size = Int(ity).size(dl);
                     for variant in &mut variants {
-                        for offset in &mut variant.offset_after_field {
+                        for offset in &mut variant.offsets[1..] {
                             if *offset > old_ity_size {
                                 break;
                             }
                             *offset = new_ity_size;
                         }
+                        // We might be making the struct larger.
+                        if variant.min_size <= old_ity_size {
+                            variant.min_size = new_ity_size;
+                        }
                     }
                 }
 
index 717b8923a16358a5edcccdcfc421f90bf64615d5..cc13299d4347585a8ce6f480e0951c1be6c963e6 100644 (file)
@@ -2228,7 +2228,7 @@ pub fn expr_is_lval(self, expr: &hir::Expr) -> bool {
             hir::ExprClosure(..) |
             hir::ExprBlock(..) |
             hir::ExprRepeat(..) |
-            hir::ExprVec(..) |
+            hir::ExprArray(..) |
             hir::ExprBreak(..) |
             hir::ExprAgain(..) |
             hir::ExprRet(..) |
index 5a87ea1473d982fbda294e9dc4f5e13566aa2faf..abd5cb51f39baa795d2a4cb2d265ce80926a96d2 100644 (file)
@@ -296,13 +296,8 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
             UnsafetyMismatch(x) => UnsafetyMismatch(x),
             AbiMismatch(x) => AbiMismatch(x),
             Mutability => Mutability,
-            BoxMutability => BoxMutability,
-            PtrMutability => PtrMutability,
-            RefMutability => RefMutability,
-            VecMutability => VecMutability,
             TupleSize(x) => TupleSize(x),
             FixedArraySize(x) => FixedArraySize(x),
-            TyParamSize(x) => TyParamSize(x),
             ArgCount => ArgCount,
             RegionsDoesNotOutlive(a, b) => {
                 return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b))
@@ -319,14 +314,12 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
             RegionsOverlyPolymorphic(a, b) => {
                 return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b))
             }
-            IntegerAsChar => IntegerAsChar,
             IntMismatch(x) => IntMismatch(x),
             FloatMismatch(x) => FloatMismatch(x),
             Traits(x) => Traits(x),
             BuiltinBoundsMismatch(x) => BuiltinBoundsMismatch(x),
             VariadicMismatch(x) => VariadicMismatch(x),
             CyclicTy => CyclicTy,
-            ConvergenceMismatch(x) => ConvergenceMismatch(x),
             ProjectionNameMismatched(x) => ProjectionNameMismatched(x),
             ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
 
index c8fd27f066cac328280d380d6778d3eec46aa3cf..c209503e90e7d50c83b88a412b409ed1b5ca3ba8 100644 (file)
@@ -12,6 +12,7 @@
 
 use hir::def_id::DefId;
 use infer::InferCtxt;
+use hir::map as ast_map;
 use hir::pat_util;
 use traits::{self, Reveal};
 use ty::{self, Ty, AdtKind, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
@@ -388,16 +389,77 @@ pub fn is_adt_dtorck(self, adt: ty::AdtDef) -> bool {
     }
 }
 
+// When hashing a type this ends up affecting properties like symbol names. We
+// want these symbol names to be calculated independent of other factors like
+// what architecture you're compiling *from*.
+//
+// The hashing just uses the standard `Hash` trait, but the implementations of
+// `Hash` for the `usize` and `isize` types are *not* architecture independent
+// (e.g. they has 4 or 8 bytes). As a result we want to avoid `usize` and
+// `isize` completely when hashing. To ensure that these don't leak in we use a
+// custom hasher implementation here which inflates the size of these to a `u64`
+// and `i64`.
+struct WidenUsizeHasher<H> {
+    inner: H,
+}
+
+impl<H> WidenUsizeHasher<H> {
+    fn new(inner: H) -> WidenUsizeHasher<H> {
+        WidenUsizeHasher { inner: inner }
+    }
+}
+
+impl<H: Hasher> Hasher for WidenUsizeHasher<H> {
+    fn write(&mut self, bytes: &[u8]) {
+        self.inner.write(bytes)
+    }
+
+    fn finish(&self) -> u64 {
+        self.inner.finish()
+    }
+
+    fn write_u8(&mut self, i: u8) {
+        self.inner.write_u8(i)
+    }
+    fn write_u16(&mut self, i: u16) {
+        self.inner.write_u16(i)
+    }
+    fn write_u32(&mut self, i: u32) {
+        self.inner.write_u32(i)
+    }
+    fn write_u64(&mut self, i: u64) {
+        self.inner.write_u64(i)
+    }
+    fn write_usize(&mut self, i: usize) {
+        self.inner.write_u64(i as u64)
+    }
+    fn write_i8(&mut self, i: i8) {
+        self.inner.write_i8(i)
+    }
+    fn write_i16(&mut self, i: i16) {
+        self.inner.write_i16(i)
+    }
+    fn write_i32(&mut self, i: i32) {
+        self.inner.write_i32(i)
+    }
+    fn write_i64(&mut self, i: i64) {
+        self.inner.write_i64(i)
+    }
+    fn write_isize(&mut self, i: isize) {
+        self.inner.write_i64(i as i64)
+    }
+}
+
 pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, H> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    state: H
+    state: WidenUsizeHasher<H>,
 }
 
 impl<'a, 'gcx, 'tcx, H: Hasher> TypeIdHasher<'a, 'gcx, 'tcx, H> {
     pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, state: H) -> Self {
         TypeIdHasher {
             tcx: tcx,
-            state: state
+            state: WidenUsizeHasher::new(state),
         }
     }
 
@@ -421,9 +483,12 @@ fn hash_discriminant_u8<T>(&mut self, x: &T) {
     fn def_id(&mut self, did: DefId) {
         // Hash the DefPath corresponding to the DefId, which is independent
         // of compiler internal state.
-        let tcx = self.tcx;
-        let def_path = tcx.def_path(did);
-        def_path.deterministic_hash_to(tcx, &mut self.state);
+        let path = self.tcx.def_path(did);
+        self.def_path(&path)
+    }
+
+    pub fn def_path(&mut self, def_path: &ast_map::DefPath) {
+        def_path.deterministic_hash_to(self.tcx, &mut self.state);
     }
 }
 
index f7ae47d2e5e56efac5e5707f4cc1c47ef43b2d2e..c0f358ca8017bd884c3bfa53a892ee58a2e67a95 100644 (file)
 extern crate serialize;
 #[macro_use] extern crate log;
 
+extern crate serialize as rustc_serialize; // used by deriving
+
 pub mod tempdir;
 pub mod sha2;
 pub mod target;
 pub mod slice;
 pub mod dynamic_lib;
+
+use serialize::json::{Json, ToJson};
+
+#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+pub enum PanicStrategy {
+    Unwind,
+    Abort,
+}
+
+impl PanicStrategy {
+    pub fn desc(&self) -> &str {
+        match *self {
+            PanicStrategy::Unwind => "unwind",
+            PanicStrategy::Abort => "abort",
+        }
+    }
+}
+
+impl ToJson for PanicStrategy {
+    fn to_json(&self) -> Json {
+        match *self {
+            PanicStrategy::Abort => "abort".to_json(),
+            PanicStrategy::Unwind => "unwind".to_json(),
+        }
+    }
+}
index 9ccfdbb129c7352bceab72900939f340660c7512..667f7cf2c214a9defc7c7b01c0d0f60addf59e91 100644 (file)
@@ -22,6 +22,7 @@ pub fn target() -> Result<Target, String> {
         allow_asm: false,
         obj_is_bitcode: true,
         max_atomic_width: 32,
+        post_link_args: vec!["-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
         .. Default::default()
     };
     Ok(Target {
diff --git a/src/librustc_back/target/haiku_base.rs b/src/librustc_back/target/haiku_base.rs
new file mode 100644 (file)
index 0000000..5e319ba
--- /dev/null
@@ -0,0 +1,23 @@
+// 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 target::TargetOptions;
+use std::default::Default;
+
+pub fn opts() -> TargetOptions {
+    TargetOptions {
+        linker: "cc".to_string(),
+        dynamic_linking: true,
+        executables: true,
+        has_rpath: true,
+        linker_is_gnu: true,
+        .. Default::default()
+    }
+}
diff --git a/src/librustc_back/target/i686_unknown_haiku.rs b/src/librustc_back/target/i686_unknown_haiku.rs
new file mode 100644 (file)
index 0000000..8620167
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use target::{Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::haiku_base::opts();
+    base.cpu = "pentium4".to_string();
+    base.max_atomic_width = 64;
+    base.pre_link_args.push("-m32".to_string());
+
+    Ok(Target {
+        llvm_target: "i686-unknown-haiku".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
+        arch: "x86".to_string(),
+        target_os: "haiku".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "unknown".to_string(),
+        options: base,
+    })
+}
index 837856344280f89c9fffb86a2b92eef2fdf8ed73..7e45b3206536007084206735de1d868717bf884e 100644 (file)
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
         llvm_target: "mips64-unknown-linux-gnuabi64".to_string(),
         target_endian: "big".to_string(),
         target_pointer_width: "64".to_string(),
-        data_layout: "E-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
+        data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
index e1340e8e127b229ddb9baf69c14994843ef9242e..338a5da1e1d1d64e87909a325d8eae6312424733 100644 (file)
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
         llvm_target: "mips64el-unknown-linux-gnuabi64".to_string(),
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
-        data_layout: "e-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
+        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
index 756586602b45a6d7f9bcbd6cec0809b72067e13e..4404af1970e77857423c39d13a864fb503a36a54 100644 (file)
 use std::io::prelude::*;
 use syntax::abi::Abi;
 
+use PanicStrategy;
+
 mod android_base;
 mod apple_base;
 mod apple_ios_base;
 mod bitrig_base;
 mod dragonfly_base;
 mod freebsd_base;
+mod haiku_base;
 mod linux_base;
 mod linux_musl_base;
 mod openbsd_base;
@@ -165,6 +168,9 @@ fn $module() {
     ("x86_64-unknown-netbsd", x86_64_unknown_netbsd),
     ("x86_64-rumprun-netbsd", x86_64_rumprun_netbsd),
 
+    ("i686-unknown-haiku", i686_unknown_haiku),
+    ("x86_64-unknown-haiku", x86_64_unknown_haiku),
+
     ("x86_64-apple-darwin", x86_64_apple_darwin),
     ("i686-apple-darwin", i686_apple_darwin),
 
@@ -184,7 +190,8 @@ fn $module() {
     ("i586-pc-windows-msvc", i586_pc_windows_msvc),
 
     ("le32-unknown-nacl", le32_unknown_nacl),
-    ("asmjs-unknown-emscripten", asmjs_unknown_emscripten)
+    ("asmjs-unknown-emscripten", asmjs_unknown_emscripten),
+    ("wasm32-unknown-emscripten", wasm32_unknown_emscripten)
 }
 
 /// Everything `rustc` knows about how to compile for a specific target.
@@ -343,6 +350,9 @@ pub struct TargetOptions {
     /// Maximum integer size in bits that this target can perform atomic
     /// operations on.
     pub max_atomic_width: u64,
+
+    /// Panic strategy: "unwind" or "abort"
+    pub panic_strategy: PanicStrategy,
 }
 
 impl Default for TargetOptions {
@@ -392,6 +402,7 @@ fn default() -> TargetOptions {
             has_elf_tls: false,
             obj_is_bitcode: false,
             max_atomic_width: 0,
+            panic_strategy: PanicStrategy::Unwind,
         }
     }
 }
@@ -470,6 +481,19 @@ macro_rules! key {
                     .map(|o| o.as_u64()
                          .map(|s| base.options.$key_name = s));
             } );
+            ($key_name:ident, PanicStrategy) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                    match s {
+                        "unwind" => base.options.$key_name = PanicStrategy::Unwind,
+                        "abort" => base.options.$key_name = PanicStrategy::Abort,
+                        _ => return Some(Err(format!("'{}' is not a valid value for \
+                                                      panic-strategy. Use 'unwind' or 'abort'.",
+                                                     s))),
+                }
+                Some(Ok(()))
+            })).unwrap_or(Ok(()))
+            } );
             ($key_name:ident, list) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).map(|o| o.as_array()
@@ -530,6 +554,7 @@ macro_rules! key {
         key!(has_elf_tls, bool);
         key!(obj_is_bitcode, bool);
         key!(max_atomic_width, u64);
+        try!(key!(panic_strategy, PanicStrategy));
 
         Ok(base)
     }
@@ -672,6 +697,7 @@ macro_rules! target_option_val {
         target_option_val!(has_elf_tls);
         target_option_val!(obj_is_bitcode);
         target_option_val!(max_atomic_width);
+        target_option_val!(panic_strategy);
 
         Json::Object(d)
     }
diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_back/target/wasm32_unknown_emscripten.rs
new file mode 100644 (file)
index 0000000..2923f2e
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::{Target, TargetOptions};
+
+pub fn target() -> Result<Target, String> {
+    let opts = TargetOptions {
+        linker: "emcc".to_string(),
+        ar: "emar".to_string(),
+
+        dynamic_linking: false,
+        executables: true,
+        // Today emcc emits two files - a .js file to bootstrap and
+        // possibly interpret the wasm, and a .wasm file
+        exe_suffix: ".js".to_string(),
+        linker_is_gnu: true,
+        allow_asm: false,
+        obj_is_bitcode: true,
+        max_atomic_width: 32,
+        post_link_args: vec!["-s".to_string(), "BINARYEN=1".to_string(),
+                             "-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
+        .. Default::default()
+    };
+    Ok(Target {
+        llvm_target: "asmjs-unknown-emscripten".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_os: "emscripten".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "unknown".to_string(),
+        data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
+        arch: "wasm32".to_string(),
+        options: opts,
+    })
+}
diff --git a/src/librustc_back/target/x86_64_unknown_haiku.rs b/src/librustc_back/target/x86_64_unknown_haiku.rs
new file mode 100644 (file)
index 0000000..171e88c
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use target::{Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::haiku_base::opts();
+    base.cpu = "x86-64".to_string();
+    base.max_atomic_width = 64;
+    base.pre_link_args.push("-m64".to_string());
+
+    Ok(Target {
+        llvm_target: "x86_64-unknown-haiku".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "64".to_string(),
+        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        arch: "x86_64".to_string(),
+        target_os: "haiku".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "unknown".to_string(),
+        options: base,
+    })
+}
index aeb91f06a9aa455947d200861ac94c294adbbee4..5e22d477c518556b65fb6c123fa33231ed76cd9c 100644 (file)
@@ -73,11 +73,13 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     };
     assert!(args.len() == 1);
     let peek_arg_lval = match args[0] {
-        repr::Operand::Consume(ref lval @ repr::Lvalue::Temp(_)) => {
-            lval
-        }
-        repr::Operand::Consume(_) |
-        repr::Operand::Constant(_) => {
+        repr::Operand::Consume(ref lval @ repr::Lvalue::Local(_)) => Some(lval),
+        _ => None,
+    };
+
+    let peek_arg_lval = match peek_arg_lval {
+        Some(arg) => arg,
+        None => {
             tcx.sess.diagnostic().span_err(
                 span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
             return;
index 96702b209a1f5d0b271b8a5e0c7e6f2b5b6e9e1b..188fce467be52c8024be3e5f2606fb51493b7afa 100644 (file)
@@ -118,7 +118,7 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> {
     env: &'a MoveDataParamEnv<'tcx>,
     flow_inits: DataflowResults<MaybeInitializedLvals<'a, 'tcx>>,
     flow_uninits:  DataflowResults<MaybeUninitializedLvals<'a, 'tcx>>,
-    drop_flags: FnvHashMap<MovePathIndex, Temp>,
+    drop_flags: FnvHashMap<MovePathIndex, Local>,
     patch: MirPatch<'tcx>,
 }
 
@@ -164,7 +164,7 @@ fn create_drop_flag(&mut self, index: MovePathIndex) {
     }
 
     fn drop_flag(&mut self, index: MovePathIndex) -> Option<Lvalue<'tcx>> {
-        self.drop_flags.get(&index).map(|t| Lvalue::Temp(*t))
+        self.drop_flags.get(&index).map(|t| Lvalue::Local(*t))
     }
 
     /// create a patch that elaborates all drops in the input
@@ -847,14 +847,14 @@ fn unelaborated_free_block<'a>(
             statements.push(Statement {
                 source_info: c.source_info,
                 kind: StatementKind::Assign(
-                    Lvalue::Temp(flag),
+                    Lvalue::Local(flag),
                     self.constant_bool(c.source_info.span, false)
                 )
             });
         }
 
         let tcx = self.tcx;
-        let unit_temp = Lvalue::Temp(self.patch.new_temp(tcx.mk_nil()));
+        let unit_temp = Lvalue::Local(self.patch.new_temp(tcx.mk_nil()));
         let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
             .unwrap_or_else(|e| tcx.sess.fatal(&e));
         let substs = Substs::new(tcx, iter::once(Kind::from(ty)));
@@ -917,7 +917,7 @@ fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagSta
         if let Some(&flag) = self.drop_flags.get(&path) {
             let span = self.patch.source_info_for_location(self.mir, loc).span;
             let val = self.constant_bool(span, val.value());
-            self.patch.add_assign(loc, Lvalue::Temp(flag), val);
+            self.patch.add_assign(loc, Lvalue::Local(flag), val);
         }
     }
 
@@ -926,7 +926,7 @@ fn drop_flags_on_init(&mut self) {
         let span = self.patch.source_info_for_location(self.mir, loc).span;
         let false_ = self.constant_bool(span, false);
         for flag in self.drop_flags.values() {
-            self.patch.add_assign(loc, Lvalue::Temp(*flag), false_.clone());
+            self.patch.add_assign(loc, Lvalue::Local(*flag), false_.clone());
         }
     }
 
index 6346c1e58897e12e62d32e05abc82e3c38c80fc3..16e25d2b7725810c6bfa3f8086f5f819e995ab22 100644 (file)
@@ -173,13 +173,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 /// Tables mapping from an l-value to its MovePathIndex.
 #[derive(Debug)]
 pub struct MovePathLookup<'tcx> {
-    vars: IndexVec<Var, MovePathIndex>,
-    temps: IndexVec<Temp, MovePathIndex>,
-    args: IndexVec<Arg, MovePathIndex>,
-
-    /// The move path representing the return value is constructed
-    /// lazily when we first encounter it in the input MIR.
-    return_ptr: Option<MovePathIndex>,
+    locals: IndexVec<Local, MovePathIndex>,
 
     /// projections are made from a base-lvalue and a projection
     /// elem. The base-lvalue will have a unique MovePathIndex; we use
@@ -218,16 +212,9 @@ fn new(mir: &'a Mir<'tcx>,
                 moves: IndexVec::new(),
                 loc_map: LocationMap::new(mir),
                 rev_lookup: MovePathLookup {
-                    vars: mir.var_decls.indices().map(Lvalue::Var).map(|v| {
+                    locals: mir.local_decls.indices().map(Lvalue::Local).map(|v| {
                         Self::new_move_path(&mut move_paths, &mut path_map, None, v)
                     }).collect(),
-                    temps: mir.temp_decls.indices().map(Lvalue::Temp).map(|t| {
-                        Self::new_move_path(&mut move_paths, &mut path_map, None, t)
-                    }).collect(),
-                    args: mir.arg_decls.indices().map(Lvalue::Arg).map(|a| {
-                        Self::new_move_path(&mut move_paths, &mut path_map, None, a)
-                    }).collect(),
-                    return_ptr: None,
                     projections: FnvHashMap(),
                 },
                 move_paths: move_paths,
@@ -272,23 +259,9 @@ fn move_path_for(&mut self, lval: &Lvalue<'tcx>)
     {
         debug!("lookup({:?})", lval);
         match *lval {
-            Lvalue::Var(var) => Ok(self.data.rev_lookup.vars[var]),
-            Lvalue::Arg(arg) => Ok(self.data.rev_lookup.args[arg]),
-            Lvalue::Temp(temp) => Ok(self.data.rev_lookup.temps[temp]),
+            Lvalue::Local(local) => Ok(self.data.rev_lookup.locals[local]),
             // error: can't move out of a static
             Lvalue::Static(..) => Err(MovePathError::IllegalMove),
-            Lvalue::ReturnPointer => match self.data.rev_lookup.return_ptr {
-                Some(ptr) => Ok(ptr),
-                ref mut ptr @ None => {
-                    let path = Self::new_move_path(
-                        &mut self.data.move_paths,
-                        &mut self.data.path_map,
-                        None,
-                        lval.clone());
-                    *ptr = Some(path);
-                    Ok(path)
-                }
-            },
             Lvalue::Projection(ref proj) => {
                 self.move_path_for_projection(lval, proj)
             }
@@ -373,11 +346,8 @@ impl<'tcx> MovePathLookup<'tcx> {
     // parent.
     pub fn find(&self, lval: &Lvalue<'tcx>) -> LookupResult {
         match *lval {
-            Lvalue::Var(var) => LookupResult::Exact(self.vars[var]),
-            Lvalue::Temp(temp) => LookupResult::Exact(self.temps[temp]),
-            Lvalue::Arg(arg) => LookupResult::Exact(self.args[arg]),
+            Lvalue::Local(local) => LookupResult::Exact(self.locals[local]),
             Lvalue::Static(..) => LookupResult::Parent(None),
-            Lvalue::ReturnPointer => LookupResult::Exact(self.return_ptr.unwrap()),
             Lvalue::Projection(ref proj) => {
                 match self.find(&proj.base) {
                     LookupResult::Exact(base_path) => {
@@ -486,7 +456,7 @@ fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) {
             TerminatorKind::Unreachable => { }
 
             TerminatorKind::Return => {
-                self.gather_move(loc, &Lvalue::ReturnPointer);
+                self.gather_move(loc, &Lvalue::Local(RETURN_POINTER));
             }
 
             TerminatorKind::If { .. } |
index f26afdc2b857280ae51891af7712098027323db4..2a3c602b134e77074342603728aaa7558f0126e7 100644 (file)
@@ -338,8 +338,8 @@ fn drop_flag_effects_for_function_entry<'a, 'tcx, F>(
     where F: FnMut(MovePathIndex, DropFlagState)
 {
     let move_data = &ctxt.move_data;
-    for (arg, _) in mir.arg_decls.iter_enumerated() {
-        let lvalue = repr::Lvalue::Arg(arg);
+    for arg in mir.args_iter() {
+        let lvalue = repr::Lvalue::Local(arg);
         let lookup_result = move_data.rev_lookup.find(&lvalue);
         on_lookup_result_bits(tcx, mir, move_data,
                               lookup_result,
index 52cd1a9f949bf6219b7e1cd7e101a9a7c6ea0d8e..5d018c98684e32870315574b771efd6c814bdb36 100644 (file)
@@ -19,9 +19,9 @@ pub struct MirPatch<'tcx> {
     patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>,
     new_blocks: Vec<BasicBlockData<'tcx>>,
     new_statements: Vec<(Location, StatementKind<'tcx>)>,
-    new_temps: Vec<TempDecl<'tcx>>,
+    new_locals: Vec<LocalDecl<'tcx>>,
     resume_block: BasicBlock,
-    next_temp: usize,
+    next_local: usize,
 }
 
 impl<'tcx> MirPatch<'tcx> {
@@ -29,9 +29,9 @@ pub fn new(mir: &Mir<'tcx>) -> Self {
         let mut result = MirPatch {
             patch_map: IndexVec::from_elem(None, mir.basic_blocks()),
             new_blocks: vec![],
-            new_temps: vec![],
             new_statements: vec![],
-            next_temp: mir.temp_decls.len(),
+            new_locals: vec![],
+            next_local: mir.local_decls.len(),
             resume_block: START_BLOCK
         };
 
@@ -92,11 +92,11 @@ pub fn terminator_loc(&self, mir: &Mir<'tcx>, bb: BasicBlock) -> Location {
         }
     }
 
-    pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Temp {
-        let index = self.next_temp;
-        self.next_temp += 1;
-        self.new_temps.push(TempDecl { ty: ty });
-        Temp::new(index as usize)
+    pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Local {
+        let index = self.next_local;
+        self.next_local += 1;
+        self.new_locals.push(LocalDecl::new_temp(ty));
+        Local::new(index as usize)
     }
 
     pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock {
@@ -124,11 +124,11 @@ pub fn add_assign(&mut self, loc: Location, lv: Lvalue<'tcx>, rv: Rvalue<'tcx>)
 
     pub fn apply(self, mir: &mut Mir<'tcx>) {
         debug!("MirPatch: {:?} new temps, starting from index {}: {:?}",
-               self.new_temps.len(), mir.temp_decls.len(), self.new_temps);
+               self.new_locals.len(), mir.local_decls.len(), self.new_locals);
         debug!("MirPatch: {} new blocks, starting from index {}",
                self.new_blocks.len(), mir.basic_blocks().len());
         mir.basic_blocks_mut().extend(self.new_blocks);
-        mir.temp_decls.extend(self.new_temps);
+        mir.local_decls.extend(self.new_locals);
         for (src, patch) in self.patch_map.into_iter_enumerated() {
             if let Some(patch) = patch {
                 debug!("MirPatch: patching block {:?}", src);
index eb74936d8c905380625a63e630a06f6a24934631..5178ef65cf6a46ef356ff767996872483973688c 100644 (file)
@@ -536,10 +536,10 @@ fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
                 }
                 PatKind::Box(inner) => PatKind::Box(self.fold_pat(inner)),
                 PatKind::Ref(inner, mutbl) => PatKind::Ref(self.fold_pat(inner), mutbl),
-                PatKind::Vec(before, slice, after) => {
-                    PatKind::Vec(before.move_map(|x| self.fold_pat(x)),
-                                 slice.map(|x| self.fold_pat(x)),
-                                 after.move_map(|x| self.fold_pat(x)))
+                PatKind::Slice(before, slice, after) => {
+                    PatKind::Slice(before.move_map(|x| self.fold_pat(x)),
+                                   slice.map(|x| self.fold_pat(x)),
+                                   after.move_map(|x| self.fold_pat(x)))
                 }
                 PatKind::Wild |
                 PatKind::Lit(_) |
@@ -610,14 +610,14 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
         ty::TySlice(_) => match ctor {
             &Slice(n) => {
                 assert_eq!(pats_len, n);
-                PatKind::Vec(pats.collect(), None, hir::HirVec::new())
+                PatKind::Slice(pats.collect(), None, hir::HirVec::new())
             },
             _ => unreachable!()
         },
 
         ty::TyArray(_, len) => {
             assert_eq!(pats_len, len);
-            PatKind::Vec(pats.collect(), None, hir::HirVec::new())
+            PatKind::Slice(pats.collect(), None, hir::HirVec::new())
         }
 
         _ => {
@@ -713,7 +713,7 @@ fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
     };
 
     let max_slice_length = rows.iter().filter_map(|row| match row[0].0.node {
-        PatKind::Vec(ref before, _, ref after) => Some(before.len() + after.len()),
+        PatKind::Slice(ref before, _, ref after) => Some(before.len() + after.len()),
         _ => None
     }).max().map_or(0, |v| v + 1);
 
@@ -812,7 +812,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
             vec![ConstantValue(eval_const_expr(cx.tcx, &expr))],
         PatKind::Range(ref lo, ref hi) =>
             vec![ConstantRange(eval_const_expr(cx.tcx, &lo), eval_const_expr(cx.tcx, &hi))],
-        PatKind::Vec(ref before, ref slice, ref after) =>
+        PatKind::Slice(ref before, ref slice, ref after) =>
             match left_ty.sty {
                 ty::TyArray(..) => vec![Single],
                 ty::TySlice(_) if slice.is_some() => {
@@ -1001,7 +1001,7 @@ pub fn specialize<'a, 'b, 'tcx>(
             }
         }
 
-        PatKind::Vec(ref before, ref slice, ref after) => {
+        PatKind::Slice(ref before, ref slice, ref after) => {
             let pat_len = before.len() + after.len();
             match *constructor {
                 Single => {
index 4ae3c7d37db8dec202f82f0bf9f34cf2c3b49930..3bf936dc9960c26e206a5bcbc9e1320f98107008 100644 (file)
@@ -317,11 +317,11 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             PatKind::Struct(path.clone(), field_pats, false)
         }
 
-        hir::ExprVec(ref exprs) => {
+        hir::ExprArray(ref exprs) => {
             let pats = exprs.iter()
                             .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
                             .collect::<Result<_, _>>()?;
-            PatKind::Vec(pats, None, hir::HirVec::new())
+            PatKind::Slice(pats, None, hir::HirVec::new())
         }
 
         hir::ExprPath(_, ref path) => {
@@ -898,7 +898,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             Array(_, n) if idx >= n => {
                 signal!(e, IndexOutOfBounds { len: n, index: idx })
             }
-            Array(v, n) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
+            Array(v, n) => if let hir::ExprArray(ref v) = tcx.map.expect_expr(v).node {
                 assert_eq!(n as usize as u64, n);
                 eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args)?
             } else {
@@ -925,7 +925,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             _ => signal!(e, IndexedNonVec),
         }
       }
-      hir::ExprVec(ref v) => Array(e.id, v.len() as u64),
+      hir::ExprArray(ref v) => Array(e.id, v.len() as u64),
       hir::ExprRepeat(_, ref n) => {
           let len_hint = ty_hint.checked_or(tcx.types.usize);
           Repeat(
index 4a184d3174dff51deb5918b57604988f703050d7..510c9ceef0960a8c8b6a20e3625ee6c2e10b4052 100644 (file)
@@ -94,6 +94,27 @@ pub struct flock {
         pub const F_SETLKW: libc::c_int = 9;
     }
 
+    #[cfg(target_os = "haiku")]
+    mod os {
+        use libc;
+
+        pub struct flock {
+            pub l_type: libc::c_short,
+            pub l_whence: libc::c_short,
+            pub l_start: libc::off_t,
+            pub l_len: libc::off_t,
+            pub l_pid: libc::pid_t,
+
+            // not actually here, but brings in line with freebsd
+            pub l_sysid: libc::c_int,
+        }
+
+        pub const F_UNLCK: libc::c_short = 0x0200;
+        pub const F_WRLCK: libc::c_short = 0x0400;
+        pub const F_SETLK: libc::c_int = 0x0080;
+        pub const F_SETLKW: libc::c_int = 0x0100;
+    }
+
     #[cfg(any(target_os = "macos", target_os = "ios"))]
     mod os {
         use libc;
index 9d5dce7ad058eafd0e494067cb6e1722faddf0d6..f9ac1312d3c7505e71aa62ec34ae8a77c7f42be9 100644 (file)
@@ -639,6 +639,12 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
     }
     sess.track_errors(|| sess.lint_store.borrow_mut().process_command_line(sess))?;
 
+    // Currently, we ignore the name resolution data structures for the purposes of dependency
+    // tracking. Instead we will run name resolution and include its output in the hash of each
+    // item, much like we do for macro expansion. In other words, the hash reflects not just
+    // its contents but the results of name resolution on those contents. Hopefully we'll push
+    // this back at some point.
+    let _ignore = sess.dep_graph.in_ignore();
     let mut crate_loader = CrateLoader::new(sess, &cstore, &krate, crate_name);
     let resolver_arenas = Resolver::arenas();
     let mut resolver =
@@ -733,9 +739,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
         })
     })?;
 
-    // Collect defintions for def ids.
-    time(sess.time_passes(), "collecting defs", || resolver.definitions.collect(&krate));
-
     time(sess.time_passes(),
          "early lint checks",
          || lint::check_ast_crate(sess, &krate));
@@ -745,13 +748,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
          || ast_validation::check_crate(sess, &krate));
 
     time(sess.time_passes(), "name resolution", || -> CompileResult {
-        // Currently, we ignore the name resolution data structures for the purposes of dependency
-        // tracking. Instead we will run name resolution and include its output in the hash of each
-        // item, much like we do for macro expansion. In other words, the hash reflects not just
-        // its contents but the results of name resolution on those contents. Hopefully we'll push
-        // this back at some point.
-        let _ignore = sess.dep_graph.in_ignore();
-        resolver.build_reduced_graph(&krate);
         resolver.resolve_imports();
 
         // Since import resolution will eventually happen in expansion,
index 681a7ec5b5ac99d1f89670c7fb89b9ef8b3060ed..492165e2f2a8e081290d8af025ea390352c5b330 100644 (file)
@@ -73,7 +73,8 @@
 use rustc::dep_graph::DepGraph;
 use rustc::session::{self, config, Session, build_session, CompileResult};
 use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
-use rustc::session::config::{get_unstable_features_setting, nightly_options};
+use rustc::session::config::nightly_options;
+use rustc::session::early_error;
 use rustc::lint::Lint;
 use rustc::lint;
 use rustc_metadata::loader;
@@ -93,8 +94,6 @@
 use std::sync::{Arc, Mutex};
 use std::thread;
 
-use rustc::session::early_error;
-
 use syntax::{ast, json};
 use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
 use syntax::feature_gate::{GatedCfg, UnstableFeatures};
@@ -131,17 +130,18 @@ pub fn abort_on_err<T>(result: Result<T, usize>, sess: &Session) -> T {
     }
 }
 
-pub fn run(args: Vec<String>) -> isize {
+pub fn run<F>(run_compiler: F) -> isize
+    where F: FnOnce() -> (CompileResult, Option<Session>) + Send + 'static
+{
     monitor(move || {
-        let (result, session) = run_compiler(&args, &mut RustcDefaultCalls);
+        let (result, session) = run_compiler();
         if let Err(err_count) = result {
             if err_count > 0 {
                 match session {
                     Some(sess) => sess.fatal(&abort_msg(err_count)),
                     None => {
                         let emitter =
-                            errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
-                                                                   None);
+                            errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, None);
                         let handler = errors::Handler::with_emitter(true, false, Box::new(emitter));
                         handler.emit(&MultiSpan::new(),
                                      &abort_msg(err_count),
@@ -155,20 +155,15 @@ pub fn run(args: Vec<String>) -> isize {
     0
 }
 
-pub fn run_compiler<'a>(args: &[String],
-                        callbacks: &mut CompilerCalls<'a>)
-                        -> (CompileResult, Option<Session>) {
-    run_compiler_with_file_loader(args, callbacks, box RealFileLoader)
-}
-
 // Parse args and run the compiler. This is the primary entry point for rustc.
 // See comments on CompilerCalls below for details about the callbacks argument.
 // The FileLoader provides a way to load files from sources other than the file system.
-pub fn run_compiler_with_file_loader<'a, L>(args: &[String],
-                                            callbacks: &mut CompilerCalls<'a>,
-                                            loader: Box<L>)
-                                            -> (CompileResult, Option<Session>)
-    where L: FileLoader + 'static {
+pub fn run_compiler<'a>(args: &[String],
+                        callbacks: &mut CompilerCalls<'a>,
+                        file_loader: Option<Box<FileLoader + 'static>>,
+                        emitter_dest: Option<Box<Write + Send>>)
+                        -> (CompileResult, Option<Session>)
+{
     macro_rules! do_or_return {($expr: expr, $sess: expr) => {
         match $expr {
             Compilation::Stop => return (Ok(()), $sess),
@@ -207,13 +202,16 @@ macro_rules! do_or_return {($expr: expr, $sess: expr) => {
 
     let dep_graph = DepGraph::new(sopts.build_dep_graph());
     let cstore = Rc::new(CStore::new(&dep_graph));
+
+    let loader = file_loader.unwrap_or(box RealFileLoader);
     let codemap = Rc::new(CodeMap::with_file_loader(loader));
     let sess = session::build_session_with_codemap(sopts,
                                                    &dep_graph,
                                                    input_file_path,
                                                    descriptions,
                                                    cstore.clone(),
-                                                   codemap);
+                                                   codemap,
+                                                   emitter_dest);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
     let mut cfg = config::build_configuration(&sess, cfg);
     target_features::add_configuration(&mut cfg, &sess);
@@ -649,10 +647,8 @@ fn print_crate_info(sess: &Session,
                     }
                 }
                 PrintRequest::Cfg => {
-                    let allow_unstable_cfg = match get_unstable_features_setting() {
-                        UnstableFeatures::Disallow => false,
-                        _ => true,
-                    };
+                    let allow_unstable_cfg = UnstableFeatures::from_environment()
+                        .is_nightly_build();
 
                     for cfg in cfg {
                         if !allow_unstable_cfg && GatedCfg::gate(&*cfg).is_some() {
@@ -1079,7 +1075,7 @@ fn flush(&mut self) -> io::Result<()> {
     }
 
     let thread = cfg.spawn(move || {
-         io::set_panic(box err);
+         io::set_panic(Some(box err));
          f()
      });
 
@@ -1125,7 +1121,7 @@ fn exit_on_err() -> ! {
     // Panic so the process returns a failure code, but don't pollute the
     // output with some unnecessary panic messages, we've already
     // printed everything that we needed to.
-    io::set_panic(box io::sink());
+    io::set_panic(Some(box io::sink()));
     panic!();
 }
 
@@ -1146,6 +1142,9 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
 }
 
 pub fn main() {
-    let result = run(env::args().collect());
+    let result = run(|| run_compiler(&env::args().collect::<Vec<_>>(),
+                                     &mut RustcDefaultCalls,
+                                     None,
+                                     None));
     process::exit(result as i32);
 }
index 6456b72dfb56cbe5b5bc78c9bd5bc811bbb0b81a..1d7ff45b3b8a04820b0255199abb580b6865a1ea 100644 (file)
@@ -99,8 +99,10 @@ pub fn stderr(color_config: ColorConfig,
     pub fn new(dst: Box<Write + Send>,
                code_map: Option<Rc<CodeMapper>>)
                -> EmitterWriter {
-        EmitterWriter { dst: Raw(dst),
-                        cm: code_map}
+        EmitterWriter {
+            dst: Raw(dst),
+            cm: code_map,
+        }
     }
 
     fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec<FileWithAnnotatedLines> {
index 55fe5fc1e349a21aa69278692053a484b22781f7..d0ae83a9826c25fbe35b2447011c1da2ed9e419f 100644 (file)
@@ -207,7 +207,7 @@ enum SawExprComponent<'a> {
     SawExprAgain(Option<token::InternedString>),
 
     SawExprBox,
-    SawExprVec,
+    SawExprArray,
     SawExprCall,
     SawExprMethodCall,
     SawExprTup,
@@ -235,7 +235,7 @@ enum SawExprComponent<'a> {
 fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
     match *node {
         ExprBox(..)              => SawExprBox,
-        ExprVec(..)              => SawExprVec,
+        ExprArray(..)            => SawExprArray,
         ExprCall(..)             => SawExprCall,
         ExprMethodCall(..)       => SawExprMethodCall,
         ExprTup(..)              => SawExprTup,
index 619e237ee34a3fc6f49d30503e5c3f127fb78c3c..d238121872be67131f8a2a206e4c20cbd456e68e 100644 (file)
@@ -20,6 +20,7 @@
 use rustc::util::nodemap::DefIdMap;
 use std::fmt::{self, Debug};
 use std::iter::once;
+use std::collections::HashMap;
 
 /// Index into the DefIdDirectory
 #[derive(Copy, Clone, Debug, PartialOrd, Ord, Hash, PartialEq, Eq,
@@ -90,18 +91,29 @@ pub fn krate_still_valid(&self,
     }
 
     pub fn retrace(&self, tcx: TyCtxt) -> RetracedDefIdDirectory {
-        let max_current_crate = self.max_current_crate(tcx);
+
+        fn make_key(name: &str, disambiguator: &str) -> String {
+            format!("{}/{}", name, disambiguator)
+        }
+
+        let new_krates: HashMap<_, _> =
+            once(LOCAL_CRATE)
+            .chain(tcx.sess.cstore.crates())
+            .map(|krate| (make_key(&tcx.crate_name(krate),
+                                   &tcx.crate_disambiguator(krate)), krate))
+            .collect();
 
         let ids = self.paths.iter()
                             .map(|path| {
-                                if self.krate_still_valid(tcx, max_current_crate, path.krate) {
-                                    tcx.retrace_path(path)
+                                let old_krate_id = path.krate.as_usize();
+                                assert!(old_krate_id < self.krates.len());
+                                let old_crate_info = &self.krates[old_krate_id];
+                                let old_crate_key = make_key(&old_crate_info.name,
+                                                         &old_crate_info.disambiguator);
+                                if let Some(&new_crate_key) = new_krates.get(&old_crate_key) {
+                                    tcx.retrace_path(new_crate_key, &path.data)
                                 } else {
-                                    debug!("crate {} changed from {:?} to {:?}/{:?}",
-                                           path.krate,
-                                           self.krates[path.krate.as_usize()],
-                                           tcx.crate_name(path.krate),
-                                           tcx.crate_disambiguator(path.krate));
+                                    debug!("crate {:?} no longer exists", old_crate_key);
                                     None
                                 }
                             })
diff --git a/src/librustc_incremental/persist/file_format.rs b/src/librustc_incremental/persist/file_format.rs
new file mode 100644 (file)
index 0000000..7c2b69e
--- /dev/null
@@ -0,0 +1,122 @@
+// 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.
+
+//! This module defines a generic file format that allows to check if a given
+//! file generated by incremental compilation was generated by a compatible
+//! compiler version. This file format is used for the on-disk version of the
+//! dependency graph and the exported metadata hashes.
+//!
+//! In practice "compatible compiler version" means "exactly the same compiler
+//! version", since the header encodes the git commit hash of the compiler.
+//! Since we can always just ignore the incremental compilation cache and
+//! compiler versions don't change frequently for the typical user, being
+//! conservative here practically has no downside.
+
+use std::io::{self, Read};
+use std::path::Path;
+use std::fs::File;
+use std::env;
+
+use rustc::session::config::nightly_options;
+
+/// The first few bytes of files generated by incremental compilation
+const FILE_MAGIC: &'static [u8] = b"RSIC";
+
+/// Change this if the header format changes
+const HEADER_FORMAT_VERSION: u16 = 0;
+
+/// A version string that hopefully is always different for compiler versions
+/// with different encodings of incremental compilation artifacts. Contains
+/// the git commit hash.
+const RUSTC_VERSION: Option<&'static str> = option_env!("CFG_VERSION");
+
+pub fn write_file_header<W: io::Write>(stream: &mut W) -> io::Result<()> {
+    stream.write_all(FILE_MAGIC)?;
+    stream.write_all(&[(HEADER_FORMAT_VERSION >> 0) as u8,
+                       (HEADER_FORMAT_VERSION >> 8) as u8])?;
+
+    let rustc_version = rustc_version();
+    assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize);
+    stream.write_all(&[rustc_version.len() as u8])?;
+    stream.write_all(rustc_version.as_bytes())?;
+
+    Ok(())
+}
+
+/// Reads the contents of a file with a file header as defined in this module.
+///
+/// - Returns `Ok(Some(data))` if the file existed and was generated by a
+///   compatible compiler version. `data` is the entire contents of the file
+///   *after* the header.
+/// - Returns `Ok(None)` if the file did not exist or was generated by an
+///   incompatible version of the compiler.
+/// - Returns `Err(..)` if some kind of IO error occurred while reading the
+///   file.
+pub fn read_file(path: &Path) -> io::Result<Option<Vec<u8>>> {
+    if !path.exists() {
+        return Ok(None);
+    }
+
+    let mut file = File::open(path)?;
+
+    // Check FILE_MAGIC
+    {
+        debug_assert!(FILE_MAGIC.len() == 4);
+        let mut file_magic = [0u8; 4];
+        file.read_exact(&mut file_magic)?;
+        if file_magic != FILE_MAGIC {
+            return Ok(None)
+        }
+    }
+
+    // Check HEADER_FORMAT_VERSION
+    {
+        debug_assert!(::std::mem::size_of_val(&HEADER_FORMAT_VERSION) == 2);
+        let mut header_format_version = [0u8; 2];
+        file.read_exact(&mut header_format_version)?;
+        let header_format_version = (header_format_version[0] as u16) |
+                                    ((header_format_version[1] as u16) << 8);
+
+        if header_format_version != HEADER_FORMAT_VERSION {
+            return Ok(None)
+        }
+    }
+
+    // Check RUSTC_VERSION
+    {
+        let mut rustc_version_str_len = [0u8; 1];
+        file.read_exact(&mut rustc_version_str_len)?;
+        let rustc_version_str_len = rustc_version_str_len[0] as usize;
+        let mut buffer = Vec::with_capacity(rustc_version_str_len);
+        buffer.resize(rustc_version_str_len, 0);
+        file.read_exact(&mut buffer[..])?;
+
+        if &buffer[..] != rustc_version().as_bytes() {
+            return Ok(None);
+        }
+    }
+
+    let mut data = vec![];
+    file.read_to_end(&mut data)?;
+
+    Ok(Some(data))
+}
+
+fn rustc_version() -> String {
+    if nightly_options::is_nightly_build() {
+        if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") {
+            return val.to_string_lossy().into_owned()
+        }
+    }
+
+    RUSTC_VERSION.expect("Cannot use rustc without explicit version for \
+                          incremental compilation")
+                 .to_string()
+}
index c9cfaf4f6613fd6a59490b8d571477bbbe05e7ec..2d28afeaebf2d37aa5e7f43dfd8842d3099fda42 100644 (file)
@@ -345,6 +345,15 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) {
     let _ = garbage_collect_session_directories(sess);
 }
 
+pub fn delete_all_session_dir_contents(sess: &Session) -> io::Result<()> {
+    let sess_dir_iterator = sess.incr_comp_session_dir().read_dir()?;
+    for entry in sess_dir_iterator {
+        let entry = entry?;
+        safe_remove_file(&entry.path())?
+    }
+    Ok(())
+}
+
 fn copy_files(target_dir: &Path,
               source_dir: &Path,
               print_stats_on_success: bool)
index 5a4716e45f6e1f9ae6af39fe04ac38394bae6cc0..ca173db15fcac37e303aff0beb9b16bb3a29bfd5 100644 (file)
 use rustc_data_structures::flock;
 use rustc_serialize::Decodable;
 use rustc_serialize::opaque::Decoder;
-use std::io::{ErrorKind, Read};
-use std::fs::File;
 
 use IncrementalHashesMap;
 use super::data::*;
 use super::fs::*;
+use super::file_format;
 
 pub struct HashContext<'a, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -153,12 +152,9 @@ fn load_data(&mut self, cnum: CrateNum) {
 
             let hashes_file_path = metadata_hash_import_path(&session_dir);
 
-            let mut data = vec![];
-            match
-                File::open(&hashes_file_path)
-                     .and_then(|mut file| file.read_to_end(&mut data))
+            match file_format::read_file(&hashes_file_path)
             {
-                Ok(_) => {
+                Ok(Some(data)) => {
                     match self.load_from_data(cnum, &data, svh) {
                         Ok(()) => { }
                         Err(err) => {
@@ -167,18 +163,13 @@ fn load_data(&mut self, cnum: CrateNum) {
                         }
                     }
                 }
+                Ok(None) => {
+                    // If the file is not found, that's ok.
+                }
                 Err(err) => {
-                    match err.kind() {
-                        ErrorKind::NotFound => {
-                            // If the file is not found, that's ok.
-                        }
-                        _ => {
-                            self.tcx.sess.err(
-                                &format!("could not load dep information from `{}`: {}",
-                                         hashes_file_path.display(), err));
-                            return;
-                        }
-                    }
+                    self.tcx.sess.err(
+                        &format!("could not load dep information from `{}`: {}",
+                                 hashes_file_path.display(), err));
                 }
             }
         }
index ba15529c81a570aa950eef032c57254def57bbab..db8d3125e510bf3f388e90f7c9054058485d5be2 100644 (file)
@@ -18,8 +18,7 @@
 use rustc_data_structures::fnv::{FnvHashSet, FnvHashMap};
 use rustc_serialize::Decodable as RustcDecodable;
 use rustc_serialize::opaque::Decoder;
-use std::io::Read;
-use std::fs::{self, File};
+use std::fs;
 use std::path::{Path};
 
 use IncrementalHashesMap;
@@ -28,6 +27,7 @@
 use super::dirty_clean;
 use super::hash::*;
 use super::fs::*;
+use super::file_format;
 
 pub type DirtyNodes = FnvHashSet<DepNode<DefPathIndex>>;
 
@@ -94,25 +94,26 @@ fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 fn load_data(sess: &Session, path: &Path) -> Option<Vec<u8>> {
-    if !path.exists() {
-        return None;
-    }
-
-    let mut data = vec![];
-    match
-        File::open(path)
-        .and_then(|mut file| file.read_to_end(&mut data))
-    {
-        Ok(_) => {
-            Some(data)
+    match file_format::read_file(path) {
+        Ok(Some(data)) => return Some(data),
+        Ok(None) => {
+            // The file either didn't exist or was produced by an incompatible
+            // compiler version. Neither is an error.
         }
         Err(err) => {
             sess.err(
                 &format!("could not load dep-graph from `{}`: {}",
                          path.display(), err));
-            None
         }
     }
+
+    if let Err(err) = delete_all_session_dir_contents(sess) {
+        sess.err(&format!("could not clear incompatible incremental \
+                           compilation session directory `{}`: {}",
+                          path.display(), err));
+    }
+
+    None
 }
 
 /// Decode the dep graph and load the edges/nodes that are still clean
@@ -331,16 +332,22 @@ fn load_prev_metadata_hashes(tcx: TyCtxt,
 
     debug!("load_prev_metadata_hashes() - File: {}", file_path.display());
 
-    let mut data = vec![];
-    if !File::open(&file_path)
-             .and_then(|mut file| file.read_to_end(&mut data)).is_ok() {
-        debug!("load_prev_metadata_hashes() - Couldn't read file containing \
-                hashes at `{}`", file_path.display());
-        return
-    }
+    let data = match file_format::read_file(&file_path) {
+        Ok(Some(data)) => data,
+        Ok(None) => {
+            debug!("load_prev_metadata_hashes() - File produced by incompatible \
+                    compiler version: {}", file_path.display());
+            return
+        }
+        Err(err) => {
+            debug!("load_prev_metadata_hashes() - Error reading file `{}`: {}",
+                   file_path.display(), err);
+            return
+        }
+    };
 
     debug!("load_prev_metadata_hashes() - Decoding hashes");
-    let mut decoder = Decoder::new(&mut data, 0);
+    let mut decoder = Decoder::new(&data, 0);
     let _ = Svh::decode(&mut decoder).unwrap();
     let serialized_hashes = SerializedMetadataHashes::decode(&mut decoder).unwrap();
 
@@ -358,3 +365,4 @@ fn load_prev_metadata_hashes(tcx: TyCtxt,
     debug!("load_prev_metadata_hashes() - successfully loaded {} hashes",
            serialized_hashes.index_map.len());
 }
+
index ba0f71971bb45e9afce432e341843b41d164816c..26fcde05868b9e4ca4bdf02119104661429050c6 100644 (file)
@@ -21,6 +21,7 @@
 mod preds;
 mod save;
 mod work_product;
+mod file_format;
 
 pub use self::fs::finalize_session_directory;
 pub use self::fs::in_incr_comp_dir;
index 896e8a9845e9480638c6c46f5aecd6b5b1e5f675..e6fb1da1982c11a6de53f9709c194f07605184cc 100644 (file)
@@ -28,6 +28,7 @@
 use super::preds::*;
 use super::fs::*;
 use super::dirty_clean;
+use super::file_format;
 
 pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 incremental_hashes_map: &IncrementalHashesMap,
@@ -102,6 +103,7 @@ fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
 
     // generate the data in a memory buffer
     let mut wr = Cursor::new(Vec::new());
+    file_format::write_file_header(&mut wr).unwrap();
     match encode(&mut Encoder::new(&mut wr)) {
         Ok(()) => {}
         Err(err) => {
index 1209ced8dd3d75ffd0d4fc45c67363267194ebd3..4caf7a04fe05806d40834755117b5f87e95e4a5a 100644 (file)
@@ -738,7 +738,7 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
                         .zip(variants)
                         .map(|(variant, variant_layout)| {
                             // Subtract the size of the enum discriminant
-                            let bytes = variant_layout.min_size().bytes()
+                            let bytes = variant_layout.min_size.bytes()
                                                                  .saturating_sub(discr_size);
 
                             debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);
index 3f551476e2b46b87a6529075e55bd2c6b124f5e5..5257575a94e8b1322a87ce3e0986adc1fa16afb7 100644 (file)
@@ -66,7 +66,8 @@ fn main() {
     let host = env::var("HOST").expect("HOST was not set");
     let is_crossed = target != host;
 
-    let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz"];
+    let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz",
+                               "jsbackend"];
 
     // FIXME: surely we don't need all these components, right? Stuff like mcjit
     //        or interpreter the compiler itself never uses.
index eb45d3d25c5c05f5ff71a713d57c039626cac426..3946b44ead5787c69b5e925359cef91f8aed5943 100644 (file)
@@ -434,6 +434,10 @@ fn init() { }
                  LLVMInitializeSystemZTargetMC,
                  LLVMInitializeSystemZAsmPrinter,
                  LLVMInitializeSystemZAsmParser);
+    init_target!(llvm_component = "jsbackend",
+                 LLVMInitializeJSBackendTargetInfo,
+                 LLVMInitializeJSBackendTarget,
+                 LLVMInitializeJSBackendTargetMC);
 }
 
 pub fn last_error() -> Option<String> {
index c2a2cc2ecd64d9c7414aafea261843b3858db034..1f3b705671db789c6c47cf676d967a1304e675db 100644 (file)
@@ -139,7 +139,7 @@ fn from_str(src: &str) -> Result<TokenStream, LexError> {
         __internal::with_parse_sess(|sess| {
             let src = src.to_string();
             let cfg = Vec::new();
-            let name = "rustc-macro source code".to_string();
+            let name = "<rustc-macro source code>".to_string();
             let mut parser = parse::new_parser_from_source_str(sess, cfg, name,
                                                                src);
             let mut ret = TokenStream { inner: Vec::new() };
index 2e03b7868a3bc8fe18d293435652eb03f4131c19..0c7f6204438a78803b21456fa7f94fb60153069b 100644 (file)
@@ -19,7 +19,7 @@
 use rustc::hir::svh::Svh;
 use rustc::middle::cstore::LoadedMacro;
 use rustc::session::{config, Session};
-use rustc::session::config::PanicStrategy;
+use rustc_back::PanicStrategy;
 use rustc::session::search_paths::PathKind;
 use rustc::middle;
 use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
@@ -710,7 +710,7 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
         // The logic for finding the panic runtime here is pretty much the same
         // as the allocator case with the only addition that the panic strategy
         // compilation mode also comes into play.
-        let desired_strategy = self.sess.opts.cg.panic.clone();
+        let desired_strategy = self.sess.panic_strategy();
         let mut runtime_found = false;
         let mut needs_panic_runtime = attr::contains_name(&krate.attrs,
                                                           "needs_panic_runtime");
index 1f25136ffe1acc679c7870dc66be5362b2f3ff5c..16a5b5402fbe30fc431939cf614f5774dcf32bc1 100644 (file)
@@ -26,7 +26,7 @@
 use rustc::mir::repr::Mir;
 use rustc::mir::mir_map::MirMap;
 use rustc::util::nodemap::{NodeSet, DefIdMap};
-use rustc::session::config::PanicStrategy;
+use rustc_back::PanicStrategy;
 
 use std::path::PathBuf;
 use syntax::ast;
index 0a1ff70a0497e518992afb0b8507f63aab173d32..038d0f73d5ce8fd579b6b001e48d8387d00ef14e 100644 (file)
@@ -19,7 +19,7 @@
 use rustc::hir::map::DefKey;
 use rustc::hir::svh::Svh;
 use rustc::middle::cstore::ExternCrate;
-use rustc::session::config::PanicStrategy;
+use rustc_back::PanicStrategy;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap, FnvHashSet};
 
index f52e1437acc9534a9b1a5c98c313d617c38aaf67..c03375bf8254fe822d095b3ae73e041bcebee967 100644 (file)
 
 ```compile_fail,E0466
 #[macro_use(a_macro(another_macro))] // error: invalid import declaration
-extern crate some_crate;
+extern crate core as some_crate;
 
 #[macro_use(i_want = "some_macros")] // error: invalid import declaration
-extern crate another_crate;
+extern crate core as another_crate;
 ```
 
 This is a syntax error at the level of attribute declarations. The proper
@@ -135,10 +135,10 @@ macro_rules! get_pimientos {
 
 ```compile_fail,E0467
 #[macro_reexport]                    // error: no macros listed for export
-extern crate macros_for_good;
+extern crate core as macros_for_good;
 
 #[macro_reexport(fun_macro = "foo")] // error: not a macro identifier
-extern crate other_macros_for_good;
+extern crate core as other_macros_for_good;
 ```
 
 This is a syntax error at the level of attribute declarations.
@@ -165,8 +165,8 @@ macro_rules! get_pimientos {
 ```compile_fail,E0468
 mod foo {
     #[macro_use(helpful_macro)] // error: must be at crate root to import
-    extern crate some_crate;    //        macros from another crate
-    helpful_macro!(...)
+    extern crate core;          //        macros from another crate
+    helpful_macro!(...);
 }
 ```
 
index 0f067270b80f5cb84c67bac8fc0ae956736ea6fd..4d18462848e5d84c6f1b5ea608b43fd3c6fb1f70 100644 (file)
@@ -1288,12 +1288,12 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot> {
         let link_meta = self.link_meta;
         let is_rustc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro);
         let root = self.lazy(&CrateRoot {
-            rustc_version: RUSTC_VERSION.to_string(),
+            rustc_version: rustc_version(),
             name: link_meta.crate_name.clone(),
             triple: tcx.sess.opts.target_triple.clone(),
             hash: link_meta.crate_hash,
             disambiguator: tcx.sess.local_crate_disambiguator().to_string(),
-            panic_strategy: tcx.sess.opts.cg.panic.clone(),
+            panic_strategy: tcx.sess.panic_strategy(),
             plugin_registrar_fn: tcx.sess.plugin_registrar_fn.get().map(|id| {
                 tcx.map.local_def_id(id).index
             }),
index fc94cec916aad146be7f830c77cc64040aa7912b..75242fc36db762bf592c4fc4ce2084049cb077cb 100644 (file)
 //! metadata::loader or metadata::creader for all the juicy details!
 
 use cstore::MetadataBlob;
-use schema::{METADATA_HEADER, RUSTC_VERSION};
+use schema::{METADATA_HEADER, rustc_version};
 
 use rustc::hir::svh::Svh;
 use rustc::session::Session;
@@ -382,7 +382,7 @@ pub fn report_load_errs(&mut self) -> ! {
         }
         if !self.rejected_via_version.is_empty() {
             err.help(&format!("please recompile that crate using this compiler ({})",
-                              RUSTC_VERSION));
+                              rustc_version()));
             let mismatches = self.rejected_via_version.iter();
             for (i, &CrateMismatch { ref path, ref got }) in mismatches.enumerate() {
                 err.note(&format!("crate `{}` path #{}: {} compiled by {:?}",
@@ -597,9 +597,10 @@ fn extract_one(&mut self, m: FnvHashMap<PathBuf, PathKind>, flavor: CrateFlavor,
 
     fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
         let root = metadata.get_root();
-        if root.rustc_version != RUSTC_VERSION {
+        let rustc_version = rustc_version();
+        if root.rustc_version != rustc_version {
             info!("Rejecting via version: expected {} got {}",
-                  RUSTC_VERSION, root.rustc_version);
+                  rustc_version, root.rustc_version);
             self.rejected_via_version.push(CrateMismatch {
                 path: libpath.to_path_buf(),
                 got: root.rustc_version
index 2ff7a6c41b551b260e2b4f503c8aca5b498ab4f9..385f582e2d36b84f0d0b1da715e8a55163415d5a 100644 (file)
@@ -18,7 +18,7 @@
 use creader::{CrateLoader, Macros};
 
 use rustc::hir::def_id::DefIndex;
-use rustc::middle::cstore::LoadedMacro;
+use rustc::middle::cstore::{LoadedMacro, LoadedMacroKind};
 use rustc::session::Session;
 use rustc::util::nodemap::FnvHashMap;
 use rustc_back::dynamic_lib::DynamicLibrary;
@@ -28,7 +28,7 @@
 use syntax::attr;
 use syntax::parse::token;
 use syntax_ext::deriving::custom::CustomDerive;
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 
 pub fn call_bad_macro_reexport(a: &Session, b: Span) {
     span_err!(a, b, E0467, "bad macro reexport");
@@ -36,6 +36,11 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) {
 
 pub type MacroSelection = FnvHashMap<token::InternedString, Span>;
 
+enum ImportSelection {
+    All(Span),
+    Some(MacroSelection),
+}
+
 pub fn load_macros(loader: &mut CrateLoader, extern_crate: &ast::Item, allows_macros: bool)
                    -> Vec<LoadedMacro> {
     loader.load_crate(extern_crate, allows_macros)
@@ -46,7 +51,7 @@ fn load_crate(&mut self,
                   extern_crate: &ast::Item,
                   allows_macros: bool) -> Vec<LoadedMacro> {
         // Parse the attributes relating to macros.
-        let mut import = Some(FnvHashMap());  // None => load all
+        let mut import = ImportSelection::Some(FnvHashMap());
         let mut reexport = FnvHashMap();
 
         for attr in &extern_crate.attrs {
@@ -55,11 +60,9 @@ fn load_crate(&mut self,
                 "macro_use" => {
                     let names = attr.meta_item_list();
                     if names.is_none() {
-                        // no names => load all
-                        import = None;
-                    }
-                    if let (Some(sel), Some(names)) = (import.as_mut(), names) {
-                        for attr in names {
+                        import = ImportSelection::All(attr.span);
+                    } else if let ImportSelection::Some(ref mut sel) = import {
+                        for attr in names.unwrap() {
                             if let Some(word) = attr.word() {
                                 sel.insert(word.name().clone(), attr.span());
                             } else {
@@ -98,10 +101,10 @@ fn load_crate(&mut self,
     fn load_macros<'b>(&mut self,
                        vi: &ast::Item,
                        allows_macros: bool,
-                       import: Option<MacroSelection>,
+                       import: ImportSelection,
                        reexport: MacroSelection)
                        -> Vec<LoadedMacro> {
-        if let Some(sel) = import.as_ref() {
+        if let ImportSelection::Some(ref sel) = import {
             if sel.is_empty() && reexport.is_empty() {
                 return Vec::new();
             }
@@ -120,15 +123,19 @@ fn load_macros<'b>(&mut self,
         for mut def in macros.macro_rules.drain(..) {
             let name = def.ident.name.as_str();
 
-            def.use_locally = match import.as_ref() {
-                None => true,
-                Some(sel) => sel.contains_key(&name),
+            let import_site = match import {
+                ImportSelection::All(span) => Some(span),
+                ImportSelection::Some(ref sel) => sel.get(&name).cloned()
             };
+            def.use_locally = import_site.is_some();
             def.export = reexport.contains_key(&name);
             def.allow_internal_unstable = attr::contains_name(&def.attrs,
                                                               "allow_internal_unstable");
             debug!("load_macros: loaded: {:?}", def);
-            ret.push(LoadedMacro::Def(def));
+            ret.push(LoadedMacro {
+                kind: LoadedMacroKind::Def(def),
+                import_site: import_site.unwrap_or(DUMMY_SP),
+            });
             seen.insert(name);
         }
 
@@ -137,7 +144,7 @@ fn load_macros<'b>(&mut self,
             // exported macros, enforced elsewhere
             assert_eq!(ret.len(), 0);
 
-            if import.is_some() {
+            if let ImportSelection::Some(..) = import {
                 self.sess.span_err(vi.span, "`rustc-macro` crates cannot be \
                                              selectively imported from, must \
                                              use `#[macro_use]`");
@@ -151,10 +158,10 @@ fn load_macros<'b>(&mut self,
             self.load_derive_macros(vi.span, &macros, index, &mut ret);
         }
 
-        if let Some(sel) = import.as_ref() {
+        if let ImportSelection::Some(sel) = import {
             for (name, span) in sel {
                 if !seen.contains(&name) {
-                    span_err!(self.sess, *span, E0469,
+                    span_err!(self.sess, span, E0469,
                               "imported macro not found");
                 }
             }
@@ -199,18 +206,21 @@ fn load_derive_macros(&mut self,
             mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
         };
 
-        struct MyRegistrar<'a>(&'a mut Vec<LoadedMacro>);
+        struct MyRegistrar<'a>(&'a mut Vec<LoadedMacro>, Span);
 
         impl<'a> Registry for MyRegistrar<'a> {
             fn register_custom_derive(&mut self,
                                       trait_name: &str,
                                       expand: fn(TokenStream) -> TokenStream) {
                 let derive = Rc::new(CustomDerive::new(expand));
-                self.0.push(LoadedMacro::CustomDerive(trait_name.to_string(), derive));
+                self.0.push(LoadedMacro {
+                    kind: LoadedMacroKind::CustomDerive(trait_name.to_string(), derive),
+                    import_site: self.1,
+                });
             }
         }
 
-        registrar(&mut MyRegistrar(ret));
+        registrar(&mut MyRegistrar(ret, span));
 
         // Intentionally leak the dynamic library. We can't ever unload it
         // since the library can make things that will live arbitrarily long.
index f4d1e8e17f842066e39ec459dd6d39da5ee2de29..1a46315e9cd7ac7a2da4395412568520b19c97ff 100644 (file)
@@ -18,7 +18,7 @@
 use rustc::middle::lang_items;
 use rustc::mir;
 use rustc::ty::{self, Ty};
-use rustc::session::config::PanicStrategy;
+use rustc_back::PanicStrategy;
 
 use rustc_serialize as serialize;
 use syntax::{ast, attr};
 
 use std::marker::PhantomData;
 
-#[cfg(not(test))]
-pub const RUSTC_VERSION: &'static str = concat!("rustc ", env!("CFG_VERSION"));
-
-#[cfg(test)]
-pub const RUSTC_VERSION: &'static str = "rustc 0.0.0-unit-test";
+pub fn rustc_version() -> String {
+    format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version"))
+}
 
 /// Metadata encoding version.
 /// NB: increment this if you change the format of metadata such that
index ae5ccbfd820996f8c1b582e66a501032f538797f..a9dfc6ea651e411499c584d392518a5b6b7d7233 100644 (file)
@@ -77,11 +77,11 @@ fn expr_as_lvalue(&mut self,
                 success.and(slice.index(idx))
             }
             ExprKind::SelfRef => {
-                block.and(Lvalue::Arg(Arg::new(0)))
+                block.and(Lvalue::Local(Local::new(1)))
             }
             ExprKind::VarRef { id } => {
                 let index = this.var_indices[&id];
-                block.and(Lvalue::Var(index))
+                block.and(Lvalue::Local(index))
             }
             ExprKind::StaticRef { id } => {
                 block.and(Lvalue::Static(id))
index a40571c5d859784125c247ea19cf785b6e8d1622..2123235ddc1d887f7417d8f26e32c8aebe64ea0f 100644 (file)
@@ -160,7 +160,7 @@ fn expr_as_rvalue(&mut self,
                           .map(|f| unpack!(block = this.as_operand(block, f)))
                           .collect();
 
-                block.and(Rvalue::Aggregate(AggregateKind::Vec, fields))
+                block.and(Rvalue::Aggregate(AggregateKind::Array, fields))
             }
             ExprKind::Tuple { fields } => { // see (*) above
                 // first process the set of fields
index 8ae23c9103b02ca7c51d7925b05715724e1cda83..9448527e6e65f0b9d21cc42084641be7faaf8d3f 100644 (file)
@@ -90,9 +90,13 @@ pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd
             }
             ExprKind::Return { value } => {
                 block = match value {
-                    Some(value) => unpack!(this.into(&Lvalue::ReturnPointer, block, value)),
+                    Some(value) => {
+                        unpack!(this.into(&Lvalue::Local(RETURN_POINTER), block, value))
+                    }
                     None => {
-                        this.cfg.push_assign_unit(block, source_info, &Lvalue::ReturnPointer);
+                        this.cfg.push_assign_unit(block,
+                                                  source_info,
+                                                  &Lvalue::Local(RETURN_POINTER));
                         block
                     }
                 };
index 1b64b4d0b5317861712ebae924b4fec20e60fa32..a9ea82140b536eaf4b985bccba170057bd14aa88 100644 (file)
@@ -123,7 +123,7 @@ pub fn expr_into_pattern(&mut self,
                                    var,
                                    subpattern: None, .. } => {
                 self.storage_live_for_bindings(block, &irrefutable_pat);
-                let lvalue = Lvalue::Var(self.var_indices[&var]);
+                let lvalue = Lvalue::Local(self.var_indices[&var]);
                 return self.into(&lvalue, block, initializer);
             }
             _ => {}
@@ -214,7 +214,7 @@ pub fn storage_live_for_bindings(&mut self,
                                      pattern: &Pattern<'tcx>) {
         match *pattern.kind {
             PatternKind::Binding { var, ref subpattern, .. } => {
-                let lvalue = Lvalue::Var(self.var_indices[&var]);
+                let lvalue = Lvalue::Local(self.var_indices[&var]);
                 let source_info = self.source_info(pattern.span);
                 self.cfg.push(block, Statement {
                     source_info: source_info,
@@ -705,10 +705,10 @@ fn bind_matched_candidate(&mut self,
             let source_info = self.source_info(binding.span);
             self.cfg.push(block, Statement {
                 source_info: source_info,
-                kind: StatementKind::StorageLive(Lvalue::Var(var_index))
+                kind: StatementKind::StorageLive(Lvalue::Local(var_index))
             });
             self.cfg.push_assign(block, source_info,
-                                 &Lvalue::Var(var_index), rvalue);
+                                 &Lvalue::Local(var_index), rvalue);
         }
     }
 
@@ -718,19 +718,19 @@ fn declare_binding(&mut self,
                        name: Name,
                        var_id: NodeId,
                        var_ty: Ty<'tcx>)
-                       -> Var
+                       -> Local
     {
         debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, source_info={:?})",
                var_id, name, var_ty, source_info);
 
-        let var = self.var_decls.push(VarDecl::<'tcx> {
-            source_info: source_info,
+        let var = self.local_decls.push(LocalDecl::<'tcx> {
             mutability: mutability,
-            name: name,
             ty: var_ty.clone(),
+            name: Some(name),
+            source_info: Some(source_info),
         });
         let extent = self.extent_of_innermost_scope();
-        self.schedule_drop(source_info.span, extent, &Lvalue::Var(var), var_ty);
+        self.schedule_drop(source_info.span, extent, &Lvalue::Local(var), var_ty);
         self.var_indices.insert(var_id, var);
 
         debug!("declare_binding: var={:?}", var);
index 79a4cf73041d7c6e6d120018d37e2297d8ac1a6b..4bc51c3a6252db89c3b1fccadafdf871273ddcaa 100644 (file)
@@ -28,10 +28,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// NB: **No cleanup is scheduled for this temporary.** You should
     /// call `schedule_drop` once the temporary is initialized.
     pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> {
-        let temp = self.temp_decls.push(TempDecl { ty: ty });
-        let lvalue = Lvalue::Temp(temp);
+        let temp = self.local_decls.push(LocalDecl::new_temp(ty));
+        let lvalue = Lvalue::Local(temp);
         debug!("temp: created temp {:?} with type {:?}",
-               lvalue, self.temp_decls[temp].ty);
+               lvalue, self.local_decls[temp].ty);
         lvalue
     }
 
index 23591f05b8774f27d6a61815335a8ca58559f332..353aaaa45e18bed2d9f9bc9c9794ac37404edf55 100644 (file)
@@ -28,6 +28,7 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     cfg: CFG<'tcx>,
 
     fn_span: Span,
+    arg_count: usize,
 
     /// the current set of scopes, updated as we traverse;
     /// see the `scope` module for more details
@@ -49,9 +50,9 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
     visibility_scope: VisibilityScope,
 
-    var_decls: IndexVec<Var, VarDecl<'tcx>>,
-    var_indices: NodeMap<Var>,
-    temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
+    /// Maps node ids of variable bindings to the `Local`s created for them.
+    var_indices: NodeMap<Local>,
+    local_decls: IndexVec<Local, LocalDecl<'tcx>>,
     unit_temp: Option<Lvalue<'tcx>>,
 
     /// cached block with the RESUME terminator; this is created
@@ -157,9 +158,11 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                                        -> (Mir<'tcx>, ScopeAuxiliaryVec)
     where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
 {
+    let arguments: Vec<_> = arguments.collect();
+
     let tcx = hir.tcx();
     let span = tcx.map.span(fn_id);
-    let mut builder = Builder::new(hir, span);
+    let mut builder = Builder::new(hir, span, arguments.len(), return_ty);
 
     let body_id = ast_block.id;
     let call_site_extent =
@@ -169,9 +172,9 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
         tcx.region_maps.lookup_code_extent(
             CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
     let mut block = START_BLOCK;
-    let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
-        let arg_decls = unpack!(block = builder.in_scope(arg_extent, block, |builder| {
-            builder.args_and_body(block, return_ty, arguments, arg_extent, ast_block)
+    unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
+        unpack!(block = builder.in_scope(arg_extent, block, |builder| {
+            builder.args_and_body(block, return_ty, &arguments, arg_extent, ast_block)
         }));
 
         let source_info = builder.source_info(span);
@@ -180,16 +183,15 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                               TerminatorKind::Goto { target: return_block });
         builder.cfg.terminate(return_block, source_info,
                               TerminatorKind::Return);
-        return_block.and(arg_decls)
+        return_block.unit()
     }));
     assert_eq!(block, builder.return_block());
 
+    let mut spread_arg = None;
     match tcx.node_id_to_type(fn_id).sty {
         ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
             // RustCall pseudo-ABI untuples the last argument.
-            if let Some(last_arg) = arg_decls.last() {
-                arg_decls[last_arg].spread = true;
-            }
+            spread_arg = Some(Local::new(arguments.len()));
         }
         _ => {}
     }
@@ -218,7 +220,9 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
         }).collect()
     });
 
-    builder.finish(upvar_decls, arg_decls, return_ty)
+    let (mut mir, aux) = builder.finish(upvar_decls, return_ty);
+    mir.spread_arg = spread_arg;
+    (mir, aux)
 }
 
 pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
@@ -226,15 +230,16 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
                                        ast_expr: &'tcx hir::Expr)
                                        -> (Mir<'tcx>, ScopeAuxiliaryVec) {
     let tcx = hir.tcx();
+    let ty = tcx.expr_ty_adjusted(ast_expr);
     let span = tcx.map.span(item_id);
-    let mut builder = Builder::new(hir, span);
+    let mut builder = Builder::new(hir, span, 0, ty);
 
     let extent = tcx.region_maps.temporary_scope(ast_expr.id)
                     .unwrap_or(ROOT_CODE_EXTENT);
     let mut block = START_BLOCK;
     let _ = builder.in_scope(extent, block, |builder| {
         let expr = builder.hir.mirror(ast_expr);
-        unpack!(block = builder.into(&Lvalue::ReturnPointer, block, expr));
+        unpack!(block = builder.into(&Lvalue::Local(RETURN_POINTER), block, expr));
 
         let source_info = builder.source_info(span);
         let return_block = builder.return_block();
@@ -246,23 +251,26 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
         return_block.unit()
     });
 
-    let ty = tcx.expr_ty_adjusted(ast_expr);
-    builder.finish(vec![], IndexVec::new(), ty)
+    builder.finish(vec![], ty)
 }
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
-    fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span) -> Builder<'a, 'gcx, 'tcx> {
+    fn new(hir: Cx<'a, 'gcx, 'tcx>,
+           span: Span,
+           arg_count: usize,
+           return_ty: Ty<'tcx>)
+           -> Builder<'a, 'gcx, 'tcx> {
         let mut builder = Builder {
             hir: hir,
             cfg: CFG { basic_blocks: IndexVec::new() },
             fn_span: span,
+            arg_count: arg_count,
             scopes: vec![],
             visibility_scopes: IndexVec::new(),
             visibility_scope: ARGUMENT_VISIBILITY_SCOPE,
             scope_auxiliary: IndexVec::new(),
             loop_scopes: vec![],
-            temp_decls: IndexVec::new(),
-            var_decls: IndexVec::new(),
+            local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1),
             var_indices: NodeMap(),
             unit_temp: None,
             cached_resume_block: None,
@@ -278,7 +286,6 @@ fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span) -> Builder<'a, 'gcx, 'tcx> {
 
     fn finish(self,
               upvar_decls: Vec<UpvarDecl>,
-              arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
               return_ty: Ty<'tcx>)
               -> (Mir<'tcx>, ScopeAuxiliaryVec) {
         for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
@@ -291,27 +298,45 @@ fn finish(self,
                   self.visibility_scopes,
                   IndexVec::new(),
                   return_ty,
-                  self.var_decls,
-                  arg_decls,
-                  self.temp_decls,
+                  self.local_decls,
+                  self.arg_count,
                   upvar_decls,
                   self.fn_span
         ), self.scope_auxiliary)
     }
 
-    fn args_and_body<A>(&mut self,
-                        mut block: BasicBlock,
-                        return_ty: Ty<'tcx>,
-                        arguments: A,
-                        argument_extent: CodeExtent,
-                        ast_block: &'gcx hir::Block)
-                        -> BlockAnd<IndexVec<Arg, ArgDecl<'tcx>>>
-        where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
+    fn args_and_body(&mut self,
+                     mut block: BasicBlock,
+                     return_ty: Ty<'tcx>,
+                     arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)],
+                     argument_extent: CodeExtent,
+                     ast_block: &'gcx hir::Block)
+                     -> BlockAnd<()>
     {
-        // to start, translate the argument patterns and collect the argument types.
+        // Allocate locals for the function arguments
+        for &(ty, pattern) in arguments.iter() {
+            // If this is a simple binding pattern, give the local a nice name for debuginfo.
+            let mut name = None;
+            if let Some(pat) = pattern {
+                if let hir::PatKind::Binding(_, ref ident, _) = pat.node {
+                    name = Some(ident.node);
+                }
+            }
+
+            self.local_decls.push(LocalDecl {
+                mutability: Mutability::Not,
+                ty: ty,
+                source_info: None,
+                name: name,
+            });
+        }
+
         let mut scope = None;
-        let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| {
-            let lvalue = Lvalue::Arg(Arg::new(index));
+        // Bind the argument patterns
+        for (index, &(ty, pattern)) in arguments.iter().enumerate() {
+            // Function arguments always get the first Local indices after the return pointer
+            let lvalue = Lvalue::Local(Local::new(index + 1));
+
             if let Some(pattern) = pattern {
                 let pattern = self.hir.irrefutable_pat(pattern);
                 scope = self.declare_bindings(scope, ast_block.span, &pattern);
@@ -322,19 +347,7 @@ fn args_and_body<A>(&mut self,
             self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
                                argument_extent, &lvalue, ty);
 
-            let mut name = keywords::Invalid.name();
-            if let Some(pat) = pattern {
-                if let hir::PatKind::Binding(_, ref ident, _) = pat.node {
-                    name = ident.node;
-                }
-            }
-
-            ArgDecl {
-                ty: ty,
-                spread: false,
-                debug_name: name
-            }
-        }).collect();
+        }
 
         // Enter the argument pattern bindings visibility scope, if it exists.
         if let Some(visibility_scope) = scope {
@@ -344,9 +357,10 @@ fn args_and_body<A>(&mut self,
         // FIXME(#32959): temporary hack for the issue at hand
         let return_is_unit = return_ty.is_nil();
         // start the first basic block and translate the body
-        unpack!(block = self.ast_block(&Lvalue::ReturnPointer, return_is_unit, block, ast_block));
+        unpack!(block = self.ast_block(&Lvalue::Local(RETURN_POINTER),
+                return_is_unit, block, ast_block));
 
-        block.and(arg_decls)
+        block.unit()
     }
 
     fn get_unit_temp(&mut self) -> Lvalue<'tcx> {
index 0b33e5a145083fabc58475ea20d0f153480413cb..01cce3c7dd79474d2b2c55fc8a7091474f032dde 100644 (file)
@@ -26,7 +26,7 @@
 For now, we keep a mapping from each `CodeExtent` to its
 corresponding SEME region for later reference (see caveat in next
 paragraph). This is because region scopes are tied to
-them. Eventually, when we shift to non-lexical lifetimes, three should
+them. Eventually, when we shift to non-lexical lifetimes, there should
 be no need to remember this mapping.
 
 There is one additional wrinkle, actually, that I wanted to hide from
@@ -67,7 +67,7 @@
 early exit occurs, the method `exit_scope` is called. It is given the
 current point in execution where the early exit occurs, as well as the
 scope you want to branch to (note that all early exits from to some
-other enclosing scope). `exit_scope` will record thid exit point and
+other enclosing scope). `exit_scope` will record this exit point and
 also add all drops.
 
 Panics are handled in a similar fashion, except that a panic always
@@ -322,7 +322,11 @@ pub fn pop_scope(&mut self,
         self.diverge_cleanup();
         let scope = self.scopes.pop().unwrap();
         assert_eq!(scope.extent, extent);
-        unpack!(block = build_scope_drops(&mut self.cfg, &scope, &self.scopes, block));
+        unpack!(block = build_scope_drops(&mut self.cfg,
+                                          &scope,
+                                          &self.scopes,
+                                          block,
+                                          self.arg_count));
         self.scope_auxiliary[scope.id]
             .postdoms
             .push(self.cfg.current_location(block));
@@ -362,7 +366,11 @@ pub fn exit_scope(&mut self,
                 scope.cached_exits.insert((target, extent), b);
                 b
             };
-            unpack!(block = build_scope_drops(&mut self.cfg, scope, rest, block));
+            unpack!(block = build_scope_drops(&mut self.cfg,
+                                              scope,
+                                              rest,
+                                              block,
+                                              self.arg_count));
             if let Some(ref free_data) = scope.free {
                 let next = self.cfg.start_new_block();
                 let free = build_free(self.hir.tcx(), &tmp, free_data, next);
@@ -454,7 +462,7 @@ pub fn schedule_drop(&mut self,
         } else {
             // Only temps and vars need their storage dead.
             match *lvalue {
-                Lvalue::Temp(_) | Lvalue::Var(_) => DropKind::Storage,
+                Lvalue::Local(index) if index.index() > self.arg_count => DropKind::Storage,
                 _ => return
             }
         };
@@ -671,7 +679,8 @@ pub fn assert(&mut self, block: BasicBlock,
 fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
                            scope: &Scope<'tcx>,
                            earlier_scopes: &[Scope<'tcx>],
-                           mut block: BasicBlock)
+                           mut block: BasicBlock,
+                           arg_count: usize)
                            -> BlockAnd<()> {
     let mut iter = scope.drops.iter().rev().peekable();
     while let Some(drop_data) = iter.next() {
@@ -703,7 +712,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
             DropKind::Storage => {
                 // Only temps and vars need their storage dead.
                 match drop_data.location {
-                    Lvalue::Temp(_) | Lvalue::Var(_) => {}
+                    Lvalue::Local(index) if index.index() > arg_count => {}
                     _ => continue
                 }
 
index 11b4441c8460a62e486194febb783ba9b2d1ec0c..343d802119ea0d8287c58aa22f1d26e5dbb5b38f 100644 (file)
 
 use rustc::mir::repr::{Local, Location, Lvalue, Mir};
 use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_data_structures::indexed_vec::IndexVec;
 use std::marker::PhantomData;
 use std::mem;
 
 pub struct DefUseAnalysis<'tcx> {
     info: IndexVec<Local, Info<'tcx>>,
-    mir_summary: MirSummary,
 }
 
 #[derive(Clone)]
@@ -35,15 +34,13 @@ pub struct Use<'tcx> {
 impl<'tcx> DefUseAnalysis<'tcx> {
     pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> {
         DefUseAnalysis {
-            info: IndexVec::from_elem_n(Info::new(), mir.count_locals()),
-            mir_summary: MirSummary::new(mir),
+            info: IndexVec::from_elem_n(Info::new(), mir.local_decls.len()),
         }
     }
 
     pub fn analyze(&mut self, mir: &Mir<'tcx>) {
         let mut finder = DefUseFinder {
             info: mem::replace(&mut self.info, IndexVec::new()),
-            mir_summary: self.mir_summary,
         };
         finder.visit_mir(mir);
         self.info = finder.info
@@ -64,7 +61,6 @@ fn mutate_defs_and_uses<F>(&self, local: Local, mir: &mut Mir<'tcx>, mut callbac
         for lvalue_use in &self.info[local].defs_and_uses {
             MutateUseVisitor::new(local,
                                   &mut callback,
-                                  self.mir_summary,
                                   mir).visit_location(mir, lvalue_use.location)
         }
     }
@@ -80,13 +76,17 @@ pub fn replace_all_defs_and_uses_with(&self,
 
 struct DefUseFinder<'tcx> {
     info: IndexVec<Local, Info<'tcx>>,
-    mir_summary: MirSummary,
 }
 
 impl<'tcx> DefUseFinder<'tcx> {
     fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> {
         let info = &mut self.info;
-        self.mir_summary.local_index(lvalue).map(move |local| &mut info[local])
+
+        if let Lvalue::Local(local) = *lvalue {
+            Some(&mut info[local])
+        } else {
+            None
+        }
     }
 }
 
@@ -132,18 +132,16 @@ pub fn use_count(&self) -> usize {
 struct MutateUseVisitor<'tcx, F> {
     query: Local,
     callback: F,
-    mir_summary: MirSummary,
     phantom: PhantomData<&'tcx ()>,
 }
 
 impl<'tcx, F> MutateUseVisitor<'tcx, F> {
-    fn new(query: Local, callback: F, mir_summary: MirSummary, _: &Mir<'tcx>)
+    fn new(query: Local, callback: F, _: &Mir<'tcx>)
            -> MutateUseVisitor<'tcx, F>
            where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
         MutateUseVisitor {
             query: query,
             callback: callback,
-            mir_summary: mir_summary,
             phantom: PhantomData,
         }
     }
@@ -155,43 +153,11 @@ fn visit_lvalue(&mut self,
                     lvalue: &mut Lvalue<'tcx>,
                     context: LvalueContext<'tcx>,
                     location: Location) {
-        if self.mir_summary.local_index(lvalue) == Some(self.query) {
-            (self.callback)(lvalue, context, location)
-        }
-        self.super_lvalue(lvalue, context, location)
-    }
-}
-
-/// A small structure that enables various metadata of the MIR to be queried
-/// without a reference to the MIR itself.
-#[derive(Clone, Copy)]
-pub struct MirSummary {
-    arg_count: usize,
-    var_count: usize,
-    temp_count: usize,
-}
-
-impl MirSummary {
-    pub fn new(mir: &Mir) -> MirSummary {
-        MirSummary {
-            arg_count: mir.arg_decls.len(),
-            var_count: mir.var_decls.len(),
-            temp_count: mir.temp_decls.len(),
-        }
-    }
-
-    pub fn local_index<'tcx>(&self, lvalue: &Lvalue<'tcx>) -> Option<Local> {
-        match *lvalue {
-            Lvalue::Arg(arg) => Some(Local::new(arg.index())),
-            Lvalue::Var(var) => Some(Local::new(var.index() + self.arg_count)),
-            Lvalue::Temp(temp) => {
-                Some(Local::new(temp.index() + self.arg_count + self.var_count))
+        if let Lvalue::Local(local) = *lvalue {
+            if local == self.query {
+                (self.callback)(lvalue, context, location)
             }
-            Lvalue::ReturnPointer => {
-                Some(Local::new(self.arg_count + self.var_count + self.temp_count))
-            }
-            _ => None,
         }
+        self.super_lvalue(lvalue, context, location)
     }
 }
-
index 72b6d7f0e5aa514605252addab0cc268760c4650..1c1f0ca790267fe5b66f43c21e74d115a9caf3ef 100644 (file)
@@ -136,30 +136,31 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     write!(w, "    label=<fn {}(", dot::escape_html(&tcx.node_path_str(nid)))?;
 
     // fn argument types.
-    for (i, arg) in mir.arg_decls.iter().enumerate() {
+    for (i, arg) in mir.args_iter().enumerate() {
         if i > 0 {
             write!(w, ", ")?;
         }
-        write!(w, "{:?}: {}", Lvalue::Arg(Arg::new(i)), escape(&arg.ty))?;
+        write!(w, "{:?}: {}", Lvalue::Local(arg), escape(&mir.local_decls[arg].ty))?;
     }
 
     write!(w, ") -&gt; {}", escape(mir.return_ty))?;
     write!(w, r#"<br align="left"/>"#)?;
 
-    // User variable types (including the user's name in a comment).
-    for (i, var) in mir.var_decls.iter().enumerate() {
+    for local in mir.vars_and_temps_iter() {
+        let decl = &mir.local_decls[local];
+
         write!(w, "let ")?;
-        if var.mutability == Mutability::Mut {
+        if decl.mutability == Mutability::Mut {
             write!(w, "mut ")?;
         }
-        write!(w, r#"{:?}: {}; // {}<br align="left"/>"#,
-               Lvalue::Var(Var::new(i)), escape(&var.ty), var.name)?;
-    }
 
-    // Compiler-introduced temporary types.
-    for (i, temp) in mir.temp_decls.iter().enumerate() {
-        write!(w, r#"let mut {:?}: {};<br align="left"/>"#,
-               Lvalue::Temp(Temp::new(i)), escape(&temp.ty))?;
+        if let Some(name) = decl.name {
+            write!(w, r#"{:?}: {}; // {}<br align="left"/>"#,
+                   Lvalue::Local(local), escape(&decl.ty), name)?;
+        } else {
+            write!(w, r#"let mut {:?}: {};<br align="left"/>"#,
+                   Lvalue::Local(local), escape(&decl.ty))?;
+        }
     }
 
     writeln!(w, ">;")
index 6283ff2187ab8bbed00b8ff395d367627f26a409..2840538ae5b4f473feca3ec31e11bccb692b3cbd 100644 (file)
@@ -613,7 +613,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 value: value.to_ref(),
                 value_extents: cx.tcx.region_maps.node_extent(value.id)
             },
-        hir::ExprVec(ref fields) =>
+        hir::ExprArray(ref fields) =>
             ExprKind::Vec { fields: fields.to_ref() },
         hir::ExprTup(ref fields) =>
             ExprKind::Tuple { fields: fields.to_ref() },
index 7b8446b184fb3725f4fd8fc2170c25a23a9cbe62..8751b1dc03aabd7780d2baf08b2a0a3641529c68 100644 (file)
@@ -113,7 +113,7 @@ fn to_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
                 PatternKind::Deref { subpattern: self.to_pattern(subpattern) }
             }
 
-            PatKind::Vec(ref prefix, ref slice, ref suffix) => {
+            PatKind::Slice(ref prefix, ref slice, ref suffix) => {
                 let ty = self.cx.tcx.node_id_to_type(pat.id);
                 match ty.sty {
                     ty::TyRef(_, mt) =>
index 5e92a057da38280a46c8ca1ef21353e1bad1ef64..2dcefcc12f6e5e3b3374773f561309f30c4ca9a7 100644 (file)
@@ -202,7 +202,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
 
     // Array lengths, i.e. [T; constant].
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        if let hir::TyFixedLengthVec(_, ref length) = ty.node {
+        if let hir::TyArray(_, ref length) = ty.node {
             self.build_const_integer(length);
         }
         intravisit::walk_ty(self, ty);
index 01e2c6308ba01b9ef9d00a81e6da5519fb08a64f..5c88c89862126be6060d6e87a777087259f43a33 100644 (file)
@@ -214,6 +214,9 @@ fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
     format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
 }
 
+/// Prints user-defined variables in a scope tree.
+///
+/// Returns the total number of variables printed.
 fn write_scope_tree(tcx: TyCtxt,
                     mir: &Mir,
                     scope_tree: &FnvHashMap<VisibilityScope, Vec<VisibilityScope>>,
@@ -234,11 +237,14 @@ fn write_scope_tree(tcx: TyCtxt,
         writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;
 
         // User variable types (including the user's name in a comment).
-        for (id, var) in mir.var_decls.iter_enumerated() {
-            // Skip if not declared in this scope.
-            if var.source_info.scope != child {
+        for local in mir.vars_iter() {
+            let var = &mir.local_decls[local];
+            let (name, source_info) = if var.source_info.unwrap().scope == child {
+                (var.name.unwrap(), var.source_info.unwrap())
+            } else {
+                // Not a variable or not declared in this scope.
                 continue;
-            }
+            };
 
             let mut_str = if var.mutability == Mutability::Mut {
                 "mut "
@@ -251,13 +257,13 @@ fn write_scope_tree(tcx: TyCtxt,
                                        INDENT,
                                        indent,
                                        mut_str,
-                                       id,
+                                       local,
                                        var.ty);
             writeln!(w, "{0:1$} // \"{2}\" in {3}",
                      indented_var,
                      ALIGN,
-                     var.name,
-                     comment(tcx, var.source_info))?;
+                     name,
+                     comment(tcx, source_info))?;
         }
 
         write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;
@@ -291,9 +297,23 @@ fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
     }
 
+    // Print return pointer
+    let indented_retptr = format!("{}let mut {:?}: {};",
+                                  INDENT,
+                                  RETURN_POINTER,
+                                  mir.return_ty);
+    writeln!(w, "{0:1$} // return pointer",
+             indented_retptr,
+             ALIGN)?;
+
     write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;
 
-    write_mir_decls(mir, w)
+    write_temp_decls(mir, w)?;
+
+    // Add an empty line before the first block is printed.
+    writeln!(w, "")?;
+
+    Ok(())
 }
 
 fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
@@ -313,29 +333,24 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
         write!(w, "(")?;
 
         // fn argument types.
-        for (i, arg) in mir.arg_decls.iter_enumerated() {
-            if i.index() != 0 {
+        for (i, arg) in mir.args_iter().enumerate() {
+            if i != 0 {
                 write!(w, ", ")?;
             }
-            write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?;
+            write!(w, "{:?}: {}", Lvalue::Local(arg), mir.local_decls[arg].ty)?;
         }
 
         write!(w, ") -> {}", mir.return_ty)
     } else {
-        assert!(mir.arg_decls.is_empty());
+        assert_eq!(mir.arg_count, 0);
         write!(w, ": {} =", mir.return_ty)
     }
 }
 
-fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
+fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
     // Compiler-introduced temporary types.
-    for (id, temp) in mir.temp_decls.iter_enumerated() {
-        writeln!(w, "{}let mut {:?}: {};", INDENT, id, temp.ty)?;
-    }
-
-    // Wrote any declaration? Add an empty line before the first block is printed.
-    if !mir.var_decls.is_empty() || !mir.temp_decls.is_empty() {
-        writeln!(w, "")?;
+    for temp in mir.temps_iter() {
+        writeln!(w, "{}let mut {:?}: {};", INDENT, temp, mir.local_decls[temp].ty)?;
     }
 
     Ok(())
index 79fd16012d9ee24780e6449bd8baa4706a3ad109..783162cd5588fd90510ad4c7b6c008d57691b13e 100644 (file)
 //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the
 //! future.
 
-use def_use::{DefUseAnalysis, MirSummary};
+use def_use::DefUseAnalysis;
 use rustc::mir::repr::{Constant, Local, Location, Lvalue, Mir, Operand, Rvalue, StatementKind};
 use rustc::mir::transform::{MirPass, MirSource, Pass};
 use rustc::mir::visit::MutVisitor;
 use rustc::ty::TyCtxt;
-use rustc_data_structures::indexed_vec::Idx;
 use transform::qualify_consts;
 
 pub struct CopyPropagation;
@@ -78,9 +77,8 @@ fn run_pass<'a>(&mut self,
             def_use_analysis.analyze(mir);
 
             let mut changed = false;
-            for dest_local_index in 0..mir.count_locals() {
-                let dest_local = Local::new(dest_local_index);
-                debug!("Considering destination local: {}", mir.format_local(dest_local));
+            for dest_local in mir.local_decls.indices() {
+                debug!("Considering destination local: {:?}", dest_local);
 
                 let action;
                 let location;
@@ -89,19 +87,19 @@ fn run_pass<'a>(&mut self,
                     let dest_use_info = def_use_analysis.local_info(dest_local);
                     let dest_def_count = dest_use_info.def_count_not_including_drop();
                     if dest_def_count == 0 {
-                        debug!("  Can't copy-propagate local: dest {} undefined",
-                               mir.format_local(dest_local));
+                        debug!("  Can't copy-propagate local: dest {:?} undefined",
+                               dest_local);
                         continue
                     }
                     if dest_def_count > 1 {
-                        debug!("  Can't copy-propagate local: dest {} defined {} times",
-                               mir.format_local(dest_local),
+                        debug!("  Can't copy-propagate local: dest {:?} defined {} times",
+                               dest_local,
                                dest_use_info.def_count());
                         continue
                     }
                     if dest_use_info.use_count() == 0 {
-                        debug!("  Can't copy-propagate local: dest {} unused",
-                               mir.format_local(dest_local));
+                        debug!("  Can't copy-propagate local: dest {:?} unused",
+                               dest_local);
                         continue
                     }
                     let dest_lvalue_def = dest_use_info.defs_and_uses.iter().filter(|lvalue_def| {
@@ -121,11 +119,11 @@ fn run_pass<'a>(&mut self,
 
                     // That use of the source must be an assignment.
                     match statement.kind {
-                        StatementKind::Assign(ref dest_lvalue, Rvalue::Use(ref operand)) if
-                                Some(dest_local) == mir.local_index(dest_lvalue) => {
+                        StatementKind::Assign(Lvalue::Local(local), Rvalue::Use(ref operand)) if
+                                local == dest_local => {
                             let maybe_action = match *operand {
                                 Operand::Consume(ref src_lvalue) => {
-                                    Action::local_copy(mir, &def_use_analysis, src_lvalue)
+                                    Action::local_copy(&def_use_analysis, src_lvalue)
                                 }
                                 Operand::Constant(ref src_constant) => {
                                     Action::constant(src_constant)
@@ -162,15 +160,14 @@ enum Action<'tcx> {
 }
 
 impl<'tcx> Action<'tcx> {
-    fn local_copy(mir: &Mir<'tcx>, def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>)
+    fn local_copy(def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>)
                   -> Option<Action<'tcx>> {
         // The source must be a local.
-        let src_local = match mir.local_index(src_lvalue) {
-            Some(src_local) => src_local,
-            None => {
-                debug!("  Can't copy-propagate local: source is not a local");
-                return None
-            }
+        let src_local = if let Lvalue::Local(local) = *src_lvalue {
+            local
+        } else {
+            debug!("  Can't copy-propagate local: source is not a local");
+            return None;
         };
 
         // We're trying to copy propagate a local.
@@ -225,9 +222,9 @@ fn perform(self,
                 // First, remove all markers.
                 //
                 // FIXME(pcwalton): Don't do this. Merge live ranges instead.
-                debug!("  Replacing all uses of {} with {} (local)",
-                       mir.format_local(dest_local),
-                       mir.format_local(src_local));
+                debug!("  Replacing all uses of {:?} with {:?} (local)",
+                       dest_local,
+                       src_local);
                 for lvalue_use in &def_use_analysis.local_info(dest_local).defs_and_uses {
                     if lvalue_use.context.is_storage_marker() {
                         mir.make_statement_nop(lvalue_use.location)
@@ -240,7 +237,7 @@ fn perform(self,
                 }
 
                 // Replace all uses of the destination local with the source local.
-                let src_lvalue = Lvalue::from_local(mir, src_local);
+                let src_lvalue = Lvalue::Local(src_local);
                 def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue);
 
                 // Finally, zap the now-useless assignment instruction.
@@ -253,8 +250,8 @@ fn perform(self,
                 // First, remove all markers.
                 //
                 // FIXME(pcwalton): Don't do this. Merge live ranges instead.
-                debug!("  Replacing all uses of {} with {:?} (constant)",
-                       mir.format_local(dest_local),
+                debug!("  Replacing all uses of {:?} with {:?} (constant)",
+                       dest_local,
                        src_constant);
                 let dest_local_info = def_use_analysis.local_info(dest_local);
                 for lvalue_use in &dest_local_info.defs_and_uses {
@@ -264,8 +261,7 @@ fn perform(self,
                 }
 
                 // Replace all uses of the destination local with the constant.
-                let mut visitor = ConstantPropagationVisitor::new(MirSummary::new(mir),
-                                                                  dest_local,
+                let mut visitor = ConstantPropagationVisitor::new(dest_local,
                                                                   src_constant);
                 for dest_lvalue_use in &dest_local_info.defs_and_uses {
                     visitor.visit_location(mir, dest_lvalue_use.location)
@@ -298,17 +294,15 @@ fn perform(self,
 struct ConstantPropagationVisitor<'tcx> {
     dest_local: Local,
     constant: Constant<'tcx>,
-    mir_summary: MirSummary,
     uses_replaced: usize,
 }
 
 impl<'tcx> ConstantPropagationVisitor<'tcx> {
-    fn new(mir_summary: MirSummary, dest_local: Local, constant: Constant<'tcx>)
+    fn new(dest_local: Local, constant: Constant<'tcx>)
            -> ConstantPropagationVisitor<'tcx> {
         ConstantPropagationVisitor {
             dest_local: dest_local,
             constant: constant,
-            mir_summary: mir_summary,
             uses_replaced: 0,
         }
     }
@@ -319,16 +313,11 @@ fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
         self.super_operand(operand, location);
 
         match *operand {
-            Operand::Consume(ref lvalue) => {
-                if self.mir_summary.local_index(lvalue) != Some(self.dest_local) {
-                    return
-                }
-            }
-            Operand::Constant(_) => return,
+            Operand::Consume(Lvalue::Local(local)) if local == self.dest_local => {}
+            _ => return,
         }
 
         *operand = Operand::Constant(self.constant.clone());
         self.uses_replaced += 1
     }
 }
-
index a0331f03b019742e9d1b2f51486deee00187b756..b4159af6f071d8d64de0c6eb5d52a729543944f9 100644 (file)
 
 //! Performs various peephole optimizations.
 
-use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue};
+use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue, Local};
 use rustc::mir::transform::{MirPass, MirSource, Pass};
 use rustc::mir::visit::{MutVisitor, Visitor};
 use rustc::ty::TyCtxt;
 use rustc::util::nodemap::FnvHashSet;
+use rustc_data_structures::indexed_vec::Idx;
 use std::mem;
 
 pub struct InstCombine {
@@ -61,7 +62,8 @@ fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
             debug!("Replacing `&*`: {:?}", rvalue);
             let new_lvalue = match *rvalue {
                 Rvalue::Ref(_, _, Lvalue::Projection(ref mut projection)) => {
-                    mem::replace(&mut projection.base, Lvalue::ReturnPointer)
+                    // Replace with dummy
+                    mem::replace(&mut projection.base, Lvalue::Local(Local::new(0)))
                 }
                 _ => bug!("Detected `&*` but didn't find `&*`!"),
             };
@@ -107,4 +109,3 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
 struct OptimizationList {
     and_stars: FnvHashSet<Location>,
 }
-
index 57de68fce1d1a4543e435b08bf4cc0b847fa00ba..9afc97d1e319a1f2523dc98f664f7d581bd50972 100644 (file)
@@ -30,6 +30,7 @@
 
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
+use std::iter;
 use std::mem;
 use std::usize;
 
@@ -74,15 +75,24 @@ pub enum Candidate {
     ShuffleIndices(BasicBlock)
 }
 
-struct TempCollector {
-    temps: IndexVec<Temp, TempState>,
-    span: Span
+struct TempCollector<'tcx> {
+    temps: IndexVec<Local, TempState>,
+    span: Span,
+    mir: &'tcx Mir<'tcx>,
 }
 
-impl<'tcx> Visitor<'tcx> for TempCollector {
-    fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) {
+impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> {
+    fn visit_lvalue(&mut self,
+                    lvalue: &Lvalue<'tcx>,
+                    context: LvalueContext<'tcx>,
+                    location: Location) {
         self.super_lvalue(lvalue, context, location);
-        if let Lvalue::Temp(index) = *lvalue {
+        if let Lvalue::Local(index) = *lvalue {
+            // We're only interested in temporaries
+            if self.mir.local_kind(index) != LocalKind::Temp {
+                return;
+            }
+
             // Ignore drops, if the temp gets promoted,
             // then it's constant and thus drop is noop.
             // Storage live ranges are also irrelevant.
@@ -126,10 +136,11 @@ fn visit_source_info(&mut self, source_info: &SourceInfo) {
     }
 }
 
-pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, TempState> {
+pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Local, TempState> {
     let mut collector = TempCollector {
-        temps: IndexVec::from_elem(TempState::Undefined, &mir.temp_decls),
-        span: mir.span
+        temps: IndexVec::from_elem(TempState::Undefined, &mir.local_decls),
+        span: mir.span,
+        mir: mir,
     };
     for (bb, data) in rpo {
         collector.visit_basic_block_data(bb, data);
@@ -140,7 +151,7 @@ pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, Te
 struct Promoter<'a, 'tcx: 'a> {
     source: &'a mut Mir<'tcx>,
     promoted: Mir<'tcx>,
-    temps: &'a mut IndexVec<Temp, TempState>,
+    temps: &'a mut IndexVec<Local, TempState>,
 
     /// If true, all nested temps are also kept in the
     /// source MIR, not moved to the promoted MIR.
@@ -163,7 +174,7 @@ fn new_block(&mut self) -> BasicBlock {
         })
     }
 
-    fn assign(&mut self, dest: Lvalue<'tcx>, rvalue: Rvalue<'tcx>, span: Span) {
+    fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) {
         let last = self.promoted.basic_blocks().last().unwrap();
         let data = &mut self.promoted[last];
         data.statements.push(Statement {
@@ -171,13 +182,13 @@ fn assign(&mut self, dest: Lvalue<'tcx>, rvalue: Rvalue<'tcx>, span: Span) {
                 span: span,
                 scope: ARGUMENT_VISIBILITY_SCOPE
             },
-            kind: StatementKind::Assign(dest, rvalue)
+            kind: StatementKind::Assign(Lvalue::Local(dest), rvalue)
         });
     }
 
     /// Copy the initialization of this temp to the
     /// promoted MIR, recursing through temps.
-    fn promote_temp(&mut self, temp: Temp) -> Temp {
+    fn promote_temp(&mut self, temp: Local) -> Local {
         let old_keep_original = self.keep_original;
         let (bb, stmt_idx) = match self.temps[temp] {
             TempState::Defined {
@@ -259,20 +270,19 @@ fn promote_temp(&mut self, temp: Temp) -> Temp {
             });
         }
 
-        let new_temp = self.promoted.temp_decls.push(TempDecl {
-            ty: self.source.temp_decls[temp].ty
-        });
+        let new_temp = self.promoted.local_decls.push(
+            LocalDecl::new_temp(self.source.local_decls[temp].ty));
 
         // Inject the Rvalue or Call into the promoted MIR.
         if stmt_idx < no_stmts {
-            self.assign(Lvalue::Temp(new_temp), rvalue.unwrap(), source_info.span);
+            self.assign(new_temp, rvalue.unwrap(), source_info.span);
         } else {
             let last = self.promoted.basic_blocks().last().unwrap();
             let new_target = self.new_block();
             let mut call = call.unwrap();
             match call {
                 TerminatorKind::Call { ref mut destination, ..}  => {
-                    *destination = Some((Lvalue::Temp(new_temp), new_target));
+                    *destination = Some((Lvalue::Local(new_temp), new_target));
                 }
                 _ => bug!()
             }
@@ -315,11 +325,12 @@ fn promote_candidate(mut self, candidate: Candidate) {
                 }
             }
         };
-        self.visit_rvalue(&mut rvalue, Location{
+        self.visit_rvalue(&mut rvalue, Location {
             block: BasicBlock::new(0),
             statement_index: usize::MAX
         });
-        self.assign(Lvalue::ReturnPointer, rvalue, span);
+
+        self.assign(RETURN_POINTER, rvalue, span);
         self.source.promoted.push(self.promoted);
     }
 }
@@ -330,8 +341,10 @@ fn visit_lvalue(&mut self,
                     lvalue: &mut Lvalue<'tcx>,
                     context: LvalueContext<'tcx>,
                     location: Location) {
-        if let Lvalue::Temp(ref mut temp) = *lvalue {
-            *temp = self.promote_temp(*temp);
+        if let Lvalue::Local(ref mut temp) = *lvalue {
+            if self.source.local_kind(*temp) == LocalKind::Temp {
+                *temp = self.promote_temp(*temp);
+            }
         }
         self.super_lvalue(lvalue, context, location);
     }
@@ -339,7 +352,7 @@ fn visit_lvalue(&mut self,
 
 pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                    mut temps: IndexVec<Temp, TempState>,
+                                    mut temps: IndexVec<Local, TempState>,
                                     candidates: Vec<Candidate>) {
     // Visit candidates in reverse, in case they're nested.
     for candidate in candidates.into_iter().rev() {
@@ -353,7 +366,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                                   "expected assignment to promote");
                     }
                 };
-                if let Lvalue::Temp(index) = *dest {
+                if let Lvalue::Local(index) = *dest {
                     if temps[index] == TempState::PromotedOut {
                         // Already promoted.
                         continue;
@@ -376,8 +389,10 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
             }
         };
 
+        // Declare return pointer local
+        let initial_locals = iter::once(LocalDecl::new_return_pointer(ty)).collect();
+
         let mut promoter = Promoter {
-            source: mir,
             promoted: Mir::new(
                 IndexVec::new(),
                 Some(VisibilityScopeData {
@@ -386,12 +401,12 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                 }).into_iter().collect(),
                 IndexVec::new(),
                 ty,
-                IndexVec::new(),
-                IndexVec::new(),
-                IndexVec::new(),
+                initial_locals,
+                0,
                 vec![],
                 span
             ),
+            source: mir,
             temps: &mut temps,
             keep_original: false
         };
@@ -400,13 +415,13 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
     }
 
     // Eliminate assignments to, and drops of promoted temps.
-    let promoted = |index: Temp| temps[index] == TempState::PromotedOut;
+    let promoted = |index: Local| temps[index] == TempState::PromotedOut;
     for block in mir.basic_blocks_mut() {
         block.statements.retain(|statement| {
             match statement.kind {
-                StatementKind::Assign(Lvalue::Temp(index), _) |
-                StatementKind::StorageLive(Lvalue::Temp(index)) |
-                StatementKind::StorageDead(Lvalue::Temp(index)) => {
+                StatementKind::Assign(Lvalue::Local(index), _) |
+                StatementKind::StorageLive(Lvalue::Local(index)) |
+                StatementKind::StorageDead(Lvalue::Local(index)) => {
                     !promoted(index)
                 }
                 _ => true
@@ -414,7 +429,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
         });
         let terminator = block.terminator_mut();
         match terminator.kind {
-            TerminatorKind::Drop { location: Lvalue::Temp(index), target, .. } => {
+            TerminatorKind::Drop { location: Lvalue::Local(index), target, .. } => {
                 if promoted(index) {
                     terminator.kind = TerminatorKind::Goto {
                         target: target
index 2c03af2c8e97a93d67fa655683e662e0c38afa80..b00a88093d72655f5364a5c5f02daa12750d5fb2 100644 (file)
@@ -143,11 +143,11 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     param_env: ty::ParameterEnvironment<'tcx>,
     qualif_map: &'a mut DefIdMap<Qualif>,
     mir_map: Option<&'a MirMap<'tcx>>,
-    temp_qualif: IndexVec<Temp, Option<Qualif>>,
+    temp_qualif: IndexVec<Local, Option<Qualif>>,
     return_qualif: Option<Qualif>,
     qualif: Qualif,
     const_fn_arg_vars: BitVector,
-    temp_promotion_state: IndexVec<Temp, TempState>,
+    temp_promotion_state: IndexVec<Local, TempState>,
     promotion_candidates: Vec<Candidate>
 }
 
@@ -173,10 +173,10 @@ fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             param_env: param_env,
             qualif_map: qualif_map,
             mir_map: mir_map,
-            temp_qualif: IndexVec::from_elem(None, &mir.temp_decls),
+            temp_qualif: IndexVec::from_elem(None, &mir.local_decls),
             return_qualif: None,
             qualif: Qualif::empty(),
-            const_fn_arg_vars: BitVector::new(mir.var_decls.len()),
+            const_fn_arg_vars: BitVector::new(mir.local_decls.len()),
             temp_promotion_state: temps,
             promotion_candidates: vec![]
         }
@@ -332,8 +332,10 @@ fn assign(&mut self, dest: &Lvalue<'tcx>, location: Location) {
 
         // Only handle promotable temps in non-const functions.
         if self.mode == Mode::Fn {
-            if let Lvalue::Temp(index) = *dest {
-                if self.temp_promotion_state[index].is_promotable() {
+            if let Lvalue::Local(index) = *dest {
+                if self.mir.local_kind(index) == LocalKind::Temp
+                && self.temp_promotion_state[index].is_promotable() {
+                    debug!("store to promotable temp {:?}", index);
                     store(&mut self.temp_qualif[index]);
                 }
             }
@@ -341,13 +343,20 @@ fn assign(&mut self, dest: &Lvalue<'tcx>, location: Location) {
         }
 
         match *dest {
-            Lvalue::Temp(index) => store(&mut self.temp_qualif[index]),
-            Lvalue::ReturnPointer => store(&mut self.return_qualif),
+            Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::Temp => {
+                debug!("store to temp {:?}", index);
+                store(&mut self.temp_qualif[index])
+            }
+            Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::ReturnPointer => {
+                debug!("store to return pointer {:?}", index);
+                store(&mut self.return_qualif)
+            }
 
             Lvalue::Projection(box Projection {
-                base: Lvalue::Temp(index),
+                base: Lvalue::Local(index),
                 elem: ProjectionElem::Deref
-            }) if self.mir.temp_decls[index].ty.is_unique()
+            }) if self.mir.local_kind(index) == LocalKind::Temp
+               && self.mir.local_decls[index].ty.is_unique()
                && self.temp_qualif[index].map_or(false, |qualif| {
                     qualif.intersects(Qualif::NOT_CONST)
                }) => {
@@ -366,6 +375,8 @@ fn assign(&mut self, dest: &Lvalue<'tcx>, location: Location) {
 
     /// Qualify a whole const, static initializer or const fn.
     fn qualify_const(&mut self) -> Qualif {
+        debug!("qualifying {} {}", self.mode, self.tcx.item_path_str(self.def_id));
+
         let mir = self.mir;
 
         let mut seen_blocks = BitVector::new(mir.basic_blocks().len());
@@ -399,7 +410,7 @@ fn qualify_const(&mut self) -> Qualif {
                 TerminatorKind::Return => {
                     // Check for unused values. This usually means
                     // there are extra statements in the AST.
-                    for temp in mir.temp_decls.indices() {
+                    for temp in mir.temps_iter() {
                         if self.temp_qualif[temp].is_none() {
                             continue;
                         }
@@ -424,9 +435,10 @@ fn qualify_const(&mut self) -> Qualif {
 
                     // Make sure there are no extra unassigned variables.
                     self.qualif = Qualif::NOT_CONST;
-                    for index in 0..mir.var_decls.len() {
-                        if !self.const_fn_arg_vars.contains(index) {
-                            self.assign(&Lvalue::Var(Var::new(index)), Location {
+                    for index in mir.vars_iter() {
+                        if !self.const_fn_arg_vars.contains(index.index()) {
+                            debug!("unassigned variable {:?}", index);
+                            self.assign(&Lvalue::Local(index), Location {
                                 block: bb,
                                 statement_index: usize::MAX,
                             });
@@ -480,23 +492,28 @@ fn visit_lvalue(&mut self,
                     context: LvalueContext<'tcx>,
                     location: Location) {
         match *lvalue {
-            Lvalue::Arg(_) => {
-                self.add(Qualif::FN_ARGUMENT);
-            }
-            Lvalue::Var(_) => {
-                self.add(Qualif::NOT_CONST);
-            }
-            Lvalue::Temp(index) => {
-                if !self.temp_promotion_state[index].is_promotable() {
-                    self.add(Qualif::NOT_PROMOTABLE);
+            Lvalue::Local(local) => match self.mir.local_kind(local) {
+                LocalKind::ReturnPointer => {
+                    self.not_const();
+                }
+                LocalKind::Arg => {
+                    self.add(Qualif::FN_ARGUMENT);
+                }
+                LocalKind::Var => {
+                    self.add(Qualif::NOT_CONST);
                 }
+                LocalKind::Temp => {
+                    if !self.temp_promotion_state[local].is_promotable() {
+                        self.add(Qualif::NOT_PROMOTABLE);
+                    }
 
-                if let Some(qualif) = self.temp_qualif[index] {
-                    self.add(qualif);
-                } else {
-                    self.not_const();
+                    if let Some(qualif) = self.temp_qualif[local] {
+                        self.add(qualif);
+                    } else {
+                        self.not_const();
+                    }
                 }
-            }
+            },
             Lvalue::Static(_) => {
                 self.add(Qualif::STATIC);
                 if self.mode == Mode::Const || self.mode == Mode::ConstFn {
@@ -505,9 +522,6 @@ fn visit_lvalue(&mut self,
                                a constant instead", self.mode);
                 }
             }
-            Lvalue::ReturnPointer => {
-                self.not_const();
-            }
             Lvalue::Projection(ref proj) => {
                 self.nest(|this| {
                     this.super_lvalue(lvalue, context, location);
@@ -685,8 +699,10 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                 if self.mode == Mode::Fn || self.mode == Mode::ConstFn {
                     if !self.qualif.intersects(Qualif::NEVER_PROMOTE) {
                         // We can only promote direct borrows of temps.
-                        if let Lvalue::Temp(_) = *lvalue {
-                            self.promotion_candidates.push(candidate);
+                        if let Lvalue::Local(local) = *lvalue {
+                            if self.mir.local_kind(local) == LocalKind::Temp {
+                                self.promotion_candidates.push(candidate);
+                            }
                         }
                     }
                 }
@@ -879,17 +895,21 @@ fn visit_assign(&mut self,
         self.visit_rvalue(rvalue, location);
 
         // Check the allowed const fn argument forms.
-        if let (Mode::ConstFn, &Lvalue::Var(index)) = (self.mode, dest) {
-            if self.const_fn_arg_vars.insert(index.index()) {
+        if let (Mode::ConstFn, &Lvalue::Local(index)) = (self.mode, dest) {
+            if self.mir.local_kind(index) == LocalKind::Var &&
+               self.const_fn_arg_vars.insert(index.index()) {
+
                 // Direct use of an argument is permitted.
-                if let Rvalue::Use(Operand::Consume(Lvalue::Arg(_))) = *rvalue {
-                    return;
+                if let Rvalue::Use(Operand::Consume(Lvalue::Local(local))) = *rvalue {
+                    if self.mir.local_kind(local) == LocalKind::Arg {
+                        return;
+                    }
                 }
 
                 // Avoid a generic error for other uses of arguments.
                 if self.qualif.intersects(Qualif::FN_ARGUMENT) {
-                    let decl = &self.mir.var_decls[index];
-                    span_err!(self.tcx.sess, decl.source_info.span, E0022,
+                    let decl = &self.mir.local_decls[index];
+                    span_err!(self.tcx.sess, decl.source_info.unwrap().span, E0022,
                               "arguments of constant functions can only \
                                be immutable by-value bindings");
                     return;
index 7b6a2f5580819c98ddce4ee4265185aeb3ada921..7a6822924295431230d4022c33797d0ab3453d1f 100644 (file)
@@ -90,14 +90,8 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
 
     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
         self.sanitize_type(&"return type", mir.return_ty);
-        for var_decl in &mir.var_decls {
-            self.sanitize_type(var_decl, var_decl.ty);
-        }
-        for (n, arg_decl) in mir.arg_decls.iter().enumerate() {
-            self.sanitize_type(&(n, arg_decl), arg_decl.ty);
-        }
-        for (n, tmp_decl) in mir.temp_decls.iter().enumerate() {
-            self.sanitize_type(&(n, tmp_decl), tmp_decl.ty);
+        for local_decl in &mir.local_decls {
+            self.sanitize_type(local_decl, local_decl.ty);
         }
         if self.errors_reported {
             return;
@@ -131,14 +125,9 @@ fn sanitize_type(&mut self, parent: &fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
     fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> {
         debug!("sanitize_lvalue: {:?}", lvalue);
         match *lvalue {
-            Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index].ty },
-            Lvalue::Temp(index) => LvalueTy::Ty { ty: self.mir.temp_decls[index].ty },
-            Lvalue::Arg(index) => LvalueTy::Ty { ty: self.mir.arg_decls[index].ty },
+            Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty },
             Lvalue::Static(def_id) =>
                 LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty },
-            Lvalue::ReturnPointer => {
-                LvalueTy::Ty { ty: self.mir.return_ty }
-            }
             Lvalue::Projection(ref proj) => {
                 let base_ty = self.sanitize_lvalue(&proj.base, location);
                 if let LvalueTy::Ty { ty } = base_ty {
@@ -380,9 +369,9 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>) {
             StatementKind::StorageLive(ref lv) |
             StatementKind::StorageDead(ref lv) => {
                 match *lv {
-                    Lvalue::Temp(_) | Lvalue::Var(_) => {}
+                    Lvalue::Local(_) => {}
                     _ => {
-                        span_mirbug!(self, stmt, "bad lvalue: expected temp or var");
+                        span_mirbug!(self, stmt, "bad lvalue: expected local");
                     }
                 }
             }
@@ -711,6 +700,8 @@ pub fn new() -> Self {
 impl<'tcx> MirPass<'tcx> for TypeckMir {
     fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     src: MirSource, mir: &mut Mir<'tcx>) {
+        debug!("run_pass: {}", tcx.node_path_str(src.item_id()));
+
         if tcx.sess.err_count() > 0 {
             // compiling a broken program can obviously result in a
             // broken MIR, so try not to report duplicate errors.
index 6275639a9adfff9649c41192389deb2e76f5ae2c..5096a574e2ba59419b06b6b14c86b9bc6119e1c9 100644 (file)
@@ -53,8 +53,11 @@ fn invalid_visibility(&self, vis: &Visibility, span: Span, note: Option<&str>) {
                                            span,
                                            E0449,
                                            "unnecessary visibility qualifier");
+            if vis == &Visibility::Public {
+                err.span_label(span, &format!("`pub` not needed here"));
+            }
             if let Some(note) = note {
-                err.span_note(span, note);
+                err.note(note);
             }
             err.emit();
         }
index f919e42b6bd7d38d6de6f483f002192ee80ae70f..1b86c84a057026f324769d04ee6405a3d06962a3 100644 (file)
@@ -602,7 +602,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
         hir::ExprIndex(..) |
         hir::ExprField(..) |
         hir::ExprTupField(..) |
-        hir::ExprVec(_) |
+        hir::ExprArray(_) |
         hir::ExprType(..) |
         hir::ExprTup(..) => {}
 
index 0ab8e2d7fcd2812b50e8740fcf687c18629670b0..0336c3063d83f69c0ec63315be60e62a17b745b4 100644 (file)
@@ -143,7 +143,7 @@ fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F, span: Span)
             });
             if any_static {
                 if !self.sess.features.borrow().static_recursion {
-                    emit_feature_err(&self.sess.parse_sess.span_diagnostic,
+                    emit_feature_err(&self.sess.parse_sess,
                                      "static_recursion",
                                      *self.root_span,
                                      GateIssue::Language,
index 1b119fd008509c61ed7f8c2bf8f982b12c94f16e..43cdf2942d23068a280f18f255d03e6d3150d676 100644 (file)
@@ -972,8 +972,10 @@ fn visit_ty(&mut self, ty: &hir::Ty) {
                         if !vis.is_at_least(self.required_visibility, &self.tcx.map) {
                             if self.tcx.sess.features.borrow().pub_restricted ||
                                self.old_error_set.contains(&ty.id) {
-                                span_err!(self.tcx.sess, ty.span, E0446,
+                                let mut err = struct_span_err!(self.tcx.sess, ty.span, E0446,
                                           "private type in public interface");
+                                err.span_label(ty.span, &format!("can't leak private type"));
+                                err.emit();
                             } else {
                                 self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
                                                        node_id,
index 9202f8c0946f47e3ebb2a5c4c1ed6769e1f00e7a..2bf517600b73d693321e6487886a20167ab5a5e0 100644 (file)
@@ -13,6 +13,7 @@
 //! Here we build the "reduced graph": the graph of the module tree without
 //! any imports resolved.
 
+use macros;
 use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
 use {Module, ModuleS, ModuleKind};
 use Namespace::{self, TypeNS, ValueNS};
 use Resolver;
 use {resolve_error, resolve_struct_error, ResolutionError};
 
+use rustc::middle::cstore::LoadedMacroKind;
 use rustc::hir::def::*;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::hir::map::DefPathData;
 use rustc::ty;
 
 use std::cell::Cell;
+use std::rc::Rc;
 
 use syntax::ast::Name;
 use syntax::attr;
 use syntax::parse::token;
 
-use syntax::ast::{Block, Crate};
-use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind};
+use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind};
 use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind};
 use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
+use syntax::ext::base::{MultiItemModifier, Resolver as SyntaxResolver};
+use syntax::ext::hygiene::Mark;
+use syntax::feature_gate::{self, emit_feature_err};
+use syntax::ext::tt::macro_rules;
 use syntax::parse::token::keywords;
 use syntax::visit::{self, Visitor};
 
@@ -53,11 +59,6 @@ fn to_name_binding(self) -> NameBinding<'a> {
 }
 
 impl<'b> Resolver<'b> {
-    /// Constructs the reduced graph for the entire crate.
-    pub fn build_reduced_graph(&mut self, krate: &Crate) {
-        visit::walk_crate(&mut BuildReducedGraphVisitor { resolver: self }, krate);
-    }
-
     /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
     /// otherwise, reports an error.
     fn define<T>(&mut self, parent: Module<'b>, name: Name, ns: Namespace, def: T)
@@ -72,15 +73,13 @@ fn define<T>(&mut self, parent: Module<'b>, name: Name, ns: Namespace, def: T)
     fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
         // If any statements are items, we need to create an anonymous module
         block.stmts.iter().any(|statement| match statement.node {
-            StmtKind::Item(_) => true,
+            StmtKind::Item(_) | StmtKind::Mac(_) => true,
             _ => false,
         })
     }
 
     /// Constructs the reduced graph for one item.
-    fn build_reduced_graph_for_item(&mut self, item: &Item) {
-        self.crate_loader.process_item(item, &self.definitions);
-
+    fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
         let parent = self.current_module;
         let name = item.ident.name;
         let sp = item.span;
@@ -188,8 +187,39 @@ fn build_reduced_graph_for_item(&mut self, item: &Item) {
             }
 
             ItemKind::ExternCrate(_) => {
-                // n.b. we don't need to look at the path option here, because cstore already
-                // did
+                // We need to error on `#[macro_use] extern crate` when it isn't at the
+                // crate root, because `$crate` won't work properly.
+                let is_crate_root = self.current_module.parent.is_none();
+                for loaded_macro in self.crate_loader.load_macros(item, is_crate_root) {
+                    match loaded_macro.kind {
+                        LoadedMacroKind::Def(mut def) => {
+                            let name = def.ident.name;
+                            if def.use_locally {
+                                let ext = macro_rules::compile(&self.session.parse_sess, &def);
+                                let shadowing =
+                                    self.resolve_macro_name(Mark::root(), name, false).is_some();
+                                self.expansion_data[&Mark::root()].module.macros.borrow_mut()
+                                    .insert(name, macros::NameBinding {
+                                        ext: Rc::new(ext),
+                                        expansion: expansion,
+                                        shadowing: shadowing,
+                                        span: loaded_macro.import_site,
+                                    });
+                                self.macro_names.insert(name);
+                            }
+                            if def.export {
+                                def.id = self.next_node_id();
+                                self.exported_macros.push(def);
+                            }
+                        }
+                        LoadedMacroKind::CustomDerive(name, ext) => {
+                            self.insert_custom_derive(&name, ext, item.span);
+                        }
+                    }
+                }
+                self.crate_loader.process_item(item, &self.definitions);
+
+                // n.b. we don't need to look at the path option here, because cstore already did
                 if let Some(crate_id) = self.session.cstore.extern_mod_stmt_cnum(item.id) {
                     let def_id = DefId {
                         krate: crate_id,
@@ -206,6 +236,8 @@ fn build_reduced_graph_for_item(&mut self, item: &Item) {
                 }
             }
 
+            ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
+
             ItemKind::Mod(..) => {
                 let def = Def::Mod(self.definitions.local_def_id(item.id));
                 let module = self.arenas.alloc_module(ModuleS {
@@ -213,6 +245,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item) {
                         attr::contains_name(&item.attrs, "no_implicit_prelude")
                     },
                     normal_ancestor_id: Some(item.id),
+                    macros_escape: self.contains_macro_use(&item.attrs),
                     ..ModuleS::new(Some(parent), ModuleKind::Def(def, name))
                 });
                 self.define(parent, name, TypeNS, (module, sp, vis));
@@ -222,7 +255,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item) {
                 self.current_module = module;
             }
 
-            ItemKind::ForeignMod(..) => {}
+            ItemKind::ForeignMod(..) => self.crate_loader.process_item(item, &self.definitions),
 
             // These items live in the value namespace.
             ItemKind::Static(_, m, _) => {
@@ -476,22 +509,89 @@ pub fn populate_module_if_necessary(&mut self, module: Module<'b>) {
         }
         module.populated.set(true)
     }
+
+    // does this attribute list contain "macro_use"?
+    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
+        for attr in attrs {
+            if attr.check_name("macro_escape") {
+                let msg = "macro_escape is a deprecated synonym for macro_use";
+                let mut err = self.session.struct_span_warn(attr.span, msg);
+                if let ast::AttrStyle::Inner = attr.node.style {
+                    err.help("consider an outer attribute, #[macro_use] mod ...").emit();
+                } else {
+                    err.emit();
+                }
+            } else if !attr.check_name("macro_use") {
+                continue;
+            }
+
+            if !attr.is_word() {
+                self.session.span_err(attr.span, "arguments to macro_use are not allowed here");
+            }
+            return true;
+        }
+
+        false
+    }
+
+    fn insert_custom_derive(&mut self, name: &str, ext: Rc<MultiItemModifier>, sp: Span) {
+        if !self.session.features.borrow().rustc_macro {
+            let sess = &self.session.parse_sess;
+            let msg = "loading custom derive macro crates is experimentally supported";
+            emit_feature_err(sess, "rustc_macro", sp, feature_gate::GateIssue::Language, msg);
+        }
+        if self.derive_modes.insert(token::intern(name), ext).is_some() {
+            self.session.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
+        }
+    }
 }
 
-struct BuildReducedGraphVisitor<'a, 'b: 'a> {
-    resolver: &'a mut Resolver<'b>,
+pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
+    pub resolver: &'a mut Resolver<'b>,
+    pub expansion: Mark,
+}
+
+impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
+    fn visit_invoc(&mut self, id: ast::NodeId) {
+        self.resolver.expansion_data.get_mut(&Mark::from_placeholder_id(id)).unwrap().module =
+            self.resolver.current_module;
+    }
+}
+
+macro_rules! method {
+    ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
+        fn $visit(&mut self, node: &$ty) {
+            match node.node {
+                $invoc(..) => self.visit_invoc(node.id),
+                _ => visit::$walk(self, node),
+            }
+        }
+    }
 }
 
 impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
+    method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
+    method!(visit_stmt:      ast::Stmt,     ast::StmtKind::Mac,       walk_stmt);
+    method!(visit_expr:      ast::Expr,     ast::ExprKind::Mac,       walk_expr);
+    method!(visit_pat:       ast::Pat,      ast::PatKind::Mac,        walk_pat);
+    method!(visit_ty:        ast::Ty,       ast::TyKind::Mac,         walk_ty);
+
     fn visit_item(&mut self, item: &Item) {
+        match item.node {
+            ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => return, // Scope placeholder
+            ItemKind::Mac(..) => return self.visit_invoc(item.id),
+            _ => {}
+        }
+
         let parent = self.resolver.current_module;
-        self.resolver.build_reduced_graph_for_item(item);
+        self.resolver.build_reduced_graph_for_item(item, self.expansion);
         visit::walk_item(self, item);
         self.resolver.current_module = parent;
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
         self.resolver.build_reduced_graph_for_foreign_item(foreign_item);
+        visit::walk_foreign_item(self, foreign_item);
     }
 
     fn visit_block(&mut self, block: &Block) {
@@ -515,7 +615,7 @@ fn visit_trait_item(&mut self, item: &TraitItem) {
                 (Def::Method(item_def_id), ValueNS)
             }
             TraitItemKind::Type(..) => (Def::AssociatedTy(item_def_id), TypeNS),
-            TraitItemKind::Macro(_) => panic!("unexpanded macro in resolve!"),
+            TraitItemKind::Macro(_) => return self.visit_invoc(item.id),
         };
 
         self.resolver.trait_item_map.insert((item.ident.name, def_id), is_static_method);
index fb9819b72ab3e43b40bcb9fc86c14cc2acbdee52..90a9e5960617e65d6e41e8bc797e704232ce29a0 100644 (file)
@@ -42,7 +42,7 @@
 use self::UseLexicalScopeFlag::*;
 use self::ModulePrefixResult::*;
 
-use rustc::hir::map::Definitions;
+use rustc::hir::map::{Definitions, DefCollector};
 use rustc::hir::{self, PrimTy, TyBool, TyChar, TyFloat, TyInt, TyUint, TyStr};
 use rustc::middle::cstore::CrateLoader;
 use rustc::session::Session;
@@ -72,9 +72,9 @@
 use errors::DiagnosticBuilder;
 
 use std::cell::{Cell, RefCell};
-use std::rc::Rc;
 use std::fmt;
 use std::mem::replace;
+use std::rc::Rc;
 
 use resolve_imports::{ImportDirective, NameResolution};
 
@@ -366,9 +366,14 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
             let mut err = struct_span_err!(resolver.session,
                                            span,
                                            E0425,
-                                           "unresolved name `{}`{}",
-                                           path,
-                                           msg);
+                                           "unresolved name `{}`",
+                                           path);
+            if msg != "" {
+                err.span_label(span, &msg);
+            } else {
+                err.span_label(span, &format!("unresolved name"));
+            }
+
             match context {
                 UnresolvedNameContext::Other => {
                     if msg.is_empty() && is_static_method && is_field {
@@ -786,6 +791,9 @@ pub struct ModuleS<'a> {
     // access the children must be preceded with a
     // `populate_module_if_necessary` call.
     populated: Cell<bool>,
+
+    macros: RefCell<FnvHashMap<Name, macros::NameBinding>>,
+    macros_escape: bool,
 }
 
 pub type Module<'a> = &'a ModuleS<'a>;
@@ -803,6 +811,8 @@ fn new(parent: Option<Module<'a>>, kind: ModuleKind) -> Self {
             globs: RefCell::new((Vec::new())),
             traits: RefCell::new(None),
             populated: Cell::new(true),
+            macros: RefCell::new(FnvHashMap()),
+            macros_escape: false,
         }
     }
 
@@ -1063,6 +1073,7 @@ pub struct Resolver<'a> {
 
     privacy_errors: Vec<PrivacyError<'a>>,
     ambiguity_errors: Vec<AmbiguityError<'a>>,
+    macro_shadowing_errors: FnvHashSet<Span>,
 
     arenas: &'a ResolverArenas<'a>,
     dummy_binding: &'a NameBinding<'a>,
@@ -1074,7 +1085,7 @@ pub struct Resolver<'a> {
     macro_names: FnvHashSet<Name>,
 
     // Maps the `Mark` of an expansion to its containing module or block.
-    expansion_data: FnvHashMap<u32, macros::ExpansionData>,
+    expansion_data: FnvHashMap<Mark, macros::ExpansionData<'a>>,
 }
 
 pub struct ResolverArenas<'a> {
@@ -1188,13 +1199,16 @@ pub fn new(session: &'a Session,
         let mut module_map = NodeMap();
         module_map.insert(CRATE_NODE_ID, graph_root);
 
+        let mut definitions = Definitions::new();
+        DefCollector::new(&mut definitions).collect_root();
+
         let mut expansion_data = FnvHashMap();
-        expansion_data.insert(0, macros::ExpansionData::default()); // Crate root expansion
+        expansion_data.insert(Mark::root(), macros::ExpansionData::root(graph_root));
 
         Resolver {
             session: session,
 
-            definitions: Definitions::new(),
+            definitions: definitions,
             macros_at_scope: FnvHashMap(),
 
             // The outermost module has def ID 0; this is not reflected in the
@@ -1235,6 +1249,7 @@ pub fn new(session: &'a Session,
 
             privacy_errors: Vec::new(),
             ambiguity_errors: Vec::new(),
+            macro_shadowing_errors: FnvHashSet(),
 
             arenas: arenas,
             dummy_binding: arenas.alloc_name_binding(NameBinding {
@@ -1264,6 +1279,13 @@ pub fn arenas() -> ResolverArenas<'a> {
 
     /// Entry point to crate resolution.
     pub fn resolve_crate(&mut self, krate: &Crate) {
+        // Collect `DefId`s for exported macro defs.
+        for def in &krate.exported_macros {
+            DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| {
+                collector.visit_macro_def(def)
+            })
+        }
+
         self.current_module = self.graph_root;
         visit::walk_crate(self, krate);
 
@@ -2941,7 +2963,7 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
                                 let mut context =  UnresolvedNameContext::Other;
                                 let mut def = Def::Err;
                                 if !msg.is_empty() {
-                                    msg = format!(". Did you mean {}?", msg);
+                                    msg = format!("did you mean {}?", msg);
                                 } else {
                                     // we display a help message if this is a module
                                     let name_path = path.segments.iter()
@@ -3513,7 +3535,7 @@ fn collect_mod(names: &mut Vec<ast::Name>, module: Module) {
         } else {
             // danger, shouldn't be ident?
             names.push(token::intern("<opaque>"));
-            collect_mod(names, module);
+            collect_mod(names, module.parent.unwrap());
         }
     }
     collect_mod(&mut names, module);
index 292669c592afed162a6954a58b47eb3de8446081..3f6c69278bee8a2ec91472228925a01d262f4909 100644 (file)
@@ -8,36 +8,49 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use Resolver;
-use rustc::middle::cstore::LoadedMacro;
-use rustc::util::nodemap::FnvHashMap;
-use std::cell::RefCell;
-use std::mem;
+use {Module, Resolver};
+use build_reduced_graph::BuildReducedGraphVisitor;
+use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex};
+use rustc::hir::map::{self, DefCollector};
 use std::rc::Rc;
-use syntax::ast::{self, Name};
+use syntax::ast;
 use syntax::errors::DiagnosticBuilder;
 use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier};
-use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
+use syntax::ext::base::{NormalTT, SyntaxExtension};
 use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
-use syntax::ext::hygiene::Mark;
+use syntax::ext::hygiene::{Mark, SyntaxContext};
 use syntax::ext::tt::macro_rules;
-use syntax::feature_gate::{self, emit_feature_err};
-use syntax::parse::token::{self, intern};
+use syntax::parse::token::intern;
 use syntax::util::lev_distance::find_best_match_for_name;
-use syntax::visit::{self, Visitor};
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
+
+// FIXME(jseyfried) Merge with `::NameBinding`.
+pub struct NameBinding {
+    pub ext: Rc<SyntaxExtension>,
+    pub expansion: Mark,
+    pub shadowing: bool,
+    pub span: Span,
+}
 
-#[derive(Clone, Default)]
-pub struct ExpansionData {
-    module: Rc<ModuleData>,
+#[derive(Clone)]
+pub struct ExpansionData<'a> {
+    backtrace: SyntaxContext,
+    pub module: Module<'a>,
+    def_index: DefIndex,
+    // True if this expansion is in a `const_integer` position, for example `[u32; m!()]`.
+    // c.f. `DefCollector::visit_ast_const_integer`.
+    const_integer: bool,
 }
 
-// FIXME(jseyfried): merge with `::ModuleS`.
-#[derive(Default)]
-struct ModuleData {
-    parent: Option<Rc<ModuleData>>,
-    macros: RefCell<FnvHashMap<Name, Rc<SyntaxExtension>>>,
-    macros_escape: bool,
+impl<'a> ExpansionData<'a> {
+    pub fn root(graph_root: Module<'a>) -> Self {
+        ExpansionData {
+            backtrace: SyntaxContext::empty(),
+            module: graph_root,
+            def_index: CRATE_DEF_INDEX,
+            const_integer: false,
+        }
+    }
 }
 
 impl<'a> base::Resolver for Resolver<'a> {
@@ -45,11 +58,22 @@ fn next_node_id(&mut self) -> ast::NodeId {
         self.session.next_node_id()
     }
 
-    fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
-        expansion.visit_with(&mut ExpansionVisitor {
-            current_module: self.expansion_data[&mark.as_u32()].module.clone(),
-            resolver: self,
+    fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
+        let mark = Mark::fresh();
+        let module = self.module_map[&id];
+        self.expansion_data.insert(mark, ExpansionData {
+            backtrace: SyntaxContext::empty(),
+            module: module,
+            def_index: module.def_id().unwrap().index,
+            const_integer: false,
         });
+        mark
+    }
+
+    fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
+        self.collect_def_ids(mark, expansion);
+        self.current_module = self.expansion_data[&mark].module;
+        expansion.visit_with(&mut BuildReducedGraphVisitor { resolver: self, expansion: mark });
     }
 
     fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
@@ -57,8 +81,18 @@ fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
             self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
         }
         if def.use_locally {
-            let ext = macro_rules::compile(&self.session.parse_sess, &def);
-            self.add_ext(scope, def.ident, Rc::new(ext));
+            let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope];
+            while module.macros_escape {
+                module = module.parent.unwrap();
+            }
+            let binding = NameBinding {
+                ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
+                expansion: backtrace.data().prev_ctxt.data().outer_mark,
+                shadowing: self.resolve_macro_name(scope, def.ident.name, false).is_some(),
+                span: def.span,
+            };
+            module.macros.borrow_mut().insert(def.ident.name, binding);
+            self.macro_names.insert(def.ident.name);
         }
         if def.export {
             def.id = self.next_node_id();
@@ -66,16 +100,16 @@ fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
         }
     }
 
-    fn add_ext(&mut self, scope: Mark, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
+    fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
         if let NormalTT(..) = *ext {
             self.macro_names.insert(ident.name);
         }
-
-        let mut module = self.expansion_data[&scope.as_u32()].module.clone();
-        while module.macros_escape {
-            module = module.parent.clone().unwrap();
-        }
-        module.macros.borrow_mut().insert(ident.name, ext);
+        self.graph_root.macros.borrow_mut().insert(ident.name, NameBinding {
+            ext: ext,
+            expansion: Mark::root(),
+            shadowing: false,
+            span: DUMMY_SP,
+        });
     }
 
     fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
@@ -85,8 +119,8 @@ fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
     fn find_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
         for i in 0..attrs.len() {
             let name = intern(&attrs[i].name());
-            match self.expansion_data[&0].module.macros.borrow().get(&name) {
-                Some(ext) => match **ext {
+            match self.expansion_data[&Mark::root()].module.macros.borrow().get(&name) {
+                Some(binding) => match *binding.ext {
                     MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
                         return Some(attrs.remove(i))
                     }
@@ -113,22 +147,13 @@ fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<Syntax
             InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
         };
 
-        let mut module = self.expansion_data[&scope.as_u32()].module.clone();
-        loop {
-            if let Some(ext) = module.macros.borrow().get(&name) {
-                return Some(ext.clone());
-            }
-            match module.parent.clone() {
-                Some(parent) => module = parent,
-                None => break,
-            }
-        }
-
-        let mut err =
-            self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
-        self.suggest_macro_name(&name.as_str(), &mut err);
-        err.emit();
-        None
+        self.resolve_macro_name(scope, name, true).or_else(|| {
+            let mut err =
+                self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
+            self.suggest_macro_name(&name.as_str(), &mut err);
+            err.emit();
+            None
+        })
     }
 
     fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>> {
@@ -137,126 +162,69 @@ fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModif
 }
 
 impl<'a> Resolver<'a> {
-    fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
-        if let Some(suggestion) = find_best_match_for_name(self.macro_names.iter(), name, None) {
-            if suggestion != name {
-                err.help(&format!("did you mean `{}!`?", suggestion));
-            } else {
-                err.help(&format!("have you added the `#[macro_use]` on the module/import?"));
-            }
-        }
-    }
-
-    fn insert_custom_derive(&mut self, name: &str, ext: Rc<MultiItemModifier>, sp: Span) {
-        if !self.session.features.borrow().rustc_macro {
-            let diagnostic = &self.session.parse_sess.span_diagnostic;
-            let msg = "loading custom derive macro crates is experimentally supported";
-            emit_feature_err(diagnostic, "rustc_macro", sp, feature_gate::GateIssue::Language, msg);
-        }
-        if self.derive_modes.insert(token::intern(name), ext).is_some() {
-            self.session.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
-        }
-    }
-}
-
-struct ExpansionVisitor<'b, 'a: 'b> {
-    resolver: &'b mut Resolver<'a>,
-    current_module: Rc<ModuleData>,
-}
-
-impl<'a, 'b> ExpansionVisitor<'a, 'b> {
-    fn visit_invoc(&mut self, id: ast::NodeId) {
-        self.resolver.expansion_data.insert(id.as_u32(), ExpansionData {
-            module: self.current_module.clone(),
-        });
-    }
+    pub fn resolve_macro_name(&mut self, scope: Mark, name: ast::Name, record_used: bool)
+                              -> Option<Rc<SyntaxExtension>> {
+        let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope];
+        loop {
+            if let Some(binding) = module.macros.borrow().get(&name) {
+                let mut backtrace = backtrace.data();
+                while binding.expansion != backtrace.outer_mark {
+                    if backtrace.outer_mark != Mark::root() {
+                        backtrace = backtrace.prev_ctxt.data();
+                        continue
+                    }
 
-    // does this attribute list contain "macro_use"?
-    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
-        for attr in attrs {
-            if attr.check_name("macro_escape") {
-                let msg = "macro_escape is a deprecated synonym for macro_use";
-                let mut err = self.resolver.session.struct_span_warn(attr.span, msg);
-                if let ast::AttrStyle::Inner = attr.node.style {
-                    err.help("consider an outer attribute, #[macro_use] mod ...").emit();
-                } else {
-                    err.emit();
+                    if record_used && binding.shadowing &&
+                       self.macro_shadowing_errors.insert(binding.span) {
+                        let msg = format!("`{}` is already in scope", name);
+                        self.session.struct_span_err(binding.span, &msg)
+                            .note("macro-expanded `macro_rules!`s and `#[macro_use]`s \
+                                   may not shadow existing macros (see RFC 1560)")
+                            .emit();
+                    }
+                    break
                 }
-            } else if !attr.check_name("macro_use") {
-                continue;
+                return Some(binding.ext.clone());
             }
-
-            if !attr.is_word() {
-                self.resolver.session.span_err(attr.span,
-                                               "arguments to macro_use are not allowed here");
+            match module.parent {
+                Some(parent) => module = parent,
+                None => break,
             }
-            return true;
         }
-
-        false
+        None
     }
-}
 
-macro_rules! method {
-    ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
-        fn $visit(&mut self, node: &$ty) {
-            match node.node {
-                $invoc(..) => self.visit_invoc(node.id),
-                _ => visit::$walk(self, node),
+    fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
+        if let Some(suggestion) = find_best_match_for_name(self.macro_names.iter(), name, None) {
+            if suggestion != name {
+                err.help(&format!("did you mean `{}!`?", suggestion));
+            } else {
+                err.help(&format!("have you added the `#[macro_use]` on the module/import?"));
             }
         }
     }
-}
 
-impl<'a, 'b> Visitor for ExpansionVisitor<'a, 'b>  {
-    method!(visit_trait_item: ast::TraitItem, ast::TraitItemKind::Macro, walk_trait_item);
-    method!(visit_impl_item:  ast::ImplItem,  ast::ImplItemKind::Macro,  walk_impl_item);
-    method!(visit_stmt:       ast::Stmt,      ast::StmtKind::Mac,        walk_stmt);
-    method!(visit_expr:       ast::Expr,      ast::ExprKind::Mac,        walk_expr);
-    method!(visit_pat:        ast::Pat,       ast::PatKind::Mac,         walk_pat);
-    method!(visit_ty:         ast::Ty,        ast::TyKind::Mac,          walk_ty);
+    fn collect_def_ids(&mut self, mark: Mark, expansion: &Expansion) {
+        let expansion_data = &mut self.expansion_data;
+        let ExpansionData { backtrace, def_index, const_integer, module } = expansion_data[&mark];
+        let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| {
+            expansion_data.entry(invoc.mark).or_insert(ExpansionData {
+                backtrace: backtrace.apply_mark(invoc.mark),
+                def_index: invoc.def_index,
+                const_integer: invoc.const_integer,
+                module: module,
+            });
+        };
 
-    fn visit_item(&mut self, item: &ast::Item) {
-        match item.node {
-            ast::ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => {} // Scope placeholder
-            ast::ItemKind::Mac(..) => self.visit_invoc(item.id),
-            ast::ItemKind::Mod(..) => {
-                let module_data = ModuleData {
-                    parent: Some(self.current_module.clone()),
-                    macros: RefCell::new(FnvHashMap()),
-                    macros_escape: self.contains_macro_use(&item.attrs),
-                };
-                let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data));
-                visit::walk_item(self, item);
-                self.current_module = orig_module;
-            }
-            ast::ItemKind::ExternCrate(..) => {
-                // We need to error on `#[macro_use] extern crate` when it isn't at the
-                // crate root, because `$crate` won't work properly.
-                // FIXME(jseyfried): This will be nicer once `ModuleData` is merged with `ModuleS`.
-                let is_crate_root = self.current_module.parent.as_ref().unwrap().parent.is_none();
-                for def in self.resolver.crate_loader.load_macros(item, is_crate_root) {
-                    match def {
-                        LoadedMacro::Def(def) => self.resolver.add_macro(Mark::root(), def),
-                        LoadedMacro::CustomDerive(name, ext) => {
-                            self.resolver.insert_custom_derive(&name, ext, item.span);
-                        }
-                    }
+        let mut def_collector = DefCollector::new(&mut self.definitions);
+        def_collector.visit_macro_invoc = Some(visit_macro_invoc);
+        def_collector.with_parent(def_index, |def_collector| {
+            if const_integer {
+                if let Expansion::Expr(ref expr) = *expansion {
+                    def_collector.visit_ast_const_integer(expr);
                 }
-                visit::walk_item(self, item);
             }
-            _ => visit::walk_item(self, item),
-        }
-    }
-
-    fn visit_block(&mut self, block: &ast::Block) {
-        let module_data = ModuleData {
-            parent: Some(self.current_module.clone()),
-            macros: RefCell::new(FnvHashMap()),
-            macros_escape: false,
-        };
-        let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data));
-        visit::walk_block(self, block);
-        self.current_module = orig_module;
+            expansion.visit_with(def_collector)
+        });
     }
 }
index ba45b773c09f36915174a4c5078e5da9bcbf0ef7..1fc9c45de930647b9021aa88e75f6e6749819451 100644 (file)
@@ -683,9 +683,8 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResu
         };
 
         match (value_result, type_result) {
-            // With `#![feature(item_like_imports)]`, all namespaces
-            // must be re-exported with extra visibility for an error to occur.
-            (Ok(value_binding), Ok(type_binding)) if self.new_import_semantics => {
+            // All namespaces must be re-exported with extra visibility for an error to occur.
+            (Ok(value_binding), Ok(type_binding)) => {
                 let vis = directive.vis.get();
                 if !value_binding.pseudo_vis().is_at_least(vis, self) &&
                    !type_binding.pseudo_vis().is_at_least(vis, self) {
index 683ad76952a7e5a338e66e84e7438248c55146de..0a5b013c79ac21fbdc979244a6a11a98b8a922c7 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::{self, ValueRef};
+use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector};
 use base;
 use build::AllocaFcx;
 use common::{type_is_fat_ptr, BlockAndBuilder, C_uint};
@@ -519,6 +519,7 @@ pub fn adjust_for_abi<'a, 'tcx>(&mut self,
             "powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self),
             "s390x" => cabi_s390x::compute_abi_info(ccx, self),
             "asmjs" => cabi_asmjs::compute_abi_info(ccx, self),
+            "wasm32" => cabi_asmjs::compute_abi_info(ccx, self),
             a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
         }
 
@@ -598,3 +599,73 @@ pub fn apply_attrs_callsite(&self, callsite: ValueRef) {
         }
     }
 }
+
+pub fn align_up_to(off: usize, a: usize) -> usize {
+    return (off + a - 1) / a * a;
+}
+
+fn align(off: usize, ty: Type, pointer: usize) -> usize {
+    let a = ty_align(ty, pointer);
+    return align_up_to(off, a);
+}
+
+pub fn ty_align(ty: Type, pointer: usize) -> usize {
+    match ty.kind() {
+        Integer => ((ty.int_width() as usize) + 7) / 8,
+        Pointer => pointer,
+        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, pointer)))
+            }
+        }
+        Array => {
+            let elt = ty.element_type();
+            ty_align(elt, pointer)
+        }
+        Vector => {
+            let len = ty.vector_length();
+            let elt = ty.element_type();
+            ty_align(elt, pointer) * len
+        }
+        _ => bug!("ty_align: unhandled type")
+    }
+}
+
+pub fn ty_size(ty: Type, pointer: usize) -> usize {
+    match ty.kind() {
+        Integer => ((ty.int_width() as usize) + 7) / 8,
+        Pointer => pointer,
+        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, pointer))
+            } else {
+                let str_tys = ty.field_types();
+                let size = str_tys.iter().fold(0, |s, t| {
+                    align(s, *t, pointer) + ty_size(*t, pointer)
+                });
+                align(size, ty, pointer)
+            }
+        }
+        Array => {
+            let len = ty.array_length();
+            let elt = ty.element_type();
+            let eltsz = ty_size(elt, pointer);
+            len * eltsz
+        }
+        Vector => {
+            let len = ty.vector_length();
+            let elt = ty.element_type();
+            let eltsz = ty_size(elt, pointer);
+            len * eltsz
+        },
+        _ => bug!("ty_size: unhandled type")
+    }
+}
index 8c6074fdaf9aa3ccbdcde1d740934c9415e5b000..f5cbe138cc5eb6216af21799ceb09662425b2b12 100644 (file)
@@ -632,7 +632,7 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
     let meta = val.meta;
 
 
-    let offset = st.offset_of_field(ix).bytes();
+    let offset = st.offsets[ix].bytes();
     let unaligned_offset = C_uint(bcx.ccx(), offset);
 
     // Get the alignment of the field
@@ -695,9 +695,9 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D
             let lldiscr = C_integral(Type::from_integer(ccx, d), discr.0 as u64, true);
             let mut vals_with_discr = vec![lldiscr];
             vals_with_discr.extend_from_slice(vals);
-            let mut contents = build_const_struct(ccx, &variant.offset_after_field[..],
-                &vals_with_discr[..], variant.packed);
-            let needed_padding = l.size(dl).bytes() - variant.min_size().bytes();
+            let mut contents = build_const_struct(ccx, &variant,
+                &vals_with_discr[..]);
+            let needed_padding = l.size(dl).bytes() - variant.min_size.bytes();
             if needed_padding > 0 {
                 contents.push(padding(ccx, needed_padding));
             }
@@ -711,7 +711,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D
         layout::Univariant { ref variant, .. } => {
             assert_eq!(discr, Disr(0));
             let contents = build_const_struct(ccx,
-                &variant.offset_after_field[..], vals, variant.packed);
+                &variant, vals);
             C_struct(ccx, &contents[..], variant.packed)
         }
         layout::Vector { .. } => {
@@ -728,9 +728,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D
         }
         layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
             if discr.0 == nndiscr {
-                C_struct(ccx, &build_const_struct(ccx,
-                                                 &nonnull.offset_after_field[..],
-                                                 vals, nonnull.packed),
+                C_struct(ccx, &build_const_struct(ccx, &nonnull, vals),
                          false)
             } else {
                 let fields = compute_fields(ccx, t, nndiscr as usize, false);
@@ -739,10 +737,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D
                     // field; see #8506.
                     C_null(type_of::sizing_type_of(ccx, ty))
                 }).collect::<Vec<ValueRef>>();
-                C_struct(ccx, &build_const_struct(ccx,
-                                                 &nonnull.offset_after_field[..],
-                                                 &vals[..],
-                                                 false),
+                C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]),
                          false)
             }
         }
@@ -759,11 +754,10 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D
 /// a two-element struct will locate it at offset 4, and accesses to it
 /// will read the wrong memory.
 fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                offset_after_field: &[layout::Size],
-                                vals: &[ValueRef],
-                                packed: bool)
+                                st: &layout::Struct,
+                                vals: &[ValueRef])
                                 -> Vec<ValueRef> {
-    assert_eq!(vals.len(), offset_after_field.len());
+    assert_eq!(vals.len(), st.offsets.len());
 
     if vals.len() == 0 {
         return Vec::new();
@@ -772,24 +766,19 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // offset of current value
     let mut offset = 0;
     let mut cfields = Vec::new();
-    let target_offsets = offset_after_field.iter().map(|i| i.bytes());
-    for (&val, target_offset) in vals.iter().zip(target_offsets) {
-        assert!(!is_undef(val));
-        cfields.push(val);
-        offset += machine::llsize_of_alloc(ccx, val_ty(val));
-        if !packed {
-            let val_align = machine::llalign_of_min(ccx, val_ty(val));
-            offset = roundup(offset, val_align);
-        }
-        if offset != target_offset {
+    let offsets = st.offsets.iter().map(|i| i.bytes());
+    for (&val, target_offset) in vals.iter().zip(offsets) {
+        if offset < target_offset {
             cfields.push(padding(ccx, target_offset - offset));
             offset = target_offset;
         }
+        assert!(!is_undef(val));
+        cfields.push(val);
+        offset += machine::llsize_of_alloc(ccx, val_ty(val));
     }
 
-    let size = offset_after_field.last().unwrap();
-    if offset < size.bytes() {
-        cfields.push(padding(ccx, size.bytes() - offset));
+    if offset < st.min_size.bytes() {
+        cfields.push(padding(ccx, st.min_size.bytes() - offset));
     }
 
     cfields
index 201e1e5f2ec4cf05619bbcd239d317fe69a33586..5dab82dbc7ac4f786fc1c387469a14be2ba83310 100644 (file)
@@ -754,7 +754,8 @@ fn link_args(cmd: &mut Linker,
         let empty_vec = Vec::new();
         let empty_str = String::new();
         let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
-        let mut args = args.iter().chain(used_link_args.iter());
+        let more_args = &sess.opts.cg.link_arg;
+        let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter());
         let relocation_model = sess.opts.cg.relocation_model.as_ref()
                                    .unwrap_or(&empty_str);
         if (t.options.relocation_model == "pic" || *relocation_model == "pic")
@@ -844,6 +845,7 @@ fn link_args(cmd: &mut Linker,
     if let Some(ref args) = sess.opts.cg.link_args {
         cmd.args(args);
     }
+    cmd.args(&sess.opts.cg.link_arg);
     cmd.args(&used_link_args);
 }
 
index 0a668db06908090b8a7689380bdf37ffc5da243b..f0661e03bc8153f0f38a09a4dae47b1de386bbfd 100644 (file)
@@ -152,17 +152,17 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     let mut hash_state = scx.symbol_hasher().borrow_mut();
     record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
         hash_state.reset();
-        let mut hasher = Sha256Hasher(&mut hash_state);
+        let hasher = Sha256Hasher(&mut hash_state);
+        let mut hasher = ty::util::TypeIdHasher::new(tcx, hasher);
 
         // the main symbol name is not necessarily unique; hash in the
         // compiler's internal def-path, guaranteeing each symbol has a
         // truly unique path
-        def_path.deterministic_hash_to(tcx, &mut hasher);
+        hasher.def_path(def_path);
 
         // Include the main item-type. Note that, in this case, the
         // assertions about `needs_subst` may not hold, but this item-type
         // ought to be the same for every reference anyway.
-        let mut hasher = ty::util::TypeIdHasher::new(tcx, hasher);
         assert!(!item_type.has_erasable_regions());
         hasher.visit_ty(item_type);
 
index fc11e3888d3c2e6cfcf72d42e3384ff25d11c39e..59a84439950bad2876ab8a18dd216bdafcc02b82 100644 (file)
 #![allow(non_upper_case_globals)]
 
 use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{FnType, ArgType};
+use abi::{self, FnType, ArgType};
 use context::CrateContext;
 use 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)
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            ty_align(elt) * len
-        }
-        _ => bug!("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
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt);
-            len * eltsz
-        }
-        _ => bug!("ty_size: unhandled type")
-    }
+    abi::ty_size(ty, 8)
 }
 
 fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
index 68a2e8aa8ce95d8c38bfd91ad30db2cc08927a39..93d43f7d96116c5095fddd65f18e11d6ba92047d 100644 (file)
@@ -11,7 +11,7 @@
 #![allow(non_upper_case_globals)]
 
 use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{FnType, ArgType};
+use abi::{self, align_up_to, FnType, ArgType};
 use context::CrateContext;
 use type_::Type;
 
@@ -24,40 +24,13 @@ pub enum Flavor {
 
 type TyAlignFn = fn(ty: Type) -> usize;
 
-fn align_up_to(off: usize, a: usize) -> usize {
-    return (off + a - 1) / a * a;
-}
-
 fn align(off: usize, ty: Type, align_fn: TyAlignFn) -> usize {
     let a = align_fn(ty);
     return align_up_to(off, a);
 }
 
 fn general_ty_align(ty: Type) -> usize {
-    match ty.kind() {
-        Integer => ((ty.int_width() as usize) + 7) / 8,
-        Pointer => 4,
-        Float => 4,
-        Double => 8,
-        Struct => {
-            if ty.is_packed() {
-                1
-            } else {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(1, |a, t| cmp::max(a, general_ty_align(*t)))
-            }
-        }
-        Array => {
-            let elt = ty.element_type();
-            general_ty_align(elt)
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            general_ty_align(elt) * len
-        }
-        _ => bug!("ty_align: unhandled type")
-    }
+    abi::ty_align(ty, 4)
 }
 
 // For more information see:
index 680310e195a41536d18554af0a994b095f79951d..25fe53e7ef40f88ab96ba44d3ed6198a9af6fd24 100644 (file)
 use libc::c_uint;
 use std::cmp;
 use llvm;
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{ArgType, FnType};
+use llvm::{Integer, Pointer, Float, Double, Vector};
+use abi::{self, align_up_to, ArgType, FnType};
 use context::CrateContext;
 use type_::Type;
 
-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 => 4,
-        Float => 4,
-        Double => 8,
-        Struct => {
-          if ty.is_packed() {
-            1
-          } else {
-            let str_tys = ty.field_types();
-            str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
-          }
-        }
-        Array => {
-            let elt = ty.element_type();
-            ty_align(elt)
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            ty_align(elt) * len
-        }
-        _ => bug!("ty_align: unhandled type")
-    }
+    abi::ty_align(ty, 4)
 }
 
 fn ty_size(ty: Type) -> usize {
-    match ty.kind() {
-        Integer => ((ty.int_width() as usize) + 7) / 8,
-        Pointer => 4,
-        Float => 4,
-        Double => 8,
-        Struct => {
-            if ty.is_packed() {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(0, |s, t| s + ty_size(*t))
-            } else {
-                let str_tys = ty.field_types();
-                let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
-                align(size, ty)
-            }
-        }
-        Array => {
-            let len = ty.array_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt);
-            len * eltsz
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt);
-            len * eltsz
-        }
-        _ => bug!("ty_size: unhandled type")
-    }
+    abi::ty_size(ty, 4)
 }
 
 fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
index e92ef1eaec8ec571ad74a4274afca8122ef2f6a7..e6b500c88dc7ac1be0916491e5afb0be7ecba08f 100644 (file)
 use libc::c_uint;
 use std::cmp;
 use llvm;
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{ArgType, FnType};
+use llvm::{Integer, Pointer, Float, Double, Vector};
+use abi::{self, align_up_to, ArgType, FnType};
 use context::CrateContext;
 use type_::Type;
 
-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)
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            ty_align(elt) * len
-        }
-        _ => bug!("ty_align: unhandled type")
-    }
+    abi::ty_align(ty, 8)
 }
 
 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
-        }
-        Vector => {
-            let len = ty.vector_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt);
-            len * eltsz
-        }
-        _ => bug!("ty_size: unhandled type")
-    }
+    abi::ty_size(ty, 8)
 }
 
 fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
index e05c31b1d88cdce6d187d3cbfa132f1b27a86381..4e1d7a93378270dfb006d8113c1417ecad0dbfc0 100644 (file)
 
 use libc::c_uint;
 use llvm;
-use llvm::{Integer, Pointer, Float, Double, Struct, Array};
-use abi::{FnType, ArgType};
+use llvm::{Integer, Pointer, Float, Double, Vector};
+use abi::{self, align_up_to, FnType, ArgType};
 use context::CrateContext;
 use 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 => 4,
-        Float => 4,
-        Double => 8,
-        Struct => {
-          if ty.is_packed() {
-            1
-          } else {
-            let str_tys = ty.field_types();
-            str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
-          }
-        }
-        Array => {
-            let elt = ty.element_type();
-            ty_align(elt)
-        }
-        _ => bug!("ty_size: unhandled type")
+    if ty.kind() == Vector {
+        bug!("ty_size: unhandled type")
+    } else {
+        abi::ty_align(ty, 4)
     }
 }
 
 fn ty_size(ty: Type) -> usize {
-    match ty.kind() {
-        Integer => ((ty.int_width() as usize) + 7) / 8,
-        Pointer => 4,
-        Float => 4,
-        Double => 8,
-        Struct => {
-            if ty.is_packed() {
-                let str_tys = ty.field_types();
-                str_tys.iter().fold(0, |s, t| s + ty_size(*t))
-            } else {
-                let str_tys = ty.field_types();
-                let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
-                align(size, ty)
-            }
-        }
-        Array => {
-            let len = ty.array_length();
-            let elt = ty.element_type();
-            let eltsz = ty_size(elt);
-            len * eltsz
-        }
-        _ => bug!("ty_size: unhandled type")
+    if ty.kind() == Vector {
+        bug!("ty_size: unhandled type")
+    } else {
+        abi::ty_size(ty, 4)
     }
 }
 
index ba54e369fd8382779b9ee6bfd567ccc82b4d2834..cdc7c1fd1afb379e937c3825853d832260e5fb9e 100644 (file)
 // 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};
-use abi::{FnType, ArgType};
+use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array};
+use abi::{self, FnType, ArgType};
 use context::CrateContext;
 use 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)
-        }
-        _ => bug!("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
-        }
-        _ => bug!("ty_size: unhandled type")
+    if ty.kind() == Vector {
+        bug!("ty_size: unhandled type")
+    } else {
+        abi::ty_size(ty, 8)
     }
 }
 
index 19404b667e1fc953c92305327a24892a6af8d3f3..5a666c6083d16f4649cc9292ea8f878a35aa3e2a 100644 (file)
 // for a pre-z13 machine or using -mno-vx.
 
 use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
-use abi::{FnType, ArgType};
+use abi::{align_up_to, FnType, ArgType};
 use context::CrateContext;
 use 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);
index eb67f4ca6185a36b257352b389b1c00f7079f6f7..33990148c8b7de13d4dbc1e4a39de610d9cd58f3 100644 (file)
 
 use llvm::{Integer, Pointer, Float, Double};
 use llvm::{Struct, Array, Attribute, Vector};
-use abi::{ArgType, FnType};
+use abi::{self, ArgType, FnType};
 use context::CrateContext;
 use type_::Type;
 
-use std::cmp;
-
 #[derive(Clone, Copy, PartialEq)]
 enum RegClass {
     NoClass,
@@ -90,62 +88,11 @@ fn align(off: usize, ty: Type) -> usize {
     }
 
     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)
-            }
-            Vector => {
-                let len = ty.vector_length();
-                let elt = ty.element_type();
-                ty_align(elt) * len
-            }
-            _ => bug!("ty_align: unhandled type")
-        }
+        abi::ty_align(ty, 8)
     }
 
     fn ty_size(ty: Type) -> usize {
-        match ty.kind() {
-            Integer => (ty.int_width() as usize + 7) / 8,
-            Pointer => 8,
-            Float => 4,
-            Double => 8,
-            Struct => {
-                let str_tys = ty.field_types();
-                if ty.is_packed() {
-                    str_tys.iter().fold(0, |s, t| s + ty_size(*t))
-                } else {
-                    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
-            }
-            Vector => {
-                let len = ty.vector_length();
-                let elt = ty.element_type();
-                let eltsz = ty_size(elt);
-                len * eltsz
-            }
-
-            _ => bug!("ty_size: unhandled type")
-        }
+        abi::ty_size(ty, 8)
     }
 
     fn all_mem(cls: &mut [RegClass]) {
index 5b1f691af8df74b244da2c7d0f68af0db3a4c6eb..6ae5fc1657aa728359f7b8f27df4743b537ec15a 100644 (file)
@@ -127,7 +127,7 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
         Layout::FatPointer { .. } => true,
         Layout::Univariant { ref variant, .. } => {
             // There must be only 2 fields.
-            if variant.offset_after_field.len() != 2 {
+            if variant.offsets.len() != 2 {
                 return false;
             }
 
index 21716d55ac6fa33c67d950d467f4d49deae26574..1d7e4991aa847e4566d77f4dc9bb23224cc5f889 100644 (file)
@@ -63,8 +63,9 @@ pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, Mir
 
     // Find all the scopes with variables defined in them.
     let mut has_variables = BitVector::new(mir.visibility_scopes.len());
-    for var in &mir.var_decls {
-        has_variables.insert(var.source_info.scope.index());
+    for var in mir.vars_iter() {
+        let decl = &mir.local_decls[var];
+        has_variables.insert(decl.source_info.unwrap().scope.index());
     }
 
     // Instantiate all scopes.
index fe76ec05f6eadda4a945c3e7d0bdb6357ce3e6fb..64d959d29080ccc975c67fef1208e92c9a8a2cf6 100644 (file)
@@ -335,20 +335,9 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
             let layout = ccx.layout_of(t);
             debug!("DST {} layout: {:?}", t, layout);
 
-            // Returns size in bytes of all fields except the last one
-            // (we will be recursing on the last one).
-            fn local_prefix_bytes(variant: &ty::layout::Struct) -> u64 {
-                let fields = variant.offset_after_field.len();
-                if fields > 1 {
-                    variant.offset_after_field[fields - 2].bytes()
-                } else {
-                    0
-                }
-            }
-
             let (sized_size, sized_align) = match *layout {
                 ty::layout::Layout::Univariant { ref variant, .. } => {
-                    (local_prefix_bytes(variant), variant.align.abi())
+                    (variant.offsets.last().map_or(0, |o| o.bytes()), variant.align.abi())
                 }
                 _ => {
                     bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}",
index 5de59b9f6bded47cb54591fbbfb25195b4a5b1a5..455cf4eb455162c10f5a637de44a846157fdfdb8 100644 (file)
@@ -20,7 +20,6 @@
 use rustc::mir::traversal;
 use common::{self, Block, BlockAndBuilder};
 use glue;
-use std::iter;
 use super::rvalue;
 
 pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
@@ -30,11 +29,7 @@ pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
 
     analyzer.visit_mir(mir);
 
-    let local_types = mir.arg_decls.iter().map(|a| a.ty)
-               .chain(mir.var_decls.iter().map(|v| v.ty))
-               .chain(mir.temp_decls.iter().map(|t| t.ty))
-               .chain(iter::once(mir.return_ty));
-    for (index, ty) in local_types.enumerate() {
+    for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() {
         let ty = bcx.monomorphize(&ty);
         debug!("local {} has type {:?}", index, ty);
         if ty.is_scalar() ||
@@ -80,12 +75,11 @@ impl<'mir, 'bcx, 'tcx> LocalAnalyzer<'mir, 'bcx, 'tcx> {
     fn new(mir: &'mir mir::Mir<'tcx>,
            bcx: &'mir BlockAndBuilder<'bcx, 'tcx>)
            -> LocalAnalyzer<'mir, 'bcx, 'tcx> {
-        let local_count = mir.count_locals();
         LocalAnalyzer {
             mir: mir,
             bcx: bcx,
-            lvalue_locals: BitVector::new(local_count),
-            seen_assigned: BitVector::new(local_count)
+            lvalue_locals: BitVector::new(mir.local_decls.len()),
+            seen_assigned: BitVector::new(mir.local_decls.len())
         }
     }
 
@@ -109,7 +103,7 @@ fn visit_assign(&mut self,
                     location: Location) {
         debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue);
 
-        if let Some(index) = self.mir.local_index(lvalue) {
+        if let mir::Lvalue::Local(index) = *lvalue {
             self.mark_assigned(index);
             if !rvalue::rvalue_creates_operand(self.mir, self.bcx, rvalue) {
                 self.mark_as_lvalue(index);
@@ -153,7 +147,7 @@ fn visit_lvalue(&mut self,
 
         // Allow uses of projections of immediate pair fields.
         if let mir::Lvalue::Projection(ref proj) = *lvalue {
-            if self.mir.local_index(&proj.base).is_some() {
+            if let mir::Lvalue::Local(_) = proj.base {
                 let ty = proj.base.ty(self.mir, self.bcx.tcx());
 
                 let ty = self.bcx.monomorphize(&ty.to_ty(self.bcx.tcx()));
@@ -167,7 +161,7 @@ fn visit_lvalue(&mut self,
             }
         }
 
-        if let Some(index) = self.mir.local_index(lvalue) {
+        if let mir::Lvalue::Local(index) = *lvalue {
             match context {
                 LvalueContext::Call => {
                     self.mark_assigned(index);
index 003830123ff3b9c7f136ea0c854025bc3bce6350..9e2d947c5e56342647bdeaaa9053275f07b65e45 100644 (file)
@@ -192,8 +192,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                 }
 
                 let llval = if let Some(cast_ty) = ret.cast {
-                    let index = mir.local_index(&mir::Lvalue::ReturnPointer).unwrap();
-                    let op = match self.locals[index] {
+                    let op = match self.locals[mir::RETURN_POINTER] {
                         LocalRef::Operand(Some(op)) => op,
                         LocalRef::Operand(None) => bug!("use of return before def"),
                         LocalRef::Lvalue(tr_lvalue) => {
@@ -218,7 +217,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                     }
                     load
                 } else {
-                    let op = self.trans_consume(&bcx, &mir::Lvalue::ReturnPointer);
+                    let op = self.trans_consume(&bcx, &mir::Lvalue::Local(mir::RETURN_POINTER));
                     op.pack_if_pair(&bcx).immediate()
                 };
                 bcx.ret(llval);
@@ -844,7 +843,7 @@ fn make_return_dest(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
         if fn_ret_ty.is_ignore() {
             return ReturnDest::Nothing;
         }
-        let dest = if let Some(index) = self.mir.local_index(dest) {
+        let dest = if let mir::Lvalue::Local(index) = *dest {
             let ret_ty = self.monomorphized_lvalue_ty(dest);
             match self.locals[index] {
                 LocalRef::Lvalue(dest) => dest,
index b74d56ce368a9cb64eddc86559f0c5fd721dc76b..76b63512bdbd02870f1de5db2d0e2ae8ee7bffed 100644 (file)
@@ -221,16 +221,17 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
     fn new(ccx: &'a CrateContext<'a, 'tcx>,
            mir: &'a mir::Mir<'tcx>,
            substs: &'tcx Substs<'tcx>,
-           args: IndexVec<mir::Arg, Const<'tcx>>)
+           args: IndexVec<mir::Local, Const<'tcx>>)
            -> MirConstContext<'a, 'tcx> {
         let mut context = MirConstContext {
             ccx: ccx,
             mir: mir,
             substs: substs,
-            locals: (0..mir.count_locals()).map(|_| None).collect(),
+            locals: (0..mir.local_decls.len()).map(|_| None).collect(),
         };
         for (i, arg) in args.into_iter().enumerate() {
-            let index = mir.local_index(&mir::Lvalue::Arg(mir::Arg::new(i))).unwrap();
+            // Locals after local 0 are the function arguments
+            let index = mir::Local::new(i + 1);
             context.locals[index] = Some(arg);
         }
         context
@@ -238,7 +239,7 @@ fn new(ccx: &'a CrateContext<'a, 'tcx>,
 
     fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
                  mut instance: Instance<'tcx>,
-                 args: IndexVec<mir::Arg, Const<'tcx>>)
+                 args: IndexVec<mir::Local, Const<'tcx>>)
                  -> Result<Const<'tcx>, ConstEvalErr> {
         // Try to resolve associated constants.
         if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) {
@@ -311,8 +312,7 @@ fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> {
                 mir::TerminatorKind::Goto { target } => target,
                 mir::TerminatorKind::Return => {
                     failure?;
-                    let index = self.mir.local_index(&mir::Lvalue::ReturnPointer).unwrap();
-                    return Ok(self.locals[index].unwrap_or_else(|| {
+                    return Ok(self.locals[mir::RETURN_POINTER].unwrap_or_else(|| {
                         span_bug!(span, "no returned value in constant");
                     }));
                 }
@@ -376,7 +376,7 @@ fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> {
     }
 
     fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) {
-        if let Some(index) = self.mir.local_index(dest) {
+        if let mir::Lvalue::Local(index) = *dest {
             self.locals[index] = Some(value);
         } else {
             span_bug!(span, "assignment to {:?} in constant", dest);
@@ -387,17 +387,14 @@ fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
                     -> Result<ConstLvalue<'tcx>, ConstEvalErr> {
         let tcx = self.ccx.tcx();
 
-        if let Some(index) = self.mir.local_index(lvalue) {
+        if let mir::Lvalue::Local(index) = *lvalue {
             return Ok(self.locals[index].unwrap_or_else(|| {
                 span_bug!(span, "{:?} not initialized", lvalue)
             }).as_lvalue());
         }
 
         let lvalue = match *lvalue {
-            mir::Lvalue::Var(_) |
-            mir::Lvalue::Temp(_) |
-            mir::Lvalue::Arg(_) |
-            mir::Lvalue::ReturnPointer => bug!(), // handled above
+            mir::Lvalue::Local(_)  => bug!(), // handled above
             mir::Lvalue::Static(def_id) => {
                 ConstLvalue {
                     base: Base::Static(consts::get_static(self.ccx, def_id)),
@@ -572,7 +569,7 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                 }
 
                 match *kind {
-                    mir::AggregateKind::Vec => {
+                    mir::AggregateKind::Array => {
                         self.const_array(dest_ty, &fields)
                     }
                     mir::AggregateKind::Adt(..) |
index 0ce5544c3bfc5b50bb650226e1f7601e32d23edb..7102bd81caf36e3d5243ab5a3014d11aa1650f6c 100644 (file)
@@ -91,7 +91,7 @@ pub fn trans_lvalue(&mut self,
         let ccx = bcx.ccx();
         let tcx = bcx.tcx();
 
-        if let Some(index) = self.mir.local_index(lvalue) {
+        if let mir::Lvalue::Local(index) = *lvalue {
             match self.locals[index] {
                 LocalRef::Lvalue(lvalue) => {
                     return lvalue;
@@ -103,10 +103,7 @@ pub fn trans_lvalue(&mut self,
         }
 
         let result = match *lvalue {
-            mir::Lvalue::Var(_) |
-            mir::Lvalue::Temp(_) |
-            mir::Lvalue::Arg(_) |
-            mir::Lvalue::ReturnPointer => bug!(), // handled above
+            mir::Lvalue::Local(_) => bug!(), // handled above
             mir::Lvalue::Static(def_id) => {
                 let const_ty = self.monomorphized_lvalue_ty(lvalue);
                 LvalueRef::new_sized(consts::get_static(ccx, def_id),
@@ -235,7 +232,7 @@ pub fn with_lvalue_ref<F, U>(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
                                  lvalue: &mir::Lvalue<'tcx>, f: F) -> U
     where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U
     {
-        if let Some(index) = self.mir.local_index(lvalue) {
+        if let mir::Lvalue::Local(index) = *lvalue {
             match self.locals[index] {
                 LocalRef::Lvalue(lvalue) => f(self, lvalue),
                 LocalRef::Operand(None) => {
index 1934f7b870d187be0f06dbd18ca2b306a20c7570..fe71023ea34dea34dc16af6908eaee6cc12f5da6 100644 (file)
@@ -237,51 +237,61 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
     // Allocate variable and temp allocas
     mircx.locals = {
         let args = arg_local_refs(&bcx, &mir, &mircx.scopes, &lvalue_locals);
-        let vars = mir.var_decls.iter().enumerate().map(|(i, decl)| {
+
+        let mut allocate_local = |local| {
+            let decl = &mir.local_decls[local];
             let ty = bcx.monomorphize(&decl.ty);
-            let debug_scope = mircx.scopes[decl.source_info.scope];
-            let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo;
 
-            let local = mir.local_index(&mir::Lvalue::Var(mir::Var::new(i))).unwrap();
-            if !lvalue_locals.contains(local.index()) && !dbg {
-                return LocalRef::new_operand(bcx.ccx(), ty);
-            }
+            if let Some(name) = decl.name {
+                // User variable
+                let source_info = decl.source_info.unwrap();
+                let debug_scope = mircx.scopes[source_info.scope];
+                let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo;
 
-            let lvalue = LvalueRef::alloca(&bcx, ty, &decl.name.as_str());
-            if dbg {
-                let dbg_loc = mircx.debug_loc(decl.source_info);
-                if let DebugLoc::ScopeAt(scope, span) = dbg_loc {
-                    bcx.with_block(|bcx| {
-                        declare_local(bcx, decl.name, ty, scope,
-                                    VariableAccess::DirectVariable { alloca: lvalue.llval },
-                                    VariableKind::LocalVariable, span);
-                    });
-                } else {
-                    panic!("Unexpected");
+                if !lvalue_locals.contains(local.index()) && !dbg {
+                    debug!("alloc: {:?} ({}) -> operand", local, name);
+                    return LocalRef::new_operand(bcx.ccx(), ty);
                 }
-            }
-            LocalRef::Lvalue(lvalue)
-        });
-
-        let locals = mir.temp_decls.iter().enumerate().map(|(i, decl)| {
-            (mir::Lvalue::Temp(mir::Temp::new(i)), decl.ty)
-        }).chain(iter::once((mir::Lvalue::ReturnPointer, mir.return_ty)));
-
-        args.into_iter().chain(vars).chain(locals.map(|(lvalue, ty)| {
-            let ty = bcx.monomorphize(&ty);
-            let local = mir.local_index(&lvalue).unwrap();
-            if lvalue == mir::Lvalue::ReturnPointer && fcx.fn_ty.ret.is_indirect() {
-                let llretptr = llvm::get_param(fcx.llfn, 0);
-                LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty)))
-            } else if lvalue_locals.contains(local.index()) {
-                LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty, &format!("{:?}", lvalue)))
+
+                debug!("alloc: {:?} ({}) -> lvalue", local, name);
+                let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str());
+                if dbg {
+                    let dbg_loc = mircx.debug_loc(source_info);
+                    if let DebugLoc::ScopeAt(scope, span) = dbg_loc {
+                        bcx.with_block(|bcx| {
+                            declare_local(bcx, name, ty, scope,
+                                        VariableAccess::DirectVariable { alloca: lvalue.llval },
+                                        VariableKind::LocalVariable, span);
+                        });
+                    } else {
+                        panic!("Unexpected");
+                    }
+                }
+                LocalRef::Lvalue(lvalue)
             } else {
-                // If this is an immediate local, we do not create an
-                // alloca in advance. Instead we wait until we see the
-                // definition and update the operand there.
-                LocalRef::new_operand(bcx.ccx(), ty)
+                // Temporary or return pointer
+                if local == mir::RETURN_POINTER && fcx.fn_ty.ret.is_indirect() {
+                    debug!("alloc: {:?} (return pointer) -> lvalue", local);
+                    let llretptr = llvm::get_param(fcx.llfn, 0);
+                    LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty)))
+                } else if lvalue_locals.contains(local.index()) {
+                    debug!("alloc: {:?} -> lvalue", local);
+                    LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty, &format!("{:?}", local)))
+                } else {
+                    // If this is an immediate local, we do not create an
+                    // alloca in advance. Instead we wait until we see the
+                    // definition and update the operand there.
+                    debug!("alloc: {:?} -> operand", local);
+                    LocalRef::new_operand(bcx.ccx(), ty)
+                }
             }
-        })).collect()
+        };
+
+        let retptr = allocate_local(mir::RETURN_POINTER);
+        iter::once(retptr)
+            .chain(args.into_iter())
+            .chain(mir.vars_and_temps_iter().map(allocate_local))
+            .collect()
     };
 
     // Branch to the START block
@@ -346,10 +356,11 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
         None
     };
 
-    mir.arg_decls.iter().enumerate().map(|(arg_index, arg_decl)| {
+    mir.args_iter().enumerate().map(|(arg_index, local)| {
+        let arg_decl = &mir.local_decls[local];
         let arg_ty = bcx.monomorphize(&arg_decl.ty);
-        let local = mir.local_index(&mir::Lvalue::Arg(mir::Arg::new(arg_index))).unwrap();
-        if arg_decl.spread {
+
+        if Some(local) == mir.spread_arg {
             // This argument (e.g. the last argument in the "rust-call" ABI)
             // is a tuple that was spread at the ABI level and now we have
             // to reconstruct it into a tuple local variable, from multiple
@@ -467,8 +478,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
         bcx.with_block(|bcx| arg_scope.map(|scope| {
             // Is this a regular argument?
             if arg_index > 0 || mir.upvar_decls.is_empty() {
-                declare_local(bcx, arg_decl.debug_name, arg_ty, scope,
-                              VariableAccess::DirectVariable { alloca: llval },
+                declare_local(bcx, arg_decl.name.unwrap_or(keywords::Invalid.name()), arg_ty,
+                              scope, VariableAccess::DirectVariable { alloca: llval },
                               VariableKind::ArgumentVariable(arg_index + 1),
                               bcx.fcx().span.unwrap_or(DUMMY_SP));
                 return;
index 270033be9375c20029f763de31b8da3816bc930d..4f1ec40398ca97659d1bbcf2881a199981c82dcc 100644 (file)
@@ -175,7 +175,7 @@ pub fn trans_consume(&mut self,
 
         // watch out for locals that do not have an
         // alloca; they are handled somewhat differently
-        if let Some(index) = self.mir.local_index(lvalue) {
+        if let mir::Lvalue::Local(index) = *lvalue {
             match self.locals[index] {
                 LocalRef::Operand(Some(o)) => {
                     return o;
@@ -191,7 +191,7 @@ pub fn trans_consume(&mut self,
 
         // Moves out of pair fields are trivial.
         if let &mir::Lvalue::Projection(ref proj) = lvalue {
-            if let Some(index) = self.mir.local_index(&proj.base) {
+            if let mir::Lvalue::Local(index) = proj.base {
                 if let LocalRef::Operand(Some(o)) = self.locals[index] {
                     match (o.val, &proj.elem) {
                         (OperandValue::Pair(a, b),
index 9943acbc88e6d2365857e89ac7300483816ebb28..3d6aad37ed571fd16a3960efdf17aafb66b46473 100644 (file)
@@ -30,7 +30,7 @@ pub fn trans_statement(&mut self,
         debug_loc.apply(bcx.fcx());
         match statement.kind {
             mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
-                if let Some(index) = self.mir.local_index(lvalue) {
+                if let mir::Lvalue::Local(index) = *lvalue {
                     match self.locals[index] {
                         LocalRef::Lvalue(tr_dest) => {
                             self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc)
@@ -86,7 +86,7 @@ fn trans_storage_liveness(&self,
                               lvalue: &mir::Lvalue<'tcx>,
                               intrinsic: base::Lifetime)
                               -> BlockAndBuilder<'bcx, 'tcx> {
-        if let Some(index) = self.mir.local_index(lvalue) {
+        if let mir::Lvalue::Local(index) = *lvalue {
             if let LocalRef::Lvalue(tr_lval) = self.locals[index] {
                 intrinsic.call(&bcx, tr_lval.llval);
             }
index cbdce3229c7c76d96e6152384f7fde2cc5844b53..568e44a95191d947ce48dc0700ad48e72b53a2a7 100644 (file)
@@ -795,7 +795,7 @@ fn create_substs_for_ast_trait_ref(&self,
                 // For now, require that parenthetical notation be used
                 // only with `Fn()` etc.
                 if !self.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar {
-                    emit_feature_err(&self.tcx().sess.parse_sess.span_diagnostic,
+                    emit_feature_err(&self.tcx().sess.parse_sess,
                                      "unboxed_closures", span, GateIssue::Language,
                                      "\
                         the precise format of `Fn`-family traits' \
@@ -807,7 +807,7 @@ fn create_substs_for_ast_trait_ref(&self,
                 // For now, require that parenthetical notation be used
                 // only with `Fn()` etc.
                 if !self.tcx().sess.features.borrow().unboxed_closures && !trait_def.paren_sugar {
-                    emit_feature_err(&self.tcx().sess.parse_sess.span_diagnostic,
+                    emit_feature_err(&self.tcx().sess.parse_sess,
                                      "unboxed_closures", span, GateIssue::Language,
                                      "\
                         parenthetical notation is only stable when used with `Fn`-family traits");
@@ -1241,10 +1241,12 @@ fn one_bound_for_assoc_type(&self,
         -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
     {
         if bounds.is_empty() {
-            span_err!(self.tcx().sess, span, E0220,
+            struct_span_err!(self.tcx().sess, span, E0220,
                       "associated type `{}` not found for `{}`",
                       assoc_name,
-                      ty_param_name);
+                      ty_param_name)
+              .span_label(span, &format!("associated type `{}` not found", assoc_name))
+              .emit();
             return Err(ErrorReported);
         }
 
@@ -1623,7 +1625,7 @@ pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
         }
 
         let result_ty = match ast_ty.node {
-            hir::TyVec(ref ty) => {
+            hir::TySlice(ref ty) => {
                 tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty))
             }
             hir::TyObjectSum(ref ty, ref bounds) => {
@@ -1758,7 +1760,7 @@ pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
 
                 ty
             }
-            hir::TyFixedLengthVec(ref ty, ref e) => {
+            hir::TyArray(ref ty, ref e) => {
                 if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") {
                     tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
                 } else {
index de7ca479b0b6632bb72981fc627a7dea4434f1b8..99d1da77018ad26ecec59cdc6713fce19d4309e4 100644 (file)
@@ -227,7 +227,7 @@ pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
                     tcx.types.err
                 }
             }
-            PatKind::Vec(ref before, ref slice, ref after) => {
+            PatKind::Slice(ref before, ref slice, ref after) => {
                 let expected_ty = self.structurally_resolved_type(pat.span, expected);
                 let (inner_ty, slice_ty) = match expected_ty.sty {
                     ty::TyArray(inner_ty, size) => {
@@ -675,14 +675,14 @@ fn check_struct_pat_fields(&self,
         for &Spanned { node: ref field, span } in fields {
             let field_ty = match used_fields.entry(field.name) {
                 Occupied(occupied) => {
-                    let mut err = struct_span_err!(tcx.sess, span, E0025,
-                                                   "field `{}` bound multiple times \
-                                                    in the pattern",
-                                                   field.name);
-                    span_note!(&mut err, *occupied.get(),
-                               "field `{}` previously bound here",
-                               field.name);
-                    err.emit();
+                    struct_span_err!(tcx.sess, span, E0025,
+                                     "field `{}` bound multiple times \
+                                      in the pattern",
+                                     field.name)
+                        .span_label(span,
+                                    &format!("multiple uses of `{}` in pattern", field.name))
+                        .span_label(*occupied.get(), &format!("first use of `{}`", field.name))
+                        .emit();
                     tcx.types.err
                 }
                 Vacant(vacant) => {
index d1fb0736d21154e465e0948ed94be55a6d84f19b..75c1d28f7d830385c15953f1c86b0f1cd58f8f6e 100644 (file)
@@ -47,8 +47,9 @@ pub fn check_call(&self,
                       expected: Expectation<'tcx>) -> Ty<'tcx>
     {
         let original_callee_ty = self.check_expr(callee_expr);
+        let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty);
 
-        let mut autoderef = self.autoderef(callee_expr.span, original_callee_ty);
+        let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
         let result = autoderef.by_ref().flat_map(|(adj_ty, idx)| {
             self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx)
         }).next();
index ffff05885adbc8282ad8cb0f75c7750f8a5302f4..826a88127d84e78ec5165c29bd083eb884b5bcee 100644 (file)
@@ -148,14 +148,70 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 
     if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() {
-        span_err!(tcx.sess, impl_m_span, E0050,
+        let trait_number_args = trait_m.fty.sig.0.inputs.len();
+        let impl_number_args = impl_m.fty.sig.0.inputs.len();
+        let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id);
+        let trait_span = if let Some(trait_id) = trait_m_node_id {
+            match tcx.map.expect_trait_item(trait_id).node {
+                TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+                    if let Some(arg) = trait_m_sig.decl.inputs.get(
+                        if trait_number_args > 0 {
+                            trait_number_args - 1
+                        } else {
+                            0
+                        }) {
+                        Some(arg.pat.span)
+                    } else {
+                        trait_item_span
+                    }
+                }
+                _ => bug!("{:?} is not a method", impl_m)
+            }
+        } else {
+            trait_item_span
+        };
+        let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
+        let impl_span = match tcx.map.expect_impl_item(impl_m_node_id).node {
+            ImplItemKind::Method(ref impl_m_sig, _) => {
+                if let Some(arg) = impl_m_sig.decl.inputs.get(
+                    if impl_number_args > 0 {
+                        impl_number_args - 1
+                    } else {
+                        0
+                    }) {
+                    arg.pat.span
+                } else {
+                    impl_m_span
+                }
+            }
+            _ => bug!("{:?} is not a method", impl_m)
+        };
+        let mut err = struct_span_err!(tcx.sess, impl_span, E0050,
             "method `{}` has {} parameter{} \
              but the declaration in trait `{}` has {}",
             trait_m.name,
-            impl_m.fty.sig.0.inputs.len(),
-            if impl_m.fty.sig.0.inputs.len() == 1 {""} else {"s"},
+            impl_number_args,
+            if impl_number_args == 1 {""} else {"s"},
             tcx.item_path_str(trait_m.def_id),
-            trait_m.fty.sig.0.inputs.len());
+            trait_number_args);
+        if let Some(trait_span) = trait_span {
+            err.span_label(trait_span,
+                           &format!("trait requires {}",
+                                    &if trait_number_args != 1 {
+                                        format!("{} parameters", trait_number_args)
+                                    } else {
+                                        format!("{} parameter", trait_number_args)
+                                    }));
+        }
+        err.span_label(impl_span,
+                       &format!("expected {}, found {}",
+                                &if trait_number_args != 1 {
+                                    format!("{} parameters", trait_number_args)
+                                } else {
+                                    format!("{} parameter", trait_number_args)
+                                },
+                       impl_number_args));
+        err.emit();
         return;
     }
 
index 563b645910e41535398de97673525fcb4b3d71e6..93d8b3e1563d974e27520c66f8fe2fa6dd366ff4 100644 (file)
@@ -379,7 +379,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
                         span_err!(tcx.sess, it.span, E0444,
                                   "platform-specific intrinsic has invalid number of \
                                    arguments: found {}, expected {}",
-                                  intr.inputs.len(), sig.inputs.len());
+                                  sig.inputs.len(), intr.inputs.len());
                         return
                     }
                     let input_pairs = intr.inputs.iter().zip(&sig.inputs);
index ab59fafb652099087028a0406a6202802c200523..e81bca3c171839b2e67e671abeedb34716d829ab 100644 (file)
@@ -312,13 +312,25 @@ fn instantiate_method_substs(&mut self,
 
         if num_supplied_types > 0 && num_supplied_types != num_method_types {
             if num_method_types == 0 {
-                span_err!(self.tcx.sess, self.span, E0035,
-                    "does not take type parameters");
+                struct_span_err!(self.tcx.sess, self.span, E0035,
+                                 "does not take type parameters")
+                    .span_label(self.span, &"called with unneeded type parameters")
+                    .emit();
             } else {
-                span_err!(self.tcx.sess, self.span, E0036,
+                struct_span_err!(self.tcx.sess, self.span, E0036,
                     "incorrect number of type parameters given for this method: \
                      expected {}, found {}",
-                    num_method_types, num_supplied_types);
+                    num_method_types, num_supplied_types)
+                    .span_label(self.span,
+                                &format!("Passed {} type argument{}, expected {}",
+                                         num_supplied_types,
+                                         if num_supplied_types != 1 {
+                                            "s"
+                                         } else {
+                                            ""
+                                         },
+                                         num_method_types))
+                    .emit();
             }
             supplied_method_types = vec![self.tcx.types.err; num_method_types];
         }
index 8c5b607f94cdf4ca0093a1ae3d15477c3c087ed5..2ac2dab999bb0470d0ee7111a76a87d6b82ebd7a 100644 (file)
@@ -450,7 +450,7 @@ fn visit_item(&mut self, i: &'tcx hir::Item) {
 
     fn visit_ty(&mut self, t: &'tcx hir::Ty) {
         match t.node {
-            hir::TyFixedLengthVec(_, ref expr) => {
+            hir::TyArray(_, ref expr) => {
                 check_const_with_type(self.ccx, &expr, self.ccx.tcx.types.usize, expr.id);
             }
             _ => {}
@@ -626,7 +626,7 @@ fn visit_block(&mut self, b: &'gcx hir::Block) {
     // need to record the type for that node
     fn visit_ty(&mut self, t: &'gcx hir::Ty) {
         match t.node {
-            hir::TyFixedLengthVec(ref ty, ref count_expr) => {
+            hir::TyArray(ref ty, ref count_expr) => {
                 self.visit_ty(&ty);
                 self.fcx.check_expr_with_hint(&count_expr, self.fcx.tcx.types.usize);
             }
@@ -1525,9 +1525,11 @@ pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> Ty<'tcx> {
         match self.locals.borrow().get(&nid) {
             Some(&t) => t,
             None => {
-                span_err!(self.tcx.sess, span, E0513,
-                          "no type for local variable {}",
-                          nid);
+                struct_span_err!(self.tcx.sess, span, E0513,
+                                 "no type for local variable {}",
+                                 self.tcx.map.node_to_string(nid))
+                    .span_label(span, &"no type for variable")
+                    .emit();
                 self.tcx.types.err
             }
         }
@@ -3255,7 +3257,7 @@ pub fn check_struct_path(&self,
         if let Some((def_id, variant)) = variant {
             if variant.kind == ty::VariantKind::Tuple &&
                     !self.tcx.sess.features.borrow().relaxed_adts {
-                emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic,
+                emit_feature_err(&self.tcx.sess.parse_sess,
                                  "relaxed_adts", span, GateIssue::Language,
                                  "tuple structs and variants in struct patterns are unstable");
             }
@@ -3588,7 +3590,7 @@ fn check_expr_kind(&self,
               self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref)
           }
           hir::ExprCast(ref e, ref t) => {
-            if let hir::TyFixedLengthVec(_, ref count_expr) = t.node {
+            if let hir::TyArray(_, ref count_expr) = t.node {
                 self.check_expr_with_hint(&count_expr, tcx.types.usize);
             }
 
@@ -3621,7 +3623,7 @@ fn check_expr_kind(&self,
             self.check_expr_eq_type(&e, typ);
             typ
           }
-          hir::ExprVec(ref args) => {
+          hir::ExprArray(ref args) => {
             let uty = expected.to_option(self).and_then(|uty| {
                 match uty.sty {
                     ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty),
index 0b70d904c26549830c9a3326afb669ccfa736a93..8685f703a599c8888f7becf687f9091f53d364e8 100644 (file)
@@ -247,7 +247,7 @@ fn visit_local(&mut self, l: &hir::Local) {
 
     fn visit_ty(&mut self, t: &hir::Ty) {
         match t.node {
-            hir::TyFixedLengthVec(ref ty, ref count_expr) => {
+            hir::TyArray(ref ty, ref count_expr) => {
                 self.visit_ty(&ty);
                 write_ty_to_tcx(self.fcx.ccx, count_expr.id, self.tcx().types.usize);
             }
index 3b4c98fc71e4451246ff6286df5a3ea82ba6ed35..ca22faa2ec36ab27f27c1c31cf01f2f3db772815 100644 (file)
@@ -20,7 +20,7 @@
 use rustc::ty::subst::Subst;
 use rustc::ty::{self, TyCtxt, TypeFoldable};
 use rustc::traits::{self, Reveal};
-use rustc::ty::{ParameterEnvironment};
+use rustc::ty::ParameterEnvironment;
 use rustc::ty::{Ty, TyBool, TyChar, TyError};
 use rustc::ty::{TyParam, TyRawPtr};
 use rustc::ty::{TyRef, TyAdt, TyTrait, TyNever, TyTuple};
 mod overlap;
 mod unsafety;
 
-struct CoherenceChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+struct CoherenceChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     crate_context: &'a CrateCtxt<'a, 'gcx>,
     inference_context: InferCtxt<'a, 'gcx, 'tcx>,
 }
 
-struct CoherenceCheckVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>
+struct CoherenceCheckVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
+    cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>,
 }
 
 impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
@@ -62,36 +62,25 @@ fn visit_item(&mut self, item: &Item) {
 }
 
 impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
-
     // Returns the def ID of the base type, if there is one.
     fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
         match ty.sty {
-            TyAdt(def, _) => {
-                Some(def.did)
-            }
+            TyAdt(def, _) => Some(def.did),
 
-            TyTrait(ref t) => {
-                Some(t.principal.def_id())
-            }
+            TyTrait(ref t) => Some(t.principal.def_id()),
 
-            TyBox(_) => {
-                self.inference_context.tcx.lang_items.owned_box()
-            }
+            TyBox(_) => self.inference_context.tcx.lang_items.owned_box(),
 
-            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
-            TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) |
-            TyTuple(..) | TyParam(..) | TyError | TyNever |
-            TyRawPtr(_) | TyRef(..) | TyProjection(..) => {
-                None
-            }
+            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) |
+            TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError |
+            TyNever | TyRawPtr(_) | TyRef(..) | TyProjection(..) => None,
 
             TyInfer(..) | TyClosure(..) | TyAnon(..) => {
                 // `ty` comes from a user declaration so we should only expect types
                 // that the user can type
-                span_bug!(
-                    span,
-                    "coherence encountered unexpected type searching for base type: {}",
-                    ty);
+                span_bug!(span,
+                          "coherence encountered unexpected type searching for base type: {}",
+                          ty);
             }
         }
     }
@@ -100,9 +89,8 @@ fn check(&self) {
         // Check implementations and traits. This populates the tables
         // containing the inherent methods and extension methods. It also
         // builds up the trait inheritance table.
-        self.crate_context.tcx.visit_all_items_in_krate(
-            DepNode::CoherenceCheckImpl,
-            &mut CoherenceCheckVisitor { cc: self });
+        self.crate_context.tcx.visit_all_items_in_krate(DepNode::CoherenceCheckImpl,
+                                                        &mut CoherenceCheckVisitor { cc: self });
 
         // Populate the table of destructors. It might seem a bit strange to
         // do this here, but it's actually the most convenient place, since
@@ -167,7 +155,8 @@ fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) {
 
     fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'gcx>, impl_def_id: DefId) {
         debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
-               impl_trait_ref, impl_def_id);
+               impl_trait_ref,
+               impl_def_id);
         let trait_def = self.crate_context.tcx.lookup_trait_def(impl_trait_ref.def_id);
         trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
     }
@@ -176,9 +165,9 @@ fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'gcx>, impl_def_id: DefId)
     fn create_impl_from_item(&self, item: &Item) -> Vec<DefId> {
         match item.node {
             ItemImpl(.., ref impl_items) => {
-                impl_items.iter().map(|impl_item| {
-                    self.crate_context.tcx.map.local_def_id(impl_item.id)
-                }).collect()
+                impl_items.iter()
+                    .map(|impl_item| self.crate_context.tcx.map.local_def_id(impl_item.id))
+                    .collect()
             }
             _ => {
                 span_bug!(item.span, "can't convert a non-impl to an impl");
@@ -186,14 +175,14 @@ fn create_impl_from_item(&self, item: &Item) -> Vec<DefId> {
         }
     }
 
-    //
     // Destructors
     //
 
     fn populate_destructors(&self) {
         let tcx = self.crate_context.tcx;
         let drop_trait = match tcx.lang_items.drop_trait() {
-            Some(id) => id, None => { return }
+            Some(id) => id,
+            None => return,
         };
         tcx.populate_implementations_for_trait_if_necessary(drop_trait);
         let drop_trait = tcx.lookup_trait_def(drop_trait);
@@ -219,13 +208,14 @@ fn populate_destructors(&self) {
                         match tcx.map.find(impl_node_id) {
                             Some(hir_map::NodeItem(item)) => {
                                 let span = match item.node {
-                                    ItemImpl(.., ref ty, _) => {
-                                        ty.span
-                                    },
-                                    _ => item.span
+                                    ItemImpl(.., ref ty, _) => ty.span,
+                                    _ => item.span,
                                 };
-                                struct_span_err!(tcx.sess, span, E0120,
-                                    "the Drop trait may only be implemented on structures")
+                                struct_span_err!(tcx.sess,
+                                                 span,
+                                                 E0120,
+                                                 "the Drop trait may only be implemented on \
+                                                  structures")
                                     .span_label(span,
                                                 &format!("implementing Drop requires a struct"))
                                     .emit();
@@ -254,15 +244,14 @@ fn check_implementations_of_copy(&self) {
         let copy_trait = tcx.lookup_trait_def(copy_trait);
 
         copy_trait.for_each_impl(tcx, |impl_did| {
-            debug!("check_implementations_of_copy: impl_did={:?}",
-                   impl_did);
+            debug!("check_implementations_of_copy: impl_did={:?}", impl_did);
 
             let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
                 n
             } else {
                 debug!("check_implementations_of_copy(): impl not in this \
                         crate");
-                return
+                return;
             };
 
             let self_type = tcx.lookup_item_type(impl_did);
@@ -280,14 +269,12 @@ fn check_implementations_of_copy(&self) {
             match param_env.can_type_implement_copy(tcx, self_type, span) {
                 Ok(()) => {}
                 Err(CopyImplementationError::InfrigingField(name)) => {
-                       struct_span_err!(tcx.sess, span, E0204,
-                                 "the trait `Copy` may not be implemented for \
-                                 this type")
-                           .span_label(span, &format!(
-                                 "field `{}` does not implement `Copy`", name)
-                               )
-                           .emit()
-
+                    struct_span_err!(tcx.sess,
+                                     span,
+                                     E0204,
+                                     "the trait `Copy` may not be implemented for this type")
+                        .span_label(span, &format!("field `{}` does not implement `Copy`", name))
+                        .emit()
                 }
                 Err(CopyImplementationError::InfrigingVariant(name)) => {
                     let item = tcx.map.expect_item(impl_node_id);
@@ -297,10 +284,12 @@ fn check_implementations_of_copy(&self) {
                         span
                     };
 
-                    struct_span_err!(tcx.sess, span, E0205,
+                    struct_span_err!(tcx.sess,
+                                     span,
+                                     E0205,
                                      "the trait `Copy` may not be implemented for this type")
-                        .span_label(span, &format!("variant `{}` does not implement `Copy`",
-                                                   name))
+                        .span_label(span,
+                                    &format!("variant `{}` does not implement `Copy`", name))
                         .emit()
                 }
                 Err(CopyImplementationError::NotAnAdt) => {
@@ -311,15 +300,19 @@ fn check_implementations_of_copy(&self) {
                         span
                     };
 
-                    struct_span_err!(tcx.sess, span, E0206,
+                    struct_span_err!(tcx.sess,
+                                     span,
+                                     E0206,
                                      "the trait `Copy` may not be implemented for this type")
                         .span_label(span, &format!("type is not a structure or enumeration"))
                         .emit();
                 }
                 Err(CopyImplementationError::HasDestructor) => {
-                    struct_span_err!(tcx.sess, span, E0184,
-                              "the trait `Copy` may not be implemented for this type; \
-                               the type has a destructor")
+                    struct_span_err!(tcx.sess,
+                                     span,
+                                     E0184,
+                                     "the trait `Copy` may not be implemented for this type; the \
+                                      type has a destructor")
                         .span_label(span, &format!("Copy not allowed on types with destructors"))
                         .emit();
                 }
@@ -359,7 +352,8 @@ fn check_implementations_of_coerce_unsized(&self) {
             let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap();
             let target = trait_ref.substs.type_at(1);
             debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
-                   source, target);
+                   source,
+                   target);
 
             let span = tcx.map.span(impl_node_id);
             let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
@@ -368,15 +362,19 @@ fn check_implementations_of_coerce_unsized(&self) {
             assert!(!source.has_escaping_regions());
 
             debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
-                   source, target);
+                   source,
+                   target);
 
             tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
                 let origin = TypeOrigin::Misc(span);
-                let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>, mt_b: ty::TypeAndMut<'gcx>,
+                let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>,
+                                   mt_b: ty::TypeAndMut<'gcx>,
                                    mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| {
                     if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
-                        infcx.report_mismatched_types(origin, mk_ptr(mt_b.ty),
-                                                      target, ty::error::TypeError::Mutability);
+                        infcx.report_mismatched_types(origin,
+                                                      mk_ptr(mt_b.ty),
+                                                      target,
+                                                      ty::error::TypeError::Mutability);
                     }
                     (mt_a.ty, mt_b.ty, unsize_trait, None)
                 };
@@ -394,37 +392,45 @@ fn check_implementations_of_coerce_unsized(&self) {
                     }
 
                     (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b))
-                            if def_a.is_struct() && def_b.is_struct() => {
+                        if def_a.is_struct() && def_b.is_struct() => {
                         if def_a != def_b {
                             let source_path = tcx.item_path_str(def_a.did);
                             let target_path = tcx.item_path_str(def_b.did);
-                            span_err!(tcx.sess, span, E0377,
+                            span_err!(tcx.sess,
+                                      span,
+                                      E0377,
                                       "the trait `CoerceUnsized` may only be implemented \
                                        for a coercion between structures with the same \
                                        definition; expected {}, found {}",
-                                      source_path, target_path);
+                                      source_path,
+                                      target_path);
                             return;
                         }
 
                         let fields = &def_a.struct_variant().fields;
-                        let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| {
-                            let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
-
-                            if f.unsubst_ty().is_phantom_data() {
-                                // Ignore PhantomData fields
-                                None
-                            } else if infcx.sub_types(false, origin, b, a).is_ok() {
-                                // Ignore fields that aren't significantly changed
-                                None
-                            } else {
-                                // Collect up all fields that were significantly changed
-                                // i.e. those that contain T in coerce_unsized T -> U
-                                Some((i, a, b))
-                            }
-                        }).collect::<Vec<_>>();
+                        let diff_fields = fields.iter()
+                            .enumerate()
+                            .filter_map(|(i, f)| {
+                                let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
+
+                                if f.unsubst_ty().is_phantom_data() {
+                                    // Ignore PhantomData fields
+                                    None
+                                } else if infcx.sub_types(false, origin, b, a).is_ok() {
+                                    // Ignore fields that aren't significantly changed
+                                    None
+                                } else {
+                                    // Collect up all fields that were significantly changed
+                                    // i.e. those that contain T in coerce_unsized T -> U
+                                    Some((i, a, b))
+                                }
+                            })
+                            .collect::<Vec<_>>();
 
                         if diff_fields.is_empty() {
-                            span_err!(tcx.sess, span, E0374,
+                            span_err!(tcx.sess,
+                                      span,
+                                      E0374,
                                       "the trait `CoerceUnsized` may only be implemented \
                                        for a coercion between structures with one field \
                                        being coerced, none found");
@@ -437,16 +443,22 @@ fn check_implementations_of_coerce_unsized(&self) {
                                 tcx.map.span(impl_node_id)
                             };
 
-                            let mut err = struct_span_err!(tcx.sess, span, E0375,
-                                      "implementing the trait `CoerceUnsized` \
-                                       requires multiple coercions");
+                            let mut err = struct_span_err!(tcx.sess,
+                                                           span,
+                                                           E0375,
+                                                           "implementing the trait \
+                                                            `CoerceUnsized` requires multiple \
+                                                            coercions");
                             err.note("`CoerceUnsized` may only be implemented for \
                                       a coercion between structures with one field being coerced");
                             err.note(&format!("currently, {} fields need coercions: {}",
-                                             diff_fields.len(),
-                                             diff_fields.iter().map(|&(i, a, b)| {
-                                                format!("{} ({} to {})", fields[i].name, a, b)
-                                             }).collect::<Vec<_>>().join(", ") ));
+                                              diff_fields.len(),
+                                              diff_fields.iter()
+                                                  .map(|&(i, a, b)| {
+                                                      format!("{} ({} to {})", fields[i].name, a, b)
+                                                  })
+                                                  .collect::<Vec<_>>()
+                                                  .join(", ")));
                             err.span_label(span, &format!("requires multiple coercions"));
                             err.emit();
                             return;
@@ -458,7 +470,9 @@ fn check_implementations_of_coerce_unsized(&self) {
                     }
 
                     _ => {
-                        span_err!(tcx.sess, span, E0376,
+                        span_err!(tcx.sess,
+                                  span,
+                                  E0376,
                                   "the trait `CoerceUnsized` may only be implemented \
                                    for a coercion between structures");
                         return;
@@ -469,8 +483,8 @@ fn check_implementations_of_coerce_unsized(&self) {
 
                 // Register an obligation for `A: Trait<B>`.
                 let cause = traits::ObligationCause::misc(span, impl_node_id);
-                let predicate = tcx.predicate_for_trait_def(cause, trait_def_id, 0,
-                                                            source, &[target]);
+                let predicate =
+                    tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]);
                 fulfill_cx.register_predicate_obligation(&infcx, predicate);
 
                 // Check that all transitive obligations are satisfied.
@@ -480,8 +494,8 @@ fn check_implementations_of_coerce_unsized(&self) {
 
                 // Finally, resolve all regions.
                 let mut free_regions = FreeRegionMap::new();
-                free_regions.relate_free_regions_from_predicates(
-                    &infcx.parameter_environment.caller_bounds);
+                free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment
+                    .caller_bounds);
                 infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
 
                 if let Some(kind) = kind {
@@ -495,7 +509,7 @@ fn check_implementations_of_coerce_unsized(&self) {
 fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: DefId) {
     if tcx.sess.features.borrow().unboxed_closures {
         // the feature gate allows all of them
-        return
+        return;
     }
     let did = Some(trait_def_id);
     let li = &tcx.lang_items;
@@ -507,14 +521,15 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
     } else if did == li.fn_once_trait() {
         "FnOnce"
     } else {
-        return // everything OK
+        return; // everything OK
     };
     let mut err = struct_span_err!(tcx.sess,
                                    sp,
                                    E0183,
                                    "manual implementations of `{}` are experimental",
                                    trait_name);
-    help!(&mut err, "add `#![feature(unboxed_closures)]` to the crate attributes to enable");
+    help!(&mut err,
+          "add `#![feature(unboxed_closures)]` to the crate attributes to enable");
     err.emit();
 }
 
@@ -522,9 +537,10 @@ pub fn check_coherence(ccx: &CrateCtxt) {
     let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
     ccx.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
         CoherenceChecker {
-            crate_context: ccx,
-            inference_context: infcx,
-        }.check();
+                crate_context: ccx,
+                inference_context: infcx,
+            }
+            .check();
     });
     unsafety::check(ccx.tcx);
     orphan::check(ccx.tcx);
index 70342a0cd258e3658372df31df5f3ae0cb590b52..bff794364c098dadc745f646022e5d77df181ebc 100644 (file)
@@ -25,17 +25,20 @@ pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     tcx.visit_all_items_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan);
 }
 
-struct OrphanChecker<'cx, 'tcx:'cx> {
-    tcx: TyCtxt<'cx, 'tcx, 'tcx>
+struct OrphanChecker<'cx, 'tcx: 'cx> {
+    tcx: TyCtxt<'cx, 'tcx, 'tcx>,
 }
 
 impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
     fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
         if def_id.krate != LOCAL_CRATE {
-            struct_span_err!(self.tcx.sess, item.span, E0116,
-                      "cannot define inherent `impl` for a type outside of the \
-                       crate where the type is defined")
-                .span_label(item.span, &format!("impl for type defined outside of crate."))
+            struct_span_err!(self.tcx.sess,
+                             item.span,
+                             E0116,
+                             "cannot define inherent `impl` for a type outside of the crate \
+                              where the type is defined")
+                .span_label(item.span,
+                            &format!("impl for type defined outside of crate."))
                 .note("define and implement a trait or new type instead")
                 .emit();
         }
@@ -48,11 +51,17 @@ fn check_primitive_impl(&self,
                             ty: &str,
                             span: Span) {
         match lang_def_id {
-            Some(lang_def_id) if lang_def_id == impl_def_id => { /* OK */ },
+            Some(lang_def_id) if lang_def_id == impl_def_id => {
+                // OK
+            }
             _ => {
-                struct_span_err!(self.tcx.sess, span, E0390,
-                          "only a single inherent implementation marked with `#[lang = \"{}\"]` \
-                           is allowed for the `{}` primitive", lang, ty)
+                struct_span_err!(self.tcx.sess,
+                                 span,
+                                 E0390,
+                                 "only a single inherent implementation marked with `#[lang = \
+                                  \"{}\"]` is allowed for the `{}` primitive",
+                                 lang,
+                                 ty)
                     .span_help(span, "consider using a trait to implement these methods")
                     .emit();
             }
@@ -209,12 +218,14 @@ fn check_item(&self, item: &hir::Item) {
                         return;
                     }
                     _ => {
-                        struct_span_err!(self.tcx.sess, ty.span, E0118,
+                        struct_span_err!(self.tcx.sess,
+                                         ty.span,
+                                         E0118,
                                          "no base type found for inherent implementation")
-                        .span_label(ty.span, &format!("impl requires a base type"))
-                        .note(&format!("either implement a trait on it or create a newtype \
-                                        to wrap it instead"))
-                        .emit();
+                            .span_label(ty.span, &format!("impl requires a base type"))
+                            .note(&format!("either implement a trait on it or create a newtype \
+                                            to wrap it instead"))
+                            .emit();
                         return;
                     }
                 }
@@ -226,20 +237,23 @@ fn check_item(&self, item: &hir::Item) {
                 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
                 let trait_def_id = trait_ref.def_id;
                 match traits::orphan_check(self.tcx, def_id) {
-                    Ok(()) => { }
+                    Ok(()) => {}
                     Err(traits::OrphanCheckErr::NoLocalInputType) => {
-                        struct_span_err!(
-                            self.tcx.sess, item.span, E0117,
-                             "only traits defined in the current crate can be \
-                             implemented for arbitrary types")
-                        .span_label(item.span, &format!("impl doesn't use types inside crate"))
-                        .note(&format!("the impl does not reference any \
-                                        types defined in this crate"))
-                        .emit();
+                        struct_span_err!(self.tcx.sess,
+                                         item.span,
+                                         E0117,
+                                         "only traits defined in the current crate can be \
+                                          implemented for arbitrary types")
+                            .span_label(item.span, &format!("impl doesn't use types inside crate"))
+                            .note(&format!("the impl does not reference any types defined in \
+                                            this crate"))
+                            .emit();
                         return;
                     }
                     Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
-                        span_err!(self.tcx.sess, item.span, E0210,
+                        span_err!(self.tcx.sess,
+                                  item.span,
+                                  E0210,
                                   "type parameter `{}` must be used as the type parameter for \
                                    some local type (e.g. `MyStruct<T>`); only traits defined in \
                                    the current crate can be implemented for a type parameter",
@@ -285,10 +299,8 @@ fn check_item(&self, item: &hir::Item) {
                        trait_ref,
                        trait_def_id,
                        self.tcx.trait_has_default_impl(trait_def_id));
-                if
-                    self.tcx.trait_has_default_impl(trait_def_id) &&
-                    trait_def_id.krate != LOCAL_CRATE
-                {
+                if self.tcx.trait_has_default_impl(trait_def_id) &&
+                   trait_def_id.krate != LOCAL_CRATE {
                     let self_ty = trait_ref.self_ty();
                     let opt_self_def_id = match self_ty.sty {
                         ty::TyAdt(self_def, _) => Some(self_def.did),
@@ -305,20 +317,17 @@ fn check_item(&self, item: &hir::Item) {
                             if self_def_id.is_local() {
                                 None
                             } else {
-                                Some(format!(
-                                    "cross-crate traits with a default impl, like `{}`, \
-                                     can only be implemented for a struct/enum type \
-                                     defined in the current crate",
-                                    self.tcx.item_path_str(trait_def_id)))
+                                Some(format!("cross-crate traits with a default impl, like `{}`, \
+                                              can only be implemented for a struct/enum type \
+                                              defined in the current crate",
+                                             self.tcx.item_path_str(trait_def_id)))
                             }
                         }
                         _ => {
-                            Some(format!(
-                                "cross-crate traits with a default impl, like `{}`, \
-                                 can only be implemented for a struct/enum type, \
-                                 not `{}`",
-                                self.tcx.item_path_str(trait_def_id),
-                                self_ty))
+                            Some(format!("cross-crate traits with a default impl, like `{}`, can \
+                                          only be implemented for a struct/enum type, not `{}`",
+                                         self.tcx.item_path_str(trait_def_id),
+                                         self_ty))
                         }
                     };
 
@@ -330,14 +339,18 @@ fn check_item(&self, item: &hir::Item) {
 
                 // Disallow *all* explicit impls of `Sized` and `Unsize` for now.
                 if Some(trait_def_id) == self.tcx.lang_items.sized_trait() {
-                    struct_span_err!(self.tcx.sess, item.span, E0322,
-                              "explicit impls for the `Sized` trait are not permitted")
+                    struct_span_err!(self.tcx.sess,
+                                     item.span,
+                                     E0322,
+                                     "explicit impls for the `Sized` trait are not permitted")
                         .span_label(item.span, &format!("impl of 'Sized' not allowed"))
                         .emit();
                     return;
                 }
                 if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() {
-                    span_err!(self.tcx.sess, item.span, E0328,
+                    span_err!(self.tcx.sess,
+                              item.span,
+                              E0328,
                               "explicit impls for the `Unsize` trait are not permitted");
                     return;
                 }
@@ -348,9 +361,11 @@ fn check_item(&self, item: &hir::Item) {
                        self.tcx.map.node_to_string(item.id));
                 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
                 if trait_ref.def_id.krate != LOCAL_CRATE {
-                    struct_span_err!(self.tcx.sess, item_trait_ref.path.span, E0318,
-                              "cannot create default implementations for traits outside the \
-                               crate they're defined in; define a new trait instead")
+                    struct_span_err!(self.tcx.sess,
+                                     item_trait_ref.path.span,
+                                     E0318,
+                                     "cannot create default implementations for traits outside \
+                                      the crate they're defined in; define a new trait instead")
                         .span_label(item_trait_ref.path.span,
                                     &format!("`{}` trait not defined in this crate",
                                              item_trait_ref.path))
@@ -365,7 +380,7 @@ fn check_item(&self, item: &hir::Item) {
     }
 }
 
-impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
+impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         self.check_item(item);
     }
index c42b8f8840028afecb8fdc41764c3dff85899744..1bf140c21a5a5b0f99756d38dd4837e73b99d620 100644 (file)
 use lint;
 
 pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let mut overlap = OverlapChecker { tcx: tcx,
-                                       default_impls: DefIdMap() };
+    let mut overlap = OverlapChecker {
+        tcx: tcx,
+        default_impls: DefIdMap(),
+    };
 
     // this secondary walk specifically checks for some other cases,
     // like defaulted traits, for which additional overlap rules exist
     tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
 }
 
-struct OverlapChecker<'cx, 'tcx:'cx> {
+struct OverlapChecker<'cx, 'tcx: 'cx> {
     tcx: TyCtxt<'cx, 'tcx, 'tcx>,
 
     // maps from a trait def-id to an impl id
@@ -41,18 +43,21 @@ struct OverlapChecker<'cx, 'tcx:'cx> {
 impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
     fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
         #[derive(Copy, Clone, PartialEq)]
-        enum Namespace { Type, Value }
+        enum Namespace {
+            Type,
+            Value,
+        }
 
         fn name_and_namespace<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         def_id: DefId)
-                                        -> (ast::Name, Namespace)
-        {
+                                        -> (ast::Name, Namespace) {
             let item = tcx.impl_or_trait_item(def_id);
-            (item.name(), match item {
-                ty::TypeTraitItem(..) => Namespace::Type,
-                ty::ConstTraitItem(..) => Namespace::Value,
-                ty::MethodTraitItem(..) => Namespace::Value,
-            })
+            (item.name(),
+             match item {
+                 ty::TypeTraitItem(..) => Namespace::Type,
+                 ty::ConstTraitItem(..) => Namespace::Value,
+                 ty::MethodTraitItem(..) => Namespace::Value,
+             })
         }
 
         let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow();
@@ -79,11 +84,11 @@ fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
         let inherent_impls = self.tcx.inherent_impls.borrow();
         let impls = match inherent_impls.get(&ty_def_id) {
             Some(impls) => impls,
-            None => return
+            None => return,
         };
 
         for (i, &impl1_def_id) in impls.iter().enumerate() {
-            for &impl2_def_id in &impls[(i+1)..] {
+            for &impl2_def_id in &impls[(i + 1)..] {
                 self.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
                     if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
                         self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
@@ -94,10 +99,12 @@ fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
     }
 }
 
-impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
+impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v hir::Item) {
         match item.node {
-            hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => {
+            hir::ItemEnum(..) |
+            hir::ItemStruct(..) |
+            hir::ItemUnion(..) => {
                 let type_def_id = self.tcx.map.local_def_id(item.id);
                 self.check_for_overlapping_inherent_impls(type_def_id);
             }
@@ -111,12 +118,14 @@ fn visit_item(&mut self, item: &'v hir::Item) {
 
                 let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
                 if let Some(prev_id) = prev_default_impl {
-                    let mut err = struct_span_err!(
-                        self.tcx.sess,
-                        self.tcx.span_of_impl(impl_def_id).unwrap(), E0521,
-                        "redundant default implementations of trait `{}`:",
-                        trait_ref);
-                    err.span_note(self.tcx.span_of_impl(self.tcx.map.local_def_id(prev_id))
+                    let mut err = struct_span_err!(self.tcx.sess,
+                                                   self.tcx.span_of_impl(impl_def_id).unwrap(),
+                                                   E0521,
+                                                   "redundant default implementations of trait \
+                                                    `{}`:",
+                                                   trait_ref);
+                    err.span_note(self.tcx
+                                      .span_of_impl(self.tcx.map.local_def_id(prev_id))
                                       .unwrap(),
                                   "redundant implementation is here:");
                     err.emit();
@@ -127,8 +136,8 @@ fn visit_item(&mut self, item: &'v hir::Item) {
                 let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
                 let trait_def_id = trait_ref.def_id;
 
-                let _task = self.tcx.dep_graph.in_task(
-                    DepNode::CoherenceOverlapCheck(trait_def_id));
+                let _task =
+                    self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
 
                 let def = self.tcx.lookup_trait_def(trait_def_id);
 
@@ -137,17 +146,19 @@ fn visit_item(&mut self, item: &'v hir::Item) {
 
                 // insertion failed due to overlap
                 if let Err(overlap) = insert_result {
-                    let mut err = struct_span_err!(
-                        self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0119,
-                        "conflicting implementations of trait `{}`{}:",
-                        overlap.trait_desc,
-                        overlap.self_desc.clone().map_or(String::new(),
-                                                         |ty| format!(" for type `{}`", ty)));
+                    let mut err = struct_span_err!(self.tcx.sess,
+                                                   self.tcx.span_of_impl(impl_def_id).unwrap(),
+                                                   E0119,
+                                                   "conflicting implementations of trait `{}`{}:",
+                                                   overlap.trait_desc,
+                                                   overlap.self_desc.clone().map_or(String::new(),
+                                                                                    |ty| {
+                        format!(" for type `{}`", ty)
+                    }));
 
                     match self.tcx.span_of_impl(overlap.with_impl) {
                         Ok(span) => {
-                            err.span_label(span,
-                                           &format!("first implementation here"));
+                            err.span_label(span, &format!("first implementation here"));
                             err.span_label(self.tcx.span_of_impl(impl_def_id).unwrap(),
                                            &format!("conflicting implementation{}",
                                                     overlap.self_desc
@@ -155,8 +166,7 @@ fn visit_item(&mut self, item: &'v hir::Item) {
                                                                 |ty| format!(" for `{}`", ty))));
                         }
                         Err(cname) => {
-                            err.note(&format!("conflicting implementation in crate `{}`",
-                                              cname));
+                            err.note(&format!("conflicting implementation in crate `{}`", cname));
                         }
                     }
 
@@ -177,7 +187,9 @@ fn visit_item(&mut self, item: &'v hir::Item) {
                         let mut supertrait_def_ids =
                             traits::supertrait_def_ids(self.tcx, data.principal.def_id());
                         if supertrait_def_ids.any(|d| d == trait_def_id) {
-                            span_err!(self.tcx.sess, item.span, E0371,
+                            span_err!(self.tcx.sess,
+                                      item.span,
+                                      E0371,
                                       "the object type `{}` automatically \
                                        implements the trait `{}`",
                                       trait_ref.self_ty(),
index cdf5478e692b2bc84bd6a10db881f817a0946613..ff55ce0e5eb55cea69b75aa270a9a04ea14e7e66 100644 (file)
@@ -20,21 +20,26 @@ pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     tcx.map.krate().visit_all_items(&mut orphan);
 }
 
-struct UnsafetyChecker<'cx, 'tcx:'cx> {
-    tcx: TyCtxt<'cx, 'tcx, 'tcx>
+struct UnsafetyChecker<'cx, 'tcx: 'cx> {
+    tcx: TyCtxt<'cx, 'tcx, 'tcx>,
 }
 
 impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
-    fn check_unsafety_coherence(&mut self, item: &'v hir::Item,
+    fn check_unsafety_coherence(&mut self,
+                                item: &'v hir::Item,
                                 unsafety: hir::Unsafety,
                                 polarity: hir::ImplPolarity) {
         match self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id)) {
             None => {
                 // Inherent impl.
                 match unsafety {
-                    hir::Unsafety::Normal => { /* OK */ }
+                    hir::Unsafety::Normal => {
+                        // OK
+                    }
                     hir::Unsafety::Unsafe => {
-                        span_err!(self.tcx.sess, item.span, E0197,
+                        span_err!(self.tcx.sess,
+                                  item.span,
+                                  E0197,
                                   "inherent impls cannot be declared as unsafe");
                     }
                 }
@@ -43,31 +48,33 @@ fn check_unsafety_coherence(&mut self, item: &'v hir::Item,
             Some(trait_ref) => {
                 let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id);
                 match (trait_def.unsafety, unsafety, polarity) {
-                    (hir::Unsafety::Unsafe,
-                     hir::Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
-                        span_err!(self.tcx.sess, item.span, E0198,
+                    (hir::Unsafety::Unsafe, hir::Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
+                        span_err!(self.tcx.sess,
+                                  item.span,
+                                  E0198,
                                   "negative implementations are not unsafe");
                     }
 
                     (hir::Unsafety::Normal, hir::Unsafety::Unsafe, _) => {
-                        span_err!(self.tcx.sess, item.span, E0199,
+                        span_err!(self.tcx.sess,
+                                  item.span,
+                                  E0199,
                                   "implementing the trait `{}` is not unsafe",
                                   trait_ref);
                     }
 
-                    (hir::Unsafety::Unsafe,
-                     hir::Unsafety::Normal, hir::ImplPolarity::Positive) => {
-                        span_err!(self.tcx.sess, item.span, E0200,
+                    (hir::Unsafety::Unsafe, hir::Unsafety::Normal, hir::ImplPolarity::Positive) => {
+                        span_err!(self.tcx.sess,
+                                  item.span,
+                                  E0200,
                                   "the trait `{}` requires an `unsafe impl` declaration",
                                   trait_ref);
                     }
 
-                    (hir::Unsafety::Unsafe,
-                     hir::Unsafety::Normal, hir::ImplPolarity::Negative) |
-                    (hir::Unsafety::Unsafe,
-                     hir::Unsafety::Unsafe, hir::ImplPolarity::Positive) |
+                    (hir::Unsafety::Unsafe, hir::Unsafety::Normal, hir::ImplPolarity::Negative) |
+                    (hir::Unsafety::Unsafe, hir::Unsafety::Unsafe, hir::ImplPolarity::Positive) |
                     (hir::Unsafety::Normal, hir::Unsafety::Normal, _) => {
-                        /* OK */
+                        // OK
                     }
                 }
             }
@@ -75,7 +82,7 @@ fn check_unsafety_coherence(&mut self, item: &'v hir::Item,
     }
 }
 
-impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
+impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v hir::Item) {
         match item.node {
             hir::ItemDefaultImpl(unsafety, _) => {
@@ -84,7 +91,7 @@ fn visit_item(&mut self, item: &'v hir::Item) {
             hir::ItemImpl(unsafety, polarity, ..) => {
                 self.check_unsafety_coherence(item, unsafety, polarity);
             }
-            _ => { }
+            _ => {}
         }
     }
 }
index e5d4d4a9dae2ccaaf83b754206204c4f66fd5407..cdd7bef2c7fb92c6325194f76f297044dee47dea 100644 (file)
@@ -1164,10 +1164,12 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         } else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) {
             Some(disr)
         } else {
-            span_err!(tcx.sess, v.span, E0370,
-                      "enum discriminant overflowed on value after {}; \
-                       set explicitly via {} = {} if that is desired outcome",
-                      prev_disr.unwrap(), v.node.name, wrapped_disr);
+            struct_span_err!(tcx.sess, v.span, E0370,
+                             "enum discriminant overflowed")
+                .span_label(v.span, &format!("overflowed on value after {}", prev_disr.unwrap()))
+                .note(&format!("explicitly set `{} = {}` if that is desired outcome",
+                               v.node.name, wrapped_disr))
+                .emit();
             None
         }.unwrap_or(wrapped_disr);
         prev_disr = Some(disr);
index e5c901f223ffb5a061cd21642bdb1d37d5277c59..0d6b43b59c6ad7b17371a7fefef4dcf92795dd4f 100644 (file)
@@ -3766,6 +3766,45 @@ struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8,
 ```
 "##,
 
+E0513: r##"
+The type of the variable couldn't be found out.
+
+Erroneous code example:
+
+```compile_fail,E0513
+use std::mem;
+
+unsafe {
+    let size = mem::size_of::<u32>();
+    mem::transmute_copy::<u32, [u8; size]>(&8_8);
+    // error: no type for local variable
+}
+```
+
+To fix this error, please use a constant size instead of `size`. To make
+this error more obvious, you could run:
+
+```compile_fail,E0080
+use std::mem;
+
+unsafe {
+    mem::transmute_copy::<u32, [u8; mem::size_of::<u32>()]>(&8_8);
+    // error: constant evaluation error
+}
+```
+
+So now, you can fix your code by setting the size directly:
+
+```
+use std::mem;
+
+unsafe {
+    mem::transmute_copy::<u32, [u8; 4]>(&8_8);
+    // `u32` is 4 bytes so we replace the `mem::size_of` call with its size
+}
+```
+"##,
+
 E0516: r##"
 The `typeof` keyword is currently reserved but unimplemented.
 Erroneous code example:
@@ -4064,7 +4103,6 @@ struct Simba {
     E0399, // trait items need to be implemented because the associated
            // type `{}` was overridden
     E0436, // functional record update requires a struct
-    E0513, // no type for local variable ..
     E0521, // redundant default implementations of trait
     E0533, // `{}` does not name a unit variant, unit struct or a constant
     E0562, // `impl Trait` not allowed outside of function
index 5a0c27d9c609f4cc5b0b09e4081a0707669d0c21..702d7d8b4b2ca421aac2a4bf796d7a1aeabd0d18 100644 (file)
@@ -37,7 +37,7 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::char::{MAX, from_digit, from_u32, from_u32_unchecked};
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use core::char::{EncodeUtf16, EncodeUtf8, EscapeDebug, EscapeDefault, EscapeUnicode};
+pub use core::char::{EscapeDebug, EscapeDefault, EscapeUnicode};
 
 // unstable reexports
 #[unstable(feature = "try_from", issue = "33417")]
@@ -435,50 +435,96 @@ pub fn len_utf16(self) -> usize {
         C::len_utf16(self)
     }
 
-    /// Returns an iterator over the bytes of this character as UTF-8.
+    /// Encodes this character as UTF-8 into the provided byte buffer,
+    /// and then returns the subslice of the buffer that contains the encoded character.
     ///
-    /// The returned iterator also has an `as_slice()` method to view the
-    /// encoded bytes as a byte slice.
+    /// # Panics
+    ///
+    /// Panics if the buffer is not large enough.
+    /// A buffer of length four is large enough to encode any `char`.
     ///
     /// # Examples
     ///
+    /// In both of these examples, 'ß' takes two bytes to encode.
+    ///
     /// ```
     /// #![feature(unicode)]
     ///
-    /// let iterator = 'ß'.encode_utf8();
-    /// assert_eq!(iterator.as_slice(), [0xc3, 0x9f]);
+    /// let mut b = [0; 2];
     ///
-    /// for (i, byte) in iterator.enumerate() {
-    ///     println!("byte {}: {:x}", i, byte);
-    /// }
+    /// let result = 'ß'.encode_utf8(&mut b);
+    ///
+    /// assert_eq!(result, "ß");
+    ///
+    /// assert_eq!(result.len(), 2);
+    /// ```
+    ///
+    /// A buffer that's too small:
+    ///
+    /// ```
+    /// #![feature(unicode)]
+    /// use std::thread;
+    ///
+    /// let result = thread::spawn(|| {
+    ///     let mut b = [0; 1];
+    ///
+    ///     // this panics
+    ///    'ß'.encode_utf8(&mut b);
+    /// }).join();
+    ///
+    /// assert!(result.is_err());
     /// ```
-    #[unstable(feature = "unicode", issue = "27784")]
+    #[unstable(feature = "unicode",
+               reason = "pending decision about Iterator/Writer/Reader",
+               issue = "27784")]
     #[inline]
-    pub fn encode_utf8(self) -> EncodeUtf8 {
-        C::encode_utf8(self)
+    pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
+        C::encode_utf8(self, dst)
     }
 
-    /// Returns an iterator over the `u16` entries of this character as UTF-16.
+    /// Encodes this character as UTF-16 into the provided `u16` buffer,
+    /// and then returns the subslice of the buffer that contains the encoded character.
     ///
-    /// The returned iterator also has an `as_slice()` method to view the
-    /// encoded form as a slice.
+    /// # Panics
+    ///
+    /// Panics if the buffer is not large enough.
+    /// A buffer of length 2 is large enough to encode any `char`.
     ///
     /// # Examples
     ///
+    /// In both of these examples, '𝕊' takes two `u16`s to encode.
+    ///
     /// ```
     /// #![feature(unicode)]
     ///
-    /// let iterator = '𝕊'.encode_utf16();
-    /// assert_eq!(iterator.as_slice(), [0xd835, 0xdd4a]);
+    /// let mut b = [0; 2];
     ///
-    /// for (i, val) in iterator.enumerate() {
-    ///     println!("entry {}: {:x}", i, val);
-    /// }
+    /// let result = '𝕊'.encode_utf16(&mut b);
+    ///
+    /// assert_eq!(result.len(), 2);
     /// ```
-    #[unstable(feature = "unicode", issue = "27784")]
+    ///
+    /// A buffer that's too small:
+    ///
+    /// ```
+    /// #![feature(unicode)]
+    /// use std::thread;
+    ///
+    /// let result = thread::spawn(|| {
+    ///     let mut b = [0; 1];
+    ///
+    ///     // this panics
+    ///     '𝕊'.encode_utf16(&mut b);
+    /// }).join();
+    ///
+    /// assert!(result.is_err());
+    /// ```
+    #[unstable(feature = "unicode",
+               reason = "pending decision about Iterator/Writer/Reader",
+               issue = "27784")]
     #[inline]
-    pub fn encode_utf16(self) -> EncodeUtf16 {
-        C::encode_utf16(self)
+    pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] {
+        C::encode_utf16(self, dst)
     }
 
     /// Returns true if this `char` is an alphabetic code point, and false if not.
index eb5b6feeb7ec4893e9655ec3095769a005c7c064..19e419e37a09c3be92715ae9158a8fd1c0d0207d 100644 (file)
@@ -157,13 +157,13 @@ fn next(&mut self) -> Option<u16> {
             return Some(tmp);
         }
 
+        let mut buf = [0; 2];
         self.chars.next().map(|ch| {
-            let n = CharExt::encode_utf16(ch);
-            let n = n.as_slice();
-            if n.len() == 2 {
-                self.extra = n[1];
+            let n = CharExt::encode_utf16(ch, &mut buf).len();
+            if n == 2 {
+                self.extra = buf[1];
             }
-            n[0]
+            buf[0]
         })
     }
 
index 0ae059509bd1057a6ba16d3b4d5c1f1d9a7f9353..c1ee4e61c5c72b45bf8d827c6f4def8a2ea0f56e 100644 (file)
@@ -283,34 +283,34 @@ pub fn is_crate(&self) -> bool {
         }
     }
     pub fn is_mod(&self) -> bool {
-        ItemType::from(self) == ItemType::Module
+        self.type_() == ItemType::Module
     }
     pub fn is_trait(&self) -> bool {
-        ItemType::from(self) == ItemType::Trait
+        self.type_() == ItemType::Trait
     }
     pub fn is_struct(&self) -> bool {
-        ItemType::from(self) == ItemType::Struct
+        self.type_() == ItemType::Struct
     }
     pub fn is_enum(&self) -> bool {
-        ItemType::from(self) == ItemType::Module
+        self.type_() == ItemType::Module
     }
     pub fn is_fn(&self) -> bool {
-        ItemType::from(self) == ItemType::Function
+        self.type_() == ItemType::Function
     }
     pub fn is_associated_type(&self) -> bool {
-        ItemType::from(self) == ItemType::AssociatedType
+        self.type_() == ItemType::AssociatedType
     }
     pub fn is_associated_const(&self) -> bool {
-        ItemType::from(self) == ItemType::AssociatedConst
+        self.type_() == ItemType::AssociatedConst
     }
     pub fn is_method(&self) -> bool {
-        ItemType::from(self) == ItemType::Method
+        self.type_() == ItemType::Method
     }
     pub fn is_ty_method(&self) -> bool {
-        ItemType::from(self) == ItemType::TyMethod
+        self.type_() == ItemType::TyMethod
     }
     pub fn is_primitive(&self) -> bool {
-        ItemType::from(self) == ItemType::Primitive
+        self.type_() == ItemType::Primitive
     }
     pub fn is_stripped(&self) -> bool {
         match self.inner { StrippedItem(..) => true, _ => false }
@@ -342,6 +342,11 @@ pub fn stability_class(&self) -> String {
     pub fn stable_since(&self) -> Option<&str> {
         self.stability.as_ref().map(|s| &s.since[..])
     }
+
+    /// Returns a documentation-level item type from the item.
+    pub fn type_(&self) -> ItemType {
+        ItemType::from(self)
+    }
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
@@ -1646,8 +1651,8 @@ fn clean(&self, cx: &DocContext) -> Type {
             TyRptr(ref l, ref m) =>
                 BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
                              type_: box m.ty.clean(cx)},
-            TyVec(ref ty) => Vector(box ty.clean(cx)),
-            TyFixedLengthVec(ref ty, ref e) => {
+            TySlice(ref ty) => Vector(box ty.clean(cx)),
+            TyArray(ref ty, ref e) => {
                 let n = if let Some(tcx) = cx.tcx_opt() {
                     use rustc_const_math::{ConstInt, ConstUsize};
                     use rustc_const_eval::eval_const_expr;
@@ -2699,7 +2704,7 @@ fn name_from_pat(p: &hir::Pat) -> String {
         },
         PatKind::Range(..) => panic!("tried to get argument name from PatKind::Range, \
                               which is not allowed in function arguments"),
-        PatKind::Vec(ref begin, ref mid, ref end) => {
+        PatKind::Slice(ref begin, ref mid, ref end) => {
             let begin = begin.iter().map(|p| name_from_pat(&**p));
             let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
             let end = end.iter().map(|p| name_from_pat(&**p));
index c52497dc89bd6b7c824ff2b3acc0010afddee7ab..49e467e5cbe3bba50bfc813ac45cce9c3354781a 100644 (file)
@@ -32,6 +32,7 @@
 use std::cell::{RefCell, Cell};
 use std::mem;
 use std::rc::Rc;
+use std::path::PathBuf;
 
 use visit_ast::RustdocVisitor;
 use clean;
@@ -127,7 +128,8 @@ pub fn run_core(search_paths: SearchPaths,
                 cfgs: Vec<String>,
                 externs: config::Externs,
                 input: Input,
-                triple: Option<String>) -> (clean::Crate, RenderInfo)
+                triple: Option<String>,
+                maybe_sysroot: Option<PathBuf>) -> (clean::Crate, RenderInfo)
 {
     // Parse, resolve, and typecheck the given crate.
 
@@ -139,7 +141,7 @@ pub fn run_core(search_paths: SearchPaths,
     let warning_lint = lint::builtin::WARNINGS.name_lower();
 
     let sessopts = config::Options {
-        maybe_sysroot: None,
+        maybe_sysroot: maybe_sysroot,
         search_paths: search_paths,
         crate_types: vec!(config::CrateTypeRlib),
         lint_opts: vec!((warning_lint, lint::Allow)),
index aff5a964f75cc297053b69a0213b43ff48bc21e0..e9a1f650c9b2f30d4d5250960366cc29725e36ed 100644 (file)
@@ -27,7 +27,6 @@
 #![allow(non_camel_case_types)]
 
 use libc;
-use rustc::session::config::get_unstable_features_setting;
 use std::ascii::AsciiExt;
 use std::cell::RefCell;
 use std::default::Default;
@@ -478,13 +477,10 @@ fn parse(string: &str) -> LangString {
         let mut data = LangString::all_false();
         let mut allow_compile_fail = false;
         let mut allow_error_code_check = false;
-        match get_unstable_features_setting() {
-            UnstableFeatures::Allow | UnstableFeatures::Cheat => {
-                allow_compile_fail = true;
-                allow_error_code_check = true;
-            }
-            _ => {},
-        };
+        if UnstableFeatures::from_environment().is_nightly_build() {
+            allow_compile_fail = true;
+            allow_error_code_check = true;
+        }
 
         let tokens = string.split(|c: char|
             !(c == '_' || c == '-' || c.is_alphanumeric())
index 03d772d1a6db3f0294cfc088e306d37d1cfb1b2a..46461226381a3e04b5fb314f94fdc9a92d7d45ea 100644 (file)
@@ -58,7 +58,6 @@
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
 use rustc::middle::privacy::AccessLevels;
 use rustc::middle::stability;
-use rustc::session::config::get_unstable_features_setting;
 use rustc::hir;
 use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
 use rustc_data_structures::flock;
@@ -90,9 +89,6 @@ pub struct Context {
     /// Current hierarchy of components leading down to what's currently being
     /// rendered
     pub current: Vec<String>,
-    /// String representation of how to get back to the root path of the 'doc/'
-    /// folder in terms of a relative URL.
-    pub root_path: String,
     /// The current destination folder of where HTML artifacts should be placed.
     /// This changes as the context descends into the module hierarchy.
     pub dst: PathBuf,
@@ -497,7 +493,6 @@ pub fn run(mut krate: clean::Crate,
     krate = render_sources(&dst, &mut scx, krate)?;
     let cx = Context {
         current: Vec::new(),
-        root_path: String::new(),
         dst: dst,
         render_redirect_pages: false,
         shared: Arc::new(scx),
@@ -592,7 +587,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
     for &(did, ref item) in orphan_impl_items {
         if let Some(&(ref fqp, _)) = paths.get(&did) {
             search_index.push(IndexItem {
-                ty: item_type(item),
+                ty: item.type_(),
                 name: item.name.clone().unwrap(),
                 path: fqp[..fqp.len() - 1].join("::"),
                 desc: Escape(&shorter(item.doc_value())).to_string(),
@@ -836,11 +831,6 @@ fn mkdir(path: &Path) -> io::Result<()> {
     }
 }
 
-/// Returns a documentation-level item type from the item.
-fn item_type(item: &clean::Item) -> ItemType {
-    ItemType::from(item)
-}
-
 /// Takes a path to a source file and cleans the path to it. This canonicalizes
 /// things like ".." to components which preserve the "top down" hierarchy of a
 /// static HTML tree. Each component in the cleaned path will be passed as an
@@ -1076,7 +1066,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                     // inserted later on when serializing the search-index.
                     if item.def_id.index != CRATE_DEF_INDEX {
                         self.search_index.push(IndexItem {
-                            ty: item_type(&item),
+                            ty: item.type_(),
                             name: s.to_string(),
                             path: path.join("::").to_string(),
                             desc: Escape(&shorter(item.doc_value())).to_string(),
@@ -1123,7 +1113,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                     self.access_levels.is_public(item.def_id)
                 {
                     self.paths.insert(item.def_id,
-                                      (self.stack.clone(), item_type(&item)));
+                                      (self.stack.clone(), item.type_()));
                 }
             }
             // link variants to their parent enum because pages aren't emitted
@@ -1136,7 +1126,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
 
             clean::PrimitiveItem(..) if item.visibility.is_some() => {
                 self.paths.insert(item.def_id, (self.stack.clone(),
-                                                item_type(&item)));
+                                                item.type_()));
             }
 
             _ => {}
@@ -1231,6 +1221,12 @@ fn generics(&mut self, generics: &clean::Generics) {
 }
 
 impl Context {
+    /// String representation of how to get back to the root path of the 'doc/'
+    /// folder in terms of a relative URL.
+    fn root_path(&self) -> String {
+        repeat("../").take(self.current.len()).collect::<String>()
+    }
+
     /// Recurse in the directory structure and change the "root path" to make
     /// sure it always points to the top (relatively)
     fn recurse<T, F>(&mut self, s: String, f: F) -> T where
@@ -1241,7 +1237,6 @@ fn recurse<T, F>(&mut self, s: String, f: F) -> T where
         }
         let prev = self.dst.clone();
         self.dst.push(&s);
-        self.root_path.push_str("../");
         self.current.push(s);
 
         info!("Recursing into {}", self.dst.display());
@@ -1252,8 +1247,6 @@ fn recurse<T, F>(&mut self, s: String, f: F) -> T where
 
         // Go back to where we were at
         self.dst = prev;
-        let len = self.root_path.len();
-        self.root_path.truncate(len - 3);
         self.current.pop().unwrap();
 
         return ret;
@@ -1305,7 +1298,7 @@ fn render_item(&self,
             title.push_str(it.name.as_ref().unwrap());
         }
         title.push_str(" - Rust");
-        let tyname = item_type(it).css_class();
+        let tyname = it.type_().css_class();
         let desc = if it.is_crate() {
             format!("API documentation for the Rust `{}` crate.",
                     self.shared.layout.krate)
@@ -1316,7 +1309,7 @@ fn render_item(&self,
         let keywords = make_item_keywords(it);
         let page = layout::Page {
             css_class: tyname,
-            root_path: &self.root_path,
+            root_path: &self.root_path(),
             title: &title,
             description: &desc,
             keywords: &keywords,
@@ -1330,8 +1323,7 @@ fn render_item(&self,
                            &Item{ cx: self, item: it },
                            self.shared.css_file_extension.is_some())?;
         } else {
-            let mut url = repeat("../").take(self.current.len())
-                                       .collect::<String>();
+            let mut url = self.root_path();
             if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) {
                 for name in &names[..names.len() - 1] {
                     url.push_str(name);
@@ -1408,7 +1400,7 @@ fn item<F>(&mut self, item: clean::Item, mut f: F) -> Result<(), Error> where
             // buf will be empty if the item is stripped and there is no redirect for it
             if !buf.is_empty() {
                 let name = item.name.as_ref().unwrap();
-                let item_type = item_type(&item);
+                let item_type = item.type_();
                 let file_name = &item_path(item_type, name);
                 let joint_dst = self.dst.join(file_name);
                 try_err!(fs::create_dir_all(&self.dst), &self.dst);
@@ -1445,7 +1437,7 @@ fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<NameDoc
         for item in &m.items {
             if maybe_ignore_item(item) { continue }
 
-            let short = item_type(item).css_class();
+            let short = item.type_().css_class();
             let myname = match item.name {
                 None => continue,
                 Some(ref s) => s.to_string(),
@@ -1493,7 +1485,7 @@ fn href(&self) -> Option<String> {
             }).map(|l| &l.1);
             let root = match root {
                 Some(&Remote(ref s)) => s.to_string(),
-                Some(&Local) => self.cx.root_path.clone(),
+                Some(&Local) => self.cx.root_path(),
                 None | Some(&Unknown) => return None,
             };
             Some(format!("{root}/{krate}/macro.{name}.html?gotomacrosrc=1",
@@ -1508,7 +1500,7 @@ fn href(&self) -> Option<String> {
             let path = PathBuf::from(&self.item.source.filename);
             self.cx.shared.local_sources.get(&path).map(|path| {
                 format!("{root}src/{krate}/{path}#{href}",
-                        root = self.cx.root_path,
+                        root = self.cx.root_path(),
                         krate = self.cx.shared.layout.krate,
                         path = path,
                         href = href)
@@ -1532,7 +1524,7 @@ fn href(&self) -> Option<String> {
             };
             let mut path = match cache.extern_locations.get(&self.item.def_id.krate) {
                 Some(&(_, Remote(ref s))) => s.to_string(),
-                Some(&(_, Local)) => self.cx.root_path.clone(),
+                Some(&(_, Local)) => self.cx.root_path(),
                 Some(&(_, Unknown)) => return None,
                 None => return None,
             };
@@ -1542,7 +1534,7 @@ fn href(&self) -> Option<String> {
             }
             Some(format!("{path}{file}?gotosrc={goto}",
                          path = path,
-                         file = item_path(item_type(self.item), external_path.last().unwrap()),
+                         file = item_path(self.item.type_(), external_path.last().unwrap()),
                          goto = self.item.def_id.index.as_usize()))
         }
     }
@@ -1587,7 +1579,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
             }
         }
         write!(fmt, "<a class='{}' href=''>{}</a>",
-               item_type(self.item), self.item.name.as_ref().unwrap())?;
+               self.item.type_(), self.item.name.as_ref().unwrap())?;
 
         write!(fmt, "</span>")?; // in-band
         write!(fmt, "<span class='out-of-band'>")?;
@@ -1740,8 +1732,8 @@ fn reorder(ty: ItemType) -> u8 {
     }
 
     fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering {
-        let ty1 = item_type(i1);
-        let ty2 = item_type(i2);
+        let ty1 = i1.type_();
+        let ty2 = i2.type_();
         if ty1 != ty2 {
             return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2))
         }
@@ -1765,7 +1757,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
             continue;
         }
 
-        let myty = Some(item_type(myitem));
+        let myty = Some(myitem.type_());
         if curty == Some(ItemType::ExternCrate) && myty == Some(ItemType::Import) {
             // Put `extern crate` and `use` re-exports in the same section.
             curty = myty;
@@ -1852,9 +1844,9 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                        name = *myitem.name.as_ref().unwrap(),
                        stab_docs = stab_docs,
                        docs = shorter(Some(&Markdown(doc_value).to_string())),
-                       class = item_type(myitem),
+                       class = myitem.type_(),
                        stab = myitem.stability_class(),
-                       href = item_path(item_type(myitem), myitem.name.as_ref().unwrap()),
+                       href = item_path(myitem.type_(), myitem.name.as_ref().unwrap()),
                        title = full_path(cx, myitem))?;
             }
         }
@@ -1971,7 +1963,7 @@ fn item_static(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
 fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                  f: &clean::Function) -> fmt::Result {
     // FIXME(#24111): remove when `const_fn` is stabilized
-    let vis_constness = match get_unstable_features_setting() {
+    let vis_constness = match UnstableFeatures::from_environment() {
         UnstableFeatures::Allow => f.constness,
         _ => hir::Constness::NotConst
     };
@@ -2060,7 +2052,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::Item)
                   -> fmt::Result {
         let name = m.name.as_ref().unwrap();
-        let item_type = item_type(m);
+        let item_type = m.type_();
         let id = derive_id(format!("{}.{}", item_type, name));
         let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
         write!(w, "<h3 id='{id}' class='method stab {stab}'>\
@@ -2146,7 +2138,7 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
                let (ref path, _) = cache.external_paths[&it.def_id];
                path[..path.len() - 1].join("/")
            },
-           ty = item_type(it).css_class(),
+           ty = it.type_().css_class(),
            name = *it.name.as_ref().unwrap())?;
     Ok(())
 }
@@ -2155,7 +2147,7 @@ fn naive_assoc_href(it: &clean::Item, link: AssocItemLink) -> String {
     use html::item_type::ItemType::*;
 
     let name = it.name.as_ref().unwrap();
-    let ty = match item_type(it) {
+    let ty = match it.type_() {
         Typedef | AssociatedType => AssociatedType,
         s@_ => s,
     };
@@ -2233,7 +2225,7 @@ fn method(w: &mut fmt::Formatter,
               link: AssocItemLink)
               -> fmt::Result {
         let name = meth.name.as_ref().unwrap();
-        let anchor = format!("#{}.{}", item_type(meth), name);
+        let anchor = format!("#{}.{}", meth.type_(), name);
         let href = match link {
             AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
             AssocItemLink::Anchor(None) => anchor,
@@ -2250,7 +2242,7 @@ fn method(w: &mut fmt::Formatter,
             }
         };
         // FIXME(#24111): remove when `const_fn` is stabilized
-        let vis_constness = match get_unstable_features_setting() {
+        let vis_constness = match UnstableFeatures::from_environment() {
             UnstableFeatures::Allow => constness,
             _ => hir::Constness::NotConst
         };
@@ -2741,7 +2733,7 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
                      link: AssocItemLink, render_mode: RenderMode,
                      is_default_item: bool, outer_version: Option<&str>,
                      trait_: Option<&clean::Trait>) -> fmt::Result {
-        let item_type = item_type(item);
+        let item_type = item.type_();
         let name = item.name.as_ref().unwrap();
 
         let render_method_item: bool = match render_mode {
@@ -2919,7 +2911,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                 write!(fmt, "::<wbr>")?;
             }
             write!(fmt, "<a href='{}index.html'>{}</a>",
-                   &cx.root_path[..(cx.current.len() - i - 1) * 3],
+                   &cx.root_path()[..(cx.current.len() - i - 1) * 3],
                    *name)?;
         }
         write!(fmt, "</p>")?;
@@ -2933,7 +2925,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                    relpath: '{path}'\
                 }};</script>",
                name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""),
-               ty = item_type(it).css_class(),
+               ty = it.type_().css_class(),
                path = relpath)?;
         if parentlen == 0 {
             // there is no sidebar-items.js beyond the crate root path
index 9a6cded5b4ce7d2927f357968535dac4bfbd235a..cad5fae690fb817d3baf3b313945c29e10dc3b96 100644 (file)
@@ -378,6 +378,11 @@ h4 > code, h3 > code, .invisible > code {
     font-size: 90%;
 }
 
+/* Shift where in trait listing down a line */
+pre.trait .where::before {
+    content: '\a         ';
+}
+
 nav {
     border-bottom: 1px solid;
     padding-bottom: 10px;
index cc5cdf9f4e74cb19337732523bc8bc1df62f37cc..1ff84b95da6a4c54414f9418b5a0d84d1dfd2e0c 100644 (file)
@@ -91,31 +91,6 @@ pub mod html {
 
 use clean::Attributes;
 
-type Pass = (&'static str,                                      // name
-             fn(clean::Crate) -> plugins::PluginResult,         // fn
-             &'static str);                                     // description
-
-const PASSES: &'static [Pass] = &[
-    ("strip-hidden", passes::strip_hidden,
-     "strips all doc(hidden) items from the output"),
-    ("unindent-comments", passes::unindent_comments,
-     "removes excess indentation on comments in order for markdown to like it"),
-    ("collapse-docs", passes::collapse_docs,
-     "concatenates all document attributes into one document attribute"),
-    ("strip-private", passes::strip_private,
-     "strips all private items from a crate which cannot be seen externally, \
-      implies strip-priv-imports"),
-    ("strip-priv-imports", passes::strip_priv_imports,
-     "strips all private import statements (`use`, `extern crate`) from a crate"),
-];
-
-const DEFAULT_PASSES: &'static [&'static str] = &[
-    "strip-hidden",
-    "strip-private",
-    "collapse-docs",
-    "unindent-comments",
-];
-
 struct Output {
     krate: clean::Crate,
     renderinfo: html::render::RenderInfo,
@@ -123,7 +98,7 @@ struct Output {
 }
 
 pub fn main() {
-    const STACK_SIZE: usize = 32000000; // 32MB
+    const STACK_SIZE: usize = 32_000_000; // 32MB
     let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || {
         let s = env::args().collect::<Vec<_>>();
         main_args(&s)
@@ -186,6 +161,7 @@ pub fn opts() -> Vec<RustcOptGroup> {
                          own theme", "PATH")),
         unstable(optmulti("Z", "",
                           "internal and debugging options (only on nightly build)", "FLAG")),
+        stable(optopt("", "sysroot", "Override the system root", "PATH")),
     )
 }
 
@@ -222,11 +198,11 @@ pub fn main_args(args: &[String]) -> isize {
 
     if matches.opt_strs("passes") == ["list"] {
         println!("Available passes for running rustdoc:");
-        for &(name, _, description) in PASSES {
+        for &(name, _, description) in passes::PASSES {
             println!("{:>20} - {}", name, description);
         }
         println!("\nDefault passes for rustdoc:");
-        for &name in DEFAULT_PASSES {
+        for &name in passes::DEFAULT_PASSES {
             println!("{:>20}", name);
         }
         return 0;
@@ -235,7 +211,8 @@ pub fn main_args(args: &[String]) -> isize {
     if matches.free.is_empty() {
         println!("expected an input file to act on");
         return 1;
-    } if matches.free.len() > 1 {
+    }
+    if matches.free.len() > 1 {
         println!("only one input file may be specified");
         return 1;
     }
@@ -370,6 +347,7 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) ->
     }
     let cfgs = matches.opt_strs("cfg");
     let triple = matches.opt_str("target");
+    let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
 
     let cr = PathBuf::from(cratefile);
     info!("starting to run rustc");
@@ -379,7 +357,7 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) ->
         use rustc::session::config::Input;
 
         tx.send(core::run_core(paths, cfgs, externs, Input::File(cr),
-                               triple)).unwrap();
+                               triple, maybe_sysroot)).unwrap();
     });
     let (mut krate, renderinfo) = rx.recv().unwrap();
     info!("finished with rustc");
@@ -410,7 +388,7 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) ->
     }
 
     if default_passes {
-        for name in DEFAULT_PASSES.iter().rev() {
+        for name in passes::DEFAULT_PASSES.iter().rev() {
             passes.insert(0, name.to_string());
         }
     }
@@ -420,11 +398,11 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) ->
                       .unwrap_or("/tmp/rustdoc/plugins".to_string());
     let mut pm = plugins::PluginManager::new(PathBuf::from(path));
     for pass in &passes {
-        let plugin = match PASSES.iter()
-                                 .position(|&(p, ..)| {
-                                     p == *pass
-                                 }) {
-            Some(i) => PASSES[i].1,
+        let plugin = match passes::PASSES.iter()
+                                         .position(|&(p, ..)| {
+                                             p == *pass
+                                         }) {
+            Some(i) => passes::PASSES[i].1,
             None => {
                 error!("unknown pass {}, skipping", *pass);
                 continue
diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs
deleted file mode 100644 (file)
index c60e228..0000000
+++ /dev/null
@@ -1,416 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use rustc::hir::def_id::DefId;
-use rustc::middle::privacy::AccessLevels;
-use rustc::util::nodemap::DefIdSet;
-use std::cmp;
-use std::mem;
-use std::string::String;
-use std::usize;
-
-use clean::{self, Attributes, GetDefId};
-use clean::Item;
-use plugins;
-use fold;
-use fold::DocFolder;
-use fold::FoldItem::Strip;
-
-/// Strip items marked `#[doc(hidden)]`
-pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
-    let mut retained = DefIdSet();
-
-    // strip all #[doc(hidden)] items
-    let krate = {
-        struct Stripper<'a> {
-            retained: &'a mut DefIdSet,
-            update_retained: bool,
-        }
-        impl<'a> fold::DocFolder for Stripper<'a> {
-            fn fold_item(&mut self, i: Item) -> Option<Item> {
-                if i.attrs.list("doc").has_word("hidden") {
-                    debug!("found one in strip_hidden; removing");
-                    // use a dedicated hidden item for given item type if any
-                    match i.inner {
-                        clean::StructFieldItem(..) | clean::ModuleItem(..) => {
-                            // We need to recurse into stripped modules to
-                            // strip things like impl methods but when doing so
-                            // we must not add any items to the `retained` set.
-                            let old = mem::replace(&mut self.update_retained, false);
-                            let ret = Strip(self.fold_item_recur(i).unwrap()).fold();
-                            self.update_retained = old;
-                            return ret;
-                        }
-                        _ => return None,
-                    }
-                } else {
-                    if self.update_retained {
-                        self.retained.insert(i.def_id);
-                    }
-                }
-                self.fold_item_recur(i)
-            }
-        }
-        let mut stripper = Stripper{ retained: &mut retained, update_retained: true };
-        stripper.fold_crate(krate)
-    };
-
-    // strip all impls referencing stripped items
-    let mut stripper = ImplStripper { retained: &retained };
-    stripper.fold_crate(krate)
-}
-
-/// Strip private items from the point of view of a crate or externally from a
-/// crate, specified by the `xcrate` flag.
-pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
-    // This stripper collects all *retained* nodes.
-    let mut retained = DefIdSet();
-    let access_levels = krate.access_levels.clone();
-
-    // strip all private items
-    {
-        let mut stripper = Stripper {
-            retained: &mut retained,
-            access_levels: &access_levels,
-            update_retained: true,
-        };
-        krate = ImportStripper.fold_crate(stripper.fold_crate(krate));
-    }
-
-    // strip all impls referencing private items
-    let mut stripper = ImplStripper { retained: &retained };
-    stripper.fold_crate(krate)
-}
-
-struct Stripper<'a> {
-    retained: &'a mut DefIdSet,
-    access_levels: &'a AccessLevels<DefId>,
-    update_retained: bool,
-}
-
-impl<'a> fold::DocFolder for Stripper<'a> {
-    fn fold_item(&mut self, i: Item) -> Option<Item> {
-        match i.inner {
-            clean::StrippedItem(..) => {
-                // We need to recurse into stripped modules to strip things
-                // like impl methods but when doing so we must not add any
-                // items to the `retained` set.
-                let old = mem::replace(&mut self.update_retained, false);
-                let ret = self.fold_item_recur(i);
-                self.update_retained = old;
-                return ret;
-            }
-            // These items can all get re-exported
-            clean::TypedefItem(..) | clean::StaticItem(..) |
-            clean::StructItem(..) | clean::EnumItem(..) |
-            clean::TraitItem(..) | clean::FunctionItem(..) |
-            clean::VariantItem(..) | clean::MethodItem(..) |
-            clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
-            clean::ConstantItem(..) | clean::UnionItem(..) => {
-                if i.def_id.is_local() {
-                    if !self.access_levels.is_exported(i.def_id) {
-                        return None;
-                    }
-                }
-            }
-
-            clean::StructFieldItem(..) => {
-                if i.visibility != Some(clean::Public) {
-                    return Strip(i).fold();
-                }
-            }
-
-            clean::ModuleItem(..) => {
-                if i.def_id.is_local() && i.visibility != Some(clean::Public) {
-                    let old = mem::replace(&mut self.update_retained, false);
-                    let ret = Strip(self.fold_item_recur(i).unwrap()).fold();
-                    self.update_retained = old;
-                    return ret;
-                }
-            }
-
-            // handled in the `strip-priv-imports` pass
-            clean::ExternCrateItem(..) | clean::ImportItem(..) => {}
-
-            clean::DefaultImplItem(..) | clean::ImplItem(..) => {}
-
-            // tymethods/macros have no control over privacy
-            clean::MacroItem(..) | clean::TyMethodItem(..) => {}
-
-            // Primitives are never stripped
-            clean::PrimitiveItem(..) => {}
-
-            // Associated consts and types are never stripped
-            clean::AssociatedConstItem(..) |
-            clean::AssociatedTypeItem(..) => {}
-        }
-
-        let fastreturn = match i.inner {
-            // nothing left to do for traits (don't want to filter their
-            // methods out, visibility controlled by the trait)
-            clean::TraitItem(..) => true,
-
-            // implementations of traits are always public.
-            clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
-            // Struct variant fields have inherited visibility
-            clean::VariantItem(clean::Variant {
-                kind: clean::StructVariant(..)
-            }) => true,
-            _ => false,
-        };
-
-        let i = if fastreturn {
-            if self.update_retained {
-                self.retained.insert(i.def_id);
-            }
-            return Some(i);
-        } else {
-            self.fold_item_recur(i)
-        };
-
-        i.and_then(|i| {
-            match i.inner {
-                // emptied modules have no need to exist
-                clean::ModuleItem(ref m)
-                    if m.items.is_empty() &&
-                       i.doc_value().is_none() => None,
-                _ => {
-                    if self.update_retained {
-                        self.retained.insert(i.def_id);
-                    }
-                    Some(i)
-                }
-            }
-        })
-    }
-}
-
-// This stripper discards all impls which reference stripped items
-struct ImplStripper<'a> {
-    retained: &'a DefIdSet
-}
-
-impl<'a> fold::DocFolder for ImplStripper<'a> {
-    fn fold_item(&mut self, i: Item) -> Option<Item> {
-        if let clean::ImplItem(ref imp) = i.inner {
-            // emptied none trait impls can be stripped
-            if imp.trait_.is_none() && imp.items.is_empty() {
-                return None;
-            }
-            if let Some(did) = imp.for_.def_id() {
-                if did.is_local() && !imp.for_.is_generic() &&
-                    !self.retained.contains(&did)
-                {
-                    return None;
-                }
-            }
-            if let Some(did) = imp.trait_.def_id() {
-                if did.is_local() && !self.retained.contains(&did) {
-                    return None;
-                }
-            }
-        }
-        self.fold_item_recur(i)
-    }
-}
-
-// This stripper discards all private import statements (`use`, `extern crate`)
-struct ImportStripper;
-impl fold::DocFolder for ImportStripper {
-    fn fold_item(&mut self, i: Item) -> Option<Item> {
-        match i.inner {
-            clean::ExternCrateItem(..) |
-            clean::ImportItem(..) if i.visibility != Some(clean::Public) => None,
-            _ => self.fold_item_recur(i)
-        }
-    }
-}
-
-pub fn strip_priv_imports(krate: clean::Crate)  -> plugins::PluginResult {
-    ImportStripper.fold_crate(krate)
-}
-
-pub fn unindent_comments(krate: clean::Crate) -> plugins::PluginResult {
-    struct CommentCleaner;
-    impl fold::DocFolder for CommentCleaner {
-        fn fold_item(&mut self, mut i: Item) -> Option<Item> {
-            let mut avec: Vec<clean::Attribute> = Vec::new();
-            for attr in &i.attrs {
-                match attr {
-                    &clean::NameValue(ref x, ref s)
-                            if "doc" == *x => {
-                        avec.push(clean::NameValue("doc".to_string(),
-                                                   unindent(s)))
-                    }
-                    x => avec.push(x.clone())
-                }
-            }
-            i.attrs = avec;
-            self.fold_item_recur(i)
-        }
-    }
-    let mut cleaner = CommentCleaner;
-    let krate = cleaner.fold_crate(krate);
-    krate
-}
-
-pub fn collapse_docs(krate: clean::Crate) -> plugins::PluginResult {
-    struct Collapser;
-    impl fold::DocFolder for Collapser {
-        fn fold_item(&mut self, mut i: Item) -> Option<Item> {
-            let mut docstr = String::new();
-            for attr in &i.attrs {
-                if let clean::NameValue(ref x, ref s) = *attr {
-                    if "doc" == *x {
-                        docstr.push_str(s);
-                        docstr.push('\n');
-                    }
-                }
-            }
-            let mut a: Vec<clean::Attribute> = i.attrs.iter().filter(|&a| match a {
-                &clean::NameValue(ref x, _) if "doc" == *x => false,
-                _ => true
-            }).cloned().collect();
-            if !docstr.is_empty() {
-                a.push(clean::NameValue("doc".to_string(), docstr));
-            }
-            i.attrs = a;
-            self.fold_item_recur(i)
-        }
-    }
-    let mut collapser = Collapser;
-    let krate = collapser.fold_crate(krate);
-    krate
-}
-
-pub fn unindent(s: &str) -> String {
-    let lines = s.lines().collect::<Vec<&str> >();
-    let mut saw_first_line = false;
-    let mut saw_second_line = false;
-    let min_indent = lines.iter().fold(usize::MAX, |min_indent, line| {
-
-        // After we see the first non-whitespace line, look at
-        // the line we have. If it is not whitespace, and therefore
-        // part of the first paragraph, then ignore the indentation
-        // level of the first line
-        let ignore_previous_indents =
-            saw_first_line &&
-            !saw_second_line &&
-            !line.chars().all(|c| c.is_whitespace());
-
-        let min_indent = if ignore_previous_indents {
-            usize::MAX
-        } else {
-            min_indent
-        };
-
-        if saw_first_line {
-            saw_second_line = true;
-        }
-
-        if line.chars().all(|c| c.is_whitespace()) {
-            min_indent
-        } else {
-            saw_first_line = true;
-            let mut whitespace = 0;
-            line.chars().all(|char| {
-                // Compare against either space or tab, ignoring whether they
-                // are mixed or not
-                if char == ' ' || char == '\t' {
-                    whitespace += 1;
-                    true
-                } else {
-                    false
-                }
-            });
-            cmp::min(min_indent, whitespace)
-        }
-    });
-
-    if !lines.is_empty() {
-        let mut unindented = vec![ lines[0].trim().to_string() ];
-        unindented.extend_from_slice(&lines[1..].iter().map(|&line| {
-            if line.chars().all(|c| c.is_whitespace()) {
-                line.to_string()
-            } else {
-                assert!(line.len() >= min_indent);
-                line[min_indent..].to_string()
-            }
-        }).collect::<Vec<_>>());
-        unindented.join("\n")
-    } else {
-        s.to_string()
-    }
-}
-
-#[cfg(test)]
-mod unindent_tests {
-    use super::unindent;
-
-    #[test]
-    fn should_unindent() {
-        let s = "    line1\n    line2".to_string();
-        let r = unindent(&s);
-        assert_eq!(r, "line1\nline2");
-    }
-
-    #[test]
-    fn should_unindent_multiple_paragraphs() {
-        let s = "    line1\n\n    line2".to_string();
-        let r = unindent(&s);
-        assert_eq!(r, "line1\n\nline2");
-    }
-
-    #[test]
-    fn should_leave_multiple_indent_levels() {
-        // Line 2 is indented another level beyond the
-        // base indentation and should be preserved
-        let s = "    line1\n\n        line2".to_string();
-        let r = unindent(&s);
-        assert_eq!(r, "line1\n\n    line2");
-    }
-
-    #[test]
-    fn should_ignore_first_line_indent() {
-        // The first line of the first paragraph may not be indented as
-        // far due to the way the doc string was written:
-        //
-        // #[doc = "Start way over here
-        //          and continue here"]
-        let s = "line1\n    line2".to_string();
-        let r = unindent(&s);
-        assert_eq!(r, "line1\nline2");
-    }
-
-    #[test]
-    fn should_not_ignore_first_line_indent_in_a_single_line_para() {
-        let s = "line1\n\n    line2".to_string();
-        let r = unindent(&s);
-        assert_eq!(r, "line1\n\n    line2");
-    }
-
-    #[test]
-    fn should_unindent_tabs() {
-        let s = "\tline1\n\tline2".to_string();
-        let r = unindent(&s);
-        assert_eq!(r, "line1\nline2");
-    }
-
-    #[test]
-    fn should_trim_mixed_indentation() {
-        let s = "\t    line1\n\t    line2".to_string();
-        let r = unindent(&s);
-        assert_eq!(r, "line1\nline2");
-
-        let s = "    \tline1\n    \tline2".to_string();
-        let r = unindent(&s);
-        assert_eq!(r, "line1\nline2");
-    }
-}
diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs
new file mode 100644 (file)
index 0000000..c034ef9
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::string::String;
+
+use clean::{self, Item};
+use plugins;
+use fold;
+use fold::DocFolder;
+
+pub fn collapse_docs(krate: clean::Crate) -> plugins::PluginResult {
+    let mut collapser = Collapser;
+    let krate = collapser.fold_crate(krate);
+    krate
+}
+
+struct Collapser;
+
+impl fold::DocFolder for Collapser {
+    fn fold_item(&mut self, mut i: Item) -> Option<Item> {
+        let mut docstr = String::new();
+        for attr in &i.attrs {
+            if let clean::NameValue(ref x, ref s) = *attr {
+                if "doc" == *x {
+                    docstr.push_str(s);
+                    docstr.push('\n');
+                }
+            }
+        }
+        let mut a: Vec<clean::Attribute> = i.attrs.iter().filter(|&a| match a {
+            &clean::NameValue(ref x, _) if "doc" == *x => false,
+            _ => true
+        }).cloned().collect();
+        if !docstr.is_empty() {
+            a.push(clean::NameValue("doc".to_string(), docstr));
+        }
+        i.attrs = a;
+        self.fold_item_recur(i)
+    }
+}
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
new file mode 100644 (file)
index 0000000..a1b330e
--- /dev/null
@@ -0,0 +1,204 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::hir::def_id::DefId;
+use rustc::middle::privacy::AccessLevels;
+use rustc::util::nodemap::DefIdSet;
+use std::mem;
+
+use clean::{self, GetDefId, Item};
+use fold;
+use fold::FoldItem::Strip;
+use plugins;
+
+mod collapse_docs;
+pub use self::collapse_docs::collapse_docs;
+
+mod strip_hidden;
+pub use self::strip_hidden::strip_hidden;
+
+mod strip_private;
+pub use self::strip_private::strip_private;
+
+mod strip_priv_imports;
+pub use self::strip_priv_imports::strip_priv_imports;
+
+mod unindent_comments;
+pub use self::unindent_comments::unindent_comments;
+
+type Pass = (&'static str,                                      // name
+             fn(clean::Crate) -> plugins::PluginResult,         // fn
+             &'static str);                                     // description
+
+pub const PASSES: &'static [Pass] = &[
+    ("strip-hidden", strip_hidden,
+     "strips all doc(hidden) items from the output"),
+    ("unindent-comments", unindent_comments,
+     "removes excess indentation on comments in order for markdown to like it"),
+    ("collapse-docs", collapse_docs,
+     "concatenates all document attributes into one document attribute"),
+    ("strip-private", strip_private,
+     "strips all private items from a crate which cannot be seen externally, \
+      implies strip-priv-imports"),
+    ("strip-priv-imports", strip_priv_imports,
+     "strips all private import statements (`use`, `extern crate`) from a crate"),
+];
+
+pub const DEFAULT_PASSES: &'static [&'static str] = &[
+    "strip-hidden",
+    "strip-private",
+    "collapse-docs",
+    "unindent-comments",
+];
+
+
+struct Stripper<'a> {
+    retained: &'a mut DefIdSet,
+    access_levels: &'a AccessLevels<DefId>,
+    update_retained: bool,
+}
+
+impl<'a> fold::DocFolder for Stripper<'a> {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        match i.inner {
+            clean::StrippedItem(..) => {
+                // We need to recurse into stripped modules to strip things
+                // like impl methods but when doing so we must not add any
+                // items to the `retained` set.
+                let old = mem::replace(&mut self.update_retained, false);
+                let ret = self.fold_item_recur(i);
+                self.update_retained = old;
+                return ret;
+            }
+            // These items can all get re-exported
+            clean::TypedefItem(..) | clean::StaticItem(..) |
+            clean::StructItem(..) | clean::EnumItem(..) |
+            clean::TraitItem(..) | clean::FunctionItem(..) |
+            clean::VariantItem(..) | clean::MethodItem(..) |
+            clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
+            clean::ConstantItem(..) | clean::UnionItem(..) => {
+                if i.def_id.is_local() {
+                    if !self.access_levels.is_exported(i.def_id) {
+                        return None;
+                    }
+                }
+            }
+
+            clean::StructFieldItem(..) => {
+                if i.visibility != Some(clean::Public) {
+                    return Strip(i).fold();
+                }
+            }
+
+            clean::ModuleItem(..) => {
+                if i.def_id.is_local() && i.visibility != Some(clean::Public) {
+                    let old = mem::replace(&mut self.update_retained, false);
+                    let ret = Strip(self.fold_item_recur(i).unwrap()).fold();
+                    self.update_retained = old;
+                    return ret;
+                }
+            }
+
+            // handled in the `strip-priv-imports` pass
+            clean::ExternCrateItem(..) | clean::ImportItem(..) => {}
+
+            clean::DefaultImplItem(..) | clean::ImplItem(..) => {}
+
+            // tymethods/macros have no control over privacy
+            clean::MacroItem(..) | clean::TyMethodItem(..) => {}
+
+            // Primitives are never stripped
+            clean::PrimitiveItem(..) => {}
+
+            // Associated consts and types are never stripped
+            clean::AssociatedConstItem(..) |
+            clean::AssociatedTypeItem(..) => {}
+        }
+
+        let fastreturn = match i.inner {
+            // nothing left to do for traits (don't want to filter their
+            // methods out, visibility controlled by the trait)
+            clean::TraitItem(..) => true,
+
+            // implementations of traits are always public.
+            clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
+            // Struct variant fields have inherited visibility
+            clean::VariantItem(clean::Variant {
+                kind: clean::StructVariant(..)
+            }) => true,
+            _ => false,
+        };
+
+        let i = if fastreturn {
+            if self.update_retained {
+                self.retained.insert(i.def_id);
+            }
+            return Some(i);
+        } else {
+            self.fold_item_recur(i)
+        };
+
+        i.and_then(|i| {
+            match i.inner {
+                // emptied modules have no need to exist
+                clean::ModuleItem(ref m)
+                    if m.items.is_empty() &&
+                       i.doc_value().is_none() => None,
+                _ => {
+                    if self.update_retained {
+                        self.retained.insert(i.def_id);
+                    }
+                    Some(i)
+                }
+            }
+        })
+    }
+}
+
+// This stripper discards all impls which reference stripped items
+struct ImplStripper<'a> {
+    retained: &'a DefIdSet
+}
+
+impl<'a> fold::DocFolder for ImplStripper<'a> {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        if let clean::ImplItem(ref imp) = i.inner {
+            // emptied none trait impls can be stripped
+            if imp.trait_.is_none() && imp.items.is_empty() {
+                return None;
+            }
+            if let Some(did) = imp.for_.def_id() {
+                if did.is_local() && !imp.for_.is_generic() &&
+                    !self.retained.contains(&did)
+                {
+                    return None;
+                }
+            }
+            if let Some(did) = imp.trait_.def_id() {
+                if did.is_local() && !self.retained.contains(&did) {
+                    return None;
+                }
+            }
+        }
+        self.fold_item_recur(i)
+    }
+}
+
+// This stripper discards all private import statements (`use`, `extern crate`)
+struct ImportStripper;
+impl fold::DocFolder for ImportStripper {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        match i.inner {
+            clean::ExternCrateItem(..) |
+            clean::ImportItem(..) if i.visibility != Some(clean::Public) => None,
+            _ => self.fold_item_recur(i)
+        }
+    }
+}
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
new file mode 100644 (file)
index 0000000..927ccf9
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::util::nodemap::DefIdSet;
+use std::mem;
+
+use clean::{self, Attributes};
+use clean::Item;
+use plugins;
+use fold;
+use fold::DocFolder;
+use fold::FoldItem::Strip;
+use passes::ImplStripper;
+
+/// Strip items marked `#[doc(hidden)]`
+pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
+    let mut retained = DefIdSet();
+
+    // strip all #[doc(hidden)] items
+    let krate = {
+        let mut stripper = Stripper{ retained: &mut retained, update_retained: true };
+        stripper.fold_crate(krate)
+    };
+
+    // strip all impls referencing stripped items
+    let mut stripper = ImplStripper { retained: &retained };
+    stripper.fold_crate(krate)
+}
+
+struct Stripper<'a> {
+    retained: &'a mut DefIdSet,
+    update_retained: bool,
+}
+
+impl<'a> fold::DocFolder for Stripper<'a> {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        if i.attrs.list("doc").has_word("hidden") {
+            debug!("found one in strip_hidden; removing");
+            // use a dedicated hidden item for given item type if any
+            match i.inner {
+                clean::StructFieldItem(..) | clean::ModuleItem(..) => {
+                    // We need to recurse into stripped modules to
+                    // strip things like impl methods but when doing so
+                    // we must not add any items to the `retained` set.
+                    let old = mem::replace(&mut self.update_retained, false);
+                    let ret = Strip(self.fold_item_recur(i).unwrap()).fold();
+                    self.update_retained = old;
+                    return ret;
+                }
+                _ => return None,
+            }
+        } else {
+            if self.update_retained {
+                self.retained.insert(i.def_id);
+            }
+        }
+        self.fold_item_recur(i)
+    }
+}
diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs
new file mode 100644 (file)
index 0000000..91f8be4
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use clean;
+use fold::DocFolder;
+use plugins;
+use passes::ImportStripper;
+
+pub fn strip_priv_imports(krate: clean::Crate)  -> plugins::PluginResult {
+    ImportStripper.fold_crate(krate)
+}
diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs
new file mode 100644 (file)
index 0000000..acd7357
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::util::nodemap::DefIdSet;
+
+use clean;
+use plugins;
+use fold::DocFolder;
+use passes::{ImplStripper, ImportStripper, Stripper};
+
+/// Strip private items from the point of view of a crate or externally from a
+/// crate, specified by the `xcrate` flag.
+pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
+    // This stripper collects all *retained* nodes.
+    let mut retained = DefIdSet();
+    let access_levels = krate.access_levels.clone();
+
+    // strip all private items
+    {
+        let mut stripper = Stripper {
+            retained: &mut retained,
+            access_levels: &access_levels,
+            update_retained: true,
+        };
+        krate = ImportStripper.fold_crate(stripper.fold_crate(krate));
+    }
+
+    // strip all impls referencing private items
+    let mut stripper = ImplStripper { retained: &retained };
+    stripper.fold_crate(krate)
+}
diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs
new file mode 100644 (file)
index 0000000..20640f3
--- /dev/null
@@ -0,0 +1,168 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cmp;
+use std::string::String;
+use std::usize;
+
+use clean::{self, Item};
+use plugins;
+use fold::{self, DocFolder};
+
+pub fn unindent_comments(krate: clean::Crate) -> plugins::PluginResult {
+    let mut cleaner = CommentCleaner;
+    let krate = cleaner.fold_crate(krate);
+    krate
+}
+
+struct CommentCleaner;
+
+impl fold::DocFolder for CommentCleaner {
+    fn fold_item(&mut self, mut i: Item) -> Option<Item> {
+        let mut avec: Vec<clean::Attribute> = Vec::new();
+        for attr in &i.attrs {
+            match attr {
+                &clean::NameValue(ref x, ref s)
+                        if "doc" == *x => {
+                    avec.push(clean::NameValue("doc".to_string(),
+                                               unindent(s)))
+                }
+                x => avec.push(x.clone())
+            }
+        }
+        i.attrs = avec;
+        self.fold_item_recur(i)
+    }
+}
+
+fn unindent(s: &str) -> String {
+    let lines = s.lines().collect::<Vec<&str> >();
+    let mut saw_first_line = false;
+    let mut saw_second_line = false;
+    let min_indent = lines.iter().fold(usize::MAX, |min_indent, line| {
+
+        // After we see the first non-whitespace line, look at
+        // the line we have. If it is not whitespace, and therefore
+        // part of the first paragraph, then ignore the indentation
+        // level of the first line
+        let ignore_previous_indents =
+            saw_first_line &&
+            !saw_second_line &&
+            !line.chars().all(|c| c.is_whitespace());
+
+        let min_indent = if ignore_previous_indents {
+            usize::MAX
+        } else {
+            min_indent
+        };
+
+        if saw_first_line {
+            saw_second_line = true;
+        }
+
+        if line.chars().all(|c| c.is_whitespace()) {
+            min_indent
+        } else {
+            saw_first_line = true;
+            let mut whitespace = 0;
+            line.chars().all(|char| {
+                // Compare against either space or tab, ignoring whether they
+                // are mixed or not
+                if char == ' ' || char == '\t' {
+                    whitespace += 1;
+                    true
+                } else {
+                    false
+                }
+            });
+            cmp::min(min_indent, whitespace)
+        }
+    });
+
+    if !lines.is_empty() {
+        let mut unindented = vec![ lines[0].trim().to_string() ];
+        unindented.extend_from_slice(&lines[1..].iter().map(|&line| {
+            if line.chars().all(|c| c.is_whitespace()) {
+                line.to_string()
+            } else {
+                assert!(line.len() >= min_indent);
+                line[min_indent..].to_string()
+            }
+        }).collect::<Vec<_>>());
+        unindented.join("\n")
+    } else {
+        s.to_string()
+    }
+}
+
+#[cfg(test)]
+mod unindent_tests {
+    use super::unindent;
+
+    #[test]
+    fn should_unindent() {
+        let s = "    line1\n    line2".to_string();
+        let r = unindent(&s);
+        assert_eq!(r, "line1\nline2");
+    }
+
+    #[test]
+    fn should_unindent_multiple_paragraphs() {
+        let s = "    line1\n\n    line2".to_string();
+        let r = unindent(&s);
+        assert_eq!(r, "line1\n\nline2");
+    }
+
+    #[test]
+    fn should_leave_multiple_indent_levels() {
+        // Line 2 is indented another level beyond the
+        // base indentation and should be preserved
+        let s = "    line1\n\n        line2".to_string();
+        let r = unindent(&s);
+        assert_eq!(r, "line1\n\n    line2");
+    }
+
+    #[test]
+    fn should_ignore_first_line_indent() {
+        // The first line of the first paragraph may not be indented as
+        // far due to the way the doc string was written:
+        //
+        // #[doc = "Start way over here
+        //          and continue here"]
+        let s = "line1\n    line2".to_string();
+        let r = unindent(&s);
+        assert_eq!(r, "line1\nline2");
+    }
+
+    #[test]
+    fn should_not_ignore_first_line_indent_in_a_single_line_para() {
+        let s = "line1\n\n    line2".to_string();
+        let r = unindent(&s);
+        assert_eq!(r, "line1\n\n    line2");
+    }
+
+    #[test]
+    fn should_unindent_tabs() {
+        let s = "\tline1\n\tline2".to_string();
+        let r = unindent(&s);
+        assert_eq!(r, "line1\nline2");
+    }
+
+    #[test]
+    fn should_trim_mixed_indentation() {
+        let s = "\t    line1\n\t    line2".to_string();
+        let r = unindent(&s);
+        assert_eq!(r, "line1\nline2");
+
+        let s = "    \tline1\n    \tline2".to_string();
+        let r = unindent(&s);
+        assert_eq!(r, "line1\nline2");
+    }
+}
index 4518945dd9857ffd99bed3791eb02f264dee4341..02f0916de0ef3a970e0cd95c11ba4f0823912912 100644 (file)
@@ -25,8 +25,7 @@
 use rustc::dep_graph::DepGraph;
 use rustc::hir::map as hir_map;
 use rustc::session::{self, config};
-use rustc::session::config::{get_unstable_features_setting, OutputType,
-                             OutputTypes, Externs};
+use rustc::session::config::{OutputType, OutputTypes, Externs};
 use rustc::session::search_paths::{SearchPaths, PathKind};
 use rustc_back::dynamic_lib::DynamicLibrary;
 use rustc_back::tempdir::TempDir;
@@ -35,6 +34,7 @@
 use rustc_metadata::cstore::CStore;
 use rustc_resolve::MakeGlobMap;
 use syntax::codemap::CodeMap;
+use syntax::feature_gate::UnstableFeatures;
 use errors;
 use errors::emitter::ColorConfig;
 
@@ -68,7 +68,7 @@ pub fn run(input: &str,
         search_paths: libs.clone(),
         crate_types: vec!(config::CrateTypeDylib),
         externs: externs.clone(),
-        unstable_features: get_unstable_features_setting(),
+        unstable_features: UnstableFeatures::from_environment(),
         ..config::basic_options().clone()
     };
 
@@ -197,7 +197,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
             .. config::basic_codegen_options()
         },
         test: as_test_harness,
-        unstable_features: get_unstable_features_setting(),
+        unstable_features: UnstableFeatures::from_environment(),
         ..config::basic_options().clone()
     };
 
@@ -228,7 +228,7 @@ fn drop(&mut self) {
     let codemap = Rc::new(CodeMap::new());
     let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
                                                       Some(codemap.clone()));
-    let old = io::set_panic(box Sink(data.clone()));
+    let old = io::set_panic(Some(box Sink(data.clone())));
     let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
 
     // Compile the code
index 6ccc0be41bc0f7f3c0f23df423adafed0312efcb..5e25c61bae995b254b239644df01c38a3b25fd12 100644 (file)
@@ -433,9 +433,7 @@ fn escape_str(wr: &mut fmt::Write, v: &str) -> EncodeResult {
 }
 
 fn escape_char(writer: &mut fmt::Write, v: char) -> EncodeResult {
-    escape_str(writer, unsafe {
-        str::from_utf8_unchecked(v.encode_utf8().as_slice())
-    })
+    escape_str(writer, v.encode_utf8(&mut [0; 4]))
 }
 
 fn spaces(wr: &mut fmt::Write, mut n: usize) -> EncodeResult {
index e8ca2977241e0769f43aaef5c8758457bf79757e..b0a6c224897468b71a8f6d75624f31d5d7c9aa81 100644 (file)
@@ -187,15 +187,29 @@ fn capacity(&self, raw_cap: usize) -> usize {
 //
 // FIXME(Gankro, pczarn): review the proof and put it all in a separate README.md
 
-/// A hash map implementation which uses linear probing with Robin
-/// Hood bucket stealing.
+/// A hash map implementation which uses linear probing with Robin Hood bucket
+/// stealing.
 ///
-/// By default, HashMap uses a somewhat slow hashing algorithm which can provide resistance
-/// to DoS attacks. Rust makes a best attempt at acquiring random numbers without IO
-/// blocking from your system. Because of this HashMap is not guaranteed to provide
-/// DoS resistance since the numbers generated might not be truly random. If you do
-/// require this behavior you can create your own hashing function using
-/// [BuildHasherDefault](../hash/struct.BuildHasherDefault.html).
+/// By default, `HashMap` uses a hashing algorithm selected to provide
+/// resistance against HashDoS attacks. The algorithm is randomly seeded, and a
+/// reasonable best-effort is made to generate this seed from a high quality,
+/// secure source of randomness provided by the host without blocking the
+/// program. Because of this, the randomness of the seed is dependant on the
+/// quality of the system's random number generator at the time it is created.
+/// In particular, seeds generated when the system's entropy pool is abnormally
+/// low such as during system boot may be of a lower quality.
+///
+/// The default hashing algorithm is currently SipHash 1-3, though this is
+/// subject to change at any point in the future. While its performance is very
+/// competitive for medium sized keys, other hashing algorithms will outperform
+/// it for small keys such as integers as well as large keys such as long
+/// strings, though those algorithms will typically *not* protect against
+/// attacks such as HashDoS.
+///
+/// The hashing algorithm can be replaced on a per-`HashMap` basis using the
+/// `HashMap::default`, `HashMap::with_hasher`, and
+/// `HashMap::with_capacity_and_hasher` methods. Many alternative algorithms
+/// are available on crates.io, such as the `fnv` crate.
 ///
 /// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although
 /// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`.
@@ -326,6 +340,22 @@ fn capacity(&self, raw_cap: usize) -> usize {
 ///     println!("{:?} has {} hp", viking, health);
 /// }
 /// ```
+///
+/// A HashMap with fixed list of elements can be initialized from an array:
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// fn main() {
+///     let timber_resources: HashMap<&str, i32> =
+///     [("Norway", 100),
+///      ("Denmark", 50),
+///      ("Iceland", 10)]
+///      .iter().cloned().collect();
+///     // use the values stored in map
+/// }
+/// ```
+
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct HashMap<K, V, S = RandomState> {
index dc2603dea03a88fd89ec831b5a574c94907b9774..e5fe3c2f7c61f55550b421fec6447181b11ef2a3 100644 (file)
 ///     println!("{:?}", x);
 /// }
 /// ```
+///
+/// HashSet with fixed list of elements can be initialized from an array:
+///
+/// ```
+/// use std::collections::HashSet;
+///
+/// fn main() {
+///     let viking_names: HashSet<&str> =
+///         [ "Einar", "Olaf", "Harald" ].iter().cloned().collect();
+///     // use the values stored in the set
+/// }
+/// ```
+
+
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct HashSet<T, S = RandomState> {
index 8f02c9c7d3de0334ca6403101bc4fc0c525c1a26..afd833d8bdd81dfbebf49c4c1f5a9a8322dba0c4 100644 (file)
@@ -59,7 +59,6 @@
 /// around just the "table" part of the hashtable. It enforces some
 /// invariants at the type level and employs some performance trickery,
 /// but in general is just a tricked out `Vec<Option<u64, K, V>>`.
-#[cfg_attr(stage0, unsafe_no_drop_flag)]
 pub struct RawTable<K, V> {
     capacity: usize,
     size: usize,
index 76eb92bd55989880f73416743fc4244ee3839317..e29dbe35c5a59a242c592fd0dc0c3c3c5adb47ab 100644 (file)
@@ -21,6 +21,7 @@
 use fmt;
 use io;
 use path::{Path, PathBuf};
+use sys;
 use sys::os as os_imp;
 
 /// Returns the current working directory as a `PathBuf`.
@@ -557,7 +558,7 @@ pub struct Args { inner: ArgsOs }
 ///
 /// This structure is created through the `std::env::args_os` method.
 #[stable(feature = "env", since = "1.0.0")]
-pub struct ArgsOs { inner: os_imp::Args }
+pub struct ArgsOs { inner: sys::args::Args }
 
 /// Returns the arguments which this program was started with (normally passed
 /// via the command line).
@@ -606,7 +607,7 @@ pub fn args() -> Args {
 /// ```
 #[stable(feature = "env", since = "1.0.0")]
 pub fn args_os() -> ArgsOs {
-    ArgsOs { inner: os_imp::args() }
+    ArgsOs { inner: sys::args::args() }
 }
 
 #[stable(feature = "env", since = "1.0.0")]
@@ -649,6 +650,8 @@ fn next_back(&mut self) -> Option<OsString> { self.inner.next_back() }
 /// Constants associated with the current target
 #[stable(feature = "env", since = "1.0.0")]
 pub mod consts {
+    use sys::env::os;
+
     /// A string describing the architecture of the CPU that is currently
     /// in use.
     ///
@@ -673,7 +676,7 @@ pub mod consts {
     /// - unix
     /// - windows
     #[stable(feature = "env", since = "1.0.0")]
-    pub const FAMILY: &'static str = super::os::FAMILY;
+    pub const FAMILY: &'static str = os::FAMILY;
 
     /// A string describing the specific operating system in use.
     /// Example value is `linux`.
@@ -692,7 +695,7 @@ pub mod consts {
     /// - android
     /// - windows
     #[stable(feature = "env", since = "1.0.0")]
-    pub const OS: &'static str = super::os::OS;
+    pub const OS: &'static str = os::OS;
 
     /// Specifies the filename prefix used for shared libraries on this
     /// platform. Example value is `lib`.
@@ -702,7 +705,7 @@ pub mod consts {
     /// - lib
     /// - `""` (an empty string)
     #[stable(feature = "env", since = "1.0.0")]
-    pub const DLL_PREFIX: &'static str = super::os::DLL_PREFIX;
+    pub const DLL_PREFIX: &'static str = os::DLL_PREFIX;
 
     /// Specifies the filename suffix used for shared libraries on this
     /// platform. Example value is `.so`.
@@ -713,7 +716,7 @@ pub mod consts {
     /// - .dylib
     /// - .dll
     #[stable(feature = "env", since = "1.0.0")]
-    pub const DLL_SUFFIX: &'static str = super::os::DLL_SUFFIX;
+    pub const DLL_SUFFIX: &'static str = os::DLL_SUFFIX;
 
     /// Specifies the file extension used for shared libraries on this
     /// platform that goes after the dot. Example value is `so`.
@@ -724,7 +727,7 @@ pub mod consts {
     /// - dylib
     /// - dll
     #[stable(feature = "env", since = "1.0.0")]
-    pub const DLL_EXTENSION: &'static str = super::os::DLL_EXTENSION;
+    pub const DLL_EXTENSION: &'static str = os::DLL_EXTENSION;
 
     /// Specifies the filename suffix used for executable binaries on this
     /// platform. Example value is `.exe`.
@@ -736,7 +739,7 @@ pub mod consts {
     /// - .pexe
     /// - `""` (an empty string)
     #[stable(feature = "env", since = "1.0.0")]
-    pub const EXE_SUFFIX: &'static str = super::os::EXE_SUFFIX;
+    pub const EXE_SUFFIX: &'static str = os::EXE_SUFFIX;
 
     /// Specifies the file extension, if any, used for executable binaries
     /// on this platform. Example value is `exe`.
@@ -746,161 +749,7 @@ pub mod consts {
     /// - exe
     /// - `""` (an empty string)
     #[stable(feature = "env", since = "1.0.0")]
-    pub const EXE_EXTENSION: &'static str = super::os::EXE_EXTENSION;
-
-}
-
-#[cfg(target_os = "linux")]
-mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "linux";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".so";
-    pub const DLL_EXTENSION: &'static str = "so";
-    pub const EXE_SUFFIX: &'static str = "";
-    pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "macos")]
-mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "macos";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".dylib";
-    pub const DLL_EXTENSION: &'static str = "dylib";
-    pub const EXE_SUFFIX: &'static str = "";
-    pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "ios")]
-mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "ios";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".dylib";
-    pub const DLL_EXTENSION: &'static str = "dylib";
-    pub const EXE_SUFFIX: &'static str = "";
-    pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "freebsd")]
-mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "freebsd";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".so";
-    pub const DLL_EXTENSION: &'static str = "so";
-    pub const EXE_SUFFIX: &'static str = "";
-    pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "dragonfly")]
-mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "dragonfly";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".so";
-    pub const DLL_EXTENSION: &'static str = "so";
-    pub const EXE_SUFFIX: &'static str = "";
-    pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "bitrig")]
-mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "bitrig";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".so";
-    pub const DLL_EXTENSION: &'static str = "so";
-    pub const EXE_SUFFIX: &'static str = "";
-    pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "netbsd")]
-mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "netbsd";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".so";
-    pub const DLL_EXTENSION: &'static str = "so";
-    pub const EXE_SUFFIX: &'static str = "";
-    pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "openbsd")]
-mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "openbsd";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".so";
-    pub const DLL_EXTENSION: &'static str = "so";
-    pub const EXE_SUFFIX: &'static str = "";
-    pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "android")]
-mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "android";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".so";
-    pub const DLL_EXTENSION: &'static str = "so";
-    pub const EXE_SUFFIX: &'static str = "";
-    pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "solaris")]
-mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "solaris";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".so";
-    pub const DLL_EXTENSION: &'static str = "so";
-    pub const EXE_SUFFIX: &'static str = "";
-    pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "windows")]
-mod os {
-    pub const FAMILY: &'static str = "windows";
-    pub const OS: &'static str = "windows";
-    pub const DLL_PREFIX: &'static str = "";
-    pub const DLL_SUFFIX: &'static str = ".dll";
-    pub const DLL_EXTENSION: &'static str = "dll";
-    pub const EXE_SUFFIX: &'static str = ".exe";
-    pub const EXE_EXTENSION: &'static str = "exe";
-}
-
-#[cfg(all(target_os = "nacl", not(target_arch = "le32")))]
-mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "nacl";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".so";
-    pub const DLL_EXTENSION: &'static str = "so";
-    pub const EXE_SUFFIX: &'static str = ".nexe";
-    pub const EXE_EXTENSION: &'static str = "nexe";
-}
-#[cfg(all(target_os = "nacl", target_arch = "le32"))]
-mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "pnacl";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".pso";
-    pub const DLL_EXTENSION: &'static str = "pso";
-    pub const EXE_SUFFIX: &'static str = ".pexe";
-    pub const EXE_EXTENSION: &'static str = "pexe";
-}
-
-#[cfg(target_os = "emscripten")]
-mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "emscripten";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".so";
-    pub const DLL_EXTENSION: &'static str = "so";
-    pub const EXE_SUFFIX: &'static str = ".js";
-    pub const EXE_EXTENSION: &'static str = "js";
+    pub const EXE_EXTENSION: &'static str = os::EXE_EXTENSION;
 }
 
 #[cfg(target_arch = "x86")]
@@ -958,6 +807,11 @@ mod arch {
     pub const ARCH: &'static str = "asmjs";
 }
 
+#[cfg(target_arch = "wasm32")]
+mod arch {
+    pub const ARCH: &'static str = "wasm32";
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -1006,6 +860,7 @@ fn test_set_var_overwrite() {
     }
 
     #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn test_var_big() {
         let mut s = "".to_string();
         let mut i = 0;
@@ -1019,6 +874,7 @@ fn test_var_big() {
     }
 
     #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn test_self_exe_path() {
         let path = current_exe();
         assert!(path.is_ok());
@@ -1029,6 +885,7 @@ fn test_self_exe_path() {
     }
 
     #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn test_env_set_get_huge() {
         let n = make_rand_name();
         let s = repeat("x").take(10000).collect::<String>();
index d6a5efbd279a549f1ec5a9487fafc8d608ecb3b6..6f5ce350e6cb376092275f63cf7bd9c124a8a862 100644 (file)
@@ -314,9 +314,11 @@ fn into_inner(self) -> Box<[u8]> {
 }
 
 // Turns this `CString` into an empty string to prevent
-// memory unsafe code from working by accident.
+// memory unsafe code from working by accident. Inline
+// to prevent LLVM from optimizing it away in debug builds.
 #[stable(feature = "cstring_drop", since = "1.13.0")]
 impl Drop for CString {
+    #[inline]
     fn drop(&mut self) {
         unsafe { *self.inner.get_unchecked_mut(0) = 0; }
     }
index d93d3c7362261223d2b678450372b04837c3c9b1..84b50f04463fe7dc8ccef469b5f02e1df007a67b 100644 (file)
@@ -53,17 +53,6 @@ pub fn new() -> OsString {
         OsString { inner: Buf::from_string(String::new()) }
     }
 
-    #[cfg(unix)]
-    fn _from_bytes(vec: Vec<u8>) -> Option<OsString> {
-        use os::unix::ffi::OsStringExt;
-        Some(OsString::from_vec(vec))
-    }
-
-    #[cfg(windows)]
-    fn _from_bytes(vec: Vec<u8>) -> Option<OsString> {
-        String::from_utf8(vec).ok().map(OsString::from)
-    }
-
     /// Converts to an `OsStr` slice.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn as_os_str(&self) -> &OsStr {
index 576198564dbd43f7393335460a51c07d06c74195..2f2969b110db17a7687b81802ce6409013526277 100644 (file)
@@ -1686,7 +1686,7 @@ fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use io::prelude::*;
 
index 4ff8c6ac128bd9872fdc8b546914d2327cc252be..21a0cc1fb3b13e0028014fc916973a9f06ef7775 100644 (file)
@@ -1107,6 +1107,7 @@ fn flush(&mut self) -> io::Result<()> {
     }
 
     #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn panic_in_write_doesnt_flush_in_drop() {
         static WRITES: AtomicUsize = AtomicUsize::new(0);
 
index 06609cfad152e969130324f96b552c5852a06294..3becc0a0c9ee17ca1886823e0ad87c0cb2c02ce0 100644 (file)
@@ -1264,15 +1264,13 @@ pub trait BufRead: Read {
     #[stable(feature = "rust1", since = "1.0.0")]
     fn consume(&mut self, amt: usize);
 
-    /// Read all bytes into `buf` until the delimiter `byte` is reached.
+    /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached.
     ///
     /// This function will read bytes from the underlying stream until the
     /// delimiter or EOF is found. Once found, all bytes up to, and including,
     /// the delimiter (if found) will be appended to `buf`.
     ///
-    /// If this reader is currently at EOF then this function will not modify
-    /// `buf` and will return `Ok(n)` where `n` is the number of bytes which
-    /// were read.
+    /// If successful, this function will return the total number of bytes read.
     ///
     /// # Errors
     ///
@@ -1315,9 +1313,7 @@ fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
     /// up to, and including, the delimiter (if found) will be appended to
     /// `buf`.
     ///
-    /// If this reader is currently at EOF then this function will not modify
-    /// `buf` and will return `Ok(n)` where `n` is the number of bytes which
-    /// were read.
+    /// If successful, this function will return the total number of bytes read.
     ///
     /// # Errors
     ///
@@ -1432,7 +1428,7 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
     fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
         if !self.done_first {
             match self.first.read(buf)? {
-                0 => { self.done_first = true; }
+                0 if buf.len() != 0 => { self.done_first = true; }
                 n => return Ok(n),
             }
         }
@@ -1761,6 +1757,7 @@ mod tests {
     use super::repeat;
 
     #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn read_until() {
         let mut buf = Cursor::new(&b"12"[..]);
         let mut v = Vec::new();
@@ -1959,7 +1956,19 @@ fn chain_bufread() {
         cmp_bufread(chain1, chain2, &testdata[..]);
     }
 
+    #[test]
+    fn chain_zero_length_read_is_not_eof() {
+        let a = b"A";
+        let b = b"B";
+        let mut s = String::new();
+        let mut chain = (&a[..]).chain(&b[..]);
+        chain.read(&mut []).unwrap();
+        chain.read_to_string(&mut s).unwrap();
+        assert_eq!("AB", s);
+    }
+
     #[bench]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn bench_read_to_end(b: &mut test::Bencher) {
         b.iter(|| {
             let mut lr = repeat(1).take(10000000);
index 9a782e95f6e5f994fd2cabe77cd59512a99ef90f..c24ee8ff303c875530d976f01708a7d8e75cd3d9 100644 (file)
@@ -125,13 +125,10 @@ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
 }
 
 fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
-    #[cfg(windows)]
-    const ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;
-    #[cfg(not(windows))]
-    const ERR: i32 = ::libc::EBADF as i32;
+    use sys::stdio::EBADF_ERR;
 
     match r {
-        Err(ref e) if e.raw_os_error() == Some(ERR) => Ok(default),
+        Err(ref e) if e.raw_os_error() == Some(EBADF_ERR) => Ok(default),
         r => r
     }
 }
@@ -593,11 +590,11 @@ fn flush(&mut self) -> io::Result<()> {
                      with a more general mechanism",
            issue = "0")]
 #[doc(hidden)]
-pub fn set_panic(sink: Box<Write + Send>) -> Option<Box<Write + Send>> {
+pub fn set_panic(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
     use panicking::LOCAL_STDERR;
     use mem;
     LOCAL_STDERR.with(move |slot| {
-        mem::replace(&mut *slot.borrow_mut(), Some(sink))
+        mem::replace(&mut *slot.borrow_mut(), sink)
     }).and_then(|mut s| {
         let _ = s.flush();
         Some(s)
@@ -617,10 +614,10 @@ pub fn set_panic(sink: Box<Write + Send>) -> Option<Box<Write + Send>> {
                      with a more general mechanism",
            issue = "0")]
 #[doc(hidden)]
-pub fn set_print(sink: Box<Write + Send>) -> Option<Box<Write + Send>> {
+pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
     use mem;
     LOCAL_STDOUT.with(move |slot| {
-        mem::replace(&mut *slot.borrow_mut(), Some(sink))
+        mem::replace(&mut *slot.borrow_mut(), sink)
     }).and_then(|mut s| {
         let _ = s.flush();
         Some(s)
@@ -668,6 +665,7 @@ mod tests {
     use super::*;
 
     #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn panic_doesnt_poison() {
         thread::spawn(|| {
             let _a = stdin();
index 912045453e086dabff0d23766606abafd7bed660..b3e4351e9b20006ce4efe118d2b7d3635d19e2b3 100644 (file)
 #![feature(unboxed_closures)]
 #![feature(unicode)]
 #![feature(unique)]
-#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
 #![feature(unwind_attributes)]
 #![feature(vec_push_all)]
 #![feature(zero_one)]
index c78840bd42b073b89b1ca44c4c36400232e78fdb..8946af8af53d756c124ffd93eb344e5cb8d5d182 100644 (file)
@@ -450,9 +450,16 @@ macro_rules! module_path { () => ({ /* compiler built-in */ }) }
     #[macro_export]
     macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) }
 
-    /// Parse the current given file as an expression.
-    ///
-    /// This is generally a bad idea, because it's going to behave unhygienically.
+    /// Parse the file provided in the argument as an expression or an
+    /// item according to the context. This file is located relative
+    /// to the current file (similarly to how modules are found).
+    ///
+    /// Using this macro is often a bad idea, because if the file is
+    /// parsed as an expression, it is going to be placed in the
+    /// surrounding code unhygenically. This could result in variables
+    /// or functions being different from what the file expected if
+    /// there are variables or functions that have the same name in
+    /// the current file.
     ///
     /// # Examples
     ///
index 03f55f7ad61864cf3ed90ed794b36e41728873c0..7c8c97a6caf9cfc2dd3f188def54060449c822d4 100644 (file)
@@ -11,8 +11,6 @@
 // Original implementation taken from rust-memchr
 // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
 
-
-
 /// A safe interface to `memchr`.
 ///
 /// Returns the index corresponding to the first occurrence of `needle` in
 /// let haystack = b"the quick brown fox";
 /// assert_eq!(memchr(b'k', haystack), Some(8));
 /// ```
+#[inline]
 pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
-    // libc memchr
-    #[cfg(not(target_os = "windows"))]
-    fn memchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
-        use libc;
-
-        let p = unsafe {
-            libc::memchr(
-                haystack.as_ptr() as *const libc::c_void,
-                needle as libc::c_int,
-                haystack.len() as libc::size_t)
-        };
-        if p.is_null() {
-            None
-        } else {
-            Some(p as usize - (haystack.as_ptr() as usize))
-        }
-    }
-
-    // use fallback on windows, since it's faster
-    #[cfg(target_os = "windows")]
-    fn memchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
-        fallback::memchr(needle, haystack)
-    }
-
-    memchr_specific(needle, haystack)
+    ::sys::memchr::memchr(needle, haystack)
 }
 
 /// A safe interface to `memrchr`.
@@ -75,251 +50,9 @@ fn memchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
 /// let haystack = b"the quick brown fox";
 /// assert_eq!(memrchr(b'o', haystack), Some(17));
 /// ```
+#[inline]
 pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
-
-    #[cfg(target_os = "linux")]
-    fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
-        use libc;
-
-        // GNU's memrchr() will - unlike memchr() - error if haystack is empty.
-        if haystack.is_empty() {return None}
-        let p = unsafe {
-            libc::memrchr(
-                haystack.as_ptr() as *const libc::c_void,
-                needle as libc::c_int,
-                haystack.len() as libc::size_t)
-        };
-        if p.is_null() {
-            None
-        } else {
-            Some(p as usize - (haystack.as_ptr() as usize))
-        }
-    }
-
-    #[cfg(not(target_os = "linux"))]
-    fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
-        fallback::memrchr(needle, haystack)
-    }
-
-    memrchr_specific(needle, haystack)
-}
-
-#[allow(dead_code)]
-mod fallback {
-    use cmp;
-    use mem;
-
-    const LO_U64: u64 = 0x0101010101010101;
-    const HI_U64: u64 = 0x8080808080808080;
-
-    // use truncation
-    const LO_USIZE: usize = LO_U64 as usize;
-    const HI_USIZE: usize = HI_U64 as usize;
-
-    /// Return `true` if `x` contains any zero byte.
-    ///
-    /// From *Matters Computational*, J. Arndt
-    ///
-    /// "The idea is to subtract one from each of the bytes and then look for
-    /// bytes where the borrow propagated all the way to the most significant
-    /// bit."
-    #[inline]
-    fn contains_zero_byte(x: usize) -> bool {
-        x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
-    }
-
-    #[cfg(target_pointer_width = "32")]
-    #[inline]
-    fn repeat_byte(b: u8) -> usize {
-        let mut rep = (b as usize) << 8 | b as usize;
-        rep = rep << 16 | rep;
-        rep
-    }
-
-    #[cfg(target_pointer_width = "64")]
-    #[inline]
-    fn repeat_byte(b: u8) -> usize {
-        let mut rep = (b as usize) << 8 | b as usize;
-        rep = rep << 16 | rep;
-        rep = rep << 32 | rep;
-        rep
-    }
-
-    /// Return the first index matching the byte `a` in `text`.
-    pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
-        // Scan for a single byte value by reading two `usize` words at a time.
-        //
-        // Split `text` in three parts
-        // - unaligned initial part, before the first word aligned address in text
-        // - body, scan by 2 words at a time
-        // - the last remaining part, < 2 word size
-        let len = text.len();
-        let ptr = text.as_ptr();
-        let usize_bytes = mem::size_of::<usize>();
-
-        // search up to an aligned boundary
-        let align = (ptr as usize) & (usize_bytes- 1);
-        let mut offset;
-        if align > 0 {
-            offset = cmp::min(usize_bytes - align, len);
-            if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
-                return Some(index);
-            }
-        } else {
-            offset = 0;
-        }
-
-        // search the body of the text
-        let repeated_x = repeat_byte(x);
-
-        if len >= 2 * usize_bytes {
-            while offset <= len - 2 * usize_bytes {
-                unsafe {
-                    let u = *(ptr.offset(offset as isize) as *const usize);
-                    let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);
-
-                    // break if there is a matching byte
-                    let zu = contains_zero_byte(u ^ repeated_x);
-                    let zv = contains_zero_byte(v ^ repeated_x);
-                    if zu || zv {
-                        break;
-                    }
-                }
-                offset += usize_bytes * 2;
-            }
-        }
-
-        // find the byte after the point the body loop stopped
-        text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
-    }
-
-    /// Return the last index matching the byte `a` in `text`.
-    pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
-        // Scan for a single byte value by reading two `usize` words at a time.
-        //
-        // Split `text` in three parts
-        // - unaligned tail, after the last word aligned address in text
-        // - body, scan by 2 words at a time
-        // - the first remaining bytes, < 2 word size
-        let len = text.len();
-        let ptr = text.as_ptr();
-        let usize_bytes = mem::size_of::<usize>();
-
-        // search to an aligned boundary
-        let end_align = (ptr as usize + len) & (usize_bytes - 1);
-        let mut offset;
-        if end_align > 0 {
-            offset = if end_align >= len { 0 } else { len - end_align };
-            if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
-                return Some(offset + index);
-            }
-        } else {
-            offset = len;
-        }
-
-        // search the body of the text
-        let repeated_x = repeat_byte(x);
-
-        while offset >= 2 * usize_bytes {
-            unsafe {
-                let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
-                let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);
-
-                // break if there is a matching byte
-                let zu = contains_zero_byte(u ^ repeated_x);
-                let zv = contains_zero_byte(v ^ repeated_x);
-                if zu || zv {
-                    break;
-                }
-            }
-            offset -= 2 * usize_bytes;
-        }
-
-        // find the byte before the point the body loop stopped
-        text[..offset].iter().rposition(|elt| *elt == x)
-    }
-
-    // test fallback implementations on all platforms
-    #[test]
-    fn matches_one() {
-        assert_eq!(Some(0), memchr(b'a', b"a"));
-    }
-
-    #[test]
-    fn matches_begin() {
-        assert_eq!(Some(0), memchr(b'a', b"aaaa"));
-    }
-
-    #[test]
-    fn matches_end() {
-        assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
-    }
-
-    #[test]
-    fn matches_nul() {
-        assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
-    }
-
-    #[test]
-    fn matches_past_nul() {
-        assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
-    }
-
-    #[test]
-    fn no_match_empty() {
-        assert_eq!(None, memchr(b'a', b""));
-    }
-
-    #[test]
-    fn no_match() {
-        assert_eq!(None, memchr(b'a', b"xyz"));
-    }
-
-    #[test]
-    fn matches_one_reversed() {
-        assert_eq!(Some(0), memrchr(b'a', b"a"));
-    }
-
-    #[test]
-    fn matches_begin_reversed() {
-        assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
-    }
-
-    #[test]
-    fn matches_end_reversed() {
-        assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
-    }
-
-    #[test]
-    fn matches_nul_reversed() {
-        assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
-    }
-
-    #[test]
-    fn matches_past_nul_reversed() {
-        assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
-    }
-
-    #[test]
-    fn no_match_empty_reversed() {
-        assert_eq!(None, memrchr(b'a', b""));
-    }
-
-    #[test]
-    fn no_match_reversed() {
-        assert_eq!(None, memrchr(b'a', b"xyz"));
-    }
-
-    #[test]
-    fn each_alignment_reversed() {
-        let mut data = [1u8; 64];
-        let needle = 2;
-        let pos = 40;
-        data[pos] = needle;
-        for start in 0..16 {
-            assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
-        }
-    }
+    ::sys::memchr::memrchr(needle, haystack)
 }
 
 #[cfg(test)]
index d0b59b42c1798a73a2ca56e75d553849ea5a9672..58daa7dbf8dc4d843b9b5e49f2da0f860d0e85f8 100644 (file)
@@ -519,7 +519,7 @@ fn to_socket_addrs(&self) -> io::Result<T::Iter> {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use net::*;
     use net::test::{tsa, sa6, sa4};
index 05ef559422f33187707e1894c56eef67800945cf..ba2cd70e0d7776a77f0b553b2006eeb95c38d850 100644 (file)
@@ -669,7 +669,7 @@ fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
 }
 
 // Tests for this module
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use net::*;
     use net::Ipv6MulticastScope::*;
index ad2fe3c1c0dbc8874e093328a1c530d6bec47aab..56286fbe25399a62a322c24e815475cf6c69085a 100644 (file)
@@ -31,7 +31,8 @@
 mod tcp;
 mod udp;
 mod parser;
-#[cfg(test)] mod test;
+#[cfg(test)]
+mod test;
 
 /// Possible values which can be passed to the [`shutdown`] method of
 /// [`TcpStream`].
index 3c5f07c3e33a6db25ef7fd9f033d9f3825d080be..0e7c5b06713fb31a58d3977a85f7f4f1aa5e27ac 100644 (file)
@@ -428,7 +428,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use io::ErrorKind;
     use io::prelude::*;
index 98ac61f6461132d94f320d11ba31b7bb516803c4..3f2eacda7d60eb11a9902255b3158dae07a69da7 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#[allow(dead_code)] // not used on emscripten
+
 use env;
 use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
 use sync::atomic::{AtomicUsize, Ordering};
index 781f026c12c7795e1b2c82fae0506c5b40d8b566..c03ac496adbb27b6f9c4ecef20e412a7f833764e 100644 (file)
@@ -353,7 +353,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use io::ErrorKind;
     use net::*;
diff --git a/src/libstd/os/haiku/fs.rs b/src/libstd/os/haiku/fs.rs
new file mode 100644 (file)
index 0000000..54f8ea1
--- /dev/null
@@ -0,0 +1,138 @@
+// 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.
+
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use libc;
+
+use fs::Metadata;
+use sys_common::AsInner;
+
+#[allow(deprecated)]
+use os::haiku::raw;
+
+/// OS-specific extension methods for `fs::Metadata`
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+    /// Gain a reference to the underlying `stat` structure which contains
+    /// the raw information returned by the OS.
+    ///
+    /// The contents of the returned `stat` are **not** consistent across
+    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+    /// cross-Unix abstractions contained within the raw stat.
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    #[rustc_deprecated(since = "1.8.0",
+                       reason = "deprecated in favor of the accessor \
+                                 methods of this trait")]
+    #[allow(deprecated)]
+    fn as_raw_stat(&self) -> &raw::stat;
+
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_dev(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ino(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mode(&self) -> u32;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_nlink(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_uid(&self) -> u32;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_gid(&self) -> u32;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_rdev(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_size(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_crtime(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_crtime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blksize(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+    #[allow(deprecated)]
+    fn as_raw_stat(&self) -> &raw::stat {
+        unsafe {
+            &*(self.as_inner().as_inner() as *const libc::stat
+                                          as *const raw::stat)
+        }
+    }
+    fn st_dev(&self) -> u64 {
+        self.as_inner().as_inner().st_dev as u64
+    }
+    fn st_ino(&self) -> u64 {
+        self.as_inner().as_inner().st_ino as u64
+    }
+    fn st_mode(&self) -> u32 {
+        self.as_inner().as_inner().st_mode as u32
+    }
+    fn st_nlink(&self) -> u64 {
+        self.as_inner().as_inner().st_nlink as u64
+    }
+    fn st_uid(&self) -> u32 {
+        self.as_inner().as_inner().st_uid as u32
+    }
+    fn st_gid(&self) -> u32 {
+        self.as_inner().as_inner().st_gid as u32
+    }
+    fn st_rdev(&self) -> u64 {
+        self.as_inner().as_inner().st_rdev as u64
+    }
+    fn st_size(&self) -> u64 {
+        self.as_inner().as_inner().st_size as u64
+    }
+    fn st_atime(&self) -> i64 {
+        self.as_inner().as_inner().st_atime as i64
+    }
+    fn st_atime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_atime_nsec as i64
+    }
+    fn st_mtime(&self) -> i64 {
+        self.as_inner().as_inner().st_mtime as i64
+    }
+    fn st_mtime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_mtime_nsec as i64
+    }
+    fn st_ctime(&self) -> i64 {
+        self.as_inner().as_inner().st_ctime as i64
+    }
+    fn st_ctime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_ctime_nsec as i64
+    }
+    fn st_crtime(&self) -> i64 {
+        self.as_inner().as_inner().st_crtime as i64
+    }
+    fn st_crtime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_crtime_nsec as i64
+    }
+    fn st_blksize(&self) -> u64 {
+        self.as_inner().as_inner().st_blksize as u64
+    }
+    fn st_blocks(&self) -> u64 {
+        self.as_inner().as_inner().st_blocks as u64
+    }
+}
diff --git a/src/libstd/os/haiku/mod.rs b/src/libstd/os/haiku/mod.rs
new file mode 100644 (file)
index 0000000..dd1675c
--- /dev/null
@@ -0,0 +1,16 @@
+// 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.
+
+//! Haiku-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/haiku/raw.rs b/src/libstd/os/haiku/raw.rs
new file mode 100644 (file)
index 0000000..95353d9
--- /dev/null
@@ -0,0 +1,74 @@
+// 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.
+
+//! Haiku-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+#![allow(deprecated)]
+
+use os::raw::{c_long};
+use os::unix::raw::{uid_t, gid_t};
+
+// Use the direct definition of usize, instead of uintptr_t like in libc
+#[stable(feature = "pthread_t", since = "1.8.0")] pub type pthread_t = usize;
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = i32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = i32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = i64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = i32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = i64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_dev: dev_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_ino: ino_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_mode: mode_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_nlink: nlink_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_uid: uid_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_gid: gid_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_size: off_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_rdev: dev_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_blksize: blksize_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_atime: time_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_atime_nsec: c_long,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_mtime: time_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_mtime_nsec: c_long,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_ctime: time_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_ctime_nsec: c_long,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_crtime: time_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_crtime_nsec: c_long,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_type: u32,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_blocks: blkcnt_t,
+}
index 1c19e58818d743e5fb67c2da76c45e8c2dbf48e4..e6a95bc831ffbafdbea5df3a14e5610d2c8cb32f 100644 (file)
@@ -34,7 +34,8 @@
           target_arch = "le32",
           target_arch = "powerpc",
           target_arch = "arm",
-          target_arch = "asmjs"))]
+          target_arch = "asmjs",
+          target_arch = "wasm32"))]
 mod arch {
     use os::raw::{c_long, c_short, c_uint};
 
index a91d251fc120aaa504823dbfcd68afa4d27bfb57..7622ef886935c3e601328a6dafe01d9a1f3e560e 100644 (file)
@@ -24,6 +24,7 @@
 #[cfg(target_os = "bitrig")]    pub mod bitrig;
 #[cfg(target_os = "dragonfly")] pub mod dragonfly;
 #[cfg(target_os = "freebsd")]   pub mod freebsd;
+#[cfg(target_os = "haiku")]     pub mod haiku;
 #[cfg(target_os = "ios")]       pub mod ios;
 #[cfg(target_os = "linux")]     pub mod linux;
 #[cfg(target_os = "macos")]     pub mod macos;
index bd27bcf48a09d3671b9392aea2b5ba5d72941fe7..fdc1978b0c5012bd5be5edf1c86300b5f996525e 100644 (file)
 
 use ffi::{OsStr, OsString};
 
-use self::platform::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix};
+use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix};
 
 ////////////////////////////////////////////////////////////////////////////////
 // GENERAL NOTES
 // OsStr APIs for parsing, but it will take a while for those to become
 // available.
 
-////////////////////////////////////////////////////////////////////////////////
-// Platform-specific definitions
-////////////////////////////////////////////////////////////////////////////////
-
-// The following modules give the most basic tools for parsing paths on various
-// platforms. The bulk of the code is devoted to parsing prefixes on Windows.
-
-#[cfg(unix)]
-mod platform {
-    use super::Prefix;
-    use ffi::OsStr;
-
-    #[inline]
-    pub fn is_sep_byte(b: u8) -> bool {
-        b == b'/'
-    }
-
-    #[inline]
-    pub fn is_verbatim_sep(b: u8) -> bool {
-        b == b'/'
-    }
-
-    pub fn parse_prefix(_: &OsStr) -> Option<Prefix> {
-        None
-    }
-
-    pub const MAIN_SEP_STR: &'static str = "/";
-    pub const MAIN_SEP: char = '/';
-}
-
-#[cfg(windows)]
-mod platform {
-    use ascii::*;
-
-    use super::{os_str_as_u8_slice, u8_slice_as_os_str, Prefix};
-    use ffi::OsStr;
-
-    #[inline]
-    pub fn is_sep_byte(b: u8) -> bool {
-        b == b'/' || b == b'\\'
-    }
-
-    #[inline]
-    pub fn is_verbatim_sep(b: u8) -> bool {
-        b == b'\\'
-    }
-
-    pub fn parse_prefix<'a>(path: &'a OsStr) -> Option<Prefix> {
-        use super::Prefix::*;
-        unsafe {
-            // The unsafety here stems from converting between &OsStr and &[u8]
-            // and back. This is safe to do because (1) we only look at ASCII
-            // contents of the encoding and (2) new &OsStr values are produced
-            // only from ASCII-bounded slices of existing &OsStr values.
-            let mut path = os_str_as_u8_slice(path);
-
-            if path.starts_with(br"\\") {
-                // \\
-                path = &path[2..];
-                if path.starts_with(br"?\") {
-                    // \\?\
-                    path = &path[2..];
-                    if path.starts_with(br"UNC\") {
-                        // \\?\UNC\server\share
-                        path = &path[4..];
-                        let (server, share) = match parse_two_comps(path, is_verbatim_sep) {
-                            Some((server, share)) =>
-                                (u8_slice_as_os_str(server), u8_slice_as_os_str(share)),
-                            None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])),
-                        };
-                        return Some(VerbatimUNC(server, share));
-                    } else {
-                        // \\?\path
-                        let idx = path.iter().position(|&b| b == b'\\');
-                        if idx == Some(2) && path[1] == b':' {
-                            let c = path[0];
-                            if c.is_ascii() && (c as char).is_alphabetic() {
-                                // \\?\C:\ path
-                                return Some(VerbatimDisk(c.to_ascii_uppercase()));
-                            }
-                        }
-                        let slice = &path[..idx.unwrap_or(path.len())];
-                        return Some(Verbatim(u8_slice_as_os_str(slice)));
-                    }
-                } else if path.starts_with(b".\\") {
-                    // \\.\path
-                    path = &path[2..];
-                    let pos = path.iter().position(|&b| b == b'\\');
-                    let slice = &path[..pos.unwrap_or(path.len())];
-                    return Some(DeviceNS(u8_slice_as_os_str(slice)));
-                }
-                match parse_two_comps(path, is_sep_byte) {
-                    Some((server, share)) if !server.is_empty() && !share.is_empty() => {
-                        // \\server\share
-                        return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)));
-                    }
-                    _ => (),
-                }
-            } else if path.get(1) == Some(& b':') {
-                // C:
-                let c = path[0];
-                if c.is_ascii() && (c as char).is_alphabetic() {
-                    return Some(Disk(c.to_ascii_uppercase()));
-                }
-            }
-            return None;
-        }
-
-        fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> {
-            let first = match path.iter().position(|x| f(*x)) {
-                None => return None,
-                Some(x) => &path[..x],
-            };
-            path = &path[(first.len() + 1)..];
-            let idx = path.iter().position(|x| f(*x));
-            let second = &path[..idx.unwrap_or(path.len())];
-            Some((first, second))
-        }
-    }
-
-    pub const MAIN_SEP_STR: &'static str = "\\";
-    pub const MAIN_SEP: char = '\\';
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Windows Prefixes
 ////////////////////////////////////////////////////////////////////////////////
@@ -373,7 +249,7 @@ pub fn is_separator(c: char) -> bool {
 
 /// The primary separator for the current platform
 #[stable(feature = "rust1", since = "1.0.0")]
-pub const MAIN_SEPARATOR: char = platform::MAIN_SEP;
+pub const MAIN_SEPARATOR: char = ::sys::path::MAIN_SEP;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Misc helpers
index f0c4443070074aa3318f11605b11ba8abebf8b97..9d21a76e81b9e41f4e39ebe1af7fba669e002aa2 100644 (file)
@@ -8,7 +8,25 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Working with processes.
+//! A module for working with processes.
+//!
+//! # Examples
+//!
+//! Basic usage where we try to execute the `cat` shell command:
+//!
+//! ```should_panic
+//! use std::process::Command;
+//!
+//! let mut child = Command::new("/bin/cat")
+//!                         .arg("file.txt")
+//!                         .spawn()
+//!                         .expect("failed to execute child");
+//!
+//! let ecode = child.wait()
+//!                  .expect("failed to wait on child");
+//!
+//! assert!(ecode.success());
+//! ```
 
 #![stable(feature = "process", since = "1.0.0")]
 
@@ -807,7 +825,7 @@ pub fn exit(code: i32) -> ! {
     ::sys::os::exit(code)
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use io::prelude::*;
 
index 3f14fcd239f1d0ceb2d6d36f32da74a3a845c345..69cd37651d5c28bde1bc9d5427975abea94e0133 100644 (file)
@@ -242,6 +242,7 @@ fn test_os_rng() {
     }
 
     #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn test_os_rng_tasks() {
 
         let mut txs = vec!();
index e3de1efaa31e3051457741b68523d92c37a3ea53..78d5aa597ba0df01f33a1ae000f70bc9414b7b2a 100644 (file)
@@ -51,7 +51,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
         thread_info::set(main_guard, thread);
 
         // Store our args if necessary in a squirreled away location
-        sys_common::args::init(argc, argv);
+        sys::args::init(argc, argv);
 
         // Let's run some code!
         let res = panic::catch_unwind(mem::transmute::<_, fn()>(main));
index a11200873d500b980ea89326f7f621689e0f87c1..5dc6ee2bc8c660921d7f1cac3062ce41525d0e47 100644 (file)
@@ -62,3 +62,7 @@
 #[cfg(target_os = "ios")]
 #[link(name = "System")]
 extern {}
+
+#[cfg(target_os = "haiku")]
+#[link(name = "network")]
+extern {}
index ac0f400379e3cabf3504a10b496426774e2c0659..f46eab684846384a9b5245657d11f20bd450d867 100644 (file)
@@ -118,6 +118,7 @@ mod tests {
     use thread;
 
     #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn test_barrier() {
         const N: usize = 10;
 
index 3db8b05b954c3dacf4b157a8edc73f9d83118613..a983ae716a4816d387c75659c4dedafc3a5007e3 100644 (file)
@@ -270,6 +270,7 @@ fn smoke() {
     }
 
     #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn notify_one() {
         let m = Arc::new(Mutex::new(()));
         let m2 = m.clone();
@@ -286,6 +287,7 @@ fn notify_one() {
     }
 
     #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn notify_all() {
         const N: usize = 10;
 
@@ -322,6 +324,7 @@ fn notify_all() {
     }
 
     #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn wait_timeout_ms() {
         let m = Arc::new(Mutex::new(()));
         let m2 = m.clone();
@@ -343,6 +346,7 @@ fn wait_timeout_ms() {
 
     #[test]
     #[should_panic]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn two_mutexes() {
         let m = Arc::new(Mutex::new(()));
         let m2 = m.clone();
index 3d9f81413dc734202b1e8a6df174ed35703b2d2b..d9c14ef2f771eb83a81cdb8ea9130704449d66d9 100644 (file)
@@ -1268,7 +1268,7 @@ fn cause(&self) -> Option<&error::Error> {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use env;
     use super::*;
@@ -1942,7 +1942,7 @@ fn destroy_upgraded_shared_port_when_sender_still_active() {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod sync_tests {
     use env;
     use thread;
index d926043fbbcd074e37fae9807f07b6a34cbfcce8..8d80f942ff75cb9f50c29919c75d7beaf6a21466 100644 (file)
@@ -146,7 +146,7 @@ fn drop(&mut self) {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use sync::mpsc::channel;
     use super::{Queue, Data, Empty, Inconsistent};
index 51b08bd75c4bc3475548171cf9dd1ec018619629..e056a350815a79d6fa4b3af11e05fd03f6c37766 100644 (file)
@@ -366,8 +366,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-#[cfg(test)]
 #[allow(unused_imports)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use thread;
     use sync::mpsc::*;
index 724d7b1be730d59953620950ffa5ca20f55b5172..5858e4b6ddb1f2ab35312aaa4a5406baa84ca29c 100644 (file)
@@ -231,7 +231,7 @@ fn drop(&mut self) {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use sync::Arc;
     use super::Queue;
index 098a3e44258c77f2d116826b5dffe71560d355e5..812724c7a167eaf13e61801d079dd421222c9315 100644 (file)
@@ -352,7 +352,7 @@ pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Fla
     &guard.__lock.poison
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use sync::mpsc::channel;
     use sync::{Arc, Mutex, Condvar};
index 86d2986959c999abee5e10c3761f16f4fa0253fc..ad9d0b375442200be9ecf0cf59fb04d64dcfdd44 100644 (file)
@@ -367,7 +367,7 @@ pub fn poisoned(&self) -> bool {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use panic;
     use sync::mpsc::channel;
index 7f053c6704b56dffb09b5b32bf135fbc07345ef9..48ecae185f95c37e9e9a54a3e24c121587bb5fcc 100644 (file)
@@ -380,7 +380,7 @@ fn drop(&mut self) {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     #![allow(deprecated)] // rand
 
diff --git a/src/libstd/sys/common/args.rs b/src/libstd/sys/common/args.rs
deleted file mode 100644 (file)
index fad2c27..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Global storage for command line arguments
-//!
-//! The current incarnation of the Rust runtime expects for
-//! the processes `argc` and `argv` arguments to be stored
-//! in a globally-accessible location for use by the `os` module.
-//!
-//! Only valid to call on Linux. Mac and Windows use syscalls to
-//! discover the command line arguments.
-//!
-//! FIXME #7756: Would be nice for this to not exist.
-
-#![allow(dead_code)] // different code on OSX/linux/etc
-
-/// One-time global initialization.
-pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
-
-/// One-time global cleanup.
-pub unsafe fn cleanup() { imp::cleanup() }
-
-/// Make a clone of the global arguments.
-pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
-
-#[cfg(any(target_os = "linux",
-          target_os = "android",
-          target_os = "freebsd",
-          target_os = "dragonfly",
-          target_os = "bitrig",
-          target_os = "netbsd",
-          target_os = "openbsd",
-          target_os = "solaris",
-          target_os = "emscripten"))]
-mod imp {
-    use libc::c_char;
-    use mem;
-    use ffi::CStr;
-
-    use sys_common::mutex::Mutex;
-
-    static mut GLOBAL_ARGS_PTR: usize = 0;
-    static LOCK: Mutex = Mutex::new();
-
-    pub unsafe fn init(argc: isize, argv: *const *const u8) {
-        let args = (0..argc).map(|i| {
-            CStr::from_ptr(*argv.offset(i) as *const c_char).to_bytes().to_vec()
-        }).collect();
-
-        LOCK.lock();
-        let ptr = get_global_ptr();
-        assert!((*ptr).is_none());
-        (*ptr) = Some(box args);
-        LOCK.unlock();
-    }
-
-    pub unsafe fn cleanup() {
-        LOCK.lock();
-        *get_global_ptr() = None;
-        LOCK.unlock();
-    }
-
-    pub fn clone() -> Option<Vec<Vec<u8>>> {
-        unsafe {
-            LOCK.lock();
-            let ptr = get_global_ptr();
-            let ret = (*ptr).as_ref().map(|s| (**s).clone());
-            LOCK.unlock();
-            return ret
-        }
-    }
-
-    fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
-        unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
-    }
-
-}
-
-#[cfg(any(target_os = "macos",
-          target_os = "ios",
-          target_os = "windows"))]
-mod imp {
-    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
-    }
-
-    pub fn cleanup() {
-    }
-
-    pub fn clone() -> Option<Vec<Vec<u8>>> {
-        panic!()
-    }
-}
index 3cd70eddb858c1d0f8566855ff2fb0aca5fa478c..0483725dd83bc22631aec0f0bc15a988e7ddd8f2 100644 (file)
@@ -51,6 +51,7 @@ pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::
 }
 
 #[cfg(test)]
+#[allow(dead_code)] // not used on emscripten
 pub mod test {
     use path::{Path, PathBuf};
     use env;
@@ -165,6 +166,7 @@ fn read_to_end_uninit_good() {
     }
 
     #[bench]
+    #[cfg_attr(target_os = "emscripten", ignore)]
     fn bench_uninitialized(b: &mut ::test::Bencher) {
         b.iter(|| {
             let mut lr = repeat(1).take(10000000);
diff --git a/src/libstd/sys/common/memchr.rs b/src/libstd/sys/common/memchr.rs
new file mode 100644 (file)
index 0000000..3824a5f
--- /dev/null
@@ -0,0 +1,230 @@
+// 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.
+//
+// Original implementation taken from rust-memchr
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+#[allow(dead_code)]
+pub mod fallback {
+    use cmp;
+    use mem;
+
+    const LO_U64: u64 = 0x0101010101010101;
+    const HI_U64: u64 = 0x8080808080808080;
+
+    // use truncation
+    const LO_USIZE: usize = LO_U64 as usize;
+    const HI_USIZE: usize = HI_U64 as usize;
+
+    /// Return `true` if `x` contains any zero byte.
+    ///
+    /// From *Matters Computational*, J. Arndt
+    ///
+    /// "The idea is to subtract one from each of the bytes and then look for
+    /// bytes where the borrow propagated all the way to the most significant
+    /// bit."
+    #[inline]
+    fn contains_zero_byte(x: usize) -> bool {
+        x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
+    }
+
+    #[cfg(target_pointer_width = "32")]
+    #[inline]
+    fn repeat_byte(b: u8) -> usize {
+        let mut rep = (b as usize) << 8 | b as usize;
+        rep = rep << 16 | rep;
+        rep
+    }
+
+    #[cfg(target_pointer_width = "64")]
+    #[inline]
+    fn repeat_byte(b: u8) -> usize {
+        let mut rep = (b as usize) << 8 | b as usize;
+        rep = rep << 16 | rep;
+        rep = rep << 32 | rep;
+        rep
+    }
+
+    /// Return the first index matching the byte `a` in `text`.
+    pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
+        // Scan for a single byte value by reading two `usize` words at a time.
+        //
+        // Split `text` in three parts
+        // - unaligned initial part, before the first word aligned address in text
+        // - body, scan by 2 words at a time
+        // - the last remaining part, < 2 word size
+        let len = text.len();
+        let ptr = text.as_ptr();
+        let usize_bytes = mem::size_of::<usize>();
+
+        // search up to an aligned boundary
+        let align = (ptr as usize) & (usize_bytes- 1);
+        let mut offset;
+        if align > 0 {
+            offset = cmp::min(usize_bytes - align, len);
+            if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
+                return Some(index);
+            }
+        } else {
+            offset = 0;
+        }
+
+        // search the body of the text
+        let repeated_x = repeat_byte(x);
+
+        if len >= 2 * usize_bytes {
+            while offset <= len - 2 * usize_bytes {
+                unsafe {
+                    let u = *(ptr.offset(offset as isize) as *const usize);
+                    let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);
+
+                    // break if there is a matching byte
+                    let zu = contains_zero_byte(u ^ repeated_x);
+                    let zv = contains_zero_byte(v ^ repeated_x);
+                    if zu || zv {
+                        break;
+                    }
+                }
+                offset += usize_bytes * 2;
+            }
+        }
+
+        // find the byte after the point the body loop stopped
+        text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
+    }
+
+    /// Return the last index matching the byte `a` in `text`.
+    pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
+        // Scan for a single byte value by reading two `usize` words at a time.
+        //
+        // Split `text` in three parts
+        // - unaligned tail, after the last word aligned address in text
+        // - body, scan by 2 words at a time
+        // - the first remaining bytes, < 2 word size
+        let len = text.len();
+        let ptr = text.as_ptr();
+        let usize_bytes = mem::size_of::<usize>();
+
+        // search to an aligned boundary
+        let end_align = (ptr as usize + len) & (usize_bytes - 1);
+        let mut offset;
+        if end_align > 0 {
+            offset = if end_align >= len { 0 } else { len - end_align };
+            if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
+                return Some(offset + index);
+            }
+        } else {
+            offset = len;
+        }
+
+        // search the body of the text
+        let repeated_x = repeat_byte(x);
+
+        while offset >= 2 * usize_bytes {
+            unsafe {
+                let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
+                let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);
+
+                // break if there is a matching byte
+                let zu = contains_zero_byte(u ^ repeated_x);
+                let zv = contains_zero_byte(v ^ repeated_x);
+                if zu || zv {
+                    break;
+                }
+            }
+            offset -= 2 * usize_bytes;
+        }
+
+        // find the byte before the point the body loop stopped
+        text[..offset].iter().rposition(|elt| *elt == x)
+    }
+
+    // test fallback implementations on all platforms
+    #[test]
+    fn matches_one() {
+        assert_eq!(Some(0), memchr(b'a', b"a"));
+    }
+
+    #[test]
+    fn matches_begin() {
+        assert_eq!(Some(0), memchr(b'a', b"aaaa"));
+    }
+
+    #[test]
+    fn matches_end() {
+        assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
+    }
+
+    #[test]
+    fn matches_nul() {
+        assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
+    }
+
+    #[test]
+    fn matches_past_nul() {
+        assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
+    }
+
+    #[test]
+    fn no_match_empty() {
+        assert_eq!(None, memchr(b'a', b""));
+    }
+
+    #[test]
+    fn no_match() {
+        assert_eq!(None, memchr(b'a', b"xyz"));
+    }
+
+    #[test]
+    fn matches_one_reversed() {
+        assert_eq!(Some(0), memrchr(b'a', b"a"));
+    }
+
+    #[test]
+    fn matches_begin_reversed() {
+        assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
+    }
+
+    #[test]
+    fn matches_end_reversed() {
+        assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
+    }
+
+    #[test]
+    fn matches_nul_reversed() {
+        assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
+    }
+
+    #[test]
+    fn matches_past_nul_reversed() {
+        assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
+    }
+
+    #[test]
+    fn no_match_empty_reversed() {
+        assert_eq!(None, memrchr(b'a', b""));
+    }
+
+    #[test]
+    fn no_match_reversed() {
+        assert_eq!(None, memrchr(b'a', b"xyz"));
+    }
+
+    #[test]
+    fn each_alignment_reversed() {
+        let mut data = [1u8; 64];
+        let needle = 2;
+        let pos = 40;
+        data[pos] = needle;
+        for start in 0..16 {
+            assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
+        }
+    }
+}
index d1ca676510714d1548ae005c08fc4e10d523f90f..2845f895f1869e30a174b6f3fde86c6ade9f73fd 100644 (file)
@@ -25,12 +25,12 @@ macro_rules! rtassert {
     })
 }
 
-pub mod args;
 pub mod at_exit_imp;
 #[cfg(any(not(cargobuild), feature = "backtrace"))]
 pub mod backtrace;
 pub mod condvar;
 pub mod io;
+pub mod memchr;
 pub mod mutex;
 pub mod net;
 pub mod poison;
@@ -91,7 +91,7 @@ pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
 pub fn cleanup() {
     static CLEANUP: Once = Once::new();
     CLEANUP.call_once(|| unsafe {
-        args::cleanup();
+        sys::args::cleanup();
         sys::stack_overflow::cleanup();
         at_exit_imp::cleanup();
     });
index a777cfe35e56d4125a9a565584ae96ebc1fca11a..2599bb660e813de607551694d513973217fedef4 100644 (file)
 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
           target_os = "ios", target_os = "macos",
           target_os = "openbsd", target_os = "netbsd",
-          target_os = "solaris"))]
+          target_os = "solaris", target_os = "haiku"))]
 use sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
 #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
               target_os = "ios", target_os = "macos",
               target_os = "openbsd", target_os = "netbsd",
-              target_os = "solaris")))]
+              target_os = "solaris", taget_os = "haiku")))]
 use sys::net::netc::IPV6_ADD_MEMBERSHIP;
 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
           target_os = "ios", target_os = "macos",
           target_os = "openbsd", target_os = "netbsd",
-          target_os = "solaris"))]
+          target_os = "solaris", target_os = "haiku"))]
 use sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
 #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
               target_os = "ios", target_os = "macos",
               target_os = "openbsd", target_os = "netbsd",
-              target_os = "solaris")))]
+              target_os = "solaris", target_os = "haiku")))]
 use sys::net::netc::IPV6_DROP_MEMBERSHIP;
 
+#[cfg(target_os = "linux")]
+use libc::MSG_NOSIGNAL;
+#[cfg(not(target_os = "linux"))]
+const MSG_NOSIGNAL: c_int = 0x0; // unused dummy value
+
 ////////////////////////////////////////////////////////////////////////////////
 // sockaddr and misc bindings
 ////////////////////////////////////////////////////////////////////////////////
@@ -225,7 +230,7 @@ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
             c::send(*self.inner.as_inner(),
                     buf.as_ptr() as *const c_void,
                     len,
-                    0)
+                    MSG_NOSIGNAL)
         })?;
         Ok(ret as usize)
     }
@@ -449,7 +454,7 @@ pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
         let ret = cvt(unsafe {
             c::sendto(*self.inner.as_inner(),
                       buf.as_ptr() as *const c_void, len,
-                      0, dstp, dstlen)
+                      MSG_NOSIGNAL, dstp, dstlen)
         })?;
         Ok(ret as usize)
     }
@@ -573,7 +578,7 @@ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
             c::send(*self.inner.as_inner(),
                     buf.as_ptr() as *const c_void,
                     len,
-                    0)
+                    MSG_NOSIGNAL)
         })?;
         Ok(ret as usize)
     }
index cbdeaad7f6bd3acfbff16c2cb7fa25ab688f904a..4d0407ccf6c8903bb20eee0059b492319a94d81f 100644 (file)
@@ -156,7 +156,7 @@ fn drop(&mut self) {
 }
 
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
     use cell::RefCell;
index 8d357aa78c9e93568b91f508ea373052a523b58d..0a94ff1e958236e6337d8700ab4bb9f36bfff905 100644 (file)
@@ -206,10 +206,12 @@ pub fn from_wide(v: &[u16]) -> Wtf8Buf {
     /// Copied from String::push
     /// This does **not** include the WTF-8 concatenation check.
     fn push_code_point_unchecked(&mut self, code_point: CodePoint) {
-        let bytes = unsafe {
-            char::from_u32_unchecked(code_point.value).encode_utf8()
+        let c = unsafe {
+            char::from_u32_unchecked(code_point.value)
         };
-        self.bytes.extend_from_slice(bytes.as_slice());
+        let mut bytes = [0; 4];
+        let bytes = c.encode_utf8(&mut bytes).as_bytes();
+        self.bytes.extend_from_slice(bytes)
     }
 
     #[inline]
@@ -738,15 +740,16 @@ fn next(&mut self) -> Option<u16> {
             return Some(tmp);
         }
 
+        let mut buf = [0; 2];
         self.code_points.next().map(|code_point| {
-            let n = unsafe {
-                char::from_u32_unchecked(code_point.value).encode_utf16()
+            let c = unsafe {
+                char::from_u32_unchecked(code_point.value)
             };
-            let n = n.as_slice();
-            if n.len() == 2 {
-                self.extra = n[1];
+            let n = c.encode_utf16(&mut buf).len();
+            if n == 2 {
+                self.extra = buf[1];
             }
-            n[0]
+            buf[0]
         })
     }
 
diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs
new file mode 100644 (file)
index 0000000..c64db33
--- /dev/null
@@ -0,0 +1,211 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Global initialization and retreival of command line arguments.
+//!
+//! On some platforms these are stored during runtime startup,
+//! and on some they are retrieved from the system on demand.
+
+#![allow(dead_code)] // runtime init functions not used during testing
+
+use ffi::OsString;
+use marker::PhantomData;
+use vec;
+
+/// One-time global initialization.
+pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
+
+/// One-time global cleanup.
+pub unsafe fn cleanup() { imp::cleanup() }
+
+/// Returns the command line arguments
+pub fn args() -> Args {
+    imp::args()
+}
+
+pub struct Args {
+    iter: vec::IntoIter<OsString>,
+    _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> { self.iter.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize { self.iter.len() }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
+}
+
+#[cfg(any(target_os = "linux",
+          target_os = "android",
+          target_os = "freebsd",
+          target_os = "dragonfly",
+          target_os = "bitrig",
+          target_os = "netbsd",
+          target_os = "openbsd",
+          target_os = "solaris",
+          target_os = "emscripten",
+          target_os = "haiku"))]
+mod imp {
+    use os::unix::prelude::*;
+    use mem;
+    use ffi::{CStr, OsString};
+    use marker::PhantomData;
+    use libc;
+    use super::Args;
+
+    use sys_common::mutex::Mutex;
+
+    static mut GLOBAL_ARGS_PTR: usize = 0;
+    static LOCK: Mutex = Mutex::new();
+
+    pub unsafe fn init(argc: isize, argv: *const *const u8) {
+        let args = (0..argc).map(|i| {
+            CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
+        }).collect();
+
+        LOCK.lock();
+        let ptr = get_global_ptr();
+        assert!((*ptr).is_none());
+        (*ptr) = Some(box args);
+        LOCK.unlock();
+    }
+
+    pub unsafe fn cleanup() {
+        LOCK.lock();
+        *get_global_ptr() = None;
+        LOCK.unlock();
+    }
+
+    pub fn args() -> Args {
+        let bytes = clone().unwrap_or(Vec::new());
+        let v: Vec<OsString> = bytes.into_iter().map(|v| {
+            OsStringExt::from_vec(v)
+        }).collect();
+        Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
+    }
+
+    fn clone() -> Option<Vec<Vec<u8>>> {
+        unsafe {
+            LOCK.lock();
+            let ptr = get_global_ptr();
+            let ret = (*ptr).as_ref().map(|s| (**s).clone());
+            LOCK.unlock();
+            return ret
+        }
+    }
+
+    fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
+        unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
+    }
+
+}
+
+#[cfg(any(target_os = "macos",
+          target_os = "ios"))]
+mod imp {
+    use ffi::CStr;
+    use marker::PhantomData;
+    use libc;
+    use super::Args;
+
+    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+    }
+
+    pub fn cleanup() {
+    }
+
+    #[cfg(target_os = "macos")]
+    pub fn args() -> Args {
+        use os::unix::prelude::*;
+        extern {
+            // These functions are in crt_externs.h.
+            fn _NSGetArgc() -> *mut libc::c_int;
+            fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
+        }
+
+        let vec = unsafe {
+            let (argc, argv) = (*_NSGetArgc() as isize,
+                                *_NSGetArgv() as *const *const libc::c_char);
+            (0.. argc as isize).map(|i| {
+                let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
+                OsStringExt::from_vec(bytes)
+            }).collect::<Vec<_>>()
+        };
+        Args {
+            iter: vec.into_iter(),
+            _dont_send_or_sync_me: PhantomData,
+        }
+    }
+
+    // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
+    // and use underscores in their names - they're most probably
+    // are considered private and therefore should be avoided
+    // Here is another way to get arguments using Objective C
+    // runtime
+    //
+    // In general it looks like:
+    // res = Vec::new()
+    // let args = [[NSProcessInfo processInfo] arguments]
+    // for i in (0..[args count])
+    //      res.push([args objectAtIndex:i])
+    // res
+    #[cfg(target_os = "ios")]
+    pub fn args() -> Args {
+        use ffi::OsString;
+        use mem;
+        use str;
+
+        extern {
+            fn sel_registerName(name: *const libc::c_uchar) -> Sel;
+            fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
+            fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
+        }
+
+        #[link(name = "Foundation", kind = "framework")]
+        #[link(name = "objc")]
+        #[cfg(not(cargobuild))]
+        extern {}
+
+        type Sel = *const libc::c_void;
+        type NsId = *const libc::c_void;
+
+        let mut res = Vec::new();
+
+        unsafe {
+            let process_info_sel = sel_registerName("processInfo\0".as_ptr());
+            let arguments_sel = sel_registerName("arguments\0".as_ptr());
+            let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
+            let count_sel = sel_registerName("count\0".as_ptr());
+            let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
+
+            let klass = objc_getClass("NSProcessInfo\0".as_ptr());
+            let info = objc_msgSend(klass, process_info_sel);
+            let args = objc_msgSend(info, arguments_sel);
+
+            let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
+            for i in 0..cnt {
+                let tmp = objc_msgSend(args, object_at_sel, i);
+                let utf_c_str: *const libc::c_char =
+                    mem::transmute(objc_msgSend(tmp, utf8_sel));
+                let bytes = CStr::from_ptr(utf_c_str).to_bytes();
+                res.push(OsString::from(str::from_utf8(bytes).unwrap()))
+            }
+        }
+
+        Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
+    }
+}
diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs
new file mode 100644 (file)
index 0000000..92c4899
--- /dev/null
@@ -0,0 +1,173 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(target_os = "linux")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "linux";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "macos")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "macos";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".dylib";
+    pub const DLL_EXTENSION: &'static str = "dylib";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "ios")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "ios";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".dylib";
+    pub const DLL_EXTENSION: &'static str = "dylib";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "freebsd")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "freebsd";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "dragonfly")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "dragonfly";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "bitrig")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "bitrig";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "netbsd")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "netbsd";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "openbsd")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "openbsd";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "android")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "android";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "solaris")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "solaris";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(all(target_os = "nacl", not(target_arch = "le32")))]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "nacl";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = ".nexe";
+    pub const EXE_EXTENSION: &'static str = "nexe";
+}
+#[cfg(all(target_os = "nacl", target_arch = "le32"))]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "pnacl";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".pso";
+    pub const DLL_EXTENSION: &'static str = "pso";
+    pub const EXE_SUFFIX: &'static str = ".pexe";
+    pub const EXE_EXTENSION: &'static str = "pexe";
+}
+
+#[cfg(target_os = "haiku")]
+mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "haiku";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))]
+mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "emscripten";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = ".js";
+    pub const EXE_EXTENSION: &'static str = "js";
+}
+
+#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))]
+mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "emscripten";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = ".js";
+    pub const EXE_EXTENSION: &'static str = "js";
+}
index 3f93fce1935611f236f611d3eb5ed9652617d851..622fd4b85a59afe2a9fedad389c4d93443374a4e 100644 (file)
 use sys::net::Socket;
 use sys_common::{AsInner, FromInner, IntoInner};
 
+#[cfg(target_os = "linux")]
+use libc::MSG_NOSIGNAL;
+#[cfg(not(target_os = "linux"))]
+const MSG_NOSIGNAL: libc::c_int = 0x0; // unused dummy value
+
 fn sun_path_offset() -> usize {
     unsafe {
         // Work with an actual instance of the type since using a null pointer is UB
@@ -690,7 +695,7 @@ fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result<usize> {
                 let count = cvt(libc::sendto(*d.0.as_inner(),
                                              buf.as_ptr() as *const _,
                                              buf.len(),
-                                             0,
+                                             MSG_NOSIGNAL,
                                              &addr as *const _ as *const _,
                                              len))?;
                 Ok(count as usize)
@@ -786,7 +791,7 @@ fn into_raw_fd(self) -> RawFd {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod test {
     use thread;
     use io;
index b2b1f16f20a9aed7b5542f283718aa43b6f34fe0..60c1750b4693c965b9a16c50f2af30e2a0ce561d 100644 (file)
@@ -59,14 +59,20 @@ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         Ok(ret as usize)
     }
 
-    #[cfg(not(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten")))]
+    #[cfg(not(any(target_env = "newlib",
+                  target_os = "solaris",
+                  target_os = "emscripten",
+                  target_os = "haiku")))]
     pub fn set_cloexec(&self) -> io::Result<()> {
         unsafe {
             cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
             Ok(())
         }
     }
-    #[cfg(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten"))]
+    #[cfg(any(target_env = "newlib",
+              target_os = "solaris",
+              target_os = "emscripten",
+              target_os = "haiku"))]
     pub fn set_cloexec(&self) -> io::Result<()> {
         unsafe {
             let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
@@ -104,9 +110,9 @@ pub fn duplicate(&self) -> io::Result<FileDesc> {
         // resolve so we at least compile this.
         //
         // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
-        #[cfg(target_os = "android")]
+        #[cfg(any(target_os = "android", target_os = "haiku"))]
         use libc::F_DUPFD as F_DUPFD_CLOEXEC;
-        #[cfg(not(target_os = "android"))]
+        #[cfg(not(any(target_os = "android", target_os="haiku")))]
         use libc::F_DUPFD_CLOEXEC;
 
         let make_filedesc = |fd| {
index e6fe3eb112a6093ea038044132736d8bdb5ef40e..d015aeee338dba7a3699bdf7509ef9ddd8e73c6c 100644 (file)
@@ -279,7 +279,12 @@ pub fn file_type(&self) -> io::Result<FileType> {
         stat(&self.path()).map(|m| m.file_type())
     }
 
-    #[cfg(not(target_os = "solaris"))]
+    #[cfg(target_os = "haiku")]
+    pub fn file_type(&self) -> io::Result<FileType> {
+        lstat(&self.path()).map(|m| m.file_type())
+    }
+
+    #[cfg(not(any(target_os = "solaris", target_os = "haiku")))]
     pub fn file_type(&self) -> io::Result<FileType> {
         match self.entry.d_type {
             libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }),
@@ -298,7 +303,8 @@ pub fn file_type(&self) -> io::Result<FileType> {
               target_os = "linux",
               target_os = "emscripten",
               target_os = "android",
-              target_os = "solaris"))]
+              target_os = "solaris",
+              target_os = "haiku"))]
     pub fn ino(&self) -> u64 {
         self.entry.d_ino as u64
     }
@@ -327,7 +333,8 @@ fn name_bytes(&self) -> &[u8] {
     }
     #[cfg(any(target_os = "android",
               target_os = "linux",
-              target_os = "emscripten"))]
+              target_os = "emscripten",
+              target_os = "haiku"))]
     fn name_bytes(&self) -> &[u8] {
         unsafe {
             CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()
diff --git a/src/libstd/sys/unix/memchr.rs b/src/libstd/sys/unix/memchr.rs
new file mode 100644 (file)
index 0000000..5038e07
--- /dev/null
@@ -0,0 +1,57 @@
+// 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.
+//
+// Original implementation taken from rust-memchr
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+    use libc;
+
+    let p = unsafe {
+        libc::memchr(
+            haystack.as_ptr() as *const libc::c_void,
+            needle as libc::c_int,
+            haystack.len() as libc::size_t)
+    };
+    if p.is_null() {
+        None
+    } else {
+        Some(p as usize - (haystack.as_ptr() as usize))
+    }
+}
+
+pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+
+    #[cfg(target_os = "linux")]
+    fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
+        use libc;
+
+        // GNU's memrchr() will - unlike memchr() - error if haystack is empty.
+        if haystack.is_empty() {return None}
+        let p = unsafe {
+            libc::memrchr(
+                haystack.as_ptr() as *const libc::c_void,
+                needle as libc::c_int,
+                haystack.len() as libc::size_t)
+        };
+        if p.is_null() {
+            None
+        } else {
+            Some(p as usize - (haystack.as_ptr() as usize))
+        }
+    }
+
+    #[cfg(not(target_os = "linux"))]
+    fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
+        ::sys_common::memchr::fallback::memrchr(needle, haystack)
+    }
+
+    memrchr_specific(needle, haystack)
+}
index 23687e10e476d40de9750064d09ded52a0624369..dc410cba89e04e4bfb4b52a0d39d30b75921ef85 100644 (file)
@@ -17,6 +17,7 @@
 #[cfg(target_os = "bitrig")]    pub use os::bitrig as platform;
 #[cfg(target_os = "dragonfly")] pub use os::dragonfly as platform;
 #[cfg(target_os = "freebsd")]   pub use os::freebsd as platform;
+#[cfg(target_os = "haiku")]     pub use os::haiku as platform;
 #[cfg(target_os = "ios")]       pub use os::ios as platform;
 #[cfg(target_os = "linux")]     pub use os::linux as platform;
 #[cfg(target_os = "macos")]     pub use os::macos as platform;
 #[macro_use]
 pub mod weak;
 
+pub mod args;
 pub mod android;
 #[cfg(any(not(cargobuild), feature = "backtrace"))]
 pub mod backtrace;
 pub mod condvar;
+pub mod env;
 pub mod ext;
 pub mod fd;
 pub mod fs;
+pub mod memchr;
 pub mod mutex;
 pub mod net;
 pub mod os;
 pub mod os_str;
+pub mod path;
 pub mod pipe;
 pub mod process;
 pub mod rand;
index f124ea651ec2c586ff2d317f49e90ae70556abbd..ad287bbec3889b276c5292c7fa6efa082600b472 100644 (file)
@@ -10,7 +10,7 @@
 
 use ffi::CStr;
 use io;
-use libc::{self, c_int, size_t, sockaddr, socklen_t};
+use libc::{self, c_int, size_t, sockaddr, socklen_t, EAI_SYSTEM};
 use net::{SocketAddr, Shutdown};
 use str;
 use sys::fd::FileDesc;
 #[cfg(not(target_os = "linux"))]
 const SOCK_CLOEXEC: c_int = 0;
 
+// Another conditional contant for name resolution: Macos et iOS use
+// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
+// Other platforms do otherwise.
+#[cfg(target_vendor = "apple")]
+use libc::SO_NOSIGPIPE;
+#[cfg(not(target_vendor = "apple"))]
+const SO_NOSIGPIPE: c_int = 0;
+
 pub struct Socket(FileDesc);
 
 pub fn init() {}
 
 pub fn cvt_gai(err: c_int) -> io::Result<()> {
-    if err == 0 { return Ok(()) }
+    if err == 0 {
+        return Ok(())
+    }
+    if err == EAI_SYSTEM {
+        return Err(io::Error::last_os_error())
+    }
 
     let detail = unsafe {
         str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap()
@@ -76,7 +89,11 @@ pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
             let fd = cvt(libc::socket(fam, ty, 0))?;
             let fd = FileDesc::new(fd);
             fd.set_cloexec()?;
-            Ok(Socket(fd))
+            let socket = Socket(fd);
+            if cfg!(target_vendor = "apple") {
+                setsockopt(&socket, libc::SOL_SOCKET, SO_NOSIGPIPE, 1)?;
+            }
+            Ok(socket)
         }
     }
 
index 82606d2c728ea7da2c7de529e470f2466a960a1c..c6118a333b192e5f24d2ce0b1a863c440578bec4 100644 (file)
@@ -51,6 +51,7 @@
                    target_os = "ios",
                    target_os = "freebsd"),
                link_name = "__error")]
+    #[cfg_attr(target_os = "haiku", link_name = "_errnop")]
     fn errno_location() -> *mut c_int;
 }
 
@@ -303,123 +304,47 @@ pub fn current_exe() -> io::Result<PathBuf> {
     }
 }
 
-pub struct Args {
-    iter: vec::IntoIter<OsString>,
-    _dont_send_or_sync_me: PhantomData<*mut ()>,
-}
-
-impl Iterator for Args {
-    type Item = OsString;
-    fn next(&mut self) -> Option<OsString> { self.iter.next() }
-    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
-}
-
-impl ExactSizeIterator for Args {
-    fn len(&self) -> usize { self.iter.len() }
-}
-
-impl DoubleEndedIterator for Args {
-    fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
-}
-
-/// Returns the command line arguments
-///
-/// Returns a list of the command line arguments.
-#[cfg(target_os = "macos")]
-pub fn args() -> Args {
-    extern {
-        // These functions are in crt_externs.h.
-        fn _NSGetArgc() -> *mut c_int;
-        fn _NSGetArgv() -> *mut *mut *mut c_char;
-    }
-
-    let vec = unsafe {
-        let (argc, argv) = (*_NSGetArgc() as isize,
-                            *_NSGetArgv() as *const *const c_char);
-        (0.. argc as isize).map(|i| {
-            let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
-            OsStringExt::from_vec(bytes)
-        }).collect::<Vec<_>>()
-    };
-    Args {
-        iter: vec.into_iter(),
-        _dont_send_or_sync_me: PhantomData,
-    }
-}
-
-// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
-// and use underscores in their names - they're most probably
-// are considered private and therefore should be avoided
-// Here is another way to get arguments using Objective C
-// runtime
-//
-// In general it looks like:
-// res = Vec::new()
-// let args = [[NSProcessInfo processInfo] arguments]
-// for i in (0..[args count])
-//      res.push([args objectAtIndex:i])
-// res
-#[cfg(target_os = "ios")]
-pub fn args() -> Args {
-    use mem;
-
-    extern {
-        fn sel_registerName(name: *const libc::c_uchar) -> Sel;
-        fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
-        fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
+#[cfg(target_os = "haiku")]
+pub fn current_exe() -> io::Result<PathBuf> {
+    // Use Haiku's image info functions
+    #[repr(C)]
+    struct image_info {
+        id: i32,
+        type_: i32,
+        sequence: i32,
+        init_order: i32,
+        init_routine: *mut libc::c_void,    // function pointer
+        term_routine: *mut libc::c_void,    // function pointer
+        device: libc::dev_t,
+        node: libc::ino_t,
+        name: [libc::c_char; 1024],         // MAXPATHLEN
+        text: *mut libc::c_void,
+        data: *mut libc::c_void,
+        text_size: i32,
+        data_size: i32,
+        api_version: i32,
+        abi: i32,
     }
 
-    #[link(name = "Foundation", kind = "framework")]
-    #[link(name = "objc")]
-    #[cfg(not(cargobuild))]
-    extern {}
-
-    type Sel = *const libc::c_void;
-    type NsId = *const libc::c_void;
-
-    let mut res = Vec::new();
-
     unsafe {
-        let process_info_sel = sel_registerName("processInfo\0".as_ptr());
-        let arguments_sel = sel_registerName("arguments\0".as_ptr());
-        let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
-        let count_sel = sel_registerName("count\0".as_ptr());
-        let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
-
-        let klass = objc_getClass("NSProcessInfo\0".as_ptr());
-        let info = objc_msgSend(klass, process_info_sel);
-        let args = objc_msgSend(info, arguments_sel);
-
-        let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
-        for i in 0..cnt {
-            let tmp = objc_msgSend(args, object_at_sel, i);
-            let utf_c_str: *const libc::c_char =
-                mem::transmute(objc_msgSend(tmp, utf8_sel));
-            let bytes = CStr::from_ptr(utf_c_str).to_bytes();
-            res.push(OsString::from(str::from_utf8(bytes).unwrap()))
+        extern {
+            fn _get_next_image_info(team_id: i32, cookie: *mut i32,
+                info: *mut image_info, size: i32) -> i32;
         }
-    }
 
-    Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
-}
-
-#[cfg(any(target_os = "linux",
-          target_os = "android",
-          target_os = "freebsd",
-          target_os = "dragonfly",
-          target_os = "bitrig",
-          target_os = "netbsd",
-          target_os = "openbsd",
-          target_os = "solaris",
-          target_os = "nacl",
-          target_os = "emscripten"))]
-pub fn args() -> Args {
-    use sys_common;
-    let bytes = sys_common::args::clone().unwrap_or(Vec::new());
-    let v: Vec<OsString> = bytes.into_iter().map(|v| {
-        OsStringExt::from_vec(v)
-    }).collect();
-    Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
+        let mut info: image_info = mem::zeroed();
+        let mut cookie: i32 = 0;
+        // the executable can be found at team id 0
+        let result = _get_next_image_info(0, &mut cookie, &mut info,
+            mem::size_of::<image_info>() as i32);
+        if result != 0 {
+            use io::ErrorKind;
+            Err(io::Error::new(ErrorKind::Other, "Error getting executable path"))
+        } else {
+            let name = CStr::from_ptr(info.name.as_ptr()).to_bytes();
+            Ok(PathBuf::from(OsStr::from_bytes(name)))
+        }
+    }
 }
 
 pub struct Env {
diff --git a/src/libstd/sys/unix/path.rs b/src/libstd/sys/unix/path.rs
new file mode 100644 (file)
index 0000000..bf9af7a
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use path::Prefix;
+use ffi::OsStr;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+    b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+    b == b'/'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix> {
+    None
+}
+
+pub const MAIN_SEP_STR: &'static str = "/";
+pub const MAIN_SEP: char = '/';
index 50014f51f6cf46420fbaaa2a3e2e68db15933f3e..dafc11d9cc8e9c7b01b01f1aeb0968d1254b9a3c 100644 (file)
@@ -369,7 +369,7 @@ macro_rules! t {
         }
 
         // NaCl has no signal support.
-        if cfg!(not(target_os = "nacl")) {
+        if cfg!(not(any(target_os = "nacl", target_os = "emscripten"))) {
             // Reset signal handling so the child process starts in a
             // standardized state. libstd ignores SIGPIPE, and signal-handling
             // libraries often set a mask. Child processes inherit ignored
@@ -589,7 +589,7 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use super::*;
 
index 972bdbc38186b06eab0373222b9b492e41e1d137..947ba2cc75232a72fdb8f0b6440c87445f55b837 100644 (file)
@@ -65,3 +65,5 @@ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
     }
     fn flush(&mut self) -> io::Result<()> { Ok(()) }
 }
+
+pub const EBADF_ERR: i32 = ::libc::EBADF as i32;
index 5db7086e42752b1387227bba79c10a30818b70aa..1e879117f73abf2e185c0d7b57a05ad38aaed1f3 100644 (file)
@@ -29,6 +29,20 @@ pub struct Thread {
 unsafe impl Send for Thread {}
 unsafe impl Sync for Thread {}
 
+// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc,
+// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS.
+#[cfg(not(target_os = "emscripten"))]
+unsafe fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
+                                    stack_size: libc::size_t) -> libc::c_int {
+    libc::pthread_attr_setstacksize(attr, stack_size)
+}
+
+#[cfg(target_os = "emscripten")]
+unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t,
+                                    _stack_size: libc::size_t) -> libc::c_int {
+    panic!()
+}
+
 impl Thread {
     pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
                           -> io::Result<Thread> {
@@ -38,8 +52,8 @@ pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
         assert_eq!(libc::pthread_attr_init(&mut attr), 0);
 
         let stack_size = cmp::max(stack, min_stack_size(&attr));
-        match libc::pthread_attr_setstacksize(&mut attr,
-                                              stack_size as libc::size_t) {
+        match pthread_attr_setstacksize(&mut attr,
+                                        stack_size as libc::size_t) {
             0 => {}
             n => {
                 assert_eq!(n, libc::EINVAL);
@@ -115,9 +129,12 @@ pub fn set_name(name: &CStr) {
                                      name.as_ptr() as *mut libc::c_void);
         }
     }
-    #[cfg(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten"))]
+    #[cfg(any(target_env = "newlib",
+              target_os = "solaris",
+              target_os = "haiku",
+              target_os = "emscripten"))]
     pub fn set_name(_name: &CStr) {
-        // Newlib, Illumos and Emscripten have no way to set a thread name.
+        // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name.
     }
 
     pub fn sleep(dur: Duration) {
diff --git a/src/libstd/sys/windows/args.rs b/src/libstd/sys/windows/args.rs
new file mode 100644 (file)
index 0000000..aa61f9a
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)] // runtime init functions not used during testing
+
+use os::windows::prelude::*;
+use sys::c;
+use slice;
+use ops::Range;
+use ffi::OsString;
+use libc::{c_int, c_void};
+
+pub unsafe fn init(_argc: isize, _argv: *const *const u8) { }
+
+pub unsafe fn cleanup() { }
+
+pub fn args() -> Args {
+    unsafe {
+        let mut nArgs: c_int = 0;
+        let lpCmdLine = c::GetCommandLineW();
+        let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs);
+
+        // szArcList can be NULL if CommandLinToArgvW failed,
+        // but in that case nArgs is 0 so we won't actually
+        // try to read a null pointer
+        Args { cur: szArgList, range: 0..(nArgs as isize) }
+    }
+}
+
+pub struct Args {
+    range: Range<isize>,
+    cur: *mut *mut u16,
+}
+
+unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString {
+    let mut len = 0;
+    while *ptr.offset(len) != 0 { len += 1; }
+
+    // Push it onto the list.
+    let ptr = ptr as *const u16;
+    let buf = slice::from_raw_parts(ptr, len as usize);
+    OsStringExt::from_wide(buf)
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> {
+        self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> {
+        self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
+    }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize { self.range.len() }
+}
+
+impl Drop for Args {
+    fn drop(&mut self) {
+        // self.cur can be null if CommandLineToArgvW previously failed,
+        // but LocalFree ignores NULL pointers
+        unsafe { c::LocalFree(self.cur as *mut c_void); }
+    }
+}
diff --git a/src/libstd/sys/windows/env.rs b/src/libstd/sys/windows/env.rs
new file mode 100644 (file)
index 0000000..e6d7489
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub mod os {
+    pub const FAMILY: &'static str = "windows";
+    pub const OS: &'static str = "windows";
+    pub const DLL_PREFIX: &'static str = "";
+    pub const DLL_SUFFIX: &'static str = ".dll";
+    pub const DLL_EXTENSION: &'static str = "dll";
+    pub const EXE_SUFFIX: &'static str = ".exe";
+    pub const EXE_EXTENSION: &'static str = "exe";
+}
diff --git a/src/libstd/sys/windows/memchr.rs b/src/libstd/sys/windows/memchr.rs
new file mode 100644 (file)
index 0000000..5a5386a
--- /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.
+//
+// Original implementation taken from rust-memchr
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+// Fallback memchr is fastest on windows
+pub use sys_common::memchr::fallback::{memchr, memrchr};
index 9741a704e8fe51e1ab5667157fe37be52b3cac07..9cd6e6ca1761dfa23937f2628b27d3820d605eeb 100644 (file)
 
 #[macro_use] pub mod compat;
 
+pub mod args;
 pub mod backtrace;
 pub mod c;
 pub mod condvar;
 pub mod dynamic_lib;
+pub mod env;
 pub mod ext;
 pub mod fs;
 pub mod handle;
+pub mod memchr;
 pub mod mutex;
 pub mod net;
 pub mod os;
 pub mod os_str;
+pub mod path;
 pub mod pipe;
 pub mod process;
 pub mod rand;
index 260fc3c4db62ef8371929b95cdcb36e1b1754930..7e28dd1e259c8c1551e7f73fc97d2daaecc09501 100644 (file)
@@ -18,8 +18,6 @@
 use ffi::{OsString, OsStr};
 use fmt;
 use io;
-use libc::{c_int, c_void};
-use ops::Range;
 use os::windows::ffi::EncodeWide;
 use path::{self, PathBuf};
 use ptr;
@@ -272,60 +270,6 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
     }).map(|_| ())
 }
 
-pub struct Args {
-    range: Range<isize>,
-    cur: *mut *mut u16,
-}
-
-unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString {
-    let mut len = 0;
-    while *ptr.offset(len) != 0 { len += 1; }
-
-    // Push it onto the list.
-    let ptr = ptr as *const u16;
-    let buf = slice::from_raw_parts(ptr, len as usize);
-    OsStringExt::from_wide(buf)
-}
-
-impl Iterator for Args {
-    type Item = OsString;
-    fn next(&mut self) -> Option<OsString> {
-        self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
-    }
-    fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
-}
-
-impl DoubleEndedIterator for Args {
-    fn next_back(&mut self) -> Option<OsString> {
-        self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
-    }
-}
-
-impl ExactSizeIterator for Args {
-    fn len(&self) -> usize { self.range.len() }
-}
-
-impl Drop for Args {
-    fn drop(&mut self) {
-        // self.cur can be null if CommandLineToArgvW previously failed,
-        // but LocalFree ignores NULL pointers
-        unsafe { c::LocalFree(self.cur as *mut c_void); }
-    }
-}
-
-pub fn args() -> Args {
-    unsafe {
-        let mut nArgs: c_int = 0;
-        let lpCmdLine = c::GetCommandLineW();
-        let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs);
-
-        // szArcList can be NULL if CommandLinToArgvW failed,
-        // but in that case nArgs is 0 so we won't actually
-        // try to read a null pointer
-        Args { cur: szArgList, range: 0..(nArgs as isize) }
-    }
-}
-
 pub fn temp_dir() -> PathBuf {
     super::fill_utf16_buf(|buf, sz| unsafe {
         c::GetTempPathW(sz, buf)
diff --git a/src/libstd/sys/windows/path.rs b/src/libstd/sys/windows/path.rs
new file mode 100644 (file)
index 0000000..2b47808
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ascii::*;
+
+use path::Prefix;
+use ffi::OsStr;
+use mem;
+
+fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
+    unsafe { mem::transmute(s) }
+}
+unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
+    mem::transmute(s)
+}
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+    b == b'/' || b == b'\\'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+    b == b'\\'
+}
+
+pub fn parse_prefix<'a>(path: &'a OsStr) -> Option<Prefix> {
+    use path::Prefix::*;
+    unsafe {
+        // The unsafety here stems from converting between &OsStr and &[u8]
+        // and back. This is safe to do because (1) we only look at ASCII
+        // contents of the encoding and (2) new &OsStr values are produced
+        // only from ASCII-bounded slices of existing &OsStr values.
+        let mut path = os_str_as_u8_slice(path);
+
+        if path.starts_with(br"\\") {
+            // \\
+            path = &path[2..];
+            if path.starts_with(br"?\") {
+                // \\?\
+                path = &path[2..];
+                if path.starts_with(br"UNC\") {
+                    // \\?\UNC\server\share
+                    path = &path[4..];
+                    let (server, share) = match parse_two_comps(path, is_verbatim_sep) {
+                        Some((server, share)) =>
+                            (u8_slice_as_os_str(server), u8_slice_as_os_str(share)),
+                        None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])),
+                    };
+                    return Some(VerbatimUNC(server, share));
+                } else {
+                    // \\?\path
+                    let idx = path.iter().position(|&b| b == b'\\');
+                    if idx == Some(2) && path[1] == b':' {
+                        let c = path[0];
+                        if c.is_ascii() && (c as char).is_alphabetic() {
+                            // \\?\C:\ path
+                            return Some(VerbatimDisk(c.to_ascii_uppercase()));
+                        }
+                    }
+                    let slice = &path[..idx.unwrap_or(path.len())];
+                    return Some(Verbatim(u8_slice_as_os_str(slice)));
+                }
+            } else if path.starts_with(b".\\") {
+                // \\.\path
+                path = &path[2..];
+                let pos = path.iter().position(|&b| b == b'\\');
+                let slice = &path[..pos.unwrap_or(path.len())];
+                return Some(DeviceNS(u8_slice_as_os_str(slice)));
+            }
+            match parse_two_comps(path, is_sep_byte) {
+                Some((server, share)) if !server.is_empty() && !share.is_empty() => {
+                    // \\server\share
+                    return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)));
+                }
+                _ => (),
+            }
+        } else if path.get(1) == Some(& b':') {
+            // C:
+            let c = path[0];
+            if c.is_ascii() && (c as char).is_alphabetic() {
+                return Some(Disk(c.to_ascii_uppercase()));
+            }
+        }
+        return None;
+    }
+
+    fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> {
+        let first = match path.iter().position(|x| f(*x)) {
+            None => return None,
+            Some(x) => &path[..x],
+        };
+        path = &path[(first.len() + 1)..];
+        let idx = path.iter().position(|x| f(*x));
+        let second = &path[..idx.unwrap_or(path.len())];
+        Some((first, second))
+    }
+}
+
+pub const MAIN_SEP_STR: &'static str = "\\";
+pub const MAIN_SEP: char = '\\';
index 01249f05f620252134d8c53d5a4c7ea1edca267a..5f097d2631d9558c5e1129109aa19a85b898c71e 100644 (file)
@@ -205,3 +205,5 @@ pub fn handle(&self) -> &Handle {
 fn invalid_encoding() -> io::Error {
     io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
 }
+
+pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;
index c44dee49f14a69373eed7cbcf6952358b701f8e5..a333a7d967d240fa11f757543fe50f068c529cad 100644 (file)
@@ -524,7 +524,7 @@ pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use sync::mpsc::{channel, Sender};
     use cell::{Cell, UnsafeCell};
index d8e021bb04ff9d9aeaead09365b762e20c7401cf..901ff98fcb3c5fa51e23b52a83e42042cbb9d0ca 100644 (file)
 //!
 //! [`Cell`]: ../cell/struct.Cell.html
 //! [`RefCell`]: ../cell/struct.RefCell.html
-//! [`thread_local!`]: ../macro.thread_local!.html
+//! [`thread_local!`]: ../macro.thread_local.html
 //! [`with`]: struct.LocalKey.html#method.with
 
 #![stable(feature = "rust1", since = "1.0.0")]
@@ -741,7 +741,7 @@ fn _assert_both<T: Send + Sync>() {}
 // Tests
 ////////////////////////////////////////////////////////////////////////////////
 
-#[cfg(test)]
+#[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use any::Any;
     use sync::mpsc::{channel, Sender};
index 154f603c84f162f591c7fd75b8b8541676ca6024..6854f1e14fa137e3f3fa2ef99d98705b3bb5d271 100644 (file)
 pub struct SystemTime(time::SystemTime);
 
 /// An error returned from the `duration_since` method on `SystemTime`,
-/// used to learn about why how far in the opposite direction a timestamp lies.
+/// used to learn how far in the opposite direction a system time lies.
 #[derive(Clone, Debug)]
 #[stable(feature = "time2", since = "1.8.0")]
 pub struct SystemTimeError(Duration);
index 64a71133a8c0235aadf0a94f68be2e45288630b8..1f2dc228ded3468250cbc08ca6b49cc7a33cdd0f 100644 (file)
@@ -24,6 +24,7 @@ pub enum Os {
     Netbsd,
     Openbsd,
     NaCl,
+    Haiku,
     Solaris,
 }
 
@@ -146,6 +147,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             Os::Netbsd => "netbsd".fmt(f),
             Os::Openbsd => "openbsd".fmt(f),
             Os::NaCl => "nacl".fmt(f),
+            Os::Haiku => "haiku".fmt(f),
             Os::Solaris => "solaris".fmt(f),
         }
     }
index c18b36161dfcf3a190d3c3e4b71324912d5828d8..fcf2d32ded960aab2c61ccf47baf3ce785a8f91d 100644 (file)
@@ -121,6 +121,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 /// A lifetime definition, e.g. `'a: 'b+'c+'d`
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct LifetimeDef {
+    pub attrs: ThinVec<Attribute>,
     pub lifetime: Lifetime,
     pub bounds: Vec<Lifetime>
 }
@@ -370,6 +371,7 @@ pub enum TraitBoundModifier {
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct TyParam {
+    pub attrs: ThinVec<Attribute>,
     pub ident: Ident,
     pub id: NodeId,
     pub bounds: TyParamBounds,
@@ -593,7 +595,7 @@ pub fn walk<F>(&self, it: &mut F) -> bool
             PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
                 s.walk(it)
             }
-            PatKind::Vec(ref before, ref slice, ref after) => {
+            PatKind::Slice(ref before, ref slice, ref after) => {
                 before.iter().all(|p| p.walk(it)) &&
                 slice.iter().all(|p| p.walk(it)) &&
                 after.iter().all(|p| p.walk(it))
@@ -669,8 +671,8 @@ pub enum PatKind {
     /// A range pattern, e.g. `1...2`
     Range(P<Expr>, P<Expr>),
     /// `[a, b, ..i, y, z]` is represented as:
-    ///     `PatKind::Vec(box [a, b], Some(i), box [y, z])`
-    Vec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
+    ///     `PatKind::Slice(box [a, b], Some(i), box [y, z])`
+    Slice(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
     /// A macro pattern; pre-expansion
     Mac(Mac),
 }
@@ -1431,10 +1433,10 @@ pub struct BareFnTy {
 /// The different kinds of types recognized by the compiler
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum TyKind {
-    /// A variable-length array (`[T]`)
-    Vec(P<Ty>),
+    /// A variable-length slice (`[T]`)
+    Slice(P<Ty>),
     /// A fixed length array (`[T; n]`)
-    FixedLengthVec(P<Ty>, P<Expr>),
+    Array(P<Ty>, P<Expr>),
     /// A raw pointer (`*const T` or `*mut T`)
     Ptr(MutTy),
     /// A reference (`&'a T` or `&'a mut T`)
index abbbbe1e3d1cc49df8cedf47c749ce909ddfbab3..94a7f6030b9373d557fec1c6d3ec4c720f1430a9 100644 (file)
@@ -157,7 +157,7 @@ fn visit_stmt_or_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
         // flag the offending attributes
         for attr in attrs.iter() {
             if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
-                emit_feature_err(&self.sess.span_diagnostic,
+                emit_feature_err(&self.sess,
                                  "stmt_expr_attributes",
                                  attr.span,
                                  GateIssue::Language,
@@ -303,6 +303,6 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
     attr.check_name("cfg")
 }
 
-fn is_test_or_bench(attr: &ast::Attribute) -> bool {
+pub fn is_test_or_bench(attr: &ast::Attribute) -> bool {
     attr.check_name("test") || attr.check_name("bench")
 }
index 4e50299e836b3b71ef58be94ef9175bb342dc868..81c8e0bdb8262c082835f9713470b87eebd880e4 100644 (file)
@@ -215,7 +215,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt,
 
     let ty = ecx.ty(
         span,
-        ast::TyKind::FixedLengthVec(
+        ast::TyKind::Array(
             ecx.ty(
                 span,
                 ast::TyKind::Tup(vec![ty_str.clone(), ty_str])
index 3e85565beb6d118e2da672622e67def58b0f15fd..b56018e1e9dcd98b33e30a6c421e47559ef1bdd4 100644 (file)
@@ -18,8 +18,7 @@
 use ext::expand::{self, Invocation, Expansion};
 use ext::hygiene::Mark;
 use fold::{self, Folder};
-use parse;
-use parse::parser::{self, Parser};
+use parse::{self, parser};
 use parse::token;
 use parse::token::{InternedString, str_to_ident};
 use ptr::P;
@@ -188,146 +187,6 @@ fn expand<'cx>(&self,
     }
 }
 
-pub struct TokResult<'a> {
-    pub parser: Parser<'a>,
-    pub span: Span,
-}
-
-impl<'a> TokResult<'a> {
-    // There is quite a lot of overlap here with ParserAnyMacro in ext/tt/macro_rules.rs
-    // We could probably share more code.
-    // FIXME(#36641) Unify TokResult and ParserAnyMacro.
-    fn ensure_complete_parse(&mut self, allow_semi: bool) {
-        let macro_span = &self.span;
-        self.parser.ensure_complete_parse(allow_semi, |parser| {
-            let token_str = parser.this_token_to_string();
-            let msg = format!("macro expansion ignores token `{}` and any following", token_str);
-            let span = parser.span;
-            parser.diagnostic()
-                  .struct_span_err(span, &msg)
-                  .span_note(*macro_span, "caused by the macro expansion here")
-                  .emit();
-        });
-    }
-}
-
-impl<'a> MacResult for TokResult<'a> {
-    fn make_items(mut self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> {
-        if self.parser.sess.span_diagnostic.has_errors() {
-            return Some(SmallVector::zero());
-        }
-
-        let mut items = SmallVector::zero();
-        loop {
-            match self.parser.parse_item() {
-                Ok(Some(item)) => items.push(item),
-                Ok(None) => {
-                    self.ensure_complete_parse(false);
-                    return Some(items);
-                }
-                Err(mut e) => {
-                    e.emit();
-                    return Some(SmallVector::zero());
-                }
-            }
-        }
-    }
-
-    fn make_impl_items(mut self: Box<Self>) -> Option<SmallVector<ast::ImplItem>> {
-        let mut items = SmallVector::zero();
-        loop {
-            if self.parser.token == token::Eof {
-                break;
-            }
-            match self.parser.parse_impl_item() {
-                Ok(item) => items.push(item),
-                Err(mut e) => {
-                    e.emit();
-                    return Some(SmallVector::zero());
-                }
-            }
-        }
-        self.ensure_complete_parse(false);
-        Some(items)
-    }
-
-    fn make_trait_items(mut self: Box<Self>) -> Option<SmallVector<ast::TraitItem>> {
-        let mut items = SmallVector::zero();
-        loop {
-            if self.parser.token == token::Eof {
-                break;
-            }
-            match self.parser.parse_trait_item() {
-                Ok(item) => items.push(item),
-                Err(mut e) => {
-                    e.emit();
-                    return Some(SmallVector::zero());
-                }
-            }
-        }
-        self.ensure_complete_parse(false);
-        Some(items)
-    }
-
-    fn make_expr(mut self: Box<Self>) -> Option<P<ast::Expr>> {
-        match self.parser.parse_expr() {
-            Ok(e) => {
-                self.ensure_complete_parse(true);
-                Some(e)
-            }
-            Err(mut e) => {
-                e.emit();
-                Some(DummyResult::raw_expr(self.span))
-            }
-        }
-    }
-
-    fn make_pat(mut self: Box<Self>) -> Option<P<ast::Pat>> {
-        match self.parser.parse_pat() {
-            Ok(e) => {
-                self.ensure_complete_parse(false);
-                Some(e)
-            }
-            Err(mut e) => {
-                e.emit();
-                Some(P(DummyResult::raw_pat(self.span)))
-            }
-        }
-    }
-
-    fn make_stmts(mut self: Box<Self>) -> Option<SmallVector<ast::Stmt>> {
-        let mut stmts = SmallVector::zero();
-        loop {
-            if self.parser.token == token::Eof {
-                break;
-            }
-            match self.parser.parse_full_stmt(false) {
-                Ok(Some(stmt)) => stmts.push(stmt),
-                Ok(None) => { /* continue */ }
-                Err(mut e) => {
-                    e.emit();
-                    return Some(SmallVector::zero());
-                }
-            }
-        }
-        self.ensure_complete_parse(false);
-        Some(stmts)
-    }
-
-    fn make_ty(mut self: Box<Self>) -> Option<P<ast::Ty>> {
-        match self.parser.parse_ty() {
-            Ok(e) => {
-                self.ensure_complete_parse(false);
-                Some(e)
-            }
-            Err(mut e) => {
-                e.emit();
-                Some(DummyResult::raw_ty(self.span))
-            }
-        }
-    }
-}
-
 /// Represents a thing that maps token trees to Macro Results
 pub trait TTMacroExpander {
     fn expand<'cx>(&self,
@@ -656,10 +515,11 @@ pub enum SyntaxExtension {
 
 pub trait Resolver {
     fn next_node_id(&mut self) -> ast::NodeId;
+    fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
 
     fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
     fn add_macro(&mut self, scope: Mark, def: ast::MacroDef);
-    fn add_ext(&mut self, scope: Mark, ident: ast::Ident, ext: Rc<SyntaxExtension>);
+    fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
     fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
 
     fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
@@ -671,10 +531,11 @@ pub trait Resolver {
 
 impl Resolver for DummyResolver {
     fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID }
+    fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
 
     fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
     fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef) {}
-    fn add_ext(&mut self, _scope: Mark, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
+    fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
     fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
 
     fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
@@ -696,7 +557,9 @@ pub struct ExpansionData {
     pub depth: usize,
     pub backtrace: ExpnId,
     pub module: Rc<ModuleData>,
-    pub in_block: bool,
+
+    // True if non-inline modules without a `#[path]` are forbidden at the root of this expansion.
+    pub no_noninline_mod: bool,
 }
 
 /// One of these is made during expansion and incrementally updated as we go;
@@ -708,6 +571,7 @@ pub struct ExtCtxt<'a> {
     pub ecfg: expand::ExpansionConfig<'a>,
     pub crate_root: Option<&'static str>,
     pub resolver: &'a mut Resolver,
+    pub resolve_err_count: usize,
     pub current_expansion: ExpansionData,
 }
 
@@ -722,12 +586,13 @@ pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
             ecfg: ecfg,
             crate_root: None,
             resolver: resolver,
+            resolve_err_count: 0,
             current_expansion: ExpansionData {
                 mark: Mark::root(),
                 depth: 0,
                 backtrace: NO_EXPANSION,
                 module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
-                in_block: false,
+                no_noninline_mod: false,
             },
         }
     }
@@ -884,7 +749,7 @@ pub fn initialize(&mut self, user_exts: Vec<NamedSyntaxExtension>, krate: &ast::
 
         for (name, extension) in user_exts {
             let ident = ast::Ident::with_empty_ctxt(name);
-            self.resolver.add_ext(Mark::root(), ident, Rc::new(extension));
+            self.resolver.add_ext(ident, Rc::new(extension));
         }
 
         let mut module = ModuleData {
index b81d95a6998c310e01006df4c6733d0f81d28684..bdbc45471bba29c115693a563cb9c29db8da5294 100644 (file)
@@ -73,6 +73,7 @@ fn ty_ptr(&self, span: Span,
     fn typaram(&self,
                span: Span,
                id: ast::Ident,
+               attrs: Vec<ast::Attribute>,
                bounds: ast::TyParamBounds,
                default: Option<P<ast::Ty>>) -> ast::TyParam;
 
@@ -83,6 +84,7 @@ fn typaram(&self,
     fn lifetime_def(&self,
                     span: Span,
                     name: ast::Name,
+                    attrs: Vec<ast::Attribute>,
                     bounds: Vec<ast::Lifetime>)
                     -> ast::LifetimeDef;
 
@@ -96,7 +98,7 @@ fn stmt_let_typed(&self,
                       ident: ast::Ident,
                       typ: P<ast::Ty>,
                       ex: P<ast::Expr>)
-                      -> P<ast::Stmt>;
+                      -> ast::Stmt;
     fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt;
     fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt;
 
@@ -452,11 +454,13 @@ fn ty_infer(&self, span: Span) -> P<ast::Ty> {
     fn typaram(&self,
                span: Span,
                id: ast::Ident,
+               attrs: Vec<ast::Attribute>,
                bounds: ast::TyParamBounds,
                default: Option<P<ast::Ty>>) -> ast::TyParam {
         ast::TyParam {
             ident: id,
             id: ast::DUMMY_NODE_ID,
+            attrs: attrs.into(),
             bounds: bounds,
             default: default,
             span: span
@@ -503,9 +507,11 @@ fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime {
     fn lifetime_def(&self,
                     span: Span,
                     name: ast::Name,
+                    attrs: Vec<ast::Attribute>,
                     bounds: Vec<ast::Lifetime>)
                     -> ast::LifetimeDef {
         ast::LifetimeDef {
+            attrs: attrs.into(),
             lifetime: self.lifetime(span, name),
             bounds: bounds
         }
@@ -556,7 +562,7 @@ fn stmt_let_typed(&self,
                       ident: ast::Ident,
                       typ: P<ast::Ty>,
                       ex: P<ast::Expr>)
-                      -> P<ast::Stmt> {
+                      -> ast::Stmt {
         let pat = if mutbl {
             let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Mutable);
             self.pat_ident_binding_mode(sp, ident, binding_mode)
@@ -571,11 +577,11 @@ fn stmt_let_typed(&self,
             span: sp,
             attrs: ast::ThinVec::new(),
         });
-        P(ast::Stmt {
+        ast::Stmt {
             id: ast::DUMMY_NODE_ID,
             node: ast::StmtKind::Local(local),
             span: sp,
-        })
+        }
     }
 
     // Generate `let _: Type;`, usually used for type assertions.
index 7359c21ecccacc134710c75bca158fd104f5a308..b1d828d0e3e4938446beda36e0fe2daacf0bf331 100644 (file)
@@ -9,21 +9,21 @@
 // except according to those terms.
 
 use ast::{Block, Crate, Ident, Mac_, PatKind};
-use ast::{MacStmtStyle, StmtKind, ItemKind};
+use ast::{Name, MacStmtStyle, StmtKind, ItemKind};
 use ast;
 use ext::hygiene::Mark;
 use ext::placeholders::{placeholder, PlaceholderExpander};
 use attr::{self, HasAttrs};
 use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use syntax_pos::{self, Span, ExpnId};
-use config::StripUnconfigured;
+use config::{is_test_or_bench, StripUnconfigured};
 use ext::base::*;
 use feature_gate::{self, Features};
 use fold;
 use fold::*;
-use parse::{ParseSess, lexer};
+use parse::{ParseSess, PResult, lexer};
 use parse::parser::Parser;
-use parse::token::{intern, keywords};
+use parse::token::{self, intern, keywords};
 use print::pprust;
 use ptr::P;
 use tokenstream::{TokenTree, TokenStream};
@@ -38,12 +38,12 @@ macro_rules! expansions {
     ($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident,
             $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
             $(.$visit:ident)*  $(lift .$visit_elt:ident)*;)*) => {
-        #[derive(Copy, Clone)]
+        #[derive(Copy, Clone, PartialEq, Eq)]
         pub enum ExpansionKind { OptExpr, $( $kind, )*  }
         pub enum Expansion { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* }
 
         impl ExpansionKind {
-            fn name(self) -> &'static str {
+            pub fn name(self) -> &'static str {
                 match self {
                     ExpansionKind::OptExpr => "expression",
                     $( ExpansionKind::$kind => $kind_name, )*
@@ -106,6 +106,12 @@ fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
                 self.expand(Expansion::$kind(SmallVector::one(node))).$make()
             })*)*
         }
+
+        impl<'a> MacResult for ::ext::tt::macro_rules::ParserAnyMacro<'a> {
+            $(fn $make(self: Box<::ext::tt::macro_rules::ParserAnyMacro<'a>>) -> Option<$ty> {
+                Some(self.make(ExpansionKind::$kind).$make())
+            })*
+        }
     }
 }
 
@@ -200,7 +206,7 @@ fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
             _ => unreachable!(),
         };
 
-        if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
+        if self.cx.parse_sess.span_diagnostic.err_count() - self.cx.resolve_err_count > err_count {
             self.cx.parse_sess.span_diagnostic.abort_if_errors();
         }
 
@@ -271,8 +277,10 @@ fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec<Invoc
         self.cx.cfg = crate_config;
 
         if self.monotonic {
+            let err_count = self.cx.parse_sess.span_diagnostic.err_count();
             let mark = self.cx.current_expansion.mark;
             self.cx.resolver.visit_expansion(mark, &result.0);
+            self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count;
         }
 
         result
@@ -293,10 +301,11 @@ fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
         };
 
         attr::mark_used(&attr);
+        let name = intern(&attr.name());
         self.cx.bt_push(ExpnInfo {
             call_site: attr.span,
             callee: NameAndSpan {
-                format: MacroAttribute(intern(&attr.name())),
+                format: MacroAttribute(name),
                 span: Some(attr.span),
                 allow_internal_unstable: false,
             }
@@ -319,14 +328,7 @@ fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
                 let item_toks = TokenStream::from_tts(tts_for_item(&item, &self.cx.parse_sess));
 
                 let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks);
-                let parser = self.cx.new_parser_from_tts(&tok_result.to_tts());
-                let result = Box::new(TokResult { parser: parser, span: attr.span });
-
-                kind.make_from(result).unwrap_or_else(|| {
-                    let msg = format!("macro could not be expanded into {} position", kind.name());
-                    self.cx.span_err(attr.span, &msg);
-                    kind.dummy(attr.span)
-                })
+                self.parse_expansion(tok_result, kind, name, attr.span)
             }
             _ => unreachable!(),
         }
@@ -344,7 +346,7 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
         // Detect use of feature-gated or invalid attributes on macro invoations
         // since they will not be detected after macro expansion.
         for attr in attrs.iter() {
-            feature_gate::check_attribute(&attr, &self.cx.parse_sess.span_diagnostic,
+            feature_gate::check_attribute(&attr, &self.cx.parse_sess,
                                           &self.cx.parse_sess.codemap(),
                                           &self.cx.ecfg.features.unwrap());
         }
@@ -423,14 +425,9 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
                     },
                 });
 
-
-                let tok_result = expandfun.expand(self.cx,
-                                                  span,
-                                                  TokenStream::from_tts(marked_tts));
-                let parser = self.cx.new_parser_from_tts(&tok_result.to_tts());
-                let result = Box::new(TokResult { parser: parser, span: span });
-                // FIXME better span info.
-                kind.make_from(result).map(|i| i.fold_with(&mut ChangeSpan { span: span }))
+                let toks = TokenStream::from_tts(marked_tts);
+                let tok_result = expandfun.expand(self.cx, span, toks);
+                Some(self.parse_expansion(tok_result, kind, extname, span))
             }
         };
 
@@ -448,6 +445,75 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
             expn_id: Some(self.cx.backtrace()),
         })
     }
+
+    fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, name: Name, span: Span)
+                       -> Expansion {
+        let mut parser = self.cx.new_parser_from_tts(&toks.to_tts());
+        let expansion = match parser.parse_expansion(kind, false) {
+            Ok(expansion) => expansion,
+            Err(mut err) => {
+                err.emit();
+                return kind.dummy(span);
+            }
+        };
+        parser.ensure_complete_parse(name, kind.name(), span);
+        // FIXME better span info
+        expansion.fold_with(&mut ChangeSpan { span: span })
+    }
+}
+
+impl<'a> Parser<'a> {
+    pub fn parse_expansion(&mut self, kind: ExpansionKind, macro_legacy_warnings: bool)
+                           -> PResult<'a, Expansion> {
+        Ok(match kind {
+            ExpansionKind::Items => {
+                let mut items = SmallVector::zero();
+                while let Some(item) = self.parse_item()? {
+                    items.push(item);
+                }
+                Expansion::Items(items)
+            }
+            ExpansionKind::TraitItems => {
+                let mut items = SmallVector::zero();
+                while self.token != token::Eof {
+                    items.push(self.parse_trait_item()?);
+                }
+                Expansion::TraitItems(items)
+            }
+            ExpansionKind::ImplItems => {
+                let mut items = SmallVector::zero();
+                while self.token != token::Eof {
+                    items.push(self.parse_impl_item()?);
+                }
+                Expansion::ImplItems(items)
+            }
+            ExpansionKind::Stmts => {
+                let mut stmts = SmallVector::zero();
+                while self.token != token::Eof {
+                    if let Some(stmt) = self.parse_full_stmt(macro_legacy_warnings)? {
+                        stmts.push(stmt);
+                    }
+                }
+                Expansion::Stmts(stmts)
+            }
+            ExpansionKind::Expr => Expansion::Expr(self.parse_expr()?),
+            ExpansionKind::OptExpr => Expansion::OptExpr(Some(self.parse_expr()?)),
+            ExpansionKind::Ty => Expansion::Ty(self.parse_ty()?),
+            ExpansionKind::Pat => Expansion::Pat(self.parse_pat()?),
+        })
+    }
+
+    pub fn ensure_complete_parse(&mut self, macro_name: ast::Name, kind_name: &str, span: Span) {
+        if self.token != token::Eof {
+            let msg = format!("macro expansion ignores token `{}` and any following",
+                              self.this_token_to_string());
+            let mut err = self.diagnostic().struct_span_err(self.span, &msg);
+            let msg = format!("caused by the macro expansion here; the usage \
+                               of `{}!` is likely invalid in {} context",
+                               macro_name, kind_name);
+            err.span_note(span, &msg).emit();
+        }
+    }
 }
 
 struct InvocationCollector<'a, 'b: 'a> {
@@ -601,16 +667,16 @@ fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> {
     }
 
     fn fold_block(&mut self, block: P<Block>) -> P<Block> {
-        let orig_in_block = mem::replace(&mut self.cx.current_expansion.in_block, true);
+        let no_noninline_mod = mem::replace(&mut self.cx.current_expansion.no_noninline_mod, true);
         let result = noop_fold_block(block, self);
-        self.cx.current_expansion.in_block = orig_in_block;
+        self.cx.current_expansion.no_noninline_mod = no_noninline_mod;
         result
     }
 
     fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
         let item = configure!(self, item);
 
-        let (item, attr) = self.classify_item(item);
+        let (mut item, attr) = self.classify_item(item);
         if let Some(attr) = attr {
             let item = Annotatable::Item(fully_configure!(self, item, noop_fold_item));
             return self.collect_attr(attr, item, ExpansionKind::Items).make_items();
@@ -642,6 +708,7 @@ fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
                     return noop_fold_item(item, self);
                 }
 
+                let orig_no_noninline_mod = self.cx.current_expansion.no_noninline_mod;
                 let mut module = (*self.cx.current_expansion.module).clone();
                 module.mod_path.push(item.ident);
 
@@ -651,11 +718,14 @@ fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
                 let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP;
 
                 if inline_module {
-                    module.directory.push(&*{
-                        ::attr::first_attr_value_str_by_name(&item.attrs, "path")
-                            .unwrap_or(item.ident.name.as_str())
-                    });
+                    if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") {
+                        self.cx.current_expansion.no_noninline_mod = false;
+                        module.directory.push(&*path);
+                    } else {
+                        module.directory.push(&*item.ident.name.as_str());
+                    }
                 } else {
+                    self.cx.current_expansion.no_noninline_mod = false;
                     module.directory =
                         PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner));
                     module.directory.pop();
@@ -665,8 +735,16 @@ fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
                     mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
                 let result = noop_fold_item(item, self);
                 self.cx.current_expansion.module = orig_module;
+                self.cx.current_expansion.no_noninline_mod = orig_no_noninline_mod;
                 return result;
             }
+            // Ensure that test functions are accessible from the test harness.
+            ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => {
+                if item.attrs.iter().any(|attr| is_test_or_bench(attr)) {
+                    item = item.map(|mut item| { item.vis = ast::Visibility::Public; item });
+                }
+                noop_fold_item(item, self)
+            }
             _ => noop_fold_item(item, self),
         }
     }
index 34126fac4ac784c888a282a0e947ba8685998400..0fd72277cca9f46015f5df1600e015b26365cede 100644 (file)
@@ -15,6 +15,7 @@
 //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
 //! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093
 
+use ast::NodeId;
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::fmt;
@@ -46,6 +47,10 @@ pub fn root() -> Self {
         Mark(0)
     }
 
+    pub fn from_placeholder_id(id: NodeId) -> Self {
+        Mark(id.as_u32())
+    }
+
     pub fn as_u32(&self) -> u32 {
         self.0
     }
index 0eed3e5898c00d17747b6fe7cddb03389ad6e7dc..2e0c7ddb540f4c50967f87bf810ce367607e529b 100644 (file)
@@ -12,6 +12,7 @@
 use syntax_pos::{Span, DUMMY_SP};
 use ext::base::{DummyResult, ExtCtxt, MacEager, MacResult, SyntaxExtension};
 use ext::base::{IdentMacroExpander, NormalTT, TTMacroExpander};
+use ext::expand::{Expansion, ExpansionKind};
 use ext::placeholders;
 use ext::tt::macro_parser::{Success, Error, Failure};
 use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
 use parse::token::{self, gensym_ident, NtTT, Token};
 use parse::token::Token::*;
 use print;
-use ptr::P;
 use tokenstream::{self, TokenTree};
 
-use util::small_vector::SmallVector;
-
-use std::cell::RefCell;
 use std::collections::{HashMap};
 use std::collections::hash_map::{Entry};
 use std::rc::Rc;
 
-struct ParserAnyMacro<'a> {
-    parser: RefCell<Parser<'a>>,
+pub struct ParserAnyMacro<'a> {
+    parser: Parser<'a>,
 
     /// Span of the expansion site of the macro this parser is for
     site_span: Span,
@@ -42,106 +39,20 @@ struct ParserAnyMacro<'a> {
 }
 
 impl<'a> ParserAnyMacro<'a> {
-    /// Make sure we don't have any tokens left to parse, so we don't
-    /// silently drop anything. `allow_semi` is so that "optional"
-    /// semicolons at the end of normal expressions aren't complained
-    /// about e.g. the semicolon in `macro_rules! kapow { () => {
-    /// panic!(); } }` doesn't get picked up by .parse_expr(), but it's
-    /// allowed to be there.
-    fn ensure_complete_parse(&self, allow_semi: bool, context: &str) {
-        let mut parser = self.parser.borrow_mut();
-        parser.ensure_complete_parse(allow_semi, |parser| {
-            let token_str = parser.this_token_to_string();
-            let msg = format!("macro expansion ignores token `{}` and any \
-                               following",
-                              token_str);
-            let span = parser.span;
-            let mut err = parser.diagnostic().struct_span_err(span, &msg);
-            let msg = format!("caused by the macro expansion here; the usage \
-                               of `{}!` is likely invalid in {} context",
-                               self.macro_ident, context);
-            err.span_note(self.site_span, &msg)
-               .emit();
-        });
-    }
-}
-
-impl<'a> MacResult for ParserAnyMacro<'a> {
-    fn make_expr(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Expr>> {
-        let ret = panictry!(self.parser.borrow_mut().parse_expr());
-        self.ensure_complete_parse(true, "expression");
-        Some(ret)
-    }
-    fn make_pat(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Pat>> {
-        let ret = panictry!(self.parser.borrow_mut().parse_pat());
-        self.ensure_complete_parse(false, "pattern");
-        Some(ret)
-    }
-    fn make_items(self: Box<ParserAnyMacro<'a>>) -> Option<SmallVector<P<ast::Item>>> {
-        let mut ret = SmallVector::zero();
-        while let Some(item) = panictry!(self.parser.borrow_mut().parse_item()) {
-            ret.push(item);
-        }
-        self.ensure_complete_parse(false, "item");
-        Some(ret)
-    }
-
-    fn make_impl_items(self: Box<ParserAnyMacro<'a>>)
-                       -> Option<SmallVector<ast::ImplItem>> {
-        let mut ret = SmallVector::zero();
-        loop {
-            let mut parser = self.parser.borrow_mut();
-            match parser.token {
-                token::Eof => break,
-                _ => ret.push(panictry!(parser.parse_impl_item()))
-            }
-        }
-        self.ensure_complete_parse(false, "item");
-        Some(ret)
-    }
-
-    fn make_trait_items(self: Box<ParserAnyMacro<'a>>)
-                       -> Option<SmallVector<ast::TraitItem>> {
-        let mut ret = SmallVector::zero();
-        loop {
-            let mut parser = self.parser.borrow_mut();
-            match parser.token {
-                token::Eof => break,
-                _ => ret.push(panictry!(parser.parse_trait_item()))
-            }
-        }
-        self.ensure_complete_parse(false, "item");
-        Some(ret)
-    }
-
-
-    fn make_stmts(self: Box<ParserAnyMacro<'a>>)
-                 -> Option<SmallVector<ast::Stmt>> {
-        let mut ret = SmallVector::zero();
-        loop {
-            let mut parser = self.parser.borrow_mut();
-            match parser.token {
-                token::Eof => break,
-                _ => match parser.parse_full_stmt(true) {
-                    Ok(maybe_stmt) => match maybe_stmt {
-                        Some(stmt) => ret.push(stmt),
-                        None => (),
-                    },
-                    Err(mut e) => {
-                        e.emit();
-                        break;
-                    }
-                }
-            }
+    pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: ExpansionKind) -> Expansion {
+        let ParserAnyMacro { site_span, macro_ident, ref mut parser } = *self;
+        let expansion = panictry!(parser.parse_expansion(kind, true));
+
+        // We allow semicolons at the end of expressions -- e.g. the semicolon in
+        // `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`,
+        // but `m!()` is allowed in expression positions (c.f. issue #34706).
+        if kind == ExpansionKind::Expr && parser.token == token::Semi {
+            parser.bump();
         }
-        self.ensure_complete_parse(false, "statement");
-        Some(ret)
-    }
 
-    fn make_ty(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Ty>> {
-        let ret = panictry!(self.parser.borrow_mut().parse_ty());
-        self.ensure_complete_parse(false, "type");
-        Some(ret)
+        // Make sure we don't have any tokens left to parse so we don't silently drop anything.
+        parser.ensure_complete_parse(macro_ident.name, kind.name(), site_span);
+        expansion
     }
 }
 
@@ -211,7 +122,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                                            rhs);
                 let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
                 p.directory = cx.current_expansion.module.directory.clone();
-                p.restrictions = match cx.current_expansion.in_block {
+                p.restrictions = match cx.current_expansion.no_noninline_mod {
                     true => Restrictions::NO_NONINLINE_MOD,
                     false => Restrictions::empty(),
                 };
@@ -219,7 +130,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                 // Let the context choose how to interpret the result.
                 // Weird, but useful for X-macros.
                 return Box::new(ParserAnyMacro {
-                    parser: RefCell::new(p),
+                    parser: p,
 
                     // Pass along the original expansion site and the name of the macro
                     // so we can print a useful error message if the parse of the expanded
@@ -332,7 +243,7 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
                     (**tt).clone()
                 }
                 _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
-            }).collect()
+            }).collect::<Vec<TokenTree>>()
         }
         _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
     };
@@ -351,6 +262,11 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
         valid &= check_rhs(sess, rhs);
     }
 
+    // don't abort iteration early, so that errors for multiple lhses can be reported
+    for lhs in &lhses {
+        valid &= check_lhs_no_empty_seq(sess, &[lhs.clone()])
+    }
+
     let exp: Box<_> = Box::new(MacroRulesMacroExpander {
         name: def.ident,
         imported_from: def.imported_from,
@@ -377,6 +293,38 @@ fn check_lhs_nt_follows(sess: &ParseSess, lhs: &TokenTree) -> bool {
     // after parsing/expansion. we can report every error in every macro this way.
 }
 
+/// Check that the lhs contains no repetition which could match an empty token
+/// tree, because then the matcher would hang indefinitely.
+fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[TokenTree]) -> bool {
+    for tt in tts {
+        match *tt {
+            TokenTree::Token(_, _) => (),
+            TokenTree::Delimited(_, ref del) => if !check_lhs_no_empty_seq(sess, &del.tts) {
+                return false;
+            },
+            TokenTree::Sequence(span, ref seq) => {
+                if seq.separator.is_none() {
+                    if seq.tts.iter().all(|seq_tt| {
+                        match *seq_tt {
+                            TokenTree::Sequence(_, ref sub_seq) =>
+                                sub_seq.op == tokenstream::KleeneOp::ZeroOrMore,
+                            _ => false,
+                        }
+                    }) {
+                        sess.span_diagnostic.span_err(span, "repetition matches empty token tree");
+                        return false;
+                    }
+                }
+                if !check_lhs_no_empty_seq(sess, &seq.tts) {
+                    return false;
+                }
+            }
+        }
+    }
+
+    true
+}
+
 fn check_rhs(sess: &ParseSess, rhs: &TokenTree) -> bool {
     match *rhs {
         TokenTree::Delimited(..) => return true,
index 75cfa587ab1f3f8a3c0972d3e6512fd360e65ff8..079d7175822cc9f7d4afc401d50ac84fc36faba8 100644 (file)
@@ -36,6 +36,7 @@
 use parse::token::InternedString;
 
 use std::ascii::AsciiExt;
+use std::env;
 
 macro_rules! setter {
     ($field: ident) => {{
@@ -302,6 +303,9 @@ pub fn new() -> Features {
     // Used to identify the `compiler_builtins` crate
     // rustc internal
     (active, compiler_builtins, "1.13.0", None),
+
+    // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
+    (active, generic_param_attrs, "1.11.0", Some(34761)),
 );
 
 declare_features! (
@@ -679,16 +683,15 @@ pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
     pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
         let (cfg, feature, has_feature) = GATED_CFGS[self.index];
         if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
-            let diagnostic = &sess.span_diagnostic;
             let explain = format!("`cfg({})` is experimental and subject to change", cfg);
-            emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
+            emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
         }
     }
 }
 
 struct Context<'a> {
     features: &'a Features,
-    span_handler: &'a Handler,
+    parse_sess: &'a ParseSess,
     cm: &'a CodeMap,
     plugin_attributes: &'a [(String, AttributeType)],
 }
@@ -699,7 +702,7 @@ macro_rules! gate_feature_fn {
         let has_feature: bool = has_feature(&$cx.features);
         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
         if !has_feature && !cx.cm.span_allows_unstable(span) {
-            emit_feature_err(cx.span_handler, name, span, GateIssue::Language, explain);
+            emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
         }
     }}
 }
@@ -756,10 +759,10 @@ fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
     }
 }
 
-pub fn check_attribute(attr: &ast::Attribute, handler: &Handler,
+pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess,
                        cm: &CodeMap, features: &Features) {
     let cx = Context {
-        features: features, span_handler: handler,
+        features: features, parse_sess: parse_sess,
         cm: cm, plugin_attributes: &[]
     };
     cx.check_attribute(attr, true);
@@ -788,8 +791,10 @@ pub enum GateIssue {
     Library(Option<u32>)
 }
 
-pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue,
+pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
                         explain: &str) {
+    let diag = &sess.span_diagnostic;
+
     let issue = match issue {
         GateIssue::Language => find_lang_feature_issue(feature),
         GateIssue::Library(lib) => lib,
@@ -802,13 +807,12 @@ pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIs
     };
 
     // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
-    if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() {
-        err.emit();
-        return;
+    if sess.unstable_features.is_nightly_build() {
+        err.help(&format!("add #![feature({})] to the \
+                           crate attributes to enable",
+                          feature));
     }
-    err.help(&format!("add #![feature({})] to the \
-                       crate attributes to enable",
-                      feature));
+
     err.emit();
 }
 
@@ -962,9 +966,10 @@ fn visit_item(&mut self, i: &ast::Item) {
                 if attr::contains_name(&i.attrs[..], "simd") {
                     gate_feature_post!(&self, simd, i.span,
                                        "SIMD types are experimental and possibly buggy");
-                    self.context.span_handler.span_warn(i.span,
-                                                        "the `#[simd]` attribute is deprecated, \
-                                                         use `#[repr(simd)]` instead");
+                    self.context.parse_sess.span_diagnostic.span_warn(i.span,
+                                                                      "the `#[simd]` attribute \
+                                                                       is deprecated, use \
+                                                                       `#[repr(simd)]` instead");
                 }
                 for attr in &i.attrs {
                     if attr.name() == "repr" {
@@ -1080,14 +1085,14 @@ fn visit_expr(&mut self, e: &ast::Expr) {
 
     fn visit_pat(&mut self, pattern: &ast::Pat) {
         match pattern.node {
-            PatKind::Vec(_, Some(_), ref last) if !last.is_empty() => {
+            PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
                 gate_feature_post!(&self, advanced_slice_patterns,
                                   pattern.span,
                                   "multiple-element slice matches anywhere \
                                    but at the end of a slice (e.g. \
                                    `[0, ..xs, 0]`) are experimental")
             }
-            PatKind::Vec(..) => {
+            PatKind::Slice(..) => {
                 gate_feature_post!(&self, slice_patterns,
                                   pattern.span,
                                   "slice pattern syntax is experimental");
@@ -1218,6 +1223,24 @@ fn visit_vis(&mut self, vis: &ast::Visibility) {
 
         visit::walk_vis(self, vis)
     }
+
+    fn visit_generics(&mut self, g: &ast::Generics) {
+        for t in &g.ty_params {
+            if !t.attrs.is_empty() {
+                gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
+                                   "attributes on type parameter bindings are experimental");
+            }
+        }
+        visit::walk_generics(self, g)
+    }
+
+    fn visit_lifetime_def(&mut self, lifetime_def: &ast::LifetimeDef) {
+        if !lifetime_def.attrs.is_empty() {
+            gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
+                               "attributes on lifetime bindings are experimental");
+        }
+        visit::walk_lifetime_def(self, lifetime_def)
+    }
 }
 
 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
@@ -1273,7 +1296,7 @@ pub fn check_crate(krate: &ast::Crate,
     maybe_stage_features(&sess.span_diagnostic, krate, unstable);
     let ctx = Context {
         features: features,
-        span_handler: &sess.span_diagnostic,
+        parse_sess: sess,
         cm: sess.codemap(),
         plugin_attributes: plugin_attributes,
     };
@@ -1294,6 +1317,30 @@ pub enum UnstableFeatures {
     Cheat
 }
 
+impl UnstableFeatures {
+    pub fn from_environment() -> UnstableFeatures {
+        // Whether this is a feature-staged build, i.e. on the beta or stable channel
+        let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
+        // The secret key needed to get through the rustc build itself by
+        // subverting the unstable features lints
+        let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY");
+        // The matching key to the above, only known by the build system
+        let bootstrap_provided_key = env::var("RUSTC_BOOTSTRAP_KEY").ok();
+        match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) {
+            (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat,
+            (true, _, _) => UnstableFeatures::Disallow,
+            (false, _, _) => UnstableFeatures::Allow
+        }
+    }
+
+    pub fn is_nightly_build(&self) -> bool {
+        match *self {
+            UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
+            _ => false,
+        }
+    }
+}
+
 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
                         unstable: UnstableFeatures) {
     let allow_features = match unstable {
index 36f273e1dbc299f3c6c31773578ee050307f6649..08c0637b2d90255f666d7d0293966ff7c6c5e660 100644 (file)
@@ -356,7 +356,7 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
         id: fld.new_id(id),
         node: match node {
             TyKind::Infer | TyKind::ImplicitSelf => node,
-            TyKind::Vec(ty) => TyKind::Vec(fld.fold_ty(ty)),
+            TyKind::Slice(ty) => TyKind::Slice(fld.fold_ty(ty)),
             TyKind::Ptr(mt) => TyKind::Ptr(fld.fold_mt(mt)),
             TyKind::Rptr(region, mt) => {
                 TyKind::Rptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt))
@@ -385,8 +385,8 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
                 TyKind::ObjectSum(fld.fold_ty(ty),
                             fld.fold_bounds(bounds))
             }
-            TyKind::FixedLengthVec(ty, e) => {
-                TyKind::FixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
+            TyKind::Array(ty, e) => {
+                TyKind::Array(fld.fold_ty(ty), fld.fold_expr(e))
             }
             TyKind::Typeof(expr) => {
                 TyKind::Typeof(fld.fold_expr(expr))
@@ -662,8 +662,13 @@ pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T)
 }
 
 pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
-    let TyParam {id, ident, bounds, default, span} = tp;
+    let TyParam {attrs, id, ident, bounds, default, span} = tp;
+    let attrs: Vec<_> = attrs.into();
     TyParam {
+        attrs: attrs.into_iter()
+            .flat_map(|x| fld.fold_attribute(x).into_iter())
+            .collect::<Vec<_>>()
+            .into(),
         id: fld.new_id(id),
         ident: ident,
         bounds: fld.fold_bounds(bounds),
@@ -687,7 +692,12 @@ pub fn noop_fold_lifetime<T: Folder>(l: Lifetime, fld: &mut T) -> Lifetime {
 
 pub fn noop_fold_lifetime_def<T: Folder>(l: LifetimeDef, fld: &mut T)
                                          -> LifetimeDef {
+    let attrs: Vec<_> = l.attrs.into();
     LifetimeDef {
+        attrs: attrs.into_iter()
+            .flat_map(|x| fld.fold_attribute(x).into_iter())
+            .collect::<Vec<_>>()
+            .into(),
         lifetime: fld.fold_lifetime(l.lifetime),
         bounds: fld.fold_lifetimes(l.bounds),
     }
@@ -1092,8 +1102,8 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
             PatKind::Range(e1, e2) => {
                 PatKind::Range(folder.fold_expr(e1), folder.fold_expr(e2))
             },
-            PatKind::Vec(before, slice, after) => {
-                PatKind::Vec(before.move_map(|x| folder.fold_pat(x)),
+            PatKind::Slice(before, slice, after) => {
+                PatKind::Slice(before.move_map(|x| folder.fold_pat(x)),
                        slice.map(|x| folder.fold_pat(x)),
                        after.move_map(|x| folder.fold_pat(x)))
             }
index a40c30b3e3397fe61d6175a21e5ab9f56bd8bbad..a1c273baeea42b67e09e6c8814915a8b56388e37 100644 (file)
@@ -38,14 +38,24 @@ pub struct JsonEmitter {
 }
 
 impl JsonEmitter {
+    pub fn stderr(registry: Option<Registry>,
+                  code_map: Rc<CodeMap>) -> JsonEmitter {
+        JsonEmitter {
+            dst: Box::new(io::stderr()),
+            registry: registry,
+            cm: code_map,
+        }
+    }
+
     pub fn basic() -> JsonEmitter {
         JsonEmitter::stderr(None, Rc::new(CodeMap::new()))
     }
 
-    pub fn stderr(registry: Option<Registry>,
-                  code_map: Rc<CodeMap>) -> JsonEmitter {
+    pub fn new(dst: Box<Write + Send>,
+               registry: Option<Registry>,
+               code_map: Rc<CodeMap>) -> JsonEmitter {
         JsonEmitter {
-            dst: Box::new(io::stderr()),
+            dst: dst,
             registry: registry,
             cm: code_map,
         }
index 5aa0efdec11a2565a75323770dbf1817502a6dd0..1e286c143de9b4b5ad97718343f6f1ea2c9ed053 100644 (file)
@@ -14,6 +14,7 @@
 use codemap::CodeMap;
 use syntax_pos::{self, Span, FileMap};
 use errors::{Handler, ColorConfig, DiagnosticBuilder};
+use feature_gate::UnstableFeatures;
 use parse::parser::Parser;
 use parse::token::InternedString;
 use ptr::P;
@@ -42,6 +43,7 @@
 /// Info about a parsing session.
 pub struct ParseSess {
     pub span_diagnostic: Handler, // better be the same as the one in the reader!
+    pub unstable_features: UnstableFeatures,
     /// Used to determine and report recursive mod inclusions
     included_mod_stack: RefCell<Vec<PathBuf>>,
     code_map: Rc<CodeMap>,
@@ -60,6 +62,7 @@ pub fn new() -> ParseSess {
     pub fn with_span_handler(handler: Handler, code_map: Rc<CodeMap>) -> ParseSess {
         ParseSess {
             span_diagnostic: handler,
+            unstable_features: UnstableFeatures::from_environment(),
             included_mod_stack: RefCell::new(vec![]),
             code_map: code_map
         }
index 23085fadc5e6068c3c32bb217fd05a655a08da32..9b6002b2469f2991411f4457295bf10aa79c70cc 100644 (file)
@@ -542,11 +542,6 @@ pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
         }
     }
 
-    fn parse_ident_into_path(&mut self) -> PResult<'a, ast::Path> {
-        let ident = self.parse_ident()?;
-        Ok(ast::Path::from_ident(self.last_span, ident))
-    }
-
     /// Check if the next token is `tok`, and return `true` if so.
     ///
     /// This method will automatically add `tok` to `expected_tokens` if `tok` is not
@@ -1184,7 +1179,7 @@ pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> {
         let lo = self.span.lo;
 
         let (name, node) = if self.eat_keyword(keywords::Type) {
-            let TyParam {ident, bounds, default, ..} = self.parse_ty_param()?;
+            let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?;
             self.expect(&token::Semi)?;
             (ident, TraitItemKind::Type(bounds, default))
         } else if self.is_const_item() {
@@ -1202,94 +1197,87 @@ pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> {
                 None
             };
             (ident, TraitItemKind::Const(ty, default))
-        } else if !self.token.is_any_keyword()
-            && self.look_ahead(1, |t| *t == token::Not)
-            && (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
-                || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) {
-                // trait item macro.
-                // code copied from parse_macro_use_or_failure... abstraction!
-                let lo = self.span.lo;
-                let pth = self.parse_ident_into_path()?;
-                self.expect(&token::Not)?;
+        } else if self.token.is_path_start() {
+            // trait item macro.
+            // code copied from parse_macro_use_or_failure... abstraction!
+            let lo = self.span.lo;
+            let pth = self.parse_path(PathStyle::Mod)?;
+            self.expect(&token::Not)?;
 
-                // eat a matched-delimiter token tree:
-                let delim = self.expect_open_delim()?;
-                let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
-                                             SeqSep::none(),
-                                             |pp| pp.parse_token_tree())?;
-                let m_ = Mac_ { path: pth, tts: tts };
-                let m: ast::Mac = codemap::Spanned { node: m_,
-                                                     span: mk_sp(lo,
-                                                                 self.last_span.hi) };
-                if delim != token::Brace {
-                    self.expect(&token::Semi)?
-                }
-                (keywords::Invalid.ident(), ast::TraitItemKind::Macro(m))
-            } else {
-                let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
-                    Ok(cua) => cua,
-                    Err(e) => {
-                        loop {
-                            match self.token {
-                                token::Eof => break,
-                                token::CloseDelim(token::Brace) |
-                                token::Semi => {
-                                    self.bump();
-                                    break;
-                                }
-                                token::OpenDelim(token::Brace) => {
-                                    self.parse_token_tree()?;
-                                    break;
-                                }
-                                _ => self.bump()
+            // eat a matched-delimiter token tree:
+            let delim = self.expect_open_delim()?;
+            let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
+                                            SeqSep::none(),
+                                            |pp| pp.parse_token_tree())?;
+            if delim != token::Brace {
+                self.expect(&token::Semi)?
+            }
+
+            let mac = spanned(lo, self.last_span.hi, Mac_ { path: pth, tts: tts });
+            (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac))
+        } else {
+            let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
+                Ok(cua) => cua,
+                Err(e) => {
+                    loop {
+                        match self.token {
+                            token::Eof => break,
+                            token::CloseDelim(token::Brace) |
+                            token::Semi => {
+                                self.bump();
+                                break;
+                            }
+                            token::OpenDelim(token::Brace) => {
+                                self.parse_token_tree()?;
+                                break;
                             }
+                            _ => self.bump(),
                         }
-
-                        return Err(e);
                     }
-                };
 
-                let ident = self.parse_ident()?;
-                let mut generics = self.parse_generics()?;
+                    return Err(e);
+                }
+            };
 
-                let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{
-                    // This is somewhat dubious; We don't want to allow
-                    // argument names to be left off if there is a
-                    // definition...
-                    p.parse_arg_general(false)
-                })?;
+            let ident = self.parse_ident()?;
+            let mut generics = self.parse_generics()?;
 
-                generics.where_clause = self.parse_where_clause()?;
-                let sig = ast::MethodSig {
-                    unsafety: unsafety,
-                    constness: constness,
-                    decl: d,
-                    generics: generics,
-                    abi: abi,
-                };
+            let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{
+                // This is somewhat dubious; We don't want to allow
+                // argument names to be left off if there is a
+                // definition...
+                p.parse_arg_general(false)
+            })?;
 
-                let body = match self.token {
-                    token::Semi => {
-                        self.bump();
-                        debug!("parse_trait_methods(): parsing required method");
-                        None
-                    }
-                    token::OpenDelim(token::Brace) => {
-                        debug!("parse_trait_methods(): parsing provided method");
-                        let (inner_attrs, body) =
-                            self.parse_inner_attrs_and_block()?;
-                        attrs.extend(inner_attrs.iter().cloned());
-                        Some(body)
-                    }
+            generics.where_clause = self.parse_where_clause()?;
+            let sig = ast::MethodSig {
+                unsafety: unsafety,
+                constness: constness,
+                decl: d,
+                generics: generics,
+                abi: abi,
+            };
 
-                    _ => {
-                        let token_str = self.this_token_to_string();
-                        return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`",
-                                                    token_str)[..]))
-                    }
-                };
-                (ident, ast::TraitItemKind::Method(sig, body))
+            let body = match self.token {
+                token::Semi => {
+                    self.bump();
+                    debug!("parse_trait_methods(): parsing required method");
+                    None
+                }
+                token::OpenDelim(token::Brace) => {
+                    debug!("parse_trait_methods(): parsing provided method");
+                    let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
+                    attrs.extend(inner_attrs.iter().cloned());
+                    Some(body)
+                }
+                _ => {
+                    let token_str = self.this_token_to_string();
+                    return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`", token_str)));
+                }
             };
+            (ident, ast::TraitItemKind::Method(sig, body))
+        };
+
         Ok(TraitItem {
             id: ast::DUMMY_NODE_ID,
             ident: name,
@@ -1398,8 +1386,8 @@ pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
             // Parse the `; e` in `[ i32; e ]`
             // where `e` is a const expression
             let t = match self.maybe_parse_fixed_length_of_vec()? {
-                None => TyKind::Vec(t),
-                Some(suffix) => TyKind::FixedLengthVec(t, suffix)
+                None => TyKind::Slice(t),
+                Some(suffix) => TyKind::Array(t, suffix)
             };
             self.expect(&token::CloseDelim(token::Bracket))?;
             t
@@ -1430,9 +1418,8 @@ pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
             TyKind::Path(Some(qself), path)
         } else if self.token.is_path_start() {
             let path = self.parse_path(PathStyle::Type)?;
-            if self.check(&token::Not) {
+            if self.eat(&token::Not) {
                 // MACRO INVOCATION
-                self.bump();
                 let delim = self.expect_open_delim()?;
                 let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
                                                 SeqSep::none(),
@@ -1923,10 +1910,22 @@ pub fn parse_lifetime(&mut self) -> PResult<'a, ast::Lifetime> {
 
     /// Parses `lifetime_defs = [ lifetime_defs { ',' lifetime_defs } ]` where `lifetime_def  =
     /// lifetime [':' lifetimes]`
-    pub fn parse_lifetime_defs(&mut self) -> PResult<'a, Vec<ast::LifetimeDef>> {
-
+    ///
+    /// If `followed_by_ty_params` is None, then we are in a context
+    /// where only lifetime parameters are allowed, and thus we should
+    /// error if we encounter attributes after the bound lifetimes.
+    ///
+    /// If `followed_by_ty_params` is Some(r), then there may be type
+    /// parameter bindings after the lifetimes, so we should pass
+    /// along the parsed attributes to be attached to the first such
+    /// type parmeter.
+    pub fn parse_lifetime_defs(&mut self,
+                               followed_by_ty_params: Option<&mut Vec<ast::Attribute>>)
+                               -> PResult<'a, Vec<ast::LifetimeDef>>
+    {
         let mut res = Vec::new();
         loop {
+            let attrs = self.parse_outer_attributes()?;
             match self.token {
                 token::Lifetime(_) => {
                     let lifetime = self.parse_lifetime()?;
@@ -1936,11 +1935,20 @@ pub fn parse_lifetime_defs(&mut self) -> PResult<'a, Vec<ast::LifetimeDef>> {
                         } else {
                             Vec::new()
                         };
-                    res.push(ast::LifetimeDef { lifetime: lifetime,
+                    res.push(ast::LifetimeDef { attrs: attrs.into(),
+                                                lifetime: lifetime,
                                                 bounds: bounds });
                 }
 
                 _ => {
+                    if let Some(recv) = followed_by_ty_params {
+                        assert!(recv.is_empty());
+                        *recv = attrs;
+                    } else {
+                        let msg = "trailing attribute after lifetime parameters";
+                        return Err(self.fatal(msg));
+                    }
+                    debug!("parse_lifetime_defs ret {:?}", res);
                     return Ok(res);
                 }
             }
@@ -2310,21 +2318,14 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
                     let pth = self.parse_path(PathStyle::Expr)?;
 
                     // `!`, as an operator, is prefix, so we know this isn't that
-                    if self.check(&token::Not) {
+                    if self.eat(&token::Not) {
                         // MACRO INVOCATION expression
-                        self.bump();
-
                         let delim = self.expect_open_delim()?;
-                        let tts = self.parse_seq_to_end(
-                            &token::CloseDelim(delim),
-                            SeqSep::none(),
-                            |p| p.parse_token_tree())?;
+                        let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
+                                                        SeqSep::none(),
+                                                        |p| p.parse_token_tree())?;
                         let hi = self.last_span.hi;
-
-                        return Ok(self.mk_mac_expr(lo,
-                                                   hi,
-                                                   Mac_ { path: pth, tts: tts },
-                                                   attrs));
+                        return Ok(self.mk_mac_expr(lo, hi, Mac_ { path: pth, tts: tts }, attrs));
                     }
                     if self.check(&token::OpenDelim(token::Brace)) {
                         // This is a struct literal, unless we're prohibited
@@ -2333,51 +2334,7 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
                             Restrictions::RESTRICTION_NO_STRUCT_LITERAL
                         );
                         if !prohibited {
-                            // It's a struct literal.
-                            self.bump();
-                            let mut fields = Vec::new();
-                            let mut base = None;
-
-                            attrs.extend(self.parse_inner_attributes()?);
-
-                            while self.token != token::CloseDelim(token::Brace) {
-                                if self.eat(&token::DotDot) {
-                                    match self.parse_expr() {
-                                        Ok(e) => {
-                                            base = Some(e);
-                                        }
-                                        Err(mut e) => {
-                                            e.emit();
-                                            self.recover_stmt();
-                                        }
-                                    }
-                                    break;
-                                }
-
-                                match self.parse_field() {
-                                    Ok(f) => fields.push(f),
-                                    Err(mut e) => {
-                                        e.emit();
-                                        self.recover_stmt();
-                                        break;
-                                    }
-                                }
-
-                                match self.expect_one_of(&[token::Comma],
-                                                         &[token::CloseDelim(token::Brace)]) {
-                                    Ok(()) => {}
-                                    Err(mut e) => {
-                                        e.emit();
-                                        self.recover_stmt();
-                                        break;
-                                    }
-                                }
-                            }
-
-                            hi = self.span.hi;
-                            self.expect(&token::CloseDelim(token::Brace))?;
-                            ex = ExprKind::Struct(pth, fields, base);
-                            return Ok(self.mk_expr(lo, hi, ex, attrs));
+                            return self.parse_struct_expr(lo, pth, attrs);
                         }
                     }
 
@@ -2403,6 +2360,53 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
         return Ok(self.mk_expr(lo, hi, ex, attrs));
     }
 
+    fn parse_struct_expr(&mut self, lo: BytePos, pth: ast::Path, mut attrs: ThinVec<Attribute>)
+                         -> PResult<'a, P<Expr>> {
+        self.bump();
+        let mut fields = Vec::new();
+        let mut base = None;
+
+        attrs.extend(self.parse_inner_attributes()?);
+
+        while self.token != token::CloseDelim(token::Brace) {
+            if self.eat(&token::DotDot) {
+                match self.parse_expr() {
+                    Ok(e) => {
+                        base = Some(e);
+                    }
+                    Err(mut e) => {
+                        e.emit();
+                        self.recover_stmt();
+                    }
+                }
+                break;
+            }
+
+            match self.parse_field() {
+                Ok(f) => fields.push(f),
+                Err(mut e) => {
+                    e.emit();
+                    self.recover_stmt();
+                    break;
+                }
+            }
+
+            match self.expect_one_of(&[token::Comma],
+                                     &[token::CloseDelim(token::Brace)]) {
+                Ok(()) => {}
+                Err(mut e) => {
+                    e.emit();
+                    self.recover_stmt();
+                    break;
+                }
+            }
+        }
+
+        let hi = self.span.hi;
+        self.expect(&token::CloseDelim(token::Brace))?;
+        return Ok(self.mk_expr(lo, hi, ExprKind::Struct(pth, fields, base), attrs));
+    }
+
     fn parse_or_use_outer_attributes(&mut self,
                                      already_parsed_attrs: Option<ThinVec<Attribute>>)
                                      -> PResult<'a, ThinVec<Attribute>> {
@@ -3577,39 +3581,37 @@ pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
         let lo = self.span.lo;
         let pat;
         match self.token {
-          token::Underscore => {
-            // Parse _
-            self.bump();
-            pat = PatKind::Wild;
-          }
-          token::BinOp(token::And) | token::AndAnd => {
-            // Parse &pat / &mut pat
-            self.expect_and()?;
-            let mutbl = self.parse_mutability()?;
-            if let token::Lifetime(ident) = self.token {
-                return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident)));
+            token::Underscore => {
+                // Parse _
+                self.bump();
+                pat = PatKind::Wild;
+            }
+            token::BinOp(token::And) | token::AndAnd => {
+                // Parse &pat / &mut pat
+                self.expect_and()?;
+                let mutbl = self.parse_mutability()?;
+                if let token::Lifetime(ident) = self.token {
+                    return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident)));
+                }
+                let subpat = self.parse_pat()?;
+                pat = PatKind::Ref(subpat, mutbl);
+            }
+            token::OpenDelim(token::Paren) => {
+                // Parse (pat,pat,pat,...) as tuple pattern
+                self.bump();
+                let (fields, ddpos) = self.parse_pat_tuple_elements(true)?;
+                self.expect(&token::CloseDelim(token::Paren))?;
+                pat = PatKind::Tuple(fields, ddpos);
+            }
+            token::OpenDelim(token::Bracket) => {
+                // Parse [pat,pat,...] as slice pattern
+                self.bump();
+                let (before, slice, after) = self.parse_pat_vec_elements()?;
+                self.expect(&token::CloseDelim(token::Bracket))?;
+                pat = PatKind::Slice(before, slice, after);
             }
-
-            let subpat = self.parse_pat()?;
-            pat = PatKind::Ref(subpat, mutbl);
-          }
-          token::OpenDelim(token::Paren) => {
-            // Parse (pat,pat,pat,...) as tuple pattern
-            self.bump();
-            let (fields, ddpos) = self.parse_pat_tuple_elements(true)?;
-            self.expect(&token::CloseDelim(token::Paren))?;
-            pat = PatKind::Tuple(fields, ddpos);
-          }
-          token::OpenDelim(token::Bracket) => {
-            // Parse [pat,pat,...] as slice pattern
-            self.bump();
-            let (before, slice, after) = self.parse_pat_vec_elements()?;
-            self.expect(&token::CloseDelim(token::Bracket))?;
-            pat = PatKind::Vec(before, slice, after);
-          }
-          _ => {
             // At this point, token != _, &, &&, (, [
-            if self.eat_keyword(keywords::Mut) {
+            _ => if self.eat_keyword(keywords::Mut) {
                 // Parse mut ident @ pat
                 pat = self.parse_pat_ident(BindingMode::ByValue(Mutability::Mutable))?;
             } else if self.eat_keyword(keywords::Ref) {
@@ -3620,43 +3622,39 @@ pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
                 // Parse box pat
                 let subpat = self.parse_pat()?;
                 pat = PatKind::Box(subpat);
+            } else if self.token.is_ident() && self.token.is_path_start() &&
+                      self.look_ahead(1, |t| match *t {
+                          token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
+                          token::DotDotDot | token::ModSep | token::Not => false,
+                          _ => true,
+                      }) {
+                // Parse ident @ pat
+                // This can give false positives and parse nullary enums,
+                // they are dealt with later in resolve
+                let binding_mode = BindingMode::ByValue(Mutability::Immutable);
+                pat = self.parse_pat_ident(binding_mode)?;
             } else if self.token.is_path_start() {
                 // Parse pattern starting with a path
-                if self.token.is_ident() && self.look_ahead(1, |t| *t != token::DotDotDot &&
-                        *t != token::OpenDelim(token::Brace) &&
-                        *t != token::OpenDelim(token::Paren) &&
-                        *t != token::ModSep) {
-                    // Plain idents have some extra abilities here compared to general paths
-                    if self.look_ahead(1, |t| *t == token::Not) {
+                let (qself, path) = if self.eat_lt() {
+                    // Parse a qualified path
+                    let (qself, path) = self.parse_qualified_path(PathStyle::Expr)?;
+                    (Some(qself), path)
+                } else {
+                    // Parse an unqualified path
+                    (None, self.parse_path(PathStyle::Expr)?)
+                };
+                match self.token {
+                    token::Not if qself.is_none() => {
                         // Parse macro invocation
-                        let path = self.parse_ident_into_path()?;
                         self.bump();
                         let delim = self.expect_open_delim()?;
-                        let tts = self.parse_seq_to_end(
-                            &token::CloseDelim(delim),
-                            SeqSep::none(), |p| p.parse_token_tree())?;
-                        let mac = Mac_ { path: path, tts: tts };
-                        pat = PatKind::Mac(codemap::Spanned {node: mac,
-                                                               span: mk_sp(lo, self.last_span.hi)});
-                    } else {
-                        // Parse ident @ pat
-                        // This can give false positives and parse nullary enums,
-                        // they are dealt with later in resolve
-                        let binding_mode = BindingMode::ByValue(Mutability::Immutable);
-                        pat = self.parse_pat_ident(binding_mode)?;
+                        let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
+                                                        SeqSep::none(),
+                                                        |p| p.parse_token_tree())?;
+                        let mac = spanned(lo, self.last_span.hi, Mac_ { path: path, tts: tts });
+                        pat = PatKind::Mac(mac);
                     }
-                } else {
-                    let (qself, path) = if self.eat_lt() {
-                        // Parse a qualified path
-                        let (qself, path) =
-                            self.parse_qualified_path(PathStyle::Expr)?;
-                        (Some(qself), path)
-                    } else {
-                        // Parse an unqualified path
-                        (None, self.parse_path(PathStyle::Expr)?)
-                    };
-                    match self.token {
-                      token::DotDotDot => {
+                    token::DotDotDot => {
                         // Parse range
                         let hi = self.last_span.hi;
                         let begin =
@@ -3664,9 +3662,9 @@ pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
                         self.bump();
                         let end = self.parse_pat_range_end()?;
                         pat = PatKind::Range(begin, end);
-                      }
-                      token::OpenDelim(token::Brace) => {
-                         if qself.is_some() {
+                    }
+                    token::OpenDelim(token::Brace) => {
+                        if qself.is_some() {
                             return Err(self.fatal("unexpected `{` after qualified path"));
                         }
                         // Parse struct pattern
@@ -3678,8 +3676,8 @@ pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
                         });
                         self.bump();
                         pat = PatKind::Struct(path, fields, etc);
-                      }
-                      token::OpenDelim(token::Paren) => {
+                    }
+                    token::OpenDelim(token::Paren) => {
                         if qself.is_some() {
                             return Err(self.fatal("unexpected `(` after qualified path"));
                         }
@@ -3688,11 +3686,8 @@ pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
                         let (fields, ddpos) = self.parse_pat_tuple_elements(false)?;
                         self.expect(&token::CloseDelim(token::Paren))?;
                         pat = PatKind::TupleStruct(path, fields, ddpos)
-                      }
-                      _ => {
-                        pat = PatKind::Path(qself, path);
-                      }
                     }
+                    _ => pat = PatKind::Path(qself, path),
                 }
             } else {
                 // Try to parse everything else as literal with optional minus
@@ -3712,7 +3707,6 @@ pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
                     }
                 }
             }
-          }
         }
 
         let hi = self.last_span.hi;
@@ -3894,16 +3888,33 @@ fn parse_stmt_without_recovery(&mut self,
                 node: StmtKind::Local(self.parse_local(attrs.into())?),
                 span: mk_sp(lo, self.last_span.hi),
             }
-        } else if self.token.is_ident()
-            && !self.token.is_any_keyword()
-            && self.look_ahead(1, |t| *t == token::Not) {
-            // it's a macro invocation:
+        } else if self.token.is_path_start() && self.token != token::Lt && {
+            !self.check_keyword(keywords::Union) ||
+            self.look_ahead(1, |t| *t == token::Not || *t == token::ModSep)
+        } {
+            let pth = self.parse_path(PathStyle::Expr)?;
 
-            // Potential trouble: if we allow macros with paths instead of
-            // idents, we'd need to look ahead past the whole path here...
-            let pth = self.parse_ident_into_path()?;
-            self.bump();
+            if !self.eat(&token::Not) {
+                let expr = if self.check(&token::OpenDelim(token::Brace)) {
+                    self.parse_struct_expr(lo, pth, ThinVec::new())?
+                } else {
+                    let hi = self.last_span.hi;
+                    self.mk_expr(lo, hi, ExprKind::Path(None, pth), ThinVec::new())
+                };
+
+                let expr = self.with_res(Restrictions::RESTRICTION_STMT_EXPR, |this| {
+                    let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
+                    this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
+                })?;
+
+                return Ok(Some(Stmt {
+                    id: ast::DUMMY_NODE_ID,
+                    node: StmtKind::Expr(expr),
+                    span: mk_sp(lo, self.last_span.hi),
+                }));
+            }
 
+            // it's a macro invocation
             let id = match self.token {
                 token::OpenDelim(_) => keywords::Invalid.ident(), // no special identifier
                 _ => self.parse_ident()?,
@@ -4238,7 +4249,7 @@ fn parse_ty_param_bounds(&mut self,
     }
 
     /// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?
-    fn parse_ty_param(&mut self) -> PResult<'a, TyParam> {
+    fn parse_ty_param(&mut self, preceding_attrs: Vec<ast::Attribute>) -> PResult<'a, TyParam> {
         let span = self.span;
         let ident = self.parse_ident()?;
 
@@ -4252,6 +4263,7 @@ fn parse_ty_param(&mut self) -> PResult<'a, TyParam> {
         };
 
         Ok(TyParam {
+            attrs: preceding_attrs.into(),
             ident: ident,
             id: ast::DUMMY_NODE_ID,
             bounds: bounds,
@@ -4272,11 +4284,27 @@ pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
         let span_lo = self.span.lo;
 
         if self.eat(&token::Lt) {
-            let lifetime_defs = self.parse_lifetime_defs()?;
+            // Upon encountering attribute in generics list, we do not
+            // know if it is attached to lifetime or to type param.
+            //
+            // Solution: 1. eagerly parse attributes in tandem with
+            // lifetime defs, 2. store last set of parsed (and unused)
+            // attributes in `attrs`, and 3. pass in those attributes
+            // when parsing formal type param after lifetime defs.
+            let mut attrs = vec![];
+            let lifetime_defs = self.parse_lifetime_defs(Some(&mut attrs))?;
             let mut seen_default = false;
+            let mut post_lifetime_attrs = Some(attrs);
             let ty_params = self.parse_seq_to_gt(Some(token::Comma), |p| {
                 p.forbid_lifetime()?;
-                let ty_param = p.parse_ty_param()?;
+                // Move out of `post_lifetime_attrs` if present. O/w
+                // not first type param: parse attributes anew.
+                let attrs = match post_lifetime_attrs.as_mut() {
+                    None => p.parse_outer_attributes()?,
+                    Some(attrs) => mem::replace(attrs, vec![]),
+                };
+                post_lifetime_attrs = None;
+                let ty_param = p.parse_ty_param(attrs)?;
                 if ty_param.default.is_some() {
                     seen_default = true;
                 } else if seen_default {
@@ -4286,6 +4314,12 @@ pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
                 }
                 Ok(ty_param)
             })?;
+            if let Some(attrs) = post_lifetime_attrs {
+                if !attrs.is_empty() {
+                    self.span_err(attrs[0].span,
+                                  "trailing attribute after lifetime parameters");
+                }
+            }
             Ok(ast::Generics {
                 lifetimes: lifetime_defs,
                 ty_params: ty_params,
@@ -4433,7 +4467,7 @@ pub fn parse_where_clause(&mut self) -> PResult<'a, ast::WhereClause> {
                     let bound_lifetimes = if self.eat_keyword(keywords::For) {
                         // Higher ranked constraint.
                         self.expect(&token::Lt)?;
-                        let lifetime_defs = self.parse_lifetime_defs()?;
+                        let lifetime_defs = self.parse_lifetime_defs(None)?;
                         self.expect_gt()?;
                         lifetime_defs
                     } else {
@@ -4857,17 +4891,14 @@ fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) {
     fn parse_impl_method(&mut self, vis: &Visibility)
                          -> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
         // code copied from parse_macro_use_or_failure... abstraction!
-        if !self.token.is_any_keyword()
-            && self.look_ahead(1, |t| *t == token::Not)
-            && (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
-                || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) {
+        if self.token.is_path_start() {
             // method macro.
 
             let last_span = self.last_span;
             self.complain_if_pub_macro(&vis, last_span);
 
             let lo = self.span.lo;
-            let pth = self.parse_ident_into_path()?;
+            let pth = self.parse_path(PathStyle::Mod)?;
             self.expect(&token::Not)?;
 
             // eat a matched-delimiter token tree:
@@ -4875,14 +4906,12 @@ fn parse_impl_method(&mut self, vis: &Visibility)
             let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
                                             SeqSep::none(),
                                             |p| p.parse_token_tree())?;
-            let m_ = Mac_ { path: pth, tts: tts };
-            let m: ast::Mac = codemap::Spanned { node: m_,
-                                                    span: mk_sp(lo,
-                                                                self.last_span.hi) };
             if delim != token::Brace {
                 self.expect(&token::Semi)?
             }
-            Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(m)))
+
+            let mac = spanned(lo, self.last_span.hi, Mac_ { path: pth, tts: tts });
+            Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(mac)))
         } else {
             let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
             let ident = self.parse_ident()?;
@@ -5006,7 +5035,7 @@ fn parse_trait_ref(&mut self) -> PResult<'a, TraitRef> {
     fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<ast::LifetimeDef>> {
         if self.eat_keyword(keywords::For) {
             self.expect(&token::Lt)?;
-            let lifetime_defs = self.parse_lifetime_defs()?;
+            let lifetime_defs = self.parse_lifetime_defs(None)?;
             self.expect_gt()?;
             Ok(lifetime_defs)
         } else {
@@ -5289,23 +5318,27 @@ fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo>
             }
         } else {
             let directory = self.directory.clone();
-            self.push_directory(id, &outer_attrs);
+            let restrictions = self.push_directory(id, &outer_attrs);
             self.expect(&token::OpenDelim(token::Brace))?;
             let mod_inner_lo = self.span.lo;
             let attrs = self.parse_inner_attributes()?;
-            let m = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
+            let m = self.with_res(restrictions, |this| {
+                this.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)
+            })?;
             self.directory = directory;
             Ok((id, ItemKind::Mod(m), Some(attrs)))
         }
     }
 
-    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
-        let default_path = self.id_to_interned_str(id);
-        let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") {
-            Some(d) => d,
-            None => default_path,
-        };
-        self.directory.push(&*file_path)
+    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) -> Restrictions {
+        if let Some(path) = ::attr::first_attr_value_str_by_name(attrs, "path") {
+            self.directory.push(&*path);
+            self.restrictions - Restrictions::NO_NONINLINE_MOD
+        } else {
+            let default_path = self.id_to_interned_str(id);
+            self.directory.push(&*default_path);
+            self.restrictions
+        }
     }
 
     pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option<PathBuf> {
@@ -5979,11 +6012,7 @@ fn parse_macro_use_or_failure(
         lo: BytePos,
         visibility: Visibility
     ) -> PResult<'a, Option<P<Item>>> {
-        if macros_allowed && !self.token.is_any_keyword()
-                && self.look_ahead(1, |t| *t == token::Not)
-                && (self.look_ahead(2, |t| t.is_ident())
-                    || self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
-                    || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) {
+        if macros_allowed && self.token.is_path_start() {
             // MACRO INVOCATION ITEM
 
             let last_span = self.last_span;
@@ -5992,7 +6021,7 @@ fn parse_macro_use_or_failure(
             let mac_lo = self.span.lo;
 
             // item macro.
-            let pth = self.parse_ident_into_path()?;
+            let pth = self.parse_path(PathStyle::Mod)?;
             self.expect(&token::Not)?;
 
             // a 'special' identifier (like what `macro_rules!` uses)
@@ -6008,12 +6037,6 @@ fn parse_macro_use_or_failure(
             let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
                                             SeqSep::none(),
                                             |p| p.parse_token_tree())?;
-            // single-variant-enum... :
-            let m = Mac_ { path: pth, tts: tts };
-            let m: ast::Mac = codemap::Spanned { node: m,
-                                                 span: mk_sp(mac_lo,
-                                                             self.last_span.hi) };
-
             if delim != token::Brace {
                 if !self.eat(&token::Semi) {
                     let last_span = self.last_span;
@@ -6024,14 +6047,9 @@ fn parse_macro_use_or_failure(
                 }
             }
 
-            let item_ = ItemKind::Mac(m);
-            let last_span = self.last_span;
-            let item = self.mk_item(lo,
-                                    last_span.hi,
-                                    id,
-                                    item_,
-                                    visibility,
-                                    attrs);
+            let hi = self.last_span.hi;
+            let mac = spanned(mac_lo, hi, Mac_ { path: pth, tts: tts });
+            let item = self.mk_item(lo, hi, id, ItemKind::Mac(mac), visibility, attrs);
             return Ok(Some(item));
         }
 
@@ -6171,15 +6189,4 @@ pub fn parse_str(&mut self) -> PResult<'a, (InternedString, StrStyle)> {
             _ =>  Err(self.fatal("expected string literal"))
         }
     }
-
-    pub fn ensure_complete_parse<F>(&mut self, allow_semi: bool, on_err: F)
-        where F: FnOnce(&Parser)
-    {
-        if allow_semi && self.token == token::Semi {
-            self.bump();
-        }
-        if self.token != token::Eof {
-            on_err(self);
-        }
-    }
 }
index 8563d27908db61428405892616fa437fc5948e77..3c106970232cdb4dbf39e516d9db32544fbd5dec 100644 (file)
@@ -972,7 +972,7 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> io::Result<()> {
         try!(self.maybe_print_comment(ty.span.lo));
         try!(self.ibox(0));
         match ty.node {
-            ast::TyKind::Vec(ref ty) => {
+            ast::TyKind::Slice(ref ty) => {
                 try!(word(&mut self.s, "["));
                 try!(self.print_type(&ty));
                 try!(word(&mut self.s, "]"));
@@ -1039,7 +1039,7 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> io::Result<()> {
             ast::TyKind::ImplTrait(ref bounds) => {
                 try!(self.print_bounds("impl ", &bounds[..]));
             }
-            ast::TyKind::FixedLengthVec(ref ty, ref v) => {
+            ast::TyKind::Array(ref ty, ref v) => {
                 try!(word(&mut self.s, "["));
                 try!(self.print_type(&ty));
                 try!(word(&mut self.s, "; "));
@@ -2573,7 +2573,7 @@ pub fn print_pat(&mut self, pat: &ast::Pat) -> io::Result<()> {
                 try!(word(&mut self.s, "..."));
                 try!(self.print_expr(&end));
             }
-            PatKind::Vec(ref before, ref slice, ref after) => {
+            PatKind::Slice(ref before, ref slice, ref after) => {
                 try!(word(&mut self.s, "["));
                 try!(self.commasep(Inconsistent,
                                    &before[..],
index 6327e8f71bcd5f211dff79f24754a3974ff1e3cd..8faad77859e18d7cd1d5a4688ae91850b33ef670 100644 (file)
@@ -19,7 +19,7 @@
 use std::slice;
 use std::mem;
 use std::vec;
-use attr;
+use attr::{self, HasAttrs};
 use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos};
 use std::rc::Rc;
 
@@ -119,7 +119,7 @@ fn fold_item(&mut self, i: P<ast::Item>) -> SmallVector<P<ast::Item>> {
         }
         debug!("current path: {}", path_name_i(&self.cx.path));
 
-        let i = if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) {
+        if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) {
             match i.node {
                 ast::ItemKind::Fn(_, ast::Unsafety::Unsafe, _, _, _, _) => {
                     let diag = self.cx.span_diagnostic;
@@ -136,54 +136,37 @@ fn fold_item(&mut self, i: P<ast::Item>) -> SmallVector<P<ast::Item>> {
                     };
                     self.cx.testfns.push(test);
                     self.tests.push(i.ident);
-                    // debug!("have {} test/bench functions",
-                    //        cx.testfns.len());
-
-                    // Make all tests public so we can call them from outside
-                    // the module (note that the tests are re-exported and must
-                    // be made public themselves to avoid privacy errors).
-                    i.map(|mut i| {
-                        i.vis = ast::Visibility::Public;
-                        i
-                    })
                 }
             }
-        } else {
-            i
-        };
+        }
 
+        let mut item = i.unwrap();
         // We don't want to recurse into anything other than mods, since
         // mods or tests inside of functions will break things
-        let res = match i.node {
-            ast::ItemKind::Mod(..) => fold::noop_fold_item(i, self),
-            _ => SmallVector::one(i),
-        };
+        if let ast::ItemKind::Mod(module) = item.node {
+            let tests = mem::replace(&mut self.tests, Vec::new());
+            let tested_submods = mem::replace(&mut self.tested_submods, Vec::new());
+            let mut mod_folded = fold::noop_fold_mod(module, self);
+            let tests = mem::replace(&mut self.tests, tests);
+            let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
+
+            if !tests.is_empty() || !tested_submods.is_empty() {
+                let (it, sym) = mk_reexport_mod(&mut self.cx, item.id, tests, tested_submods);
+                mod_folded.items.push(it);
+
+                if !self.cx.path.is_empty() {
+                    self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
+                } else {
+                    debug!("pushing nothing, sym: {:?}", sym);
+                    self.cx.toplevel_reexport = Some(sym);
+                }
+            }
+            item.node = ast::ItemKind::Mod(mod_folded);
+        }
         if ident.name != keywords::Invalid.name() {
             self.cx.path.pop();
         }
-        res
-    }
-
-    fn fold_mod(&mut self, m: ast::Mod) -> ast::Mod {
-        let tests = mem::replace(&mut self.tests, Vec::new());
-        let tested_submods = mem::replace(&mut self.tested_submods, Vec::new());
-        let mut mod_folded = fold::noop_fold_mod(m, self);
-        let tests = mem::replace(&mut self.tests, tests);
-        let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
-
-        if !tests.is_empty() || !tested_submods.is_empty() {
-            let (it, sym) = mk_reexport_mod(&mut self.cx, tests, tested_submods);
-            mod_folded.items.push(it);
-
-            if !self.cx.path.is_empty() {
-                self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
-            } else {
-                debug!("pushing nothing, sym: {:?}", sym);
-                self.cx.toplevel_reexport = Some(sym);
-            }
-        }
-
-        mod_folded
+        SmallVector::one(P(item))
     }
 
     fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
@@ -239,16 +222,24 @@ fn fold_item(&mut self, i: P<ast::Item>) -> SmallVector<P<ast::Item>> {
     fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
 }
 
-fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
+fn mk_reexport_mod(cx: &mut TestCtxt, parent: ast::NodeId, tests: Vec<ast::Ident>,
                    tested_submods: Vec<(ast::Ident, ast::Ident)>) -> (P<ast::Item>, ast::Ident) {
     let super_ = token::str_to_ident("super");
 
+    // Generate imports with `#[allow(private_in_public)]` to work around issue #36768.
+    let allow_private_in_public = cx.ext_cx.attribute(DUMMY_SP, cx.ext_cx.meta_list(
+        DUMMY_SP,
+        InternedString::new("allow"),
+        vec![cx.ext_cx.meta_list_item_word(DUMMY_SP, InternedString::new("private_in_public"))],
+    ));
     let items = tests.into_iter().map(|r| {
         cx.ext_cx.item_use_simple(DUMMY_SP, ast::Visibility::Public,
                                   cx.ext_cx.path(DUMMY_SP, vec![super_, r]))
+            .map_attrs(|_| vec![allow_private_in_public.clone()])
     }).chain(tested_submods.into_iter().map(|(r, sym)| {
         let path = cx.ext_cx.path(DUMMY_SP, vec![super_, r, sym]);
         cx.ext_cx.item_use_simple_(DUMMY_SP, ast::Visibility::Public, r, path)
+            .map_attrs(|_| vec![allow_private_in_public.clone()])
     })).collect();
 
     let reexport_mod = ast::Mod {
@@ -257,6 +248,8 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
     };
 
     let sym = token::gensym_ident("__test_reexports");
+    let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent };
+    cx.ext_cx.current_expansion.mark = cx.ext_cx.resolver.get_module_scope(parent);
     let it = cx.ext_cx.monotonic_expander().fold_item(P(ast::Item {
         ident: sym.clone(),
         attrs: Vec::new(),
@@ -579,7 +572,7 @@ fn mk_tests(cx: &TestCtxt) -> P<ast::Item> {
     let static_lt = ecx.lifetime(sp, keywords::StaticLifetime.name());
     // &'static [self::test::TestDescAndFn]
     let static_type = ecx.ty_rptr(sp,
-                                  ecx.ty(sp, ast::TyKind::Vec(struct_type)),
+                                  ecx.ty(sp, ast::TyKind::Slice(struct_type)),
                                   Some(static_lt),
                                   ast::Mutability::Immutable);
     // static TESTS: $static_type = &[...];
index 57b06c40878fe9dcea3adc3c7486a9a0f4c6a018..7fb3e5c6bee1d719d5b68267d25aa9f693afbff2 100644 (file)
@@ -201,6 +201,7 @@ pub fn walk_lifetime<V: Visitor>(visitor: &mut V, lifetime: &Lifetime) {
 pub fn walk_lifetime_def<V: Visitor>(visitor: &mut V, lifetime_def: &LifetimeDef) {
     visitor.visit_lifetime(&lifetime_def.lifetime);
     walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
+    walk_list!(visitor, visit_attribute, &*lifetime_def.attrs);
 }
 
 pub fn walk_poly_trait_ref<V>(visitor: &mut V, trait_ref: &PolyTraitRef, _: &TraitBoundModifier)
@@ -313,7 +314,7 @@ pub fn walk_variant<V>(visitor: &mut V, variant: &Variant, generics: &Generics,
 
 pub fn walk_ty<V: Visitor>(visitor: &mut V, typ: &Ty) {
     match typ.node {
-        TyKind::Vec(ref ty) | TyKind::Paren(ref ty) => {
+        TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => {
             visitor.visit_ty(ty)
         }
         TyKind::Ptr(ref mutable_type) => {
@@ -341,7 +342,7 @@ pub fn walk_ty<V: Visitor>(visitor: &mut V, typ: &Ty) {
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_ty_param_bound, bounds);
         }
-        TyKind::FixedLengthVec(ref ty, ref expression) => {
+        TyKind::Array(ref ty, ref expression) => {
             visitor.visit_ty(ty);
             visitor.visit_expr(expression)
         }
@@ -434,7 +435,7 @@ pub fn walk_pat<V: Visitor>(visitor: &mut V, pattern: &Pat) {
             visitor.visit_expr(upper_bound)
         }
         PatKind::Wild => (),
-        PatKind::Vec(ref prepatterns, ref slice_pattern, ref postpatterns) => {
+        PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => {
             walk_list!(visitor, visit_pat, prepatterns);
             walk_list!(visitor, visit_pat, slice_pattern);
             walk_list!(visitor, visit_pat, postpatterns);
@@ -474,6 +475,7 @@ pub fn walk_generics<V: Visitor>(visitor: &mut V, generics: &Generics) {
         visitor.visit_ident(param.span, param.ident);
         walk_list!(visitor, visit_ty_param_bound, &param.bounds);
         walk_list!(visitor, visit_ty, &param.default);
+        walk_list!(visitor, visit_attribute, &*param.attrs);
     }
     walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
     for predicate in &generics.where_clause.predicates {
index 77425b809de1dc9a9db8e402c58021f79b4c61e4..cc4fb604d6ccb76799c0db76a044352b7029807d 100644 (file)
@@ -53,7 +53,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                        tts: &[tokenstream::TokenTree])
                        -> Box<base::MacResult + 'cx> {
     if !cx.ecfg.enable_asm() {
-        feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
+        feature_gate::emit_feature_err(&cx.parse_sess,
                                        "asm",
                                        sp,
                                        feature_gate::GateIssue::Language,
index 15aaf3c78237f2410f3760df07afca52f9e9c396..e56c6e2229a75630657eedd7bcc164635b033541 100644 (file)
@@ -23,7 +23,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt,
                               tts: &[TokenTree])
                               -> Box<base::MacResult + 'cx> {
     if !cx.ecfg.enable_concat_idents() {
-        feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
+        feature_gate::emit_feature_err(&cx.parse_sess,
                                        "concat_idents",
                                        sp,
                                        feature_gate::GateIssue::Language,
index e307925a6ed83907b03de79f5b25d2b13188b4f2..bc47d8f4e613741977ac0dc0a52c3b78acd40aed 100644 (file)
@@ -536,7 +536,7 @@ fn create_derived_impl(&self,
                 bounds.push((*declared_bound).clone());
             }
 
-            cx.typaram(self.span, ty_param.ident, P::from_vec(bounds), None)
+            cx.typaram(self.span, ty_param.ident, vec![], P::from_vec(bounds), None)
         }));
 
         // and similarly for where clauses
index 210878b7c9f0e09d3d62d1052cc967514bcece27..4749d082bc0ec3dcd0723e57a000862ed3e866f7 100644 (file)
@@ -194,6 +194,7 @@ pub fn to_path(&self,
 fn mk_ty_param(cx: &ExtCtxt,
                span: Span,
                name: &str,
+               attrs: &[ast::Attribute],
                bounds: &[Path],
                self_ident: Ident,
                self_generics: &Generics)
@@ -204,7 +205,7 @@ fn mk_ty_param(cx: &ExtCtxt,
             cx.typarambound(path)
         })
         .collect();
-    cx.typaram(span, cx.ident_of(name), bounds, None)
+    cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None)
 }
 
 fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>, span: Span)
@@ -246,7 +247,7 @@ pub fn to_generics(&self,
                 let bounds = bounds.iter()
                     .map(|b| cx.lifetime(span, cx.ident_of(*b).name))
                     .collect();
-                cx.lifetime_def(span, cx.ident_of(*lt).name, bounds)
+                cx.lifetime_def(span, cx.ident_of(*lt).name, vec![], bounds)
             })
             .collect();
         let ty_params = self.bounds
@@ -254,7 +255,7 @@ pub fn to_generics(&self,
             .map(|t| {
                 match *t {
                     (ref name, ref bounds) => {
-                        mk_ty_param(cx, span, *name, bounds, self_ty, self_generics)
+                        mk_ty_param(cx, span, *name, &[], bounds, self_ty, self_generics)
                     }
                 }
             })
index c3c2f7eabb9c797d3a2a812eb3ecbe4e0579b083..111596cfe88e03de33eacdbdce06c36536006d84 100644 (file)
@@ -108,11 +108,109 @@ pub fn expand_derive(cx: &mut ExtCtxt,
         cx.span_err(mitem.span, "unexpected value in `derive`");
     }
 
-    let traits = mitem.meta_item_list().unwrap_or(&[]);
+    let mut traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
     if traits.is_empty() {
         cx.span_warn(mitem.span, "empty trait list in `derive`");
     }
 
+    // First, weed out malformed #[derive]
+    traits.retain(|titem| {
+        if titem.word().is_none() {
+            cx.span_err(titem.span, "malformed `derive` entry");
+            false
+        } else {
+            true
+        }
+    });
+
+    // Next, check for old-style #[derive(Foo)]
+    //
+    // These all get expanded to `#[derive_Foo]` and will get expanded first. If
+    // we actually add any attributes here then we return to get those expanded
+    // and then eventually we'll come back to finish off the other derive modes.
+    let mut new_attributes = Vec::new();
+    traits.retain(|titem| {
+        let tword = titem.word().unwrap();
+        let tname = tword.name();
+
+        let derive_mode = ast::Ident::with_empty_ctxt(intern(&tname));
+        let derive_mode = cx.resolver.resolve_derive_mode(derive_mode);
+        if is_builtin_trait(&tname) || derive_mode.is_some() {
+            return true
+        }
+
+        if !cx.ecfg.enable_custom_derive() {
+            feature_gate::emit_feature_err(&cx.parse_sess,
+                                           "custom_derive",
+                                           titem.span,
+                                           feature_gate::GateIssue::Language,
+                                           feature_gate::EXPLAIN_CUSTOM_DERIVE);
+        } else {
+            let name = intern_and_get_ident(&format!("derive_{}", tname));
+            let mitem = cx.meta_word(titem.span, name);
+            new_attributes.push(cx.attribute(mitem.span, mitem));
+        }
+        false
+    });
+    if new_attributes.len() > 0 {
+        item = item.map(|mut i| {
+            let list = cx.meta_list(mitem.span,
+                                    intern_and_get_ident("derive"),
+                                    traits);
+            i.attrs.extend(new_attributes);
+            i.attrs.push(cx.attribute(mitem.span, list));
+            i
+        });
+        return vec![Annotatable::Item(item)]
+    }
+
+    // Now check for macros-1.1 style custom #[derive].
+    //
+    // Expand each of them in order given, but *before* we expand any built-in
+    // derive modes. The logic here is to:
+    //
+    // 1. Collect the remaining `#[derive]` annotations into a list. If
+    //    there are any left, attach a `#[derive]` attribute to the item
+    //    that we're currently expanding with the remaining derive modes.
+    // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander.
+    // 3. Expand the current item we're expanding, getting back a list of
+    //    items that replace it.
+    // 4. Extend the returned list with the current list of items we've
+    //    collected so far.
+    // 5. Return everything!
+    //
+    // If custom derive extensions end up threading through the `#[derive]`
+    // attribute, we'll get called again later on to continue expanding
+    // those modes.
+    let macros_11_derive = traits.iter()
+                                 .cloned()
+                                 .enumerate()
+                                 .filter(|&(_, ref name)| !is_builtin_trait(&name.name().unwrap()))
+                                 .next();
+    if let Some((i, titem)) = macros_11_derive {
+        let tname = ast::Ident::with_empty_ctxt(intern(&titem.name().unwrap()));
+        let ext = cx.resolver.resolve_derive_mode(tname).unwrap();
+        traits.remove(i);
+        if traits.len() > 0 {
+            item = item.map(|mut i| {
+                let list = cx.meta_list(mitem.span,
+                                        intern_and_get_ident("derive"),
+                                        traits);
+                i.attrs.push(cx.attribute(mitem.span, list));
+                i
+            });
+        }
+        let titem = cx.meta_list_item_word(titem.span, titem.name().unwrap());
+        let mitem = cx.meta_list(titem.span,
+                                 intern_and_get_ident("derive"),
+                                 vec![titem]);
+        let item = Annotatable::Item(item);
+        return ext.expand(cx, mitem.span, &mitem, item)
+    }
+
+    // Ok, at this point we know that there are no old-style `#[derive_Foo]` nor
+    // any macros-1.1 style `#[derive(Foo)]`. Expand all built-in traits here.
+
     // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
     // `#[structural_match]` attribute.
     if traits.iter().filter_map(|t| t.name()).any(|t| t == "PartialEq") &&
@@ -141,103 +239,33 @@ pub fn expand_derive(cx: &mut ExtCtxt,
         });
     }
 
-    let mut other_items = Vec::new();
-
-    let mut iter = traits.iter();
-    while let Some(titem) = iter.next() {
-
-        let tword = match titem.word() {
-            Some(name) => name,
-            None => {
-                cx.span_err(titem.span, "malformed `derive` entry");
-                continue
-            }
+    let mut items = Vec::new();
+    for titem in traits.iter() {
+        let tname = titem.word().unwrap().name();
+        let name = intern_and_get_ident(&format!("derive({})", tname));
+        let mitem = cx.meta_word(titem.span, name);
+
+        let span = Span {
+            expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
+                call_site: titem.span,
+                callee: codemap::NameAndSpan {
+                    format: codemap::MacroAttribute(intern(&format!("derive({})", tname))),
+                    span: Some(titem.span),
+                    allow_internal_unstable: true,
+                },
+            }),
+            ..titem.span
         };
-        let tname = tword.name();
 
-        // If this is a built-in derive mode, then we expand it immediately
-        // here.
-        if is_builtin_trait(&tname) {
-            let name = intern_and_get_ident(&format!("derive({})", tname));
-            let mitem = cx.meta_word(titem.span, name);
-
-            let span = Span {
-                expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
-                    call_site: titem.span,
-                    callee: codemap::NameAndSpan {
-                        format: codemap::MacroAttribute(intern(&format!("derive({})", tname))),
-                        span: Some(titem.span),
-                        allow_internal_unstable: true,
-                    },
-                }),
-                ..titem.span
-            };
-
-            let my_item = Annotatable::Item(item);
-            expand_builtin(&tname, cx, span, &mitem, &my_item, &mut |a| {
-                other_items.push(a);
-            });
-            item = my_item.expect_item();
-
-        // Otherwise if this is a `rustc_macro`-style derive mode, we process it
-        // here. The logic here is to:
-        //
-        // 1. Collect the remaining `#[derive]` annotations into a list. If
-        //    there are any left, attach a `#[derive]` attribute to the item
-        //    that we're currently expanding with the remaining derive modes.
-        // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander.
-        // 3. Expand the current item we're expanding, getting back a list of
-        //    items that replace it.
-        // 4. Extend the returned list with the current list of items we've
-        //    collected so far.
-        // 5. Return everything!
-        //
-        // If custom derive extensions end up threading through the `#[derive]`
-        // attribute, we'll get called again later on to continue expanding
-        // those modes.
-        } else if let Some(ext) =
-                   cx.resolver.resolve_derive_mode(ast::Ident::with_empty_ctxt(intern(&tname))) {
-            let remaining_derives = iter.cloned().collect::<Vec<_>>();
-            if remaining_derives.len() > 0 {
-                let list = cx.meta_list(titem.span,
-                                        intern_and_get_ident("derive"),
-                                        remaining_derives);
-                let attr = cx.attribute(titem.span, list);
-                item = item.map(|mut i| {
-                    i.attrs.push(attr);
-                    i
-                });
-            }
-            let titem = cx.meta_list_item_word(titem.span, tname.clone());
-            let mitem = cx.meta_list(titem.span,
-                                     intern_and_get_ident("derive"),
-                                     vec![titem]);
-            let item = Annotatable::Item(item);
-            let mut items = ext.expand(cx, mitem.span, &mitem, item);
-            items.extend(other_items);
-            return items
-
-        // If we've gotten this far then it means that we're in the territory of
-        // the old custom derive mechanism. If the feature isn't enabled, we
-        // issue an error, otherwise manufacture the `derive_Foo` attribute.
-        } else if !cx.ecfg.enable_custom_derive() {
-            feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
-                                           "custom_derive",
-                                           titem.span,
-                                           feature_gate::GateIssue::Language,
-                                           feature_gate::EXPLAIN_CUSTOM_DERIVE);
-        } else {
-            let name = intern_and_get_ident(&format!("derive_{}", tname));
-            let mitem = cx.meta_word(titem.span, name);
-            item = item.map(|mut i| {
-                i.attrs.push(cx.attribute(mitem.span, mitem));
-                i
-            });
-        }
+        let my_item = Annotatable::Item(item);
+        expand_builtin(&tname, cx, span, &mitem, &my_item, &mut |a| {
+            items.push(a);
+        });
+        item = my_item.expect_item();
     }
 
-    other_items.insert(0, Annotatable::Item(item));
-    return other_items
+    items.insert(0, Annotatable::Item(item));
+    return items
 }
 
 macro_rules! derive_traits {
index 892ebcfa76129ee468188419c22db46ebf7b81ec..de78f859f0f616d7f155df7e5e42a4d6d58c2e74 100644 (file)
@@ -506,7 +506,7 @@ fn static_array(ecx: &mut ExtCtxt,
                     -> P<ast::Expr> {
         let sp = piece_ty.span;
         let ty = ecx.ty_rptr(sp,
-                             ecx.ty(sp, ast::TyKind::Vec(piece_ty)),
+                             ecx.ty(sp, ast::TyKind::Slice(piece_ty)),
                              Some(ecx.lifetime(sp, keywords::StaticLifetime.name())),
                              ast::Mutability::Immutable);
         let slice = ecx.expr_vec_slice(sp, pieces);
index bd9f1cf0d77f1a6e7d7abbff8d91044a2c325497..6e4f3dde4bd24d7153abc4f71ba0277e347d31e5 100644 (file)
 use std::rc::Rc;
 use syntax::ast;
 use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier};
-use syntax::ext::hygiene::Mark;
 use syntax::ext::tt::macro_rules::MacroRulesExpander;
 use syntax::parse::token::intern;
 
 pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) {
     let mut register = |name, ext| {
-        resolver.add_ext(Mark::root(), ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext));
+        resolver.add_ext(ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext));
     };
 
     register("macro_rules", IdentTT(Box::new(MacroRulesExpander), None, false));
index 7242b9865a92c73e4b634e0090689d6feb856cb1..71f1951d5d455c168d7c9d23d784d8ed8a19691b 100644 (file)
@@ -19,7 +19,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt,
                               tts: &[tokenstream::TokenTree])
                               -> Box<base::MacResult + 'cx> {
     if !cx.ecfg.enable_log_syntax() {
-        feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
+        feature_gate::emit_feature_err(&cx.parse_sess,
                                        "log_syntax",
                                        sp,
                                        feature_gate::GateIssue::Language,
index 794169ae3429cd9d19c01928fe413dee00af944b..9578af68100782d0611ba79239c4643908b7eda0 100644 (file)
@@ -20,7 +20,7 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt,
                            tt: &[TokenTree])
                            -> Box<base::MacResult + 'static> {
     if !cx.ecfg.enable_trace_macros() {
-        feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
+        feature_gate::emit_feature_err(&cx.parse_sess,
                                        "trace_macros",
                                        sp,
                                        feature_gate::GateIssue::Language,
index e869c5083373ca4fa577e860cd40c8232d6de176..4b1df7d170dbc273ff4f38b1e72ed1f349321673 100644 (file)
@@ -48,10 +48,12 @@ pub fn get_dbpath_for_term(term: &str) -> Option<PathBuf> {
                 // According to  /etc/terminfo/README, after looking at
                 // ~/.terminfo, ncurses will search /etc/terminfo, then
                 // /lib/terminfo, and eventually /usr/share/terminfo.
+                // On Haiku the database can be found at /boot/system/data/terminfo
                 Err(..) => {
                     dirs_to_search.push(PathBuf::from("/etc/terminfo"));
                     dirs_to_search.push(PathBuf::from("/lib/terminfo"));
                     dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
+                    dirs_to_search.push(PathBuf::from("/boot/system/data/terminfo"));
                 }
             }
         }
index 2b4193306ddf5d08faa91a464431ef37b6887e01..5949afe0ff167c070710d903c126450d693da163 100644 (file)
@@ -303,6 +303,7 @@ pub struct TestOpts {
     pub color: ColorConfig,
     pub quiet: bool,
     pub test_threads: Option<usize>,
+    pub skip: Vec<String>,
 }
 
 impl TestOpts {
@@ -318,6 +319,7 @@ fn new() -> TestOpts {
             color: AutoColor,
             quiet: false,
             test_threads: None,
+            skip: vec![],
         }
     }
 }
@@ -337,6 +339,8 @@ fn optgroups() -> Vec<getopts::OptGroup> {
                                          task, allow printing directly"),
       getopts::optopt("", "test-threads", "Number of threads used for running tests \
                                            in parallel", "n_threads"),
+      getopts::optmulti("", "skip", "Skip tests whose names contain FILTER (this flag can \
+                                     be used multiple times)","FILTER"),
       getopts::optflag("q", "quiet", "Display one character per test instead of one line"),
       getopts::optopt("", "color", "Configure coloring of output:
             auto   = colorize if stdout is a tty and tests are run on serially (default);
@@ -446,6 +450,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
         color: color,
         quiet: quiet,
         test_threads: test_threads,
+        skip: matches.opt_strs("skip"),
     };
 
     Some(Ok(test_opts))
@@ -1080,6 +1085,12 @@ fn num_cpus() -> usize {
         }
         cpus as usize
     }
+
+    #[cfg(target_os = "haiku")]
+    fn num_cpus() -> usize {
+        // FIXME: implement
+        1
+    }
 }
 
 pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
@@ -1095,6 +1106,11 @@ pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescA
         }
     };
 
+    // Skip tests that match any of the skip filters
+    filtered = filtered.into_iter()
+        .filter(|t| !opts.skip.iter().any(|sf| t.desc.name.as_slice().contains(&sf[..])))
+        .collect();
+
     // Maybe pull out the ignored test and unignore them
     filtered = if !opts.run_ignored {
         filtered
@@ -1166,26 +1182,59 @@ fn flush(&mut self) -> io::Result<()> {
             }
         }
 
-        thread::spawn(move || {
-            let data = Arc::new(Mutex::new(Vec::new()));
-            let data2 = data.clone();
-            let cfg = thread::Builder::new().name(match desc.name {
-                DynTestName(ref name) => name.clone(),
-                StaticTestName(name) => name.to_owned(),
+        // If the platform is single-threaded we're just going to run
+        // the test synchronously, regardless of the concurrency
+        // level.
+        let supports_threads = !cfg!(target_os = "emscripten");
+
+        // Buffer for capturing standard I/O
+        let data = Arc::new(Mutex::new(Vec::new()));
+        let data2 = data.clone();
+
+        if supports_threads {
+            thread::spawn(move || {
+                let cfg = thread::Builder::new().name(match desc.name {
+                    DynTestName(ref name) => name.clone(),
+                    StaticTestName(name) => name.to_owned(),
+                });
+
+                let result_guard = cfg.spawn(move || {
+                    if !nocapture {
+                        io::set_print(Some(box Sink(data2.clone())));
+                        io::set_panic(Some(box Sink(data2)));
+                    }
+                    testfn()
+                })
+                    .unwrap();
+                let test_result = calc_result(&desc, result_guard.join());
+                let stdout = data.lock().unwrap().to_vec();
+                monitor_ch.send((desc.clone(), test_result, stdout)).unwrap();
             });
+        } else {
+            let oldio = if !nocapture {
+                Some((
+                    io::set_print(Some(box Sink(data2.clone()))),
+                    io::set_panic(Some(box Sink(data2)))
+                ))
+            } else {
+                None
+            };
+
+            use std::panic::{catch_unwind, AssertUnwindSafe};
+
+            let result = catch_unwind(AssertUnwindSafe(|| {
+                testfn()
+            }));
 
-            let result_guard = cfg.spawn(move || {
-                                      if !nocapture {
-                                          io::set_print(box Sink(data2.clone()));
-                                          io::set_panic(box Sink(data2));
-                                      }
-                                      testfn()
-                                  })
-                                  .unwrap();
-            let test_result = calc_result(&desc, result_guard.join());
+            if let Some((printio, panicio)) = oldio {
+                io::set_print(printio);
+                io::set_panic(panicio);
+            };
+
+            let test_result = calc_result(&desc, result);
             let stdout = data.lock().unwrap().to_vec();
             monitor_ch.send((desc.clone(), test_result, stdout)).unwrap();
-        });
+        }
     }
 
     match testfn {
@@ -1275,7 +1324,7 @@ pub fn fmt_metrics(&self) -> String {
 ///
 /// This function is a no-op, and does not even read from `dummy`.
 #[cfg(not(any(all(target_os = "nacl", target_arch = "le32"),
-              target_arch = "asmjs")))]
+              target_arch = "asmjs", target_arch = "wasm32")))]
 pub fn black_box<T>(dummy: T) -> T {
     // we need to "use" the argument in some way LLVM can't
     // introspect.
@@ -1283,7 +1332,7 @@ pub fn black_box<T>(dummy: T) -> T {
     dummy
 }
 #[cfg(any(all(target_os = "nacl", target_arch = "le32"),
-          target_arch = "asmjs"))]
+          target_arch = "asmjs", target_arch = "wasm32"))]
 #[inline(never)]
 pub fn black_box<T>(dummy: T) -> T {
     dummy
index 3900ba65293c078960c3e2ee5a86ac8a42a95878..c2edf754e49c18ef38c97ac9fbb1d8b25f8658c6 100644 (file)
@@ -65,7 +65,7 @@ pub enum _Unwind_Reason_Code {
 #[cfg(target_arch = "s390x")]
 pub const unwinder_private_data_size: usize = 2;
 
-#[cfg(target_arch = "asmjs")]
+#[cfg(target_os = "emscripten")]
 pub const unwinder_private_data_size: usize = 20;
 
 #[repr(C)]
@@ -241,6 +241,7 @@ pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Rea
 #[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
                target_os = "freebsd",
                target_os = "solaris",
+               target_os = "haiku",
                all(target_os = "linux",
                    target_env = "musl",
                    not(target_arch = "x86"),
index 7801978ec1f3637fcda1b564048ebc732bf586af..3e03f7374169cd41547d75e62ac2ab8a103a913c 160000 (submodule)
--- a/src/llvm
+++ b/src/llvm
@@ -1 +1 @@
-Subproject commit 7801978ec1f3637fcda1b564048ebc732bf586af
+Subproject commit 3e03f7374169cd41547d75e62ac2ab8a103a913c
index 1e873b5345c43d22f09da97e95eb203062b22c51..12cd81ec700444b7b07f8db14bd76e3a0065c96d 100644 (file)
@@ -22,7 +22,7 @@ struct RustArchiveMember {
   Archive::Child child;
 
   RustArchiveMember(): filename(NULL), name(NULL),
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
     child(NULL, NULL, NULL)
 #else
     child(NULL, NULL)
@@ -35,7 +35,7 @@ struct RustArchiveMember {
 struct RustArchiveIterator {
     Archive::child_iterator cur;
     Archive::child_iterator end;
-#if LLVM_VERSION_MINOR >= 9
+#if LLVM_VERSION_GE(3, 9)
     Error err;
 #endif
 };
@@ -81,7 +81,7 @@ LLVMRustOpenArchive(char *path) {
         return nullptr;
     }
 
-#if LLVM_VERSION_MINOR <= 8
+#if LLVM_VERSION_LE(3, 8)
     ErrorOr<std::unique_ptr<Archive>> archive_or =
 #else
     Expected<std::unique_ptr<Archive>> archive_or =
@@ -89,7 +89,7 @@ LLVMRustOpenArchive(char *path) {
         Archive::create(buf_or.get()->getMemBufferRef());
 
     if (!archive_or) {
-#if LLVM_VERSION_MINOR <= 8
+#if LLVM_VERSION_LE(3, 8)
         LLVMRustSetLastError(archive_or.getError().message().c_str());
 #else
         LLVMRustSetLastError(toString(archive_or.takeError()).c_str());
@@ -112,7 +112,7 @@ extern "C" LLVMRustArchiveIteratorRef
 LLVMRustArchiveIteratorNew(LLVMRustArchiveRef ra) {
     Archive *ar = ra->getBinary();
     RustArchiveIterator *rai = new RustArchiveIterator();
-#if LLVM_VERSION_MINOR <= 8
+#if LLVM_VERSION_LE(3, 8)
     rai->cur = ar->child_begin();
 #else
     rai->cur = ar->child_begin(rai->err);
@@ -127,7 +127,7 @@ LLVMRustArchiveIteratorNew(LLVMRustArchiveRef ra) {
 
 extern "C" LLVMRustArchiveChildConstRef
 LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef rai) {
-#if LLVM_VERSION_MINOR >= 9
+#if LLVM_VERSION_GE(3, 9)
     if (rai->err) {
         LLVMRustSetLastError(toString(std::move(rai->err)).c_str());
         return NULL;
@@ -135,7 +135,7 @@ LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef rai) {
 #endif
     if (rai->cur == rai->end)
         return NULL;
-#if LLVM_VERSION_MINOR == 8
+#if LLVM_VERSION_EQ(3, 8)
     const ErrorOr<Archive::Child>* cur = rai->cur.operator->();
     if (!*cur) {
         LLVMRustSetLastError(cur->getError().message().c_str());
@@ -207,7 +207,7 @@ LLVMRustWriteArchive(char *Dst,
                      bool WriteSymbtab,
                      LLVMRustArchiveKind rust_kind) {
 
-#if LLVM_VERSION_MINOR <= 8
+#if LLVM_VERSION_LE(3, 8)
   std::vector<NewArchiveIterator> Members;
 #else
   std::vector<NewArchiveMember> Members;
@@ -218,20 +218,20 @@ LLVMRustWriteArchive(char *Dst,
     auto Member = NewMembers[i];
     assert(Member->name);
     if (Member->filename) {
-#if LLVM_VERSION_MINOR >= 9
+#if LLVM_VERSION_GE(3, 9)
       Expected<NewArchiveMember> MOrErr = NewArchiveMember::getFile(Member->filename, true);
       if (!MOrErr) {
         LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
         return LLVMRustResult::Failure;
       }
       Members.push_back(std::move(*MOrErr));
-#elif LLVM_VERSION_MINOR == 8
+#elif LLVM_VERSION_EQ(3, 8)
       Members.push_back(NewArchiveIterator(Member->filename));
 #else
       Members.push_back(NewArchiveIterator(Member->filename, Member->name));
 #endif
     } else {
-#if LLVM_VERSION_MINOR <= 8
+#if LLVM_VERSION_LE(3, 8)
       Members.push_back(NewArchiveIterator(Member->child, Member->name));
 #else
       Expected<NewArchiveMember> MOrErr = NewArchiveMember::getOldMember(Member->child, true);
@@ -243,7 +243,7 @@ LLVMRustWriteArchive(char *Dst,
 #endif
     }
   }
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
   auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
 #else
   auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true);
index a271987210b673411e77c959379f55d6b49b40a3..60093e9bd37a812afdd97d87ed125658fd0f6a1b 100644 (file)
@@ -46,7 +46,7 @@ LLVMInitializePasses() {
   initializeVectorization(Registry);
   initializeIPO(Registry);
   initializeAnalysis(Registry);
-#if LLVM_VERSION_MINOR == 7
+#if LLVM_VERSION_EQ(3, 7)
   initializeIPA(Registry);
 #endif
   initializeTransformUtils(Registry);
@@ -297,7 +297,7 @@ LLVMRustCreateTargetMachine(const char *triple,
                             bool FunctionSections,
                             bool DataSections) {
 
-#if LLVM_VERSION_MINOR <= 8
+#if LLVM_VERSION_LE(3, 8)
     Reloc::Model RM;
 #else
     Optional<Reloc::Model> RM;
@@ -316,7 +316,7 @@ LLVMRustCreateTargetMachine(const char *triple,
             RM = Reloc::DynamicNoPIC;
             break;
         default:
-#if LLVM_VERSION_MINOR <= 8
+#if LLVM_VERSION_LE(3, 8)
             RM = Reloc::Default;
 #endif
             break;
@@ -337,7 +337,7 @@ LLVMRustCreateTargetMachine(const char *triple,
     }
 
     TargetOptions Options;
-#if LLVM_VERSION_MINOR <= 8
+#if LLVM_VERSION_LE(3, 8)
     Options.PositionIndependentExecutable = PositionIndependentExecutable;
 #endif
 
@@ -539,7 +539,7 @@ extern "C" void
 LLVMRustRunRestrictionPass(LLVMModuleRef M, char **symbols, size_t len) {
     llvm::legacy::PassManager passes;
 
-#if LLVM_VERSION_MINOR <= 8
+#if LLVM_VERSION_LE(3, 8)
     ArrayRef<const char*> ref(symbols, len);
     passes.add(llvm::createInternalizePass(ref));
 #else
@@ -593,7 +593,7 @@ LLVMRustGetModuleDataLayout(LLVMModuleRef M) {
 
 extern "C" void
 LLVMRustSetModulePIELevel(LLVMModuleRef M) {
-#if LLVM_VERSION_MINOR >= 9
+#if LLVM_VERSION_GE(3, 9)
     unwrap(M)->setPIELevel(PIELevel::Level::Large);
 #endif
 }
index 124eb1eba4f7b9f694e40c3d911bcb7a7fd2ad81..672ab117f15f3c801006079ce22db0be62c7a989 100644 (file)
@@ -394,7 +394,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateSubroutineType(
     LLVMRustMetadataRef File,
     LLVMRustMetadataRef ParameterTypes) {
     return wrap(Builder->createSubroutineType(
-#if LLVM_VERSION_MINOR == 7
+#if LLVM_VERSION_EQ(3, 7)
         unwrapDI<DIFile>(File),
 #endif
         DITypeRefArray(unwrap<MDTuple>(ParameterTypes))));
@@ -416,7 +416,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateFunction(
     LLVMValueRef Fn,
     LLVMRustMetadataRef TParam,
     LLVMRustMetadataRef Decl) {
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
     DITemplateParameterArray TParams =
         DITemplateParameterArray(unwrap<MDTuple>(TParam));
     DISubprogram *Sub = Builder->createFunction(
@@ -565,7 +565,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable(
     int64_t* AddrOps,
     unsigned AddrOpsCount,
     unsigned ArgNo) {
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
     if (Tag == 0x100) { // DW_TAG_auto_variable
         return wrap(Builder->createAutoVariable(
             unwrapDI<DIDescriptor>(Scope), Name,
@@ -814,7 +814,7 @@ LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) {
 
     raw_string_ostream Stream(Err);
     DiagnosticPrinterRawOStream DP(Stream);
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
     if (Linker::linkModules(*Dst, std::move(Src.get()))) {
 #else
     if (Linker::LinkModules(Dst, Src->get(), [&](const DiagnosticInfo &DI) { DI.print(DP); })) {
@@ -937,14 +937,14 @@ to_rust(DiagnosticKind kind)
         return LLVMRustDiagnosticKind::OptimizationRemarkMissed;
     case DK_OptimizationRemarkAnalysis:
         return LLVMRustDiagnosticKind::OptimizationRemarkAnalysis;
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
     case DK_OptimizationRemarkAnalysisFPCommute:
         return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisFPCommute;
     case DK_OptimizationRemarkAnalysisAliasing:
         return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisAliasing;
 #endif
     default:
-#if LLVM_VERSION_MINOR >= 9
+#if LLVM_VERSION_GE(3, 9)
         return (kind >= DK_FirstRemark && kind <= DK_LastRemark) ?
             LLVMRustDiagnosticKind::OptimizationRemarkOther :
             LLVMRustDiagnosticKind::Other;
@@ -994,7 +994,7 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
     return LLVMVectorTypeKind;
   case Type::X86_MMXTyID:
     return LLVMX86_MMXTypeKind;
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
   case Type::TokenTyID:
     return LLVMTokenTypeKind;
 #endif
@@ -1043,7 +1043,7 @@ LLVMRustBuildCleanupPad(LLVMBuilderRef Builder,
                         unsigned ArgCnt,
                         LLVMValueRef *LLArgs,
                         const char *Name) {
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
     Value **Args = unwrap(LLArgs);
     if (ParentPad == NULL) {
         Type *Ty = Type::getTokenTy(unwrap(Builder)->getContext());
@@ -1061,7 +1061,7 @@ extern "C" LLVMValueRef
 LLVMRustBuildCleanupRet(LLVMBuilderRef Builder,
                         LLVMValueRef CleanupPad,
                         LLVMBasicBlockRef UnwindBB) {
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
     CleanupPadInst *Inst = cast<CleanupPadInst>(unwrap(CleanupPad));
     return wrap(unwrap(Builder)->CreateCleanupRet(Inst, unwrap(UnwindBB)));
 #else
@@ -1075,7 +1075,7 @@ LLVMRustBuildCatchPad(LLVMBuilderRef Builder,
                       unsigned ArgCnt,
                       LLVMValueRef *LLArgs,
                       const char *Name) {
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
     Value **Args = unwrap(LLArgs);
     return wrap(unwrap(Builder)->CreateCatchPad(unwrap(ParentPad),
                                                 ArrayRef<Value*>(Args, ArgCnt),
@@ -1089,7 +1089,7 @@ extern "C" LLVMValueRef
 LLVMRustBuildCatchRet(LLVMBuilderRef Builder,
                       LLVMValueRef Pad,
                       LLVMBasicBlockRef BB) {
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
     return wrap(unwrap(Builder)->CreateCatchRet(cast<CatchPadInst>(unwrap(Pad)),
                                                 unwrap(BB)));
 #else
@@ -1103,7 +1103,7 @@ LLVMRustBuildCatchSwitch(LLVMBuilderRef Builder,
                          LLVMBasicBlockRef BB,
                          unsigned NumHandlers,
                          const char *Name) {
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
     if (ParentPad == NULL) {
         Type *Ty = Type::getTokenTy(unwrap(Builder)->getContext());
         ParentPad = wrap(Constant::getNullValue(Ty));
@@ -1120,7 +1120,7 @@ LLVMRustBuildCatchSwitch(LLVMBuilderRef Builder,
 extern "C" void
 LLVMRustAddHandler(LLVMValueRef CatchSwitchRef,
                    LLVMBasicBlockRef Handler) {
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
     Value *CatchSwitch = unwrap(CatchSwitchRef);
     cast<CatchSwitchInst>(CatchSwitch)->addHandler(unwrap(Handler));
 #endif
@@ -1129,14 +1129,14 @@ LLVMRustAddHandler(LLVMValueRef CatchSwitchRef,
 extern "C" void
 LLVMRustSetPersonalityFn(LLVMBuilderRef B,
                          LLVMValueRef Personality) {
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
     unwrap(B)->GetInsertBlock()
              ->getParent()
              ->setPersonalityFn(cast<Function>(unwrap(Personality)));
 #endif
 }
 
-#if LLVM_VERSION_MINOR >= 8
+#if LLVM_VERSION_GE(3, 8)
 extern "C" OperandBundleDef*
 LLVMRustBuildOperandBundleDef(const char *Name,
                               LLVMValueRef *Inputs,
index ea8d59290df2e23415bbe18db4b4ac7f04dfb594..979f5f07abea129a351a1e5e27a26547d0e56fe2 100644 (file)
@@ -1,4 +1,4 @@
 # If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
 # The actual contents of this file do not matter, but to trigger a change on the
 # build bots then the contents should be changed so git updates the mtime.
-2016-09-17
+2016-09-25
index 5aae11fb456b6d9ce0abb96efcf587c9fbfec24f..ffe94d1e22f20b117bd607cb3ab129f10ef75100 100644 (file)
 #include "llvm-c/ExecutionEngine.h"
 #include "llvm-c/Object.h"
 
-#if LLVM_VERSION_MINOR >= 7
+#define LLVM_VERSION_GE(major, minor) \
+  (LLVM_VERSION_MAJOR > (major) || LLVM_VERSION_MAJOR == (major) && LLVM_VERSION_MINOR >= (minor))
+
+#define LLVM_VERSION_EQ(major, minor) \
+  (LLVM_VERSION_MAJOR == (major) && LLVM_VERSION_MINOR == (minor))
+
+#define LLVM_VERSION_LE(major, minor) \
+  (LLVM_VERSION_MAJOR < (major) || LLVM_VERSION_MAJOR == (major) && LLVM_VERSION_MINOR <= (minor))
+
+#if LLVM_VERSION_GE(3, 7)
 #include "llvm/IR/LegacyPassManager.h"
 #else
 #include "llvm/PassManager.h"
index f9cf819dc9487649557a1b10888f73e5b6bea165..05189f2011b0ddeb823ca17fe89a0d0d0542c974 100644 (file)
@@ -12,6 +12,6 @@
 # tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was
 # released on `$date`
 
-rustc: beta-2016-08-17
-rustc_key: 195e6261
-cargo: nightly-2016-08-21
+rustc: beta-2016-09-28
+rustc_key: 62b3e239
+cargo: nightly-2016-09-26
index c275eb954b094296d69496812ca8002d94600354..0295311334b6b04c73c6f3344ec678901fe2fb59 100644 (file)
@@ -45,8 +45,8 @@ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
 }
 
 
-//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::eq[0]
-//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::ne[0]
+//~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::eq[0]
+//~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::ne[0]
 #[derive(PartialEq)]
 pub struct Equatable(u32);
 
@@ -54,7 +54,7 @@ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
 impl Add<u32> for Equatable {
     type Output = u32;
 
-    //~ TRANS_ITEM fn overloaded_operators::{{impl}}[3]::add[0]
+    //~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::add[0]
     fn add(self, rhs: u32) -> u32 {
         self.0 + rhs
     }
@@ -63,7 +63,7 @@ fn add(self, rhs: u32) -> u32 {
 impl Deref for Equatable {
     type Target = u32;
 
-    //~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::deref[0]
+    //~ TRANS_ITEM fn overloaded_operators::{{impl}}[3]::deref[0]
     fn deref(&self) -> &Self::Target {
         &self.0
     }
index cf91e7a8bcb660772fd955e6b5cef2a21db8efab..81f6cf309da50f3ee84e58a062dae5b6361d33f5 100644 (file)
@@ -30,11 +30,11 @@ pub fn test() {
 // CHECK: [[S_b:%[0-9]+]] = bitcast %"2.std::option::Option<i32>"** %b to i8*
 // CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_b]])
 
-// CHECK: [[S_tmp2:%[0-9]+]] = bitcast %"2.std::option::Option<i32>"* %tmp2 to i8*
-// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_tmp2]])
+// CHECK: [[S__5:%[0-9]+]] = bitcast %"2.std::option::Option<i32>"* %_5 to i8*
+// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S__5]])
 
-// CHECK: [[E_tmp2:%[0-9]+]] = bitcast %"2.std::option::Option<i32>"* %tmp2 to i8*
-// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_tmp2]])
+// CHECK: [[E__5:%[0-9]+]] = bitcast %"2.std::option::Option<i32>"* %_5 to i8*
+// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E__5]])
 
 // CHECK: [[E_b:%[0-9]+]] = bitcast %"2.std::option::Option<i32>"** %b to i8*
 // CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_b]])
index 01c81a8bbcee4878a80c86008532e2bb63f5253d..6ae5544d68699651fba5ac593a8e28a3e1be426b 100644 (file)
@@ -10,7 +10,6 @@
 
 #![no_std]
 
-extern crate core;
 extern crate rand;
 extern crate serialize as rustc_serialize;
 
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs b/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs
deleted file mode 100644 (file)
index 1300fe6..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.
-
-// aux-build:append-impl.rs
-
-#![feature(rustc_macro)]
-#![allow(warnings)]
-
-#[macro_use]
-extern crate append_impl;
-
-trait Append {
-    fn foo(&self);
-}
-
-#[derive(PartialEq,
-         Append,
-         Eq)]
-struct A {
-//~^ ERROR: the semantics of constant patterns is not yet settled
-    inner: u32,
-}
-
-fn main() {
-    A { inner: 3 }.foo();
-}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs
deleted file mode 100644 (file)
index c3d295e..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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.
-
-// force-host
-// no-prefer-dynamic
-
-#![feature(rustc_macro)]
-#![feature(rustc_macro_lib)]
-#![crate_type = "rustc-macro"]
-
-extern crate rustc_macro;
-
-use rustc_macro::TokenStream;
-
-#[rustc_macro_derive(Append)]
-pub fn derive_a(input: TokenStream) -> TokenStream {
-    let mut input = input.to_string();
-    input.push_str("
-        impl Append for A {
-            fn foo(&self) {}
-        }
-    ");
-    input.parse().unwrap()
-}
index 3f5922cdc02311f9313208e86a73fdc8c7023b81..1d15cef8bc9308d54b0860948e0e88ff6308dc71 100644 (file)
@@ -15,5 +15,8 @@ struct Foo {
 
 fn main() {
     let x = Foo { a:1, b:2 };
-    let Foo { a: x, a: y, b: 0 } = x; //~ ERROR E0025
+    let Foo { a: x, a: y, b: 0 } = x;
+    //~^ ERROR field `a` bound multiple times in the pattern
+    //~| NOTE multiple uses of `a` in pattern
+    //~| NOTE first use of `a`
 }
index d320bcd4d0f5536924c86f666d02a18426e07a77..44f73e10e25d3d93c39c93593cefa774231b3cd9 100644 (file)
@@ -15,6 +15,7 @@ trait SomeTrait {
 fn main() {
     let trait_obj: &SomeTrait = SomeTrait;
     //~^ ERROR E0425
+    //~| NOTE unresolved name
     //~| ERROR E0038
     //~| method `foo` has no receiver
     //~| NOTE the trait `SomeTrait` cannot be made into an object
index 43f46e3578c20fc6867b0821015114b45c0eed9e..9322d21d2a88d325d5913cd989aa93eae3fe4223 100644 (file)
@@ -17,4 +17,5 @@ fn method(&self) {}
 fn main() {
     let x = Test;
     x.method::<i32>(); //~ ERROR E0035
+                       //~| NOTE called with unneeded type parameters
 }
index 35fd6e8942fe7286129df10e40d62be568d46985..ecb6dac66f218f138ec68d2d1029091438669ffe 100644 (file)
@@ -20,4 +20,5 @@ fn main() {
     let x = Test;
     let v = &[0];
     x.method::<i32, i32>(v); //~ ERROR E0036
+                             //~| NOTE Passed 2 type arguments, expected 1
 }
index 2f7dc96361f9c60b1e174222135589ca932c4707..5c53d62709aef2bb6239f266a3e375f1c830aae9 100644 (file)
@@ -9,13 +9,20 @@
 // except according to those terms.
 
 trait Foo {
-    fn foo(&self, x: u8) -> bool;
+    fn foo(&self, x: u8) -> bool; //~ NOTE trait requires 2 parameters
+    fn bar(&self, x: u8, y: u8, z: u8); //~ NOTE trait requires 4 parameters
+    fn less(&self); //~ NOTE trait requires 1 parameter
 }
 
 struct Bar;
 
 impl Foo for Bar {
     fn foo(&self) -> bool { true } //~ ERROR E0050
+                                   //~| NOTE expected 2 parameters, found 1
+    fn bar(&self) { } //~ ERROR E0050
+                      //~| NOTE expected 4 parameters, found 1
+    fn less(&self, x: u8, y: u8, z: u8) { } //~ ERROR E0050
+                                            //~| NOTE expected 1 parameter, found 4
 }
 
 fn main() {
index 17e2b18b3745e55a14a3e2ef99193d4a842503e5..c5a1824514d74ad6b7790d690bc5eb168062c3dc 100644 (file)
@@ -13,7 +13,8 @@ trait Trait {
 }
 
 type Foo = Trait<F=i32>; //~ ERROR E0220
-                         //~^ ERROR E0191
-
+                         //~| NOTE associated type `F` not found
+                         //~| ERROR E0191
+                         //~| NOTE missing associated type `Bar` value
 fn main() {
 }
index c576661828471abf71e304c1cae2e8c69de94260..493a2722617762163b66b032dd0f84779d28c39b 100644 (file)
@@ -12,6 +12,7 @@ mod Foo {
     struct Bar(u32);
 
     pub fn bar() -> Bar { //~ ERROR E0446
+                          //~| NOTE can't leak private type
         Bar(0)
     }
 }
index ac365db33e5cdadc546c7f4e7cbe4b377b75a652..0b3fdb9e6abe69ba77e1109f5b94cdb4e870cd90 100644 (file)
@@ -15,9 +15,13 @@ trait Foo {
 }
 
 pub impl Bar {} //~ ERROR E0449
+                //~| NOTE `pub` not needed here
+                //~| NOTE place qualifiers on individual impl items instead
 
 pub impl Foo for Bar { //~ ERROR E0449
+                       //~| NOTE `pub` not needed here
     pub fn foo() {} //~ ERROR E0449
+                    //~| NOTE `pub` not needed here
 }
 
 fn main() {
index 25f962716413119eed2f6df8851b13a72c2fafb6..2b89873ee45ff9838a8c6e42f8dfcbb8b328c248 100644 (file)
@@ -12,4 +12,5 @@ fn takes_u8(_: u8) {}
 
 fn main() {
     unsafe { takes_u8(::std::mem::transmute(0u16)); } //~ ERROR E0512
+                                                      //~| transmuting between 16 bits and 8 bits
 }
diff --git a/src/test/compile-fail/E0513.rs b/src/test/compile-fail/E0513.rs
new file mode 100644 (file)
index 0000000..726e232
--- /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::mem;
+
+fn main() {
+    unsafe {
+        let size = mem::size_of::<u32>();
+        mem::transmute_copy::<u32, [u8; size]>(&8_8); //~ ERROR E0513
+                                                      //~| NOTE no type for variable
+    }
+}
index db7f304227f01acc9df0d1df50744ac82e3e08c4..4c576de22021ccedf276bec0859bbe85e04f55c1 100644 (file)
@@ -18,6 +18,8 @@
 // system allocator. Do this by linking in jemalloc and making sure that we get
 // an error.
 
+// ignore-emscripten FIXME: What "other allocator" should we use for emcc?
+
 #![feature(alloc_jemalloc)]
 
 extern crate allocator_dylib;
index 46ad226d255645a0df21d8ac19f5179aa6905fe0..02c271ab24da3185a550c14d08775e1aadcba06a 100644 (file)
@@ -16,6 +16,8 @@
 // Ensure that rust dynamic libraries use jemalloc as their allocator, verifying
 // by linking in the system allocator here and ensuring that we get a complaint.
 
+// ignore-emscripten FIXME: What "other allocator" is correct for emscripten?
+
 #![feature(alloc_system)]
 
 extern crate allocator_dylib2;
diff --git a/src/test/compile-fail/attr-on-generic-formals-are-visited.rs b/src/test/compile-fail/attr-on-generic-formals-are-visited.rs
new file mode 100644 (file)
index 0000000..c902cfd
--- /dev/null
@@ -0,0 +1,75 @@
+// 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.
+
+// This test ensures that attributes on formals in generic parameter
+// lists are included when we are checking for unstable attributes.
+//
+// Note that feature(generic_param_attrs) *is* enabled here. We are
+// checking feature-gating of the attributes themselves, not the
+// capability to parse such attributes in that context.
+
+#![feature(generic_param_attrs)]
+#![allow(dead_code)]
+
+struct StLt<#[lt_struct] 'a>(&'a u32);
+//~^ ERROR The attribute `lt_struct` is currently unknown to the compiler
+struct StTy<#[ty_struct] I>(I);
+//~^ ERROR The attribute `ty_struct` is currently unknown to the compiler
+
+enum EnLt<#[lt_enum] 'b> { A(&'b u32), B }
+//~^ ERROR The attribute `lt_enum` is currently unknown to the compiler
+enum EnTy<#[ty_enum] J> { A(J), B }
+//~^ ERROR The attribute `ty_enum` is currently unknown to the compiler
+
+trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
+//~^ ERROR The attribute `lt_trait` is currently unknown to the compiler
+trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); }
+//~^ ERROR The attribute `ty_trait` is currently unknown to the compiler
+
+type TyLt<#[lt_type] 'd> = &'d u32;
+//~^ ERROR The attribute `lt_type` is currently unknown to the compiler
+type TyTy<#[ty_type] L> = (L, );
+//~^ ERROR The attribute `ty_type` is currently unknown to the compiler
+
+impl<#[lt_inherent] 'e> StLt<'e> { }
+//~^ ERROR The attribute `lt_inherent` is currently unknown to the compiler
+impl<#[ty_inherent] M> StTy<M> { }
+//~^ ERROR The attribute `ty_inherent` is currently unknown to the compiler
+
+impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
+    //~^ ERROR The attribute `lt_impl_for` is currently unknown to the compiler
+    fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } }
+}
+impl<#[ty_impl_for] N> TrTy<N> for StTy<N> {
+    //~^ ERROR The attribute `ty_impl_for` is currently unknown to the compiler
+    fn foo(&self, _: N) { }
+}
+
+fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
+//~^ ERROR The attribute `lt_fn` is currently unknown to the compiler
+fn f_ty<#[ty_fn] O>(_: O) { }
+//~^ ERROR The attribute `ty_fn` is currently unknown to the compiler
+
+impl<I> StTy<I> {
+    fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
+    //~^ ERROR The attribute `lt_meth` is currently unknown to the compiler
+    fn m_ty<#[ty_meth] P>(_: P) { }
+    //~^ ERROR The attribute `ty_meth` is currently unknown to the compiler
+}
+
+fn hof_lt<Q>(_: Q)
+    where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
+    //~^ ERROR The attribute `lt_hof` is currently unknown to the compiler
+{
+}
+
+fn main() {
+
+}
diff --git a/src/test/compile-fail/attr-on-generic-formals-wo-feature-gate.rs b/src/test/compile-fail/attr-on-generic-formals-wo-feature-gate.rs
new file mode 100644 (file)
index 0000000..944802f
--- /dev/null
@@ -0,0 +1,76 @@
+// 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.
+
+// This test ensures that attributes on formals in generic parameter
+// lists are rejected if feature(generic_param_attrs) is not enabled.
+//
+// (We are prefixing all tested features with `rustc_`, to ensure that
+// the attributes themselves won't be rejected by the compiler when
+// using `rustc_attrs` feature. There is a separate compile-fail/ test
+// ensuring that the attribute feature-gating works in this context.)
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+struct StLt<#[rustc_lt_struct] 'a>(&'a u32);
+//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+struct StTy<#[rustc_ty_struct] I>(I);
+//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+
+enum EnLt<#[rustc_lt_enum] 'b> { A(&'b u32), B }
+//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+enum EnTy<#[rustc_ty_enum] J> { A(J), B }
+//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+
+trait TrLt<#[rustc_lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
+//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+trait TrTy<#[rustc_ty_trait] K> { fn foo(&self, _: K); }
+//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+
+type TyLt<#[rustc_lt_type] 'd> = &'d u32;
+//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+type TyTy<#[rustc_ty_type] L> = (L, );
+//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+
+impl<#[rustc_lt_inherent] 'e> StLt<'e> { }
+//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+impl<#[rustc_ty_inherent] M> StTy<M> { }
+//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+
+impl<#[rustc_lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
+    //~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+    fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } }
+}
+impl<#[rustc_ty_impl_for] N> TrTy<N> for StTy<N> {
+    //~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+    fn foo(&self, _: N) { }
+}
+
+fn f_lt<#[rustc_lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
+//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+fn f_ty<#[rustc_ty_fn] O>(_: O) { }
+//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+
+impl<I> StTy<I> {
+    fn m_lt<#[rustc_lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
+    //~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+    fn m_ty<#[rustc_ty_meth] P>(_: P) { }
+    //~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
+}
+
+fn hof_lt<Q>(_: Q)
+    where Q: for <#[rustc_lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
+    //~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
+{
+}
+
+fn main() {
+
+}
diff --git a/src/test/compile-fail/attrs-with-no-formal-in-generics-1.rs b/src/test/compile-fail/attrs-with-no-formal-in-generics-1.rs
new file mode 100644 (file)
index 0000000..53e287c
--- /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.
+
+// This test checks variations on `<#[attr] 'a, #[oops]>`, where
+// `#[oops]` is left dangling (that is, it is unattached, with no
+// formal binding following it).
+
+#![feature(generic_param_attrs, rustc_attrs)]
+#![allow(dead_code)]
+
+struct RefIntPair<'a, 'b>(&'a u32, &'b u32);
+
+impl<#[rustc_1] 'a, 'b, #[oops]> RefIntPair<'a, 'b> {
+    //~^ ERROR trailing attribute after lifetime parameters
+}
+
+fn main() {
+
+}
diff --git a/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs b/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs
new file mode 100644 (file)
index 0000000..a38a7bf
--- /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.
+
+// This test checks variations on `<#[attr] 'a, #[oops]>`, where
+// `#[oops]` is left dangling (that is, it is unattached, with no
+// formal binding following it).
+
+#![feature(generic_param_attrs, rustc_attrs)]
+#![allow(dead_code)]
+
+struct RefAny<'a, T>(&'a T);
+
+impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> {
+    //~^ ERROR expected identifier, found `>`
+}
+
+fn main() {
+
+}
diff --git a/src/test/compile-fail/attrs-with-no-formal-in-generics-3.rs b/src/test/compile-fail/attrs-with-no-formal-in-generics-3.rs
new file mode 100644 (file)
index 0000000..e7d5b94
--- /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.
+
+// This test checks variations on `<#[attr] 'a, #[oops]>`, where
+// `#[oops]` is left dangling (that is, it is unattached, with no
+// formal binding following it).
+
+struct RefIntPair<'a, 'b>(&'a u32, &'b u32);
+
+fn hof_lt<Q>(_: Q)
+    where Q: for <#[rustc_1] 'a, 'b, #[oops]> Fn(RefIntPair<'a,'b>) -> &'b u32
+    //~^ ERROR trailing attribute after lifetime parameters
+{
+
+}
+
+fn main() {
+
+}
index c35c9255ed28e8353928d9d1a92e348578166ec3..c18a318347745600c237235760541766f8d37454 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: unresolved name `m1::arguments`. Did you mean `arguments`?
+// error-pattern: unresolved name `m1::arguments`
 
 mod m1 {}
 
index af34887dec954fda455c740c5d55984cad3a586e..e1c1afb0049d74d76286a70842848124448f4ddb 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: unresolved name `m1::arguments`. Did you mean `arguments`?
+// error-pattern: unresolved name `m1::arguments`
 
 mod m1 {
     pub mod arguments {}
index 0ff740212e8fa46cec39e66a28c8b00de66ce70b..213683b5808838f2fdd50d497fa0bbd13fbd4a9d 100644 (file)
@@ -24,7 +24,9 @@ fn f_i8() {
     enum A {
         Ok = i8::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| NOTE overflowed on value after 127i8
+              //~| NOTE explicitly set `OhNo = -128i8` if that is desired outcome
     }
 }
 
@@ -33,7 +35,9 @@ fn f_u8() {
     enum A {
         Ok = u8::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| NOTE overflowed on value after 255u8
+              //~| NOTE explicitly set `OhNo = 0u8` if that is desired outcome
     }
 }
 
@@ -42,7 +46,9 @@ fn f_i16() {
     enum A {
         Ok = i16::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| NOTE overflowed on value after 32767i16
+              //~| NOTE explicitly set `OhNo = -32768i16` if that is desired outcome
     }
 }
 
@@ -51,7 +57,9 @@ fn f_u16() {
     enum A {
         Ok = u16::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| NOTE overflowed on value after 65535u16
+              //~| NOTE explicitly set `OhNo = 0u16` if that is desired outcome
     }
 }
 
@@ -60,7 +68,9 @@ fn f_i32() {
     enum A {
         Ok = i32::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| NOTE overflowed on value after 2147483647i32
+              //~| NOTE explicitly set `OhNo = -2147483648i32` if that is desired outcome
     }
 }
 
@@ -69,7 +79,9 @@ fn f_u32() {
     enum A {
         Ok = u32::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| NOTE overflowed on value after 4294967295u32
+              //~| NOTE explicitly set `OhNo = 0u32` if that is desired outcome
     }
 }
 
@@ -78,7 +90,9 @@ fn f_i64() {
     enum A {
         Ok = i64::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| NOTE overflowed on value after 9223372036854775807i64
+              //~| NOTE explicitly set `OhNo = -9223372036854775808i64` if that is desired outcome
     }
 }
 
@@ -87,7 +101,9 @@ fn f_u64() {
     enum A {
         Ok = u64::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| NOTE overflowed on value after 18446744073709551615u64
+              //~| NOTE explicitly set `OhNo = 0u64` if that is desired outcome
     }
 }
 
index 7316e737b6da8680379b2c617430e54b2703b4ad..a3039b8d9573adafb1093d06efc0fb058e4f308c 100644 (file)
@@ -22,7 +22,9 @@ fn f_i8() {
     enum A {
         Ok = i8::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| NOTE overflowed on value after 127i8
+              //~| NOTE explicitly set `OhNo = -128i8` if that is desired outcome
     }
 
     let x = A::Ok;
@@ -33,7 +35,9 @@ fn f_u8() {
     enum A {
         Ok = u8::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| NOTE overflowed on value after 255u8
+              //~| NOTE explicitly set `OhNo = 0u8` if that is desired outcome
     }
 
     let x = A::Ok;
@@ -44,7 +48,9 @@ fn f_i16() {
     enum A {
         Ok = i16::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| NOTE overflowed on value after 32767i16
+              //~| NOTE explicitly set `OhNo = -32768i16` if that is desired outcome
     }
 
     let x = A::Ok;
@@ -55,7 +61,9 @@ fn f_u16() {
     enum A {
         Ok = u16::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| overflowed on value after 65535u16
+              //~| NOTE explicitly set `OhNo = 0u16` if that is desired outcome
     }
 
     let x = A::Ok;
@@ -66,7 +74,9 @@ fn f_i32() {
     enum A {
         Ok = i32::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| overflowed on value after 2147483647i32
+              //~| NOTE explicitly set `OhNo = -2147483648i32` if that is desired outcome
     }
 
     let x = A::Ok;
@@ -77,7 +87,9 @@ fn f_u32() {
     enum A {
         Ok = u32::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| overflowed on value after 4294967295u32
+              //~| NOTE explicitly set `OhNo = 0u32` if that is desired outcome
     }
 
     let x = A::Ok;
@@ -88,7 +100,9 @@ fn f_i64() {
     enum A {
         Ok = i64::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| overflowed on value after 9223372036854775807i64
+              //~| NOTE explicitly set `OhNo = -9223372036854775808i64` if that is desired outcome
     }
 
     let x = A::Ok;
@@ -99,7 +113,9 @@ fn f_u64() {
     enum A {
         Ok = u64::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed
+        OhNo, //~ ERROR enum discriminant overflowed [E0370]
+              //~| overflowed on value after 18446744073709551615u64
+              //~| NOTE explicitly set `OhNo = 0u64` if that is desired outcome
     }
 
     let x = A::Ok;
index f4b9830d579a4593b73ddd82923290723b45c768..9e042c3a7d50e2313ad3bfd849133a35dfb552d1 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern crate bäz; //~ ERROR non-ascii idents
+extern crate core as bäz; //~ ERROR non-ascii idents
 
 use föö::bar; //~ ERROR non-ascii idents
 
index 5f8ccd0b0634ee22b1c9e313b319a74f2cdedd25..c7bd343bc9a33aef72a3c784702b892bfb98472b 100644 (file)
@@ -27,87 +27,111 @@ fn b(&self) {}
 impl Foo for *const BarTy {
     fn bar(&self) {
         baz();
-        //~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
+        //~^ ERROR: unresolved name `baz`
+        //~| NOTE did you mean to call `self.baz`?
         a;
         //~^ ERROR: unresolved name `a`
+        //~| NOTE unresolved name
     }
 }
 
 impl<'a> Foo for &'a BarTy {
     fn bar(&self) {
         baz();
-        //~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
+        //~^ ERROR: unresolved name `baz`
+        //~| NOTE did you mean to call `self.baz`?
         x;
-        //~^ ERROR: unresolved name `x`. Did you mean `self.x`?
+        //~^ ERROR: unresolved name `x`
+        //~| NOTE did you mean `self.x`?
         y;
-        //~^ ERROR: unresolved name `y`. Did you mean `self.y`?
+        //~^ ERROR: unresolved name `y`
+        //~| NOTE did you mean `self.y`?
         a;
         //~^ ERROR: unresolved name `a`
+        //~| NOTE unresolved name
         bah;
-        //~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
+        //~^ ERROR: unresolved name `bah`
+        //~| NOTE did you mean to call `Foo::bah`?
         b;
         //~^ ERROR: unresolved name `b`
+        //~| NOTE unresolved name
     }
 }
 
 impl<'a> Foo for &'a mut BarTy {
     fn bar(&self) {
         baz();
-        //~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
+        //~^ ERROR: unresolved name `baz`
+        //~| NOTE did you mean to call `self.baz`?
         x;
-        //~^ ERROR: unresolved name `x`. Did you mean `self.x`?
+        //~^ ERROR: unresolved name `x`
+        //~| NOTE did you mean `self.x`?
         y;
-        //~^ ERROR: unresolved name `y`. Did you mean `self.y`?
+        //~^ ERROR: unresolved name `y`
+        //~| NOTE did you mean `self.y`?
         a;
         //~^ ERROR: unresolved name `a`
+        //~| NOTE unresolved name
         bah;
-        //~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
+        //~^ ERROR: unresolved name `bah`
+        //~| NOTE did you mean to call `Foo::bah`?
         b;
         //~^ ERROR: unresolved name `b`
+        //~| NOTE unresolved name
     }
 }
 
 impl Foo for Box<BarTy> {
     fn bar(&self) {
         baz();
-        //~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
+        //~^ ERROR: unresolved name `baz`
+        //~| NOTE did you mean to call `self.baz`?
         bah;
-        //~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
+        //~^ ERROR: unresolved name `bah`
+        //~| NOTE did you mean to call `Foo::bah`?
     }
 }
 
 impl Foo for *const isize {
     fn bar(&self) {
         baz();
-        //~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
+        //~^ ERROR: unresolved name `baz`
+        //~| NOTE did you mean to call `self.baz`?
         bah;
-        //~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
+        //~^ ERROR: unresolved name `bah`
+        //~| NOTE did you mean to call `Foo::bah`?
     }
 }
 
 impl<'a> Foo for &'a isize {
     fn bar(&self) {
         baz();
-        //~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
+        //~^ ERROR: unresolved name `baz`
+        //~| NOTE did you mean to call `self.baz`?
         bah;
-        //~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
+        //~^ ERROR: unresolved name `bah`
+        //~| NOTE did you mean to call `Foo::bah`?
     }
 }
 
 impl<'a> Foo for &'a mut isize {
     fn bar(&self) {
         baz();
-        //~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
+        //~^ ERROR: unresolved name `baz`
+        //~| NOTE did you mean to call `self.baz`?
         bah;
-        //~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
+        //~^ ERROR: unresolved name `bah`
+        //~| NOTE did you mean to call `Foo::bah`?
     }
 }
 
 impl Foo for Box<isize> {
     fn bar(&self) {
         baz();
-        //~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
+        //~^ ERROR: unresolved name `baz`
+        //~| NOTE did you mean to call `self.baz`?
         bah;
-        //~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
+        //~^ ERROR: unresolved name `bah`
+        //~| NOTE did you mean to call `Foo::bah`?
     }
 }
index 5ec82326d6c1a10c4695f78751529afcbb7db8bf..5f816d34c8445fe29541b0c5f5351a296c030810 100644 (file)
@@ -14,19 +14,28 @@ struct Foo {
 
 fn main() {
     let Foo {
-        a: _, //~ NOTE field `a` previously bound here
-        a: _ //~ ERROR field `a` bound multiple times in the pattern
+        a: _, //~ NOTE first use of `a`
+        a: _
+        //~^ ERROR field `a` bound multiple times in the pattern
+        //~| NOTE multiple uses of `a` in pattern
     } = Foo { a: 29 };
 
     let Foo {
-        a, //~ NOTE field `a` previously bound here
-        a: _ //~ ERROR field `a` bound multiple times in the pattern
+        a, //~ NOTE first use of `a`
+        a: _
+        //~^ ERROR field `a` bound multiple times in the pattern
+        //~| NOTE multiple uses of `a` in pattern
     } = Foo { a: 29 };
 
     let Foo {
-        a, //~ NOTE field `a` previously bound here
-        //~^ NOTE field `a` previously bound here
-        a: _, //~ ERROR field `a` bound multiple times in the pattern
-        a: x //~ ERROR field `a` bound multiple times in the pattern
+        a,
+        //~^ NOTE first use of `a`
+        //~| NOTE first use of `a`
+        a: _,
+        //~^ ERROR field `a` bound multiple times in the pattern
+        //~| NOTE multiple uses of `a` in pattern
+        a: x
+        //~^ ERROR field `a` bound multiple times in the pattern
+        //~| NOTE multiple uses of `a` in pattern
     } = Foo { a: 29 };
 }
index 02f128e1f56448bd402edb79d6e4daa16c0bbf3f..457d40e62b0371ebc3ea09ba0d601413d74cf17d 100644 (file)
@@ -8,6 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: expected item, found `parse_error`
+// error-pattern: expected one of `!` or `::`, found `<eof>`
 include!("auxiliary/issue-21146-inc.rs");
 fn main() {}
index da92161967dbdc98921c9684174cbc913b757b45..d7635d7bc9473fc1b482e2d9b2c418cfba30eb73 100644 (file)
@@ -26,6 +26,7 @@ fn bark() {
     // If this provides a suggestion, it's a bug as MaybeDog doesn't impl Groom
     shave();
     //~^ ERROR: unresolved name `shave`
+    //~| NOTE unresolved name
   }
 }
 
@@ -33,11 +34,14 @@ impl Groom for cat {
   fn shave(other: usize) {
     whiskers -= other;
     //~^ ERROR: unresolved name `whiskers`
+    //~| NOTE unresolved name
     //~| HELP this is an associated function
     shave(4);
-    //~^ ERROR: unresolved name `shave`. Did you mean to call `Groom::shave`?
+    //~^ ERROR: unresolved name `shave`
+    //~| NOTE did you mean to call `Groom::shave`?
     purr();
     //~^ ERROR: unresolved name `purr`
+    //~| NOTE unresolved name
   }
 }
 
@@ -47,12 +51,16 @@ fn static_method() {}
     fn purr_louder() {
         static_method();
         //~^ ERROR: unresolved name `static_method`
+        //~| NOTE unresolved name
         purr();
         //~^ ERROR: unresolved name `purr`
+        //~| NOTE unresolved name
         purr();
         //~^ ERROR: unresolved name `purr`
+        //~| NOTE unresolved name
         purr();
         //~^ ERROR: unresolved name `purr`
+        //~| NOTE unresolved name
     }
 }
 
@@ -69,27 +77,33 @@ fn meow() {
   fn purr(&self) {
     grow_older();
     //~^ ERROR: unresolved name `grow_older`
+    //~| NOTE unresolved name
     shave();
     //~^ ERROR: unresolved name `shave`
+    //~| NOTE unresolved name
   }
 
   fn burn_whiskers(&mut self) {
     whiskers = 0;
-    //~^ ERROR: unresolved name `whiskers`. Did you mean `self.whiskers`?
+    //~^ ERROR: unresolved name `whiskers`
+    //~| NOTE did you mean `self.whiskers`?
   }
 
   pub fn grow_older(other:usize) {
     whiskers = 4;
     //~^ ERROR: unresolved name `whiskers`
+    //~| NOTE unresolved name
     //~| HELP this is an associated function
     purr_louder();
     //~^ ERROR: unresolved name `purr_louder`
+    //~| NOTE unresolved name
   }
 }
 
 fn main() {
     self += 1;
     //~^ ERROR: unresolved name `self`
+    //~| NOTE unresolved name
     //~| HELP: module `self`
     // it's a bug if this suggests a missing `self` as we're not in a method
 }
index 491c087c101defeb6d093d8e19f358487a0ea17b..317a47156c1ac072c877554ad136d1b92429c78b 100644 (file)
@@ -17,7 +17,7 @@ macro_rules! bar { () => {x} }
     let _ = bar!();
 }}
 
-macro_rules! bar { // test issue #31856
+macro_rules! m { // test issue #31856
     ($n:ident) => (
         let a = 1;
         let $n = a;
diff --git a/src/test/compile-fail/issue-36881.rs b/src/test/compile-fail/issue-36881.rs
new file mode 100644 (file)
index 0000000..cca20e9
--- /dev/null
@@ -0,0 +1,14 @@
+// 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.
+
+fn main() {
+    extern crate rand;
+    use rand::Rng; //~ ERROR unresolved import
+}
diff --git a/src/test/compile-fail/issue-5067.rs b/src/test/compile-fail/issue-5067.rs
new file mode 100644 (file)
index 0000000..b7b5553
--- /dev/null
@@ -0,0 +1,62 @@
+// 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.
+
+macro_rules! foo {
+    ( $()* ) => {};
+    //~^ ERROR repetition matches empty token tree
+    ( $()+ ) => {};
+    //~^ ERROR repetition matches empty token tree
+
+    ( $(),* ) => {}; // PASS
+    ( $(),+ ) => {}; // PASS
+
+    ( [$()*] ) => {};
+    //~^ ERROR repetition matches empty token tree
+    ( [$()+] ) => {};
+    //~^ ERROR repetition matches empty token tree
+
+    ( [$(),*] ) => {}; // PASS
+    ( [$(),+] ) => {}; // PASS
+
+    ( $($()* $(),* $(a)* $(a),* )* ) => {};
+    //~^ ERROR repetition matches empty token tree
+    ( $($()* $(),* $(a)* $(a),* )+ ) => {};
+    //~^ ERROR repetition matches empty token tree
+
+    ( $(a     $(),* $(a)* $(a),* )* ) => {}; // PASS
+    ( $($(a)+ $(),* $(a)* $(a),* )+ ) => {}; // PASS
+
+    ( $(a $()+)* ) => {};
+    //~^ ERROR repetition matches empty token tree
+    ( $(a $()*)+ ) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+
+// --- Original Issue --- //
+
+macro_rules! make_vec {
+    (a $e1:expr $($(, a $e2:expr)*)*) => ([$e1 $($(, $e2)*)*]);
+    //~^ ERROR repetition matches empty token tree
+}
+
+fn main() {
+    let _ = make_vec!(a 1, a 2, a 3);
+}
+
+
+// --- Minified Issue --- //
+
+macro_rules! m {
+    ( $()* ) => {}
+    //~^ ERROR repetition matches empty token tree
+}
+
+m!();
index 4aa0a3023bb109ed5398458c65e258329a1e6928..80802e19f8401de8c6344d2aee2dde3fc4b9050f 100644 (file)
@@ -14,11 +14,8 @@ macro_rules! m {
                             //~| ERROR macro expansion ignores token `typeof`
                             //~| ERROR macro expansion ignores token `;`
                             //~| ERROR macro expansion ignores token `;`
-                            //~| ERROR macro expansion ignores token `i`
 }
 
-m!();               //~ NOTE the usage of `m!` is likely invalid in item context
-
 fn main() {
     let a: m!();    //~ NOTE the usage of `m!` is likely invalid in type context
     let i = m!();   //~ NOTE the usage of `m!` is likely invalid in expression context
diff --git a/src/test/compile-fail/macro-shadowing.rs b/src/test/compile-fail/macro-shadowing.rs
new file mode 100644 (file)
index 0000000..2246382
--- /dev/null
@@ -0,0 +1,42 @@
+// 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.
+
+// aux-build:two_macros.rs
+
+macro_rules! foo { () => {} }
+macro_rules! macro_one { () => {} }
+
+macro_rules! m1 { () => {
+    macro_rules! foo { () => {} } //~ ERROR `foo` is already in scope
+    //~^ NOTE macro-expanded `macro_rules!`s and `#[macro_use]`s may not shadow existing macros
+
+    #[macro_use] //~ ERROR `macro_one` is already in scope
+    //~^ NOTE macro-expanded `macro_rules!`s and `#[macro_use]`s may not shadow existing macros
+    extern crate two_macros;
+}}
+m1!(); //~ NOTE in this expansion
+       //~| NOTE in this expansion
+       //~| NOTE in this expansion
+       //~| NOTE in this expansion
+
+fn f() { macro_one!(); }
+foo!();
+
+macro_rules! m2 { () => {
+    macro_rules! foo { () => {} }
+    #[macro_use] extern crate two_macros as __;
+
+    fn g() { macro_one!(); }
+    foo!();
+}}
+m2!();
+//^ Since `foo` and `macro_one` are not used outside this expansion, they are not shadowing errors.
+
+fn main() {}
diff --git a/src/test/compile-fail/paths-in-macro-invocations.rs b/src/test/compile-fail/paths-in-macro-invocations.rs
new file mode 100644 (file)
index 0000000..c69b7e5
--- /dev/null
@@ -0,0 +1,38 @@
+// 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.
+
+::foo::bar!(); //~ ERROR expected macro name without module separators
+foo::bar!(); //~ ERROR expected macro name without module separators
+
+trait T {
+    foo::bar!(); //~ ERROR expected macro name without module separators
+    ::foo::bar!(); //~ ERROR expected macro name without module separators
+}
+
+struct S {
+    x: foo::bar!(), //~ ERROR expected macro name without module separators
+    y: ::foo::bar!(), //~ ERROR expected macro name without module separators
+}
+
+impl S {
+    foo::bar!(); //~ ERROR expected macro name without module separators
+    ::foo::bar!(); //~ ERROR expected macro name without module separators
+}
+
+fn main() {
+    foo::bar!(); //~ ERROR expected macro name without module separators
+    ::foo::bar!(); //~ ERROR expected macro name without module separators
+
+    let _ = foo::bar!(); //~ ERROR expected macro name without module separators
+    let _ = ::foo::bar!(); //~ ERROR expected macro name without module separators
+
+    let foo::bar!() = 0; //~ ERROR expected macro name without module separators
+    let ::foo::bar!() = 0; //~ ERROR expected macro name without module separators
+}
diff --git a/src/test/compile-fail/platform-intrinsic-params.rs b/src/test/compile-fail/platform-intrinsic-params.rs
new file mode 100644 (file)
index 0000000..e8a9031
--- /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.
+
+#![feature(platform_intrinsics)]
+extern "platform-intrinsic" {
+    fn x86_mm_movemask_ps() -> i32; //~ERROR found 0, expected 1
+}
+
+fn main() { }
index f05f1cd544a10802b5b841567d8787fe58178245..edaab012757126ac17af640cc6024e7d1dd658e0 100644 (file)
@@ -9,5 +9,7 @@
 // except according to those terms.
 
 fn main() {
-    assert(true); //~ERROR unresolved name `assert`. Did you mean the macro `assert!`?
+    assert(true);
+    //~^ ERROR unresolved name `assert`
+    //~| NOTE did you mean the macro `assert!`?
 }
index b9c9d7a389b95dd63ef3375310fd0d454354ceed..0f2a3f12107ef792cea29421797fc2c4773d9a51 100644 (file)
@@ -30,8 +30,7 @@ pub fn main() {
         ref mut Self => (),
         //~^ ERROR expected identifier, found keyword `Self`
         Self!() => (),
-        //~^ ERROR expected identifier, found keyword `Self`
-        //~^^ ERROR macro undefined: 'Self!'
+        //~^ ERROR macro undefined: 'Self!'
         Foo { x: Self } => (),
         //~^ ERROR expected identifier, found keyword `Self`
         Foo { Self } => (),
@@ -39,11 +38,17 @@ pub fn main() {
     }
 }
 
-use std::option::Option as Self;
-//~^ ERROR expected identifier, found keyword `Self`
+mod m1 {
+    extern crate core as Self;
+    //~^ ERROR expected identifier, found keyword `Self`
+}
 
-extern crate Self;
-//~^ ERROR expected identifier, found keyword `Self`
+mod m2 {
+    use std::option::Option as Self;
+    //~^ ERROR expected identifier, found keyword `Self`
+}
 
-trait Self {}
-//~^ ERROR expected identifier, found keyword `Self`
+mod m3 {
+    trait Self {}
+    //~^ ERROR expected identifier, found keyword `Self`
+}
index ab429ab878073c02585aa91f7e87b0f2d56db446..151c1d432ed364715a31e02ea94169b40e46f217 100644 (file)
@@ -13,5 +13,6 @@
 fn main() {
     if foo { //~ NOTE: unclosed delimiter
     //~^ ERROR: unresolved name `foo`
+    //~| NOTE unresolved name
     ) //~ ERROR: incorrect close delimiter: `)`
 }
index 24627e94208748651be95d740ba13fda68e7c7f1..5f21bf18d7b1bfd6e5356d2d14c8de7a58775e8f 100644 (file)
@@ -19,6 +19,7 @@ pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P,
                                                                callback: F)
                                                                -> io::Result<bool> {
         if !is_directory(path.as_ref()) { //~ ERROR: unresolved name `is_directory`
+                                          //~| NOTE unresolved name
             callback(path.as_ref();  //~ NOTE: unclosed delimiter
                      //~^ ERROR: expected one of
             fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
index f5fecf3e1740a8197d0d3f3d2386dac38f1f9227..3ba9edda07f266a5b28385d1ddcb6f6887c329b7 100644 (file)
@@ -17,6 +17,8 @@ fn main() {
     //~^^^ ERROR: unresolved name `bar`
     //~^^^^ ERROR: unresolved name `foo`
     //~^^^^^ ERROR: expected one of `)`, `,`, `.`, `<`, `?`
+    //~| NOTE unresolved name
+    //~| NOTE unresolved name
 } //~ ERROR: incorrect close delimiter: `}`
 //~^ ERROR: incorrect close delimiter: `}`
 //~^^ ERROR: expected expression, found `)`
diff --git a/src/test/compile-fail/typo-suggestion.rs b/src/test/compile-fail/typo-suggestion.rs
deleted file mode 100644 (file)
index d5cf6a2..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
-    let foo = 1;
-
-    // `foo` shouldn't be suggested, it is too dissimilar from `bar`.
-    println!("Hello {}", bar);
-    //~^ ERROR: unresolved name `bar`
-
-    // But this is close enough.
-    println!("Hello {}", fob);
-    //~^ ERROR: unresolved name `fob`. Did you mean `foo`?
-}
index 1209757610251cd8477b890325a24bdaf7727b2a..50f4f3b98b337173f42103b3a049e7c6e34dd6f0 100644 (file)
@@ -15,6 +15,7 @@ trait Trait {}
 fn f<F:Trait(isize) -> isize>(x: F) {}
 //~^ ERROR E0244
 //~| NOTE expected no type arguments, found 1
-//~| ERROR associated type `Output` not found
+//~| ERROR E0220
+//~| NOTE associated type `Output` not found
 
 fn main() {}
diff --git a/src/test/incremental/cache_file_headers.rs b/src/test/incremental/cache_file_headers.rs
new file mode 100644 (file)
index 0000000..274a392
--- /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.
+
+// This test case makes sure that the compiler does not try to re-use anything
+// from the incremental compilation cache if the cache was produced by a
+// different compiler version. This is tested by artificially forcing the
+// emission of a different compiler version in the header of rpass1 artifacts,
+// and then making sure that the only object file of the test program gets
+// re-translated although the program stays unchanged.
+
+// The `l33t haxx0r` Rust compiler is known to produce incr. comp. artifacts
+// that are outrageously incompatible with just about anything, even itself:
+//[rpass1] rustc-env:RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER="l33t haxx0r rustc 2.1 LTS"
+
+// revisions:rpass1 rpass2
+
+#![feature(rustc_attrs)]
+#![rustc_partition_translated(module="cache_file_headers", cfg="rpass2")]
+
+fn main() {
+    // empty
+}
diff --git a/src/test/incremental/change_crate_order/auxiliary/a.rs b/src/test/incremental/change_crate_order/auxiliary/a.rs
new file mode 100644 (file)
index 0000000..69b4acd
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type="rlib"]
+
+pub static A : u32 = 32;
+
diff --git a/src/test/incremental/change_crate_order/auxiliary/b.rs b/src/test/incremental/change_crate_order/auxiliary/b.rs
new file mode 100644 (file)
index 0000000..1ab97a3
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type="rlib"]
+
+pub static B: u32 = 32;
+
diff --git a/src/test/incremental/change_crate_order/main.rs b/src/test/incremental/change_crate_order/main.rs
new file mode 100644 (file)
index 0000000..bd8742f
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:a.rs
+// aux-build:b.rs
+// revisions:rpass1 rpass2
+
+#![feature(rustc_attrs)]
+
+
+#[cfg(rpass1)]
+extern crate a;
+#[cfg(rpass1)]
+extern crate b;
+
+#[cfg(rpass2)]
+extern crate b;
+#[cfg(rpass2)]
+extern crate a;
+
+use a::A;
+use b::B;
+
+//? #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
+pub fn main() {
+    A + B;
+}
diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs
new file mode 100644 (file)
index 0000000..aa17a24
--- /dev/null
@@ -0,0 +1,715 @@
+// 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.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for enum definitions.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// We also test the ICH for enum definitions exported in metadata. Same as
+// above, we want to make sure that the change between rev1 and rev2 also
+// results in a change of the ICH for the enum's metadata, and that it stays
+// the same between rev2 and rev3.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+
+
+
+// Change enum visibility -----------------------------------------------------
+#[cfg(cfail1)]
+enum EnumVisibility { A }
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail3")]
+pub enum EnumVisibility { A }
+
+
+
+// Change name of a c-style variant -------------------------------------------
+#[cfg(cfail1)]
+enum EnumChangeNameCStyleVariant {
+    Variant1,
+    Variant2,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeNameCStyleVariant {
+    Variant1,
+    Variant2Changed,
+}
+
+
+
+// Change name of a tuple-style variant ---------------------------------------
+#[cfg(cfail1)]
+enum EnumChangeNameTupleStyleVariant {
+    Variant1,
+    Variant2(u32, f32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeNameTupleStyleVariant {
+    Variant1,
+    Variant2Changed(u32, f32),
+}
+
+
+
+// Change name of a struct-style variant --------------------------------------
+#[cfg(cfail1)]
+enum EnumChangeNameStructStyleVariant {
+    Variant1,
+    Variant2 { a: u32, b: f32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeNameStructStyleVariant {
+    Variant1,
+    Variant2Changed { a: u32, b: f32 },
+}
+
+
+
+// Change the value of a c-style variant --------------------------------------
+#[cfg(cfail1)]
+enum EnumChangeValueCStyleVariant0 {
+    Variant1,
+    Variant2 = 11,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeValueCStyleVariant0 {
+    Variant1,
+    Variant2 = 22,
+}
+
+#[cfg(cfail1)]
+enum EnumChangeValueCStyleVariant1 {
+    Variant1,
+    Variant2,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeValueCStyleVariant1 {
+    Variant1,
+    Variant2 = 11,
+}
+
+
+
+// Add a c-style variant ------------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddCStyleVariant {
+    Variant1,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumAddCStyleVariant {
+    Variant1,
+    Variant2,
+}
+
+
+
+// Remove a c-style variant ---------------------------------------------------
+#[cfg(cfail1)]
+enum EnumRemoveCStyleVariant {
+    Variant1,
+    Variant2,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumRemoveCStyleVariant {
+    Variant1,
+}
+
+
+
+// Add a tuple-style variant --------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddTupleStyleVariant {
+    Variant1,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumAddTupleStyleVariant {
+    Variant1,
+    Variant2(u32, f32),
+}
+
+
+
+// Remove a tuple-style variant -----------------------------------------------
+#[cfg(cfail1)]
+enum EnumRemoveTupleStyleVariant {
+    Variant1,
+    Variant2(u32, f32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumRemoveTupleStyleVariant {
+    Variant1,
+}
+
+
+
+// Add a struct-style variant -------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddStructStyleVariant {
+    Variant1,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumAddStructStyleVariant {
+    Variant1,
+    Variant2 { a: u32, b: f32 },
+}
+
+
+
+// Remove a struct-style variant ----------------------------------------------
+#[cfg(cfail1)]
+enum EnumRemoveStructStyleVariant {
+    Variant1,
+    Variant2 { a: u32, b: f32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumRemoveStructStyleVariant {
+    Variant1,
+}
+
+
+
+// Change the type of a field in a tuple-style variant ------------------------
+#[cfg(cfail1)]
+enum EnumChangeFieldTypeTupleStyleVariant {
+    Variant1(u32, u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeFieldTypeTupleStyleVariant {
+    Variant1(u32, u64),
+}
+
+
+
+// Change the type of a field in a struct-style variant -----------------------
+#[cfg(cfail1)]
+enum EnumChangeFieldTypeStructStyleVariant {
+    Variant1,
+    Variant2 { a: u32, b: u32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeFieldTypeStructStyleVariant {
+    Variant1,
+    Variant2 { a: u32, b: u64 },
+}
+
+
+
+// Change the name of a field in a struct-style variant -----------------------
+#[cfg(cfail1)]
+enum EnumChangeFieldNameStructStyleVariant {
+    Variant1 { a: u32, b: u32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeFieldNameStructStyleVariant {
+    Variant1 { a: u32, c: u32 },
+}
+
+
+
+// Change order of fields in a tuple-style variant ----------------------------
+#[cfg(cfail1)]
+enum EnumChangeOrderTupleStyleVariant {
+    Variant1(u32, u64),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeOrderTupleStyleVariant {
+    Variant1(u64, u32),
+}
+
+
+
+// Change order of fields in a struct-style variant ---------------------------
+#[cfg(cfail1)]
+enum EnumChangeFieldOrderStructStyleVariant {
+    Variant1 { a: u32, b: f32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumChangeFieldOrderStructStyleVariant {
+    Variant1 { b: f32, a: u32 },
+}
+
+
+
+// Add a field to a tuple-style variant ---------------------------------------
+#[cfg(cfail1)]
+enum EnumAddFieldTupleStyleVariant {
+    Variant1(u32, u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumAddFieldTupleStyleVariant {
+    Variant1(u32, u32, u32),
+}
+
+
+
+// Add a field to a struct-style variant --------------------------------------
+#[cfg(cfail1)]
+enum EnumAddFieldStructStyleVariant {
+    Variant1 { a: u32, b: u32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumAddFieldStructStyleVariant {
+    Variant1 { a: u32, b: u32, c: u32 },
+}
+
+
+
+// Add #[must_use] to the enum ------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddMustUse {
+    Variant1,
+    Variant2,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[must_use]
+enum EnumAddMustUse {
+    Variant1,
+    Variant2,
+}
+
+
+
+// Add #[repr(C)] to the enum -------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddReprC {
+    Variant1,
+    Variant2,
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddReprC {
+    Variant1,
+    Variant2,
+}
+
+
+
+// Change the name of a type parameter ----------------------------------------
+#[cfg(cfail1)]
+enum EnumChangeNameOfTypeParameter<S> {
+    Variant1(S),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumChangeNameOfTypeParameter<T> {
+    Variant1(T),
+}
+
+
+
+// Add a type parameter ------------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddTypeParameter<S> {
+    Variant1(S),
+    Variant2(S),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddTypeParameter<S, T> {
+    Variant1(S),
+    Variant2(T),
+}
+
+
+
+// Change the name of a lifetime parameter ------------------------------------
+#[cfg(cfail1)]
+enum EnumChangeNameOfLifetimeParameter<'a> {
+    Variant1(&'a u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumChangeNameOfLifetimeParameter<'b> {
+    Variant1(&'b u32),
+}
+
+
+
+// Add a lifetime parameter ---------------------------------------------------
+#[cfg(cfail1)]
+enum EnumAddLifetimeParameter<'a> {
+    Variant1(&'a u32),
+    Variant2(&'a u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddLifetimeParameter<'a, 'b> {
+    Variant1(&'a u32),
+    Variant2(&'b u32),
+}
+
+
+
+// Add a lifetime bound to a lifetime parameter -------------------------------
+#[cfg(cfail1)]
+enum EnumAddLifetimeParameterBound<'a, 'b> {
+    Variant1(&'a u32),
+    Variant2(&'b u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddLifetimeParameterBound<'a, 'b: 'a> {
+    Variant1(&'a u32),
+    Variant2(&'b u32),
+}
+
+// Add a lifetime bound to a type parameter -----------------------------------
+#[cfg(cfail1)]
+enum EnumAddLifetimeBoundToParameter<'a, T> {
+    Variant1(T),
+    Variant2(&'a u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddLifetimeBoundToParameter<'a, T: 'a> {
+    Variant1(T),
+    Variant2(&'a u32),
+}
+
+
+
+// Add a trait bound to a type parameter --------------------------------------
+#[cfg(cfail1)]
+enum EnumAddTraitBound<S> {
+    Variant1(S),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddTraitBound<T: Sync> {
+    Variant1(T),
+}
+
+
+
+// Add a lifetime bound to a lifetime parameter in where clause ---------------
+#[cfg(cfail1)]
+enum EnumAddLifetimeParameterBoundWhere<'a, 'b> {
+    Variant1(&'a u32),
+    Variant2(&'b u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a {
+    Variant1(&'a u32),
+    Variant2(&'b u32),
+}
+
+
+
+// Add a lifetime bound to a type parameter in where clause -------------------
+#[cfg(cfail1)]
+enum EnumAddLifetimeBoundToParameterWhere<'a, T> {
+    Variant1(T),
+    Variant2(&'a u32),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a {
+    Variant1(T),
+    Variant2(&'a u32),
+}
+
+
+
+// Add a trait bound to a type parameter in where clause ----------------------
+#[cfg(cfail1)]
+enum EnumAddTraitBoundWhere<S> {
+    Variant1(S),
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[repr(C)]
+enum EnumAddTraitBoundWhere<T> where T: Sync {
+    Variant1(T),
+}
+
+
+
+// In an enum with two variants, swap usage of type parameters ----------------
+#[cfg(cfail1)]
+enum EnumSwapUsageTypeParameters<A, B> {
+    Variant1 { a: A },
+    Variant2 { a: B },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumSwapUsageTypeParameters<A, B> {
+    Variant1 { a: B },
+    Variant2 { a: A },
+}
+
+
+
+// In an enum with two variants, swap usage of lifetime parameters ------------
+#[cfg(cfail1)]
+enum EnumSwapUsageLifetimeParameters<'a, 'b> {
+    Variant1 { a: &'a u32 },
+    Variant2 { b: &'b u32 },
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+enum EnumSwapUsageLifetimeParameters<'a, 'b> {
+    Variant1 { a: &'b u32 },
+    Variant2 { b: &'a u32 },
+}
+
+
+
+struct ReferencedType1;
+struct ReferencedType2;
+
+
+
+// Change field type in tuple-style variant indirectly by modifying a use statement
+mod change_field_type_indirectly_tuple_style {
+    #[cfg(cfail1)]
+    use super::ReferencedType1 as FieldType;
+    #[cfg(not(cfail1))]
+    use super::ReferencedType2 as FieldType;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    enum TupleStyle {
+        Variant1(FieldType)
+    }
+}
+
+
+
+// Change field type in record-style variant indirectly by modifying a use statement
+mod change_field_type_indirectly_struct_style {
+    #[cfg(cfail1)]
+    use super::ReferencedType1 as FieldType;
+    #[cfg(not(cfail1))]
+    use super::ReferencedType2 as FieldType;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    enum StructStyle {
+        Variant1 { a: FieldType }
+    }
+}
+
+
+
+trait ReferencedTrait1 {}
+trait ReferencedTrait2 {}
+
+
+
+// Change trait bound of type parameter indirectly by modifying a use statement
+mod change_trait_bound_indirectly {
+    #[cfg(cfail1)]
+    use super::ReferencedTrait1 as Trait;
+    #[cfg(not(cfail1))]
+    use super::ReferencedTrait2 as Trait;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    enum Enum<T: Trait> {
+        Variant1(T)
+    }
+}
+
+
+
+// Change trait bound of type parameter in where clause indirectly by modifying a use statement
+mod change_trait_bound_indirectly_where {
+    #[cfg(cfail1)]
+    use super::ReferencedTrait1 as Trait;
+    #[cfg(not(cfail1))]
+    use super::ReferencedTrait2 as Trait;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    enum Enum<T> where T: Trait {
+        Variant1(T)
+    }
+}
+
+
index e57a9674cf683d4be0421655c911bd7928076eb1..3304a66773ad2755c54e75ea169963aaaa6a8495 100644 (file)
@@ -23,19 +23,19 @@ fn main() {}
 // END RUST SOURCE
 // START rustc.node13.Deaggregator.before.mir
 // bb0: {
-//     var0 = arg0;                     // scope 0 at main.rs:8:8: 8:9
-//     tmp0 = var0;                     // scope 1 at main.rs:9:14: 9:15
-//     return = Baz { x: tmp0, y: const F32(0), z: const false }; // scope ...
-//     goto -> bb1;                     // scope 1 at main.rs:8:1: 10:2
+//     _2 = _1;
+//     _3 = _2;
+//     _0 = Baz { x: _3, y: const F32(0), z: const false };
+//     goto -> bb1;
 // }
 // END rustc.node13.Deaggregator.before.mir
 // START rustc.node13.Deaggregator.after.mir
 // bb0: {
-//     var0 = arg0;                     // scope 0 at main.rs:8:8: 8:9
-//     tmp0 = var0;                     // scope 1 at main.rs:9:14: 9:15
-//     (return.0: usize) = tmp0;        // scope 1 at main.rs:9:5: 9:34
-//     (return.1: f32) = const F32(0);  // scope 1 at main.rs:9:5: 9:34
-//     (return.2: bool) = const false;  // scope 1 at main.rs:9:5: 9:34
-//     goto -> bb1;                     // scope 1 at main.rs:8:1: 10:2
+//     _2 = _1;
+//     _3 = _2;
+//     (_0.0: usize) = _3;
+//     (_0.1: f32) = const F32(0);
+//     (_0.2: bool) = const false;
+//     goto -> bb1;
 // }
-// END rustc.node13.Deaggregator.after.mir
\ No newline at end of file
+// END rustc.node13.Deaggregator.after.mir
index ccfa760a28c76823905845e7524ec023c191a833..a6f12886f5527aade58d19802e1f3f1d3cda066d 100644 (file)
@@ -28,18 +28,18 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node10.Deaggregator.before.mir
 // bb0: {
-//     var0 = arg0;                     // scope 0 at main.rs:7:8: 7:9
-//     tmp0 = var0;                     // scope 1 at main.rs:8:19: 8:20
-//     return = Baz::Foo { x: tmp0 };   // scope 1 at main.rs:8:5: 8:21
-//     goto -> bb1;                     // scope 1 at main.rs:7:1: 9:2
+//     _2 = _1;
+//     _3 = _2;
+//     _0 = Baz::Foo { x: _3 };
+//     goto -> bb1;
 // }
 // END rustc.node10.Deaggregator.before.mir
 // START rustc.node10.Deaggregator.after.mir
 // bb0: {
-//     var0 = arg0;                     // scope 0 at main.rs:7:8: 7:9
-//     tmp0 = var0;                     // scope 1 at main.rs:8:19: 8:20
-//     ((return as Foo).0: usize) = tmp0; // scope 1 at main.rs:8:5: 8:21
-//     discriminant(return) = 1;         // scope 1 at main.rs:8:5: 8:21
-//     goto -> bb1;                     // scope 1 at main.rs:7:1: 9:2
+//     _2 = _1;
+//     _3 = _2;
+//     ((_0 as Foo).0: usize) = _3;
+//     discriminant(_0) = 1;
+//     goto -> bb1;
 // }
-// END rustc.node10.Deaggregator.after.mir
\ No newline at end of file
+// END rustc.node10.Deaggregator.after.mir
index dd6a857960432141e5a58f258b742bebb81a9aac..7239e32357b95eaba0e9622c2b7bdfdbf08e3abc 100644 (file)
@@ -17,11 +17,11 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node4.SimplifyBranches.initial-before.mir
 // bb0: {
-//     if(const false) -> [true: bb1, false: bb2]; // scope 0 at simplify_if.rs:12:5: 14:6
+//     if(const false) -> [true: bb1, false: bb2];
 // }
 // END rustc.node4.SimplifyBranches.initial-before.mir
 // START rustc.node4.SimplifyBranches.initial-after.mir
 // bb0: {
-//     goto -> bb2;                     // scope 0 at simplify_if.rs:12:5: 14:6
+//     goto -> bb2;
 // }
-// END rustc.node4.SimplifyBranches.initial-after.mir
\ No newline at end of file
+// END rustc.node4.SimplifyBranches.initial-after.mir
index 4ed0c8bc9ffa4184fb9da7e22c0ecab48a24c1c5..3885b233fd296ddd79552cdad2c0edf8719f7ed9 100644 (file)
@@ -21,27 +21,27 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node4.TypeckMir.before.mir
 //     bb0: {
-//         StorageLive(var0);               // scope 0 at storage_ranges.rs:14:9: 14:10
-//         var0 = const 0i32;               // scope 0 at storage_ranges.rs:14:13: 14:14
-//         StorageLive(var1);               // scope 1 at storage_ranges.rs:16:13: 16:14
-//         StorageLive(tmp1);               // scope 1 at storage_ranges.rs:16:18: 16:25
-//         StorageLive(tmp2);               // scope 1 at storage_ranges.rs:16:23: 16:24
-//         tmp2 = var0;                     // scope 1 at storage_ranges.rs:16:23: 16:24
-//         tmp1 = std::option::Option<i32>::Some(tmp2,); // scope 1 at storage_ranges.rs:16:18: 16:25
-//         var1 = &tmp1;                    // scope 1 at storage_ranges.rs:16:17: 16:25
-//         StorageDead(tmp2);               // scope 1 at storage_ranges.rs:16:23: 16:24
-//         tmp0 = ();                       // scope 2 at storage_ranges.rs:15:5: 17:6
-//         StorageDead(tmp1);               // scope 1 at storage_ranges.rs:16:18: 16:25
-//         StorageDead(var1);               // scope 1 at storage_ranges.rs:16:13: 16:14
-//         StorageLive(var2);               // scope 1 at storage_ranges.rs:18:9: 18:10
-//         var2 = const 1i32;               // scope 1 at storage_ranges.rs:18:13: 18:14
-//         return = ();                     // scope 3 at storage_ranges.rs:13:11: 19:2
-//         StorageDead(var2);               // scope 1 at storage_ranges.rs:18:9: 18:10
-//         StorageDead(var0);               // scope 0 at storage_ranges.rs:14:9: 14:10
-//         goto -> bb1;                     // scope 0 at storage_ranges.rs:13:1: 19:2
+//         StorageLive(_1);
+//         _1 = const 0i32;
+//         StorageLive(_3);
+//         StorageLive(_4);
+//         StorageLive(_5);
+//         _5 = _1;
+//         _4 = std::option::Option<i32>::Some(_5,);
+//         _3 = &_4;
+//         StorageDead(_5);
+//         _2 = ();
+//         StorageDead(_4);
+//         StorageDead(_3);
+//         StorageLive(_6);
+//         _6 = const 1i32;
+//         _0 = ();
+//         StorageDead(_6);
+//         StorageDead(_1);
+//         goto -> bb1;
 //     }
 //
 //     bb1: {
-//         return;                          // scope 0 at storage_ranges.rs:13:1: 19:2
+//         return;
 //     }
 // END rustc.node4.TypeckMir.before.mir
index acf7187cf436ff0d6ee06e40975c017099cc074f..ff3fefde40ece69c6005601d7fd513b09afba3f8 100644 (file)
@@ -11,7 +11,7 @@
 // compile-flags: -Z parse-only
 
 extern {
-    f(); //~ ERROR expected one of `fn`, `pub`, `static`, or `}`, found `f`
+    f(); //~ ERROR expected one of `!` or `::`, found `(`
 }
 
 fn main() {
index 76a4687f544da3578a553d654818dd5783e9506e..c03e0ef73217c5acee45a4012275acbff2f997bb 100644 (file)
@@ -11,5 +11,6 @@
 // compile-flags: -Z parse-only
 
 trait MyTrait<T>: Iterator {
-    Item = T; //~ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `Item`
+    Item = T; //~ ERROR expected one of `!` or `::`, found `=`
+              //~| ERROR expected item, found `=`
 }
index ab50503830534e7546ba0e89dd58807c8e7be3fd..36e2a4b86aa3965fa7d6ade6835e392162e58a55 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // error-pattern:thread '<unnamed>' panicked at 'test'
+// ignore-emscripten Needs threads
 
 use std::thread;
 
index 2d2371f5ce77c6d05fc58e85249b9442bdb580ea..4da40c3158b84c22ef955e8e243d3224b1e1a5cd 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // error-pattern:thread 'owned name' panicked at 'test'
+// ignore-emscripten Needs threads.
 
 use std::thread::Builder;
 
index ede055acd61ffcb7a20a3ff54461b366a2633a12..108430848b9b29673efe9b569fae95650be2bc3b 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // error-pattern:Ensure that the child thread runs by panicking
+// ignore-emscripten Needs threads.
 
 use std::thread;
 
index fa360570253b0f0e947eaaf1b2fe669d40704f21..21ced01d9d69efe619f8e23d79a72411bdf72b41 100644 (file)
@@ -12,6 +12,7 @@
 // error-pattern:thread 'test_foo' panicked at
 // compile-flags: --test
 // ignore-pretty: does not work well with `--test`
+// ignore-emscripten
 
 #[test]
 fn test_foo() {
index e18c5d9631a702358a6964b918fe8b2db3bb3267..74b5f17bcf9bad053905f6d917fb3498f63d7b87 100644 (file)
@@ -12,6 +12,7 @@
 // error-pattern:thread 'test_foo' panicked at
 // compile-flags: --test
 // ignore-pretty: does not work well with `--test`
+// ignore-emscripten
 
 #[test]
 #[should_panic(expected = "foobar")]
index 94ed641c79c9372cabcf34a107356b5e2bc780cc..b5c222764d243ea33060ff3826da71884f908c42 100644 (file)
@@ -15,6 +15,7 @@
 // compile-flags: --test
 // exec-env:RUST_TEST_THREADS=foo
 // ignore-pretty: does not work well with `--test`
+// ignore-emscripten
 
 #[test]
 fn do_nothing() {}
diff --git a/src/test/run-make/link-arg/Makefile b/src/test/run-make/link-arg/Makefile
new file mode 100644 (file)
index 0000000..0ee239a
--- /dev/null
@@ -0,0 +1,5 @@
+-include ../tools.mk
+RUSTC_FLAGS = -C link-arg="-lfoo" -C link-arg="-lbar" -Z print-link-args
+
+all:
+       $(RUSTC) $(RUSTC_FLAGS) empty.rs | grep lfoo | grep lbar
diff --git a/src/test/run-make/link-arg/empty.rs b/src/test/run-make/link-arg/empty.rs
new file mode 100644 (file)
index 0000000..2b76fb2
--- /dev/null
@@ -0,0 +1,11 @@
+// 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.
+
+fn main() { }
index 19e410fef538821dad9b6c7ff9d1b8422a7661d2..05c1713561a3ed6678be479569a17aa05d80f982 100644 (file)
@@ -79,8 +79,8 @@ fn main() {
         format!("_ _ --sysroot {} --crate-type dylib", path.to_str().unwrap())
         .split(' ').map(|s| s.to_string()).collect();
 
-    let (result, _) = rustc_driver::run_compiler_with_file_loader(
-        &args, &mut JitCalls, box JitLoader);
+    let (result, _) = rustc_driver::run_compiler(
+        &args, &mut JitCalls, Some(box JitLoader), None);
     if let Err(n) = result {
         panic!("Error {}", n);
     }
diff --git a/src/test/run-make/rustc-macro-dep-files/Makefile b/src/test/run-make/rustc-macro-dep-files/Makefile
new file mode 100644 (file)
index 0000000..d27b5d0
--- /dev/null
@@ -0,0 +1,6 @@
+-include ../tools.mk
+
+all:
+       $(RUSTC) foo.rs
+       $(RUSTC) bar.rs --emit dep-info
+       grep "rustc-macro source" $(TMPDIR)/bar.d && exit 1 || exit 0
diff --git a/src/test/run-make/rustc-macro-dep-files/bar.rs b/src/test/run-make/rustc-macro-dep-files/bar.rs
new file mode 100644 (file)
index 0000000..dac6527
--- /dev/null
@@ -0,0 +1,21 @@
+// 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_macro)]
+
+#[macro_use]
+extern crate foo;
+
+#[derive(A)]
+struct A;
+
+fn main() {
+    let _b = B;
+}
diff --git a/src/test/run-make/rustc-macro-dep-files/foo.rs b/src/test/run-make/rustc-macro-dep-files/foo.rs
new file mode 100644 (file)
index 0000000..c302ca8
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.
+
+#![crate_type = "rustc-macro"]
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(A)]
+pub fn derive(input: TokenStream) -> TokenStream {
+    let input = input.to_string();
+    assert!(input.contains("struct A;"));
+    "struct B;".parse().unwrap()
+}
index 775ba38004e3a195375194b4a3b48e5993449549..35e9f3f5c8d64f2968f5c4320629976f6666a238 100644 (file)
@@ -86,6 +86,6 @@ fn main() {
     let mut tc = TestCalls { count: 1 };
     // we should never get use this filename, but lets make sure they are valid args.
     let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
-    rustc_driver::run_compiler(&args, &mut tc);
+    rustc_driver::run_compiler(&args, &mut tc, None, None);
     assert_eq!(tc.count, 30);
 }
diff --git a/src/test/run-pass-fulldeps/rustc-macro/append-impl.rs b/src/test/run-pass-fulldeps/rustc-macro/append-impl.rs
new file mode 100644 (file)
index 0000000..b7025c6
--- /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.
+
+// aux-build:append-impl.rs
+
+#![feature(rustc_macro)]
+#![allow(warnings)]
+
+#[macro_use]
+extern crate append_impl;
+
+trait Append {
+    fn foo(&self);
+}
+
+#[derive(PartialEq,
+         Append,
+         Eq)]
+struct A {
+    inner: u32,
+}
+
+fn main() {
+    A { inner: 3 }.foo();
+}
diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/append-impl.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/append-impl.rs
new file mode 100644 (file)
index 0000000..c3d295e
--- /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.
+
+// force-host
+// no-prefer-dynamic
+
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+#![crate_type = "rustc-macro"]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(Append)]
+pub fn derive_a(input: TokenStream) -> TokenStream {
+    let mut input = input.to_string();
+    input.push_str("
+        impl Append for A {
+            fn foo(&self) {}
+        }
+    ");
+    input.parse().unwrap()
+}
index 4dd6ad88b757c5f00d2cfb2dbd5c0f538152396f..42155383decf95afdce9e754e61055043d3c071d 100644 (file)
@@ -22,6 +22,6 @@
 pub fn derive(input: TokenStream) -> TokenStream {
     let input = input.to_string();
     assert!(input.contains("struct A;"));
-    assert!(input.contains("#[derive(Eq, Copy, Clone)]"));
-    "#[derive(Eq, Copy, Clone)] struct A;".parse().unwrap()
+    assert!(input.contains("#[derive(Debug, PartialEq, Eq, Copy, Clone)]"));
+    "#[derive(Debug, PartialEq, Eq, Copy, Clone)] struct A;".parse().unwrap()
 }
index d7a8e79bfbee84f5951461887676e2370f5ebc65..ca2dbdf2b3de30a4a3672ecd389dc075889ca29c 100644 (file)
@@ -10,6 +10,7 @@
 
 // no-prefer-dynamic
 // aux-build:allocator-dummy.rs
+// ignore-emscripten
 
 #![feature(test)]
 
diff --git a/src/test/run-pass/attr-on-generic-formals.rs b/src/test/run-pass/attr-on-generic-formals.rs
new file mode 100644 (file)
index 0000000..5985284
--- /dev/null
@@ -0,0 +1,60 @@
+// 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.
+
+// This test ensures we can attach attributes to the formals in all
+// places where generic parameter lists occur, assuming appropriate
+// feature gates are enabled.
+//
+// (We are prefixing all tested features with `rustc_`, to ensure that
+// the attributes themselves won't be rejected by the compiler when
+// using `rustc_attrs` feature. There is a separate compile-fail/ test
+// ensuring that the attribute feature-gating works in this context.)
+
+#![feature(generic_param_attrs, rustc_attrs)]
+#![allow(dead_code)]
+
+struct StLt<#[rustc_lt_struct] 'a>(&'a u32);
+struct StTy<#[rustc_ty_struct] I>(I);
+
+enum EnLt<#[rustc_lt_enum] 'b> { A(&'b u32), B }
+enum EnTy<#[rustc_ty_enum] J> { A(J), B }
+
+trait TrLt<#[rustc_lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
+trait TrTy<#[rustc_ty_trait] K> { fn foo(&self, _: K); }
+
+type TyLt<#[rustc_lt_type] 'd> = &'d u32;
+type TyTy<#[rustc_ty_type] L> = (L, );
+
+impl<#[rustc_lt_inherent] 'e> StLt<'e> { }
+impl<#[rustc_ty_inherent] M> StTy<M> { }
+
+impl<#[rustc_lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
+    fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } }
+}
+impl<#[rustc_ty_impl_for] N> TrTy<N> for StTy<N> {
+    fn foo(&self, _: N) { }
+}
+
+fn f_lt<#[rustc_lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
+fn f_ty<#[rustc_ty_fn] O>(_: O) { }
+
+impl<I> StTy<I> {
+    fn m_lt<#[rustc_lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
+    fn m_ty<#[rustc_ty_meth] P>(_: P) { }
+}
+
+fn hof_lt<Q>(_: Q)
+    where Q: for <#[rustc_lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
+{
+}
+
+fn main() {
+
+}
diff --git a/src/test/run-pass/cstring-drop.rs b/src/test/run-pass/cstring-drop.rs
deleted file mode 100644 (file)
index 960391b..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-emscripten
-
-// Test that `CString::new("hello").unwrap().as_ptr()` pattern
-// leads to failure.
-
-use std::env;
-use std::ffi::{CString, CStr};
-use std::os::raw::c_char;
-use std::process::{Command, Stdio};
-
-fn main() {
-    let args: Vec<String> = env::args().collect();
-    if args.len() > 1 && args[1] == "child" {
-        // Repeat several times to be more confident that
-        // it is `Drop` for `CString` that does the cleanup,
-        // and not just some lucky UB.
-        let xs = vec![CString::new("Hello").unwrap(); 10];
-        let ys = xs.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
-        drop(xs);
-        assert!(ys.into_iter().any(is_hello));
-        return;
-    }
-
-    let output = Command::new(&args[0]).arg("child").output().unwrap();
-    assert!(!output.status.success());
-}
-
-fn is_hello(s: *const c_char) -> bool {
-    // `s` is a dangling pointer and reading it is technically
-    // undefined behavior. But we want to prevent the most diabolical
-    // kind of UB (apart from nasal demons): reading a value that was
-    // previously written.
-    //
-    // Segfaulting or reading an empty string is Ok,
-    // reading "Hello" is bad.
-    let s = unsafe { CStr::from_ptr(s) };
-    let hello = CString::new("Hello").unwrap();
-    s == hello.as_ref()
-}
index 1f30f3ecedc9682394888654c043a56183794520..e858ba8c823b8537d0d26d71b8cc3e8c50cce10f 100644 (file)
@@ -24,6 +24,9 @@ enum Enum {
     StructVariant { x: isize, y : usize }
 }
 
+#[derive(Debug)]
+struct Pointers(*const Send, *mut Sync);
+
 macro_rules! t {
     ($x:expr, $expected:expr) => {
         assert_eq!(format!("{:?}", $x), $expected.to_string())
diff --git a/src/test/run-pass/discriminant_value-wrapper.rs b/src/test/run-pass/discriminant_value-wrapper.rs
new file mode 100644 (file)
index 0000000..2dbda0b
--- /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(discriminant_value)]
+
+use std::mem;
+
+enum ADT {
+    First(u32, u32),
+    Second(u64)
+}
+
+pub fn main() {
+    assert!(mem::discriminant(&ADT::First(0,0)) == mem::discriminant(&ADT::First(1,1)));
+    assert!(mem::discriminant(&ADT::Second(5))  == mem::discriminant(&ADT::Second(6)));
+    assert!(mem::discriminant(&ADT::First(2,2)) != mem::discriminant(&ADT::Second(2)));
+
+    let _ = mem::discriminant(&10);
+    let _ = mem::discriminant(&"test");
+}
+
index 21948d2e5ad23c04bf3dad6312652456f48ea5bb..801a3c40ab47ddb9a2d0dd73248e521da5f0ab07 100644 (file)
@@ -12,6 +12,7 @@
 
 // pretty-expanded FIXME #23616
 // ignore-msvc
+// ignore-emscripten
 
 struct TwoU8s {
     one: u8,
index 7d49bd25309f5ad2b0479331265e36e834527413..0abe44d82591d702a89c93c44986c54b0ceeed7b 100644 (file)
@@ -11,6 +11,7 @@
 // ignore-windows
 // ignore-android
 // ignore-emscripten
+// ignore-haiku
 
 #![feature(libc)]
 
index 62d54da56b2ec95279eb421f8083b3d9222b1c93..1b9b4ab32ca40cb1cb1f767ef4cf565721470b7e 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-emscripten missing rust_begin_unwind
+
 #![feature(lang_items, start, collections)]
 #![no_std]
 
index d72386190ecd2768326ca42afec211098279a76d..91648ee5798266e3bb6e0b8ef498341156f77a2d 100644 (file)
@@ -22,23 +22,23 @@ macro_rules! foo { () => {
 
 fn g() {
     let x = 0;
-    macro_rules! m { ($x:ident) => {
-        macro_rules! m2 { () => { ($x, x) } }
+    macro_rules! m { ($m1:ident, $m2:ident, $x:ident) => {
+        macro_rules! $m1 { () => { ($x, x) } }
         let x = 1;
-        macro_rules! m3 { () => { ($x, x) } }
+        macro_rules! $m2 { () => { ($x, x) } }
     } }
 
     let x = 2;
-    m!(x);
+    m!(m2, m3, x);
 
     let x = 3;
     assert_eq!(m2!(), (2, 0));
     assert_eq!(m3!(), (2, 1));
 
     let x = 4;
-    m!(x);
-    assert_eq!(m2!(), (4, 0));
-    assert_eq!(m3!(), (4, 1));
+    m!(m4, m5, x);
+    assert_eq!(m4!(), (4, 0));
+    assert_eq!(m5!(), (4, 1));
 }
 
 mod foo {
diff --git a/src/test/run-pass/issue-18088.rs b/src/test/run-pass/issue-18088.rs
new file mode 100644 (file)
index 0000000..a452563
--- /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.
+
+
+pub trait Indexable<T>: std::ops::Index<usize, Output = T> {
+    fn index2(&self, i: usize) -> &T {
+        &self[i]
+    }
+}
+fn main() {}
diff --git a/src/test/run-pass/issue-36768.rs b/src/test/run-pass/issue-36768.rs
new file mode 100644 (file)
index 0000000..bb4d129
--- /dev/null
@@ -0,0 +1,18 @@
+// 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:--test
+#![deny(private_in_public)]
+
+#[test] fn foo() {}
+mod foo {}
+
+#[test] fn core() {}
+extern crate core;
diff --git a/src/test/run-pass/issue-36786-resolve-call.rs b/src/test/run-pass/issue-36786-resolve-call.rs
new file mode 100644 (file)
index 0000000..0d718c7
--- /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.
+
+// Ensure that types that rely on obligations are autoderefed
+// correctly
+
+fn main() {
+    let x : Vec<Box<Fn()>> = vec![Box::new(|| ())];
+    x[0]()
+}
diff --git a/src/test/run-pass/issue-36816.rs b/src/test/run-pass/issue-36816.rs
new file mode 100644 (file)
index 0000000..22f3a52
--- /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.
+
+macro_rules! m { () => { 1 } }
+macro_rules! n { () => { 1 + m!() } }
+
+fn main() {
+    let _: [u32; n!()] = [0, 0];
+}
index e0327a1dcd4ed19fed28b715f6d2991ec17caed7..28dee15cfa04399e1ebe61bbe7d33b324c03bff5 100644 (file)
@@ -17,4 +17,15 @@ mod mod_dir_simple {
 
 pub fn main() {
     assert_eq!(mod_dir_simple::syrup::foo(), 10);
+
+    #[path = "auxiliary"]
+    mod foo {
+        mod two_macros;
+    }
+
+    #[path = "auxiliary"]
+    mod bar {
+        macro_rules! m { () => { mod two_macros; } }
+        m!();
+    }
 }
index 92308c9fc3e4e0eddebe36707b3cf215c32144fc..d1e05e5a0184c3d1c8cac004726b958bf3b0c5c2 100644 (file)
@@ -7,6 +7,7 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+// ignore-emscripten Not sure what's happening here.
 
 
 use std::mem;
index 411c1807a16b71491410c7c4bfedf810985dcd2f..ee4eb86ed0de3d04a6c30d4552810aac53646e26 100644 (file)
@@ -7,6 +7,7 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+// ignore-emscripten
 
 
 use std::mem;
index 71c1a61062d1085a24bb2e02a065a68731bb07af..1c273fcba02daf77b148b7c9f44dd9779b4d416e 100644 (file)
@@ -11,6 +11,7 @@
 // compile-flags:-C panic=abort
 // aux-build:exit-success-if-unwind.rs
 // no-prefer-dynamic
+// ignore-emscripten Function not implemented
 
 extern crate exit_success_if_unwind;
 
index 2fc9d6cfd04a13ead3a726200646f7ff118650e9..be38f6ea3643a8857c7c553af3e2df34aa8ac59d 100644 (file)
@@ -10,6 +10,7 @@
 
 // compile-flags:-C panic=abort
 // no-prefer-dynamic
+// ignore-emscripten Function not implemented.
 
 use std::process::Command;
 use std::env;
index 09e33b88189fe8fb691ed1934bea768f41733016..e4cd4e809a4c6bf7684b9346ea325dbca9335c39 100644 (file)
@@ -10,6 +10,7 @@
 
 // compile-flags:-C lto -C panic=abort
 // no-prefer-dynamic
+// ignore-emscripten Function not implemented.
 
 use std::process::Command;
 use std::env;
index 10e633b3775b3530f88d325a4ed703bca6f148fa..768b88fd09e0b3fad9c8aaa33c2b3db88e2fca0e 100644 (file)
@@ -10,6 +10,7 @@
 
 // compile-flags:-C lto -C panic=unwind
 // no-prefer-dynamic
+// ignore-emscripten Function not implemented.
 
 use std::process::Command;
 use std::env;
index 2ad47c4f116ae9a34d6dbd22c145ed65391b280c..ff389bec899efba23026791c97f3aaad210e03f6 100644 (file)
@@ -7,6 +7,7 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+// ignore-emscripten Function not implemented.
 
 use std::env;
 use std::io;
index aaf129e7b8e4abf413e65847100a8dcf03f95ab8..cfa9f6e36e9bcb37fce6b735ed61b6e3d925ff08 100644 (file)
@@ -75,7 +75,7 @@ pub fn main() {
 
     // test the size hints and emptying
     let mut long = 0...255u8;
-    let mut short = 42...42;
+    let mut short = 42...42u8;
     assert_eq!(long.size_hint(), (256, Some(256)));
     assert_eq!(short.size_hint(), (1, Some(1)));
     long.next();
index 2efd9333999b24ca0f83834b7be300b849cb7f19..d32fa01c7b9453fb2e3c1d52705b6d070eb108c5 100644 (file)
@@ -7,6 +7,7 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+// ignore-emscripten linking with emcc failed
 
 #![feature(repr_simd, platform_intrinsics, concat_idents, test)]
 #![allow(non_camel_case_types)]
index 1f64f40c5255baead14e2e11b8488ffe4f305466..13d5cc989e94dac4a8dfd332bc55e2abcea5d87b 100644 (file)
@@ -30,7 +30,7 @@ fn main() {
     let data = Arc::new(Mutex::new(Vec::new()));
     let sink = Sink(data.clone());
     let res = thread::Builder::new().spawn(move|| -> () {
-        io::set_panic(Box::new(sink));
+        io::set_panic(Some(Box::new(sink)));
         panic!("Hello, world!")
     }).unwrap().join();
     assert!(res.is_err());
index 543c02fb701f35507034ad505ca50eac76cd3fa0..f865f0a5f23cdc4427c610d74a8bd97ec548b5c9 100644 (file)
@@ -2,7 +2,7 @@ error[E0425]: unresolved name `bar`
   --> $DIR/tab.rs:14:2
    |
 14 | \tbar;
-   | \t^^^
+   | \t^^^ unresolved name
 
 error: aborting due to previous error
 
index e452e8d69bdad6e7d7b9dce388bcf9cc5be45d75..1c7fac894f976cf2468dbedf5e2aa9c147e1625d 100644 (file)
@@ -2,7 +2,7 @@ error[E0425]: unresolved name `fake`
   --> $DIR/macro-backtrace-nested.rs:15:12
    |
 15 |     () => (fake)
-   |            ^^^^
+   |            ^^^^ unresolved name
 ...
 27 |     1 + call_nested_expr!();
    |         ------------------- in this macro invocation
@@ -11,7 +11,7 @@ error[E0425]: unresolved name `fake`
   --> $DIR/macro-backtrace-nested.rs:15:12
    |
 15 |     () => (fake)
-   |            ^^^^
+   |            ^^^^ unresolved name
 ...
 28 |     call_nested_expr_sum!();
    |     ------------------------ in this macro invocation
index 3cd1791a34ff7233cf05d598bfede1f5d3b29d6d..dc37acaf3f98eb3a5b320bebfb3c4d65bc40dc13 100644 (file)
@@ -2,7 +2,7 @@ error[E0220]: associated type `Trget` not found for `std::ops::Deref`
   --> $DIR/type-binding.rs:16:20
    |
 16 | fn homura<T: Deref<Trget = i32>>(_: T) {}
-   |                    ^^^^^^^^^^^
+   |                    ^^^^^^^^^^^ associated type `Trget` not found
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/typo-suggestion.rs b/src/test/ui/span/typo-suggestion.rs
new file mode 100644 (file)
index 0000000..536bf16
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    let foo = 1;
+
+    // `foo` shouldn't be suggested, it is too dissimilar from `bar`.
+    println!("Hello {}", bar);
+
+    // But this is close enough.
+    println!("Hello {}", fob);
+}
diff --git a/src/test/ui/span/typo-suggestion.stderr b/src/test/ui/span/typo-suggestion.stderr
new file mode 100644 (file)
index 0000000..5446175
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0425]: unresolved name `bar`
+  --> $DIR/typo-suggestion.rs:15:26
+   |
+15 |     println!("Hello {}", bar);
+   |                          ^^^ unresolved name
+
+error[E0425]: unresolved name `fob`
+  --> $DIR/typo-suggestion.rs:18:26
+   |
+18 |     println!("Hello {}", fob);
+   |                          ^^^ did you mean `foo`?
+
+error: aborting due to 2 previous errors
+
index 5d522736089ea4d2acf1340b99bf5a6cd6c23583..81cb927f26b0210d33ff07695a281f424ba70142 100644 (file)
@@ -183,4 +183,5 @@ pub struct Config {
     pub cflags: String,
     pub llvm_components: String,
     pub llvm_cxxflags: String,
+    pub nodejs: Option<String>,
 }
index 4afeb3613319b025bb8291e5d03ce4cf622a8a7c..ff91ab7c70b3ee97a05f96c7e93e3033c3554b51 100644 (file)
@@ -109,6 +109,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
           reqopt("", "cflags", "flags for the C compiler", "FLAGS"),
           reqopt("", "llvm-components", "list of LLVM components built in", "LIST"),
           reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS"),
+          optopt("", "nodejs", "the name of nodejs", "PATH"),
           optflag("h", "help", "show this message"));
 
     let (argv0, args_) = args.split_first().unwrap();
@@ -190,6 +191,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
         cflags: matches.opt_str("cflags").unwrap(),
         llvm_components: matches.opt_str("llvm-components").unwrap(),
         llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(),
+        nodejs: matches.opt_str("nodejs"),
     }
 }
 
@@ -313,6 +315,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
         },
         color: test::AutoColor,
         test_threads: None,
+        skip: vec![],
     }
 }
 
@@ -430,10 +433,17 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn
         }
     };
 
+    // Debugging emscripten code doesn't make sense today
+    let mut ignore = early_props.ignore;
+    if (config.mode == DebugInfoGdb || config.mode == DebugInfoLldb) &&
+        config.target.contains("emscripten") {
+        ignore = true;
+    }
+
     test::TestDescAndFn {
         desc: test::TestDesc {
             name: make_test_name(config, testpaths),
-            ignore: early_props.ignore,
+            ignore: ignore,
             should_panic: should_panic,
         },
         testfn: make_test_closure(config, testpaths),
index 8fdb882164af8517d793bb0c6e885e1277fb2751..35b93392baf2c4c96110e961a7a871f714394a01 100644 (file)
@@ -1168,7 +1168,6 @@ fn exec_compiled_test(&self) -> ProcRes {
             "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" => {
                 self._arm_exec_compiled_test(env)
             }
-
             _=> {
                 let aux_dir = self.aux_output_dir_name();
                 self.compose_and_run(self.make_run_args(),
@@ -1421,7 +1420,7 @@ fn make_lib_name(&self, auxfile: &Path) -> PathBuf {
     fn make_exe_name(&self) -> PathBuf {
         let mut f = self.output_base_name();
         // FIXME: This is using the host architecture exe suffix, not target!
-        if self.config.target == "asmjs-unknown-emscripten" {
+        if self.config.target.contains("emscripten") {
             let mut fname = f.file_name().unwrap().to_os_string();
             fname.push(".js");
             f.set_file_name(&fname);
@@ -1439,8 +1438,9 @@ fn make_run_args(&self) -> ProcArgs {
         let mut args = self.split_maybe_args(&self.config.runtool);
 
         // If this is emscripten, then run tests under nodejs
-        if self.config.target == "asmjs-unknown-emscripten" {
-            args.push("nodejs".to_owned());
+        if self.config.target.contains("emscripten") {
+            let nodejs = self.config.nodejs.clone().unwrap_or("nodejs".to_string());
+            args.push(nodejs);
         }
 
         let exe_file = self.make_exe_name();
index 2db53947d881d5929b11e311f38ed9708cb67600..cad71c59f0a4aef93ccd10d3d75b1022b0bafdc9 100644 (file)
@@ -17,6 +17,7 @@
                                                             ("darwin", "macos"),
                                                             ("dragonfly", "dragonfly"),
                                                             ("freebsd", "freebsd"),
+                                                            ("haiku", "haiku"),
                                                             ("ios", "ios"),
                                                             ("linux", "linux"),
                                                             ("mingw32", "windows"),
@@ -42,7 +43,8 @@
                                                               ("sparc", "sparc"),
                                                               ("x86_64", "x86_64"),
                                                               ("xcore", "xcore"),
-                                                              ("asmjs", "asmjs")];
+                                                              ("asmjs", "asmjs"),
+                                                              ("wasm32", "wasm32")];
 
 pub fn get_os(triple: &str) -> &'static str {
     for &(triple_os, os) in OS_TABLE {
index 2839bbded1a5f0cb8d171a70ba13cf3b7efadbee..cabaee5d0600551ac1df0488456353b3ebc669b5 100644 (file)
@@ -36,6 +36,7 @@ macro_rules! t {
 mod features;
 mod cargo;
 mod cargo_lock;
+mod pal;
 
 fn main() {
     let path = env::args_os().skip(1).next().expect("need an argument");
@@ -48,6 +49,7 @@ fn main() {
     cargo::check(&path, &mut bad);
     features::check(&path, &mut bad);
     cargo_lock::check(&path, &mut bad);
+    pal::check(&path, &mut bad);
 
     if bad {
         panic!("some tidy checks failed");
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
new file mode 100644 (file)
index 0000000..1d04e8f
--- /dev/null
@@ -0,0 +1,230 @@
+// 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.
+
+//! Tidy check to enforce rules about platform-specific code in std
+//!
+//! This is intended to maintain existing standards of code
+//! organization in hopes that the standard library will continue to
+//! be refactored to isolate platform-specific bits, making porting
+//! easier; where "standard library" roughly means "all the
+//! dependencies of the std and test crates".
+//!
+//! This generally means placing restrictions on where `cfg(unix)`,
+//! `cfg(windows)`, `cfg(target_os)` and `cfg(target_env)` may appear,
+//! the basic objective being to isolate platform-specific code to the
+//! platform-specific `std::sys` modules, and to the allocation,
+//! unwinding, and libc crates.
+//!
+//! Following are the basic rules, though there are currently
+//! exceptions:
+//!
+//! - core may not have platform-specific code
+//! - liballoc_system may have platform-specific code
+//! - liballoc_jemalloc may have platform-specific code
+//! - libpanic_abort may have platform-specific code
+//! - libpanic_unwind may have platform-specific code
+//! - libunwind may have platform-specific code
+//! - other crates in the std facade may not
+//! - std may have platform-specific code in the following places
+//!   - sys/unix/
+//!   - sys/windows/
+//!   - os/
+//!
+//! `std/sys_common` should _not_ contain platform-specific code.
+//! Finally, because std contains tests with platform-specific
+//! `ignore` attributes, once the parser encounters `mod tests`,
+//! platform-specific cfgs are allowed. Not sure yet how to deal with
+//! this in the long term.
+
+use std::fs::File;
+use std::io::Read;
+use std::path::Path;
+use std::iter::Iterator;
+
+// Paths that may contain platform-specific code
+const EXCEPTION_PATHS: &'static [&'static str] = &[
+    // std crates
+    "src/liballoc_jemalloc",
+    "src/liballoc_system",
+    "src/liblibc",
+    "src/libpanic_abort",
+    "src/libpanic_unwind",
+    "src/libunwind",
+    "src/libstd/sys/unix", // This is where platform-specific code for std should live
+    "src/libstd/sys/windows", // Ditto
+    "src/libstd/os", // Platform-specific public interfaces
+    "src/rtstartup", // Not sure what to do about this. magic stuff for mingw
+
+    // temporary exceptions
+    "src/libstd/lib.rs", // This could probably be done within the sys directory
+    "src/libstd/rtdeps.rs", // Until rustbuild replaces make
+    "src/libstd/path.rs",
+    "src/libstd/io/stdio.rs",
+    "src/libstd/num/f32.rs",
+    "src/libstd/num/f64.rs",
+    "src/libstd/thread/local.rs",
+    "src/libstd/sys/common/mod.rs",
+    "src/libstd/sys/common/net.rs",
+    "src/libstd/sys/common/util.rs",
+    "src/libterm", // Not sure how to make this crate portable, but test needs it
+    "src/libtest", // Probably should defer to unstable std::sys APIs
+
+    // std testing crates, ok for now at least
+    "src/libcoretest",
+
+    // non-std crates
+    "src/test",
+    "src/tools",
+    "src/librustc",
+    "src/librustdoc",
+    "src/libsyntax",
+    "src/bootstrap",
+];
+
+pub fn check(path: &Path, bad: &mut bool) {
+    let ref mut contents = String::new();
+    // Sanity check that the complex parsing here works
+    let ref mut saw_target_arch = false;
+    let ref mut saw_cfg_bang = false;
+    super::walk(path, &mut super::filter_dirs, &mut |file| {
+        let filestr = file.to_string_lossy().replace("\\", "/");
+        if !filestr.ends_with(".rs") { return }
+
+        let is_exception_path = EXCEPTION_PATHS.iter().any(|s| filestr.contains(&**s));
+        if is_exception_path { return }
+
+        check_cfgs(contents, &file, bad, saw_target_arch, saw_cfg_bang);
+    });
+
+    assert!(*saw_target_arch);
+    assert!(*saw_cfg_bang);
+}
+
+fn check_cfgs(contents: &mut String, file: &Path,
+              bad: &mut bool, saw_target_arch: &mut bool, saw_cfg_bang: &mut bool) {
+    contents.truncate(0);
+    t!(t!(File::open(file), file).read_to_string(contents));
+
+    // For now it's ok to have platform-specific code after 'mod tests'.
+    let mod_tests_idx = find_test_mod(contents);
+    let contents = &contents[..mod_tests_idx];
+    // Pull out all "cfg(...)" and "cfg!(...)" strings
+    let cfgs = parse_cfgs(contents);
+
+    let mut line_numbers: Option<Vec<usize>> = None;
+    let mut err = |idx: usize, cfg: &str| {
+        if line_numbers.is_none() {
+            line_numbers = Some(contents.match_indices('\n').map(|(i, _)| i).collect());
+        }
+        let line_numbers = line_numbers.as_ref().expect("");
+        let line = match line_numbers.binary_search(&idx) {
+            Ok(_) => unreachable!(),
+            Err(i) => i + 1
+        };
+        println!("{}:{}: platform-specific cfg: {}", file.display(), line, cfg);
+        *bad = true;
+    };
+
+    for (idx, cfg) in cfgs.into_iter() {
+        // Sanity check that the parsing here works
+        if !*saw_target_arch && cfg.contains("target_arch") { *saw_target_arch = true }
+        if !*saw_cfg_bang && cfg.contains("cfg!") { *saw_cfg_bang = true }
+
+        let contains_platform_specific_cfg =
+            cfg.contains("target_os")
+            || cfg.contains("target_env")
+            || cfg.contains("target_vendor")
+            || cfg.contains("unix")
+            || cfg.contains("windows");
+
+        if !contains_platform_specific_cfg { continue }
+
+        let preceeded_by_doc_comment = {
+            let pre_contents = &contents[..idx];
+            let pre_newline = pre_contents.rfind('\n');
+            let pre_doc_comment = pre_contents.rfind("///");
+            match (pre_newline, pre_doc_comment) {
+                (Some(n), Some(c)) => n < c,
+                (None, Some(_)) => true,
+                (_, None) => false,
+            }
+        };
+
+        if preceeded_by_doc_comment { continue }
+
+        err(idx, cfg);
+    }
+}
+
+fn find_test_mod(contents: &str) -> usize {
+    if let Some(mod_tests_idx) = contents.find("mod tests") {
+        // Also capture a previos line indicating "mod tests" in cfg-ed out
+        let prev_newline_idx = contents[..mod_tests_idx].rfind('\n').unwrap_or(mod_tests_idx);
+        let prev_newline_idx = contents[..prev_newline_idx].rfind('\n');
+        if let Some(nl) = prev_newline_idx {
+            let prev_line = &contents[nl + 1 .. mod_tests_idx];
+            let emcc_cfg = "cfg(all(test, not(target_os";
+            if prev_line.contains(emcc_cfg) {
+                nl
+            } else {
+                mod_tests_idx
+            }
+        } else {
+            mod_tests_idx
+        }
+    } else {
+        contents.len()
+    }
+}
+
+fn parse_cfgs<'a>(contents: &'a str) -> Vec<(usize, &'a str)> {
+    let candidate_cfgs = contents.match_indices("cfg");
+    let candidate_cfg_idxs = candidate_cfgs.map(|(i, _)| i);
+    // This is puling out the indexes of all "cfg" strings
+    // that appear to be tokens succeeded by a paren.
+    let cfgs = candidate_cfg_idxs.filter(|i| {
+        let pre_idx = i.saturating_sub(*i);
+        let succeeds_non_ident = !contents.as_bytes().get(pre_idx)
+            .cloned()
+            .map(char::from)
+            .map(char::is_alphanumeric)
+            .unwrap_or(false);
+        let contents_after = &contents[*i..];
+        let first_paren = contents_after.find('(');
+        let paren_idx = first_paren.map(|ip| i + ip);
+        let preceeds_whitespace_and_paren = paren_idx.map(|ip| {
+            let maybe_space = &contents[*i + "cfg".len() .. ip];
+            maybe_space.chars().all(|c| char::is_whitespace(c) || c == '!')
+        }).unwrap_or(false);
+
+        succeeds_non_ident && preceeds_whitespace_and_paren
+    });
+
+    cfgs.map(|i| {
+        let mut depth = 0;
+        let contents_from = &contents[i..];
+        for (j, byte) in contents_from.bytes().enumerate() {
+            match byte {
+                b'(' => {
+                    depth += 1;
+                }
+                b')' => {
+                    depth -= 1;
+                    if depth == 0 {
+                        return (i, &contents_from[.. j + 1]);
+                    }
+                }
+                _ => { }
+            }
+        }
+
+        unreachable!()
+    }).collect()
+}